From d8c8c4220128d85569c329fb28aa6b1d72f77779 Mon Sep 17 00:00:00 2001 From: Vicky Wallace Date: Fri, 5 May 2017 12:21:28 -0700 Subject: [PATCH 0001/1001] clk: qcom: Add support to round the frequency to kHz The divider round closest flag is designed for the rounding to the Hz of the requested frequency. Certain clock such as graphic clock on SDM845 needs the divider to round to the kHz. This change support this special round rate. CRs-Fixed: 2048646 Change-Id: I1d5950faea30f94593321509dcf647af1b3fa57f Signed-off-by: Vicky Wallace --- drivers/clk/clk-divider.c | 3 +++ include/linux/clk-provider.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index d85bd0188eff..36fb964314dc 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -257,6 +257,9 @@ static bool _is_best_div(unsigned long rate, unsigned long now, { if (flags & CLK_DIVIDER_ROUND_CLOSEST) return abs(rate - now) < abs(rate - best); + else if (flags & CLK_DIVIDER_ROUND_KHZ) + return (DIV_ROUND_CLOSEST(abs(rate - now), 1000) + < DIV_ROUND_CLOSEST(abs(rate - best), 1000)); return now <= rate && now > best; } diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 61345e73dae5..ee85ac354b50 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -495,6 +495,7 @@ struct clk_divider { #define CLK_DIVIDER_ROUND_CLOSEST BIT(4) #define CLK_DIVIDER_READ_ONLY BIT(5) #define CLK_DIVIDER_MAX_AT_ZERO BIT(6) +#define CLK_DIVIDER_ROUND_KHZ BIT(7) extern const struct clk_ops clk_divider_ops; extern const struct clk_ops clk_divider_ro_ops; -- GitLab From 2db8e0ba294485769c56e66d3a6e0bf8093df3b6 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 29 Nov 2017 22:29:47 +0900 Subject: [PATCH 0002/1001] UPSTREAM: android: binder: Check for errors in binder_alloc_shrinker_init(). Both list_lru_init() and register_shrinker() might return an error. Signed-off-by: Tetsuo Handa Cc: Sherry Yang Cc: Michal Hocko Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 533dfb250d1c8d2bb8c9b65252f7b296b29913d4) Change-Id: I5325ccaf34a04179ef3dae73dd8f3abfd6e21565 --- drivers/android/binder.c | 4 +++- drivers/android/binder_alloc.c | 12 +++++++++--- drivers/android/binder_alloc.h | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 751777fd64bb..3c08ba9fb337 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -5801,7 +5801,9 @@ static int __init binder_init(void) struct binder_device *device; struct hlist_node *tmp; - binder_alloc_shrinker_init(); + ret = binder_alloc_shrinker_init(); + if (ret) + return ret; atomic_set(&binder_transaction_log.cur, ~0U); atomic_set(&binder_transaction_log_failed.cur, ~0U); diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index ba6d8d23f206..0ab338a40ce6 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -1006,8 +1006,14 @@ void binder_alloc_init(struct binder_alloc *alloc) INIT_LIST_HEAD(&alloc->buffers); } -void binder_alloc_shrinker_init(void) +int binder_alloc_shrinker_init(void) { - list_lru_init(&binder_alloc_lru); - register_shrinker(&binder_shrinker); + int ret = list_lru_init(&binder_alloc_lru); + + if (ret == 0) { + ret = register_shrinker(&binder_shrinker); + if (ret) + list_lru_destroy(&binder_alloc_lru); + } + return ret; } diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index 0b145307f1fd..9ef64e563856 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -130,7 +130,7 @@ extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, size_t extra_buffers_size, int is_async); extern void binder_alloc_init(struct binder_alloc *alloc); -void binder_alloc_shrinker_init(void); +extern int binder_alloc_shrinker_init(void); extern void binder_alloc_vma_close(struct binder_alloc *alloc); extern struct binder_buffer * binder_alloc_prepare_to_free(struct binder_alloc *alloc, -- GitLab From c2d933b07bcf74c30a7b485bbc5585fe25b15967 Mon Sep 17 00:00:00 2001 From: Xiongwei Song Date: Thu, 14 Dec 2017 12:15:42 +0800 Subject: [PATCH 0003/1001] UPSTREAM: ANDROID: binder: make binder_alloc_new_buf_locked static and indent its arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function binder_alloc_new_buf_locked() is only used in this file, so make it static. Also clean up sparse warning: drivers/android/binder_alloc.c:330:23: warning: no previous prototype for ‘binder_alloc_new_buf_locked’ [-Wmissing-prototypes] In addition, the line of the function name exceeds 80 characters when add static for this function, hence indent its arguments anew. Signed-off-by: Xiongwei Song Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 3f827245463a57f5ef64a665e1ca64eed0da00a5) Change-Id: I6b379df815d30f9b3e9f1dd50334375123b25bbc --- drivers/android/binder_alloc.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 0ab338a40ce6..5a426c877dfb 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -327,11 +327,12 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, return vma ? -ENOMEM : -ESRCH; } -struct binder_buffer *binder_alloc_new_buf_locked(struct binder_alloc *alloc, - size_t data_size, - size_t offsets_size, - size_t extra_buffers_size, - int is_async) +static struct binder_buffer *binder_alloc_new_buf_locked( + struct binder_alloc *alloc, + size_t data_size, + size_t offsets_size, + size_t extra_buffers_size, + int is_async) { struct rb_node *n = alloc->free_buffers.rb_node; struct binder_buffer *buffer; -- GitLab From 47e2dd3cc079c4e37558af6a1d64882decd4b8b9 Mon Sep 17 00:00:00 2001 From: Elad Wexler Date: Fri, 29 Dec 2017 11:03:37 +0200 Subject: [PATCH 0004/1001] UPSTREAM: android: binder: Prefer __func__ to using hardcoded function name Coding style fixup Signed-off-by: Elad Wexler Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 00c41cddebde8d1a635bf81a7b255b7e56fd0d15) Change-Id: I795e2a9f525c4a8df5cd0a81842a88529ba54f21 --- drivers/android/binder.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 3c08ba9fb337..e8f3934fdcc5 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -4914,7 +4914,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) return 0; err_bad_arg: - pr_err("binder_mmap: %d %lx-%lx %s failed %d\n", + pr_err("%s: %d %lx-%lx %s failed %d\n", __func__, proc->pid, vma->vm_start, vma->vm_end, failure_string, ret); return ret; } @@ -4924,7 +4924,7 @@ static int binder_open(struct inode *nodp, struct file *filp) struct binder_proc *proc; struct binder_device *binder_dev; - binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n", + binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d:%d\n", __func__, current->group_leader->pid, current->pid); proc = kzalloc(sizeof(*proc), GFP_KERNEL); -- GitLab From c5b47d2a3b40c549b48ea7901af95a09353bda84 Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Fri, 22 Dec 2017 19:37:02 +0530 Subject: [PATCH 0005/1001] UPSTREAM: android: binder: Use octal permissions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit checkpatch warns against the use of symbolic permissions, this patch migrates all symbolic permissions in the binder driver to octal permissions. Test: debugfs nodes created by binder have the same unix permissions prior to and after this patch was applied. Signed-off-by: Harsh Shandilya Cc: "Arve Hjønnevåg" Cc: Todd Kjos Cc: Martijn Coenen Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 21d02ddf716669e182a13b69b4dd928cf8ef5e0f) Change-Id: I8152fe280ead1d04d89593e813a722f9eb5def27 --- drivers/android/binder.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index e8f3934fdcc5..0f02548d8209 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -142,7 +142,7 @@ enum { }; static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR | BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION; -module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO); +module_param_named(debug_mask, binder_debug_mask, uint, 0644); static char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES; module_param_named(devices, binder_devices_param, charp, 0444); @@ -161,7 +161,7 @@ static int binder_set_stop_on_user_error(const char *val, return ret; } module_param_call(stop_on_user_error, binder_set_stop_on_user_error, - param_get_int, &binder_stop_on_user_error, S_IWUSR | S_IRUGO); + param_get_int, &binder_stop_on_user_error, 0644); #define binder_debug(mask, x...) \ do { \ @@ -4970,7 +4970,7 @@ static int binder_open(struct inode *nodp, struct file *filp) * anyway print all contexts that a given PID has, so this * is not a problem. */ - proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO, + proc->debugfs_entry = debugfs_create_file(strbuf, 0444, binder_debugfs_dir_entry_proc, (void *)(unsigned long)proc->pid, &binder_proc_fops); @@ -5815,27 +5815,27 @@ static int __init binder_init(void) if (binder_debugfs_dir_entry_root) { debugfs_create_file("state", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, NULL, &binder_state_fops); debugfs_create_file("stats", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, NULL, &binder_stats_fops); debugfs_create_file("transactions", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, NULL, &binder_transactions_fops); debugfs_create_file("transaction_log", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, &binder_transaction_log, &binder_transaction_log_fops); debugfs_create_file("failed_transaction_log", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, &binder_transaction_log_failed, &binder_transaction_log_fops); -- GitLab From 10340bf8887225ce300dd4cec63afa7c0fe5701d Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 23 Jan 2018 12:04:27 -0600 Subject: [PATCH 0006/1001] UPSTREAM: android: binder: Use true and false for boolean values Assign true or false to boolean variables instead of an integer value. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Cc: Todd Kjos Cc: Martijn Coenen Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 197410ad884eb18b31d48e9d8e64cb5a9e326f2f) Change-Id: I30bed831d6b6ff2e9e3e521ccc5d6836f0b30944 --- drivers/android/binder.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 0f02548d8209..ef3ea79045c1 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -250,7 +250,7 @@ static struct binder_transaction_log_entry *binder_transaction_log_add( unsigned int cur = atomic_inc_return(&log->cur); if (cur >= ARRAY_SIZE(log->entry)) - log->full = 1; + log->full = true; e = &log->entry[cur % ARRAY_SIZE(log->entry)]; WRITE_ONCE(e->debug_id_done, 0); /* @@ -2802,7 +2802,7 @@ static bool binder_proc_transaction(struct binder_transaction *t, if (node->has_async_transaction) { pending_async = true; } else { - node->has_async_transaction = 1; + node->has_async_transaction = true; } } @@ -3667,7 +3667,7 @@ static int binder_thread_write(struct binder_proc *proc, w = binder_dequeue_work_head_ilocked( &buf_node->async_todo); if (!w) { - buf_node->has_async_transaction = 0; + buf_node->has_async_transaction = false; } else { binder_enqueue_work_ilocked( w, &proc->todo); -- GitLab From fccfb036ac7a59657715cbebdbc3700606db7833 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 11 May 2018 01:45:24 -0700 Subject: [PATCH 0007/1001] UPSTREAM: ANDROID: binder: remove 32-bit binder interface. New devices launching with Android P need to use the 64-bit binder interface, even on 32-bit SoCs [0]. This change removes the Kconfig option to select the 32-bit binder interface. We don't think this will affect existing userspace for the following reasons: 1) The latest Android common tree is 4.14, so we don't believe any Android devices are on kernels >4.14. 2) Android devices launch on an LTS release and stick with it, so we wouldn't expect devices running on <= 4.14 now to upgrade to 4.17 or later. But even if they did, they'd rebuild the world (kernel + userspace) anyway. 3) Other userspaces like 'anbox' are already using the 64-bit interface. Note that this change doesn't remove the 32-bit UAPI itself; the reason for that is that Android userspace always uses the latest UAPI headers from upstream, and userspace retains 32-bit support for devices that are upgrading. This will be removed as well in 2-3 years, at which point we can remove the code from the UAPI as well. Finally, this change introduces build errors on archs where 64-bit get_user/put_user is not supported, so make binder unavailable on m68k (which wouldn't want it anyway). [0]: https://android-review.googlesource.com/c/platform/build/+/595193 Signed-off-by: Martijn Coenen Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 1190b4e38f97023154e6b3bef61b251aa5f970d0) Change-Id: I73dadf1d7b45a42bb18be5d5d3f5c090e61866de --- drivers/android/Kconfig | 15 +-------------- drivers/android/binder.c | 8 ++------ 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig index 7dce3795b887..ee4880bfdcdc 100644 --- a/drivers/android/Kconfig +++ b/drivers/android/Kconfig @@ -10,7 +10,7 @@ if ANDROID config ANDROID_BINDER_IPC bool "Android Binder IPC Driver" - depends on MMU + depends on MMU && !M68K default n ---help--- Binder is used in Android for both communication between processes, @@ -32,19 +32,6 @@ config ANDROID_BINDER_DEVICES created. Each binder device has its own context manager, and is therefore logically separated from the other devices. -config ANDROID_BINDER_IPC_32BIT - bool "Use old (Android 4.4 and earlier) 32-bit binder API" - depends on !64BIT && ANDROID_BINDER_IPC - default y - ---help--- - The Binder API has been changed to support both 32 and 64bit - applications in a mixed environment. - - Enable this to support an old 32-bit Android user-space (v4.4 and - earlier). - - Note that enabling this will break newer Android user-space. - config ANDROID_BINDER_IPC_SELFTEST bool "Android Binder IPC Driver Selftest" depends on ANDROID_BINDER_IPC diff --git a/drivers/android/binder.c b/drivers/android/binder.c index ef3ea79045c1..20aaf366559b 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -72,10 +72,6 @@ #include #include -#ifdef CONFIG_ANDROID_BINDER_IPC_32BIT -#define BINDER_IPC_32BIT 1 -#endif - #include #include #include "binder_alloc.h" @@ -2212,8 +2208,8 @@ static size_t binder_validate_object(struct binder_buffer *buffer, u64 offset) struct binder_object_header *hdr; size_t object_size = 0; - if (offset > buffer->data_size - sizeof(*hdr) || - buffer->data_size < sizeof(*hdr) || + if (buffer->data_size < sizeof(*hdr) || + offset > buffer->data_size - sizeof(*hdr) || !IS_ALIGNED(offset, sizeof(u32))) return 0; -- GitLab From 30814a1e21f50df412e4888771283389a6f867e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E9=87=91=E6=97=B6?= Date: Thu, 10 May 2018 02:05:03 +0000 Subject: [PATCH 0008/1001] UPSTREAM: ANDROID: binder: correct the cmd print for BINDER_WORK_RETURN_ERROR When to execute binder_stat_br the e->cmd has been modifying as BR_OK instead of the original return error cmd, in fact we want to know the original return error, such as BR_DEAD_REPLY or BR_FAILED_REPLY, etc. instead of always BR_OK, in order to avoid the value of the e->cmd is always BR_OK, so we need assign the value of the e->cmd to cmd before e->cmd = BR_OK. Signed-off-by: songjinshi Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 838d5565669aa5bb7deb605684a5970d51d5eaf6) Change-Id: I425b32c5419a491c6b9ceee7c00dde6513e0421d --- drivers/android/binder.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 20aaf366559b..e048cd7cd799 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -4091,6 +4091,7 @@ static int binder_thread_read(struct binder_proc *proc, binder_inner_proc_unlock(proc); if (put_user(e->cmd, (uint32_t __user *)ptr)) return -EFAULT; + cmd = e->cmd; e->cmd = BR_OK; ptr += sizeof(uint32_t); -- GitLab From 864095d649649c3814d469e6e85c2d16ae7e667d Mon Sep 17 00:00:00 2001 From: Minchan Kim Date: Mon, 7 May 2018 23:15:37 +0900 Subject: [PATCH 0009/1001] UPSTREAM: ANDROID: binder: change down_write to down_read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit binder_update_page_range needs down_write of mmap_sem because vm_insert_page need to change vma->vm_flags to VM_MIXEDMAP unless it is set. However, when I profile binder working, it seems every binder buffers should be mapped in advance by binder_mmap. It means we could set VM_MIXEDMAP in binder_mmap time which is already hold a mmap_sem as down_write so binder_update_page_range doesn't need to hold a mmap_sem as down_write. Please use proper API down_read. It would help mmap_sem contention problem as well as fixing down_write abuse. Ganesh Mahendran tested app launching and binder throughput test and he said he couldn't find any problem and I did binder latency test per Greg KH request(Thanks Martijn to teach me how I can do) I cannot find any problem, too. Cc: Ganesh Mahendran Cc: Joe Perches Cc: Arve Hjønnevåg Cc: Todd Kjos Reviewed-by: Martijn Coenen Signed-off-by: Minchan Kim Reviewed-by: Joel Fernandes (Google) Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 720c241924046aff83f5f2323232f34a30a4c281) Change-Id: I8358ceaaab4030f7122c95308dcad59557cad411 --- drivers/android/binder.c | 4 +++- drivers/android/binder_alloc.c | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index e048cd7cd799..9c06e7f46d7f 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -4898,7 +4898,9 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) failure_string = "bad vm_flags"; goto err_bad_arg; } - vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE; + vma->vm_flags |= VM_DONTCOPY | VM_MIXEDMAP; + vma->vm_flags &= ~VM_MAYWRITE; + vma->vm_ops = &binder_vm_ops; vma->vm_private_data = proc; diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 5a426c877dfb..4f382d51def1 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -219,7 +219,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, mm = alloc->vma_vm_mm; if (mm) { - down_write(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = alloc->vma; } @@ -288,7 +288,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, /* vm_insert_page does not seem to increment the refcount */ } if (mm) { - up_write(&mm->mmap_sem); + up_read(&mm->mmap_sem); mmput(mm); } return 0; @@ -321,7 +321,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, } err_no_vma: if (mm) { - up_write(&mm->mmap_sem); + up_read(&mm->mmap_sem); mmput(mm); } return vma ? -ENOMEM : -ESRCH; -- GitLab From a5d8063975d239825973cd6d23446aa95b8af23e Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 21 May 2018 11:26:17 -0700 Subject: [PATCH 0010/1001] msm: camera: sync: Validate if fence is already signaled This change provides a debugfs to switch between enqueuing the cb for a signaled fence onto the workq or directly invoking the cb in the same thread context. By default the task will be enqueued onto the workq. To have the sync driver invoke cb in same ctx: adb shell "echo Y > /sys/kernel/debug/camera_sync/trigger_cb_without_switch" Change-Id: Ic2fd7e0f3b08224020fcd2bd6f317e0da1939d10 Signed-off-by: Karthik Anantha Ram --- .../platform/msm/camera/cam_sync/cam_sync.c | 64 +++++++++++++++---- .../msm/camera/cam_sync/cam_sync_private.h | 3 + 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c index 55896f497c59..cb5187a7f5c0 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c @@ -21,6 +21,13 @@ struct sync_device *sync_dev; +/* + * Flag to determine whether to enqueue cb of a + * signaled fence onto the workq or invoke it + * directly in the same context + */ +static bool trigger_cb_without_switch; + int cam_sync_create(int32_t *sync_obj, const char *name) { int rc; @@ -58,6 +65,7 @@ int cam_sync_register_callback(sync_callback cb_func, struct sync_callback_info *sync_cb; struct sync_callback_info *cb_info; struct sync_table_row *row = NULL; + int status = 0; if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0 || !cb_func) return -EINVAL; @@ -94,18 +102,27 @@ int cam_sync_register_callback(sync_callback cb_func, if ((row->state == CAM_SYNC_STATE_SIGNALED_SUCCESS || row->state == CAM_SYNC_STATE_SIGNALED_ERROR) && (!row->remaining)) { - sync_cb->callback_func = cb_func; - sync_cb->cb_data = userdata; - sync_cb->sync_obj = sync_obj; - INIT_WORK(&sync_cb->cb_dispatch_work, - cam_sync_util_cb_dispatch); - sync_cb->status = row->state; - CAM_DBG(CAM_SYNC, "Callback trigger for sync object:%d", - sync_cb->sync_obj); - queue_work(sync_dev->work_queue, - &sync_cb->cb_dispatch_work); + if (trigger_cb_without_switch) { + CAM_DBG(CAM_SYNC, "Invoke callback for sync object:%d", + sync_obj); + status = row->state; + kfree(sync_cb); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + cb_func(sync_obj, status, userdata); + } else { + sync_cb->callback_func = cb_func; + sync_cb->cb_data = userdata; + sync_cb->sync_obj = sync_obj; + INIT_WORK(&sync_cb->cb_dispatch_work, + cam_sync_util_cb_dispatch); + sync_cb->status = row->state; + CAM_DBG(CAM_SYNC, "Enqueue callback for sync object:%d", + sync_cb->sync_obj); + queue_work(sync_dev->work_queue, + &sync_cb->cb_dispatch_work); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + } - spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); return 0; } @@ -952,6 +969,26 @@ static void cam_sync_init_entity(struct sync_device *sync_dev) } #endif +static int cam_sync_create_debugfs(void) +{ + sync_dev->dentry = debugfs_create_dir("camera_sync", NULL); + + if (!sync_dev->dentry) { + CAM_ERR(CAM_SYNC, "Failed to create sync dir"); + return -ENOMEM; + } + + if (!debugfs_create_bool("trigger_cb_without_switch", + 0644, sync_dev->dentry, + &trigger_cb_without_switch)) { + CAM_ERR(CAM_SYNC, + "failed to create trigger_cb_without_switch entry"); + return -ENOMEM; + } + + return 0; +} + static int cam_sync_probe(struct platform_device *pdev) { int rc; @@ -1017,6 +1054,9 @@ static int cam_sync_probe(struct platform_device *pdev) goto v4l2_fail; } + trigger_cb_without_switch = false; + cam_sync_create_debugfs(); + return rc; v4l2_fail: @@ -1036,6 +1076,8 @@ static int cam_sync_remove(struct platform_device *pdev) v4l2_device_unregister(sync_dev->vdev->v4l2_dev); cam_sync_media_controller_cleanup(sync_dev); video_device_release(sync_dev->vdev); + debugfs_remove_recursive(sync_dev->dentry); + sync_dev->dentry = NULL; kfree(sync_dev); sync_dev = NULL; diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_private.h b/drivers/media/platform/msm/camera/cam_sync/cam_sync_private.h index ce7d94916303..38dab42a56cc 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync_private.h +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_private.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -177,6 +178,7 @@ struct cam_signalable_info { * @row_spinlocks : Spinlock array, one for each row in the table * @table_lock : Mutex used to lock the table * @open_cnt : Count of file open calls made on the sync driver + * @dentry : Debugfs entry * @work_queue : Work queue used for dispatching kernel callbacks * @cam_sync_eventq : Event queue used to dispatch user payloads to user space * @bitmap : Bitmap representation of all sync objects @@ -188,6 +190,7 @@ struct sync_device { spinlock_t row_spinlocks[CAM_SYNC_MAX_OBJS]; struct mutex table_lock; int open_cnt; + struct dentry *dentry; struct workqueue_struct *work_queue; struct v4l2_fh *cam_sync_eventq; spinlock_t cam_sync_eventq_lock; -- GitLab From ae66c60d9920d6f8abcba3795efab321f1e9d721 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 16 Jul 2018 13:33:35 -0700 Subject: [PATCH 0011/1001] msm: camera: flash: Remove wrong bubble condition check Bubble flag is set from userspace for every pd table in crm. Wrong bubble flag check does not allow flash to fire in normal condition. Remove bubble condition check resolve the issue for both usecases. Change-Id: If1399e8361c5459f55e7ff6a0bd0f3ebd77aebe8 Signed-off-by: Jigarkumar Zala --- .../cam_flash/cam_flash_core.c | 33 +++++++++++-------- .../cam_flash/cam_flash_dev.h | 8 ++--- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c index 01f8c879fce2..cc13f358e586 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c @@ -493,8 +493,14 @@ int cam_flash_apply_setting(struct cam_flash_ctrl *fctrl, "Flash off failed %d", rc); goto apply_setting_err; } + } else if (flash_data->opcode == CAM_PKT_NOP_OPCODE) { + flash_data->opcode = 0; + CAM_DBG(CAM_FLASH, "NOP Packet"); } else { - CAM_DBG(CAM_FLASH, "NOP opcode: req_id: %u", req_id); + rc = -EINVAL; + CAM_ERR(CAM_FLASH, "Invalid opcode: %d req_id: %llu", + flash_data->opcode, req_id); + goto apply_setting_err; } } @@ -765,17 +771,20 @@ int cam_flash_parser(struct cam_flash_ctrl *fctrl, void *arg) break; } case CAM_PKT_NOP_OPCODE: { + frm_offset = csl_packet->header.request_id % + MAX_PER_FRAME_ARRAY; if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) || (fctrl->flash_state == CAM_FLASH_STATE_ACQUIRE)) { CAM_WARN(CAM_FLASH, "Rxed NOP packets without linking"); - frm_offset = csl_packet->header.request_id % - MAX_PER_FRAME_ARRAY; fctrl->per_frame[frm_offset].cmn_attr.is_settings_valid = false; return 0; } + fctrl->per_frame[frm_offset].cmn_attr.is_settings_valid = false; + fctrl->per_frame[frm_offset].cmn_attr.request_id = 0; + fctrl->per_frame[frm_offset].opcode = CAM_PKT_NOP_OPCODE; CAM_DBG(CAM_FLASH, "NOP Packet is Received: req_id: %u", csl_packet->header.request_id); goto update_req_mgr; @@ -925,19 +934,15 @@ int cam_flash_apply_request(struct cam_req_mgr_apply_request *apply) fctrl = (struct cam_flash_ctrl *) cam_get_device_priv(apply->dev_hdl); if (!fctrl) { CAM_ERR(CAM_FLASH, "Device data is NULL"); - rc = -EINVAL; - goto free_resource; + return -EINVAL; } - if (!(apply->report_if_bubble)) { - mutex_lock(&fctrl->flash_wq_mutex); - rc = cam_flash_apply_setting(fctrl, apply->request_id); - if (rc) - CAM_ERR(CAM_FLASH, "apply_setting failed with rc=%d", - rc); - mutex_unlock(&fctrl->flash_wq_mutex); - } + mutex_lock(&fctrl->flash_wq_mutex); + rc = cam_flash_apply_setting(fctrl, apply->request_id); + if (rc) + CAM_ERR(CAM_FLASH, "apply_setting failed with rc=%d", + rc); + mutex_unlock(&fctrl->flash_wq_mutex); -free_resource: return rc; } diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h index 13238552416a..4adc1b2e32a9 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h @@ -78,10 +78,10 @@ struct cam_flash_intf_params { * @cmd_type : Command buffer type */ struct cam_flash_common_attr { - bool is_settings_valid; - int32_t request_id; - uint16_t count; - uint8_t cmd_type; + bool is_settings_valid; + uint64_t request_id; + uint16_t count; + uint8_t cmd_type; }; /** -- GitLab From 83a9ce055edda84d76eb089baa4d11c0ac083db0 Mon Sep 17 00:00:00 2001 From: Morten Rasmussen Date: Thu, 1 Feb 2018 11:44:13 +0000 Subject: [PATCH 0012/1001] FROMLIST: sched: Add static_key for asymmetric cpu capacity optimizations The existing asymmetric cpu capacity code should cause minimal overhead for others. Putting it behind a static_key, it has been done for SMT optimizations, would make it easier to extend and improve without causing harm to others moving forward. cc: Ingo Molnar cc: Peter Zijlstra Signed-off-by: Morten Rasmussen [Taken from https://lore.kernel.org/lkml/1530699470-29808-2-git-send-email-morten.rasmussen@arm.com] Signed-off-by: Valentin Schneider Signed-off-by: Chris Redpath Change-Id: Iced93ffb71bb2c34eee783c585cffe7252137308 --- kernel/sched/fair.c | 3 +++ kernel/sched/sched.h | 1 + kernel/sched/topology.c | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index e0e2645220f1..710d9ab354f2 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -7166,6 +7166,9 @@ static int wake_cap(struct task_struct *p, int cpu, int prev_cpu) { long min_cap, max_cap; + if (!static_branch_unlikely(&sched_asym_cpucapacity)) + return 0; + min_cap = min(capacity_orig_of(prev_cpu), capacity_orig_of(cpu)); max_cap = cpu_rq(cpu)->rd->max_cpu_capacity; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index e23079498f84..a0e4e5c39a1a 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1097,6 +1097,7 @@ DECLARE_PER_CPU(struct sched_domain *, sd_numa); DECLARE_PER_CPU(struct sched_domain *, sd_asym); DECLARE_PER_CPU(struct sched_domain *, sd_ea); DECLARE_PER_CPU(struct sched_domain *, sd_scs); +extern struct static_key_false sched_asym_cpucapacity; struct sched_group_capacity { atomic_t ref; diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c index ad78fd4a66e5..56e0f805f603 100644 --- a/kernel/sched/topology.c +++ b/kernel/sched/topology.c @@ -417,6 +417,7 @@ DEFINE_PER_CPU(struct sched_domain *, sd_numa); DEFINE_PER_CPU(struct sched_domain *, sd_asym); DEFINE_PER_CPU(struct sched_domain *, sd_ea); DEFINE_PER_CPU(struct sched_domain *, sd_scs); +DEFINE_STATIC_KEY_FALSE(sched_asym_cpucapacity); static void update_top_cache_domain(int cpu) { @@ -456,6 +457,21 @@ static void update_top_cache_domain(int cpu) rcu_assign_pointer(per_cpu(sd_scs, cpu), sd); } +static void update_asym_cpucapacity(int cpu) +{ + int enable = false; + + rcu_read_lock(); + if (lowest_flag_domain(cpu, SD_ASYM_CPUCAPACITY)) + enable = true; + rcu_read_unlock(); + + if (enable) { + /* This expects to be hotplug-safe */ + static_branch_enable_cpuslocked(&sched_asym_cpucapacity); + } +} + /* * Attach the domain 'sd' to 'cpu' as its base domain. Callers must * hold the hotplug lock. @@ -1850,6 +1866,9 @@ build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *att } rcu_read_unlock(); + if (!cpumask_empty(cpu_map)) + update_asym_cpucapacity(cpumask_first(cpu_map)); + if (rq && sched_debug_enabled) { pr_info("span: %*pbl (max cpu_capacity = %lu)\n", cpumask_pr_args(cpu_map), rq->rd->max_cpu_capacity); -- GitLab From c662b0e5b94895799d91fedd3db253f909d1ccef Mon Sep 17 00:00:00 2001 From: Morten Rasmussen Date: Fri, 17 Jul 2015 16:45:07 +0100 Subject: [PATCH 0013/1001] FROMLIST: sched/fair: Add group_misfit_task load-balance type To maximize throughput in systems with asymmetric cpu capacities (e.g. ARM big.LITTLE) load-balancing has to consider task and cpu utilization as well as per-cpu compute capacity when load-balancing in addition to the current average load based load-balancing policy. Tasks with high utilization that are scheduled on a lower capacity cpu need to be identified and migrated to a higher capacity cpu if possible to maximize throughput. To implement this additional policy an additional group_type (load-balance scenario) is added: group_misfit_task. This represents scenarios where a sched_group has one or more tasks that are not suitable for its per-cpu capacity. group_misfit_task is only considered if the system is not overloaded or imbalanced (group_imbalanced or group_overloaded). Identifying misfit tasks requires the rq lock to be held. To avoid taking remote rq locks to examine source sched_groups for misfit tasks, each cpu is responsible for tracking misfit tasks themselves and update the rq->misfit_task flag. This means checking task utilization when tasks are scheduled and on sched_tick. cc: Ingo Molnar cc: Peter Zijlstra Signed-off-by: Morten Rasmussen [From https://lore.kernel.org/lkml/1530699470-29808-3-git-send-email-morten.rasmussen@arm.com/] [backported because some parts are already present in android] Signed-off-by: Ioan Budea Signed-off-by: Valentin Schneider Signed-off-by: Chris Redpath Change-Id: I71bd3a77c7088a102ba183df6ece7943aa7eb0c2 --- kernel/sched/fair.c | 74 +++++++++++++++++++++++--------------------- kernel/sched/sched.h | 3 +- 2 files changed, 40 insertions(+), 37 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 710d9ab354f2..c4a7670d4c1e 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -729,6 +729,7 @@ static u64 sched_vslice(struct cfs_rq *cfs_rq, struct sched_entity *se) static int select_idle_sibling(struct task_struct *p, int prev_cpu, int cpu); static unsigned long task_h_load(struct task_struct *p); +static unsigned long capacity_of(int cpu); /* Give new sched_entity start runnable values to heavy its load in infant time */ void init_entity_runnable_average(struct sched_entity *se) @@ -3598,6 +3599,26 @@ static inline unsigned long cfs_rq_load_avg(struct cfs_rq *cfs_rq) static int idle_balance(struct rq *this_rq, struct rq_flags *rf); +static inline int task_fits_capacity(struct task_struct *p, long capacity); + +static inline void update_misfit_status(struct task_struct *p, struct rq *rq) +{ + if (!static_branch_unlikely(&sched_asym_cpucapacity)) + return; + + if (!p) { + rq->misfit_task_load = 0; + return; + } + + if (task_fits_capacity(p, capacity_of(cpu_of(rq)))) { + rq->misfit_task_load = 0; + return; + } + + rq->misfit_task_load = task_h_load(p); +} + #else /* CONFIG_SMP */ static inline int @@ -3635,6 +3656,8 @@ static inline int idle_balance(struct rq *rq, struct rq_flags *rf) return 0; } +static inline void update_misfit_status(struct task_struct *p, struct rq *rq) {} + #endif /* CONFIG_SMP */ static void check_spread(struct cfs_rq *cfs_rq, struct sched_entity *se) @@ -7796,29 +7819,6 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ set_last_buddy(se); } -static inline void update_misfit_task(struct rq *rq, struct task_struct *p) -{ -#ifdef CONFIG_SMP - rq->misfit_task = !task_fits_capacity(p, capacity_of(rq->cpu)); -#endif -} - -static inline void clear_rq_misfit(struct rq *rq) -{ -#ifdef CONFIG_SMP - rq->misfit_task = 0; -#endif -} - -static inline unsigned int rq_has_misfit(struct rq *rq) -{ -#ifdef CONFIG_SMP - return rq->misfit_task; -#else - return 0; -#endif -} - static struct task_struct * pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) { @@ -7909,7 +7909,7 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf if (hrtick_enabled(rq)) hrtick_start_fair(rq, p); - update_misfit_task(rq, p); + update_misfit_status(p, rq); return p; simple: @@ -7928,12 +7928,12 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf if (hrtick_enabled(rq)) hrtick_start_fair(rq, p); - update_misfit_task(rq, p); + update_misfit_status(p, rq); return p; idle: - clear_rq_misfit(rq); + update_misfit_status(NULL, rq); new_tasks = idle_balance(rq, rf); /* @@ -8682,7 +8682,8 @@ struct sg_lb_stats { unsigned int group_weight; enum group_type group_type; int group_no_capacity; - int group_misfit_task; /* A cpu has a task too big for its capacity */ + /* A cpu has a task too big for its capacity */ + unsigned long group_misfit_task_load; #ifdef CONFIG_NUMA_BALANCING unsigned int nr_numa_running; unsigned int nr_preferred_running; @@ -9001,7 +9002,7 @@ group_type group_classify(struct sched_group *group, if (sg_imbalanced(group)) return group_imbalanced; - if (sgs->group_misfit_task) + if (sgs->group_misfit_task_load) return group_misfit_task; return group_other; @@ -9056,13 +9057,13 @@ static inline void update_sg_lb_stats(struct lb_env *env, sgs->idle_cpus++; if (env->sd->flags & SD_ASYM_CPUCAPACITY && - !sgs->group_misfit_task && rq_has_misfit(rq)) - sgs->group_misfit_task = capacity_of(i); + sgs->group_misfit_task_load < rq->misfit_task_load) + sgs->group_misfit_task_load = rq->misfit_task_load; if (cpu_overutilized(i)) { *overutilized = true; - if (rq_has_misfit(rq)) + if (rq->misfit_task_load) *misfit_task = true; } } @@ -9540,7 +9541,7 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s /* Boost imbalance to allow misfit task to be balanced. */ if (busiest->group_type == group_misfit_task) { env->imbalance = max_t(long, env->imbalance, - busiest->group_misfit_task); + busiest->group_misfit_task_load); } /* @@ -9706,7 +9707,8 @@ static struct rq *find_busiest_queue(struct lb_env *env, * For ASYM_CPUCAPACITY domains with misfit tasks we ignore * load. */ - if (env->src_grp_type == group_misfit_task && rq_has_misfit(rq)) + if (env->src_grp_type == group_misfit_task && + rq->misfit_task_load) return rq; capacity = capacity_of(i); @@ -10124,7 +10126,7 @@ get_sd_balance_interval(struct sched_domain *sd, int cpu_busy) if (energy_aware() && sd_overutilized(sd)) { /* we know the root is overutilized, let's check for a misfit task */ for_each_cpu(cpu, sched_domain_span(sd)) { - if (rq_has_misfit(cpu_rq(cpu))) + if (cpu_rq(cpu)->misfit_task_load) return 1; } } @@ -10748,7 +10750,7 @@ static inline bool nohz_kick_needed(struct rq *rq, bool only_update) /* Do idle load balance if there have misfit task */ if (energy_aware()) - return rq_has_misfit(rq); + return rq->misfit_task_load; rcu_read_lock(); sds = rcu_dereference(per_cpu(sd_llc_shared, cpu)); @@ -10875,7 +10877,7 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued) if (static_branch_unlikely(&sched_numa_balancing)) task_tick_numa(rq, curr); - update_misfit_task(rq, curr); + update_misfit_status(curr, rq); update_overutilized_status(rq); } diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index a0e4e5c39a1a..521ae77b34c8 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -755,7 +755,8 @@ struct rq { unsigned char idle_balance; - unsigned int misfit_task; + unsigned long misfit_task_load; + /* For active balancing */ int active_balance; int push_cpu; -- GitLab From a07aeacbff3e35bd99601d9538be55bb56485ab8 Mon Sep 17 00:00:00 2001 From: Morten Rasmussen Date: Wed, 16 May 2018 13:35:32 +0100 Subject: [PATCH 0014/1001] FROMLIST: sched: Add sched_group per-cpu max capacity The current sg->min_capacity tracks the lowest per-cpu compute capacity available in the sched_group when rt/irq pressure is taken into account. Minimum capacity isn't the ideal metric for tracking if a sched_group needs offloading to another sched_group for some scenarios, e.g. a sched_group with multiple cpus if only one is under heavy pressure. Tracking maximum capacity isn't perfect either but a better choice for some situations as it indicates that the sched_group definitely compute capacity constrained either due to rt/irq pressure on all cpus or asymmetric cpu capacities (e.g. big.LITTLE). cc: Ingo Molnar cc: Peter Zijlstra Signed-off-by: Morten Rasmussen [from https://lore.kernel.org/lkml/1530699470-29808-4-git-send-email-morten.rasmussen@arm.com/] [backported - some of this is already present in android-4.14] Signed-off-by: Valentin Schneider Signed-off-by: Chris Redpath Change-Id: Ic96c914f7f969b8aa353cfa3ad287e0e628b1793 --- kernel/sched/fair.c | 20 ++++++++++++++++---- kernel/sched/topology.c | 1 + 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index c4a7670d4c1e..48480ac4dc59 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -8801,6 +8801,7 @@ static void update_cpu_capacity(struct sched_domain *sd, int cpu) cpu_rq(cpu)->cpu_capacity = capacity; sdg->sgc->capacity = capacity; sdg->sgc->min_capacity = capacity; + sdg->sgc->max_capacity = capacity; } void update_group_capacity(struct sched_domain *sd, int cpu) @@ -8969,16 +8970,27 @@ group_is_overloaded(struct lb_env *env, struct sg_lb_stats *sgs) } /* - * group_smaller_cpu_capacity: Returns true if sched_group sg has smaller + * group_smaller_min_cpu_capacity: Returns true if sched_group sg has smaller * per-CPU capacity than sched_group ref. */ static inline bool -group_smaller_cpu_capacity(struct sched_group *sg, struct sched_group *ref) +group_smaller_min_cpu_capacity(struct sched_group *sg, struct sched_group *ref) { return sg->sgc->min_capacity * capacity_margin < ref->sgc->min_capacity * 1024; } +/* + * group_smaller_max_cpu_capacity: Returns true if sched_group sg has smaller + * per-CPU capacity_orig than sched_group ref. + */ +static inline bool +group_smaller_max_cpu_capacity(struct sched_group *sg, struct sched_group *ref) +{ + return sg->sgc->max_capacity * capacity_margin < + ref->sgc->max_capacity * 1024; +} + /* * group_similar_cpu_capacity: Returns true if the minimum capacity of the * compared groups differ by less than 12.5%. @@ -9105,7 +9117,7 @@ static bool update_sd_pick_busiest(struct lb_env *env, * Don't try to pull misfit tasks we can't help. */ if (sgs->group_type == group_misfit_task && - (!group_smaller_cpu_capacity(sg, sds->local) || + (!group_smaller_min_cpu_capacity(sg, sds->local) || !group_has_capacity(env, &sds->local_stat))) return false; @@ -9128,7 +9140,7 @@ static bool update_sd_pick_busiest(struct lb_env *env, * power/energy consequences are not considered. */ if (sgs->sum_nr_running <= sgs->group_weight && - group_smaller_cpu_capacity(sds->local, sg)) + group_smaller_min_cpu_capacity(sds->local, sg)) return false; /* diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c index 56e0f805f603..af01a95093ca 100644 --- a/kernel/sched/topology.c +++ b/kernel/sched/topology.c @@ -914,6 +914,7 @@ static struct sched_group *get_group(int cpu, struct sd_data *sdd) sg->sgc->capacity = SCHED_CAPACITY_SCALE * cpumask_weight(sched_group_span(sg)); sg->sgc->min_capacity = SCHED_CAPACITY_SCALE; + sg->sgc->max_capacity = SCHED_CAPACITY_SCALE; return sg; } -- GitLab From d756b4bea368d69a1212011615ae9ed400180f9a Mon Sep 17 00:00:00 2001 From: Chris Redpath Date: Tue, 17 Jul 2018 20:35:07 +0100 Subject: [PATCH 0015/1001] FROMLIST: sched/fair: Consider misfit tasks when load-balancing On asymmetric cpu capacity systems load intensive tasks can end up on cpus that don't suit their compute demand. In this scenarios 'misfit' tasks should be migrated to cpus with higher compute capacity to ensure better throughput. group_misfit_task indicates this scenario, but tweaks to the load-balance code are needed to make the migrations happen. Misfit balancing only makes sense between a source group of lower per-cpu capacity and destination group of higher compute capacity. Otherwise, misfit balancing is ignored. group_misfit_task has lowest priority so any imbalance due to overload is dealt with first. The modifications are: 1. Only pick a group containing misfit tasks as the busiest group if the destination group has higher capacity and has spare capacity. 2. When the busiest group is a 'misfit' group, skip the usual average load and group capacity checks. 3. Set the imbalance for 'misfit' balancing sufficiently high for a task to be pulled ignoring average load. 4. Pick the cpu with the highest misfit load as the source cpu. 5. If the misfit task is alone on the source cpu, go for active balancing. cc: Ingo Molnar cc: Peter Zijlstra Signed-off-by: Morten Rasmussen [from https://lore.kernel.org/lkml/1530699470-29808-5-git-send-email-morten.rasmussen@arm.com/] [backported - some parts already in android-4.14] Signed-off-by: Ioan Budea Signed-off-by: Valentin Schneider Signed-off-by: Chris Redpath Change-Id: Ib9f9edd31b6c56cfbeb2a2f9d5daaa1b6824375b --- kernel/sched/fair.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 48480ac4dc59..d86659871856 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -9115,9 +9115,12 @@ static bool update_sd_pick_busiest(struct lb_env *env, /* * Don't try to pull misfit tasks we can't help. + * We can use max_capacity here as reduction in capacity on some + * cpus in the group should either be possible to resolve + * internally or be covered by avg_load imbalance (eventually). */ if (sgs->group_type == group_misfit_task && - (!group_smaller_min_cpu_capacity(sg, sds->local) || + (!group_smaller_max_cpu_capacity(sg, sds->local) || !group_has_capacity(env, &sds->local_stat))) return false; @@ -9152,6 +9155,13 @@ static bool update_sd_pick_busiest(struct lb_env *env, !group_similar_cpu_capacity(sds->local, sg)) return false; + /* + * If we have more than one misfit sg go with the biggest misfit. + */ + if (sgs->group_type == group_misfit_task && + sgs->group_misfit_task_load < busiest->group_misfit_task_load) + return false; + asym_packing: /* This is the busiest node in its class. */ if (!(env->sd->flags & SD_ASYM_PACKING)) @@ -9626,7 +9636,7 @@ static struct sched_group *find_busiest_group(struct lb_env *env) busiest->group_no_capacity) goto force_balance; - /* Misfitting tasks should be dealt with regardless of the avg load */ + /* Misfit tasks should be dealt with regardless of the avg load */ if (busiest->group_type == group_misfit_task) goto force_balance; @@ -9716,12 +9726,16 @@ static struct rq *find_busiest_queue(struct lb_env *env, continue; /* - * For ASYM_CPUCAPACITY domains with misfit tasks we ignore - * load. + * For ASYM_CPUCAPACITY domains with misfit tasks we simply + * seek the "biggest" misfit task. */ - if (env->src_grp_type == group_misfit_task && - rq->misfit_task_load) - return rq; + if (env->src_grp_type == group_misfit_task) { + if (rq->misfit_task_load > busiest_load) { + busiest_load = rq->misfit_task_load; + busiest = rq; + } + continue; + } capacity = capacity_of(i); @@ -9800,6 +9814,9 @@ static int need_active_balance(struct lb_env *env) return 1; } + if (env->src_grp_type == group_misfit_task) + return 1; + return unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2); } -- GitLab From 16419700b5cd1338191a619d0affbdba55eb627c Mon Sep 17 00:00:00 2001 From: Valentin Schneider Date: Fri, 29 Jun 2018 14:50:31 +0100 Subject: [PATCH 0016/1001] FROMLIST: sched/fair: Change prefer_sibling type to bool This variable is entirely local to update_sd_lb_stats, so we can safely change its type and slightly clean up its initialisation. Signed-off-by: Valentin Schneider [from https://lore.kernel.org/lkml/1530699470-29808-7-git-send-email-morten.rasmussen@arm.com/] Signed-off-by: Valentin Schneider Signed-off-by: Chris Redpath Change-Id: I8d3cc862292290c952505ff78e41cfe6b04bf168 --- kernel/sched/fair.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index d86659871856..c848d5b2acae 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -9242,11 +9242,9 @@ static inline void update_sd_lb_stats(struct lb_env *env, struct sd_lb_stats *sd struct sched_group *sg = env->sd->groups; struct sg_lb_stats *local = &sds->local_stat; struct sg_lb_stats tmp_sgs; - int load_idx, prefer_sibling = 0; + int load_idx; bool overload = false, overutilized = false, misfit_task = false; - - if (child && child->flags & SD_PREFER_SIBLING) - prefer_sibling = 1; + bool prefer_sibling = child && child->flags & SD_PREFER_SIBLING; #ifdef CONFIG_NO_HZ_COMMON if (env->idle == CPU_NEWLY_IDLE) { -- GitLab From 14b1b1f5b38e9d81b26c3d22da2bfb8076cf780d Mon Sep 17 00:00:00 2001 From: Valentin Schneider Date: Tue, 27 Feb 2018 15:49:40 +0000 Subject: [PATCH 0017/1001] FROMLIST: sched: Change root_domain->overload type to int sizeof(_Bool) is implementation defined, so let's just go with 'int' as is done for other structures e.g. sched_domain_shared->has_idle_cores. The local 'overload' variable used in update_sd_lb_stats can remain bool, as it won't impact any struct layout and can be assigned to the root_domain field. cc: Ingo Molnar cc: Peter Zijlstra Signed-off-by: Valentin Schneider [from https://lore.kernel.org/lkml/1530699470-29808-8-git-send-email-morten.rasmussen@arm.com/] Signed-off-by: Valentin Schneider Signed-off-by: Chris Redpath Change-Id: I24c3ee7fc9a0aa76c3a7a1369714248703e73af9 --- kernel/sched/sched.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 521ae77b34c8..1acc2fe1199b 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -628,7 +628,7 @@ struct root_domain { cpumask_var_t online; /* Indicate more than one runnable task for any CPU */ - bool overload; + int overload; /* * The bit corresponding to a CPU gets set here if such CPU has more @@ -1655,7 +1655,7 @@ static inline void add_nr_running(struct rq *rq, unsigned count) if (prev_nr < 2 && rq->nr_running >= 2) { #ifdef CONFIG_SMP if (!rq->rd->overload) - rq->rd->overload = true; + rq->rd->overload = 1; #endif } -- GitLab From 907139485794dd7922a9632ab3507bb6a16e562e Mon Sep 17 00:00:00 2001 From: Valentin Schneider Date: Tue, 27 Feb 2018 16:20:21 +0000 Subject: [PATCH 0018/1001] FROMLIST: sched: Wrap rq->rd->overload accesses with READ/WRITE_ONCE This variable can be read and set locklessly within update_sd_lb_stats(). As such, READ/WRITE_ONCE are added to make sure nothing terribly wrong can happen because of the compiler. cc: Ingo Molnar cc: Peter Zijlstra Signed-off-by: Valentin Schneider [from https://lore.kernel.org/lkml/1530699470-29808-9-git-send-email-morten.rasmussen@arm.com/] Signed-off-by: Valentin Schneider Signed-off-by: Chris Redpath Change-Id: I14ce007f916bffd6a7938b7d56faf2b384d27887 --- kernel/sched/fair.c | 6 +++--- kernel/sched/sched.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index c848d5b2acae..ee33f162b3c6 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -9332,8 +9332,8 @@ static inline void update_sd_lb_stats(struct lb_env *env, struct sd_lb_stats *sd if (!lb_sd_parent(env->sd)) { /* update overload indicator if we are at root domain */ - if (env->dst_rq->rd->overload != overload) - env->dst_rq->rd->overload = overload; + if (READ_ONCE(env->dst_rq->rd->overload) != overload) + WRITE_ONCE(env->dst_rq->rd->overload, overload); } if (overutilized) @@ -10206,7 +10206,7 @@ static int idle_balance(struct rq *this_rq, struct rq_flags *rf) rq_unpin_lock(this_rq, rf); if (this_rq->avg_idle < sysctl_sched_migration_cost || - !this_rq->rd->overload) { + !READ_ONCE(this_rq->rd->overload)) { rcu_read_lock(); sd = rcu_dereference_check_sched_domain(this_rq->sd); if (sd) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 1acc2fe1199b..36a0008d1868 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1654,8 +1654,8 @@ static inline void add_nr_running(struct rq *rq, unsigned count) if (prev_nr < 2 && rq->nr_running >= 2) { #ifdef CONFIG_SMP - if (!rq->rd->overload) - rq->rd->overload = 1; + if (!READ_ONCE(rq->rd->overload)) + WRITE_ONCE(rq->rd->overload, 1); #endif } -- GitLab From 96a2daab1f375d9ca8c16fc5c721ea3fd60cb182 Mon Sep 17 00:00:00 2001 From: Valentin Schneider Date: Tue, 27 Feb 2018 16:56:41 +0000 Subject: [PATCH 0019/1001] FROMLIST: sched/fair: Set rq->rd->overload when misfit Idle balance is a great opportunity to pull a misfit task. However, there are scenarios where misfit tasks are present but idle balance is prevented by the overload flag. A good example of this is a workload of n identical tasks. Let's suppose we have a 2+2 Arm big.LITTLE system. We then spawn 4 fairly CPU-intensive tasks - for the sake of simplicity let's say they are just CPU hogs, even when running on big CPUs. They are identical tasks, so on an SMP system they should all end at (roughly) the same time. However, in our case the LITTLE CPUs are less performing than the big CPUs, so tasks running on the LITTLEs will have a longer completion time. This means that the big CPUs will complete their work earlier, at which point they should pull the tasks from the LITTLEs. What we want to happen is summarized as follows: a,b,c,d are our CPU-hogging tasks _ signifies idling LITTLE_0 | a a a a _ _ LITTLE_1 | b b b b _ _ ---------|------------- big_0 | c c c c a a big_1 | d d d d b b ^ ^ Tasks end on the big CPUs, idle balance happens and the misfit tasks are pulled straight away This however won't happen, because currently the overload flag is only set when there is any CPU that has more than one runnable task - which may very well not be the case here if our CPU-hogging workload is all there is to run. As such, this commit sets the overload flag in update_sg_lb_stats when a group is flagged as having a misfit task. cc: Ingo Molnar cc: Peter Zijlstra Signed-off-by: Valentin Schneider [from https://lore.kernel.org/lkml/1530699470-29808-10-git-send-email-morten.rasmussen@arm.com/] Signed-off-by: Valentin Schneider Signed-off-by: Chris Redpath Change-Id: I131f9ad90f7fb53f4946f61f2fb65ab0798f23c5 --- kernel/sched/fair.c | 7 +++++-- kernel/sched/sched.h | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index ee33f162b3c6..09304850e3c8 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -9027,7 +9027,7 @@ group_type group_classify(struct sched_group *group, * @load_idx: Load index of sched_domain of this_cpu for load calc. * @local_group: Does group contain this_cpu. * @sgs: variable to hold the statistics for this group. - * @overload: Indicate more than one runnable task for any CPU. + * @overload: Indicate pullable load (e.g. >1 runnable task). * @overutilized: Indicate overutilization for any CPU. */ static inline void update_sg_lb_stats(struct lb_env *env, @@ -9069,8 +9069,11 @@ static inline void update_sg_lb_stats(struct lb_env *env, sgs->idle_cpus++; if (env->sd->flags & SD_ASYM_CPUCAPACITY && - sgs->group_misfit_task_load < rq->misfit_task_load) + sgs->group_misfit_task_load < rq->misfit_task_load) { sgs->group_misfit_task_load = rq->misfit_task_load; + *overload = 1; + } + if (cpu_overutilized(i)) { *overutilized = true; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 36a0008d1868..74ec445d7e2e 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -627,7 +627,11 @@ struct root_domain { cpumask_var_t span; cpumask_var_t online; - /* Indicate more than one runnable task for any CPU */ + /* + * Indicate pullable load on at least one CPU, e.g: + * - More than one runnable task + * - Running task is misfit + */ int overload; /* -- GitLab From 052f19c502a41e50a95d50c06db5ba0a58358620 Mon Sep 17 00:00:00 2001 From: Morten Rasmussen Date: Thu, 28 Jun 2018 16:34:35 +0100 Subject: [PATCH 0020/1001] FROMLIST: sched/core: Disable SD_ASYM_CPUCAPACITY for root_domains without asymmetry When hotplugging cpus out or creating exclusive cpusets systems which were asymmetric at boot might become symmetric. In this case leaving the flag set might lead to suboptimal scheduling decisions. The arch-code proving the flag doesn't have visibility of the cpuset configuration so it must either be told by passing a cpumask or by letting the generic topology code verify if the flag should still be set when taking the actual sched_domain_span() into account. This patch implements the latter approach. Signed-off-by: Morten Rasmussen [from https://lore.kernel.org/lkml/1530699470-29808-12-git-send-email-morten.rasmussen@arm.com/] Signed-off-by: Valentin Schneider Signed-off-by: Chris Redpath Change-Id: I6a369e474743c96fe0b866ebb084e0a250e8c5d7 --- kernel/sched/topology.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c index af01a95093ca..678f87b2c3cc 100644 --- a/kernel/sched/topology.c +++ b/kernel/sched/topology.c @@ -1306,6 +1306,26 @@ sd_init(struct sched_domain_topology_level *tl, cpumask_and(sched_domain_span(sd), cpu_map, tl->mask(cpu)); sd_id = cpumask_first(sched_domain_span(sd)); + /* + * Check if cpu_map eclipses cpu capacity asymmetry. + */ + + if (sd->flags & SD_ASYM_CPUCAPACITY) { + long capacity = arch_scale_cpu_capacity(NULL, sd_id); + bool disable = true; + int i; + + for_each_cpu(i, sched_domain_span(sd)) { + if (capacity != arch_scale_cpu_capacity(NULL, i)) { + disable = false; + break; + } + } + + if (disable) + sd->flags &= ~SD_ASYM_CPUCAPACITY; + } + /* * Convert topological properties into behaviour. */ @@ -2085,4 +2105,3 @@ void partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[], mutex_unlock(&sched_domains_mutex); } - -- GitLab From b45d82a276a0375cf9368dfc2bb0094130537b06 Mon Sep 17 00:00:00 2001 From: Morten Rasmussen Date: Thu, 28 Jun 2018 17:31:25 +0100 Subject: [PATCH 0021/1001] FROMLIST: sched/core: Disable SD_PREFER_SIBLING on asymmetric cpu capacity domains The 'prefer sibling' sched_domain flag is intended to encourage spreading tasks to sibling sched_domain to take advantage of more caches and core for SMT systems. It has recently been changed to be on all non-NUMA topology level. However, spreading across domains with cpu capacity asymmetry isn't desirable, e.g. spreading from high capacity to low capacity cpus even if high capacity cpus aren't overutilized might give access to more cache but the cpu will be slower and possibly lead to worse overall throughput. To prevent this, we need to remove SD_PREFER_SIBLING on the sched_domain level immediately below SD_ASYM_CPUCAPACITY. Signed-off-by: Morten Rasmussen [from https://lore.kernel.org/lkml/1530699470-29808-13-git-send-email-morten.rasmussen@arm.com/] Signed-off-by: Valentin Schneider Signed-off-by: Chris Redpath Change-Id: I944a003c7b685132c57a90a8aaf85509196679e6 --- kernel/sched/topology.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c index 678f87b2c3cc..8a9be7d4d286 100644 --- a/kernel/sched/topology.c +++ b/kernel/sched/topology.c @@ -1287,7 +1287,7 @@ sd_init(struct sched_domain_topology_level *tl, | 0*SD_SHARE_CPUCAPACITY | 0*SD_SHARE_PKG_RESOURCES | 0*SD_SERIALIZE - | 0*SD_PREFER_SIBLING + | 1*SD_PREFER_SIBLING | 0*SD_NUMA | sd_flags , @@ -1333,12 +1333,17 @@ sd_init(struct sched_domain_topology_level *tl, if (sd->flags & SD_ASYM_CPUCAPACITY) { struct sched_domain *t = sd; + /* + * Don't attempt to spread across cpus of different capacities. + */ + if (sd->child) + sd->child->flags &= ~SD_PREFER_SIBLING; + for_each_lower_domain(t) t->flags |= SD_BALANCE_WAKE; } if (sd->flags & SD_SHARE_CPUCAPACITY) { - sd->flags |= SD_PREFER_SIBLING; sd->imbalance_pct = 110; sd->smt_gain = 1178; /* ~15% */ @@ -1353,6 +1358,7 @@ sd_init(struct sched_domain_topology_level *tl, sd->busy_idx = 3; sd->idle_idx = 2; + sd->flags &= ~SD_PREFER_SIBLING; sd->flags |= SD_SERIALIZE; if (sched_domains_numa_distance[tl->numa_level] > RECLAIM_DISTANCE) { sd->flags &= ~(SD_BALANCE_EXEC | @@ -1362,7 +1368,6 @@ sd_init(struct sched_domain_topology_level *tl, #endif } else { - sd->flags |= SD_PREFER_SIBLING; sd->cache_nice_tries = 1; sd->busy_idx = 2; sd->idle_idx = 1; -- GitLab From 07e7ce6c8459defc34e63ae0f0334e811d223990 Mon Sep 17 00:00:00 2001 From: Chris Redpath Date: Wed, 30 May 2018 13:16:41 +0100 Subject: [PATCH 0022/1001] FROMLIST: sched/fair: Don't move tasks to lower capacity cpus unless necessary When lower capacity CPUs are load balancing and considering to pull something from a higher capacity group, we should not pull tasks from a cpu with only one task running as this is guaranteed to impede progress for that task. If there is more than one task running, load balance in the higher capacity group would have already made any possible moves to resolve imbalance and we should make better use of system compute capacity by moving a task if we still have more than one running. cc: Ingo Molnar cc: Peter Zijlstra Signed-off-by: Chris Redpath Signed-off-by: Morten Rasmussen [from https://lore.kernel.org/lkml/1530699470-29808-11-git-send-email-morten.rasmussen@arm.com/] Signed-off-by: Chris Redpath Change-Id: Ib86570abdd453a51be885b086c8d80be2773a6f2 --- kernel/sched/fair.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 09304850e3c8..23c5ce715dcc 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -9740,6 +9740,17 @@ static struct rq *find_busiest_queue(struct lb_env *env, capacity = capacity_of(i); + /* + * For ASYM_CPUCAPACITY domains, don't pick a cpu that could + * eventually lead to active_balancing high->low capacity. + * Higher per-cpu capacity is considered better than balancing + * average load. + */ + if (env->sd->flags & SD_ASYM_CPUCAPACITY && + capacity_of(env->dst_cpu) < capacity && + rq->nr_running == 1) + continue; + wl = weighted_cpuload(rq); /* -- GitLab From 9fae72e924961f3b32816193fcb56d19c1f644c2 Mon Sep 17 00:00:00 2001 From: Chris Redpath Date: Fri, 1 Jun 2018 20:34:10 +0100 Subject: [PATCH 0023/1001] ANDROID: sched/fair: Attempt to improve throughput for asym cap systems In some systems the capacity and group weights line up to defeat all the small imbalance correction conditions in fix_small_imbalance, which can cause bad task placement. Add a new condition if the existing code can't see anything to fix: If we have asymmetric capacity, and there are more tasks than CPUs in the busiest group *and* there are less tasks than CPUs in the local group then we try to pull something. There could be transient small tasks which prevent this from working, but on the whole it is beneficial for those systems with inconvenient capacity/cluster size relationships. Signed-off-by: Chris Redpath Change-Id: Icf81cde215c082a61f816534b7990ccb70aee409 --- kernel/sched/fair.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 23c5ce715dcc..e03ca45f5ccd 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -9492,7 +9492,22 @@ void fix_small_imbalance(struct lb_env *env, struct sd_lb_stats *sds) capa_move /= SCHED_CAPACITY_SCALE; /* Move if we gain throughput */ - if (capa_move > capa_now) + if (capa_move > capa_now) { + env->imbalance = busiest->load_per_task; + return; + } + + /* We can't see throughput improvement with the load-based + * method, but it is possible depending upon group size and + * capacity range that there might still be an underutilized + * cpu available in an asymmetric capacity system. Do one last + * check just in case. + */ + if (env->sd->flags & SD_ASYM_CPUCAPACITY && + busiest->group_type == group_overloaded && + busiest->sum_nr_running > busiest->group_weight && + local->sum_nr_running < local->group_weight && + local->group_capacity < busiest->group_capacity) env->imbalance = busiest->load_per_task; } -- GitLab From 37e94467884b9ab3552a4309c97985b9ec067d76 Mon Sep 17 00:00:00 2001 From: Chris Redpath Date: Tue, 5 Jun 2018 11:47:57 +0100 Subject: [PATCH 0024/1001] ANDROID: sched/fair: Don't balance misfits if it would overload local group When load balancing in a system with misfit tasks present, if we always pull a misfit task to the local group this can lead to pulling a running task from a smaller capacity CPUs to a bigger CPU which is busy. In this situation, the pulled task is likely not to get a chance to run before an idle balance on another small CPU pulls it back. This penalises the pulled task as it is stopped for a short amount of time and then likely relocated to a different CPU (since the original CPU just did a NEWLY_IDLE balance and reset the periodic interval). If we only do this unconditionally for NEWLY_IDLE balance, we can be sure that any tasks and load which are present on the local group are related to short-running tasks which we are happy to displace for a longer running task in a system with misfit tasks present. However, other balance types should only pull a task if we think that the local group is underutilized - checking the number of tasks gives us a conservative estimate here since if they were short tasks we would have been doing NEWLY_IDLE balances instead. Signed-off-by: Chris Redpath Change-Id: I710add1ab1139482620b6addc8370ad194791beb --- kernel/sched/fair.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index e03ca45f5ccd..2f2c4b69b3e9 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -9576,8 +9576,18 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s (sds->avg_load - local->avg_load) * local->group_capacity ) / SCHED_CAPACITY_SCALE; - /* Boost imbalance to allow misfit task to be balanced. */ - if (busiest->group_type == group_misfit_task) { + /* Boost imbalance to allow misfit task to be balanced. + * Always do this if we are doing a NEWLY_IDLE balance + * on the assumption that any tasks we have must not be + * long-running (and hence we cannot rely upon load). + * However if we are not idle, we should assume the tasks + * we have are longer running and not override load-based + * calculations above unless we are sure that the local + * group is underutilized. + */ + if (busiest->group_type == group_misfit_task && + (env->idle == CPU_NEWLY_IDLE || + local->sum_nr_running < local->group_weight)) { env->imbalance = max_t(long, env->imbalance, busiest->group_misfit_task_load); } -- GitLab From fcfb6e412d77e82816a93b8cd2776025f37f1396 Mon Sep 17 00:00:00 2001 From: Chris Redpath Date: Tue, 5 Jun 2018 12:21:33 +0100 Subject: [PATCH 0025/1001] ANDROID: sched/fair: Also do misfit in overloaded groups If we can classify the group as overloaded, that overrides any classification as misfit but we may still have misfit tasks present. Check the rq we're looking at to see if this is the case. Signed-off-by: Chris Redpath [Removed stray reference to rq_has_misfit] Signed-off-by: Valentin Schneider Change-Id: Ida8eb66aa625e34de3fe2ee1b0dd8a78926273d8 --- kernel/sched/fair.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 2f2c4b69b3e9..61b7bcce11c8 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -9854,6 +9854,10 @@ static int need_active_balance(struct lb_env *env) if (env->src_grp_type == group_misfit_task) return 1; + if (env->src_grp_type == group_overloaded && + env->src_rq->misfit_task_load) + return 1; + return unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2); } -- GitLab From 98d51aa17757367052ff2ce7bf31b388d29cb2f0 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Thu, 8 Feb 2018 16:43:45 +0530 Subject: [PATCH 0026/1001] ANDROID: sched/fair: fix CPU selection for non latency sensitive tasks The Non latency sensitive tasks CPU selection targets for an active CPU in the little cluster. The shallowest c-state CPU is stored as a backup. However if all CPUs in the little cluster are idle, we pick an active CPU in the BIG cluster as the target CPU. This incorrect choice of the target CPU may not get corrected by the select_energy_cpu_idx() depending on the energy difference between previous CPU and target CPU. This can be fixed easily by maintaining the same variable that tracks maximum capacity of the traversed CPU for both idle and active CPUs. Change-Id: I3efb8bc82ff005383163921ef2bd39fcac4589ad Signed-off-by: Pavankumar Kondeti --- kernel/sched/fair.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 61b7bcce11c8..58fe4fc13105 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6908,7 +6908,6 @@ static int start_cpu(bool boosted) static inline int find_best_target(struct task_struct *p, int *backup_cpu, bool boosted, bool prefer_idle) { - unsigned long best_idle_min_cap_orig = ULONG_MAX; unsigned long min_util = boosted_task_util(p); unsigned long target_capacity = ULONG_MAX; unsigned long min_wake_util = ULONG_MAX; @@ -7052,6 +7051,13 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, (capacity_orig * SCHED_CAPACITY_SCALE)) continue; + /* + * Favor CPUs with smaller capacity for non latency + * sensitive tasks. + */ + if (capacity_orig > target_capacity) + continue; + /* * Case B) Non latency sensitive tasks on IDLE CPUs. * @@ -7079,10 +7085,6 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, if (idle_cpu(i)) { int idle_idx = idle_get_state_idx(cpu_rq(i)); - /* Select idle CPU with lower cap_orig */ - if (capacity_orig > best_idle_min_cap_orig) - continue; - /* * Skip CPUs in deeper idle state, but only * if they are also less energy efficient. @@ -7093,8 +7095,7 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, best_idle_cstate <= idle_idx) continue; - /* Keep track of best idle CPU */ - best_idle_min_cap_orig = capacity_orig; + target_capacity = capacity_orig; best_idle_cstate = idle_idx; best_idle_cpu = i; continue; @@ -7120,10 +7121,6 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, * capacity. */ - /* Favor CPUs with smaller capacity */ - if (capacity_orig > target_capacity) - continue; - /* Favor CPUs with maximum spare capacity */ if ((capacity_orig - new_util) < target_max_spare_cap) continue; -- GitLab From 03429a533a2d3887c9306db5c3055dd7643c6d97 Mon Sep 17 00:00:00 2001 From: Ionela Voinescu Date: Thu, 15 Mar 2018 12:45:05 +0000 Subject: [PATCH 0027/1001] ANDROID:sched/fair: prefer energy efficient CPUs for !prefer_idle tasks For !prefer_idle tasks we want to minimize capacity_orig to bias their scheduling towards more energy efficient CPUs. This does not happen in the current code for boosted tasks due the order of CPUs considered (from big CPUs to LITTLE CPUs), and to the shallow idle state and spare capacity maximization filters, which are used to select the best idle backup CPU and the best active CPU candidates. Let's fix this by enabling the above filters only when we are within same capacity CPUs. Taking in part each of the two cases: 1. Selection of a backup idle CPU - Non prefer_idle tasks should prefer more energy efficient CPUs when there are idle CPUs in the system, independent of the order given by the presence of a boosted margin. This is the behavior for !sysctl_sched_cstate_aware and this should be the behaviour for when sysctl_sched_cstate_aware is set as well, given that we should prefer a more efficient CPU even if it's in a deeper idle state. 2. Selection of an active target CPU: There is no reason for boosted tasks to benefit from a higher chance to be placed on big CPU which is provided by ordering CPUs from bigs to littles. The other mechanism in place set for boosted tasks (making sure we select a CPU that fits the task) is enough for a non latency sensitive case. Also, by choosing a CPU with maximum spare capacity we also cover the preference towards spreading tasks, rather than packing them, which improves the chances for tasks to get better performance due to potential reduced preemption. Therefore, prefer more energy efficient CPUs and only consider spare capacity for CPUs with equal capacity_orig. Change-Id: I3b97010e682674420015e771f0717192444a63a2 Signed-off-by: Ionela Voinescu Signed-off-by: Patrick Bellasi Reviewed-by: Patrick Bellasi Reported-by: Viresh Kumar Reported-by: Leo Yan --- kernel/sched/fair.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 58fe4fc13105..598bfecb8101 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -7091,7 +7091,8 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, * IOW, prefer a deep IDLE LITTLE CPU vs a * shallow idle big CPU. */ - if (sysctl_sched_cstate_aware && + if (capacity_orig == target_capacity && + sysctl_sched_cstate_aware && best_idle_cstate <= idle_idx) continue; @@ -7122,7 +7123,8 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, */ /* Favor CPUs with maximum spare capacity */ - if ((capacity_orig - new_util) < target_max_spare_cap) + if (capacity_orig == target_capacity && + (capacity_orig - new_util) < target_max_spare_cap) continue; target_max_spare_cap = capacity_orig - new_util; -- GitLab From 5383285d1358ea595a14436e6f14415fd0c1fa0e Mon Sep 17 00:00:00 2001 From: Ionela Voinescu Date: Fri, 27 Apr 2018 18:19:13 +0100 Subject: [PATCH 0028/1001] ANDROID: sched/fair: unify spare capacity calculation Given that we have a few sites where the spare capacity of a CPU is calculated as the difference between the original capacity of the CPU and its computed new utilization, let's unify the calculation and use that value tracked with a local spare_cap variable. Change-Id: I78daece7543f78d4f74edbee5e9ceb62908af507 Signed-off-by: Ionela Voinescu --- kernel/sched/fair.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 598bfecb8101..eb517f935da2 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6941,6 +6941,7 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, unsigned long capacity_curr = capacity_curr_of(i); unsigned long capacity_orig = capacity_orig_of(i); unsigned long wake_util, new_util; + long spare_cap; if (!cpu_online(i)) continue; @@ -6965,6 +6966,13 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, if (new_util > capacity_orig) continue; + /* + * Pre-compute the maximum possible capacity we expect + * to have available on this CPU once the task is + * enqueued here. + */ + spare_cap = capacity_orig - new_util; + /* * Case A) Latency sensitive tasks * @@ -7012,9 +7020,9 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, * Case A.2: Target ACTIVE CPU * Favor CPUs with max spare capacity. */ - if ((capacity_curr > new_util) && - (capacity_orig - new_util > target_max_spare_cap)) { - target_max_spare_cap = capacity_orig - new_util; + if (capacity_curr > new_util && + spare_cap > target_max_spare_cap) { + target_max_spare_cap = spare_cap; target_cpu = i; continue; } @@ -7124,10 +7132,10 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, /* Favor CPUs with maximum spare capacity */ if (capacity_orig == target_capacity && - (capacity_orig - new_util) < target_max_spare_cap) + spare_cap < target_max_spare_cap) continue; - target_max_spare_cap = capacity_orig - new_util; + target_max_spare_cap = spare_cap; target_capacity = capacity_orig; target_util = new_util; target_cpu = i; -- GitLab From 19c03afff2992f3553cfef445e9404262d68a67a Mon Sep 17 00:00:00 2001 From: Ionela Voinescu Date: Mon, 19 Mar 2018 18:03:45 +0000 Subject: [PATCH 0029/1001] ANDROID: sched/fair: remove order from CPU selection find_best_target is currently split into code handling latency sensitive tasks and code handling non-latency sensitive tasks based on the value of the prefer_idle flag. Another differentiation is done for boosted tasks, preferring to start with higher-capacity CPU when boosted, and with more efficient CPUs when not boosted. This additional differentiation is obtained by imposing an order when considering CPUs for selection. This order is determined in typical big.LITTLE systems by the start point (the CPU with the maximum or minimum capacity) and by the order of big and little CPU groups provided in the sched domain hierarchy. However, it's not guaranteed that the sched domain hierarchy will give us a sorted list of CPU groups based on their maximum capacities when dealing with systems with more than 2 capacity groups. For example, if we consider a system with three groups of CPUs (LITTLEs, mediums, bigs), the sched domain hierarchy might provide the following scheduling groups ordering for a prefer_idle-boosted task: big CPUs -> LITTLE CPUs -> medium CPUs. If the big CPUs are not idle, but there are a few LITTLEs and mediums as idle CPUs, by returning the first idle CPU, we will be incorrectly prefering a lower capacity CPU over a higher capacity CPU. In order to eliminate this reliance on assuming sched groups are ordered by capacity, let's: 1. Iterate though all candidate CPUs for all cases. 2. Minimise or maximise the capacity of the considered CPU, depending on prefer_idle and boost information. Taking in part each of the four possible cases we analyse the implementation and impact of this solution: 1. prefer_idle and boosted This type of tasks needs to favour the selection of a reserved idle CPU, and thus we still start from the biggest CPU in the system, but we iterate though all CPUs as to correctly handle the example above by maximising the capacity of the idle CPU we select. When all CPUs are active, we already iterate though all CPUs and we're able to maximise spare capacity or minimise utilisation for the considered target or backup CPU. 2. prefer_idle and !boosted For these tasks we prefer the selection of a more energy efficient CPU and therefore we start from the smallest CPUs in the system, but we iterate through all the CPUs as to select the most energy efficient idle CPU, implementation which mimics existing behaviour. When all CPUs are active, we already iterate though all CPUs and we're able to maximise spare capacity or minimise utilisation for the considered target or backup CPU. 3. !prefer_idle and boosted and 4. !prefer_idle and !boosted For these tasks we already iterate though all CPUs and we're able to maximise the energy efficiency of the selected CPU. Change-Id: I940399e22eff29453cba0e2ec52a03b17eec12ae Signed-off-by: Ionela Voinescu Signed-off-by: Patrick Bellasi Reviewed-by: Patrick Bellasi --- kernel/sched/fair.c | 47 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index eb517f935da2..9593e5c31967 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6924,6 +6924,18 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, *backup_cpu = -1; + /* + * In most cases, target_capacity tracks capacity_orig of the most + * energy efficient CPU candidate, thus requiring to minimise + * target_capacity. For these cases target_capacity is already + * initialized to ULONG_MAX. + * However, for prefer_idle and boosted tasks we look for a high + * performance CPU, thus requiring to maximise target_capacity. In this + * case we initialise target_capacity to 0. + */ + if (prefer_idle && boosted) + target_capacity = 0; + /* Find start CPU based on boost value */ cpu = start_cpu(boosted); if (cpu < 0) @@ -7005,16 +7017,26 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, /* * Case A.1: IDLE CPU - * Return the first IDLE CPU we find. + * Return the best IDLE CPU we find: + * - for boosted tasks: the CPU with the highest + * performance (i.e. biggest capacity_orig) + * - for !boosted tasks: the most energy + * efficient CPU (i.e. smallest capacity_orig) */ if (idle_cpu(i)) { - trace_sched_find_best_target(p, - prefer_idle, min_util, - cpu, best_idle_cpu, - best_active_cpu, i); - - return i; + if (boosted && + capacity_orig <= target_capacity) + continue; + if (!boosted && + capacity_orig >= target_capacity) + continue; + + target_capacity = capacity_orig; + best_idle_cpu = i; + continue; } + if (best_idle_cpu != -1) + continue; /* * Case A.2: Target ACTIVE CPU @@ -7152,7 +7174,7 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, * * - prefer_idle tasks: * - * a) IDLE CPU available, we return immediately + * a) IDLE CPU available: best_idle_cpu * b) ACTIVE CPU where task fits and has the bigger maximum spare * capacity (i.e. target_cpu) * c) ACTIVE CPU with less contention due to other tasks @@ -7163,6 +7185,15 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, * a) ACTIVE CPU: target_cpu * b) IDLE CPU: best_idle_cpu */ + + if (prefer_idle && (best_idle_cpu != -1)) { + trace_sched_find_best_target(p, prefer_idle, min_util, cpu, + best_idle_cpu, best_active_cpu, + best_idle_cpu); + + return best_idle_cpu; + } + if (target_cpu == -1) target_cpu = prefer_idle ? best_active_cpu -- GitLab From 5f574ff1c8c75ef5d561b3f07d3f0b111976f8e3 Mon Sep 17 00:00:00 2001 From: Ionela Voinescu Date: Fri, 27 Apr 2018 18:38:00 +0100 Subject: [PATCH 0030/1001] ANDROID: sched/fair: add idle state filter to prefer_idle case The CPU selection process for a prefer_idle task either minimizes or maximizes the CPU capacity for idle CPUs depending on the task being boosted or not. Given that we are iterating through all CPUs, additionally filter the choice by preferring a CPU in a more shallow idle state. This will provide both a faster wake-up for the task and higher energy efficiency, by allowing CPUs in deeper idle states to remain idle. Change-Id: Ic55f727a0c551adc0af8e6ee03de6a41337a571b Signed-off-by: Ionela Voinescu --- kernel/sched/fair.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 9593e5c31967..7070a0b4b966 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6954,6 +6954,7 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, unsigned long capacity_orig = capacity_orig_of(i); unsigned long wake_util, new_util; long spare_cap; + int idle_idx = INT_MAX; if (!cpu_online(i)) continue; @@ -6985,6 +6986,10 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, */ spare_cap = capacity_orig - new_util; + if (idle_cpu(i)) + idle_idx = idle_get_state_idx(cpu_rq(i)); + + /* * Case A) Latency sensitive tasks * @@ -7025,13 +7030,18 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, */ if (idle_cpu(i)) { if (boosted && - capacity_orig <= target_capacity) + capacity_orig < target_capacity) continue; if (!boosted && - capacity_orig >= target_capacity) + capacity_orig > target_capacity) + continue; + if (capacity_orig == target_capacity && + sysctl_sched_cstate_aware && + best_idle_cstate <= idle_idx) continue; target_capacity = capacity_orig; + best_idle_cstate = idle_idx; best_idle_cpu = i; continue; } @@ -7113,8 +7123,6 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, * consumptions without affecting performance. */ if (idle_cpu(i)) { - int idle_idx = idle_get_state_idx(cpu_rq(i)); - /* * Skip CPUs in deeper idle state, but only * if they are also less energy efficient. -- GitLab From dc6f7513623fe5fb4be5018cf334caee5b9ca039 Mon Sep 17 00:00:00 2001 From: Chris Redpath Date: Fri, 8 Jun 2018 17:16:50 +0100 Subject: [PATCH 0031/1001] ANDROID: sched/fair: return idle CPU immediately for prefer_idle When a CPU is selected for a prefer_idle task through find_best_target this CPU will become a target CPU on which we perform an energy diff and select between the previous CPU and the target CPU based on the estimated energy consumption for both placements. For prefer_idle tasks we should favour performance over energy savings and therefore return a found idle CPU immediately. Change-Id: I2242a51134ac172dd58b3b08375388a7b4b84af0 Signed-off-by: Ionela Voinescu Signed-off-by: Chris Redpath Suggested-by: Joel Fernandes --- kernel/sched/fair.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 7070a0b4b966..562d686b5389 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -7391,7 +7391,7 @@ static int find_energy_efficient_cpu(struct sched_domain *sd, { int use_fbt = sched_feat(FIND_BEST_TARGET); int cpu_iter, eas_cpu_idx = EAS_CPU_NXT; - int energy_cpu = -1; + int target_cpu = -1; struct energy_env *eenv; if (sysctl_sched_sync_hint_enable && sync) { @@ -7403,7 +7403,7 @@ static int find_energy_efficient_cpu(struct sched_domain *sd, /* prepopulate energy diff environment */ eenv = get_eenv(p, prev_cpu); if (eenv->max_cpu_count < 2) - return energy_cpu; + return -1; if(!use_fbt) { /* @@ -7448,9 +7448,15 @@ static int find_energy_efficient_cpu(struct sched_domain *sd, eenv->max_cpu_count = EAS_CPU_BKP + 1; /* Find a cpu with sufficient capacity */ - eenv->cpu[EAS_CPU_NXT].cpu_id = find_best_target(p, - &eenv->cpu[EAS_CPU_BKP].cpu_id, - boosted, prefer_idle); + target_cpu = find_best_target(p, &eenv->cpu[EAS_CPU_BKP].cpu_id, + boosted, prefer_idle); + + /* Immediately return a found idle CPU for a prefer_idle task */ + if (prefer_idle && target_cpu >= 0 && idle_cpu(target_cpu)) + return target_cpu; + + /* Place target into NEXT slot */ + eenv->cpu[EAS_CPU_NXT].cpu_id = target_cpu; /* take note if no backup was found */ if (eenv->cpu[EAS_CPU_BKP].cpu_id < 0) @@ -7467,14 +7473,14 @@ static int find_energy_efficient_cpu(struct sched_domain *sd, * candidates beyond prev_cpu, so we will * fall-back to the regular slow-path. */ - return energy_cpu; + return -1; } /* find most energy-efficient CPU */ - energy_cpu = select_energy_cpu_idx(eenv) < 0 ? -1 : + target_cpu = select_energy_cpu_idx(eenv) < 0 ? -1 : eenv->cpu[eenv->next_idx].cpu_id; - return energy_cpu; + return target_cpu; } static inline bool nohz_kick_needed(struct rq *rq, bool only_update); -- GitLab From 8fa863274cb41ca169ff14de48620c1f33599e9c Mon Sep 17 00:00:00 2001 From: Ionela Voinescu Date: Mon, 19 Mar 2018 15:29:51 +0000 Subject: [PATCH 0032/1001] ANDROID: update_group_capacity for single cpu in cluster If we're only left with one big CPU in a cluster (either there was only one to begin with or the others have been hotplugged out), the MC level seen from the perspective of that CPU, will only contain one group (that of the CPU) and the LOAD_BALANCE flag will be cleared at that level. The MC level is kept nonetheless as it will still contain energy information, as per commit 06654998ed81 ("ANDROID: sched: EAS & 'single cpu per cluster'/cpu hotplug interoperability"). This will result in update_cpu_capacity never being called for that big CPU and its capacity will never be updated. Also, its capacity will never be considered when setting or updating the max_cpu_capacity structure. Therefore, call update_group_capacity for SD levels that do not have the SD_LOAD_BALANCE flag set in order to update the CPU capacity information of CPUs that are alone in a cluster and the groups that they belong to. The call to update_cpu_capacity will also result in appropriately setting the values of the max_cpu_capacity structure. Fixes: 06654998ed81 ("ANDROID: sched: EAS & 'single cpu per cluster'/cpu hotplug interoperability") Change-Id: I6074972dde1fdf586378f8a3534e3d0aa42a809a Signed-off-by: Ionela Voinescu --- kernel/sched/fair.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 562d686b5389..53a19c46ce43 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -10319,8 +10319,12 @@ static int idle_balance(struct rq *this_rq, struct rq_flags *rf) int continue_balancing = 1; u64 t0, domain_cost; - if (!(sd->flags & SD_LOAD_BALANCE)) + if (!(sd->flags & SD_LOAD_BALANCE)) { + if (time_after_eq(jiffies, + sd->groups->sgc->next_update)) + update_group_capacity(sd, this_cpu); continue; + } if (this_rq->avg_idle < curr_cost + sd->max_newidle_lb_cost) { update_next_balance(sd, &next_balance); @@ -10655,8 +10659,12 @@ static void rebalance_domains(struct rq *rq, enum cpu_idle_type idle) if (energy_aware() && !sd_overutilized(sd)) continue; - if (!(sd->flags & SD_LOAD_BALANCE)) + if (!(sd->flags & SD_LOAD_BALANCE)) { + if (time_after_eq(jiffies, + sd->groups->sgc->next_update)) + update_group_capacity(sd, cpu); continue; + } /* * Stop the load balance at this level. There is another -- GitLab From 8377d3545e755d3a5ce6c975c1c564fccfd18b28 Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Sun, 11 Mar 2018 12:37:21 +0100 Subject: [PATCH 0033/1001] ANDROID: Separate cpu_scale and energy model setup Keep the cpu_scale calculation in the arch_topology driver the way it is done in mainline. This will require appropriate capacity-dmips-mhz properties in the dt file. Do the energy model setup completely separate in kernel/sched/energy.c. This will allow to adapt the non-mainline energy model code more easily. Signed-off-by: Dietmar Eggemann Change-Id: Ic69d9a619c0a57bb54e5aa6f320e95618394b7cb --- arch/arm/kernel/topology.c | 32 +++----------------------------- arch/arm64/kernel/topology.c | 10 ---------- drivers/base/arch_topology.c | 13 ++----------- include/linux/sched_energy.h | 1 - kernel/sched/energy.c | 19 ------------------- 5 files changed, 5 insertions(+), 70 deletions(-) diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c index a86e1057bd36..e26e1fb199dd 100644 --- a/arch/arm/kernel/topology.c +++ b/arch/arm/kernel/topology.c @@ -36,22 +36,12 @@ static inline const struct sched_group_energy * const cpu_core_energy(int cpu) { struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL0]; - unsigned long capacity; - int max_cap_idx; if (!sge) { pr_warn("Invalid sched_group_energy for CPU%d\n", cpu); return NULL; } - max_cap_idx = sge->nr_cap_states - 1; - capacity = sge->cap_states[max_cap_idx].cap; - - printk_deferred("cpu=%d set cpu scale %lu from energy model\n", - cpu, capacity); - - topology_set_cpu_scale(cpu, capacity); - return sge; } @@ -207,26 +197,10 @@ static void __init parse_dt_topology(void) */ static void update_cpu_capacity(unsigned int cpu) { - const struct sched_group_energy *sge; - unsigned long capacity; - - sge = cpu_core_energy(cpu); - - if (sge) { - int max_cap_idx; - - max_cap_idx = sge->nr_cap_states - 1; - capacity = sge->cap_states[max_cap_idx].cap; - - printk_deferred("cpu=%d set cpu scale %lu from energy model\n", - cpu, capacity); - } else { - if (!cpu_capacity(cpu) || cap_from_dt) - return; - capacity = cpu_capacity(cpu) / middle_capacity; - } + if (!cpu_capacity(cpu) || cap_from_dt) + return; - topology_set_cpu_scale(cpu, capacity); + topology_set_cpu_scale(cpu, cpu_capacity(cpu) / middle_capacity); pr_info("CPU%u: update cpu_capacity %lu\n", cpu, topology_get_cpu_scale(NULL, cpu)); diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index 35dbdfaa6129..cd0fc6b95280 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -309,22 +309,12 @@ static inline const struct sched_group_energy * const cpu_core_energy(int cpu) { struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL0]; - unsigned long capacity; - int max_cap_idx; if (!sge) { pr_warn("Invalid sched_group_energy for CPU%d\n", cpu); return NULL; } - max_cap_idx = sge->nr_cap_states - 1; - capacity = sge->cap_states[max_cap_idx].cap; - - printk_deferred("cpu=%d set cpu scale %lu from energy model\n", - cpu, capacity); - - topology_set_cpu_scale(cpu, capacity); - return sge; } diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index d711b85b55d6..972d11291549 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -73,10 +73,6 @@ static ssize_t cpu_capacity_store(struct device *dev, if (!count) return 0; - /* don't allow changes if sched-group-energy is installed */ - if(sched_energy_installed(this_cpu)) - return -EINVAL; - ret = kstrtoul(buf, 0, &new_capacity); if (ret) return ret; @@ -357,19 +353,14 @@ void topology_normalize_cpu_scale(void) bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu) { static bool cap_parsing_failed; - int ret = 0; + int ret; u32 cpu_capacity; if (cap_parsing_failed) return false; - /* override capacity-dmips-mhz if we have sched-energy-costs */ - if (of_find_property(cpu_node, "sched-energy-costs", NULL)) - cpu_capacity = topology_get_cpu_scale(NULL, cpu); - else - ret = of_property_read_u32(cpu_node, "capacity-dmips-mhz", + ret = of_property_read_u32(cpu_node, "capacity-dmips-mhz", &cpu_capacity); - if (!ret) { if (!raw_capacity) { raw_capacity = kcalloc(num_possible_cpus(), diff --git a/include/linux/sched_energy.h b/include/linux/sched_energy.h index 83d7178f8524..a9b0349dc018 100644 --- a/include/linux/sched_energy.h +++ b/include/linux/sched_energy.h @@ -33,7 +33,6 @@ extern struct sched_group_energy *sge_array[NR_CPUS][NR_SD_LEVELS]; #ifdef CONFIG_GENERIC_ARCH_TOPOLOGY void init_sched_energy_costs(void); -int sched_energy_installed(int cpu); #else void init_sched_energy_costs(void) {} #endif diff --git a/kernel/sched/energy.c b/kernel/sched/energy.c index e82248a665b8..31b7a919d0cc 100644 --- a/kernel/sched/energy.c +++ b/kernel/sched/energy.c @@ -48,21 +48,6 @@ static void free_resources(void) } } -static inline unsigned long cpu_max_capacity(int cpu) -{ - if (!sge_array[cpu][0]->cap_states) - return 1024; - if (!sge_array[cpu][0]->nr_cap_states) - return 1024; - - return sge_array[cpu][0]->cap_states[sge_array[cpu][0]->nr_cap_states-1].cap; -} - -int sched_energy_installed(int cpu) -{ - return (sge_array[cpu][0]->cap_states != NULL); -} - void init_sched_energy_costs(void) { struct device_node *cn, *cp; @@ -130,10 +115,6 @@ void init_sched_energy_costs(void) sge->idle_states = idle_states; sge_array[cpu][sd_level] = sge; - - /* populate cpu scale so that flags get set correctly */ - if (sd_level == 0) - topology_set_cpu_scale(cpu, cpu_max_capacity(cpu)); } } -- GitLab From ee517b4a776da10b46b542a30b84c61a766a8d88 Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Sun, 11 Mar 2018 13:02:20 +0100 Subject: [PATCH 0034/1001] ANDROID: Streamline sched_domain_energy_f functions There is no need to print that there is no sched group energy for a sched domain. It is e.g. perfectly fine to have an Energy Model on MC and DIE level and not on SYS level. The Energy Model consistency check between sched domains is done in init_sched_groups_energy(). In case a sched domain level (l) has energy data its child sched domain level (l-1) has to have energy data as well. Signed-off-by: Dietmar Eggemann Change-Id: Iff1ecc86720a310f4b96282c3f41931aee733af2 --- arch/arm/kernel/topology.c | 19 ++----------------- arch/arm64/kernel/topology.c | 27 +++------------------------ 2 files changed, 5 insertions(+), 41 deletions(-) diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c index e26e1fb199dd..aa1b3870e836 100644 --- a/arch/arm/kernel/topology.c +++ b/arch/arm/kernel/topology.c @@ -31,31 +31,16 @@ #include #include -/* sd energy functions */ static inline const struct sched_group_energy * const cpu_core_energy(int cpu) { - struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL0]; - - if (!sge) { - pr_warn("Invalid sched_group_energy for CPU%d\n", cpu); - return NULL; - } - - return sge; + return sge_array[cpu][SD_LEVEL0]; } static inline const struct sched_group_energy * const cpu_cluster_energy(int cpu) { - struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL1]; - - if (!sge) { - pr_warn("Invalid sched_group_energy for Cluster%d\n", cpu); - return NULL; - } - - return sge; + return sge_array[cpu][SD_LEVEL1]; } /* diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index cd0fc6b95280..a2dca5ff5298 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -308,40 +308,19 @@ static int cpu_flags(void) static inline const struct sched_group_energy * const cpu_core_energy(int cpu) { - struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL0]; - - if (!sge) { - pr_warn("Invalid sched_group_energy for CPU%d\n", cpu); - return NULL; - } - - return sge; + return sge_array[cpu][SD_LEVEL0]; } static inline const struct sched_group_energy * const cpu_cluster_energy(int cpu) { - struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL1]; - - if (!sge) { - pr_warn("Invalid sched_group_energy for Cluster%d\n", cpu); - return NULL; - } - - return sge; + return sge_array[cpu][SD_LEVEL1]; } static inline const struct sched_group_energy * const cpu_system_energy(int cpu) { - struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL2]; - - if (!sge) { - pr_warn("Invalid sched_group_energy for System%d\n", cpu); - return NULL; - } - - return sge; + return sge_array[cpu][SD_LEVEL2]; } static struct sched_domain_topology_level arm64_topology[] = { -- GitLab From 7424b86068cf9f7ca08238e809daf0af838d7008 Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Sun, 11 Mar 2018 22:35:08 +0100 Subject: [PATCH 0035/1001] ANDROID: Move energy model init call into arch_topology driver Now that we decouple the Energy Model (EM) from the cpu_scale calculation, initialize the EM after the cpu_scale calaculation has finished. Signed-off-by: Dietmar Eggemann Change-Id: Ia39c969f5c674e6e644951fd8b3e986d16cdab3b --- arch/arm/kernel/topology.c | 2 -- arch/arm64/kernel/topology.c | 2 -- drivers/base/arch_topology.c | 1 + 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c index aa1b3870e836..21dd02fa72d2 100644 --- a/arch/arm/kernel/topology.c +++ b/arch/arm/kernel/topology.c @@ -349,6 +349,4 @@ void __init init_cpu_topology(void) /* Set scheduler topology descriptor */ set_sched_topology(arm_topology); - - init_sched_energy_costs(); } diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index a2dca5ff5298..c61bc7797f7e 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -188,8 +188,6 @@ static int __init parse_dt_topology(void) if (!map) goto out; - init_sched_energy_costs(); - ret = parse_cluster(map, 0); if (ret != 0) goto out_map; diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 972d11291549..2612fb377743 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -422,6 +422,7 @@ init_cpu_capacity_callback(struct notifier_block *nb, if (cpumask_empty(cpus_to_visit)) { topology_normalize_cpu_scale(); + init_sched_energy_costs(); if (topology_detect_flags()) schedule_work(&update_topology_flags_work); free_raw_capacity(); -- GitLab From 465c96b1349d7b8af31edc522d1a1c53a4b9094a Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Sun, 11 Mar 2018 23:41:54 +0100 Subject: [PATCH 0036/1001] ANDROID: Check equality of max cap state cap and cpu scale The max cap state cpu capacity value has to be equal to the cpu scale value. Print out a warning if this is not the case. The Energy Model can be adjusted so that this warning disappears. Signed-off-by: Dietmar Eggemann Change-Id: I97fea5622ea8193154746a0b63aec30069eb9be5 --- kernel/sched/energy.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/kernel/sched/energy.c b/kernel/sched/energy.c index 31b7a919d0cc..02adff421779 100644 --- a/kernel/sched/energy.c +++ b/kernel/sched/energy.c @@ -48,6 +48,20 @@ static void free_resources(void) } } +void check_max_cap_vs_cpu_scale(int cpu, struct sched_group_energy *sge) +{ + unsigned long max_cap, cpu_scale; + + max_cap = sge->cap_states[sge->nr_cap_states - 1].cap; + cpu_scale = topology_get_cpu_scale(NULL, cpu); + + if (max_cap == cpu_scale) + return; + + pr_warn("CPU%d max energy model capacity=%ld != cpu_scale=%ld\n", cpu, + max_cap, cpu_scale); +} + void init_sched_energy_costs(void) { struct device_node *cn, *cp; @@ -116,6 +130,8 @@ void init_sched_energy_costs(void) sge_array[cpu][sd_level] = sge; } + + check_max_cap_vs_cpu_scale(cpu, sge_array[cpu][SD_LEVEL0]); } pr_info("Sched-energy-costs installed from DT\n"); -- GitLab From c0106a043c23220a0d332b06120a40a98a955f7d Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Sun, 11 Mar 2018 23:51:35 +0100 Subject: [PATCH 0037/1001] ANDROID: Adjust juno energy model The max cap state cpu capacity value (now 446) has to be equal to the cpu scale (446) value for the little cpus (A53). While add it, align the cap values betwenn core and cluster energy costs for the second lowest OPP to 302. Signed-off-by: Dietmar Eggemann Change-Id: Idffc696c0cac8175bc62e0216394cd96b75fa566 --- arch/arm64/boot/dts/arm/juno-sched-energy.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/arm/juno-sched-energy.dtsi b/arch/arm64/boot/dts/arm/juno-sched-energy.dtsi index 7ffb2554817b..221196ea2091 100644 --- a/arch/arm64/boot/dts/arm/juno-sched-energy.dtsi +++ b/arch/arm64/boot/dts/arm/juno-sched-energy.dtsi @@ -28,7 +28,7 @@ energy-costs { 302 46 368 61 406 76 - 447 93 + 446 93 >; idle-cost-data = < 6 @@ -55,10 +55,10 @@ energy-costs { CLUSTER_COST_A53: cluster-cost1 { busy-cost-data = < 235 26 - 303 30 + 302 30 368 39 406 47 - 447 57 + 446 57 >; idle-cost-data = < 56 -- GitLab From 75473ed034fd79433198c617437a3f84aa01c57a Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Sun, 11 Mar 2018 23:58:21 +0100 Subject: [PATCH 0038/1001] ANDROID: Rename and move include/linux/sched_energy.h Signed-off-by: Dietmar Eggemann Change-Id: I51401b94947c64feb598287a991eadf9de064340 --- arch/arm/kernel/topology.c | 2 +- arch/arm64/kernel/topology.c | 2 +- drivers/base/arch_topology.c | 2 +- include/linux/{sched_energy.h => sched/energy.h} | 0 kernel/sched/energy.c | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename include/linux/{sched_energy.h => sched/energy.h} (100%) diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c index 21dd02fa72d2..28ca1646a38a 100644 --- a/arch/arm/kernel/topology.c +++ b/arch/arm/kernel/topology.c @@ -23,9 +23,9 @@ #include #include #include +#include #include #include -#include #include #include diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index c61bc7797f7e..6eb9350be46f 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 2612fb377743..c4d101069af5 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -21,8 +21,8 @@ #include #include #include +#include #include -#include DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE; diff --git a/include/linux/sched_energy.h b/include/linux/sched/energy.h similarity index 100% rename from include/linux/sched_energy.h rename to include/linux/sched/energy.h diff --git a/kernel/sched/energy.c b/kernel/sched/energy.c index 02adff421779..be470c695293 100644 --- a/kernel/sched/energy.c +++ b/kernel/sched/energy.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include -- GitLab From df6f68dffb40654d144b33e00acf8ba9e08d0618 Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Sun, 25 Mar 2018 12:11:51 +0100 Subject: [PATCH 0039/1001] ANDROID: sched, trace: Remove trace event sched_load_avg_cpu The functionality of sched_load_avg_cpu can be provided by sched_load_cfs_rq. The WALT extension will be included into sched_load_cfs_rq by patch (ANDROID: trace: Add WALT util signal to trace event sched_load_cfs_rq). Signed-off-by: Dietmar Eggemann Change-Id: I2e3944a6e60a77e3237b7c8cb29cbd840118a6ad --- include/trace/events/sched.h | 37 ------------------------------------ kernel/sched/fair.c | 3 --- 2 files changed, 40 deletions(-) diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index ab8210bca863..96b3e50be78a 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -706,43 +706,6 @@ extern bool walt_disabled; } #endif -/* - * Tracepoint for accounting cpu root cfs_rq - */ -TRACE_EVENT(sched_load_avg_cpu, - - TP_PROTO(int cpu, struct cfs_rq *cfs_rq), - - TP_ARGS(cpu, cfs_rq), - - TP_STRUCT__entry( - __field( int, cpu ) - __field( unsigned long, load_avg ) - __field( unsigned long, util_avg ) - __field( unsigned long, util_avg_pelt ) - __field( unsigned long, util_avg_walt ) - ), - - TP_fast_assign( - __entry->cpu = cpu; - __entry->load_avg = cfs_rq->avg.load_avg; - __entry->util_avg = cfs_rq->avg.util_avg; - __entry->util_avg_pelt = cfs_rq->avg.util_avg; - __entry->util_avg_walt = 0; -#ifdef CONFIG_SCHED_WALT - walt_util(__entry->util_avg_walt, cpu_rq(cpu)->prev_runnable_sum); - if (!walt_disabled && sysctl_sched_use_walt_cpu_util) - __entry->util_avg = __entry->util_avg_walt; -#endif - ), - - TP_printk("cpu=%d load_avg=%lu util_avg=%lu " - "util_avg_pelt=%lu util_avg_walt=%lu", - __entry->cpu, __entry->load_avg, __entry->util_avg, - __entry->util_avg_pelt, __entry->util_avg_walt) -); - - /* * Tracepoint for sched_entity load tracking: */ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 53a19c46ce43..c7ddc9dccdd5 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -2830,9 +2830,6 @@ static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq) * See cpu_util(). */ cpufreq_update_util(rq, 0); -#ifdef CONFIG_SMP - trace_sched_load_avg_cpu(cpu_of(rq), cfs_rq); -#endif } } -- GitLab From 40bea171466d2c37d9c6340c8706a92a7abe1481 Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Sun, 25 Mar 2018 13:41:15 +0100 Subject: [PATCH 0040/1001] ANDROID: trace: Add WALT util signal to trace event sched_load_cfs_rq WALT only operates on root rq. WALT is already intergated into the trace event sched_load_se. Signed-off-by: Dietmar Eggemann Change-Id: If9c50c87404bc712ac29e9a9a8b90f7eb1b254e2 --- include/trace/events/sched.h | 43 +++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index 96b3e50be78a..51964d88bc83 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -639,6 +639,19 @@ struct cfs_rq *__trace_sched_group_cfs_rq(struct sched_entity *se) } #endif /* CREATE_TRACE_POINTS */ +#ifdef CONFIG_SCHED_WALT +extern unsigned int sysctl_sched_use_walt_cpu_util; +extern unsigned int sysctl_sched_use_walt_task_util; +extern unsigned int walt_ravg_window; +extern bool walt_disabled; + +#define walt_util(util_var, demand_sum) {\ + u64 sum = demand_sum << SCHED_CAPACITY_SHIFT;\ + do_div(sum, walt_ravg_window);\ + util_var = (typeof(util_var))sum;\ + } +#endif + /* * Tracepoint for cfs_rq load tracking: */ @@ -654,6 +667,8 @@ TRACE_EVENT(sched_load_cfs_rq, __trace_sched_path(cfs_rq, NULL, 0) ) __field( unsigned long, load ) __field( unsigned long, util ) + __field( unsigned long, util_pelt ) + __field( unsigned long, util_walt ) ), TP_fast_assign( @@ -662,10 +677,21 @@ TRACE_EVENT(sched_load_cfs_rq, __get_dynamic_array_len(path)); __entry->load = cfs_rq->runnable_load_avg; __entry->util = cfs_rq->avg.util_avg; + __entry->util_pelt = cfs_rq->avg.util_avg; + __entry->util_walt = 0; +#ifdef CONFIG_SCHED_WALT + if (&cfs_rq->rq->cfs == cfs_rq) { + walt_util(__entry->util_walt, + cfs_rq->rq->prev_runnable_sum); + if (!walt_disabled && sysctl_sched_use_walt_cpu_util) + __entry->util = __entry->util_walt; + } +#endif ), - TP_printk("cpu=%d path=%s load=%lu util=%lu", __entry->cpu, - __get_str(path), __entry->load, __entry->util) + TP_printk("cpu=%d path=%s load=%lu util=%lu util_pelt=%lu util_walt=%lu", + __entry->cpu, __get_str(path), __entry->load, __entry->util, + __entry->util_pelt, __entry->util_walt) ); /* @@ -693,19 +719,6 @@ TRACE_EVENT(sched_load_rt_rq, __entry->util) ); -#ifdef CONFIG_SCHED_WALT -extern unsigned int sysctl_sched_use_walt_cpu_util; -extern unsigned int sysctl_sched_use_walt_task_util; -extern unsigned int walt_ravg_window; -extern bool walt_disabled; - -#define walt_util(util_var, demand_sum) {\ - u64 sum = demand_sum << SCHED_CAPACITY_SHIFT;\ - do_div(sum, walt_ravg_window);\ - util_var = (typeof(util_var))sum;\ - } -#endif - /* * Tracepoint for sched_entity load tracking: */ -- GitLab From 44791a47f588394e3d755dc01c528bc072409eef Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Thu, 10 May 2018 15:48:06 +0100 Subject: [PATCH 0041/1001] ANDROID: sched/fair: add arch scaling function for max frequency capping To be able to scale the cpu capacity by this factor introduce a call to the new arch scaling function arch_scale_max_freq_capacity() in update_cpu_capacity() and provide a default implementation which returns SCHED_CAPACITY_SCALE. Another subsystem (e.g. cpufreq) or architectural or platform specific code can overwrite this default implementation, exactly as for frequency and cpu invariance. It has to be enabled by the arch by defining arch_scale_max_freq_capacity to the actual implementation. Signed-off-by: Dietmar Eggemann Signed-off-by: Ionela Voinescu Change-Id: I770a8b1f4f7340e9e314f71c64a765bf880f4b4d --- kernel/sched/fair.c | 3 +++ kernel/sched/sched.h | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index c7ddc9dccdd5..469521870371 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -8841,6 +8841,9 @@ static void update_cpu_capacity(struct sched_domain *sd, int cpu) cpu_rq(cpu)->cpu_capacity_orig = capacity; + capacity *= arch_scale_max_freq_capacity(sd, cpu); + capacity >>= SCHED_CAPACITY_SHIFT; + capacity *= scale_rt_capacity(cpu); capacity >>= SCHED_CAPACITY_SHIFT; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 74ec445d7e2e..c7956c4c0844 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1735,6 +1735,14 @@ unsigned long arch_scale_freq_capacity(struct sched_domain *sd, int cpu) } #endif +#ifndef arch_scale_max_freq_capacity +static __always_inline +unsigned long arch_scale_max_freq_capacity(struct sched_domain *sd, int cpu) +{ + return SCHED_CAPACITY_SCALE; +} +#endif + #ifndef arch_scale_cpu_capacity static __always_inline unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu) -- GitLab From b6a1f3e4ddcf9b3dddccd766b8f74066cd53ae5a Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Thu, 10 May 2018 16:52:33 +0100 Subject: [PATCH 0042/1001] ANDROID: implement max frequency capping Implements the Max Frequency Capping Engine (MFCE) getter function topology_get_max_freq_scale() to provide the scheduler with a maximum frequency scaling correction factor for more accurate cpu capacity handling by being able to deal with max frequency capping. This scaling factor describes the influence of running a cpu with a current maximum frequency (policy) lower than the maximum possible frequency (cpuinfo). The factor is: policy_max_freq(cpu) << SCHED_CAPACITY_SHIFT / cpuinfo_max_freq(cpu) It also implements the MFCE setter function arch_set_max_freq_scale() which is called from cpufreq_set_policy(). Signed-off-by: Dietmar Eggemann Signed-off-by: Ionela Voinescu Change-Id: I59e52861ee260755ab0518fe1f7183a2e4e3d0fc --- drivers/base/arch_topology.c | 25 ++++++++++++++++++++++++- drivers/cpufreq/cpufreq.c | 9 +++++++++ include/linux/arch_topology.h | 8 ++++++++ include/linux/cpufreq.h | 2 ++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index c4d101069af5..d00e7c4e52cf 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -25,6 +25,8 @@ #include DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE; +DEFINE_PER_CPU(unsigned long, max_cpu_freq); +DEFINE_PER_CPU(unsigned long, max_freq_scale) = SCHED_CAPACITY_SCALE; void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq, unsigned long max_freq) @@ -34,8 +36,29 @@ void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq, scale = (cur_freq << SCHED_CAPACITY_SHIFT) / max_freq; - for_each_cpu(i, cpus) + for_each_cpu(i, cpus) { per_cpu(freq_scale, i) = scale; + per_cpu(max_cpu_freq, i) = max_freq; + } +} + +void arch_set_max_freq_scale(struct cpumask *cpus, + unsigned long policy_max_freq) +{ + unsigned long scale, max_freq; + int cpu = cpumask_first(cpus); + + if (cpu > nr_cpu_ids) + return; + + max_freq = per_cpu(max_cpu_freq, cpu); + if (!max_freq) + return; + + scale = (policy_max_freq << SCHED_CAPACITY_SHIFT) / max_freq; + + for_each_cpu(cpu, cpus) + per_cpu(max_freq_scale, cpu) = scale; } static DEFINE_MUTEX(cpu_scale_mutex); diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 8dfd102a4b19..927399454d62 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2237,6 +2237,9 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, policy->min = new_policy->min; policy->max = new_policy->max; + + arch_set_max_freq_scale(policy->cpus, policy->max); + trace_cpu_frequency_limits(policy->max, policy->min, policy->cpu); policy->cached_target_freq = UINT_MAX; @@ -2447,6 +2450,12 @@ __weak void arch_set_freq_scale(struct cpumask *cpus, } EXPORT_SYMBOL_GPL(arch_set_freq_scale); +__weak void arch_set_max_freq_scale(struct cpumask *cpus, + unsigned long policy_max_freq) +{ +} +EXPORT_SYMBOL_GPL(arch_set_max_freq_scale); + /********************************************************************* * REGISTER / UNREGISTER CPUFREQ DRIVER * *********************************************************************/ diff --git a/include/linux/arch_topology.h b/include/linux/arch_topology.h index e7fe03600c02..d70f95476927 100644 --- a/include/linux/arch_topology.h +++ b/include/linux/arch_topology.h @@ -37,4 +37,12 @@ unsigned long topology_get_freq_scale(struct sched_domain *sd, int cpu) return per_cpu(freq_scale, cpu); } +DECLARE_PER_CPU(unsigned long, max_freq_scale); + +static inline +unsigned long topology_get_max_freq_scale(struct sched_domain *sd, int cpu) +{ + return per_cpu(max_freq_scale, cpu); +} + #endif /* _LINUX_ARCH_TOPOLOGY_H_ */ diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 065f3a8eb486..938b2a5d010c 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -922,6 +922,8 @@ extern unsigned int arch_freq_get_on_cpu(int cpu); extern void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq, unsigned long max_freq); +extern void arch_set_max_freq_scale(struct cpumask *cpus, + unsigned long policy_max_freq); /* the following are really really optional */ extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs; -- GitLab From 9dfd5a8c09f7b49c15ee9dfa7a634455875641af Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Thu, 10 May 2018 16:54:16 +0100 Subject: [PATCH 0043/1001] ANDROID: arm64: enable max frequency capping Defines arch_scale_max_freq_capacity() to use the topology driver scale function. Signed-off-by: Dietmar Eggemann Signed-off-by: Ionela Voinescu Change-Id: If7565747ec862e42ac55196240522ef8d22ca67d --- arch/arm64/include/asm/topology.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h index 13a00ece862b..b7bd70520a77 100644 --- a/arch/arm64/include/asm/topology.h +++ b/arch/arm64/include/asm/topology.h @@ -38,6 +38,9 @@ int pcibus_to_node(struct pci_bus *bus); /* Replace task scheduler's default frequency-invariant accounting */ #define arch_scale_freq_capacity topology_get_freq_scale +/* Replace task scheduler's default max-frequency-invariant accounting */ +#define arch_scale_max_freq_capacity topology_get_max_freq_scale + /* Replace task scheduler's default cpu-invariant accounting */ #define arch_scale_cpu_capacity topology_get_cpu_scale -- GitLab From d0df20f98c5620fd71cc259862ef92e6ba5b8dda Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Thu, 10 May 2018 16:58:04 +0100 Subject: [PATCH 0044/1001] ANDROID: arm: enable max frequency capping Defines arch_scale_max_freq_capacity() to use the topology driver scale function. Signed-off-by: Dietmar Eggemann Signed-off-by: Ionela Voinescu Change-Id: I79f444399ea3b2948364fde80ccee52a9ece5b9a --- arch/arm/include/asm/topology.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h index 2a786f54d8b8..201dc2011c16 100644 --- a/arch/arm/include/asm/topology.h +++ b/arch/arm/include/asm/topology.h @@ -30,6 +30,9 @@ const struct cpumask *cpu_coregroup_mask(int cpu); /* Replace task scheduler's default frequency-invariant accounting */ #define arch_scale_freq_capacity topology_get_freq_scale +/* Replace task scheduler's default max-frequency-invariant accounting */ +#define arch_scale_max_freq_capacity topology_get_max_freq_scale + /* Replace task scheduler's default cpu-invariant accounting */ #define arch_scale_cpu_capacity topology_get_cpu_scale -- GitLab From 2cc3df5e1c7be786e3089c7882716a89bd8c0d1b Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Sat, 26 Sep 2015 18:19:54 +0100 Subject: [PATCH 0045/1001] ANDROID: sched: Update max cpu capacity in case of max frequency constraints Wakeup balancing uses cpu capacity awareness and needs to know the system-wide maximum cpu capacity. Patch "sched: Store system-wide maximum cpu capacity in root domain" finds the system-wide maximum cpu capacity during scheduler domain hierarchy setup. This is sufficient as long as maximum frequency invariance is not enabled. If it is enabled, the system-wide maximum cpu capacity can change between scheduler domain hierarchy setups due to frequency capping. The cpu capacity is changed in update_cpu_capacity() which is called in load balance on the lowest scheduler domain hierarchy level. To be able to know if a change in cpu capacity for a certain cpu also has an effect on the system-wide maximum cpu capacity it is normally necessary to iterate over all cpus. This would be way too costly. That's why this patch follows a different approach. The unsigned long max_cpu_capacity value in struct root_domain is replaced with a struct max_cpu_capacity, containing value (the max_cpu_capacity) and cpu (the cpu index of the cpu providing the maximum cpu_capacity). Changes to the system-wide maximum cpu capacity and the cpu index are made if: 1 System-wide maximum cpu capacity < cpu capacity 2 System-wide maximum cpu capacity > cpu capacity and cpu index == cpu There are no changes to the system-wide maximum cpu capacity in all other cases. Atomic read and write access to the pair (max_cpu_capacity.val, max_cpu_capacity.cpu) is enforced by max_cpu_capacity.lock. The access to max_cpu_capacity.val in task_fits_max() is still performed without taking the max_cpu_capacity.lock. The code to set max cpu capacity in build_sched_domains() has been removed because the whole functionality is now provided by update_cpu_capacity() instead. This approach can introduce errors temporarily, e.g. in case the cpu currently providing the max cpu capacity has its cpu capacity lowered due to frequency capping and calls update_cpu_capacity() before any cpu which might provide the max cpu now. Signed-off-by: Dietmar Eggemann Signed-off-by: Ionela Voinescu Change-Id: Idaa7a16723001e222e476de34df332558e48dd13 --- kernel/sched/fair.c | 32 +++++++++++++++++++++++++++++++- kernel/sched/sched.h | 10 +++++++++- kernel/sched/topology.c | 13 ++----------- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 469521870371..45dfaec611b2 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -7236,7 +7236,7 @@ static int wake_cap(struct task_struct *p, int cpu, int prev_cpu) return 0; min_cap = min(capacity_orig_of(prev_cpu), capacity_orig_of(cpu)); - max_cap = cpu_rq(cpu)->rd->max_cpu_capacity; + max_cap = cpu_rq(cpu)->rd->max_cpu_capacity.val; /* Minimum capacity is close to max, no need to abort wake_affine */ if (max_cap - min_cap < max_cap >> 3) @@ -8834,16 +8834,46 @@ static unsigned long scale_rt_capacity(int cpu) return 1; } +void init_max_cpu_capacity(struct max_cpu_capacity *mcc) +{ + raw_spin_lock_init(&mcc->lock); + mcc->val = 0; + mcc->cpu = -1; +} + static void update_cpu_capacity(struct sched_domain *sd, int cpu) { unsigned long capacity = arch_scale_cpu_capacity(sd, cpu); struct sched_group *sdg = sd->groups; + struct max_cpu_capacity *mcc; + unsigned long max_capacity; + int max_cap_cpu; + unsigned long flags; cpu_rq(cpu)->cpu_capacity_orig = capacity; capacity *= arch_scale_max_freq_capacity(sd, cpu); capacity >>= SCHED_CAPACITY_SHIFT; + mcc = &cpu_rq(cpu)->rd->max_cpu_capacity; + + raw_spin_lock_irqsave(&mcc->lock, flags); + max_capacity = mcc->val; + max_cap_cpu = mcc->cpu; + + if (max_capacity > capacity && max_cap_cpu == cpu || + max_capacity < capacity) { + mcc->val = capacity; + mcc->cpu = cpu; +#ifdef CONFIG_SCHED_DEBUG + raw_spin_unlock_irqrestore(&mcc->lock, flags); + pr_info("CPU%d: update max cpu_capacity %lu\n", cpu, capacity); + goto skip_unlock; +#endif + } + raw_spin_unlock_irqrestore(&mcc->lock, flags); + +skip_unlock: __attribute__ ((unused)); capacity *= scale_rt_capacity(cpu); capacity >>= SCHED_CAPACITY_SHIFT; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index c7956c4c0844..235e519caf55 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -612,6 +612,12 @@ static inline bool sched_asym_prefer(int a, int b) return arch_asym_cpu_priority(a) > arch_asym_cpu_priority(b); } +struct max_cpu_capacity { + raw_spinlock_t lock; + unsigned long val; + int cpu; +}; + /* * We add the notion of a root-domain which will be used to define per-domain * variables. Each exclusive cpuset essentially defines an island domain by @@ -663,7 +669,8 @@ struct root_domain { cpumask_var_t rto_mask; struct cpupri cpupri; - unsigned long max_cpu_capacity; + /* Maximum cpu capacity in the system. */ + struct max_cpu_capacity max_cpu_capacity; /* First cpu with maximum and minimum original capacity */ int max_cap_orig_cpu, min_cap_orig_cpu; @@ -673,6 +680,7 @@ extern struct root_domain def_root_domain; extern struct mutex sched_domains_mutex; extern void init_defrootdomain(void); +extern void init_max_cpu_capacity(struct max_cpu_capacity *mcc); extern int sched_init_domains(const struct cpumask *cpu_map); extern void rq_attach_root(struct rq *rq, struct root_domain *rd); extern void sched_get_rd(struct root_domain *rd); diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c index 8a9be7d4d286..9e967e88676b 100644 --- a/kernel/sched/topology.c +++ b/kernel/sched/topology.c @@ -304,6 +304,8 @@ static int init_rootdomain(struct root_domain *rd) rd->max_cap_orig_cpu = rd->min_cap_orig_cpu = -1; + init_max_cpu_capacity(&rd->max_cpu_capacity); + return 0; free_cpudl: @@ -1818,7 +1820,6 @@ build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *att enum s_alloc alloc_state; struct sched_domain *sd; struct s_data d; - struct rq *rq = NULL; int i, ret = -ENOMEM; alloc_state = __visit_domain_allocation_hell(&d, cpu_map); @@ -1873,13 +1874,8 @@ build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *att int max_cpu = READ_ONCE(d.rd->max_cap_orig_cpu); int min_cpu = READ_ONCE(d.rd->min_cap_orig_cpu); - rq = cpu_rq(i); sd = *per_cpu_ptr(d.sd, i); - /* Use READ_ONCE()/WRITE_ONCE() to avoid load/store tearing: */ - if (rq->cpu_capacity_orig > READ_ONCE(d.rd->max_cpu_capacity)) - WRITE_ONCE(d.rd->max_cpu_capacity, rq->cpu_capacity_orig); - if ((max_cpu < 0) || (cpu_rq(i)->cpu_capacity_orig > cpu_rq(max_cpu)->cpu_capacity_orig)) WRITE_ONCE(d.rd->max_cap_orig_cpu, i); @@ -1895,11 +1891,6 @@ build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *att if (!cpumask_empty(cpu_map)) update_asym_cpucapacity(cpumask_first(cpu_map)); - if (rq && sched_debug_enabled) { - pr_info("span: %*pbl (max cpu_capacity = %lu)\n", - cpumask_pr_args(cpu_map), rq->rd->max_cpu_capacity); - } - ret = 0; error: __free_domain_allocs(&d, alloc_state, cpu_map); -- GitLab From 2bd47d3fcebfd8a79606e8eaed318d8361e635c8 Mon Sep 17 00:00:00 2001 From: Patrick Bellasi Date: Fri, 9 Mar 2018 09:52:43 +0000 Subject: [PATCH 0046/1001] ANDROID: sched/fair: Cleanup cpu_util{_wake}() The current implementation of cpu_util and cpu_util_wake makes more difficult the backporting of mainline patches and it also has some features not longer required by the current EAS code, e.g. delta utilization in __cpu_util(). Let's clean up these functions definitions to: 1. get rid of the not longer required __cpu_util(cpu, delta) This function is now only called with delta=0 and thus we can refold its implementation into the original wrapper function cpu_util(cpu) 2. optimize for the WALT path on CONFIG_SCHED_WALT builds Currently indeed we execute some not necessary PELT related code even when WALT signals are required. Let's change this by assuming that on CONFIG_SCHED_WALT build we are likely using WALT signals. While on !CONFIG_SCHED_WALT we still have just the PELT signals with a code structure which matches mainline 3. move the definitions from sched/sched.h into sched/fair.c This is the only module using these functions and it also better align with the mainline location for these functions 4. get rid of the walt_util macro That macro has a function-like signature but it's modifying a parameter (passed by value) which makes it a bit confusing. Moreover, the usage of the min_t() macro to cap signals with capacity_orig_of() it makes not more required the explicit type cast used by that macro to support both 32 and 63 bits targets. 5. remove forward declarations Which are not required once the definition is moved at the top of fair.c, since they don't have other local dependencies. Signed-off-by: Patrick Bellasi Change-Id: I61c9b7b8a0a34b494527c5aa76218c64543c16d2 --- kernel/sched/fair.c | 137 ++++++++++++++++++++++++++++++++----------- kernel/sched/sched.h | 70 +--------------------- 2 files changed, 105 insertions(+), 102 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 45dfaec611b2..5da7e81442d1 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -4953,8 +4953,6 @@ static inline void hrtick_update(struct rq *rq) #ifdef CONFIG_SMP static bool cpu_overutilized(int cpu); -static unsigned long cpu_util(int cpu); - static bool sd_overutilized(struct sched_domain *sd) { return sd->shared->overutilized; @@ -5495,8 +5493,6 @@ static inline bool energy_aware(void) return sched_feat(ENERGY_AWARE); } -static int cpu_util_wake(int cpu, struct task_struct *p); - /* * __cpu_norm_util() returns the cpu util relative to a specific capacity, * i.e. it's busy ratio, in the range [0..SCHED_CAPACITY_SCALE] which is useful @@ -5650,7 +5646,110 @@ struct energy_env { struct sched_group *sg; }; -static int cpu_util_wake(int cpu, struct task_struct *p); +/* + * cpu_util returns the amount of capacity of a CPU that is used by CFS + * tasks. The unit of the return value must be the one of capacity so we can + * compare the utilization with the capacity of the CPU that is available for + * CFS task (ie cpu_capacity). + * + * cfs_rq.avg.util_avg is the sum of running time of runnable tasks plus the + * recent utilization of currently non-runnable tasks on a CPU. It represents + * the amount of utilization of a CPU in the range [0..capacity_orig] where + * capacity_orig is the cpu_capacity available at the highest frequency, + * i.e. arch_scale_cpu_capacity(). + * The utilization of a CPU converges towards a sum equal to or less than the + * current capacity (capacity_curr <= capacity_orig) of the CPU because it is + * the running time on this CPU scaled by capacity_curr. + * + * Nevertheless, cfs_rq.avg.util_avg can be higher than capacity_curr or even + * higher than capacity_orig because of unfortunate rounding in + * cfs.avg.util_avg or just after migrating tasks and new task wakeups until + * the average stabilizes with the new running time. We need to check that the + * utilization stays within the range of [0..capacity_orig] and cap it if + * necessary. Without utilization capping, a group could be seen as overloaded + * (CPU0 utilization at 121% + CPU1 utilization at 80%) whereas CPU1 has 20% of + * available capacity. We allow utilization to overshoot capacity_curr (but not + * capacity_orig) as it useful for predicting the capacity required after task + * migrations (scheduler-driven DVFS). + */ +static inline unsigned long cpu_util(int cpu) +{ + struct cfs_rq *cfs_rq; + unsigned int util; + +#ifdef CONFIG_SCHED_WALT + if (likely(!walt_disabled && sysctl_sched_use_walt_cpu_util)) { + u64 walt_cpu_util = cpu_rq(cpu)->cumulative_runnable_avg; + + walt_cpu_util <<= SCHED_CAPACITY_SHIFT; + do_div(walt_cpu_util, walt_ravg_window); + + return min_t(unsigned long, walt_cpu_util, + capacity_orig_of(cpu)); + } +#endif + + cfs_rq = &cpu_rq(cpu)->cfs; + util = READ_ONCE(cfs_rq->avg.util_avg); + + return min_t(unsigned long, util, capacity_orig_of(cpu)); +} + +static inline unsigned long cpu_util_freq(int cpu) +{ +#ifdef CONFIG_SCHED_WALT + u64 walt_cpu_util; + + if (unlikely(walt_disabled || !sysctl_sched_use_walt_cpu_util)) + return cpu_util(cpu); + + walt_cpu_util = cpu_rq(cpu)->prev_runnable_sum; + walt_cpu_util <<= SCHED_CAPACITY_SHIFT; + do_div(walt_cpu_util, walt_ravg_window); + + return min_t(unsigned long, walt_cpu_util, capacity_orig_of(cpu)); +#else + return cpu_util(cpu); +#endif +} + +/* + * cpu_util_wake: Compute CPU utilization with any contributions from + * the waking task p removed. + */ +static unsigned long cpu_util_wake(int cpu, struct task_struct *p) +{ + struct cfs_rq *cfs_rq; + unsigned int util; + +#ifdef CONFIG_SCHED_WALT + /* + * WALT does not decay idle tasks in the same manner + * as PELT, so it makes little sense to subtract task + * utilization from cpu utilization. Instead just use + * cpu_util for this case. + */ + if (likely(!walt_disabled && sysctl_sched_use_walt_cpu_util)) + return cpu_util(cpu); +#endif + + /* Task has no contribution or is new */ + if (cpu != task_cpu(p) || !READ_ONCE(p->se.avg.last_update_time)) + return cpu_util(cpu); + + cfs_rq = &cpu_rq(cpu)->cfs; + util = READ_ONCE(cfs_rq->avg.util_avg); + + /* Discount task's blocked util from CPU's util */ + util -= min_t(unsigned int, util, task_util(p)); + + /* + * Utilization (estimated) can exceed the CPU capacity, thus let's + * clamp to the maximum CPU capacity to ensure consistency with + * the cpu_util call. + */ + return min_t(unsigned long, util, capacity_orig_of(cpu)); +} static unsigned long group_max_util(struct energy_env *eenv, int cpu_idx) { @@ -6862,34 +6961,6 @@ static inline unsigned long task_util(struct task_struct *p) return p->se.avg.util_avg; } -/* - * cpu_util_wake: Compute cpu utilization with any contributions from - * the waking task p removed. - */ -static int cpu_util_wake(int cpu, struct task_struct *p) -{ - unsigned long util, capacity; - -#ifdef CONFIG_SCHED_WALT - /* - * WALT does not decay idle tasks in the same manner - * as PELT, so it makes little sense to subtract task - * utilization from cpu utilization. Instead just use - * cpu_util for this case. - */ - if (!walt_disabled && sysctl_sched_use_walt_cpu_util) - return cpu_util(cpu); -#endif - /* Task has no contribution or is new */ - if (cpu != task_cpu(p) || !p->se.avg.last_update_time) - return cpu_util(cpu); - - capacity = capacity_orig_of(cpu); - util = max_t(long, cpu_rq(cpu)->cfs.avg.util_avg - task_util(p), 0); - - return (util >= capacity) ? capacity : util; -} - static inline int task_fits_capacity(struct task_struct *p, long capacity) { return capacity * 1024 > boosted_task_util(p) * capacity_margin; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 235e519caf55..690a0fac09a8 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1777,75 +1777,7 @@ extern unsigned int sysctl_sched_use_walt_cpu_util; extern unsigned int walt_ravg_window; extern bool walt_disabled; -#ifdef CONFIG_SCHED_WALT -#define walt_util(util_var, demand_sum) {\ - u64 sum = demand_sum << SCHED_CAPACITY_SHIFT;\ - do_div(sum, walt_ravg_window);\ - util_var = (typeof(util_var))sum;\ - } -#endif -/* - * cpu_util returns the amount of capacity of a CPU that is used by CFS - * tasks. The unit of the return value must be the one of capacity so we can - * compare the utilization with the capacity of the CPU that is available for - * CFS task (ie cpu_capacity). - * - * cfs_rq.avg.util_avg is the sum of running time of runnable tasks plus the - * recent utilization of currently non-runnable tasks on a CPU. It represents - * the amount of utilization of a CPU in the range [0..capacity_orig] where - * capacity_orig is the cpu_capacity available at the highest frequency - * (arch_scale_freq_capacity()). - * The utilization of a CPU converges towards a sum equal to or less than the - * current capacity (capacity_curr <= capacity_orig) of the CPU because it is - * the running time on this CPU scaled by capacity_curr. - * - * Nevertheless, cfs_rq.avg.util_avg can be higher than capacity_curr or even - * higher than capacity_orig because of unfortunate rounding in - * cfs.avg.util_avg or just after migrating tasks and new task wakeups until - * the average stabilizes with the new running time. We need to check that the - * utilization stays within the range of [0..capacity_orig] and cap it if - * necessary. Without utilization capping, a group could be seen as overloaded - * (CPU0 utilization at 121% + CPU1 utilization at 80%) whereas CPU1 has 20% of - * available capacity. We allow utilization to overshoot capacity_curr (but not - * capacity_orig) as it useful for predicting the capacity required after task - * migrations (scheduler-driven DVFS). - */ -static inline unsigned long __cpu_util(int cpu, int delta) -{ - unsigned long util = cpu_rq(cpu)->cfs.avg.util_avg; - unsigned long capacity = capacity_orig_of(cpu); - -#ifdef CONFIG_SCHED_WALT - if (!walt_disabled && sysctl_sched_use_walt_cpu_util) { - walt_util(util, cpu_rq(cpu)->cumulative_runnable_avg); - } -#endif - delta += util; - if (delta < 0) - return 0; - - return (delta >= capacity) ? capacity : delta; -} - -static inline unsigned long cpu_util(int cpu) -{ - return __cpu_util(cpu, 0); -} - -static inline unsigned long cpu_util_freq(int cpu) -{ - unsigned long util = cpu_rq(cpu)->cfs.avg.util_avg; - unsigned long capacity = capacity_orig_of(cpu); - -#ifdef CONFIG_SCHED_WALT - if (!walt_disabled && sysctl_sched_use_walt_cpu_util) { - walt_util(util, cpu_rq(cpu)->prev_runnable_sum); - } -#endif - return (util >= capacity) ? capacity : util; -} - -#endif +#endif /* CONFIG_SMP */ static inline void sched_rt_avg_update(struct rq *rq, u64 rt_delta) { -- GitLab From 700f1172f7a7cb06a037670fa1145f8cf4bdedbb Mon Sep 17 00:00:00 2001 From: Patrick Bellasi Date: Fri, 9 Mar 2018 09:52:42 +0000 Subject: [PATCH 0047/1001] BACKPORT: sched/fair: Add util_est on top of PELT The util_avg signal computed by PELT is too variable for some use-cases. For example, a big task waking up after a long sleep period will have its utilization almost completely decayed. This introduces some latency before schedutil will be able to pick the best frequency to run a task. The same issue can affect task placement. Indeed, since the task utilization is already decayed at wakeup, when the task is enqueued in a CPU, this can result in a CPU running a big task as being temporarily represented as being almost empty. This leads to a race condition where other tasks can be potentially allocated on a CPU which just started to run a big task which slept for a relatively long period. Moreover, the PELT utilization of a task can be updated every [ms], thus making it a continuously changing value for certain longer running tasks. This means that the instantaneous PELT utilization of a RUNNING task is not really meaningful to properly support scheduler decisions. For all these reasons, a more stable signal can do a better job of representing the expected/estimated utilization of a task/cfs_rq. Such a signal can be easily created on top of PELT by still using it as an estimator which produces values to be aggregated on meaningful events. This patch adds a simple implementation of util_est, a new signal built on top of PELT's util_avg where: util_est(task) = max(task::util_avg, f(task::util_avg@dequeue)) This allows to remember how big a task has been reported by PELT in its previous activations via f(task::util_avg@dequeue), which is the new _task_util_est(struct task_struct*) function added by this patch. If a task should change its behavior and it runs longer in a new activation, after a certain time its util_est will just track the original PELT signal (i.e. task::util_avg). The estimated utilization of cfs_rq is defined only for root ones. That's because the only sensible consumer of this signal are the scheduler and schedutil when looking for the overall CPU utilization due to FAIR tasks. For this reason, the estimated utilization of a root cfs_rq is simply defined as: util_est(cfs_rq) = max(cfs_rq::util_avg, cfs_rq::util_est::enqueued) where: cfs_rq::util_est::enqueued = sum(_task_util_est(task)) for each RUNNABLE task on that root cfs_rq It's worth noting that the estimated utilization is tracked only for objects of interests, specifically: - Tasks: to better support tasks placement decisions - root cfs_rqs: to better support both tasks placement decisions as well as frequencies selection Signed-off-by: Patrick Bellasi Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Dietmar Eggemann Cc: Joel Fernandes Cc: Juri Lelli Cc: Linus Torvalds Cc: Morten Rasmussen Cc: Paul Turner Cc: Rafael J . Wysocki Cc: Steve Muckle Cc: Thomas Gleixner Cc: Todd Kjos Cc: Vincent Guittot Cc: Viresh Kumar Link: http://lkml.kernel.org/r/20180309095245.11071-2-patrick.bellasi@arm.com Signed-off-by: Ingo Molnar [ backport from upstream: commit 7f65ea42eb00 ("sched/fair: Add util_est on top of PELT") No major changes. ] Signed-off-by: Patrick Bellasi Change-Id: Icfa41dd73bd4da674b0044cacb11f320cf39eabf --- include/linux/sched.h | 29 +++++++++ kernel/sched/debug.c | 4 ++ kernel/sched/fair.c | 133 ++++++++++++++++++++++++++++++++++++---- kernel/sched/features.h | 5 ++ 4 files changed, 159 insertions(+), 12 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index cf308a75503b..f8c5e72758c8 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -326,6 +326,34 @@ struct load_weight { u32 inv_weight; }; +/** + * struct util_est - Estimation utilization of FAIR tasks + * @enqueued: instantaneous estimated utilization of a task/cpu + * @ewma: the Exponential Weighted Moving Average (EWMA) + * utilization of a task + * + * Support data structure to track an Exponential Weighted Moving Average + * (EWMA) of a FAIR task's utilization. New samples are added to the moving + * average each time a task completes an activation. Sample's weight is chosen + * so that the EWMA will be relatively insensitive to transient changes to the + * task's workload. + * + * The enqueued attribute has a slightly different meaning for tasks and cpus: + * - task: the task's util_avg at last task dequeue time + * - cfs_rq: the sum of util_est.enqueued for each RUNNABLE task on that CPU + * Thus, the util_est.enqueued of a task represents the contribution on the + * estimated utilization of the CPU where that task is currently enqueued. + * + * Only for tasks we track a moving average of the past instantaneous + * estimated utilization. This allows to absorb sporadic drops in utilization + * of an otherwise almost periodic task. + */ +struct util_est { + unsigned int enqueued; + unsigned int ewma; +#define UTIL_EST_WEIGHT_SHIFT 2 +}; + /* * The load_avg/util_avg accumulates an infinite geometric series * (see __update_load_avg() in kernel/sched/fair.c). @@ -385,6 +413,7 @@ struct sched_avg { u32 period_contrib; unsigned long load_avg; unsigned long util_avg; + struct util_est util_est; }; struct sched_statistics { diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c index 0a93f253673c..4e75fda646c0 100644 --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -627,6 +627,8 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) cfs_rq->runnable_load_avg); SEQ_printf(m, " .%-30s: %lu\n", "util_avg", cfs_rq->avg.util_avg); + SEQ_printf(m, " .%-30s: %u\n", "util_est_enqueued", + cfs_rq->avg.util_est.enqueued); SEQ_printf(m, " .%-30s: %ld\n", "removed_load_avg", atomic_long_read(&cfs_rq->removed_load_avg)); SEQ_printf(m, " .%-30s: %ld\n", "removed_util_avg", @@ -1073,6 +1075,8 @@ void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns, P(se.avg.load_avg); P(se.avg.util_avg); P(se.avg.last_update_time); + P(se.avg.util_est.ewma); + P(se.avg.util_est.enqueued); #endif P(policy); P(prio); diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 5da7e81442d1..56f080f3b8a5 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -3616,6 +3616,118 @@ static inline void update_misfit_status(struct task_struct *p, struct rq *rq) rq->misfit_task_load = task_h_load(p); } +static inline unsigned long task_util(struct task_struct *p) +{ +#ifdef CONFIG_SCHED_WALT + if (likely(!walt_disabled && sysctl_sched_use_walt_task_util)) + return (p->ravg.demand / + (walt_ravg_window >> SCHED_CAPACITY_SHIFT)); +#endif + return READ_ONCE(p->se.avg.util_avg); +} + +static inline unsigned long _task_util_est(struct task_struct *p) +{ + struct util_est ue = READ_ONCE(p->se.avg.util_est); + + return max(ue.ewma, ue.enqueued); +} + +static inline unsigned long task_util_est(struct task_struct *p) +{ + return max(task_util(p), _task_util_est(p)); +} + +static inline void util_est_enqueue(struct cfs_rq *cfs_rq, + struct task_struct *p) +{ + unsigned int enqueued; + + if (!sched_feat(UTIL_EST)) + return; + + /* Update root cfs_rq's estimated utilization */ + enqueued = cfs_rq->avg.util_est.enqueued; + enqueued += _task_util_est(p); + WRITE_ONCE(cfs_rq->avg.util_est.enqueued, enqueued); +} + +/* + * Check if a (signed) value is within a specified (unsigned) margin, + * based on the observation that: + * + * abs(x) < y := (unsigned)(x + y - 1) < (2 * y - 1) + * + * NOTE: this only works when value + maring < INT_MAX. + */ +static inline bool within_margin(int value, int margin) +{ + return ((unsigned int)(value + margin - 1) < (2 * margin - 1)); +} + +static void +util_est_dequeue(struct cfs_rq *cfs_rq, struct task_struct *p, bool task_sleep) +{ + long last_ewma_diff; + struct util_est ue; + + if (!sched_feat(UTIL_EST)) + return; + + /* + * Update root cfs_rq's estimated utilization + * + * If *p is the last task then the root cfs_rq's estimated utilization + * of a CPU is 0 by definition. + */ + ue.enqueued = 0; + if (cfs_rq->nr_running) { + ue.enqueued = cfs_rq->avg.util_est.enqueued; + ue.enqueued -= min_t(unsigned int, ue.enqueued, + _task_util_est(p)); + } + WRITE_ONCE(cfs_rq->avg.util_est.enqueued, ue.enqueued); + + /* + * Skip update of task's estimated utilization when the task has not + * yet completed an activation, e.g. being migrated. + */ + if (!task_sleep) + return; + + /* + * Skip update of task's estimated utilization when its EWMA is + * already ~1% close to its last activation value. + */ + ue = p->se.avg.util_est; + ue.enqueued = task_util(p); + last_ewma_diff = ue.enqueued - ue.ewma; + if (within_margin(last_ewma_diff, (SCHED_CAPACITY_SCALE / 100))) + return; + + /* + * Update Task's estimated utilization + * + * When *p completes an activation we can consolidate another sample + * of the task size. This is done by storing the current PELT value + * as ue.enqueued and by using this value to update the Exponential + * Weighted Moving Average (EWMA): + * + * ewma(t) = w * task_util(p) + (1-w) * ewma(t-1) + * = w * task_util(p) + ewma(t-1) - w * ewma(t-1) + * = w * (task_util(p) - ewma(t-1)) + ewma(t-1) + * = w * ( last_ewma_diff ) + ewma(t-1) + * = w * (last_ewma_diff + ewma(t-1) / w) + * + * Where 'w' is the weight of new samples, which is configured to be + * 0.25, thus making w=1/4 ( >>= UTIL_EST_WEIGHT_SHIFT) + */ + ue.ewma <<= UTIL_EST_WEIGHT_SHIFT; + ue.ewma += last_ewma_diff; + ue.ewma >>= UTIL_EST_WEIGHT_SHIFT; + WRITE_ONCE(p->se.avg.util_est, ue); +} + #else /* CONFIG_SMP */ static inline int @@ -3655,6 +3767,13 @@ static inline int idle_balance(struct rq *rq, struct rq_flags *rf) static inline void update_misfit_status(struct task_struct *p, struct rq *rq) {} +static inline void +util_est_enqueue(struct cfs_rq *cfs_rq, struct task_struct *p) {} + +static inline void +util_est_dequeue(struct cfs_rq *cfs_rq, struct task_struct *p, + bool task_sleep) {} + #endif /* CONFIG_SMP */ static void check_spread(struct cfs_rq *cfs_rq, struct sched_entity *se) @@ -5068,6 +5187,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) walt_inc_cumulative_runnable_avg(rq, p); } + util_est_enqueue(&rq->cfs, p); hrtick_update(rq); } @@ -5140,6 +5260,7 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags) walt_dec_cumulative_runnable_avg(rq, p); } + util_est_dequeue(&rq->cfs, p, task_sleep); hrtick_update(rq); } @@ -6329,8 +6450,6 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p, return affine; } -static inline unsigned long task_util(struct task_struct *p); - #ifdef CONFIG_SCHED_TUNE struct reciprocal_value schedtune_spc_rdiv; @@ -6951,16 +7070,6 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target) return select_idle_sibling_cstate_aware(p, prev, target); } -static inline unsigned long task_util(struct task_struct *p) -{ -#ifdef CONFIG_SCHED_WALT - if (!walt_disabled && sysctl_sched_use_walt_task_util) { - return (p->ravg.demand / (walt_ravg_window >> SCHED_CAPACITY_SHIFT)); - } -#endif - return p->se.avg.util_avg; -} - static inline int task_fits_capacity(struct task_struct *p, long capacity) { return capacity * 1024 > boosted_task_util(p) * capacity_margin; diff --git a/kernel/sched/features.h b/kernel/sched/features.h index 306333beea5f..2283e868983e 100644 --- a/kernel/sched/features.h +++ b/kernel/sched/features.h @@ -86,6 +86,11 @@ SCHED_FEAT(WA_IDLE, true) SCHED_FEAT(WA_WEIGHT, true) SCHED_FEAT(WA_BIAS, true) +/* + * UtilEstimation. Use estimated CPU utilization. + */ +SCHED_FEAT(UTIL_EST, false) + /* * Energy aware scheduling. Use platform energy model to guide scheduling * decisions optimizing for energy efficiency. -- GitLab From f9fb6fbeb4c2d34482cd605acfb6f406459a7246 Mon Sep 17 00:00:00 2001 From: Patrick Bellasi Date: Fri, 9 Mar 2018 09:52:43 +0000 Subject: [PATCH 0048/1001] BACKPORT: sched/fair: Use util_est in LB and WU paths When the scheduler looks at the CPU utilization, the current PELT value for a CPU is returned straight away. In certain scenarios this can have undesired side effects on task placement. For example, since the task utilization is decayed at wakeup time, when a long sleeping big task is enqueued it does not add immediately a significant contribution to the target CPU. As a result we generate a race condition where other tasks can be placed on the same CPU while it is still considered relatively empty. In order to reduce this kind of race conditions, this patch introduces the required support to integrate the usage of the CPU's estimated utilization in the wakeup path, via cpu_util_wake(), as well as in the load-balance path, via cpu_util() which is used by update_sg_lb_stats(). The estimated utilization of a CPU is defined to be the maximum between its PELT's utilization and the sum of the estimated utilization (at previous dequeue time) of all the tasks currently RUNNABLE on that CPU. This allows to properly represent the spare capacity of a CPU which, for example, has just got a big task running since a long sleep period. Signed-off-by: Patrick Bellasi Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Dietmar Eggemann Cc: Joel Fernandes Cc: Juri Lelli Cc: Linus Torvalds Cc: Morten Rasmussen Cc: Paul Turner Cc: Peter Zijlstra Cc: Rafael J . Wysocki Cc: Steve Muckle Cc: Thomas Gleixner Cc: Todd Kjos Cc: Vincent Guittot Cc: Viresh Kumar Link: http://lkml.kernel.org/r/20180309095245.11071-3-patrick.bellasi@arm.com Signed-off-by: Ingo Molnar [ backport from upstream: commit f9be3e5 ("sched/fair: Use util_est in LB and WU paths") This provides also schedutil integration, since: sugov_get_util() boosted_cpu_util() cpu_util_freq() cpu_util() thus, not requiring to backport: commit a07630b8b2c1 ("sched/cpufreq/schedutil: Use util_est for OPP selection") Support for energy_diff is also provided, since: calc_sg_energy() find_new_capacity() group_max_util() cpu_util_wake() and: group_norm_util() cpu_util_wake() Where both cpu_util() and cpu_util_wake() already consider the estimated utlilization in case of PELT being in use. ] Signed-off-by: Patrick Bellasi Change-Id: I2be201cf7bb0b1449b14b4da64844067dbdb5eb4 --- kernel/sched/fair.c | 76 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 12 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 56f080f3b8a5..89b6dac144d5 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -3635,6 +3635,11 @@ static inline unsigned long _task_util_est(struct task_struct *p) static inline unsigned long task_util_est(struct task_struct *p) { +#ifdef CONFIG_SCHED_WALT + if (likely(!walt_disabled && sysctl_sched_use_walt_task_util)) + return (p->ravg.demand / + (walt_ravg_window >> SCHED_CAPACITY_SHIFT)); +#endif return max(task_util(p), _task_util_est(p)); } @@ -5767,11 +5772,13 @@ struct energy_env { struct sched_group *sg; }; -/* - * cpu_util returns the amount of capacity of a CPU that is used by CFS - * tasks. The unit of the return value must be the one of capacity so we can - * compare the utilization with the capacity of the CPU that is available for - * CFS task (ie cpu_capacity). +/** + * Amount of capacity of a CPU that is (estimated to be) used by CFS tasks + * @cpu: the CPU to get the utilization of + * + * The unit of the return value must be the one of capacity so we can compare + * the utilization with the capacity of the CPU that is available for CFS task + * (ie cpu_capacity). * * cfs_rq.avg.util_avg is the sum of running time of runnable tasks plus the * recent utilization of currently non-runnable tasks on a CPU. It represents @@ -5782,6 +5789,14 @@ struct energy_env { * current capacity (capacity_curr <= capacity_orig) of the CPU because it is * the running time on this CPU scaled by capacity_curr. * + * The estimated utilization of a CPU is defined to be the maximum between its + * cfs_rq.avg.util_avg and the sum of the estimated utilization of the tasks + * currently RUNNABLE on that CPU. + * This allows to properly represent the expected utilization of a CPU which + * has just got a big task running since a long sleep period. At the same time + * however it preserves the benefits of the "blocked utilization" in + * describing the potential for other tasks waking up on the same CPU. + * * Nevertheless, cfs_rq.avg.util_avg can be higher than capacity_curr or even * higher than capacity_orig because of unfortunate rounding in * cfs.avg.util_avg or just after migrating tasks and new task wakeups until @@ -5792,6 +5807,8 @@ struct energy_env { * available capacity. We allow utilization to overshoot capacity_curr (but not * capacity_orig) as it useful for predicting the capacity required after task * migrations (scheduler-driven DVFS). + * + * Return: the (estimated) utilization for the specified CPU */ static inline unsigned long cpu_util(int cpu) { @@ -5813,6 +5830,9 @@ static inline unsigned long cpu_util(int cpu) cfs_rq = &cpu_rq(cpu)->cfs; util = READ_ONCE(cfs_rq->avg.util_avg); + if (sched_feat(UTIL_EST)) + util = max(util, READ_ONCE(cfs_rq->avg.util_est.enqueued)); + return min_t(unsigned long, util, capacity_orig_of(cpu)); } @@ -5864,6 +5884,35 @@ static unsigned long cpu_util_wake(int cpu, struct task_struct *p) /* Discount task's blocked util from CPU's util */ util -= min_t(unsigned int, util, task_util(p)); + /* + * Covered cases: + * + * a) if *p is the only task sleeping on this CPU, then: + * cpu_util (== task_util) > util_est (== 0) + * and thus we return: + * cpu_util_wake = (cpu_util - task_util) = 0 + * + * b) if other tasks are SLEEPING on this CPU, which is now exiting + * IDLE, then: + * cpu_util >= task_util + * cpu_util > util_est (== 0) + * and thus we discount *p's blocked utilization to return: + * cpu_util_wake = (cpu_util - task_util) >= 0 + * + * c) if other tasks are RUNNABLE on that CPU and + * util_est > cpu_util + * then we use util_est since it returns a more restrictive + * estimation of the spare capacity on that CPU, by just + * considering the expected utilization of tasks already + * runnable on that CPU. + * + * Cases a) and b) are covered by the above code, while case c) is + * covered by the following code when estimated utilization is + * enabled. + */ + if (sched_feat(UTIL_EST)) + util = max(util, READ_ONCE(cfs_rq->avg.util_est.enqueued)); + /* * Utilization (estimated) can exceed the CPU capacity, thus let's * clamp to the maximum CPU capacity to ensure consistency with @@ -6500,7 +6549,7 @@ schedtune_task_margin(struct task_struct *task) if (boost == 0) return 0; - util = task_util(task); + util = task_util_est(task); margin = schedtune_margin(util, boost); return margin; @@ -6536,7 +6585,7 @@ boosted_cpu_util(int cpu) static inline unsigned long boosted_task_util(struct task_struct *task) { - unsigned long util = task_util(task); + unsigned long util = task_util_est(task); long margin = schedtune_task_margin(task); trace_sched_boost_task(task, util, margin); @@ -7145,7 +7194,7 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, * accounting. However, the blocked utilization may be zero. */ wake_util = cpu_util_wake(i, p); - new_util = wake_util + task_util(p); + new_util = wake_util + task_util_est(p); /* * Ensure minimum capacity to grant the required boost. @@ -7542,7 +7591,7 @@ static inline struct energy_env *get_eenv(struct task_struct *p, int prev_cpu) * during energy calculation, but unboosted task * util for group utilization calculations */ - eenv->util_delta = task_util(p); + eenv->util_delta = task_util_est(p); eenv->util_delta_boosted = boosted_task_util(p); cpumask_and(&cpumask_possible_cpus, &p->cpus_allowed, cpu_online_mask); @@ -7597,9 +7646,12 @@ static int find_energy_efficient_cpu(struct sched_domain *sd, if (cpu_iter == prev_cpu) continue; + /* + * Consider only CPUs where the task is expected to + * fit without making the CPU overutilized. + */ spare = capacity_spare_wake(cpu_iter, p); - - if (spare * 1024 < capacity_margin * task_util(p)) + if (spare * 1024 < capacity_margin * task_util_est(p)) continue; /* Add CPU candidate */ @@ -7701,7 +7753,7 @@ static inline int wake_energy(struct task_struct *p, int prev_cpu, * the heuristics we use there in selecting candidate * CPUs. */ - if (unlikely(!sched_feat(FIND_BEST_TARGET) && !task_util(p))) + if (unlikely(!sched_feat(FIND_BEST_TARGET) && !task_util_est(p))) return false; if(!sched_feat(EAS_PREFER_IDLE)){ -- GitLab From 3356f39e9adca368bca214340c0bdc6234e35cad Mon Sep 17 00:00:00 2001 From: Patrick Bellasi Date: Fri, 9 Mar 2018 09:52:45 +0000 Subject: [PATCH 0049/1001] BACKPORT: sched/fair: Update util_est only on util_avg updates The estimated utilization of a task is currently updated every time the task is dequeued. However, to keep overheads under control, PELT signals are effectively updated at maximum once every 1ms. Thus, for really short running tasks, it can happen that their util_avg value has not been updates since their last enqueue. If such tasks are also frequently running tasks (e.g. the kind of workload generated by hackbench) it can also happen that their util_avg is updated only every few activations. This means that updating util_est at every dequeue potentially introduces not necessary overheads and it's also conceptually wrong if the util_avg signal has never been updated during a task activation. Let's introduce a throttling mechanism on task's util_est updates to sync them with util_avg updates. To make the solution memory efficient, both in terms of space and load/store operations, we encode a synchronization flag into the LSB of util_est.enqueued. This makes util_est an even values only metric, which is still considered good enough for its purpose. The synchronization bit is (re)set by __update_load_avg_se() once the PELT signal of a task has been updated during its last activation. Such a throttling mechanism allows to keep under control util_est overheads in the wakeup hot path, thus making it a suitable mechanism which can be enabled also on high-intensity workload systems. Thus, this now switches on by default the estimation utilization scheduler feature. Suggested-by: Chris Redpath Signed-off-by: Patrick Bellasi Signed-off-by: Peter Zijlstra (Intel) Cc: Dietmar Eggemann Cc: Joel Fernandes Cc: Juri Lelli Cc: Linus Torvalds Cc: Morten Rasmussen Cc: Paul Turner Cc: Peter Zijlstra Cc: Rafael J . Wysocki Cc: Steve Muckle Cc: Thomas Gleixner Cc: Todd Kjos Cc: Vincent Guittot Cc: Viresh Kumar Link: http://lkml.kernel.org/r/20180309095245.11071-5-patrick.bellasi@arm.com Signed-off-by: Ingo Molnar [ backport from upstream: commit d519329f72a6 ("sched/fair: Update util_est only on util_avg updates") ] Signed-off-by: Patrick Bellasi Change-Id: I1309cffc11c1708c1030364facced7b25bcb49d7 --- kernel/sched/fair.c | 52 +++++++++++++++++++++++++++++++++++------ kernel/sched/features.h | 2 +- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 89b6dac144d5..32cbe41c01e3 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -3055,6 +3055,32 @@ ___update_load_avg(u64 now, int cpu, struct sched_avg *sa, return 1; } +/* + * When a task is dequeued, its estimated utilization should not be update if + * its util_avg has not been updated at least once. + * This flag is used to synchronize util_avg updates with util_est updates. + * We map this information into the LSB bit of the utilization saved at + * dequeue time (i.e. util_est.dequeued). + */ +#define UTIL_AVG_UNCHANGED 0x1 + +static inline void cfs_se_util_change(struct sched_avg *avg) +{ + unsigned int enqueued; + + if (!sched_feat(UTIL_EST)) + return; + + /* Avoid store if the flag has been already set */ + enqueued = avg->util_est.enqueued; + if (!(enqueued & UTIL_AVG_UNCHANGED)) + return; + + /* Reset flag to report util_avg has been updated */ + enqueued &= ~UTIL_AVG_UNCHANGED; + WRITE_ONCE(avg->util_est.enqueued, enqueued); +} + static int __update_load_avg_blocked_se(u64 now, int cpu, struct sched_entity *se) { @@ -3064,9 +3090,14 @@ __update_load_avg_blocked_se(u64 now, int cpu, struct sched_entity *se) static int __update_load_avg_se(u64 now, int cpu, struct cfs_rq *cfs_rq, struct sched_entity *se) { - return ___update_load_avg(now, cpu, &se->avg, - se->on_rq * scale_load_down(se->load.weight), - cfs_rq->curr == se, NULL, NULL); + if (___update_load_avg(now, cpu, &se->avg, + se->on_rq * scale_load_down(se->load.weight), + cfs_rq->curr == se, NULL, NULL)) { + cfs_se_util_change(&se->avg); + return 1; + } + + return 0; } static int @@ -3653,7 +3684,7 @@ static inline void util_est_enqueue(struct cfs_rq *cfs_rq, /* Update root cfs_rq's estimated utilization */ enqueued = cfs_rq->avg.util_est.enqueued; - enqueued += _task_util_est(p); + enqueued += (_task_util_est(p) | UTIL_AVG_UNCHANGED); WRITE_ONCE(cfs_rq->avg.util_est.enqueued, enqueued); } @@ -3689,7 +3720,7 @@ util_est_dequeue(struct cfs_rq *cfs_rq, struct task_struct *p, bool task_sleep) if (cfs_rq->nr_running) { ue.enqueued = cfs_rq->avg.util_est.enqueued; ue.enqueued -= min_t(unsigned int, ue.enqueued, - _task_util_est(p)); + (_task_util_est(p) | UTIL_AVG_UNCHANGED)); } WRITE_ONCE(cfs_rq->avg.util_est.enqueued, ue.enqueued); @@ -3700,12 +3731,19 @@ util_est_dequeue(struct cfs_rq *cfs_rq, struct task_struct *p, bool task_sleep) if (!task_sleep) return; + /* + * If the PELT values haven't changed since enqueue time, + * skip the util_est update. + */ + ue = p->se.avg.util_est; + if (ue.enqueued & UTIL_AVG_UNCHANGED) + return; + /* * Skip update of task's estimated utilization when its EWMA is * already ~1% close to its last activation value. */ - ue = p->se.avg.util_est; - ue.enqueued = task_util(p); + ue.enqueued = (task_util(p) | UTIL_AVG_UNCHANGED); last_ewma_diff = ue.enqueued - ue.ewma; if (within_margin(last_ewma_diff, (SCHED_CAPACITY_SCALE / 100))) return; diff --git a/kernel/sched/features.h b/kernel/sched/features.h index 2283e868983e..109e881a51c6 100644 --- a/kernel/sched/features.h +++ b/kernel/sched/features.h @@ -89,7 +89,7 @@ SCHED_FEAT(WA_BIAS, true) /* * UtilEstimation. Use estimated CPU utilization. */ -SCHED_FEAT(UTIL_EST, false) +SCHED_FEAT(UTIL_EST, true) /* * Energy aware scheduling. Use platform energy model to guide scheduling -- GitLab From 7fc13166181e8b70832b0491922c9c8c763d680f Mon Sep 17 00:00:00 2001 From: Patrick Bellasi Date: Thu, 24 May 2018 15:10:23 +0100 Subject: [PATCH 0050/1001] BACKPORT: sched/fair: Update util_est before updating schedutil When a task is enqueued the estimated utilization of a CPU is updated to better support the selection of the required frequency. However, schedutil is (implicitly) updated by update_load_avg() which always happens before util_est_{en,de}queue(), thus potentially introducing a latency between estimated utilization updates and frequency selections. Let's update util_est at the beginning of enqueue_task_fair(), which will ensure that all schedutil updates will see the most updated estimated utilization value for a CPU. Reported-by: Vincent Guittot Signed-off-by: Patrick Bellasi Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Thomas Gleixner Acked-by: Viresh Kumar Acked-by: Vincent Guittot Cc: Dietmar Eggemann Cc: Joel Fernandes Cc: Juri Lelli Cc: Linus Torvalds Cc: Morten Rasmussen Cc: Peter Zijlstra Cc: Rafael J . Wysocki Cc: Steve Muckle Fixes: 7f65ea42eb00 ("sched/fair: Add util_est on top of PELT") Link: http://lkml.kernel.org/r/20180524141023.13765-3-patrick.bellasi@arm.com Signed-off-by: Ingo Molnar [ backport from upstream: commit 2539fc82aa9b ("sched/fair: Update util_est before updating schedutil") ] Signed-off-by: Patrick Bellasi Change-Id: If84d40045bd283b0bbba2513a0aee0aa8c5058db --- kernel/sched/fair.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 32cbe41c01e3..68ab57d77c81 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5164,6 +5164,14 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) struct sched_entity *se = &p->se; int task_new = !(flags & ENQUEUE_WAKEUP); + /* + * The code below (indirectly) updates schedutil which looks at + * the cfs_rq utilization to select a frequency. + * Let's add the task's estimated utilization to the cfs_rq's + * estimated utilization, before we update schedutil. + */ + util_est_enqueue(&rq->cfs, p); + /* * If in_iowait is set, the code below may not trigger any cpufreq * utilization updates, so do it here explicitly with the IOWAIT flag @@ -5230,7 +5238,6 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) walt_inc_cumulative_runnable_avg(rq, p); } - util_est_enqueue(&rq->cfs, p); hrtick_update(rq); } -- GitLab From cb22d9159761cb32c35a5f9399b8011fcdae654b Mon Sep 17 00:00:00 2001 From: Patrick Bellasi Date: Tue, 21 Nov 2017 16:31:58 +0000 Subject: [PATCH 0051/1001] FROMLIST: sched/fair: add support to tune PELT ramp/decay timings The PELT half-life is the time [ms] required by the PELT signal to build up a 50% load/utilization, starting from zero. This time is currently hardcoded to be 32ms, a value which seems to make sense for most of the workloads. However, 32ms has been verified to be too long for certain classes of workloads. For example, in the mobile space many tasks affecting the user-experience run with a 16ms or 8ms cadence, since they need to match the common 60Hz or 120Hz refresh rate of the graphics pipeline. This contributed so fare to the idea that "PELT is too slow" to properly track the utilization of interactive mobile workloads, especially compared to alternative load tracking solutions which provides a better representation of tasks demand in the range of 10-20ms. A faster PELT ramp-up time could give some advantages to speed-up the time required for the signal to stabilize and thus to better represent task demands in the mobile space. As a downside, it also reduces the decay time, and thus we forget the load/utilization of sleeping tasks (or idle CPUs) faster. Fortunately, since the integration of the utilization estimation support in mainline kernel: commit 7f65ea42eb00 ("sched/fair: Add util_est on top of PELT") a fast decay time is no longer an issue for tasks utilization estimation. Although estimated utilization does not slow down the decay of blocked utilization on idle CPUs, for mobile workloads this seems not to be a major concern compared to the benefits in interactivity responsiveness. Let's add a compile time option to choose the PELT speed which better fits for a specific system. By default the current 32ms half-life is used, but we can also compile a kernel to use a faster ramp-up time of either 16ms or 8ms. These two configurations have been verified to give PELT a further improvement in performance, compared to other out-of-tree load tracking solutions, when it comes to track interactive workloads thus better supporting both tasks placements and frequencies selections. Signed-off-by: Patrick Bellasi Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Jonathan Corbet Cc: Paul Turner Cc: Vincent Guittot Cc: Joel Fernandes Cc: Morten Rasmussen Cc: linux-doc@vger.kernel.org Cc: linux-kernel@vger.kernel.org [ backport from LKML: Message-ID: <20180409165134.707-1-patrick.bellasi@arm.com> ] Signed-off-by: Patrick Bellasi Change-Id: I50569748918b799ac4bf4e7d2b387253080a0fd2 --- Documentation/scheduler/sched-pelt.c | 42 +++++++++++-------- init/Kconfig | 35 ++++++++++++++++ kernel/sched/sched-pelt.h | 60 +++++++++++++++++++++++++--- 3 files changed, 115 insertions(+), 22 deletions(-) diff --git a/Documentation/scheduler/sched-pelt.c b/Documentation/scheduler/sched-pelt.c index e4219139386a..cd3e1fe7a98a 100644 --- a/Documentation/scheduler/sched-pelt.c +++ b/Documentation/scheduler/sched-pelt.c @@ -10,21 +10,21 @@ #include #include -#define HALFLIFE 32 +#define HALFLIFE { 32, 16, 8 } #define SHIFT 32 double y; -void calc_runnable_avg_yN_inv(void) +void calc_runnable_avg_yN_inv(const int halflife) { int i; unsigned int x; printf("static const u32 runnable_avg_yN_inv[] = {"); - for (i = 0; i < HALFLIFE; i++) { + for (i = 0; i < halflife; i++) { x = ((1UL<<32)-1)*pow(y, i); - if (i % 6 == 0) printf("\n\t"); + if (i % 4 == 0) printf("\n\t"); printf("0x%8x, ", x); } printf("\n};\n\n"); @@ -32,12 +32,12 @@ void calc_runnable_avg_yN_inv(void) int sum = 1024; -void calc_runnable_avg_yN_sum(void) +void calc_runnable_avg_yN_sum(const int halflife) { int i; printf("static const u32 runnable_avg_yN_sum[] = {\n\t 0,"); - for (i = 1; i <= HALFLIFE; i++) { + for (i = 1; i <= halflife; i++) { if (i == 1) sum *= y; else @@ -55,7 +55,7 @@ int n = -1; /* first period */ long max = 1024; -void calc_converged_max(void) +void calc_converged_max(const int halflife) { long last = 0, y_inv = ((1UL<<32)-1)*y; @@ -73,17 +73,17 @@ void calc_converged_max(void) last = max; } n--; - printf("#define LOAD_AVG_PERIOD %d\n", HALFLIFE); + printf("#define LOAD_AVG_PERIOD %d\n", halflife); printf("#define LOAD_AVG_MAX %ld\n", max); -// printf("#define LOAD_AVG_MAX_N %d\n\n", n); + printf("#define LOAD_AVG_MAX_N %d\n\n", n); } -void calc_accumulated_sum_32(void) +void calc_accumulated_sum_32(const int halflife) { int i, x = sum; printf("static const u32 __accumulated_sum_N32[] = {\n\t 0,"); - for (i = 1; i <= n/HALFLIFE+1; i++) { + for (i = 1; i <= n/halflife+1; i++) { if (i > 1) x = x/2 + sum; @@ -97,12 +97,22 @@ void calc_accumulated_sum_32(void) void main(void) { + int hl_value[] = HALFLIFE; + int hl_count = sizeof(hl_value) / sizeof(int); + int hl_idx, halflife; + printf("/* Generated by Documentation/scheduler/sched-pelt; do not modify. */\n\n"); - y = pow(0.5, 1/(double)HALFLIFE); + for (hl_idx = 0; hl_idx < hl_count; ++hl_idx) { + halflife = hl_value[hl_idx]; + + y = pow(0.5, 1/(double)halflife); - calc_runnable_avg_yN_inv(); -// calc_runnable_avg_yN_sum(); - calc_converged_max(); -// calc_accumulated_sum_32(); + printf("#if CONFIG_PELT_UTIL_HALFLIFE_%d\n", halflife); + calc_runnable_avg_yN_inv(halflife); + calc_runnable_avg_yN_sum(halflife); + calc_converged_max(halflife); + calc_accumulated_sum_32(halflife); + printf("#endif\n\n"); + } } diff --git a/init/Kconfig b/init/Kconfig index 0d0798a6706d..37ecab2cba99 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -595,6 +595,41 @@ config HAVE_UNSTABLE_SCHED_CLOCK config GENERIC_SCHED_CLOCK bool +menu "FAIR Scheuler tunables" + +choice + prompt "Utilization's PELT half-Life" + default PELT_UTIL_HALFLIFE_32 + help + Allows choosing one of the possible values for the PELT half-life to + be used for the update of the utilization of tasks and CPUs. + The half-life is the amount of [ms] required by the PELT signal to + build up to 50% utilization. The higher the half-life the longer it + takes for a task to be represented as a big one. + + If not sure, use the default of 32 ms. + +config PELT_UTIL_HALFLIFE_32 + bool "32 ms, default for server" + +config PELT_UTIL_HALFLIFE_16 + bool "16 ms, suggested for interactive workloads" + help + Use 16ms as PELT half-life value. This will increase the ramp-up and + decay of utlization and load twice as fast as for the default + configuration using 32ms. + +config PELT_UTIL_HALFLIFE_8 + bool "8 ms, very fast" + help + Use 8ms as PELT half-life value. This will increase the ramp-up and + decay of utlization and load four time as fast as for the default + configuration using 32ms. + +endchoice + +endmenu # FAIR Scheduler tunables" + # # For architectures that want to enable the support for NUMA-affine scheduler # balancing logic: diff --git a/kernel/sched/sched-pelt.h b/kernel/sched/sched-pelt.h index a26473674fb7..ac7d489be8ce 100644 --- a/kernel/sched/sched-pelt.h +++ b/kernel/sched/sched-pelt.h @@ -1,14 +1,62 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Generated by Documentation/scheduler/sched-pelt; do not modify. */ + +#ifdef CONFIG_PELT_UTIL_HALFLIFE_32 static const u32 runnable_avg_yN_inv[] = { - 0xffffffff, 0xfa83b2da, 0xf5257d14, 0xefe4b99a, 0xeac0c6e6, 0xe5b906e6, - 0xe0ccdeeb, 0xdbfbb796, 0xd744fcc9, 0xd2a81d91, 0xce248c14, 0xc9b9bd85, - 0xc5672a10, 0xc12c4cc9, 0xbd08a39e, 0xb8fbaf46, 0xb504f333, 0xb123f581, - 0xad583ee9, 0xa9a15ab4, 0xa5fed6a9, 0xa2704302, 0x9ef5325f, 0x9b8d39b9, - 0x9837f050, 0x94f4efa8, 0x91c3d373, 0x8ea4398a, 0x8b95c1e3, 0x88980e80, - 0x85aac367, 0x82cd8698, + 0xffffffff,0xfa83b2da,0xf5257d14,0xefe4b99a, + 0xeac0c6e6,0xe5b906e6,0xe0ccdeeb,0xdbfbb796, + 0xd744fcc9,0xd2a81d91,0xce248c14,0xc9b9bd85, + 0xc5672a10,0xc12c4cc9,0xbd08a39e,0xb8fbaf46, + 0xb504f333,0xb123f581,0xad583ee9,0xa9a15ab4, + 0xa5fed6a9,0xa2704302,0x9ef5325f,0x9b8d39b9, + 0x9837f050,0x94f4efa8,0x91c3d373,0x8ea4398a, + 0x8b95c1e3,0x88980e80,0x85aac367,0x82cd8698, +}; + +static const u32 runnable_avg_yN_sum[] = { + 0, 1002, 1982, 2941, 3880, 4798, 5697, 6576, 7437, 8279, 9103, + 9909,10698,11470,12226,12966,13690,14398,15091,15769,16433,17082, + 17718,18340,18949,19545,20128,20698,21256,21802,22336,22859,23371, }; #define LOAD_AVG_PERIOD 32 #define LOAD_AVG_MAX 47742 +#define LOAD_AVG_MAX_N 345 + +#endif + +#ifdef CONFIG_PELT_UTIL_HALFLIFE_16 +static const u32 runnable_avg_yN_inv[] = { + 0xffffffff,0xf5257d14,0xeac0c6e6,0xe0ccdeeb, + 0xd744fcc9,0xce248c14,0xc5672a10,0xbd08a39e, + 0xb504f333,0xad583ee9,0xa5fed6a9,0x9ef5325f, + 0x9837f050,0x91c3d373,0x8b95c1e3,0x85aac367, +}; + +static const u32 runnable_avg_yN_sum[] = { + 0,22380,22411,22441,22470,22497,22523,22548,22572,22595,22617, + 22638,22658,22677,22696,22714,22731, +}; + +#define LOAD_AVG_PERIOD 16 +#define LOAD_AVG_MAX 24152 +#define LOAD_AVG_MAX_N 517 + +#endif + +#ifdef CONFIG_PELT_UTIL_HALFLIFE_8 +static const u32 runnable_avg_yN_inv[] = { + 0xffffffff,0xeac0c6e6,0xd744fcc9,0xc5672a10, + 0xb504f333,0xa5fed6a9,0x9837f050,0x8b95c1e3, +}; + +static const u32 runnable_avg_yN_sum[] = { + 0,20844,20053,19327,18661,18051,17491,16978,16507, +}; + +#define LOAD_AVG_PERIOD 8 +#define LOAD_AVG_MAX 12337 +#define LOAD_AVG_MAX_N 603 + +#endif -- GitLab From 78605d7daf0b8a9ec559fc38431dd19f015eed7a Mon Sep 17 00:00:00 2001 From: Patrick Bellasi Date: Tue, 15 May 2018 12:43:31 +0100 Subject: [PATCH 0052/1001] ANDROID: sched/fair: schedtune: update before schedutil When a task is enqueue its boosted value must be accounted on that CPU to better support the selection of the required frequency. However, schedutil is (implicitly) updated by update_load_avg() which always happens before schedtune_{en,de}queue_task(), thus potentially introducing a latency between boost value updates and frequency selections. Let's update schedtune at the beginning of enqueue_task_fair(), which will ensure that all schedutil updates will see the most updated boost value for a CPU. Signed-off-by: Patrick Bellasi Change-Id: I1038f00600dd43ca38b76b2c5681b4f438ae4036 --- kernel/sched/fair.c | 54 ++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 68ab57d77c81..9db0d45d638a 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5172,6 +5172,24 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) */ util_est_enqueue(&rq->cfs, p); + /* + * The code below (indirectly) updates schedutil which looks at + * the cfs_rq utilization to select a frequency. + * Let's update schedtune here to ensure the boost value of the + * current task is accounted for in the selection of the OPP. + * + * We do it also in the case where we enqueue a throttled task; + * we could argue that a throttled task should not boost a CPU, + * however: + * a) properly implementing CPU boosting considering throttled + * tasks will increase a lot the complexity of the solution + * b) it's not easy to quantify the benefits introduced by + * such a more complex solution. + * Thus, for the time being we go for the simple solution and boost + * also for throttled RQs. + */ + schedtune_enqueue_task(p, cpu_of(rq)); + /* * If in_iowait is set, the code below may not trigger any cpufreq * utilization updates, so do it here explicitly with the IOWAIT flag @@ -5212,25 +5230,6 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) update_cfs_shares(se); } - /* - * Update SchedTune accounting. - * - * We do it before updating the CPU capacity to ensure the - * boost value of the current task is accounted for in the - * selection of the OPP. - * - * We do it also in the case where we enqueue a throttled task; - * we could argue that a throttled task should not boost a CPU, - * however: - * a) properly implementing CPU boosting considering throttled - * tasks will increase a lot the complexity of the solution - * b) it's not easy to quantify the benefits introduced by - * such a more complex solution. - * Thus, for the time being we go for the simple solution and boost - * also for throttled RQs. - */ - schedtune_enqueue_task(p, cpu_of(rq)); - if (!se) { add_nr_running(rq, 1); if (!task_new) @@ -5254,6 +5253,14 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags) struct sched_entity *se = &p->se; int task_sleep = flags & DEQUEUE_SLEEP; + /* + * The code below (indirectly) updates schedutil which looks at + * the cfs_rq utilization to select a frequency. + * Let's update schedtune here to ensure the boost value of the + * current task is not more accounted for in the selection of the OPP. + */ + schedtune_dequeue_task(p, cpu_of(rq)); + for_each_sched_entity(se) { cfs_rq = cfs_rq_of(se); dequeue_entity(cfs_rq, se, flags); @@ -5296,15 +5303,6 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags) update_cfs_shares(se); } - /* - * Update SchedTune accounting - * - * We do it before updating the CPU capacity to ensure the - * boost value of the current task is accounted for in the - * selection of the OPP. - */ - schedtune_dequeue_task(p, cpu_of(rq)); - if (!se) { sub_nr_running(rq, 1); walt_dec_cumulative_runnable_avg(rq, p); -- GitLab From a9d8b29e5195a8ecc3b485f19b71533b07e34792 Mon Sep 17 00:00:00 2001 From: Patrick Bellasi Date: Fri, 27 Oct 2017 16:12:51 +0100 Subject: [PATCH 0053/1001] ANDROID: sched/events: Introduce util_est trace events Signed-off-by: Patrick Bellasi Change-Id: I359f7ffbd62e86a16a96d7f02da38e9ff260fd99 --- include/trace/events/sched.h | 63 ++++++++++++++++++++++++++++++++++++ kernel/sched/fair.c | 29 +++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index 51964d88bc83..9239d1c0aa08 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -986,6 +986,69 @@ TRACE_EVENT(sched_find_best_target, __entry->target) ); +/* + * Tracepoint for tasks' estimated utilization. + */ +TRACE_EVENT(sched_util_est_task, + + TP_PROTO(struct task_struct *tsk, struct sched_avg *avg), + + TP_ARGS(tsk, avg), + + TP_STRUCT__entry( + __array( char, comm, TASK_COMM_LEN ) + __field( pid_t, pid ) + __field( int, cpu ) + __field( unsigned int, util_avg ) + __field( unsigned int, est_enqueued ) + __field( unsigned int, est_ewma ) + ), + + TP_fast_assign( + memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN); + __entry->pid = tsk->pid; + __entry->cpu = task_cpu(tsk); + __entry->util_avg = avg->util_avg; + __entry->est_enqueued = avg->util_est.enqueued; + __entry->est_ewma = avg->util_est.ewma; + ), + + TP_printk("comm=%s pid=%d cpu=%d util_avg=%u util_est_ewma=%u util_est_enqueued=%u", + __entry->comm, + __entry->pid, + __entry->cpu, + __entry->util_avg, + __entry->est_ewma, + __entry->est_enqueued) +); + +/* + * Tracepoint for root cfs_rq's estimated utilization. + */ +TRACE_EVENT(sched_util_est_cpu, + + TP_PROTO(int cpu, struct cfs_rq *cfs_rq), + + TP_ARGS(cpu, cfs_rq), + + TP_STRUCT__entry( + __field( int, cpu ) + __field( unsigned int, util_avg ) + __field( unsigned int, util_est_enqueued ) + ), + + TP_fast_assign( + __entry->cpu = cpu; + __entry->util_avg = cfs_rq->avg.util_avg; + __entry->util_est_enqueued = cfs_rq->avg.util_est.enqueued; + ), + + TP_printk("cpu=%d util_avg=%u util_est_enqueued=%u", + __entry->cpu, + __entry->util_avg, + __entry->util_est_enqueued) +); + #ifdef CONFIG_SCHED_WALT struct rq; diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 9db0d45d638a..0cc6a955dbc1 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -3094,6 +3094,28 @@ __update_load_avg_se(u64 now, int cpu, struct cfs_rq *cfs_rq, struct sched_entit se->on_rq * scale_load_down(se->load.weight), cfs_rq->curr == se, NULL, NULL)) { cfs_se_util_change(&se->avg); + +#ifdef UTIL_EST_DEBUG + /* + * Trace utilization only for actual tasks. + * + * These trace events are mostly useful to get easier to + * read plots for the estimated utilization, where we can + * compare it with the actual grow/decrease of the original + * PELT signal. + * Let's keep them disabled by default in "production kernels". + */ + if (entity_is_task(se)) { + struct task_struct *tsk = task_of(se); + + trace_sched_util_est_task(tsk, &se->avg); + + /* Trace utilization only for top level CFS RQ */ + cfs_rq = &(task_rq(tsk)->cfs); + trace_sched_util_est_cpu(cpu, cfs_rq); + } +#endif /* UTIL_EST_DEBUG */ + return 1; } @@ -3686,6 +3708,9 @@ static inline void util_est_enqueue(struct cfs_rq *cfs_rq, enqueued = cfs_rq->avg.util_est.enqueued; enqueued += (_task_util_est(p) | UTIL_AVG_UNCHANGED); WRITE_ONCE(cfs_rq->avg.util_est.enqueued, enqueued); + + trace_sched_util_est_task(p, &p->se.avg); + trace_sched_util_est_cpu(cpu_of(rq_of(cfs_rq)), cfs_rq); } /* @@ -3724,6 +3749,8 @@ util_est_dequeue(struct cfs_rq *cfs_rq, struct task_struct *p, bool task_sleep) } WRITE_ONCE(cfs_rq->avg.util_est.enqueued, ue.enqueued); + trace_sched_util_est_cpu(cpu_of(rq_of(cfs_rq)), cfs_rq); + /* * Skip update of task's estimated utilization when the task has not * yet completed an activation, e.g. being migrated. @@ -3769,6 +3796,8 @@ util_est_dequeue(struct cfs_rq *cfs_rq, struct task_struct *p, bool task_sleep) ue.ewma += last_ewma_diff; ue.ewma >>= UTIL_EST_WEIGHT_SHIFT; WRITE_ONCE(p->se.avg.util_est, ue); + + trace_sched_util_est_task(p, &p->se.avg); } #else /* CONFIG_SMP */ -- GitLab From 6381e47c0ba49a6a08de171702869f068cb1e3b5 Mon Sep 17 00:00:00 2001 From: Suraj Dongre Date: Wed, 18 Jul 2018 14:34:03 -0700 Subject: [PATCH 0054/1001] msm: camera: fix double free in jpeg mgr Add NULL check for cdm cmd to avoid double free. Change-Id: I639037394f123ce09031b5afab25a5bbcbbbd498 Signed-off-by: Suraj Dongre --- .../platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index b8b3612786c0..8d033cd23d4d 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -957,7 +957,6 @@ static int cam_jpeg_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) if (hw_mgr->cdm_info[dev_type][0].ref_cnt == 0) { mutex_unlock(&hw_mgr->hw_mgr_mutex); CAM_ERR(CAM_JPEG, "Error Unbalanced deinit"); - kfree(ctx_data->cdm_cmd); return -EFAULT; } @@ -979,10 +978,13 @@ static int cam_jpeg_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) mutex_unlock(&hw_mgr->hw_mgr_mutex); CAM_ERR(CAM_JPEG, "JPEG release ctx failed"); kfree(ctx_data->cdm_cmd); + ctx_data->cdm_cmd = NULL; + return -EINVAL; } kfree(ctx_data->cdm_cmd); + ctx_data->cdm_cmd = NULL; CAM_DBG(CAM_JPEG, "handle %llu", ctx_data); return rc; -- GitLab From 572cdb99e9a32bda15aa07f0d9de7e27aad04825 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 29 May 2017 16:38:16 -0700 Subject: [PATCH 0055/1001] ANDROID: mnt: Fix next_descendent next_descendent did not properly handle the case where the initial mount had no slaves. In this case, we would look for the next slave, but since don't have a master, the check for wrapping around to the start of the list will always fail. Instead, we check for this case, and ensure that we end the iteration when we come back to the root. Signed-off-by: Daniel Rosenberg Bug: 62094374 Change-Id: I43dfcee041aa3730cb4b9a1161418974ef84812e --- fs/pnode.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/fs/pnode.c b/fs/pnode.c index 386884dd6d97..56f9a28a688b 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -616,9 +616,14 @@ static struct mount *next_descendent(struct mount *root, struct mount *cur) if (!IS_MNT_NEW(cur) && !list_empty(&cur->mnt_slave_list)) return first_slave(cur); do { - if (cur->mnt_slave.next != &cur->mnt_master->mnt_slave_list) - return next_slave(cur); - cur = cur->mnt_master; + struct mount *master = cur->mnt_master; + + if (!master || cur->mnt_slave.next != &master->mnt_slave_list) { + struct mount *next = next_slave(cur); + + return (next == root) ? NULL : next; + } + cur = master; } while (cur != root); return NULL; } -- GitLab From d41481eebd9926503af255f1552ef0dbced93f3c Mon Sep 17 00:00:00 2001 From: Satya Durga Srinivasu Prabhala Date: Wed, 8 Nov 2017 12:13:47 -0800 Subject: [PATCH 0056/1001] ANDROID: sched/walt: Fix compilation issue for x86_64 Below compilation errors observed when SCHED_WALT enabled and FAIR_GROUP_SCHED is disabled, fix it. CC kernel/sched/walt.o kernel/sched/walt.c: In function .walt_inc_cfs_cumulative_runnable_avg.: kernel/sched/walt.c:157:8: error: .struct cfs_rq. has no member named .cumulative_runnable_avg. cfs_rq->cumulative_runnable_avg += p->ravg.demand; ^ kernel/sched/walt.c: In function .walt_dec_cfs_cumulative_runnable_avg.: kernel/sched/walt.c:163:8: error: .struct cfs_rq. has no member named .cumulative_runnable_avg. cfs_rq->cumulative_runnable_avg -= p->ravg.demand; ^ make[2]: *** [kernel/sched/walt.o] Error 1 make[1]: *** [kernel/sched] Error 2 make: *** [kernel] Error 2 Change-Id: I52d506aa5494f4c351f19e6bb2f1a75c8333f321 Signed-off-by: Satya Durga Srinivasu Prabhala (cherry-picked for android-4.14) Signed-off-by: Chris Redpath --- kernel/sched/sched.h | 7 +++---- kernel/sched/walt.c | 2 ++ kernel/sched/walt.h | 21 +++++++++++++-------- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 690a0fac09a8..65a39096b3af 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -483,10 +483,6 @@ struct cfs_rq { struct list_head leaf_cfs_rq_list; struct task_group *tg; /* group that "owns" this runqueue */ -#ifdef CONFIG_SCHED_WALT - u64 cumulative_runnable_avg; -#endif - #ifdef CONFIG_CFS_BANDWIDTH int runtime_enabled; u64 runtime_expires; @@ -496,6 +492,9 @@ struct cfs_rq { u64 throttled_clock_task_time; int throttled, throttle_count; struct list_head throttled_list; +#ifdef CONFIG_SCHED_WALT + u64 cumulative_runnable_avg; +#endif /* CONFIG_SCHED_WALT */ #endif /* CONFIG_CFS_BANDWIDTH */ #endif /* CONFIG_FAIR_GROUP_SCHED */ }; diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index 01a411bf0858..6a88c6e47d8c 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -148,6 +148,7 @@ static int __init walt_init_ops(void) } late_initcall(walt_init_ops); +#ifdef CONFIG_CFS_BANDWIDTH void walt_inc_cfs_cumulative_runnable_avg(struct cfs_rq *cfs_rq, struct task_struct *p) { @@ -159,6 +160,7 @@ void walt_dec_cfs_cumulative_runnable_avg(struct cfs_rq *cfs_rq, { cfs_rq->cumulative_runnable_avg -= p->ravg.demand; } +#endif static int exiting_task(struct task_struct *p) { diff --git a/kernel/sched/walt.h b/kernel/sched/walt.h index c7a4ef96a061..3446ca1be8ac 100644 --- a/kernel/sched/walt.h +++ b/kernel/sched/walt.h @@ -20,10 +20,7 @@ void walt_update_task_ravg(struct task_struct *p, struct rq *rq, int event, u64 wallclock, u64 irqtime); void walt_inc_cumulative_runnable_avg(struct rq *rq, struct task_struct *p); void walt_dec_cumulative_runnable_avg(struct rq *rq, struct task_struct *p); -void walt_inc_cfs_cumulative_runnable_avg(struct cfs_rq *rq, - struct task_struct *p); -void walt_dec_cfs_cumulative_runnable_avg(struct cfs_rq *rq, - struct task_struct *p); + void walt_fixup_busy_time(struct task_struct *p, int new_cpu); void walt_init_new_task_load(struct task_struct *p); void walt_mark_task_starting(struct task_struct *p); @@ -42,10 +39,6 @@ static inline void walt_update_task_ravg(struct task_struct *p, struct rq *rq, int event, u64 wallclock, u64 irqtime) { } static inline void walt_inc_cumulative_runnable_avg(struct rq *rq, struct task_struct *p) { } static inline void walt_dec_cumulative_runnable_avg(struct rq *rq, struct task_struct *p) { } -static inline void walt_inc_cfs_cumulative_runnable_avg(struct cfs_rq *rq, - struct task_struct *p) { } -static inline void walt_dec_cfs_cumulative_runnable_avg(struct cfs_rq *rq, - struct task_struct *p) { } static inline void walt_fixup_busy_time(struct task_struct *p, int new_cpu) { } static inline void walt_init_new_task_load(struct task_struct *p) { } static inline void walt_mark_task_starting(struct task_struct *p) { } @@ -57,6 +50,18 @@ static inline u64 walt_ktime_clock(void) { return 0; } #endif /* CONFIG_SCHED_WALT */ +#if defined(CONFIG_CFS_BANDWIDTH) && defined(CONFIG_SCHED_WALT) +void walt_inc_cfs_cumulative_runnable_avg(struct cfs_rq *rq, + struct task_struct *p); +void walt_dec_cfs_cumulative_runnable_avg(struct cfs_rq *rq, + struct task_struct *p); +#else +static inline void walt_inc_cfs_cumulative_runnable_avg(struct cfs_rq *rq, + struct task_struct *p) { } +static inline void walt_dec_cfs_cumulative_runnable_avg(struct cfs_rq *rq, + struct task_struct *p) { } +#endif + extern bool walt_disabled; #endif -- GitLab From 28fffded4abc1ac941160c6daa3d2ba7b0b7e0ff Mon Sep 17 00:00:00 2001 From: Satya Durga Srinivasu Prabhala Date: Thu, 19 Jul 2018 11:35:34 -0700 Subject: [PATCH 0057/1001] ANDROID: sched/fair: fix a warning Below warning got introduced by 'commit 2cc3df5e1c7be78 ("ANDROID: sched: Update max cpu capacity in case of max frequency constraints")': warning: '&&' within '||' [-Wlogical-op-parentheses] Add parentheses required to fix the warning. Signed-off-by: Satya Durga Srinivasu Prabhala --- kernel/sched/fair.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 0cc6a955dbc1..8862fadbef97 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -9165,7 +9165,7 @@ static void update_cpu_capacity(struct sched_domain *sd, int cpu) max_capacity = mcc->val; max_cap_cpu = mcc->cpu; - if (max_capacity > capacity && max_cap_cpu == cpu || + if ((max_capacity > capacity && max_cap_cpu == cpu) || max_capacity < capacity) { mcc->val = capacity; mcc->cpu = cpu; -- GitLab From 55e591cc187928bac11cd2596eeea930df845cad Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 15 Mar 2018 23:03:11 +0100 Subject: [PATCH 0058/1001] BACKPORT: time: tick-sched: Reorganize idle tick management code Prepare the scheduler tick code for reworking the idle loop to avoid stopping the tick in some cases. The idea is to split the nohz idle entry call to decouple the idle time stats accounting and preparatory work from the actual tick stop code, in order to later be able to delay the tick stop once we reach more power-knowledgeable callers. Move away the tick_nohz_start_idle() invocation from __tick_nohz_idle_enter(), rename the latter to __tick_nohz_idle_stop_tick() and define tick_nohz_idle_stop_tick() as a wrapper around it for calling it from the outside. Make tick_nohz_idle_enter() only call tick_nohz_start_idle() instead of calling the entire __tick_nohz_idle_enter(), add another wrapper disabling and enabling interrupts around tick_nohz_idle_stop_tick() and make the current callers of tick_nohz_idle_enter() call it too to retain their current functionality. Cherry-picked from 0e7767687fdabfc58d5046e7488632bf2ecd4d0c - Fixed conflict with hrtimer_next_event_base which does not have an extra parameter in the backported code Change-Id: Iae3b22cdc0db13212af07249b085b4b97abf557e Signed-off-by: Rafael J. Wysocki Reviewed-by: Frederic Weisbecker Cc: Leo Yan Cc: Todd Kjos Cc: Joel Fernandes Cc: Paven Kondati Signed-off-by: Daniel Lezcano --- arch/x86/xen/smp_pv.c | 1 + include/linux/tick.h | 12 +++++++++++ kernel/sched/idle.c | 1 + kernel/time/tick-sched.c | 46 ++++++++++++++++++++++------------------ 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/arch/x86/xen/smp_pv.c b/arch/x86/xen/smp_pv.c index db6d90e451de..e3b18ad49889 100644 --- a/arch/x86/xen/smp_pv.c +++ b/arch/x86/xen/smp_pv.c @@ -430,6 +430,7 @@ static void xen_pv_play_dead(void) /* used only with HOTPLUG_CPU */ * data back is to call: */ tick_nohz_idle_enter(); + tick_nohz_idle_stop_tick_protected(); cpuhp_online_idle(CPUHP_AP_ONLINE_IDLE); } diff --git a/include/linux/tick.h b/include/linux/tick.h index 5cdac11dd317..4bf24c860151 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -114,6 +114,7 @@ enum tick_dep_bits { #ifdef CONFIG_NO_HZ_COMMON extern bool tick_nohz_enabled; extern int tick_nohz_tick_stopped(void); +extern void tick_nohz_idle_stop_tick(void); extern void tick_nohz_idle_enter(void); extern void tick_nohz_idle_exit(void); extern void tick_nohz_irq_exit(void); @@ -122,9 +123,18 @@ extern unsigned long tick_nohz_get_idle_calls(void); extern unsigned long tick_nohz_get_idle_calls_cpu(int cpu); extern u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time); extern u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time); + +static inline void tick_nohz_idle_stop_tick_protected(void) +{ + local_irq_disable(); + tick_nohz_idle_stop_tick(); + local_irq_enable(); +} + #else /* !CONFIG_NO_HZ_COMMON */ #define tick_nohz_enabled (0) static inline int tick_nohz_tick_stopped(void) { return 0; } +static inline void tick_nohz_idle_stop_tick(void) { } static inline void tick_nohz_idle_enter(void) { } static inline void tick_nohz_idle_exit(void) { } @@ -134,6 +144,8 @@ static inline ktime_t tick_nohz_get_sleep_length(void) } static inline u64 get_cpu_idle_time_us(int cpu, u64 *unused) { return -1; } static inline u64 get_cpu_iowait_time_us(int cpu, u64 *unused) { return -1; } + +static inline void tick_nohz_idle_stop_tick_protected(void) { } #endif /* !CONFIG_NO_HZ_COMMON */ #ifdef CONFIG_NO_HZ_FULL diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index c1dbb2cc1f29..9ce10f647c78 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -222,6 +222,7 @@ static void do_idle(void) __current_set_polling(); quiet_vmstat(); tick_nohz_idle_enter(); + tick_nohz_idle_stop_tick_protected(); while (!need_resched()) { check_pgt_cache(); diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index bb2af74e6b62..42df8d6a328f 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -563,14 +563,11 @@ static void tick_nohz_stop_idle(struct tick_sched *ts, ktime_t now) sched_clock_idle_wakeup_event(); } -static ktime_t tick_nohz_start_idle(struct tick_sched *ts) +static void tick_nohz_start_idle(struct tick_sched *ts) { - ktime_t now = ktime_get(); - - ts->idle_entrytime = now; + ts->idle_entrytime = ktime_get(); ts->idle_active = 1; sched_clock_idle_sleep_event(); - return now; } /** @@ -935,19 +932,21 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts) return true; } -static void __tick_nohz_idle_enter(struct tick_sched *ts) +static void __tick_nohz_idle_stop_tick(struct tick_sched *ts) { - ktime_t now, expires; + ktime_t expires; int cpu = smp_processor_id(); - now = tick_nohz_start_idle(ts); - if (can_stop_idle_tick(cpu, ts)) { int was_stopped = ts->tick_stopped; ts->idle_calls++; - expires = tick_nohz_stop_sched_tick(ts, now, cpu); + /* + * The idle entry time should be a sufficient approximation of + * the current time at this point. + */ + expires = tick_nohz_stop_sched_tick(ts, ts->idle_entrytime, cpu); if (expires > 0LL) { ts->idle_sleeps++; ts->idle_expires = expires; @@ -961,16 +960,19 @@ static void __tick_nohz_idle_enter(struct tick_sched *ts) } /** - * tick_nohz_idle_enter - stop the idle tick from the idle task + * tick_nohz_idle_stop_tick - stop the idle tick from the idle task * * When the next event is more than a tick into the future, stop the idle tick - * Called when we start the idle loop. - * - * The arch is responsible of calling: + */ +void tick_nohz_idle_stop_tick(void) +{ + __tick_nohz_idle_stop_tick(this_cpu_ptr(&tick_cpu_sched)); +} + +/** + * tick_nohz_idle_enter - prepare for entering idle on the current CPU * - * - rcu_idle_enter() after its last use of RCU before the CPU is put - * to sleep. - * - rcu_idle_exit() before the first use of RCU after the CPU is woken up. + * Called when we start the idle loop. */ void tick_nohz_idle_enter(void) { @@ -990,7 +992,7 @@ void tick_nohz_idle_enter(void) ts = this_cpu_ptr(&tick_cpu_sched); ts->inidle = 1; - __tick_nohz_idle_enter(ts); + tick_nohz_start_idle(ts); local_irq_enable(); } @@ -1007,10 +1009,12 @@ void tick_nohz_irq_exit(void) { struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); - if (ts->inidle) - __tick_nohz_idle_enter(ts); - else + if (ts->inidle) { + tick_nohz_start_idle(ts); + __tick_nohz_idle_stop_tick(ts); + } else { tick_nohz_full_update_tick(ts); + } } /** -- GitLab From f6d3093dfc66bf0afcaafa3615ae45cd3ffd6530 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 15 Mar 2018 23:05:50 +0100 Subject: [PATCH 0059/1001] BACKPORT: sched: idle: Do not stop the tick upfront in the idle loop Push the decision whether or not to stop the tick somewhat deeper into the idle loop. Stopping the tick upfront leads to unpleasant outcomes in case the idle governor doesn't agree with the nohz code on the duration of the upcoming idle period. Specifically, if the tick has been stopped and the idle governor predicts short idle, the situation is bad regardless of whether or not the prediction is accurate. If it is accurate, the tick has been stopped unnecessarily which means excessive overhead. If it is not accurate, the CPU is likely to spend too much time in the (shallow, because short idle has been predicted) idle state selected by the governor [1]. As the first step towards addressing this problem, change the code to make the tick stopping decision inside of the loop in do_idle(). In particular, do not stop the tick in the cpu_idle_poll() code path. Also don't do that in tick_nohz_irq_exit() which doesn't really have enough information on whether or not to stop the tick. Cherry-picked from 2aaf709a518d26563b80fd7a42379d7aa7ffed4a - Fixed conflict with tick_nohz_stopped_cpu not appearing in the chunk context. Trivial fix. Change-Id: Ie316e210971f28aae80dd0f35c5564cb17a81901 Link: https://marc.info/?l=linux-pm&m=150116085925208&w=2 # [1] Link: https://tu-dresden.de/zih/forschung/ressourcen/dateien/projekte/haec/powernightmares.pdf Suggested-by: Frederic Weisbecker Signed-off-by: Rafael J. Wysocki Reviewed-by: Frederic Weisbecker Cc: Leo Yan Cc: Todd Kjos Cc: Joel Fernandes Cc: Paven Kondati Signed-off-by: Daniel Lezcano --- include/linux/tick.h | 2 ++ kernel/sched/idle.c | 9 ++++++--- kernel/time/tick-sched.c | 26 ++++++++++++++++++-------- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/include/linux/tick.h b/include/linux/tick.h index 4bf24c860151..9c22d15f4d76 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -115,6 +115,7 @@ enum tick_dep_bits { extern bool tick_nohz_enabled; extern int tick_nohz_tick_stopped(void); extern void tick_nohz_idle_stop_tick(void); +extern void tick_nohz_idle_restart_tick(void); extern void tick_nohz_idle_enter(void); extern void tick_nohz_idle_exit(void); extern void tick_nohz_irq_exit(void); @@ -135,6 +136,7 @@ static inline void tick_nohz_idle_stop_tick_protected(void) #define tick_nohz_enabled (0) static inline int tick_nohz_tick_stopped(void) { return 0; } static inline void tick_nohz_idle_stop_tick(void) { } +static inline void tick_nohz_idle_restart_tick(void) { } static inline void tick_nohz_idle_enter(void) { } static inline void tick_nohz_idle_exit(void) { } diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index 9ce10f647c78..a30e97cc96ee 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -222,13 +222,13 @@ static void do_idle(void) __current_set_polling(); quiet_vmstat(); tick_nohz_idle_enter(); - tick_nohz_idle_stop_tick_protected(); while (!need_resched()) { check_pgt_cache(); rmb(); if (cpu_is_offline(smp_processor_id())) { + tick_nohz_idle_stop_tick_protected(); cpuhp_report_idle_dead(); arch_cpu_idle_dead(); } @@ -242,10 +242,13 @@ static void do_idle(void) * broadcast device expired for us, we don't want to go deep * idle as we know that the IPI is going to arrive right away. */ - if (cpu_idle_force_poll || tick_check_broadcast_expired()) + if (cpu_idle_force_poll || tick_check_broadcast_expired()) { + tick_nohz_idle_restart_tick(); cpu_idle_poll(); - else + } else { + tick_nohz_idle_stop_tick(); cpuidle_idle_call(); + } arch_cpu_idle_exit(); } diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 42df8d6a328f..e072443ad24a 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -1009,12 +1009,10 @@ void tick_nohz_irq_exit(void) { struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); - if (ts->inidle) { + if (ts->inidle) tick_nohz_start_idle(ts); - __tick_nohz_idle_stop_tick(ts); - } else { + else tick_nohz_full_update_tick(ts); - } } /** @@ -1075,6 +1073,20 @@ static void tick_nohz_account_idle_ticks(struct tick_sched *ts) #endif } +static void __tick_nohz_idle_restart_tick(struct tick_sched *ts, ktime_t now) +{ + tick_nohz_restart_sched_tick(ts, now); + tick_nohz_account_idle_ticks(ts); +} + +void tick_nohz_idle_restart_tick(void) +{ + struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); + + if (ts->tick_stopped) + __tick_nohz_idle_restart_tick(ts, ktime_get()); +} + /** * tick_nohz_idle_exit - restart the idle tick from the idle task * @@ -1099,10 +1111,8 @@ void tick_nohz_idle_exit(void) if (ts->idle_active) tick_nohz_stop_idle(ts, now); - if (ts->tick_stopped) { - tick_nohz_restart_sched_tick(ts, now); - tick_nohz_account_idle_ticks(ts); - } + if (ts->tick_stopped) + __tick_nohz_idle_restart_tick(ts, now); local_irq_enable(); } -- GitLab From 27e8616e4282ecdd7614d7d40abc1cbd2e3c4904 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 15 Mar 2018 23:07:41 +0100 Subject: [PATCH 0060/1001] UPSTREAM: sched: idle: Do not stop the tick before cpuidle_idle_call() Make cpuidle_idle_call() decide whether or not to stop the tick. First, the cpuidle_enter_s2idle() path deals with the tick (and with the entire timekeeping for that matter) by itself and it doesn't need the tick to be stopped beforehand. Second, to address the issue with short idle duration predictions by the idle governor after the tick has been stopped, it will be necessary to change the ordering of cpuidle_select() with respect to tick_nohz_idle_stop_tick(). To prepare for that, put a tick_nohz_idle_stop_tick() call in the same branch in which cpuidle_select() is called. Cherry-picked from ed98c34919985a9f87c3edacb9a8d8c283c9e243 Change-Id: Id62c91085ab6640bef9266ac64409e2686279aeb Signed-off-by: Rafael J. Wysocki Reviewed-by: Frederic Weisbecker Acked-by: Peter Zijlstra (Intel) Cc: Leo Yan Cc: Todd Kjos Cc: Joel Fernandes Cc: Paven Kondati Signed-off-by: Daniel Lezcano --- kernel/sched/idle.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index a30e97cc96ee..bfb8aacfcd78 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -147,13 +147,15 @@ static void cpuidle_idle_call(void) } /* - * Tell the RCU framework we are entering an idle section, - * so no more rcu read side critical sections and one more + * The RCU framework needs to be told that we are entering an idle + * section, so no more rcu read side critical sections and one more * step to the grace period */ - rcu_idle_enter(); if (cpuidle_not_available(drv, dev)) { + tick_nohz_idle_stop_tick(); + rcu_idle_enter(); + default_idle_call(); goto exit_idle; } @@ -170,16 +172,26 @@ static void cpuidle_idle_call(void) if (idle_should_enter_s2idle() || dev->use_deepest_state) { if (idle_should_enter_s2idle()) { + rcu_idle_enter(); + entered_state = cpuidle_enter_s2idle(drv, dev); if (entered_state > 0) { local_irq_enable(); goto exit_idle; } + + rcu_idle_exit(); } + tick_nohz_idle_stop_tick(); + rcu_idle_enter(); + next_state = cpuidle_find_deepest_state(drv, dev); call_cpuidle(drv, dev, next_state); } else { + tick_nohz_idle_stop_tick(); + rcu_idle_enter(); + /* * Ask the cpuidle framework to choose a convenient idle state. */ @@ -246,7 +258,6 @@ static void do_idle(void) tick_nohz_idle_restart_tick(); cpu_idle_poll(); } else { - tick_nohz_idle_stop_tick(); cpuidle_idle_call(); } arch_cpu_idle_exit(); -- GitLab From 8b468535dfdc168d13de37a80a1f87f07673671d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 20 Mar 2018 10:11:28 +0100 Subject: [PATCH 0061/1001] UPSTREAM: jiffies: Introduce USER_TICK_USEC and redefine TICK_USEC Since the subsequent changes will need a TICK_USEC definition analogous to TICK_NSEC, rename the existing TICK_USEC as USER_TICK_USEC, update its users and redefine TICK_USEC accordingly. Cherry-picked from efefc97736e6f3261879bc9dddcb161224a455f5 Change-Id: I14c6af0ab80964b1b4ba72ef711946e45dc1f204 Suggested-by: Peter Zijlstra Signed-off-by: Rafael J. Wysocki Acked-by: Peter Zijlstra (Intel) Reviewed-by: Frederic Weisbecker Cc: Leo Yan Cc: Todd Kjos Cc: Joel Fernandes Cc: Paven Kondati Signed-off-by: Daniel Lezcano --- drivers/net/ethernet/sfc/mcdi.c | 2 +- include/linux/jiffies.h | 7 +++++-- kernel/time/ntp.c | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 3df872f56289..37026473cf6d 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -376,7 +376,7 @@ static int efx_mcdi_poll(struct efx_nic *efx) * because generally mcdi responses are fast. After that, back off * and poll once a jiffy (approximately) */ - spins = TICK_USEC; + spins = USER_TICK_USEC; finish = jiffies + MCDI_RPC_TIMEOUT; while (1) { diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index 9385aa57497b..a27cf6652327 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -62,8 +62,11 @@ extern int register_refined_jiffies(long clock_tick_rate); /* TICK_NSEC is the time between ticks in nsec assuming SHIFTED_HZ */ #define TICK_NSEC ((NSEC_PER_SEC+HZ/2)/HZ) -/* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */ -#define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ) +/* TICK_USEC is the time between ticks in usec assuming SHIFTED_HZ */ +#define TICK_USEC ((USEC_PER_SEC + HZ/2) / HZ) + +/* USER_TICK_USEC is the time between ticks in usec assuming fake USER_HZ */ +#define USER_TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ) #ifndef __jiffy_arch_data #define __jiffy_arch_data diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 99e03bec68e4..9de770228cb0 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -31,7 +31,7 @@ /* USER_HZ period (usecs): */ -unsigned long tick_usec = TICK_USEC; +unsigned long tick_usec = USER_TICK_USEC; /* SHIFTED_HZ period (nsecs): */ unsigned long tick_nsec; -- GitLab From 3a25735bd7ecbd0e654730d1e9e955a535413f39 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 22 Mar 2018 17:50:49 +0100 Subject: [PATCH 0062/1001] UPSTREAM: cpuidle: Return nohz hint from cpuidle_select() Add a new pointer argument to cpuidle_select() and to the ->select cpuidle governor callback to allow a boolean value indicating whether or not the tick should be stopped before entering the selected state to be returned from there. Make the ladder governor ignore that pointer (to preserve its current behavior) and make the menu governor return 'false" through it if: (1) the idle exit latency is constrained at 0, or (2) the selected state is a polling one, or (3) the expected idle period duration is within the tick period range. In addition to that, the correction factor computations in the menu governor need to take the possibility that the tick may not be stopped into account to avoid artificially small correction factor values. To that end, add a mechanism to record tick wakeups, as suggested by Peter Zijlstra, and use it to modify the menu_update() behavior when tick wakeup occurs. Namely, if the CPU is woken up by the tick and the return value of tick_nohz_get_sleep_length() is not within the tick boundary, the predicted idle duration is likely too short, so make menu_update() try to compensate for that by updating the governor statistics as though the CPU was idle for a long time. Since the value returned through the new argument pointer of cpuidle_select() is not used by its caller yet, this change by itself is not expected to alter the functionality of the code. Cherry-picked from 45f1ff59e27ca59d33cc1a317e669d90022ccf7d Change-Id: I3737f2fd00e308d0becba33cc3b1db727241e2a4 Signed-off-by: Rafael J. Wysocki Acked-by: Peter Zijlstra (Intel) Cc: Leo Yan Cc: Todd Kjos Cc: Joel Fernandes Cc: Paven Kondati Signed-off-by: Daniel Lezcano --- drivers/cpuidle/cpuidle.c | 10 ++++- drivers/cpuidle/governors/ladder.c | 3 +- drivers/cpuidle/governors/menu.c | 59 ++++++++++++++++++++++++------ include/linux/cpuidle.h | 8 ++-- include/linux/tick.h | 2 + kernel/sched/idle.c | 4 +- kernel/time/tick-sched.c | 20 ++++++++++ 7 files changed, 87 insertions(+), 19 deletions(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index e47e14101768..7c33193216ea 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -263,12 +263,18 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, * * @drv: the cpuidle driver * @dev: the cpuidle device + * @stop_tick: indication on whether or not to stop the tick * * Returns the index of the idle state. The return value must not be negative. + * + * The memory location pointed to by @stop_tick is expected to be written the + * 'false' boolean value if the scheduler tick should not be stopped before + * entering the returned state. */ -int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) +int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + bool *stop_tick) { - return cpuidle_curr_governor->select(drv, dev); + return cpuidle_curr_governor->select(drv, dev, stop_tick); } /** diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index ce1a2ffffb2a..0213e07abe9c 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c @@ -62,9 +62,10 @@ static inline void ladder_do_selection(struct ladder_device *ldev, * ladder_select_state - selects the next state to enter * @drv: cpuidle driver * @dev: the CPU + * @dummy: not used */ static int ladder_select_state(struct cpuidle_driver *drv, - struct cpuidle_device *dev) + struct cpuidle_device *dev, bool *dummy) { struct ladder_device *ldev = this_cpu_ptr(&ladder_devices); struct ladder_device_state *last_state; diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index a99d5620056d..48cbab53ba4e 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -123,6 +123,7 @@ struct menu_device { int last_state_idx; int needs_update; + int tick_wakeup; unsigned int next_timer_us; unsigned int predicted_us; @@ -284,8 +285,10 @@ static unsigned int get_typical_interval(struct menu_device *data) * menu_select - selects the next idle state to enter * @drv: cpuidle driver containing state data * @dev: the CPU + * @stop_tick: indication on whether or not to stop the tick */ -static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) +static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, + bool *stop_tick) { struct menu_device *data = this_cpu_ptr(&menu_devices); struct device *device = get_cpu_device(dev->cpu); @@ -308,8 +311,10 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) latency_req = resume_latency; /* Special case when user has set very strict latency requirement */ - if (unlikely(latency_req == 0)) + if (unlikely(latency_req == 0)) { + *stop_tick = false; return 0; + } /* determine the expected residency time, round up */ data->next_timer_us = ktime_to_us(tick_nohz_get_sleep_length()); @@ -359,6 +364,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) if (latency_req > interactivity_req) latency_req = interactivity_req; + expected_interval = data->predicted_us; /* * Find the idle state with the lowest power while satisfying * our constraints. @@ -374,15 +380,30 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) idx = i; /* first enabled state */ if (s->target_residency > data->predicted_us) break; - if (s->exit_latency > latency_req) + if (s->exit_latency > latency_req) { + /* + * If we break out of the loop for latency reasons, use + * the target residency of the selected state as the + * expected idle duration so that the tick is retained + * as long as that target residency is low enough. + */ + expected_interval = drv->states[idx].target_residency; break; - + } idx = i; } if (idx == -1) idx = 0; /* No states enabled. Must use 0. */ + /* + * Don't stop the tick if the selected state is a polling one or if the + * expected idle duration is shorter than the tick period length. + */ + if ((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) || + expected_interval < TICK_USEC) + *stop_tick = false; + data->last_state_idx = idx; return data->last_state_idx; @@ -402,6 +423,7 @@ static void menu_reflect(struct cpuidle_device *dev, int index) data->last_state_idx = index; data->needs_update = 1; + data->tick_wakeup = tick_nohz_idle_got_tick(); } /** @@ -432,14 +454,27 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) * assume the state was never reached and the exit latency is 0. */ - /* measured value */ - measured_us = cpuidle_get_last_residency(dev); - - /* Deduct exit latency */ - if (measured_us > 2 * target->exit_latency) - measured_us -= target->exit_latency; - else - measured_us /= 2; + if (data->tick_wakeup && data->next_timer_us > TICK_USEC) { + /* + * The nohz code said that there wouldn't be any events within + * the tick boundary (if the tick was stopped), but the idle + * duration predictor had a differing opinion. Since the CPU + * was woken up by a tick (that wasn't stopped after all), the + * predictor was not quite right, so assume that the CPU could + * have been idle long (but not forever) to help the idle + * duration predictor do a better job next time. + */ + measured_us = 9 * MAX_INTERESTING / 10; + } else { + /* measured value */ + measured_us = cpuidle_get_last_residency(dev); + + /* Deduct exit latency */ + if (measured_us > 2 * target->exit_latency) + measured_us -= target->exit_latency; + else + measured_us /= 2; + } /* Make sure our coefficients do not exceed unity */ if (measured_us > data->next_timer_us) diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index ad33507b34be..113a14833ad3 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -131,7 +131,8 @@ extern bool cpuidle_not_available(struct cpuidle_driver *drv, struct cpuidle_device *dev); extern int cpuidle_select(struct cpuidle_driver *drv, - struct cpuidle_device *dev); + struct cpuidle_device *dev, + bool *stop_tick); extern int cpuidle_enter(struct cpuidle_driver *drv, struct cpuidle_device *dev, int index); extern void cpuidle_reflect(struct cpuidle_device *dev, int index); @@ -163,7 +164,7 @@ static inline bool cpuidle_not_available(struct cpuidle_driver *drv, struct cpuidle_device *dev) {return true; } static inline int cpuidle_select(struct cpuidle_driver *drv, - struct cpuidle_device *dev) + struct cpuidle_device *dev, bool *stop_tick) {return -ENODEV; } static inline int cpuidle_enter(struct cpuidle_driver *drv, struct cpuidle_device *dev, int index) @@ -246,7 +247,8 @@ struct cpuidle_governor { struct cpuidle_device *dev); int (*select) (struct cpuidle_driver *drv, - struct cpuidle_device *dev); + struct cpuidle_device *dev, + bool *stop_tick); void (*reflect) (struct cpuidle_device *dev, int index); }; diff --git a/include/linux/tick.h b/include/linux/tick.h index 9c22d15f4d76..d853119f7639 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -119,6 +119,7 @@ extern void tick_nohz_idle_restart_tick(void); extern void tick_nohz_idle_enter(void); extern void tick_nohz_idle_exit(void); extern void tick_nohz_irq_exit(void); +extern bool tick_nohz_idle_got_tick(void); extern ktime_t tick_nohz_get_sleep_length(void); extern unsigned long tick_nohz_get_idle_calls(void); extern unsigned long tick_nohz_get_idle_calls_cpu(int cpu); @@ -139,6 +140,7 @@ static inline void tick_nohz_idle_stop_tick(void) { } static inline void tick_nohz_idle_restart_tick(void) { } static inline void tick_nohz_idle_enter(void) { } static inline void tick_nohz_idle_exit(void) { } +static inline bool tick_nohz_idle_got_tick(void) { return false; } static inline ktime_t tick_nohz_get_sleep_length(void) { diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index bfb8aacfcd78..35e3ab39be76 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -189,13 +189,15 @@ static void cpuidle_idle_call(void) next_state = cpuidle_find_deepest_state(drv, dev); call_cpuidle(drv, dev, next_state); } else { + bool stop_tick = true; + tick_nohz_idle_stop_tick(); rcu_idle_enter(); /* * Ask the cpuidle framework to choose a convenient idle state. */ - next_state = cpuidle_select(drv, dev); + next_state = cpuidle_select(drv, dev, &stop_tick); entered_state = call_cpuidle(drv, dev, next_state); /* * Give the governor an opportunity to reflect on the outcome diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index e072443ad24a..61283bcfdecb 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -1015,6 +1015,20 @@ void tick_nohz_irq_exit(void) tick_nohz_full_update_tick(ts); } +/** + * tick_nohz_idle_got_tick - Check whether or not the tick handler has run + */ +bool tick_nohz_idle_got_tick(void) +{ + struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); + + if (ts->inidle > 1) { + ts->inidle = 1; + return true; + } + return false; +} + /** * tick_nohz_get_sleep_length - return the length of the current sleep * @@ -1126,6 +1140,9 @@ static void tick_nohz_handler(struct clock_event_device *dev) struct pt_regs *regs = get_irq_regs(); ktime_t now = ktime_get(); + if (ts->inidle) + ts->inidle = 2; + dev->next_event = KTIME_MAX; tick_sched_do_timer(now); @@ -1223,6 +1240,9 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) struct pt_regs *regs = get_irq_regs(); ktime_t now = ktime_get(); + if (ts->inidle) + ts->inidle = 2; + tick_sched_do_timer(now); /* -- GitLab From f69cfc8ef98a58c66ecdd2c684d9ae5b1d6a9f1e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 29 Mar 2018 11:31:43 +0200 Subject: [PATCH 0063/1001] BACKPORT: time: tick-sched: Split tick_nohz_stop_sched_tick() In order to address the issue with short idle duration predictions by the idle governor after the scheduler tick has been stopped, split tick_nohz_stop_sched_tick() into two separate routines, one computing the time to the next timer event and the other simply stopping the tick when the time to the next timer event is known. Prepare these two routines to be called separately, as one of them will be called by the idle governor in the cpuidle_select() code path after subsequent changes. Update the former callers of tick_nohz_stop_sched_tick() to use the new routines, tick_nohz_next_event() and tick_nohz_stop_tick(), instead of it and move the updates of the sleep_length field in struct tick_sched into __tick_nohz_idle_stop_tick() as it doesn't need to be updated anywhere else. There should be no intentional visible changes in functionality resulting from this change. Cherry-picked from 23a8d888107ce4ce444eab2dcebf4cfb3578770b - Fixed conflict with tick_nohz_stopped_cpu not appearing in the chunk context. Trivial fix. Change-Id: I43eb34c4799b4b9f18842e047c3d016394c22743 Signed-off-by: Rafael J. Wysocki Acked-by: Peter Zijlstra (Intel) Cc: Leo Yan Cc: Todd Kjos Cc: Joel Fernandes Cc: Paven Kondati Signed-off-by: Daniel Lezcano --- kernel/time/tick-sched.c | 127 ++++++++++++++++++++++++--------------- kernel/time/tick-sched.h | 4 ++ 2 files changed, 83 insertions(+), 48 deletions(-) diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 61283bcfdecb..2297f9bbf0dc 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -676,13 +676,10 @@ static inline bool local_timer_softirq_pending(void) return local_softirq_pending() & TIMER_SOFTIRQ; } -static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, - ktime_t now, int cpu) +static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu) { - struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); u64 basemono, next_tick, next_tmr, next_rcu, delta, expires; unsigned long seq, basejiff; - ktime_t tick; /* Read jiffies and the time when jiffies were updated last */ do { @@ -691,6 +688,7 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, basejiff = jiffies; } while (read_seqretry(&jiffies_lock, seq)); ts->last_jiffies = basejiff; + ts->timer_expires_base = basemono; /* * Keep the periodic tick, when RCU, architecture or irq_work @@ -735,32 +733,20 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, * next period, so no point in stopping it either, bail. */ if (!ts->tick_stopped) { - tick = 0; + ts->timer_expires = 0; goto out; } } /* - * If this CPU is the one which updates jiffies, then give up - * the assignment and let it be taken by the CPU which runs - * the tick timer next, which might be this CPU as well. If we - * don't drop this here the jiffies might be stale and - * do_timer() never invoked. Keep track of the fact that it - * was the one which had the do_timer() duty last. If this CPU - * is the one which had the do_timer() duty last, we limit the - * sleep time to the timekeeping max_deferment value. + * If this CPU is the one which had the do_timer() duty last, we limit + * the sleep time to the timekeeping max_deferment value. * Otherwise we can sleep as long as we want. */ delta = timekeeping_max_deferment(); - if (cpu == tick_do_timer_cpu) { - tick_do_timer_cpu = TICK_DO_TIMER_NONE; - ts->do_timer_last = 1; - } else if (tick_do_timer_cpu != TICK_DO_TIMER_NONE) { - delta = KTIME_MAX; - ts->do_timer_last = 0; - } else if (!ts->do_timer_last) { + if (cpu != tick_do_timer_cpu && + (tick_do_timer_cpu != TICK_DO_TIMER_NONE || !ts->do_timer_last)) delta = KTIME_MAX; - } #ifdef CONFIG_NO_HZ_FULL /* Limit the tick delta to the maximum scheduler deferment */ @@ -774,14 +760,42 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, else expires = KTIME_MAX; - expires = min_t(u64, expires, next_tick); - tick = expires; + ts->timer_expires = min_t(u64, expires, next_tick); + +out: + return ts->timer_expires; +} + +static void tick_nohz_stop_tick(struct tick_sched *ts, int cpu) +{ + struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); + u64 basemono = ts->timer_expires_base; + u64 expires = ts->timer_expires; + ktime_t tick = expires; + + /* Make sure we won't be trying to stop it twice in a row. */ + ts->timer_expires_base = 0; + + /* + * If this CPU is the one which updates jiffies, then give up + * the assignment and let it be taken by the CPU which runs + * the tick timer next, which might be this CPU as well. If we + * don't drop this here the jiffies might be stale and + * do_timer() never invoked. Keep track of the fact that it + * was the one which had the do_timer() duty last. + */ + if (cpu == tick_do_timer_cpu) { + tick_do_timer_cpu = TICK_DO_TIMER_NONE; + ts->do_timer_last = 1; + } else if (tick_do_timer_cpu != TICK_DO_TIMER_NONE) { + ts->do_timer_last = 0; + } /* Skip reprogram of event if its not changed */ if (ts->tick_stopped && (expires == ts->next_tick)) { /* Sanity check: make sure clockevent is actually programmed */ if (tick == KTIME_MAX || ts->next_tick == hrtimer_get_expires(&ts->sched_timer)) - goto out; + return; WARN_ON_ONCE(1); printk_once("basemono: %llu ts->next_tick: %llu dev->next_event: %llu timer->active: %d timer->expires: %llu\n", @@ -814,7 +828,7 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, if (unlikely(expires == KTIME_MAX)) { if (ts->nohz_mode == NOHZ_MODE_HIGHRES) hrtimer_cancel(&ts->sched_timer); - goto out; + return; } if (ts->nohz_mode == NOHZ_MODE_HIGHRES) { @@ -823,15 +837,22 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, hrtimer_set_expires(&ts->sched_timer, tick); tick_program_event(tick, 1); } +} -out: - /* - * Update the estimated sleep length until the next timer - * (not only the tick). - */ - ts->sleep_length = ktime_sub(dev->next_event, now); - return tick; +static void tick_nohz_retain_tick(struct tick_sched *ts) +{ + ts->timer_expires_base = 0; +} + +#ifdef CONFIG_NO_HZ_FULL +static void tick_nohz_stop_sched_tick(struct tick_sched *ts, int cpu) +{ + if (tick_nohz_next_event(ts, cpu)) + tick_nohz_stop_tick(ts, cpu); + else + tick_nohz_retain_tick(ts); } +#endif /* CONFIG_NO_HZ_FULL */ static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now) { @@ -868,7 +889,7 @@ static void tick_nohz_full_update_tick(struct tick_sched *ts) return; if (can_stop_full_tick(cpu, ts)) - tick_nohz_stop_sched_tick(ts, ktime_get(), cpu); + tick_nohz_stop_sched_tick(ts, cpu); else if (ts->tick_stopped) tick_nohz_restart_sched_tick(ts, ktime_get()); #endif @@ -894,10 +915,8 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts) return false; } - if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE)) { - ts->sleep_length = NSEC_PER_SEC / HZ; + if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE)) return false; - } if (need_resched()) return false; @@ -934,29 +953,37 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts) static void __tick_nohz_idle_stop_tick(struct tick_sched *ts) { + struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); ktime_t expires; int cpu = smp_processor_id(); - if (can_stop_idle_tick(cpu, ts)) { + WARN_ON_ONCE(ts->timer_expires_base); + + if (!can_stop_idle_tick(cpu, ts)) + goto out; + + expires = tick_nohz_next_event(ts, cpu); + + ts->idle_calls++; + + if (expires > 0LL) { int was_stopped = ts->tick_stopped; - ts->idle_calls++; + tick_nohz_stop_tick(ts, cpu); - /* - * The idle entry time should be a sufficient approximation of - * the current time at this point. - */ - expires = tick_nohz_stop_sched_tick(ts, ts->idle_entrytime, cpu); - if (expires > 0LL) { - ts->idle_sleeps++; - ts->idle_expires = expires; - } + ts->idle_sleeps++; + ts->idle_expires = expires; if (!was_stopped && ts->tick_stopped) { ts->idle_jiffies = ts->last_jiffies; nohz_balance_enter_idle(cpu); } + } else { + tick_nohz_retain_tick(ts); } + +out: + ts->sleep_length = ktime_sub(dev->next_event, ts->idle_entrytime); } /** @@ -982,7 +1009,7 @@ void tick_nohz_idle_enter(void) /* * Update the idle state in the scheduler domain hierarchy - * when tick_nohz_stop_sched_tick() is called from the idle loop. + * when tick_nohz_stop_tick() is called from the idle loop. * State will be updated to busy during the first busy tick after * exiting idle. */ @@ -991,6 +1018,9 @@ void tick_nohz_idle_enter(void) local_irq_disable(); ts = this_cpu_ptr(&tick_cpu_sched); + + WARN_ON_ONCE(ts->timer_expires_base); + ts->inidle = 1; tick_nohz_start_idle(ts); @@ -1116,6 +1146,7 @@ void tick_nohz_idle_exit(void) local_irq_disable(); WARN_ON_ONCE(!ts->inidle); + WARN_ON_ONCE(ts->timer_expires_base); ts->inidle = 0; diff --git a/kernel/time/tick-sched.h b/kernel/time/tick-sched.h index 954b43dbf21c..53e45a39bdbc 100644 --- a/kernel/time/tick-sched.h +++ b/kernel/time/tick-sched.h @@ -39,6 +39,8 @@ enum tick_nohz_mode { * @idle_sleeptime: Sum of the time slept in idle with sched tick stopped * @iowait_sleeptime: Sum of the time slept in idle with sched tick stopped, with IO outstanding * @sleep_length: Duration of the current idle sleep + * @timer_expires: Anticipated timer expiration time (in case sched tick is stopped) + * @timer_expires_base: Base time clock monotonic for @timer_expires * @do_timer_lst: CPU was the last one doing do_timer before going idle */ struct tick_sched { @@ -60,6 +62,8 @@ struct tick_sched { ktime_t iowait_sleeptime; ktime_t sleep_length; unsigned long last_jiffies; + u64 timer_expires; + u64 timer_expires_base; u64 next_timer; ktime_t idle_expires; int do_timer_last; -- GitLab From 6277dd586f11f0cd48e5053dfa696699cca785a6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 3 Apr 2018 23:17:00 +0200 Subject: [PATCH 0064/1001] BACKPORT: time: hrtimer: Introduce hrtimer_next_event_without() The next set of changes will need to compute the time to the next hrtimer event over all hrtimers except for the scheduler tick one. To that end introduce a new helper function, hrtimer_next_event_without(), for computing the time until the next hrtimer event over all timers except for one and modify the underlying code in __hrtimer_next_event_base() to prepare it for being called by that new function. No intentional code behavior changes. Cherry-picked from a59855cd8c613ba4bb95147f6176360d95f75e60 - Fixed conflict with tick_nohz_stopped_cpu not appearing in the chunk context. Trivial fix. Change-Id: I0dae9e08e19559efae9697800738c5522ab5933f Signed-off-by: Rafael J. Wysocki Acked-by: Peter Zijlstra (Intel) Reviewed-by: Frederic Weisbecker Cc: Leo Yan Cc: Todd Kjos Cc: Joel Fernandes Cc: Paven Kondati Signed-off-by: Daniel Lezcano --- include/linux/hrtimer.h | 1 + kernel/time/hrtimer.c | 47 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 012c37fdb688..27f14f2cc773 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -405,6 +405,7 @@ static inline ktime_t hrtimer_get_remaining(const struct hrtimer *timer) } extern u64 hrtimer_get_next_event(void); +extern u64 hrtimer_next_event_without(const struct hrtimer *exclude); extern bool hrtimer_active(const struct hrtimer *timer); diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index d00e85ac10d6..12a01cb6d25c 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -463,7 +463,8 @@ static inline void hrtimer_update_next_timer(struct hrtimer_cpu_base *cpu_base, #endif } -static ktime_t __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base) +static ktime_t __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base, + const struct hrtimer *exclude) { struct hrtimer_clock_base *base = cpu_base->clock_base; unsigned int active = cpu_base->active_bases; @@ -479,9 +480,24 @@ static ktime_t __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base) next = timerqueue_getnext(&base->active); timer = container_of(next, struct hrtimer, node); + if (timer == exclude) { + /* Get to the next timer in the queue. */ + struct rb_node *rbn = rb_next(&next->node); + + next = rb_entry_safe(rbn, struct timerqueue_node, node); + if (!next) + continue; + + timer = container_of(next, struct hrtimer, node); + } expires = ktime_sub(hrtimer_get_expires(timer), base->offset); if (expires < expires_next) { expires_next = expires; + + /* Skip cpu_base update if a timer is being excluded. */ + if (exclude) + continue; + hrtimer_update_next_timer(cpu_base, timer); } } @@ -560,7 +576,7 @@ hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal) if (!cpu_base->hres_active) return; - expires_next = __hrtimer_get_next_event(cpu_base); + expires_next = __hrtimer_get_next_event(cpu_base, NULL); if (skip_equal && expires_next == cpu_base->expires_next) return; @@ -1076,7 +1092,30 @@ u64 hrtimer_get_next_event(void) raw_spin_lock_irqsave(&cpu_base->lock, flags); if (!__hrtimer_hres_active(cpu_base)) - expires = __hrtimer_get_next_event(cpu_base); + expires = __hrtimer_get_next_event(cpu_base, NULL); + + raw_spin_unlock_irqrestore(&cpu_base->lock, flags); + + return expires; +} + +/** + * hrtimer_next_event_without - time until next expiry event w/o one timer + * @exclude: timer to exclude + * + * Returns the next expiry time over all timers except for the @exclude one or + * KTIME_MAX if none of them is pending. + */ +u64 hrtimer_next_event_without(const struct hrtimer *exclude) +{ + struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); + u64 expires = KTIME_MAX; + unsigned long flags; + + raw_spin_lock_irqsave(&cpu_base->lock, flags); + + if (__hrtimer_hres_active(cpu_base)) + expires = __hrtimer_get_next_event(cpu_base, exclude); raw_spin_unlock_irqrestore(&cpu_base->lock, flags); @@ -1318,7 +1357,7 @@ void hrtimer_interrupt(struct clock_event_device *dev) __hrtimer_run_queues(cpu_base, now); /* Reevaluate the clock bases for the next expiry */ - expires_next = __hrtimer_get_next_event(cpu_base); + expires_next = __hrtimer_get_next_event(cpu_base, NULL); /* * Store the new expiry value so the migration code can verify * against it. -- GitLab From 8c71f69fb44078dc414bf88ea9aa5a1de9422be3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 3 Apr 2018 23:17:11 +0200 Subject: [PATCH 0065/1001] UPSTREAM: sched: idle: Select idle state before stopping the tick In order to address the issue with short idle duration predictions by the idle governor after the scheduler tick has been stopped, reorder the code in cpuidle_idle_call() so that the governor idle state selection runs before tick_nohz_idle_go_idle() and use the "nohz" hint returned by cpuidle_select() to decide whether or not to stop the tick. This isn't straightforward, because menu_select() invokes tick_nohz_get_sleep_length() to get the time to the next timer event and the number returned by the latter comes from __tick_nohz_idle_stop_tick(). Fortunately, however, it is possible to compute that number without actually stopping the tick and with the help of the existing code. Namely, tick_nohz_get_sleep_length() can be made call tick_nohz_next_event(), introduced earlier, to get the time to the next non-highres timer event. If that happens, tick_nohz_next_event() need not be called by __tick_nohz_idle_stop_tick() again. If it turns out that the scheduler tick cannot be stopped going forward or the next timer event is too close for the tick to be stopped, tick_nohz_get_sleep_length() can simply return the time to the next event currently programmed into the corresponding clock event device. In addition to knowing the return value of tick_nohz_next_event(), however, tick_nohz_get_sleep_length() needs to know the time to the next highres timer event, but with the scheduler tick timer excluded, which can be computed with the help of hrtimer_get_next_event(). That minimum of that number and the tick_nohz_next_event() return value is the total time to the next timer event with the assumption that the tick will be stopped. It can be returned to the idle governor which can use it for predicting idle duration (under the assumption that the tick will be stopped) and deciding whether or not it makes sense to stop the tick before putting the CPU into the selected idle state. With the above, the sleep_length field in struct tick_sched is not necessary any more, so drop it. Cherry-picked from 554c8aa8ecade210d58a252173bb8f2106552a44 Change-Id: I11bbd473ccb00cf89105f97a3861d56459cc8377 Link: https://bugzilla.kernel.org/show_bug.cgi?id=199227 Reported-by: Doug Smythies Reported-by: Thomas Ilsche Signed-off-by: Rafael J. Wysocki Acked-by: Peter Zijlstra (Intel) Reviewed-by: Frederic Weisbecker Cc: Leo Yan Cc: Todd Kjos Cc: Joel Fernandes Cc: Paven Kondati Signed-off-by: Daniel Lezcano --- include/linux/tick.h | 2 ++ kernel/sched/idle.c | 11 ++++++-- kernel/time/tick-sched.c | 61 ++++++++++++++++++++++++++++++++-------- kernel/time/tick-sched.h | 2 -- 4 files changed, 59 insertions(+), 17 deletions(-) diff --git a/include/linux/tick.h b/include/linux/tick.h index d853119f7639..c773ebe81be6 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -115,6 +115,7 @@ enum tick_dep_bits { extern bool tick_nohz_enabled; extern int tick_nohz_tick_stopped(void); extern void tick_nohz_idle_stop_tick(void); +extern void tick_nohz_idle_retain_tick(void); extern void tick_nohz_idle_restart_tick(void); extern void tick_nohz_idle_enter(void); extern void tick_nohz_idle_exit(void); @@ -137,6 +138,7 @@ static inline void tick_nohz_idle_stop_tick_protected(void) #define tick_nohz_enabled (0) static inline int tick_nohz_tick_stopped(void) { return 0; } static inline void tick_nohz_idle_stop_tick(void) { } +static inline void tick_nohz_idle_retain_tick(void) { } static inline void tick_nohz_idle_restart_tick(void) { } static inline void tick_nohz_idle_enter(void) { } static inline void tick_nohz_idle_exit(void) { } diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index 35e3ab39be76..2e973e667b0d 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -191,13 +191,18 @@ static void cpuidle_idle_call(void) } else { bool stop_tick = true; - tick_nohz_idle_stop_tick(); - rcu_idle_enter(); - /* * Ask the cpuidle framework to choose a convenient idle state. */ next_state = cpuidle_select(drv, dev, &stop_tick); + + if (stop_tick) + tick_nohz_idle_stop_tick(); + else + tick_nohz_idle_retain_tick(); + + rcu_idle_enter(); + entered_state = call_cpuidle(drv, dev, next_state); /* * Give the governor an opportunity to reflect on the outcome diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 2297f9bbf0dc..6013e89ea18a 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -953,16 +953,19 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts) static void __tick_nohz_idle_stop_tick(struct tick_sched *ts) { - struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); ktime_t expires; int cpu = smp_processor_id(); - WARN_ON_ONCE(ts->timer_expires_base); - - if (!can_stop_idle_tick(cpu, ts)) - goto out; - - expires = tick_nohz_next_event(ts, cpu); + /* + * If tick_nohz_get_sleep_length() ran tick_nohz_next_event(), the + * tick timer expiration time is known already. + */ + if (ts->timer_expires_base) + expires = ts->timer_expires; + else if (can_stop_idle_tick(cpu, ts)) + expires = tick_nohz_next_event(ts, cpu); + else + return; ts->idle_calls++; @@ -981,9 +984,6 @@ static void __tick_nohz_idle_stop_tick(struct tick_sched *ts) } else { tick_nohz_retain_tick(ts); } - -out: - ts->sleep_length = ktime_sub(dev->next_event, ts->idle_entrytime); } /** @@ -996,6 +996,16 @@ void tick_nohz_idle_stop_tick(void) __tick_nohz_idle_stop_tick(this_cpu_ptr(&tick_cpu_sched)); } +void tick_nohz_idle_retain_tick(void) +{ + tick_nohz_retain_tick(this_cpu_ptr(&tick_cpu_sched)); + /* + * Undo the effect of get_next_timer_interrupt() called from + * tick_nohz_next_event(). + */ + timer_clear_idle(); +} + /** * tick_nohz_idle_enter - prepare for entering idle on the current CPU * @@ -1060,15 +1070,42 @@ bool tick_nohz_idle_got_tick(void) } /** - * tick_nohz_get_sleep_length - return the length of the current sleep + * tick_nohz_get_sleep_length - return the expected length of the current sleep * * Called from power state control code with interrupts disabled */ ktime_t tick_nohz_get_sleep_length(void) { + struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); + int cpu = smp_processor_id(); + /* + * The idle entry time is expected to be a sufficient approximation of + * the current time at this point. + */ + ktime_t now = ts->idle_entrytime; + ktime_t next_event; + + WARN_ON_ONCE(!ts->inidle); + + if (!can_stop_idle_tick(cpu, ts)) + goto out_dev; + + next_event = tick_nohz_next_event(ts, cpu); + if (!next_event) + goto out_dev; + + /* + * If the next highres timer to expire is earlier than next_event, the + * idle governor needs to know that. + */ + next_event = min_t(u64, next_event, + hrtimer_next_event_without(&ts->sched_timer)); + + return ktime_sub(next_event, now); - return ts->sleep_length; +out_dev: + return ktime_sub(dev->next_event, now); } /** diff --git a/kernel/time/tick-sched.h b/kernel/time/tick-sched.h index 53e45a39bdbc..2b845f2c44b1 100644 --- a/kernel/time/tick-sched.h +++ b/kernel/time/tick-sched.h @@ -38,7 +38,6 @@ enum tick_nohz_mode { * @idle_exittime: Time when the idle state was left * @idle_sleeptime: Sum of the time slept in idle with sched tick stopped * @iowait_sleeptime: Sum of the time slept in idle with sched tick stopped, with IO outstanding - * @sleep_length: Duration of the current idle sleep * @timer_expires: Anticipated timer expiration time (in case sched tick is stopped) * @timer_expires_base: Base time clock monotonic for @timer_expires * @do_timer_lst: CPU was the last one doing do_timer before going idle @@ -60,7 +59,6 @@ struct tick_sched { ktime_t idle_exittime; ktime_t idle_sleeptime; ktime_t iowait_sleeptime; - ktime_t sleep_length; unsigned long last_jiffies; u64 timer_expires; u64 timer_expires_base; -- GitLab From 30693a4f09099792f6d149355ffe1b0facf6c4ce Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 5 Apr 2018 19:12:34 +0200 Subject: [PATCH 0066/1001] UPSTREAM: cpuidle: menu: Refine idle state selection for running tick If the tick isn't stopped, the target residency of the state selected by the menu governor may be greater than the actual time to the next tick and that means lost energy. To avoid that, make tick_nohz_get_sleep_length() return the current time to the next event (before stopping the tick) in addition to the estimated one via an extra pointer argument and make menu_select() use that value to refine the state selection when necessary. Cherry-picked from 296bb1e51a4838a6488ec5ce676607093482ecbc Change-Id: I6c3b4227817231f437da0879d1ca401522ef3a70 Signed-off-by: Rafael J. Wysocki Acked-by: Peter Zijlstra (Intel) Cc: Leo Yan Cc: Todd Kjos Cc: Joel Fernandes Cc: Paven Kondati Signed-off-by: Daniel Lezcano --- drivers/cpuidle/governors/menu.c | 27 +++++++++++++++++++++++++-- include/linux/tick.h | 7 ++++--- kernel/time/tick-sched.c | 12 ++++++------ 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 48cbab53ba4e..c3034a46d11a 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -300,6 +300,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, unsigned int expected_interval; unsigned long nr_iowaiters, cpu_load; int resume_latency = dev_pm_qos_raw_read_value(device); + ktime_t delta_next; if (data->needs_update) { menu_update(drv, dev); @@ -317,7 +318,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, } /* determine the expected residency time, round up */ - data->next_timer_us = ktime_to_us(tick_nohz_get_sleep_length()); + data->next_timer_us = ktime_to_us(tick_nohz_get_sleep_length(&delta_next)); get_iowait_load(&nr_iowaiters, &cpu_load); data->bucket = which_bucket(data->next_timer_us, nr_iowaiters); @@ -401,9 +402,31 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, * expected idle duration is shorter than the tick period length. */ if ((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) || - expected_interval < TICK_USEC) + expected_interval < TICK_USEC) { + unsigned int delta_next_us = ktime_to_us(delta_next); + *stop_tick = false; + if (!tick_nohz_tick_stopped() && idx > 0 && + drv->states[idx].target_residency > delta_next_us) { + /* + * The tick is not going to be stopped and the target + * residency of the state to be returned is not within + * the time until the next timer event including the + * tick, so try to correct that. + */ + for (i = idx - 1; i >= 0; i--) { + if (drv->states[i].disabled || + dev->states_usage[i].disable) + continue; + + idx = i; + if (drv->states[i].target_residency <= delta_next_us) + break; + } + } + } + data->last_state_idx = idx; return data->last_state_idx; diff --git a/include/linux/tick.h b/include/linux/tick.h index c773ebe81be6..bd8219943a91 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -121,7 +121,7 @@ extern void tick_nohz_idle_enter(void); extern void tick_nohz_idle_exit(void); extern void tick_nohz_irq_exit(void); extern bool tick_nohz_idle_got_tick(void); -extern ktime_t tick_nohz_get_sleep_length(void); +extern ktime_t tick_nohz_get_sleep_length(ktime_t *delta_next); extern unsigned long tick_nohz_get_idle_calls(void); extern unsigned long tick_nohz_get_idle_calls_cpu(int cpu); extern u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time); @@ -144,9 +144,10 @@ static inline void tick_nohz_idle_enter(void) { } static inline void tick_nohz_idle_exit(void) { } static inline bool tick_nohz_idle_got_tick(void) { return false; } -static inline ktime_t tick_nohz_get_sleep_length(void) +static inline ktime_t tick_nohz_get_sleep_length(ktime_t *delta_next) { - return NSEC_PER_SEC / HZ; + *delta_next = TICK_NSEC; + return *delta_next; } static inline u64 get_cpu_idle_time_us(int cpu, u64 *unused) { return -1; } static inline u64 get_cpu_iowait_time_us(int cpu, u64 *unused) { return -1; } diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 6013e89ea18a..3ee1b3aa7158 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -1071,10 +1071,11 @@ bool tick_nohz_idle_got_tick(void) /** * tick_nohz_get_sleep_length - return the expected length of the current sleep + * @delta_next: duration until the next event if the tick cannot be stopped * * Called from power state control code with interrupts disabled */ -ktime_t tick_nohz_get_sleep_length(void) +ktime_t tick_nohz_get_sleep_length(ktime_t *delta_next) { struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); @@ -1088,12 +1089,14 @@ ktime_t tick_nohz_get_sleep_length(void) WARN_ON_ONCE(!ts->inidle); + *delta_next = ktime_sub(dev->next_event, now); + if (!can_stop_idle_tick(cpu, ts)) - goto out_dev; + return *delta_next; next_event = tick_nohz_next_event(ts, cpu); if (!next_event) - goto out_dev; + return *delta_next; /* * If the next highres timer to expire is earlier than next_event, the @@ -1103,9 +1106,6 @@ ktime_t tick_nohz_get_sleep_length(void) hrtimer_next_event_without(&ts->sched_timer)); return ktime_sub(next_event, now); - -out_dev: - return ktime_sub(dev->next_event, now); } /** -- GitLab From e32966ced86f33cdf795a0be789859981ecb679f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 5 Apr 2018 19:12:43 +0200 Subject: [PATCH 0067/1001] UPSTREAM: cpuidle: menu: Avoid selecting shallow states with stopped tick If the scheduler tick has been stopped already and the governor selects a shallow idle state, the CPU can spend a long time in that state if the selection is based on an inaccurate prediction of idle time. That effect turns out to be relevant, so it needs to be mitigated. To that end, modify the menu governor to discard the result of the idle time prediction if the tick is stopped and the predicted idle time is less than the tick period length, unless the tick timer is going to expire soon. Cherry-picked from 87c9fe6ee495f78f36d39cb37f6a714444a093ee Change-Id: I7f45e76140c7c429049a23ac5d7cf4728ba70542 Signed-off-by: Rafael J. Wysocki Acked-by: Peter Zijlstra (Intel) Cc: Leo Yan Cc: Todd Kjos Cc: Joel Fernandes Cc: Paven Kondati Signed-off-by: Daniel Lezcano --- drivers/cpuidle/governors/menu.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index c3034a46d11a..58c103b5892b 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -357,13 +357,28 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, */ data->predicted_us = min(data->predicted_us, expected_interval); - /* - * Use the performance multiplier and the user-configurable - * latency_req to determine the maximum exit latency. - */ - interactivity_req = data->predicted_us / performance_multiplier(nr_iowaiters, cpu_load); - if (latency_req > interactivity_req) - latency_req = interactivity_req; + if (tick_nohz_tick_stopped()) { + /* + * If the tick is already stopped, the cost of possible short + * idle duration misprediction is much higher, because the CPU + * may be stuck in a shallow idle state for a long time as a + * result of it. In that case say we might mispredict and try + * to force the CPU into a state for which we would have stopped + * the tick, unless a timer is going to expire really soon + * anyway. + */ + if (data->predicted_us < TICK_USEC) + data->predicted_us = min_t(unsigned int, TICK_USEC, + ktime_to_us(delta_next)); + } else { + /* + * Use the performance multiplier and the user-configurable + * latency_req to determine the maximum exit latency. + */ + interactivity_req = data->predicted_us / performance_multiplier(nr_iowaiters, cpu_load); + if (latency_req > interactivity_req) + latency_req = interactivity_req; + } expected_interval = data->predicted_us; /* -- GitLab From 0514073f04ac7140b438f9e88491e94f3c74c5f7 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Tue, 26 Jun 2018 11:14:35 +0530 Subject: [PATCH 0068/1001] sched: walt: Add BUG_ON() when wallclock goes backwards This reverts 'commit b5e1207658f0 ("ANDROID: arch_timer: add error handling when the MPM global timer is cleared")' The above mentioned commit removed a BUG_ON() which gets hit, when the wallclock goes backwards compared to the rq->window_start. This condition is fatal for WALT accounting. The update_task_ravg() strictly expects the wallclock - rq->window_start to be positive and when it becomes negative, the accounting issues would show up at later point of time which makes debugging difficult. This BUG_ON() is a false positive only when the MPM global timer is cleared and CPUs are running for a short time during force reset. It is very easy to identify this condition than debugging the scheduler accounting and time going backwards issues. So add the BUG_ON() back. Change-Id: Ib52862abb9448dc6db70bb7db958d11545db095f Signed-off-by: Pavankumar Kondeti Signed-off-by: Lingutla Chandrasekhar --- kernel/sched/walt.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index 9d949aa316ff..3ab874704575 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -272,15 +272,7 @@ update_window_start(struct rq *rq, u64 wallclock, int event) u64 old_window_start = rq->window_start; delta = wallclock - rq->window_start; - /* - * If the MPM global timer is cleared, set delta as 0 to - * avoid kernel BUG happening - */ - if (delta < 0) { - delta = 0; - WARN_ONCE(1, "WALT wallclock appears to have gone backwards or reset\n"); - } - + BUG_ON(delta < 0); if (delta < sched_ravg_window) return old_window_start; -- GitLab From 8e266aebf737262aeca9662254a3e61ccc7f8dec Mon Sep 17 00:00:00 2001 From: Chris Redpath Date: Mon, 9 Jul 2018 16:54:02 +0100 Subject: [PATCH 0069/1001] ANDROID: sched/rt: Add schedtune accounting to rt task enqueue/dequeue rt tasks are currently not eligible for schedtune boosting. Make it so by adding enqueue/dequeue hooks. For rt tasks, schedtune only acts as a frequency boosting framework, it has no impact on placement decisions and the prefer_idle attribute is not used. Also prepare schedutil use of boosted util for rt task boosting With this change, schedtune accounting will include rt class tasks, however boosting currently only applies to the utilization provided by fair class tasks. Sum up the tracked CPU utilization applying boost to the aggregate util instead - this includes RT task util in the boosting if any tasks are runnable. Scenario 1, considering one CPU: 1x rt task running, util 250, boost 0 1x cfs task runnable, util 250, boost 50 previous util=250+(50pct_boosted_250) = 887 new util=50_pct_boosted_500 = 762 Scenario 2, considering one CPU: 1x rt task running, util 250, boost 50 1x cfs task runnable, util 250, boost 0 previous util=250+250 = 500 new util=50_pct_boosted_500 = 762 Scenario 3, considering one CPU: 1x rt task running, util 250, boost 50 1x cfs task runnable, util 250, boost 50 previous util=250+(50pct_boosted_250) = 887 new util=50_pct_boosted_500 = 762 Scenario 4: 1x rt task running, util 250, boost 50 previous util=250 = 250 new util=50_pct_boosted_250 = 637 Change-Id: Ie287cbd0692468525095b5024db9faac8b2f4878 Signed-off-by: Chris Redpath --- kernel/sched/cpufreq_schedutil.c | 4 ++-- kernel/sched/fair.c | 8 ++++---- kernel/sched/rt.c | 5 +++++ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index 7560daeda9cc..d70794a6ee83 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -19,7 +19,7 @@ #include "sched.h" -unsigned long boosted_cpu_util(int cpu); +unsigned long boosted_cpu_util(int cpu, unsigned long other_util); #define SUGOV_KTHREAD_PRIORITY 50 @@ -216,7 +216,7 @@ static void sugov_get_util(unsigned long *util, unsigned long *max, int cpu) rt = sched_get_rt_rq_util(cpu); - *util = boosted_cpu_util(cpu) + rt; + *util = boosted_cpu_util(cpu, rt); *util = min(*util, max_cap); *max = max_cap; } diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 8862fadbef97..5e828914bf91 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5173,11 +5173,11 @@ static inline void update_overutilized_status(struct rq *rq) rcu_read_unlock(); } -unsigned long boosted_cpu_util(int cpu); +unsigned long boosted_cpu_util(int cpu, unsigned long other_util); #else #define update_overutilized_status(rq) do {} while (0) -#define boosted_cpu_util(cpu) cpu_util_freq(cpu) +#define boosted_cpu_util(cpu, other_util) cpu_util_freq(cpu) #endif /* CONFIG_SMP */ @@ -6644,9 +6644,9 @@ schedtune_task_margin(struct task_struct *task) #endif /* CONFIG_SCHED_TUNE */ unsigned long -boosted_cpu_util(int cpu) +boosted_cpu_util(int cpu, unsigned long other_util) { - unsigned long util = cpu_util_freq(cpu); + unsigned long util = cpu_util_freq(cpu) + other_util; long margin = schedtune_cpu_margin(util, cpu); trace_sched_boost_cpu(cpu, util, margin); diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 0adcb226f30c..69222ceeb0b1 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -8,6 +8,7 @@ #include #include +#include "tune.h" #include "walt.h" @@ -1324,6 +1325,8 @@ enqueue_task_rt(struct rq *rq, struct task_struct *p, int flags) { struct sched_rt_entity *rt_se = &p->rt; + schedtune_enqueue_task(p, cpu_of(rq)); + if (flags & ENQUEUE_WAKEUP) rt_se->timeout = 0; @@ -1338,6 +1341,8 @@ static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int flags) { struct sched_rt_entity *rt_se = &p->rt; + schedtune_dequeue_task(p, cpu_of(rq)); + update_curr_rt(rq); dequeue_rt_entity(rt_se, flags); walt_dec_cumulative_runnable_avg(rq, p); -- GitLab From a485e8b7bf8e95759e600396feeb7bfb400b6e46 Mon Sep 17 00:00:00 2001 From: Chris Redpath Date: Mon, 9 Jul 2018 15:44:00 +0100 Subject: [PATCH 0070/1001] ANDROID: Add hold functionality to schedtune CPU boost When tasks come and go from a runqueue quickly, this can lead to boost being applied and removed quickly which sometimes means we cannot raise the CPU frequency again when we need to (due to the rate limit on frequency updates). This has proved to be a particular issue for RT tasks and alternative methods have been used in the past to work around it. This is an attempt to solve the issue for all task classes and cpufreq governors by introducing a generic mechanism in schedtune to retain the max boost level from task enqueue for a minimum period - defined here as 50ms. This timeout was determined experimentally and is not configurable. A sched_feat guards the application of this to tasks - in the default configuration, task boosting only applied to tasks which have RT policy. Change SCHEDTUNE_BOOST_HOLD_ALL to true to apply it to all tasks regardless of class. It works like so: Every task enqueue (in an allowed class) stores a cpu-local timestamp. If the task is not a member of an allowed class (all or RT depending upon feature selection), the timestamp is not updated. The boost group will stay active regardless of tasks present until 50ms beyond the last timestamp stored. We also store the timestamp of the active boost group to avoid unneccesarily revisiting the boost groups when checking CPU boost level. If the timestamp is more than 50ms in the past when we check boost then we re-evaluate the boost groups for that CPU, taking into account the timestamps associated with each group. Idea based on rt-boost-retention patches from Joel. Change-Id: I52cc2d2e82d1c5aa03550378c8836764f41630c1 Suggested-by: Joel Fernandes Reviewed-by: Patrick Bellasi Signed-off-by: Chris Redpath [forward ported from android-4.9-eas-dev proposal] --- include/trace/events/sched.h | 11 +++-- kernel/sched/features.h | 11 +++++ kernel/sched/tune.c | 95 ++++++++++++++++++++++++++++++------ 3 files changed, 97 insertions(+), 20 deletions(-) diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index 9239d1c0aa08..ccbad75f6cc7 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -832,9 +832,9 @@ TRACE_EVENT(sched_boost_cpu, TRACE_EVENT(sched_tune_tasks_update, TP_PROTO(struct task_struct *tsk, int cpu, int tasks, int idx, - int boost, int max_boost), + int boost, int max_boost, u64 group_ts), - TP_ARGS(tsk, cpu, tasks, idx, boost, max_boost), + TP_ARGS(tsk, cpu, tasks, idx, boost, max_boost, group_ts), TP_STRUCT__entry( __array( char, comm, TASK_COMM_LEN ) @@ -844,6 +844,7 @@ TRACE_EVENT(sched_tune_tasks_update, __field( int, idx ) __field( int, boost ) __field( int, max_boost ) + __field( u64, group_ts ) ), TP_fast_assign( @@ -854,13 +855,15 @@ TRACE_EVENT(sched_tune_tasks_update, __entry->idx = idx; __entry->boost = boost; __entry->max_boost = max_boost; + __entry->group_ts = group_ts; ), TP_printk("pid=%d comm=%s " - "cpu=%d tasks=%d idx=%d boost=%d max_boost=%d", + "cpu=%d tasks=%d idx=%d boost=%d max_boost=%d timeout=%llu", __entry->pid, __entry->comm, __entry->cpu, __entry->tasks, __entry->idx, - __entry->boost, __entry->max_boost) + __entry->boost, __entry->max_boost, + __entry->group_ts) ); /* diff --git a/kernel/sched/features.h b/kernel/sched/features.h index 109e881a51c6..dbade300ef8c 100644 --- a/kernel/sched/features.h +++ b/kernel/sched/features.h @@ -118,3 +118,14 @@ SCHED_FEAT(ENERGY_AWARE, false) SCHED_FEAT(EAS_PREFER_IDLE, true) SCHED_FEAT(FIND_BEST_TARGET, true) SCHED_FEAT(FBT_STRICT_ORDER, true) + +/* + * Apply schedtune boost hold to tasks of all sched classes. + * If enabled, schedtune will hold the boost applied to a CPU + * for 50ms regardless of task activation - if the task is + * still running 50ms later, the boost hold expires and schedtune + * boost will expire immediately the task stops. + * If disabled, this behaviour will only apply to tasks of the + * RT class. + */ +SCHED_FEAT(SCHEDTUNE_BOOST_HOLD_ALL, false) diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c index 57fd9173d6b5..765dcd46d468 100644 --- a/kernel/sched/tune.c +++ b/kernel/sched/tune.c @@ -14,6 +14,9 @@ bool schedtune_initialized = false; extern struct reciprocal_value schedtune_spc_rdiv; +/* We hold schedtune boost in effect for at least this long */ +#define SCHEDTUNE_BOOST_HOLD_NS 50000000ULL + /* * EAS scheduler tunables for task groups. */ @@ -95,11 +98,14 @@ struct boost_groups { /* Maximum boost value for all RUNNABLE tasks on a CPU */ bool idle; int boost_max; + u64 boost_ts; struct { /* The boost for tasks on that boost group */ int boost; /* Count of RUNNABLE tasks on that boost group */ unsigned tasks; + /* Timestamp of boost activation */ + u64 ts; } group[BOOSTGROUPS_COUNT]; /* CPU's boost group locking */ raw_spinlock_t lock; @@ -108,30 +114,53 @@ struct boost_groups { /* Boost groups affecting each CPU in the system */ DEFINE_PER_CPU(struct boost_groups, cpu_boost_groups); +static inline bool schedtune_boost_timeout(u64 now, u64 ts) +{ + return ((now - ts) > SCHEDTUNE_BOOST_HOLD_NS); +} + +static inline bool +schedtune_boost_group_active(int idx, struct boost_groups* bg, u64 now) +{ + if (bg->group[idx].tasks) + return true; + + return !schedtune_boost_timeout(now, bg->group[idx].ts); +} + static void -schedtune_cpu_update(int cpu) +schedtune_cpu_update(int cpu, u64 now) { struct boost_groups *bg = &per_cpu(cpu_boost_groups, cpu); int boost_max; + u64 boost_ts; int idx; /* The root boost group is always active */ boost_max = bg->group[0].boost; + boost_ts = now; for (idx = 1; idx < BOOSTGROUPS_COUNT; ++idx) { /* * A boost group affects a CPU only if it has - * RUNNABLE tasks on that CPU + * RUNNABLE tasks on that CPU or it has hold + * in effect from a previous task. */ - if (bg->group[idx].tasks == 0) + if (!schedtune_boost_group_active(idx, bg, now)) + continue; + + /* This boost group is active */ + if (boost_max > bg->group[idx].boost) continue; - boost_max = max(boost_max, bg->group[idx].boost); + boost_max = bg->group[idx].boost; + boost_ts = bg->group[idx].ts; } /* Ensures boost_max is non-negative when all cgroup boost values * are neagtive. Avoids under-accounting of cpu capacity which may cause * task stacking and frequency spikes.*/ boost_max = max(boost_max, 0); bg->boost_max = boost_max; + bg->boost_ts = boost_ts; } static int @@ -141,6 +170,7 @@ schedtune_boostgroup_update(int idx, int boost) int cur_boost_max; int old_boost; int cpu; + u64 now; /* Update per CPU boost groups */ for_each_possible_cpu(cpu) { @@ -158,15 +188,19 @@ schedtune_boostgroup_update(int idx, int boost) bg->group[idx].boost = boost; /* Check if this update increase current max */ - if (boost > cur_boost_max && bg->group[idx].tasks) { + now = sched_clock_cpu(cpu); + if (boost > cur_boost_max && + schedtune_boost_group_active(idx, bg, now)) { bg->boost_max = boost; + bg->boost_ts = bg->group[idx].ts; + trace_sched_tune_boostgroup_update(cpu, 1, bg->boost_max); continue; } /* Check if this update has decreased current max */ if (cur_boost_max == old_boost && old_boost > boost) { - schedtune_cpu_update(cpu); + schedtune_cpu_update(cpu, now); trace_sched_tune_boostgroup_update(cpu, -1, bg->boost_max); continue; } @@ -180,6 +214,15 @@ schedtune_boostgroup_update(int idx, int boost) #define ENQUEUE_TASK 1 #define DEQUEUE_TASK -1 +static inline bool +schedtune_update_timestamp(struct task_struct *p) +{ + if (sched_feat(SCHEDTUNE_BOOST_HOLD_ALL)) + return true; + + return task_has_rt_policy(p); +} + static inline void schedtune_tasks_update(struct task_struct *p, int cpu, int idx, int task_count) { @@ -189,12 +232,21 @@ schedtune_tasks_update(struct task_struct *p, int cpu, int idx, int task_count) /* Update boosted tasks count while avoiding to make it negative */ bg->group[idx].tasks = max(0, tasks); - trace_sched_tune_tasks_update(p, cpu, tasks, idx, - bg->group[idx].boost, bg->boost_max); + /* Update timeout on enqueue */ + if (task_count > 0) { + u64 now = sched_clock_cpu(cpu); + + if (schedtune_update_timestamp(p)) + bg->group[idx].ts = now; - /* Boost group activation or deactivation on that RQ */ - if (tasks == 1 || tasks == 0) - schedtune_cpu_update(cpu); + /* Boost group activation or deactivation on that RQ */ + if (bg->group[idx].tasks == 1) + schedtune_cpu_update(cpu, now); + } + + trace_sched_tune_tasks_update(p, cpu, tasks, idx, + bg->group[idx].boost, bg->boost_max, + bg->group[idx].ts); } /* @@ -238,6 +290,7 @@ int schedtune_can_attach(struct cgroup_taskset *tset) int src_bg; /* Source boost group index */ int dst_bg; /* Destination boost group index */ int tasks; + u64 now; if (unlikely(!schedtune_initialized)) return 0; @@ -288,13 +341,15 @@ int schedtune_can_attach(struct cgroup_taskset *tset) bg->group[src_bg].tasks = max(0, tasks); bg->group[dst_bg].tasks += 1; - raw_spin_unlock(&bg->lock); - task_rq_unlock(rq, task, &rq_flags); + /* Update boost hold start for this group */ + now = sched_clock_cpu(cpu); + bg->group[dst_bg].ts = now; - /* Update CPU boost group */ - if (bg->group[src_bg].tasks == 0 || bg->group[dst_bg].tasks == 1) - schedtune_cpu_update(task_cpu(task)); + /* Force boost group re-evaluation at next boost check */ + bg->boost_ts = now - SCHEDTUNE_BOOST_HOLD_NS; + raw_spin_unlock(&bg->lock); + task_rq_unlock(rq, task, &rq_flags); } return 0; @@ -341,8 +396,15 @@ void schedtune_dequeue_task(struct task_struct *p, int cpu) int schedtune_cpu_boost(int cpu) { struct boost_groups *bg; + u64 now; bg = &per_cpu(cpu_boost_groups, cpu); + now = sched_clock_cpu(cpu); + + /* Check to see if we have a hold in effect */ + if (schedtune_boost_timeout(now, bg->boost_ts)) + schedtune_cpu_update(cpu, now); + return bg->boost_max; } @@ -451,6 +513,7 @@ schedtune_boostgroup_init(struct schedtune *st) bg = &per_cpu(cpu_boost_groups, cpu); bg->group[st->idx].boost = 0; bg->group[st->idx].tasks = 0; + bg->group[st->idx].ts = 0; } return 0; -- GitLab From 75965920ce1fed142cd67cd7b0b4b88e60a4f327 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Fri, 20 Jul 2018 03:15:13 -0700 Subject: [PATCH 0071/1001] msm: camera: eeprom: Memory allocation using vzalloc Use vzalloc instead of kzalloc to allocate memory for larger data sizes. Change-Id: Ic5aeca3029aa62c12b25d7f5843f2658586850c9 Signed-off-by: Vishalsingh Hajeri --- .../camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c index b58abdf03bc3..bd087b7ec51f 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c @@ -135,7 +135,7 @@ int cam_eeprom_parse_dt_memory_map(struct device_node *node, return rc; } - map = kzalloc((sizeof(*map) * data->num_map), GFP_KERNEL); + map = vzalloc((sizeof(*map) * data->num_map)); if (!map) { rc = -ENOMEM; return rc; @@ -184,7 +184,7 @@ int cam_eeprom_parse_dt_memory_map(struct device_node *node, data->num_data += map[i].mem.valid_size; } - data->mapdata = kzalloc(data->num_data, GFP_KERNEL); + data->mapdata = vzalloc(data->num_data); if (!data->mapdata) { rc = -ENOMEM; goto ERROR; @@ -192,7 +192,7 @@ int cam_eeprom_parse_dt_memory_map(struct device_node *node, return rc; ERROR: - kfree(data->map); + vfree(data->map); memset(data, 0, sizeof(*data)); return rc; } -- GitLab From 2fd1d21c9eb243f830af8e4bad6a6b67415084de Mon Sep 17 00:00:00 2001 From: Alex Yakavenka Date: Fri, 20 Jul 2018 15:17:04 -0700 Subject: [PATCH 0072/1001] ARM: dts: msm: Fix calypso frequency Change clock frequency of calypso controller for sa8155. Change-Id: Ic2f4a9305e9eeef60e2073b1184f473612b327ea Signed-off-by: Alex Yakavenka --- arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi index 07744a9b4d31..7d29320c0d12 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi @@ -23,7 +23,7 @@ interrupt-parent = <&tlmm>; interrupts = <38 0>; spi-max-frequency = <5000000>; - qcom,clk-freq-mhz = <16000000>; + qcom,clk-freq-mhz = <40000000>; qcom,max-can-channels = <4>; qcom,bits-per-word = <8>; qcom,support-can-fd; -- GitLab From 779145a6f6ec8976846aeefd60171627e3d40328 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Thu, 21 Jun 2018 09:23:22 -0700 Subject: [PATCH 0073/1001] compiler-gcc.h: Add __attribute__((gnu_inline)) to all inline declarations commit d03db2bc26f0e4a6849ad649a09c9c73fccdc656 upstream. Functions marked extern inline do not emit an externally visible function when the gnu89 C standard is used. Some KBUILD Makefiles overwrite KBUILD_CFLAGS. This is an issue for GCC 5.1+ users as without an explicit C standard specified, the default is gnu11. Since c99, the semantics of extern inline have changed such that an externally visible function is always emitted. This can lead to multiple definition errors of extern inline functions at link time of compilation units whose build files have removed an explicit C standard compiler flag for users of GCC 5.1+ or Clang. Suggested-by: Arnd Bergmann Suggested-by: H. Peter Anvin Suggested-by: Joe Perches Signed-off-by: Nick Desaulniers Acked-by: Juergen Gross Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: acme@redhat.com Cc: akataria@vmware.com Cc: akpm@linux-foundation.org Cc: andrea.parri@amarulasolutions.com Cc: ard.biesheuvel@linaro.org Cc: aryabinin@virtuozzo.com Cc: astrachan@google.com Cc: boris.ostrovsky@oracle.com Cc: brijesh.singh@amd.com Cc: caoj.fnst@cn.fujitsu.com Cc: geert@linux-m68k.org Cc: ghackmann@google.com Cc: gregkh@linuxfoundation.org Cc: jan.kiszka@siemens.com Cc: jarkko.sakkinen@linux.intel.com Cc: jpoimboe@redhat.com Cc: keescook@google.com Cc: kirill.shutemov@linux.intel.com Cc: kstewart@linuxfoundation.org Cc: linux-efi@vger.kernel.org Cc: linux-kbuild@vger.kernel.org Cc: manojgupta@google.com Cc: mawilcox@microsoft.com Cc: michal.lkml@markovi.net Cc: mjg59@google.com Cc: mka@chromium.org Cc: pombredanne@nexb.com Cc: rientjes@google.com Cc: rostedt@goodmis.org Cc: sedat.dilek@gmail.com Cc: thomas.lendacky@amd.com Cc: tstellar@redhat.com Cc: tweek@google.com Cc: virtualization@lists.linux-foundation.org Cc: will.deacon@arm.com Cc: yamada.masahiro@socionext.com Link: http://lkml.kernel.org/r/20180621162324.36656-2-ndesaulniers@google.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- include/linux/compiler-gcc.h | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index f43113b8890b..c11032b06d68 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -65,6 +65,18 @@ #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) #endif +/* + * Feature detection for gnu_inline (gnu89 extern inline semantics). Either + * __GNUC_STDC_INLINE__ is defined (not using gnu89 extern inline semantics, + * and we opt in to the gnu89 semantics), or __GNUC_STDC_INLINE__ is not + * defined so the gnu89 semantics are the default. + */ +#ifdef __GNUC_STDC_INLINE__ +# define __gnu_inline __attribute__((gnu_inline)) +#else +# define __gnu_inline +#endif + /* * Force always-inline if the user requests it so via the .config, * or if gcc is too old. @@ -72,19 +84,22 @@ * -Wunused-function. This turns out to avoid the need for complex #ifdef * directives. Suppress the warning in clang as well by using "unused" * function attribute, which is redundant but not harmful for gcc. + * Prefer gnu_inline, so that extern inline functions do not emit an + * externally visible function. This makes extern inline behave as per gnu89 + * semantics rather than c99. This prevents multiple symbol definition errors + * of extern inline functions at link time. + * A lot of inline functions can cause havoc with function tracing. */ #if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) || \ !defined(CONFIG_OPTIMIZE_INLINING) || (__GNUC__ < 4) -#define inline inline __attribute__((always_inline,unused)) notrace -#define __inline__ __inline__ __attribute__((always_inline,unused)) notrace -#define __inline __inline __attribute__((always_inline,unused)) notrace +#define inline \ + inline __attribute__((always_inline, unused)) notrace __gnu_inline #else -/* A lot of inline functions can cause havoc with function tracing */ -#define inline inline __attribute__((unused)) notrace -#define __inline__ __inline__ __attribute__((unused)) notrace -#define __inline __inline __attribute__((unused)) notrace +#define inline inline __attribute__((unused)) notrace __gnu_inline #endif +#define __inline__ inline +#define __inline inline #define __always_inline inline __attribute__((always_inline)) #define noinline __attribute__((noinline)) -- GitLab From 92e50158fc0ace8e7a0c53845588cdc246ce5ca1 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Thu, 21 Jun 2018 09:23:23 -0700 Subject: [PATCH 0074/1001] x86/asm: Add _ASM_ARG* constants for argument registers to commit 0e2e160033283e20f688d8bad5b89460cc5bfcc4 upstream. i386 and x86-64 uses different registers for arguments; make them available so we don't have to #ifdef in the actual code. Native size and specified size (q, l, w, b) versions are provided. Signed-off-by: H. Peter Anvin Signed-off-by: Nick Desaulniers Reviewed-by: Sedat Dilek Acked-by: Juergen Gross Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: acme@redhat.com Cc: akataria@vmware.com Cc: akpm@linux-foundation.org Cc: andrea.parri@amarulasolutions.com Cc: ard.biesheuvel@linaro.org Cc: arnd@arndb.de Cc: aryabinin@virtuozzo.com Cc: astrachan@google.com Cc: boris.ostrovsky@oracle.com Cc: brijesh.singh@amd.com Cc: caoj.fnst@cn.fujitsu.com Cc: geert@linux-m68k.org Cc: ghackmann@google.com Cc: gregkh@linuxfoundation.org Cc: jan.kiszka@siemens.com Cc: jarkko.sakkinen@linux.intel.com Cc: joe@perches.com Cc: jpoimboe@redhat.com Cc: keescook@google.com Cc: kirill.shutemov@linux.intel.com Cc: kstewart@linuxfoundation.org Cc: linux-efi@vger.kernel.org Cc: linux-kbuild@vger.kernel.org Cc: manojgupta@google.com Cc: mawilcox@microsoft.com Cc: michal.lkml@markovi.net Cc: mjg59@google.com Cc: mka@chromium.org Cc: pombredanne@nexb.com Cc: rientjes@google.com Cc: rostedt@goodmis.org Cc: thomas.lendacky@amd.com Cc: tstellar@redhat.com Cc: tweek@google.com Cc: virtualization@lists.linux-foundation.org Cc: will.deacon@arm.com Cc: yamada.masahiro@socionext.com Link: http://lkml.kernel.org/r/20180621162324.36656-3-ndesaulniers@google.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/asm.h | 59 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h index 386a6900e206..3bf87f92b932 100644 --- a/arch/x86/include/asm/asm.h +++ b/arch/x86/include/asm/asm.h @@ -46,6 +46,65 @@ #define _ASM_SI __ASM_REG(si) #define _ASM_DI __ASM_REG(di) +#ifndef __x86_64__ +/* 32 bit */ + +#define _ASM_ARG1 _ASM_AX +#define _ASM_ARG2 _ASM_DX +#define _ASM_ARG3 _ASM_CX + +#define _ASM_ARG1L eax +#define _ASM_ARG2L edx +#define _ASM_ARG3L ecx + +#define _ASM_ARG1W ax +#define _ASM_ARG2W dx +#define _ASM_ARG3W cx + +#define _ASM_ARG1B al +#define _ASM_ARG2B dl +#define _ASM_ARG3B cl + +#else +/* 64 bit */ + +#define _ASM_ARG1 _ASM_DI +#define _ASM_ARG2 _ASM_SI +#define _ASM_ARG3 _ASM_DX +#define _ASM_ARG4 _ASM_CX +#define _ASM_ARG5 r8 +#define _ASM_ARG6 r9 + +#define _ASM_ARG1Q rdi +#define _ASM_ARG2Q rsi +#define _ASM_ARG3Q rdx +#define _ASM_ARG4Q rcx +#define _ASM_ARG5Q r8 +#define _ASM_ARG6Q r9 + +#define _ASM_ARG1L edi +#define _ASM_ARG2L esi +#define _ASM_ARG3L edx +#define _ASM_ARG4L ecx +#define _ASM_ARG5L r8d +#define _ASM_ARG6L r9d + +#define _ASM_ARG1W di +#define _ASM_ARG2W si +#define _ASM_ARG3W dx +#define _ASM_ARG4W cx +#define _ASM_ARG5W r8w +#define _ASM_ARG6W r9w + +#define _ASM_ARG1B dil +#define _ASM_ARG2B sil +#define _ASM_ARG3B dl +#define _ASM_ARG4B cl +#define _ASM_ARG5B r8b +#define _ASM_ARG6B r9b + +#endif + /* * Macros to generate condition code outputs from inline assembly, * The output operand must be type "bool". -- GitLab From edefb935700c130ff52a0a0da7edab7a34d7572c Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Thu, 21 Jun 2018 09:23:24 -0700 Subject: [PATCH 0075/1001] x86/paravirt: Make native_save_fl() extern inline commit d0a8d9378d16eb3c69bd8e6d23779fbdbee3a8c7 upstream. native_save_fl() is marked static inline, but by using it as a function pointer in arch/x86/kernel/paravirt.c, it MUST be outlined. paravirt's use of native_save_fl() also requires that no GPRs other than %rax are clobbered. Compilers have different heuristics which they use to emit stack guard code, the emittance of which can break paravirt's callee saved assumption by clobbering %rcx. Marking a function definition extern inline means that if this version cannot be inlined, then the out-of-line version will be preferred. By having the out-of-line version be implemented in assembly, it cannot be instrumented with a stack protector, which might violate custom calling conventions that code like paravirt rely on. The semantics of extern inline has changed since gnu89. This means that folks using GCC versions >= 5.1 may see symbol redefinition errors at link time for subdirs that override KBUILD_CFLAGS (making the C standard used implicit) regardless of this patch. This has been cleaned up earlier in the patch set, but is left as a note in the commit message for future travelers. Reports: https://lkml.org/lkml/2018/5/7/534 https://github.com/ClangBuiltLinux/linux/issues/16 Discussion: https://bugs.llvm.org/show_bug.cgi?id=37512 https://lkml.org/lkml/2018/5/24/1371 Thanks to the many folks that participated in the discussion. Debugged-by: Alistair Strachan Debugged-by: Matthias Kaehlcke Suggested-by: Arnd Bergmann Suggested-by: H. Peter Anvin Suggested-by: Tom Stellar Reported-by: Sedat Dilek Tested-by: Sedat Dilek Signed-off-by: Nick Desaulniers Acked-by: Juergen Gross Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: acme@redhat.com Cc: akataria@vmware.com Cc: akpm@linux-foundation.org Cc: andrea.parri@amarulasolutions.com Cc: ard.biesheuvel@linaro.org Cc: aryabinin@virtuozzo.com Cc: astrachan@google.com Cc: boris.ostrovsky@oracle.com Cc: brijesh.singh@amd.com Cc: caoj.fnst@cn.fujitsu.com Cc: geert@linux-m68k.org Cc: ghackmann@google.com Cc: gregkh@linuxfoundation.org Cc: jan.kiszka@siemens.com Cc: jarkko.sakkinen@linux.intel.com Cc: joe@perches.com Cc: jpoimboe@redhat.com Cc: keescook@google.com Cc: kirill.shutemov@linux.intel.com Cc: kstewart@linuxfoundation.org Cc: linux-efi@vger.kernel.org Cc: linux-kbuild@vger.kernel.org Cc: manojgupta@google.com Cc: mawilcox@microsoft.com Cc: michal.lkml@markovi.net Cc: mjg59@google.com Cc: mka@chromium.org Cc: pombredanne@nexb.com Cc: rientjes@google.com Cc: rostedt@goodmis.org Cc: thomas.lendacky@amd.com Cc: tweek@google.com Cc: virtualization@lists.linux-foundation.org Cc: will.deacon@arm.com Cc: yamada.masahiro@socionext.com Link: http://lkml.kernel.org/r/20180621162324.36656-4-ndesaulniers@google.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/irqflags.h | 2 +- arch/x86/kernel/Makefile | 1 + arch/x86/kernel/irqflags.S | 26 ++++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 arch/x86/kernel/irqflags.S diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h index 89f08955fff7..c4fc17220df9 100644 --- a/arch/x86/include/asm/irqflags.h +++ b/arch/x86/include/asm/irqflags.h @@ -13,7 +13,7 @@ * Interrupt control: */ -static inline unsigned long native_save_fl(void) +extern inline unsigned long native_save_fl(void) { unsigned long flags; diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 295abaa58add..4137f7ba0f88 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -58,6 +58,7 @@ obj-y += alternative.o i8253.o pci-nommu.o hw_breakpoint.o obj-y += tsc.o tsc_msr.o io_delay.o rtc.o obj-y += pci-iommu_table.o obj-y += resource.o +obj-y += irqflags.o obj-y += process.o obj-y += fpu/ diff --git a/arch/x86/kernel/irqflags.S b/arch/x86/kernel/irqflags.S new file mode 100644 index 000000000000..ddeeaac8adda --- /dev/null +++ b/arch/x86/kernel/irqflags.S @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include +#include +#include + +/* + * unsigned long native_save_fl(void) + */ +ENTRY(native_save_fl) + pushf + pop %_ASM_AX + ret +ENDPROC(native_save_fl) +EXPORT_SYMBOL(native_save_fl) + +/* + * void native_restore_fl(unsigned long flags) + * %eax/%rdi: flags + */ +ENTRY(native_restore_fl) + push %_ASM_ARG1 + popf + ret +ENDPROC(native_restore_fl) +EXPORT_SYMBOL(native_restore_fl) -- GitLab From 61a9f6b7fe0ca9706b49a23cecf5f9a9c802b6ce Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Wed, 9 May 2018 16:01:46 +0100 Subject: [PATCH 0076/1001] Btrfs: fix duplicate extents after fsync of file with prealloc extents commit 31d11b83b96faaee4bb514d375a09489117c3e8d upstream. In commit 471d557afed1 ("Btrfs: fix loss of prealloc extents past i_size after fsync log replay"), on fsync, we started to always log all prealloc extents beyond an inode's i_size in order to avoid losing them after a power failure. However under some cases this can lead to the log replay code to create duplicate extent items, with different lengths, in the extent tree. That happens because, as of that commit, we can now log extent items based on extent maps that are not on the "modified" list of extent maps of the inode's extent map tree. Logging extent items based on extent maps is used during the fast fsync path to save time and for this to work reliably it requires that the extent maps are not merged with other adjacent extent maps - having the extent maps in the list of modified extents gives such guarantee. Consider the following example, captured during a long run of fsstress, which illustrates this problem. We have inode 271, in the filesystem tree (root 5), for which all of the following operations and discussion apply to. A buffered write starts at offset 312391 with a length of 933471 bytes (end offset at 1245862). At this point we have, for this inode, the following extent maps with the their field values: em A, start 0, orig_start 0, len 40960, block_start 18446744073709551613, block_len 0, orig_block_len 0 em B, start 40960, orig_start 40960, len 376832, block_start 1106399232, block_len 376832, orig_block_len 376832 em C, start 417792, orig_start 417792, len 782336, block_start 18446744073709551613, block_len 0, orig_block_len 0 em D, start 1200128, orig_start 1200128, len 835584, block_start 1106776064, block_len 835584, orig_block_len 835584 em E, start 2035712, orig_start 2035712, len 245760, block_start 1107611648, block_len 245760, orig_block_len 245760 Extent map A corresponds to a hole and extent maps D and E correspond to preallocated extents. Extent map D ends where extent map E begins (1106776064 + 835584 = 1107611648), but these extent maps were not merged because they are in the inode's list of modified extent maps. An fsync against this inode is made, which triggers the fast path (BTRFS_INODE_NEEDS_FULL_SYNC is not set). This fsync triggers writeback of the data previously written using buffered IO, and when the respective ordered extent finishes, btrfs_drop_extents() is called against the (aligned) range 311296..1249279. This causes a split of extent map D at btrfs_drop_extent_cache(), replacing extent map D with a new extent map D', also added to the list of modified extents, with the following values: em D', start 1249280, orig_start of 1200128, block_start 1106825216 (= 1106776064 + 1249280 - 1200128), orig_block_len 835584, block_len 786432 (835584 - (1249280 - 1200128)) Then, during the fast fsync, btrfs_log_changed_extents() is called and extent maps D' and E are removed from the list of modified extents. The flag EXTENT_FLAG_LOGGING is also set on them. After the extents are logged clear_em_logging() is called on each of them, and that makes extent map E to be merged with extent map D' (try_merge_map()), resulting in D' being deleted and E adjusted to: em E, start 1249280, orig_start 1200128, len 1032192, block_start 1106825216, block_len 1032192, orig_block_len 245760 A direct IO write at offset 1847296 and length of 360448 bytes (end offset at 2207744) starts, and at that moment the following extent maps exist for our inode: em A, start 0, orig_start 0, len 40960, block_start 18446744073709551613, block_len 0, orig_block_len 0 em B, start 40960, orig_start 40960, len 270336, block_start 1106399232, block_len 270336, orig_block_len 376832 em C, start 311296, orig_start 311296, len 937984, block_start 1112842240, block_len 937984, orig_block_len 937984 em E (prealloc), start 1249280, orig_start 1200128, len 1032192, block_start 1106825216, block_len 1032192, orig_block_len 245760 The dio write results in drop_extent_cache() being called twice. The first time for a range that starts at offset 1847296 and ends at offset 2035711 (length of 188416), which results in a double split of extent map E, replacing it with two new extent maps: em F, start 1249280, orig_start 1200128, block_start 1106825216, block_len 598016, orig_block_len 598016 em G, start 2035712, orig_start 1200128, block_start 1107611648, block_len 245760, orig_block_len 1032192 It also creates a new extent map that represents a part of the requested IO (through create_io_em()): em H, start 1847296, len 188416, block_start 1107423232, block_len 188416 The second call to drop_extent_cache() has a range with a start offset of 2035712 and end offset of 2207743 (length of 172032). This leads to replacing extent map G with a new extent map I with the following values: em I, start 2207744, orig_start 1200128, block_start 1107783680, block_len 73728, orig_block_len 1032192 It also creates a new extent map that represents the second part of the requested IO (through create_io_em()): em J, start 2035712, len 172032, block_start 1107611648, block_len 172032 The dio write set the inode's i_size to 2207744 bytes. After the dio write the inode has the following extent maps: em A, start 0, orig_start 0, len 40960, block_start 18446744073709551613, block_len 0, orig_block_len 0 em B, start 40960, orig_start 40960, len 270336, block_start 1106399232, block_len 270336, orig_block_len 376832 em C, start 311296, orig_start 311296, len 937984, block_start 1112842240, block_len 937984, orig_block_len 937984 em F, start 1249280, orig_start 1200128, len 598016, block_start 1106825216, block_len 598016, orig_block_len 598016 em H, start 1847296, orig_start 1200128, len 188416, block_start 1107423232, block_len 188416, orig_block_len 835584 em J, start 2035712, orig_start 2035712, len 172032, block_start 1107611648, block_len 172032, orig_block_len 245760 em I, start 2207744, orig_start 1200128, len 73728, block_start 1107783680, block_len 73728, orig_block_len 1032192 Now do some change to the file, like adding a xattr for example and then fsync it again. This triggers a fast fsync path, and as of commit 471d557afed1 ("Btrfs: fix loss of prealloc extents past i_size after fsync log replay"), we use the extent map I to log a file extent item because it's a prealloc extent and it starts at an offset matching the inode's i_size. However when we log it, we create a file extent item with a value for the disk byte location that is wrong, as can be seen from the following output of "btrfs inspect-internal dump-tree": item 1 key (271 EXTENT_DATA 2207744) itemoff 3782 itemsize 53 generation 22 type 2 (prealloc) prealloc data disk byte 1106776064 nr 1032192 prealloc data offset 1007616 nr 73728 Here the disk byte value corresponds to calculation based on some fields from the extent map I: 1106776064 = block_start (1107783680) - 1007616 (extent_offset) extent_offset = 2207744 (start) - 1200128 (orig_start) = 1007616 The disk byte value of 1106776064 clashes with disk byte values of the file extent items at offsets 1249280 and 1847296 in the fs tree: item 6 key (271 EXTENT_DATA 1249280) itemoff 3568 itemsize 53 generation 20 type 2 (prealloc) prealloc data disk byte 1106776064 nr 835584 prealloc data offset 49152 nr 598016 item 7 key (271 EXTENT_DATA 1847296) itemoff 3515 itemsize 53 generation 20 type 1 (regular) extent data disk byte 1106776064 nr 835584 extent data offset 647168 nr 188416 ram 835584 extent compression 0 (none) item 8 key (271 EXTENT_DATA 2035712) itemoff 3462 itemsize 53 generation 20 type 1 (regular) extent data disk byte 1107611648 nr 245760 extent data offset 0 nr 172032 ram 245760 extent compression 0 (none) item 9 key (271 EXTENT_DATA 2207744) itemoff 3409 itemsize 53 generation 20 type 2 (prealloc) prealloc data disk byte 1107611648 nr 245760 prealloc data offset 172032 nr 73728 Instead of the disk byte value of 1106776064, the value of 1107611648 should have been logged. Also the data offset value should have been 172032 and not 1007616. After a log replay we end up getting two extent items in the extent tree with different lengths, one of 835584, which is correct and existed before the log replay, and another one of 1032192 which is wrong and is based on the logged file extent item: item 12 key (1106776064 EXTENT_ITEM 835584) itemoff 3406 itemsize 53 refs 2 gen 15 flags DATA extent data backref root 5 objectid 271 offset 1200128 count 2 item 13 key (1106776064 EXTENT_ITEM 1032192) itemoff 3353 itemsize 53 refs 1 gen 22 flags DATA extent data backref root 5 objectid 271 offset 1200128 count 1 Obviously this leads to many problems and a filesystem check reports many errors: (...) checking extents Extent back ref already exists for 1106776064 parent 0 root 5 owner 271 offset 1200128 num_refs 1 extent item 1106776064 has multiple extent items ref mismatch on [1106776064 835584] extent item 2, found 3 Incorrect local backref count on 1106776064 root 5 owner 271 offset 1200128 found 2 wanted 1 back 0x55b1d0ad7680 Backref 1106776064 root 5 owner 271 offset 1200128 num_refs 0 not found in extent tree Incorrect local backref count on 1106776064 root 5 owner 271 offset 1200128 found 1 wanted 0 back 0x55b1d0ad4e70 Backref bytes do not match extent backref, bytenr=1106776064, ref bytes=835584, backref bytes=1032192 backpointer mismatch on [1106776064 835584] checking free space cache block group 1103101952 has wrong amount of free space failed to load free space cache for block group 1103101952 checking fs roots (...) So fix this by logging the prealloc extents beyond the inode's i_size based on searches in the subvolume tree instead of the extent maps. Fixes: 471d557afed1 ("Btrfs: fix loss of prealloc extents past i_size after fsync log replay") CC: stable@vger.kernel.org # 4.14+ Signed-off-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/tree-log.c | 137 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 112 insertions(+), 25 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index fc4c14a72366..bf4e22df7c97 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -4214,6 +4214,110 @@ static int log_one_extent(struct btrfs_trans_handle *trans, return ret; } +/* + * Log all prealloc extents beyond the inode's i_size to make sure we do not + * lose them after doing a fast fsync and replaying the log. We scan the + * subvolume's root instead of iterating the inode's extent map tree because + * otherwise we can log incorrect extent items based on extent map conversion. + * That can happen due to the fact that extent maps are merged when they + * are not in the extent map tree's list of modified extents. + */ +static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans, + struct btrfs_inode *inode, + struct btrfs_path *path) +{ + struct btrfs_root *root = inode->root; + struct btrfs_key key; + const u64 i_size = i_size_read(&inode->vfs_inode); + const u64 ino = btrfs_ino(inode); + struct btrfs_path *dst_path = NULL; + u64 last_extent = (u64)-1; + int ins_nr = 0; + int start_slot; + int ret; + + if (!(inode->flags & BTRFS_INODE_PREALLOC)) + return 0; + + key.objectid = ino; + key.type = BTRFS_EXTENT_DATA_KEY; + key.offset = i_size; + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) + goto out; + + while (true) { + struct extent_buffer *leaf = path->nodes[0]; + int slot = path->slots[0]; + + if (slot >= btrfs_header_nritems(leaf)) { + if (ins_nr > 0) { + ret = copy_items(trans, inode, dst_path, path, + &last_extent, start_slot, + ins_nr, 1, 0); + if (ret < 0) + goto out; + ins_nr = 0; + } + ret = btrfs_next_leaf(root, path); + if (ret < 0) + goto out; + if (ret > 0) { + ret = 0; + break; + } + continue; + } + + btrfs_item_key_to_cpu(leaf, &key, slot); + if (key.objectid > ino) + break; + if (WARN_ON_ONCE(key.objectid < ino) || + key.type < BTRFS_EXTENT_DATA_KEY || + key.offset < i_size) { + path->slots[0]++; + continue; + } + if (last_extent == (u64)-1) { + last_extent = key.offset; + /* + * Avoid logging extent items logged in past fsync calls + * and leading to duplicate keys in the log tree. + */ + do { + ret = btrfs_truncate_inode_items(trans, + root->log_root, + &inode->vfs_inode, + i_size, + BTRFS_EXTENT_DATA_KEY); + } while (ret == -EAGAIN); + if (ret) + goto out; + } + if (ins_nr == 0) + start_slot = slot; + ins_nr++; + path->slots[0]++; + if (!dst_path) { + dst_path = btrfs_alloc_path(); + if (!dst_path) { + ret = -ENOMEM; + goto out; + } + } + } + if (ins_nr > 0) { + ret = copy_items(trans, inode, dst_path, path, &last_extent, + start_slot, ins_nr, 1, 0); + if (ret > 0) + ret = 0; + } +out: + btrfs_release_path(path); + btrfs_free_path(dst_path); + return ret; +} + static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_inode *inode, @@ -4256,6 +4360,11 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, if (em->generation <= test_gen) continue; + /* We log prealloc extents beyond eof later. */ + if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags) && + em->start >= i_size_read(&inode->vfs_inode)) + continue; + if (em->start < logged_start) logged_start = em->start; if ((em->start + em->len - 1) > logged_end) @@ -4268,31 +4377,6 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, num++; } - /* - * Add all prealloc extents beyond the inode's i_size to make sure we - * don't lose them after doing a fast fsync and replaying the log. - */ - if (inode->flags & BTRFS_INODE_PREALLOC) { - struct rb_node *node; - - for (node = rb_last(&tree->map); node; node = rb_prev(node)) { - em = rb_entry(node, struct extent_map, rb_node); - if (em->start < i_size_read(&inode->vfs_inode)) - break; - if (!list_empty(&em->list)) - continue; - /* Same as above loop. */ - if (++num > 32768) { - list_del_init(&tree->modified_extents); - ret = -EFBIG; - goto process; - } - refcount_inc(&em->refs); - set_bit(EXTENT_FLAG_LOGGING, &em->flags); - list_add_tail(&em->list, &extents); - } - } - list_sort(NULL, &extents, extent_cmp); btrfs_get_logged_extents(inode, logged_list, logged_start, logged_end); /* @@ -4337,6 +4421,9 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, up_write(&inode->dio_sem); btrfs_release_path(path); + if (!ret) + ret = btrfs_log_prealloc_extents(trans, inode, path); + return ret; } -- GitLab From 1083a7e8130ca54cef63a5b1d6c86878d4b9e61d Mon Sep 17 00:00:00 2001 From: Prashanth Prakash Date: Fri, 27 Apr 2018 11:35:27 -0600 Subject: [PATCH 0077/1001] cpufreq / CPPC: Set platform specific transition_delay_us commit d4f3388afd488ed15368fa7413b8bd6d1f98bb1d upstream. Add support to specify platform specific transition_delay_us instead of using the transition delay derived from PCC. With commit 3d41386d556d (cpufreq: CPPC: Use transition_delay_us depending transition_latency) we are setting transition_delay_us directly and not applying the LATENCY_MULTIPLIER. Because of that, on Qualcomm Centriq we can end up with a very high rate of frequency change requests when using the schedutil governor (default rate_limit_us=10 compared to an earlier value of 10000). The PCC subspace describes the rate at which the platform can accept commands on the CPPC's PCC channel. This includes read and write command on the PCC channel that can be used for reasons other than frequency transitions. Moreover the same PCC subspace can be used by multiple freq domains and deriving transition_delay_us from it as we do now can be sub-optimal. Moreover if a platform does not use PCC for desired_perf register then there is no way to compute the transition latency or the delay_us. CPPC does not have a standard defined mechanism to get the transition rate or the latency at the moment. Given the above limitations, it is simpler to have a platform specific transition_delay_us and rely on PCC derived value only if a platform specific value is not available. Signed-off-by: Prashanth Prakash Cc: 4.14+ # 4.14+ Fixes: 3d41386d556d (cpufreq: CPPC: Use transition_delay_us depending transition_latency) Signed-off-by: Rafael J. Wysocki Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/cpufreq/cppc_cpufreq.c | 46 ++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 8b432d6e846d..c9ce716247c1 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -126,6 +126,49 @@ static void cppc_cpufreq_stop_cpu(struct cpufreq_policy *policy) cpu->perf_caps.lowest_perf, cpu_num, ret); } +/* + * The PCC subspace describes the rate at which platform can accept commands + * on the shared PCC channel (including READs which do not count towards freq + * trasition requests), so ideally we need to use the PCC values as a fallback + * if we don't have a platform specific transition_delay_us + */ +#ifdef CONFIG_ARM64 +#include + +static unsigned int cppc_cpufreq_get_transition_delay_us(int cpu) +{ + unsigned long implementor = read_cpuid_implementor(); + unsigned long part_num = read_cpuid_part_number(); + unsigned int delay_us = 0; + + switch (implementor) { + case ARM_CPU_IMP_QCOM: + switch (part_num) { + case QCOM_CPU_PART_FALKOR_V1: + case QCOM_CPU_PART_FALKOR: + delay_us = 10000; + break; + default: + delay_us = cppc_get_transition_latency(cpu) / NSEC_PER_USEC; + break; + } + break; + default: + delay_us = cppc_get_transition_latency(cpu) / NSEC_PER_USEC; + break; + } + + return delay_us; +} + +#else + +static unsigned int cppc_cpufreq_get_transition_delay_us(int cpu) +{ + return cppc_get_transition_latency(cpu) / NSEC_PER_USEC; +} +#endif + static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) { struct cppc_cpudata *cpu; @@ -163,8 +206,7 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.max_freq = cppc_dmi_max_khz; policy->cpuinfo.transition_latency = cppc_get_transition_latency(cpu_num); - policy->transition_delay_us = cppc_get_transition_latency(cpu_num) / - NSEC_PER_USEC; + policy->transition_delay_us = cppc_cpufreq_get_transition_delay_us(cpu_num); policy->shared_type = cpu->shared_type; if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) { -- GitLab From f5778c2d657e04782553ccc285e396f3062deb73 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 19 Mar 2018 14:23:16 -0400 Subject: [PATCH 0078/1001] xprtrdma: Fix corner cases when handling device removal commit 25524288631fc5b7d33259fca1e0dc38146be5d6 upstream. Michal Kalderon has found some corner cases around device unload with active NFS mounts that I didn't have the imagination to test when xprtrdma device removal was added last year. - The ULP device removal handler is responsible for deallocating the PD. That wasn't clear to me initially, and my own testing suggested it was not necessary, but that is incorrect. - The transport destruction path can no longer assume that there is a valid ID. - When destroying a transport, ensure that ib_free_cq() is not invoked on a CQ that was already released. Reported-by: Michal Kalderon Fixes: bebd031866ca ("xprtrdma: Support unplugging an HCA from ...") Signed-off-by: Chuck Lever Cc: stable@vger.kernel.org # v4.12+ Signed-off-by: Anna Schumaker Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/xprtrdma/verbs.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 97b9d4f671ac..2aaf46599126 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -270,7 +270,6 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event) wait_for_completion(&ia->ri_remove_done); ia->ri_id = NULL; - ia->ri_pd = NULL; ia->ri_device = NULL; /* Return 1 to ensure the core destroys the id. */ return 1; @@ -464,7 +463,9 @@ rpcrdma_ia_remove(struct rpcrdma_ia *ia) ia->ri_id->qp = NULL; } ib_free_cq(ep->rep_attr.recv_cq); + ep->rep_attr.recv_cq = NULL; ib_free_cq(ep->rep_attr.send_cq); + ep->rep_attr.send_cq = NULL; /* The ULP is responsible for ensuring all DMA * mappings and MRs are gone. @@ -477,6 +478,8 @@ rpcrdma_ia_remove(struct rpcrdma_ia *ia) rpcrdma_dma_unmap_regbuf(req->rl_recvbuf); } rpcrdma_destroy_mrs(buf); + ib_dealloc_pd(ia->ri_pd); + ia->ri_pd = NULL; /* Allow waiters to continue */ complete(&ia->ri_remove_done); @@ -650,14 +653,16 @@ rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) cancel_delayed_work_sync(&ep->rep_connect_worker); - if (ia->ri_id->qp) { + if (ia->ri_id && ia->ri_id->qp) { rpcrdma_ep_disconnect(ep, ia); rdma_destroy_qp(ia->ri_id); ia->ri_id->qp = NULL; } - ib_free_cq(ep->rep_attr.recv_cq); - ib_free_cq(ep->rep_attr.send_cq); + if (ep->rep_attr.recv_cq) + ib_free_cq(ep->rep_attr.recv_cq); + if (ep->rep_attr.send_cq) + ib_free_cq(ep->rep_attr.send_cq); } /* Re-establish a connection after a device removal event. -- GitLab From c59a8f13f36b51f2100111121b39c6d15eca124d Mon Sep 17 00:00:00 2001 From: alex chen Date: Wed, 15 Nov 2017 17:31:48 -0800 Subject: [PATCH 0079/1001] ocfs2: subsystem.su_mutex is required while accessing the item->ci_parent commit 853bc26a7ea39e354b9f8889ae7ad1492ffa28d2 upstream. The subsystem.su_mutex is required while accessing the item->ci_parent, otherwise, NULL pointer dereference to the item->ci_parent will be triggered in the following situation: add node delete node sys_write vfs_write configfs_write_file o2nm_node_store o2nm_node_local_write do_rmdir vfs_rmdir configfs_rmdir mutex_lock(&subsys->su_mutex); unlink_obj item->ci_group = NULL; item->ci_parent = NULL; to_o2nm_cluster_from_node node->nd_item.ci_parent->ci_parent BUG since of NULL pointer dereference to nd_item.ci_parent Moreover, the o2nm_cluster also should be protected by the subsystem.su_mutex. [alex.chen@huawei.com: v2] Link: http://lkml.kernel.org/r/59EEAA69.9080703@huawei.com Link: http://lkml.kernel.org/r/59E9B36A.10700@huawei.com Signed-off-by: Alex Chen Reviewed-by: Jun Piao Reviewed-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Cc: Junxiao Bi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Salvatore Bonaccorso Signed-off-by: Greg Kroah-Hartman --- fs/ocfs2/cluster/nodemanager.c | 63 +++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c index b17d180bdc16..c204ac9b49e5 100644 --- a/fs/ocfs2/cluster/nodemanager.c +++ b/fs/ocfs2/cluster/nodemanager.c @@ -40,6 +40,9 @@ char *o2nm_fence_method_desc[O2NM_FENCE_METHODS] = { "panic", /* O2NM_FENCE_PANIC */ }; +static inline void o2nm_lock_subsystem(void); +static inline void o2nm_unlock_subsystem(void); + struct o2nm_node *o2nm_get_node_by_num(u8 node_num) { struct o2nm_node *node = NULL; @@ -181,7 +184,10 @@ static struct o2nm_cluster *to_o2nm_cluster_from_node(struct o2nm_node *node) { /* through the first node_set .parent * mycluster/nodes/mynode == o2nm_cluster->o2nm_node_group->o2nm_node */ - return to_o2nm_cluster(node->nd_item.ci_parent->ci_parent); + if (node->nd_item.ci_parent) + return to_o2nm_cluster(node->nd_item.ci_parent->ci_parent); + else + return NULL; } enum { @@ -194,7 +200,7 @@ static ssize_t o2nm_node_num_store(struct config_item *item, const char *page, size_t count) { struct o2nm_node *node = to_o2nm_node(item); - struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node); + struct o2nm_cluster *cluster; unsigned long tmp; char *p = (char *)page; int ret = 0; @@ -214,6 +220,13 @@ static ssize_t o2nm_node_num_store(struct config_item *item, const char *page, !test_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes)) return -EINVAL; /* XXX */ + o2nm_lock_subsystem(); + cluster = to_o2nm_cluster_from_node(node); + if (!cluster) { + o2nm_unlock_subsystem(); + return -EINVAL; + } + write_lock(&cluster->cl_nodes_lock); if (cluster->cl_nodes[tmp]) ret = -EEXIST; @@ -226,6 +239,8 @@ static ssize_t o2nm_node_num_store(struct config_item *item, const char *page, set_bit(tmp, cluster->cl_nodes_bitmap); } write_unlock(&cluster->cl_nodes_lock); + o2nm_unlock_subsystem(); + if (ret) return ret; @@ -269,7 +284,7 @@ static ssize_t o2nm_node_ipv4_address_store(struct config_item *item, size_t count) { struct o2nm_node *node = to_o2nm_node(item); - struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node); + struct o2nm_cluster *cluster; int ret, i; struct rb_node **p, *parent; unsigned int octets[4]; @@ -286,6 +301,13 @@ static ssize_t o2nm_node_ipv4_address_store(struct config_item *item, be32_add_cpu(&ipv4_addr, octets[i] << (i * 8)); } + o2nm_lock_subsystem(); + cluster = to_o2nm_cluster_from_node(node); + if (!cluster) { + o2nm_unlock_subsystem(); + return -EINVAL; + } + ret = 0; write_lock(&cluster->cl_nodes_lock); if (o2nm_node_ip_tree_lookup(cluster, ipv4_addr, &p, &parent)) @@ -298,6 +320,8 @@ static ssize_t o2nm_node_ipv4_address_store(struct config_item *item, rb_insert_color(&node->nd_ip_node, &cluster->cl_node_ip_tree); } write_unlock(&cluster->cl_nodes_lock); + o2nm_unlock_subsystem(); + if (ret) return ret; @@ -315,7 +339,7 @@ static ssize_t o2nm_node_local_store(struct config_item *item, const char *page, size_t count) { struct o2nm_node *node = to_o2nm_node(item); - struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node); + struct o2nm_cluster *cluster; unsigned long tmp; char *p = (char *)page; ssize_t ret; @@ -333,17 +357,26 @@ static ssize_t o2nm_node_local_store(struct config_item *item, const char *page, !test_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes)) return -EINVAL; /* XXX */ + o2nm_lock_subsystem(); + cluster = to_o2nm_cluster_from_node(node); + if (!cluster) { + ret = -EINVAL; + goto out; + } + /* the only failure case is trying to set a new local node * when a different one is already set */ if (tmp && tmp == cluster->cl_has_local && - cluster->cl_local_node != node->nd_num) - return -EBUSY; + cluster->cl_local_node != node->nd_num) { + ret = -EBUSY; + goto out; + } /* bring up the rx thread if we're setting the new local node. */ if (tmp && !cluster->cl_has_local) { ret = o2net_start_listening(node); if (ret) - return ret; + goto out; } if (!tmp && cluster->cl_has_local && @@ -358,7 +391,11 @@ static ssize_t o2nm_node_local_store(struct config_item *item, const char *page, cluster->cl_local_node = node->nd_num; } - return count; + ret = count; + +out: + o2nm_unlock_subsystem(); + return ret; } CONFIGFS_ATTR(o2nm_node_, num); @@ -738,6 +775,16 @@ static struct o2nm_cluster_group o2nm_cluster_group = { }, }; +static inline void o2nm_lock_subsystem(void) +{ + mutex_lock(&o2nm_cluster_group.cs_subsys.su_mutex); +} + +static inline void o2nm_unlock_subsystem(void) +{ + mutex_unlock(&o2nm_cluster_group.cs_subsys.su_mutex); +} + int o2nm_depend_item(struct config_item *item) { return configfs_depend_item(&o2nm_cluster_group.cs_subsys, item); -- GitLab From 1ccab2bf726e1cd9292deecf4d72d732527035d6 Mon Sep 17 00:00:00 2001 From: alex chen Date: Wed, 15 Nov 2017 17:31:44 -0800 Subject: [PATCH 0080/1001] ocfs2: ip_alloc_sem should be taken in ocfs2_get_block() commit 3e4c56d41eef5595035872a2ec5a483f42e8917f upstream. ip_alloc_sem should be taken in ocfs2_get_block() when reading file in DIRECT mode to prevent concurrent access to extent tree with ocfs2_dio_end_io_write(), which may cause BUGON in the following situation: read file 'A' end_io of writing file 'A' vfs_read __vfs_read ocfs2_file_read_iter generic_file_read_iter ocfs2_direct_IO __blockdev_direct_IO do_blockdev_direct_IO do_direct_IO get_more_blocks ocfs2_get_block ocfs2_extent_map_get_blocks ocfs2_get_clusters ocfs2_get_clusters_nocache() ocfs2_search_extent_list return the index of record which contains the v_cluster, that is v_cluster > rec[i]->e_cpos. ocfs2_dio_end_io ocfs2_dio_end_io_write down_write(&oi->ip_alloc_sem); ocfs2_mark_extent_written ocfs2_change_extent_flag ocfs2_split_extent ... --> modify the rec[i]->e_cpos, resulting in v_cluster < rec[i]->e_cpos. BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos)) [alex.chen@huawei.com: v3] Link: http://lkml.kernel.org/r/59EF3614.6050008@huawei.com Link: http://lkml.kernel.org/r/59EF3614.6050008@huawei.com Fixes: c15471f79506 ("ocfs2: fix sparse file & data ordering issue in direct io") Signed-off-by: Alex Chen Reviewed-by: Jun Piao Reviewed-by: Joseph Qi Reviewed-by: Gang He Acked-by: Changwei Ge Cc: Mark Fasheh Cc: Joel Becker Cc: Junxiao Bi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Salvatore Bonaccorso Signed-off-by: Greg Kroah-Hartman --- fs/ocfs2/aops.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 88a31e9340a0..d1516327b787 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -134,6 +134,19 @@ static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock, return err; } +static int ocfs2_lock_get_block(struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create) +{ + int ret = 0; + struct ocfs2_inode_info *oi = OCFS2_I(inode); + + down_read(&oi->ip_alloc_sem); + ret = ocfs2_get_block(inode, iblock, bh_result, create); + up_read(&oi->ip_alloc_sem); + + return ret; +} + int ocfs2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { @@ -2128,7 +2141,7 @@ static void ocfs2_dio_free_write_ctx(struct inode *inode, * called like this: dio->get_blocks(dio->inode, fs_startblk, * fs_count, map_bh, dio->rw == WRITE); */ -static int ocfs2_dio_get_block(struct inode *inode, sector_t iblock, +static int ocfs2_dio_wr_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); @@ -2154,12 +2167,9 @@ static int ocfs2_dio_get_block(struct inode *inode, sector_t iblock, * while file size will be changed. */ if (pos + total_len <= i_size_read(inode)) { - down_read(&oi->ip_alloc_sem); - /* This is the fast path for re-write. */ - ret = ocfs2_get_block(inode, iblock, bh_result, create); - - up_read(&oi->ip_alloc_sem); + /* This is the fast path for re-write. */ + ret = ocfs2_lock_get_block(inode, iblock, bh_result, create); if (buffer_mapped(bh_result) && !buffer_new(bh_result) && ret == 0) @@ -2424,9 +2434,9 @@ static ssize_t ocfs2_direct_IO(struct kiocb *iocb, struct iov_iter *iter) return 0; if (iov_iter_rw(iter) == READ) - get_block = ocfs2_get_block; + get_block = ocfs2_lock_get_block; else - get_block = ocfs2_dio_get_block; + get_block = ocfs2_dio_wr_get_block; return __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, iter, get_block, -- GitLab From b913a05ab75e806db1ef6d54fb206a40dd4d5f1b Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Sun, 1 Oct 2017 13:02:15 +0200 Subject: [PATCH 0081/1001] bcm63xx_enet: correct clock usage commit 9c86b846ce02f7e35d7234cf090b80553eba5389 upstream. Check the return code of prepare_enable and change one last instance of enable only to prepare_enable. Also properly disable and release the clock in error paths and on remove for enetsw. Signed-off-by: Jonas Gorski Signed-off-by: David S. Miller Signed-off-by: Amit Pundir Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bcm63xx_enet.c | 31 +++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index 4f3845a58126..b7d8b6600be6 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -1773,7 +1773,9 @@ static int bcm_enet_probe(struct platform_device *pdev) ret = PTR_ERR(priv->mac_clk); goto out; } - clk_prepare_enable(priv->mac_clk); + ret = clk_prepare_enable(priv->mac_clk); + if (ret) + goto out_put_clk_mac; /* initialize default and fetch platform data */ priv->rx_ring_size = BCMENET_DEF_RX_DESC; @@ -1805,9 +1807,11 @@ static int bcm_enet_probe(struct platform_device *pdev) if (IS_ERR(priv->phy_clk)) { ret = PTR_ERR(priv->phy_clk); priv->phy_clk = NULL; - goto out_put_clk_mac; + goto out_disable_clk_mac; } - clk_prepare_enable(priv->phy_clk); + ret = clk_prepare_enable(priv->phy_clk); + if (ret) + goto out_put_clk_phy; } /* do minimal hardware init to be able to probe mii bus */ @@ -1901,13 +1905,16 @@ static int bcm_enet_probe(struct platform_device *pdev) out_uninit_hw: /* turn off mdc clock */ enet_writel(priv, 0, ENET_MIISC_REG); - if (priv->phy_clk) { + if (priv->phy_clk) clk_disable_unprepare(priv->phy_clk); + +out_put_clk_phy: + if (priv->phy_clk) clk_put(priv->phy_clk); - } -out_put_clk_mac: +out_disable_clk_mac: clk_disable_unprepare(priv->mac_clk); +out_put_clk_mac: clk_put(priv->mac_clk); out: free_netdev(dev); @@ -2752,7 +2759,9 @@ static int bcm_enetsw_probe(struct platform_device *pdev) ret = PTR_ERR(priv->mac_clk); goto out_unmap; } - clk_enable(priv->mac_clk); + ret = clk_prepare_enable(priv->mac_clk); + if (ret) + goto out_put_clk; priv->rx_chan = 0; priv->tx_chan = 1; @@ -2773,7 +2782,7 @@ static int bcm_enetsw_probe(struct platform_device *pdev) ret = register_netdev(dev); if (ret) - goto out_put_clk; + goto out_disable_clk; netif_carrier_off(dev); platform_set_drvdata(pdev, dev); @@ -2782,6 +2791,9 @@ static int bcm_enetsw_probe(struct platform_device *pdev) return 0; +out_disable_clk: + clk_disable_unprepare(priv->mac_clk); + out_put_clk: clk_put(priv->mac_clk); @@ -2813,6 +2825,9 @@ static int bcm_enetsw_remove(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); + clk_disable_unprepare(priv->mac_clk); + clk_put(priv->mac_clk); + free_netdev(dev); return 0; } -- GitLab From b1c3ce0cfff275ee2e88fe505a8f44712303f895 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Sun, 1 Oct 2017 13:02:16 +0200 Subject: [PATCH 0082/1001] bcm63xx_enet: do not write to random DMA channel on BCM6345 commit d6213c1f2ad54a964b77471690264ed685718928 upstream. The DMA controller regs actually point to DMA channel 0, so the write to ENETDMA_CFG_REG will actually modify a random DMA channel. Since DMA controller registers do not exist on BCM6345, guard the write with the usual check for dma_has_sram. Signed-off-by: Jonas Gorski Signed-off-by: David S. Miller Signed-off-by: Amit Pundir Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bcm63xx_enet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index b7d8b6600be6..68470c7c630a 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -1062,7 +1062,8 @@ static int bcm_enet_open(struct net_device *dev) val = enet_readl(priv, ENET_CTL_REG); val |= ENET_CTL_ENABLE_MASK; enet_writel(priv, val, ENET_CTL_REG); - enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG); + if (priv->dma_has_sram) + enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG); enet_dmac_writel(priv, priv->dma_chan_en_mask, ENETDMAC_CHANCFG, priv->rx_chan); -- GitLab From dc3782a3e9c61872df8c8ed395b60d3b7ad782b8 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Mon, 22 Jan 2018 11:28:54 +0900 Subject: [PATCH 0083/1001] PCI: exynos: Fix a potential init_clk_resources NULL pointer dereference commit b5d6bc90c9129279d363ccbc02ad11e7b657c0b4 upstream. In order to avoid triggering a NULL pointer dereference in exynos_pcie_probe() a check must be put in place to detect if the init_clk_resources hook is initialized before calling it. Add the respective function pointer check in exynos_pcie_probe(). Signed-off-by: Jaehoon Chung [lorenzo.pieralisi@arm.com: rewrote the commit log] Signed-off-by: Lorenzo Pieralisi Signed-off-by: Amit Pundir Signed-off-by: Greg Kroah-Hartman --- drivers/pci/dwc/pci-exynos.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/dwc/pci-exynos.c b/drivers/pci/dwc/pci-exynos.c index 5596fdedbb94..ea03f1ec12a4 100644 --- a/drivers/pci/dwc/pci-exynos.c +++ b/drivers/pci/dwc/pci-exynos.c @@ -695,7 +695,8 @@ static int __init exynos_pcie_probe(struct platform_device *pdev) return ret; } - if (ep->ops && ep->ops->get_clk_resources) { + if (ep->ops && ep->ops->get_clk_resources && + ep->ops->init_clk_resources) { ret = ep->ops->get_clk_resources(ep); if (ret) return ret; -- GitLab From 996a6a393b3f82f306ec65f25756a31f51ca3967 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 25 Aug 2017 15:47:14 +0200 Subject: [PATCH 0084/1001] crypto: crypto4xx - remove bad list_del commit a728a196d253530f17da5c86dc7dfbe58c5f7094 upstream. alg entries are only added to the list, after the registration was successful. If the registration failed, it was never added to the list in the first place. Signed-off-by: Christian Lamparter Signed-off-by: Herbert Xu Signed-off-by: Amit Pundir Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/amcc/crypto4xx_core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 65dc78b91dea..3118cec0d81e 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -1033,12 +1033,10 @@ int crypto4xx_register_alg(struct crypto4xx_device *sec_dev, break; } - if (rc) { - list_del(&alg->entry); + if (rc) kfree(alg); - } else { + else list_add_tail(&alg->entry, &sec_dev->alg_list); - } } return 0; -- GitLab From 03bb9187754e2c82626dafcd3e12a137cbb952ce Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 25 Aug 2017 15:47:24 +0200 Subject: [PATCH 0085/1001] crypto: crypto4xx - fix crypto4xx_build_pdr, crypto4xx_build_sdr leak commit 5d59ad6eea82ef8df92b4109615a0dde9d8093e9 upstream. If one of the later memory allocations in rypto4xx_build_pdr() fails: dev->pdr (and/or) dev->pdr_uinfo wouldn't be freed. crypto4xx_build_sdr() has the same issue with dev->sdr. Signed-off-by: Christian Lamparter Signed-off-by: Herbert Xu Signed-off-by: Amit Pundir Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/amcc/crypto4xx_core.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 3118cec0d81e..3f9eee7e555f 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -207,7 +207,7 @@ static u32 crypto4xx_build_pdr(struct crypto4xx_device *dev) dev->pdr_pa); return -ENOMEM; } - memset(dev->pdr, 0, sizeof(struct ce_pd) * PPC4XX_NUM_PD); + memset(dev->pdr, 0, sizeof(struct ce_pd) * PPC4XX_NUM_PD); dev->shadow_sa_pool = dma_alloc_coherent(dev->core_dev->device, 256 * PPC4XX_NUM_PD, &dev->shadow_sa_pool_pa, @@ -240,13 +240,15 @@ static u32 crypto4xx_build_pdr(struct crypto4xx_device *dev) static void crypto4xx_destroy_pdr(struct crypto4xx_device *dev) { - if (dev->pdr != NULL) + if (dev->pdr) dma_free_coherent(dev->core_dev->device, sizeof(struct ce_pd) * PPC4XX_NUM_PD, dev->pdr, dev->pdr_pa); + if (dev->shadow_sa_pool) dma_free_coherent(dev->core_dev->device, 256 * PPC4XX_NUM_PD, dev->shadow_sa_pool, dev->shadow_sa_pool_pa); + if (dev->shadow_sr_pool) dma_free_coherent(dev->core_dev->device, sizeof(struct sa_state_record) * PPC4XX_NUM_PD, @@ -416,12 +418,12 @@ static u32 crypto4xx_build_sdr(struct crypto4xx_device *dev) static void crypto4xx_destroy_sdr(struct crypto4xx_device *dev) { - if (dev->sdr != NULL) + if (dev->sdr) dma_free_coherent(dev->core_dev->device, sizeof(struct ce_sd) * PPC4XX_NUM_SD, dev->sdr, dev->sdr_pa); - if (dev->scatter_buffer_va != NULL) + if (dev->scatter_buffer_va) dma_free_coherent(dev->core_dev->device, dev->scatter_buffer_size * PPC4XX_NUM_SD, dev->scatter_buffer_va, @@ -1191,7 +1193,7 @@ static int crypto4xx_probe(struct platform_device *ofdev) rc = crypto4xx_build_gdr(core_dev->dev); if (rc) - goto err_build_gdr; + goto err_build_pdr; rc = crypto4xx_build_sdr(core_dev->dev); if (rc) @@ -1234,12 +1236,11 @@ static int crypto4xx_probe(struct platform_device *ofdev) err_request_irq: irq_dispose_mapping(core_dev->irq); tasklet_kill(&core_dev->tasklet); - crypto4xx_destroy_sdr(core_dev->dev); err_build_sdr: + crypto4xx_destroy_sdr(core_dev->dev); crypto4xx_destroy_gdr(core_dev->dev); -err_build_gdr: - crypto4xx_destroy_pdr(core_dev->dev); err_build_pdr: + crypto4xx_destroy_pdr(core_dev->dev); kfree(core_dev->dev); err_alloc_dev: kfree(core_dev); -- GitLab From c62e2f087af11564ecbd1c0d08bbd84ac92afc07 Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Fri, 29 Jun 2018 17:51:26 +0200 Subject: [PATCH 0086/1001] alx: take rtnl before calling __alx_open from resume [ Upstream commit bc800e8b39bad60ccdb83be828da63af71ab87b3 ] The __alx_open function can be called from ndo_open, which is called under RTNL, or from alx_resume, which isn't. Since commit d768319cd427, we're calling the netif_set_real_num_{tx,rx}_queues functions, which need to be called under RTNL. This is similar to commit 0c2cc02e571a ("igb: Move the calls to set the Tx and Rx queues into igb_open"). Fixes: d768319cd427 ("alx: enable multiple tx queues") Signed-off-by: Sabrina Dubroca Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/atheros/alx/main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index 567ee54504bc..5e5022fa1d04 100644 --- a/drivers/net/ethernet/atheros/alx/main.c +++ b/drivers/net/ethernet/atheros/alx/main.c @@ -1897,13 +1897,19 @@ static int alx_resume(struct device *dev) struct pci_dev *pdev = to_pci_dev(dev); struct alx_priv *alx = pci_get_drvdata(pdev); struct alx_hw *hw = &alx->hw; + int err; alx_reset_phy(hw); if (!netif_running(alx->dev)) return 0; netif_device_attach(alx->dev); - return __alx_open(alx, true); + + rtnl_lock(); + err = __alx_open(alx, true); + rtnl_unlock(); + + return err; } static SIMPLE_DEV_PM_OPS(alx_pm_ops, alx_suspend, alx_resume); -- GitLab From f93d65939a4a80f31e50af88bbd5fcae33266009 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 16 Jun 2018 11:55:44 +0100 Subject: [PATCH 0087/1001] atm: Preserve value of skb->truesize when accounting to vcc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 9bbe60a67be5a1c6f79b3c9be5003481a50529ff ] ATM accounts for in-flight TX packets in sk_wmem_alloc of the VCC on which they are to be sent. But it doesn't take ownership of those packets from the sock (if any) which originally owned them. They should remain owned by their actual sender until they've left the box. There's a hack in pskb_expand_head() to avoid adjusting skb->truesize for certain skbs, precisely to avoid messing up sk_wmem_alloc accounting. Ideally that hack would cover the ATM use case too, but it doesn't — skbs which aren't owned by any sock, for example PPP control frames, still get their truesize adjusted when the low-level ATM driver adds headroom. This has always been an issue, it seems. The truesize of a packet increases, and sk_wmem_alloc on the VCC goes negative. But this wasn't for normal traffic, only for control frames. So I think we just got away with it, and we probably needed to send 2GiB of LCP echo frames before the misaccounting would ever have caused a problem and caused atm_may_send() to start refusing packets. Commit 14afee4b609 ("net: convert sock.sk_wmem_alloc from atomic_t to refcount_t") did exactly what it was intended to do, and turned this mostly-theoretical problem into a real one, causing PPPoATM to fail immediately as sk_wmem_alloc underflows and atm_may_send() *immediately* starts refusing to allow new packets. The least intrusive solution to this problem is to stash the value of skb->truesize that was accounted to the VCC, in a new member of the ATM_SKB(skb) structure. Then in atm_pop_raw() subtract precisely that value instead of the then-current value of skb->truesize. Fixes: 158f323b9868 ("net: adjust skb->truesize in pskb_expand_head()") Signed-off-by: David Woodhouse Tested-by: Kevin Darbyshire-Bryant Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/atmdev.h | 15 +++++++++++++++ net/atm/br2684.c | 3 +-- net/atm/clip.c | 3 +-- net/atm/common.c | 3 +-- net/atm/lec.c | 3 +-- net/atm/mpc.c | 3 +-- net/atm/pppoatm.c | 3 +-- net/atm/raw.c | 4 ++-- 8 files changed, 23 insertions(+), 14 deletions(-) diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h index 0c27515d2cf6..8124815eb121 100644 --- a/include/linux/atmdev.h +++ b/include/linux/atmdev.h @@ -214,6 +214,7 @@ struct atmphy_ops { struct atm_skb_data { struct atm_vcc *vcc; /* ATM VCC */ unsigned long atm_options; /* ATM layer options */ + unsigned int acct_truesize; /* truesize accounted to vcc */ }; #define VCC_HTABLE_SIZE 32 @@ -241,6 +242,20 @@ void vcc_insert_socket(struct sock *sk); void atm_dev_release_vccs(struct atm_dev *dev); +static inline void atm_account_tx(struct atm_vcc *vcc, struct sk_buff *skb) +{ + /* + * Because ATM skbs may not belong to a sock (and we don't + * necessarily want to), skb->truesize may be adjusted, + * escaping the hack in pskb_expand_head() which avoids + * doing so for some cases. So stash the value of truesize + * at the time we accounted it, and atm_pop_raw() can use + * that value later, in case it changes. + */ + refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); + ATM_SKB(skb)->acct_truesize = skb->truesize; + ATM_SKB(skb)->atm_options = vcc->atm_options; +} static inline void atm_force_charge(struct atm_vcc *vcc,int truesize) { diff --git a/net/atm/br2684.c b/net/atm/br2684.c index 4e111196f902..bc21f8e8daf2 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -252,8 +252,7 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev, ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc; pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev); - refcount_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc); - ATM_SKB(skb)->atm_options = atmvcc->atm_options; + atm_account_tx(atmvcc, skb); dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; diff --git a/net/atm/clip.c b/net/atm/clip.c index 65f706e4344c..60920a42f640 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -381,8 +381,7 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb, memcpy(here, llc_oui, sizeof(llc_oui)); ((__be16 *) here)[3] = skb->protocol; } - refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); - ATM_SKB(skb)->atm_options = vcc->atm_options; + atm_account_tx(vcc, skb); entry->vccs->last_use = jiffies; pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc, vcc->dev); old = xchg(&entry->vccs->xoff, 1); /* assume XOFF ... */ diff --git a/net/atm/common.c b/net/atm/common.c index 8a4f99114cd2..9e812c782a37 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -630,10 +630,9 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size) goto out; } pr_debug("%d += %d\n", sk_wmem_alloc_get(sk), skb->truesize); - refcount_add(skb->truesize, &sk->sk_wmem_alloc); + atm_account_tx(vcc, skb); skb->dev = NULL; /* for paths shared with net_device interfaces */ - ATM_SKB(skb)->atm_options = vcc->atm_options; if (!copy_from_iter_full(skb_put(skb, size), size, &m->msg_iter)) { kfree_skb(skb); error = -EFAULT; diff --git a/net/atm/lec.c b/net/atm/lec.c index 5741b6474dd9..9f2365694ad4 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -182,9 +182,8 @@ lec_send(struct atm_vcc *vcc, struct sk_buff *skb) struct net_device *dev = skb->dev; ATM_SKB(skb)->vcc = vcc; - ATM_SKB(skb)->atm_options = vcc->atm_options; + atm_account_tx(vcc, skb); - refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); if (vcc->send(vcc, skb) < 0) { dev->stats.tx_dropped++; return; diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 5677147209e8..db9a1838687c 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -555,8 +555,7 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc) sizeof(struct llc_snap_hdr)); } - refcount_add(skb->truesize, &sk_atm(entry->shortcut)->sk_wmem_alloc); - ATM_SKB(skb)->atm_options = entry->shortcut->atm_options; + atm_account_tx(entry->shortcut, skb); entry->shortcut->send(entry->shortcut, skb); entry->packets_fwded++; mpc->in_ops->put(entry); diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c index 21d9d341a619..af8c4b38b746 100644 --- a/net/atm/pppoatm.c +++ b/net/atm/pppoatm.c @@ -350,8 +350,7 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) return 1; } - refcount_add(skb->truesize, &sk_atm(ATM_SKB(skb)->vcc)->sk_wmem_alloc); - ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options; + atm_account_tx(vcc, skb); pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev); ret = ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb) diff --git a/net/atm/raw.c b/net/atm/raw.c index ee10e8d46185..b3ba44aab0ee 100644 --- a/net/atm/raw.c +++ b/net/atm/raw.c @@ -35,8 +35,8 @@ static void atm_pop_raw(struct atm_vcc *vcc, struct sk_buff *skb) struct sock *sk = sk_atm(vcc); pr_debug("(%d) %d -= %d\n", - vcc->vci, sk_wmem_alloc_get(sk), skb->truesize); - WARN_ON(refcount_sub_and_test(skb->truesize, &sk->sk_wmem_alloc)); + vcc->vci, sk_wmem_alloc_get(sk), ATM_SKB(skb)->acct_truesize); + WARN_ON(refcount_sub_and_test(ATM_SKB(skb)->acct_truesize, &sk->sk_wmem_alloc)); dev_kfree_skb_any(skb); sk->sk_write_space(sk); } -- GitLab From 43c9207d029648dce52a45cd07dfb832d8a7957a Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 29 Jun 2018 13:28:07 -0500 Subject: [PATCH 0088/1001] atm: zatm: Fix potential Spectre v1 [ Upstream commit ced9e191501e52b95e1b57b8e0db00943869eed0 ] pool can be indirectly controlled by user-space, hence leading to a potential exploitation of the Spectre variant 1 vulnerability. This issue was detected with the help of Smatch: drivers/atm/zatm.c:1491 zatm_ioctl() warn: potential spectre issue 'zatm_dev->pool_info' (local cap) Fix this by sanitizing pool before using it to index zatm_dev->pool_info Notice that given that speculation windows are large, the policy is to kill the speculation on the first load and not worry if it can be completed with a dependent load/store [1]. [1] https://marc.info/?l=linux-kernel&m=152449131114778&w=2 Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/atm/zatm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index a8d2eb0ceb8d..2c288d1f42bb 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -1483,6 +1483,8 @@ static int zatm_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) return -EFAULT; if (pool < 0 || pool > ZATM_LAST_POOL) return -EINVAL; + pool = array_index_nospec(pool, + ZATM_LAST_POOL + 1); if (copy_from_user(&info, &((struct zatm_pool_req __user *) arg)->info, sizeof(info))) return -EFAULT; -- GitLab From e34e92d8b689179a6715518346a687bc1e87911a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 29 Jun 2018 14:07:16 -0700 Subject: [PATCH 0089/1001] hv_netvsc: split sub-channel setup into async and sync [ Upstream commit 3ffe64f1a641b80a82d9ef4efa7a05ce69049871 ] When doing device hotplug the sub channel must be async to avoid deadlock issues because device is discovered in softirq context. When doing changes to MTU and number of channels, the setup must be synchronous to avoid races such as when MTU and device settings are done in a single ip command. Reported-by: Thomas Walker Fixes: 8195b1396ec8 ("hv_netvsc: fix deadlock on hotplug") Fixes: 732e49850c5e ("netvsc: fix race on sub channel creation") Signed-off-by: Stephen Hemminger Signed-off-by: Haiyang Zhang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/hyperv/hyperv_net.h | 2 +- drivers/net/hyperv/netvsc.c | 37 ++++++++++++++++++- drivers/net/hyperv/netvsc_drv.c | 17 ++++++++- drivers/net/hyperv/rndis_filter.c | 61 ++++++------------------------- 4 files changed, 65 insertions(+), 52 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 01017dd88802..cb250cacf721 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -207,7 +207,7 @@ int netvsc_recv_callback(struct net_device *net, void netvsc_channel_cb(void *context); int netvsc_poll(struct napi_struct *napi, int budget); -void rndis_set_subchannel(struct work_struct *w); +int rndis_set_subchannel(struct net_device *ndev, struct netvsc_device *nvdev); int rndis_filter_open(struct netvsc_device *nvdev); int rndis_filter_close(struct netvsc_device *nvdev); struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 4647ecbe6f36..701be5d81062 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -62,6 +62,41 @@ void netvsc_switch_datapath(struct net_device *ndev, bool vf) VM_PKT_DATA_INBAND, 0); } +/* Worker to setup sub channels on initial setup + * Initial hotplug event occurs in softirq context + * and can't wait for channels. + */ +static void netvsc_subchan_work(struct work_struct *w) +{ + struct netvsc_device *nvdev = + container_of(w, struct netvsc_device, subchan_work); + struct rndis_device *rdev; + int i, ret; + + /* Avoid deadlock with device removal already under RTNL */ + if (!rtnl_trylock()) { + schedule_work(w); + return; + } + + rdev = nvdev->extension; + if (rdev) { + ret = rndis_set_subchannel(rdev->ndev, nvdev); + if (ret == 0) { + netif_device_attach(rdev->ndev); + } else { + /* fallback to only primary channel */ + for (i = 1; i < nvdev->num_chn; i++) + netif_napi_del(&nvdev->chan_table[i].napi); + + nvdev->max_chn = 1; + nvdev->num_chn = 1; + } + } + + rtnl_unlock(); +} + static struct netvsc_device *alloc_net_device(void) { struct netvsc_device *net_device; @@ -78,7 +113,7 @@ static struct netvsc_device *alloc_net_device(void) init_completion(&net_device->channel_init_wait); init_waitqueue_head(&net_device->subchan_open); - INIT_WORK(&net_device->subchan_work, rndis_set_subchannel); + INIT_WORK(&net_device->subchan_work, netvsc_subchan_work); return net_device; } diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 6890478a0851..aeabeb107fed 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -911,8 +911,20 @@ static int netvsc_attach(struct net_device *ndev, if (IS_ERR(nvdev)) return PTR_ERR(nvdev); - /* Note: enable and attach happen when sub-channels setup */ + if (nvdev->num_chn > 1) { + ret = rndis_set_subchannel(ndev, nvdev); + + /* if unavailable, just proceed with one queue */ + if (ret) { + nvdev->max_chn = 1; + nvdev->num_chn = 1; + } + } + + /* In any case device is now ready */ + netif_device_attach(ndev); + /* Note: enable and attach happen when sub-channels setup */ netif_carrier_off(ndev); if (netif_running(ndev)) { @@ -2035,6 +2047,9 @@ static int netvsc_probe(struct hv_device *dev, memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN); + if (nvdev->num_chn > 1) + schedule_work(&nvdev->subchan_work); + /* hw_features computed in rndis_netdev_set_hwcaps() */ net->features = net->hw_features | NETIF_F_HIGHDMA | NETIF_F_SG | diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index d1ae184008b4..cb03a6ea076a 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -1055,29 +1055,15 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc) * This breaks overlap of processing the host message for the * new primary channel with the initialization of sub-channels. */ -void rndis_set_subchannel(struct work_struct *w) +int rndis_set_subchannel(struct net_device *ndev, struct netvsc_device *nvdev) { - struct netvsc_device *nvdev - = container_of(w, struct netvsc_device, subchan_work); struct nvsp_message *init_packet = &nvdev->channel_init_pkt; - struct net_device_context *ndev_ctx; - struct rndis_device *rdev; - struct net_device *ndev; - struct hv_device *hv_dev; + struct net_device_context *ndev_ctx = netdev_priv(ndev); + struct hv_device *hv_dev = ndev_ctx->device_ctx; + struct rndis_device *rdev = nvdev->extension; int i, ret; - if (!rtnl_trylock()) { - schedule_work(w); - return; - } - - rdev = nvdev->extension; - if (!rdev) - goto unlock; /* device was removed */ - - ndev = rdev->ndev; - ndev_ctx = netdev_priv(ndev); - hv_dev = ndev_ctx->device_ctx; + ASSERT_RTNL(); memset(init_packet, 0, sizeof(struct nvsp_message)); init_packet->hdr.msg_type = NVSP_MSG5_TYPE_SUBCHANNEL; @@ -1091,13 +1077,13 @@ void rndis_set_subchannel(struct work_struct *w) VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); if (ret) { netdev_err(ndev, "sub channel allocate send failed: %d\n", ret); - goto failed; + return ret; } wait_for_completion(&nvdev->channel_init_wait); if (init_packet->msg.v5_msg.subchn_comp.status != NVSP_STAT_SUCCESS) { netdev_err(ndev, "sub channel request failed\n"); - goto failed; + return -EIO; } nvdev->num_chn = 1 + @@ -1116,21 +1102,7 @@ void rndis_set_subchannel(struct work_struct *w) for (i = 0; i < VRSS_SEND_TAB_SIZE; i++) ndev_ctx->tx_table[i] = i % nvdev->num_chn; - netif_device_attach(ndev); - rtnl_unlock(); - return; - -failed: - /* fallback to only primary channel */ - for (i = 1; i < nvdev->num_chn; i++) - netif_napi_del(&nvdev->chan_table[i].napi); - - nvdev->max_chn = 1; - nvdev->num_chn = 1; - - netif_device_attach(ndev); -unlock: - rtnl_unlock(); + return 0; } static int rndis_netdev_set_hwcaps(struct rndis_device *rndis_device, @@ -1321,21 +1293,12 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, netif_napi_add(net, &net_device->chan_table[i].napi, netvsc_poll, NAPI_POLL_WEIGHT); - if (net_device->num_chn > 1) - schedule_work(&net_device->subchan_work); + return net_device; out: - /* if unavailable, just proceed with one queue */ - if (ret) { - net_device->max_chn = 1; - net_device->num_chn = 1; - } - - /* No sub channels, device is ready */ - if (net_device->num_chn == 1) - netif_device_attach(net); - - return net_device; + /* setting up multiple channels failed */ + net_device->max_chn = 1; + net_device->num_chn = 1; err_dev_remv: rndis_filter_device_remove(dev, net_device); -- GitLab From d10c0baaae3f84185db3b3076a87d4343c9d62e6 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 30 Jun 2018 15:26:56 -0700 Subject: [PATCH 0090/1001] ipv6: sr: fix passing wrong flags to crypto_alloc_shash() [ Upstream commit fc9c2029e37c3ae9efc28bf47045e0b87e09660c ] The 'mask' argument to crypto_alloc_shash() uses the CRYPTO_ALG_* flags, not 'gfp_t'. So don't pass GFP_KERNEL to it. Fixes: bf355b8d2c30 ("ipv6: sr: add core files for SR HMAC support") Signed-off-by: Eric Biggers Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/seg6_hmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c index 33fb35cbfac1..558fe8cc6d43 100644 --- a/net/ipv6/seg6_hmac.c +++ b/net/ipv6/seg6_hmac.c @@ -373,7 +373,7 @@ static int seg6_hmac_init_algo(void) return -ENOMEM; for_each_possible_cpu(cpu) { - tfm = crypto_alloc_shash(algo->name, 0, GFP_KERNEL); + tfm = crypto_alloc_shash(algo->name, 0, 0); if (IS_ERR(tfm)) return PTR_ERR(tfm); p_tfm = per_cpu_ptr(algo->tfms, cpu); -- GitLab From f5a42d63f0d417654a8a4d4448015e1c642ee338 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Thu, 21 Jun 2018 12:56:04 +0800 Subject: [PATCH 0091/1001] ipvlan: fix IFLA_MTU ignored on NEWLINK [ Upstream commit 30877961b1cdd6fdca783c2e8c4f0f47e95dc58c ] Commit 296d48568042 ("ipvlan: inherit MTU from master device") adjusted the mtu from the master device when creating a ipvlan device, but it would also override the mtu value set in rtnl_create_link. It causes IFLA_MTU param not to take effect. So this patch is to not adjust the mtu if IFLA_MTU param is set when creating a ipvlan device. Fixes: 296d48568042 ("ipvlan: inherit MTU from master device") Reported-by: Jianlin Shi Signed-off-by: Xin Long Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ipvlan/ipvlan_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index c74893c1e620..e7f7a1a002ee 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -546,7 +546,8 @@ int ipvlan_link_new(struct net *src_net, struct net_device *dev, ipvlan->dev = dev; ipvlan->port = port; ipvlan->sfeatures = IPVLAN_FEATURES; - ipvlan_adjust_mtu(ipvlan, phy_dev); + if (!tb[IFLA_MTU]) + ipvlan_adjust_mtu(ipvlan, phy_dev); INIT_LIST_HEAD(&ipvlan->addrs); /* If the port-id base is at the MAX value, then wrap it around and -- GitLab From a2e53d69f68587d5272d45e2f4674746977bd5b2 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 26 Jun 2018 17:39:48 +0200 Subject: [PATCH 0092/1001] ixgbe: split XDP_TX tail and XDP_REDIRECT map flushing [ Upstream commit ad088ec480768850db019a5cc543685e868a513d ] The driver was combining the XDP_TX tail flush and XDP_REDIRECT map flushing (xdp_do_flush_map). This is suboptimal, these two flush operations should be kept separate. Fixes: 11393cc9b9be ("xdp: Add batching support to redirect map") Signed-off-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 20a8018d41ef..b68d94b49a8a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -2211,9 +2211,10 @@ static struct sk_buff *ixgbe_build_skb(struct ixgbe_ring *rx_ring, return skb; } -#define IXGBE_XDP_PASS 0 -#define IXGBE_XDP_CONSUMED 1 -#define IXGBE_XDP_TX 2 +#define IXGBE_XDP_PASS 0 +#define IXGBE_XDP_CONSUMED BIT(0) +#define IXGBE_XDP_TX BIT(1) +#define IXGBE_XDP_REDIR BIT(2) static int ixgbe_xmit_xdp_ring(struct ixgbe_adapter *adapter, struct xdp_buff *xdp); @@ -2242,7 +2243,7 @@ static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter, case XDP_REDIRECT: err = xdp_do_redirect(adapter->netdev, xdp, xdp_prog); if (!err) - result = IXGBE_XDP_TX; + result = IXGBE_XDP_REDIR; else result = IXGBE_XDP_CONSUMED; break; @@ -2302,7 +2303,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, unsigned int mss = 0; #endif /* IXGBE_FCOE */ u16 cleaned_count = ixgbe_desc_unused(rx_ring); - bool xdp_xmit = false; + unsigned int xdp_xmit = 0; while (likely(total_rx_packets < budget)) { union ixgbe_adv_rx_desc *rx_desc; @@ -2342,8 +2343,10 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, } if (IS_ERR(skb)) { - if (PTR_ERR(skb) == -IXGBE_XDP_TX) { - xdp_xmit = true; + unsigned int xdp_res = -PTR_ERR(skb); + + if (xdp_res & (IXGBE_XDP_TX | IXGBE_XDP_REDIR)) { + xdp_xmit |= xdp_res; ixgbe_rx_buffer_flip(rx_ring, rx_buffer, size); } else { rx_buffer->pagecnt_bias++; @@ -2415,7 +2418,10 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, total_rx_packets++; } - if (xdp_xmit) { + if (xdp_xmit & IXGBE_XDP_REDIR) + xdp_do_flush_map(); + + if (xdp_xmit & IXGBE_XDP_TX) { struct ixgbe_ring *ring = adapter->xdp_ring[smp_processor_id()]; /* Force memory writes to complete before letting h/w @@ -2423,8 +2429,6 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, */ wmb(); writel(ring->next_to_use, ring->tail); - - xdp_do_flush_map(); } u64_stats_update_begin(&rx_ring->syncp); -- GitLab From a3225a836e56487b32f21ff1a8099c731256d10a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 22 Jun 2018 06:44:14 -0700 Subject: [PATCH 0093/1001] net: dccp: avoid crash in ccid3_hc_rx_send_feedback() [ Upstream commit 74174fe5634ffbf645a7ca5a261571f700b2f332 ] On fast hosts or malicious bots, we trigger a DCCP_BUG() which seems excessive. syzbot reported : BUG: delta (-6195) <= 0 at net/dccp/ccids/ccid3.c:628/ccid3_hc_rx_send_feedback() CPU: 1 PID: 18 Comm: ksoftirqd/1 Not tainted 4.18.0-rc1+ #112 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x1c9/0x2b4 lib/dump_stack.c:113 ccid3_hc_rx_send_feedback net/dccp/ccids/ccid3.c:628 [inline] ccid3_hc_rx_packet_recv.cold.16+0x38/0x71 net/dccp/ccids/ccid3.c:793 ccid_hc_rx_packet_recv net/dccp/ccid.h:185 [inline] dccp_deliver_input_to_ccids+0xf0/0x280 net/dccp/input.c:180 dccp_rcv_established+0x87/0xb0 net/dccp/input.c:378 dccp_v4_do_rcv+0x153/0x180 net/dccp/ipv4.c:654 sk_backlog_rcv include/net/sock.h:914 [inline] __sk_receive_skb+0x3ba/0xd80 net/core/sock.c:517 dccp_v4_rcv+0x10f9/0x1f58 net/dccp/ipv4.c:875 ip_local_deliver_finish+0x2eb/0xda0 net/ipv4/ip_input.c:215 NF_HOOK include/linux/netfilter.h:287 [inline] ip_local_deliver+0x1e9/0x750 net/ipv4/ip_input.c:256 dst_input include/net/dst.h:450 [inline] ip_rcv_finish+0x823/0x2220 net/ipv4/ip_input.c:396 NF_HOOK include/linux/netfilter.h:287 [inline] ip_rcv+0xa18/0x1284 net/ipv4/ip_input.c:492 __netif_receive_skb_core+0x2488/0x3680 net/core/dev.c:4628 __netif_receive_skb+0x2c/0x1e0 net/core/dev.c:4693 process_backlog+0x219/0x760 net/core/dev.c:5373 napi_poll net/core/dev.c:5771 [inline] net_rx_action+0x7da/0x1980 net/core/dev.c:5837 __do_softirq+0x2e8/0xb17 kernel/softirq.c:284 run_ksoftirqd+0x86/0x100 kernel/softirq.c:645 smpboot_thread_fn+0x417/0x870 kernel/smpboot.c:164 kthread+0x345/0x410 kernel/kthread.c:240 ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:412 Signed-off-by: Eric Dumazet Reported-by: syzbot Cc: Gerrit Renker Cc: dccp@vger.kernel.org Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/dccp/ccids/ccid3.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 119c04317d48..b913ee062a81 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -624,9 +624,8 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk, case CCID3_FBACK_PERIODIC: delta = ktime_us_delta(now, hc->rx_tstamp_last_feedback); if (delta <= 0) - DCCP_BUG("delta (%ld) <= 0", (long)delta); - else - hc->rx_x_recv = scaled_div32(hc->rx_bytes_recv, delta); + delta = 1; + hc->rx_x_recv = scaled_div32(hc->rx_bytes_recv, delta); break; default: return; -- GitLab From fb6b14663d56afabf86a3a2078c37a8d28fc718a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 22 Jun 2018 06:44:15 -0700 Subject: [PATCH 0094/1001] net: dccp: switch rx_tstamp_last_feedback to monotonic clock [ Upstream commit 0ce4e70ff00662ad7490e545ba0cd8c1fa179fca ] To compute delays, better not use time of the day which can be changed by admins or malicious programs. Also change ccid3_first_li() to use s64 type for delta variable to avoid potential overflows. Signed-off-by: Eric Dumazet Cc: Gerrit Renker Cc: dccp@vger.kernel.org Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/dccp/ccids/ccid3.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index b913ee062a81..03fcf3ee1534 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -599,7 +599,7 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk, { struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk); struct dccp_sock *dp = dccp_sk(sk); - ktime_t now = ktime_get_real(); + ktime_t now = ktime_get(); s64 delta = 0; switch (fbtype) { @@ -631,7 +631,7 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk, return; } - ccid3_pr_debug("Interval %ldusec, X_recv=%u, 1/p=%u\n", (long)delta, + ccid3_pr_debug("Interval %lldusec, X_recv=%u, 1/p=%u\n", delta, hc->rx_x_recv, hc->rx_pinv); hc->rx_tstamp_last_feedback = now; @@ -678,7 +678,8 @@ static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb) static u32 ccid3_first_li(struct sock *sk) { struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk); - u32 x_recv, p, delta; + u32 x_recv, p; + s64 delta; u64 fval; if (hc->rx_rtt == 0) { @@ -686,7 +687,9 @@ static u32 ccid3_first_li(struct sock *sk) hc->rx_rtt = DCCP_FALLBACK_RTT; } - delta = ktime_to_us(net_timedelta(hc->rx_tstamp_last_feedback)); + delta = ktime_us_delta(ktime_get(), hc->rx_tstamp_last_feedback); + if (delta <= 0) + delta = 1; x_recv = scaled_div32(hc->rx_bytes_recv, delta); if (x_recv == 0) { /* would also trigger divide-by-zero */ DCCP_WARN("X_recv==0\n"); -- GitLab From b364a914c4993f46c0d849dab20d67ba0d82809d Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Sat, 30 Jun 2018 17:38:55 +0200 Subject: [PATCH 0095/1001] net: fix use-after-free in GRO with ESP [ Upstream commit 603d4cf8fe095b1ee78f423d514427be507fb513 ] Since the addition of GRO for ESP, gro_receive can consume the skb and return -EINPROGRESS. In that case, the lower layer GRO handler cannot touch the skb anymore. Commit 5f114163f2f5 ("net: Add a skb_gro_flush_final helper.") converted some of the gro_receive handlers that can lead to ESP's gro_receive so that they wouldn't access the skb when -EINPROGRESS is returned, but missed other spots, mainly in tunneling protocols. This patch finishes the conversion to using skb_gro_flush_final(), and adds a new helper, skb_gro_flush_final_remcsum(), used in VXLAN and GUE. Fixes: 5f114163f2f5 ("net: Add a skb_gro_flush_final helper.") Signed-off-by: Sabrina Dubroca Reviewed-by: Stefano Brivio Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/geneve.c | 2 +- drivers/net/vxlan.c | 4 +--- include/linux/netdevice.h | 20 ++++++++++++++++++++ net/8021q/vlan.c | 2 +- net/ipv4/fou.c | 4 +--- net/ipv4/gre_offload.c | 2 +- net/ipv4/udp_offload.c | 2 +- 7 files changed, 26 insertions(+), 10 deletions(-) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index fbc825ac97ab..cb51448389a1 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -474,7 +474,7 @@ static struct sk_buff **geneve_gro_receive(struct sock *sk, out_unlock: rcu_read_unlock(); out: - NAPI_GRO_CB(skb)->flush |= flush; + skb_gro_flush_final(skb, pp, flush); return pp; } diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 3d9c5b35a4a7..bbdb46916dc3 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -623,9 +623,7 @@ static struct sk_buff **vxlan_gro_receive(struct sock *sk, flush = 0; out: - skb_gro_remcsum_cleanup(skb, &grc); - skb->remcsum_offload = 0; - NAPI_GRO_CB(skb)->flush |= flush; + skb_gro_flush_final_remcsum(skb, pp, flush, &grc); return pp; } diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 46bf7cc7d5d5..2ea7ee1fb495 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2668,11 +2668,31 @@ static inline void skb_gro_flush_final(struct sk_buff *skb, struct sk_buff **pp, if (PTR_ERR(pp) != -EINPROGRESS) NAPI_GRO_CB(skb)->flush |= flush; } +static inline void skb_gro_flush_final_remcsum(struct sk_buff *skb, + struct sk_buff **pp, + int flush, + struct gro_remcsum *grc) +{ + if (PTR_ERR(pp) != -EINPROGRESS) { + NAPI_GRO_CB(skb)->flush |= flush; + skb_gro_remcsum_cleanup(skb, grc); + skb->remcsum_offload = 0; + } +} #else static inline void skb_gro_flush_final(struct sk_buff *skb, struct sk_buff **pp, int flush) { NAPI_GRO_CB(skb)->flush |= flush; } +static inline void skb_gro_flush_final_remcsum(struct sk_buff *skb, + struct sk_buff **pp, + int flush, + struct gro_remcsum *grc) +{ + NAPI_GRO_CB(skb)->flush |= flush; + skb_gro_remcsum_cleanup(skb, grc); + skb->remcsum_offload = 0; +} #endif static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index cf2e70003a53..cf82d970b0e4 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -664,7 +664,7 @@ static struct sk_buff **vlan_gro_receive(struct sk_buff **head, out_unlock: rcu_read_unlock(); out: - NAPI_GRO_CB(skb)->flush |= flush; + skb_gro_flush_final(skb, pp, flush); return pp; } diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index 1540db65241a..c9ec1603666b 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c @@ -448,9 +448,7 @@ static struct sk_buff **gue_gro_receive(struct sock *sk, out_unlock: rcu_read_unlock(); out: - NAPI_GRO_CB(skb)->flush |= flush; - skb_gro_remcsum_cleanup(skb, &grc); - skb->remcsum_offload = 0; + skb_gro_flush_final_remcsum(skb, pp, flush, &grc); return pp; } diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c index 1859c473b21a..6a7d980105f6 100644 --- a/net/ipv4/gre_offload.c +++ b/net/ipv4/gre_offload.c @@ -223,7 +223,7 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head, out_unlock: rcu_read_unlock(); out: - NAPI_GRO_CB(skb)->flush |= flush; + skb_gro_flush_final(skb, pp, flush); return pp; } diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index ea6e6e7df0ee..cde2719fcb89 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -295,7 +295,7 @@ struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb, out_unlock: rcu_read_unlock(); out: - NAPI_GRO_CB(skb)->flush |= flush; + skb_gro_flush_final(skb, pp, flush); return pp; } EXPORT_SYMBOL(udp_gro_receive); -- GitLab From f389c17b8dc54b474d33728e5882dcc276a467fa Mon Sep 17 00:00:00 2001 From: Harini Katakam Date: Wed, 20 Jun 2018 17:04:20 +0530 Subject: [PATCH 0096/1001] net: macb: Fix ptp time adjustment for large negative delta [ Upstream commit 64d7839af8c8f67daaf9bf387135052c55d85f90 ] When delta passed to gem_ptp_adjtime is negative, the sign is maintained in the ns_to_timespec64 conversion. Hence timespec_add should be used directly. timespec_sub will just subtract the negative value thus increasing the time difference. Signed-off-by: Harini Katakam Acked-by: Nicolas Ferre Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/cadence/macb_ptp.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c index 2220c771092b..678835136bf8 100755 --- a/drivers/net/ethernet/cadence/macb_ptp.c +++ b/drivers/net/ethernet/cadence/macb_ptp.c @@ -170,10 +170,7 @@ static int gem_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) if (delta > TSU_NSEC_MAX_VAL) { gem_tsu_get_time(&bp->ptp_clock_info, &now); - if (sign) - now = timespec64_sub(now, then); - else - now = timespec64_add(now, then); + now = timespec64_add(now, then); gem_tsu_set_time(&bp->ptp_clock_info, (const struct timespec64 *)&now); -- GitLab From 1d8dda4444fa0e8799a40d74e3502aac841ea002 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 31 May 2018 11:32:56 +0300 Subject: [PATCH 0097/1001] net/mlx5e: Avoid dealing with vport representors if not being e-switch manager [ Upstream commit 733d3e5497070d05971352ca5087bac83c197c3d ] In smartnic env, the host (PF) driver might not be an e-switch manager, hence the switchdev mode representors are running on the embedded cpu (EC) and not at the host. As such, we should avoid dealing with vport representors if not being esw manager. While here, make sure to disallow eswitch switchdev related setups through devlink if we are not esw managers. Fixes: cb67b832921c ('net/mlx5e: Introduce SRIOV VF representors') Signed-off-by: Or Gerlitz Reviewed-by: Eli Cohen Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 12 ++++++------ drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 2 +- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 337ce9423794..bf34264c734b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -2626,7 +2626,7 @@ void mlx5e_activate_priv_channels(struct mlx5e_priv *priv) mlx5e_activate_channels(&priv->channels); netif_tx_start_all_queues(priv->netdev); - if (MLX5_VPORT_MANAGER(priv->mdev)) + if (MLX5_ESWITCH_MANAGER(priv->mdev)) mlx5e_add_sqs_fwd_rules(priv); mlx5e_wait_channels_min_rx_wqes(&priv->channels); @@ -2637,7 +2637,7 @@ void mlx5e_deactivate_priv_channels(struct mlx5e_priv *priv) { mlx5e_redirect_rqts_to_drop(priv); - if (MLX5_VPORT_MANAGER(priv->mdev)) + if (MLX5_ESWITCH_MANAGER(priv->mdev)) mlx5e_remove_sqs_fwd_rules(priv); /* FIXME: This is a W/A only for tx timeout watch dog false alarm when @@ -4127,7 +4127,7 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev) mlx5e_set_netdev_dev_addr(netdev); #if IS_ENABLED(CONFIG_MLX5_ESWITCH) - if (MLX5_VPORT_MANAGER(mdev)) + if (MLX5_ESWITCH_MANAGER(mdev)) netdev->switchdev_ops = &mlx5e_switchdev_ops; #endif @@ -4273,7 +4273,7 @@ static void mlx5e_nic_enable(struct mlx5e_priv *priv) mlx5e_enable_async_events(priv); - if (MLX5_VPORT_MANAGER(priv->mdev)) + if (MLX5_ESWITCH_MANAGER(priv->mdev)) mlx5e_register_vport_reps(priv); if (netdev->reg_state != NETREG_REGISTERED) @@ -4300,7 +4300,7 @@ static void mlx5e_nic_disable(struct mlx5e_priv *priv) queue_work(priv->wq, &priv->set_rx_mode_work); - if (MLX5_VPORT_MANAGER(priv->mdev)) + if (MLX5_ESWITCH_MANAGER(priv->mdev)) mlx5e_unregister_vport_reps(priv); mlx5e_disable_async_events(priv); @@ -4483,7 +4483,7 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev) return NULL; #ifdef CONFIG_MLX5_ESWITCH - if (MLX5_VPORT_MANAGER(mdev)) { + if (MLX5_ESWITCH_MANAGER(mdev)) { rpriv = mlx5e_alloc_nic_rep_priv(mdev); if (!rpriv) { mlx5_core_warn(mdev, "Failed to alloc NIC rep priv data\n"); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 4727e7390834..3f6a7ca1cee8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -710,7 +710,7 @@ bool mlx5e_is_uplink_rep(struct mlx5e_priv *priv) struct mlx5e_rep_priv *rpriv = priv->ppriv; struct mlx5_eswitch_rep *rep; - if (!MLX5_CAP_GEN(priv->mdev, vport_group_manager)) + if (!MLX5_ESWITCH_MANAGER(priv->mdev)) return false; rep = rpriv->rep; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index d9fd8570b07c..c699055c0ffd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -912,8 +912,8 @@ static int mlx5_devlink_eswitch_check(struct devlink *devlink) if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH) return -EOPNOTSUPP; - if (!MLX5_CAP_GEN(dev, vport_group_manager)) - return -EOPNOTSUPP; + if(!MLX5_ESWITCH_MANAGER(dev)) + return -EPERM; if (dev->priv.eswitch->mode == SRIOV_NONE) return -EOPNOTSUPP; -- GitLab From b216867c02ac1146f3b66768845814150732f1e2 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 4 Jun 2018 19:46:53 +0300 Subject: [PATCH 0098/1001] net/mlx5e: Don't attempt to dereference the ppriv struct if not being eswitch manager [ Upstream commit 8ffd569aaa818f2624ca821d9a246342fa8b8c50 ] The check for cpu hit statistics was not returning immediate false for any non vport rep netdev and hence we crashed (say on mlx5 probed VFs) if user-space tool was calling into any possible netdev in the system. Fix that by doing a proper check before dereferencing. Fixes: 1d447a39142e ('net/mlx5e: Extendable vport representor netdev private data') Signed-off-by: Or Gerlitz Reported-by: Eli Cohen Reviewed-by: Eli Cohen Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 3f6a7ca1cee8..0e70cd6d8bc8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -724,8 +724,12 @@ bool mlx5e_is_uplink_rep(struct mlx5e_priv *priv) static bool mlx5e_is_vf_vport_rep(struct mlx5e_priv *priv) { struct mlx5e_rep_priv *rpriv = priv->ppriv; - struct mlx5_eswitch_rep *rep = rpriv->rep; + struct mlx5_eswitch_rep *rep; + if (!MLX5_CAP_GEN(priv->mdev, eswitch_flow_table)) + return false; + + rep = rpriv->rep; if (rep && rep->vport != FDB_UPLINK_VPORT) return true; -- GitLab From c3994f4f8bdaf660ad6740347d0de7acdeb4680a Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 31 May 2018 11:16:18 +0300 Subject: [PATCH 0099/1001] net/mlx5: E-Switch, Avoid setup attempt if not being e-switch manager [ Upstream commit 0efc8562491b7d36f6bbc4fbc8f3348cb6641e9c ] In smartnic env, the host (PF) driver might not be an e-switch manager, hence the FW will err on driver attempts to deal with setting/unsetting the eswitch and as a result the overall setup of sriov will fail. Fix that by avoiding the operation if e-switch management is not allowed for this driver instance. While here, move to use the correct name for the esw manager capability name. Fixes: 81848731ff40 ('net/mlx5: E-Switch, Add SR-IOV (FDB) support') Signed-off-by: Or Gerlitz Reported-by: Guy Kushnir Reviewed-by: Eli Cohen Tested-by: Eli Cohen Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 2 ++ drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 3 ++- drivers/net/ethernet/mellanox/mlx5/core/fw.c | 5 +++-- drivers/net/ethernet/mellanox/mlx5/core/sriov.c | 7 ++++++- include/linux/mlx5/mlx5_ifc.h | 2 +- 7 files changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 0e70cd6d8bc8..281911698f72 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -726,7 +726,7 @@ static bool mlx5e_is_vf_vport_rep(struct mlx5e_priv *priv) struct mlx5e_rep_priv *rpriv = priv->ppriv; struct mlx5_eswitch_rep *rep; - if (!MLX5_CAP_GEN(priv->mdev, eswitch_flow_table)) + if (!MLX5_ESWITCH_MANAGER(priv->mdev)) return false; rep = rpriv->rep; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 82e37250ed01..667415301066 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1535,7 +1535,7 @@ int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode) if (!ESW_ALLOWED(esw)) return 0; - if (!MLX5_CAP_GEN(esw->dev, eswitch_flow_table) || + if (!MLX5_ESWITCH_MANAGER(esw->dev) || !MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) { esw_warn(esw->dev, "E-Switch FDB is not supported, aborting ...\n"); return -EOPNOTSUPP; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 565c8b7a399a..10bf770675f3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -39,6 +39,8 @@ #include #include "lib/mpfs.h" +#define MLX5_ESWITCH_MANAGER(mdev) MLX5_CAP_GEN(mdev, eswitch_manager) + enum { SRIOV_NONE, SRIOV_LEGACY, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 33e5ff081e36..dd05cf148845 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -36,6 +36,7 @@ #include "mlx5_core.h" #include "fs_core.h" #include "fs_cmd.h" +#include "eswitch.h" #include "diag/fs_tracepoint.h" #define INIT_TREE_NODE_ARRAY_SIZE(...) (sizeof((struct init_tree_node[]){__VA_ARGS__}) /\ @@ -2211,7 +2212,7 @@ int mlx5_init_fs(struct mlx5_core_dev *dev) goto err; } - if (MLX5_CAP_GEN(dev, eswitch_flow_table)) { + if (MLX5_ESWITCH_MANAGER(dev)) { if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, ft_support)) { err = init_fdb_root_ns(steering); if (err) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index 2c71557d1cee..d69897a1e2ce 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -34,6 +34,7 @@ #include #include #include "mlx5_core.h" +#include "eswitch.h" #include "../../mlxfw/mlxfw.h" static int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev, u32 *out, @@ -152,13 +153,13 @@ int mlx5_query_hca_caps(struct mlx5_core_dev *dev) } if (MLX5_CAP_GEN(dev, vport_group_manager) && - MLX5_CAP_GEN(dev, eswitch_flow_table)) { + MLX5_ESWITCH_MANAGER(dev)) { err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH_FLOW_TABLE); if (err) return err; } - if (MLX5_CAP_GEN(dev, eswitch_flow_table)) { + if (MLX5_ESWITCH_MANAGER(dev)) { err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH); if (err) return err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c index 2a8b529ce6dd..a0674962f02c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c @@ -88,6 +88,9 @@ static int mlx5_device_enable_sriov(struct mlx5_core_dev *dev, int num_vfs) return -EBUSY; } + if (!MLX5_ESWITCH_MANAGER(dev)) + goto enable_vfs_hca; + err = mlx5_eswitch_enable_sriov(dev->priv.eswitch, num_vfs, SRIOV_LEGACY); if (err) { mlx5_core_warn(dev, @@ -95,6 +98,7 @@ static int mlx5_device_enable_sriov(struct mlx5_core_dev *dev, int num_vfs) return err; } +enable_vfs_hca: for (vf = 0; vf < num_vfs; vf++) { err = mlx5_core_enable_hca(dev, vf + 1); if (err) { @@ -140,7 +144,8 @@ static void mlx5_device_disable_sriov(struct mlx5_core_dev *dev) } out: - mlx5_eswitch_disable_sriov(dev->priv.eswitch); + if (MLX5_ESWITCH_MANAGER(dev)) + mlx5_eswitch_disable_sriov(dev->priv.eswitch); if (mlx5_wait_for_vf_pages(dev)) mlx5_core_warn(dev, "timeout reclaiming VFs pages\n"); diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index f3765155fa4d..1d793d86d55f 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -857,7 +857,7 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 reserved_at_1a4[0x1]; u8 ets[0x1]; u8 nic_flow_table[0x1]; - u8 eswitch_flow_table[0x1]; + u8 eswitch_manager[0x1]; u8 early_vf_enable[0x1]; u8 mcam_reg[0x1]; u8 pcam_reg[0x1]; -- GitLab From 075b5038124851d8fc79c68cb74680b20fbd2736 Mon Sep 17 00:00:00 2001 From: Alex Vesker Date: Tue, 12 Jun 2018 16:14:31 +0300 Subject: [PATCH 0100/1001] net/mlx5: Fix command interface race in polling mode [ Upstream commit d412c31dae053bf30a1bc15582a9990df297a660 ] The command interface can work in two modes: Events and Polling. In the general case, each time we invoke a command, a work is queued to handle it. When working in events, the interrupt handler completes the command execution. On the other hand, when working in polling mode, the work itself completes it. Due to a bug in the work handler, a command could have been completed by the interrupt handler, while the work handler hasn't finished yet, causing the it to complete once again if the command interface mode was changed from Events to polling after the interrupt handler was called. mlx5_unload_one() mlx5_stop_eqs() // Destroy the EQ before cmd EQ ...cmd_work_handler() write_doorbell() --> EVENT_TYPE_CMD mlx5_cmd_comp_handler() // First free free_ent(cmd, ent->idx) complete(&ent->done) <-- mlx5_stop_eqs //cmd was complete // move to polling before destroying the last cmd EQ mlx5_cmd_use_polling() cmd->mode = POLL; --> cmd_work_handler (continues) if (cmd->mode == POLL) mlx5_cmd_comp_handler() // Double free The solution is to store the cmd->mode before writing the doorbell. Fixes: e126ba97dba9 ("mlx5: Add driver for Mellanox Connect-IB adapters") Signed-off-by: Alex Vesker Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 3efe45bc2471..c5b649316bc1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -801,6 +801,7 @@ static void cmd_work_handler(struct work_struct *work) unsigned long flags; bool poll_cmd = ent->polling; int alloc_ret; + int cmd_mode; sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem; down(sem); @@ -847,6 +848,7 @@ static void cmd_work_handler(struct work_struct *work) set_signature(ent, !cmd->checksum_disabled); dump_command(dev, ent, 1); ent->ts1 = ktime_get_ns(); + cmd_mode = cmd->mode; if (ent->callback) schedule_delayed_work(&ent->cb_timeout_work, cb_timeout); @@ -871,7 +873,7 @@ static void cmd_work_handler(struct work_struct *work) iowrite32be(1 << ent->idx, &dev->iseg->cmd_dbell); mmiowb(); /* if not in polling don't use ent after this point */ - if (cmd->mode == CMD_MODE_POLLING || poll_cmd) { + if (cmd_mode == CMD_MODE_POLLING || poll_cmd) { poll_timeout(ent); /* make sure we read the descriptor after ownership is SW */ rmb(); -- GitLab From 8b7b5f76693c865fd85715e0c047719766eea2be Mon Sep 17 00:00:00 2001 From: Alex Vesker Date: Fri, 25 May 2018 20:25:59 +0300 Subject: [PATCH 0101/1001] net/mlx5: Fix incorrect raw command length parsing [ Upstream commit 603b7bcff824740500ddfa001d7a7168b0b38542 ] The NULL character was not set correctly for the string containing the command length, this caused failures reading the output of the command due to a random length. The fix is to initialize the output length string. Fixes: e126ba97dba9 ("mlx5: Add driver for Mellanox Connect-IB adapters") Signed-off-by: Alex Vesker Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index c5b649316bc1..cf94fdf25155 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -1274,7 +1274,7 @@ static ssize_t outlen_write(struct file *filp, const char __user *buf, { struct mlx5_core_dev *dev = filp->private_data; struct mlx5_cmd_debug *dbg = &dev->cmd.dbg; - char outlen_str[8]; + char outlen_str[8] = {0}; int outlen; void *ptr; int err; @@ -1289,8 +1289,6 @@ static ssize_t outlen_write(struct file *filp, const char __user *buf, if (copy_from_user(outlen_str, buf, count)) return -EFAULT; - outlen_str[7] = 0; - err = sscanf(outlen_str, "%d", &outlen); if (err < 0) return err; -- GitLab From 46ff2bc7aeb1b3d2fc36b20ddda0411889165cf1 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Wed, 13 Jun 2018 10:27:34 +0300 Subject: [PATCH 0102/1001] net/mlx5: Fix required capability for manipulating MPFS [ Upstream commit f811980444ec59ad62f9e041adbb576a821132c7 ] Manipulating of the MPFS requires eswitch manager capabilities. Fixes: eeb66cdb6826 ('net/mlx5: Separate between E-Switch and MPFS') Signed-off-by: Eli Cohen Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c index 7cb67122e8b5..22811ecd8fcd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c @@ -34,6 +34,7 @@ #include #include #include "mlx5_core.h" +#include "eswitch.h" #include "lib/mpfs.h" /* HW L2 Table (MPFS) management */ @@ -98,7 +99,7 @@ int mlx5_mpfs_init(struct mlx5_core_dev *dev) int l2table_size = 1 << MLX5_CAP_GEN(dev, log_max_l2_table); struct mlx5_mpfs *mpfs; - if (!MLX5_VPORT_MANAGER(dev)) + if (!MLX5_ESWITCH_MANAGER(dev)) return 0; mpfs = kzalloc(sizeof(*mpfs), GFP_KERNEL); @@ -122,7 +123,7 @@ void mlx5_mpfs_cleanup(struct mlx5_core_dev *dev) { struct mlx5_mpfs *mpfs = dev->priv.mpfs; - if (!MLX5_VPORT_MANAGER(dev)) + if (!MLX5_ESWITCH_MANAGER(dev)) return; WARN_ON(!hlist_empty(mpfs->hash)); @@ -137,7 +138,7 @@ int mlx5_mpfs_add_mac(struct mlx5_core_dev *dev, u8 *mac) u32 index; int err; - if (!MLX5_VPORT_MANAGER(dev)) + if (!MLX5_ESWITCH_MANAGER(dev)) return 0; mutex_lock(&mpfs->lock); @@ -179,7 +180,7 @@ int mlx5_mpfs_del_mac(struct mlx5_core_dev *dev, u8 *mac) int err = 0; u32 index; - if (!MLX5_VPORT_MANAGER(dev)) + if (!MLX5_ESWITCH_MANAGER(dev)) return 0; mutex_lock(&mpfs->lock); -- GitLab From 7ae129dd6778aa9b573b17083b13674d4336fa22 Mon Sep 17 00:00:00 2001 From: Shay Agroskin Date: Tue, 22 May 2018 14:14:02 +0300 Subject: [PATCH 0103/1001] net/mlx5: Fix wrong size allocation for QoS ETC TC regitster [ Upstream commit d14fcb8d877caf1b8d6bd65d444bf62b21f2070c ] The driver allocates wrong size (due to wrong struct name) when issuing a query/set request to NIC's register. Fixes: d8880795dabf ("net/mlx5e: Implement DCBNL IEEE max rate") Signed-off-by: Shay Agroskin Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/port.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index e07061f565d6..ccb6287aeeb7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -641,7 +641,7 @@ EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc); static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in, int inlen) { - u32 out[MLX5_ST_SZ_DW(qtct_reg)]; + u32 out[MLX5_ST_SZ_DW(qetc_reg)]; if (!MLX5_CAP_GEN(mdev, ets)) return -EOPNOTSUPP; @@ -653,7 +653,7 @@ static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in, static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out, int outlen) { - u32 in[MLX5_ST_SZ_DW(qtct_reg)]; + u32 in[MLX5_ST_SZ_DW(qetc_reg)]; if (!MLX5_CAP_GEN(mdev, ets)) return -EOPNOTSUPP; -- GitLab From ddbbd3e057438d4998904e39396871317a429b6b Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Fri, 22 Jun 2018 10:15:39 +0200 Subject: [PATCH 0104/1001] net: mvneta: fix the Rx desc DMA address in the Rx path [ Upstream commit 271f7ff5aa5a73488b7a9d8b84b5205fb5b2f7cc ] When using s/w buffer management, buffers are allocated and DMA mapped. When doing so on an arm64 platform, an offset correction is applied on the DMA address, before storing it in an Rx descriptor. The issue is this DMA address is then used later in the Rx path without removing the offset correction. Thus the DMA address is wrong, which can led to various issues. This patch fixes this by removing the offset correction from the DMA address retrieved from the Rx descriptor before using it in the Rx path. Fixes: 8d5047cf9ca2 ("net: mvneta: Convert to be 64 bits compatible") Signed-off-by: Antoine Tenart Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/marvell/mvneta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index d28f873169a9..3deaa3413313 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -1959,7 +1959,7 @@ static int mvneta_rx_swbm(struct mvneta_port *pp, int rx_todo, rx_bytes = rx_desc->data_size - (ETH_FCS_LEN + MVNETA_MH_SIZE); index = rx_desc - rxq->descs; data = rxq->buf_virt_addr[index]; - phys_addr = rx_desc->buf_phys_addr; + phys_addr = rx_desc->buf_phys_addr - pp->rx_offset_correction; if (!mvneta_rxq_desc_is_first_last(rx_status) || (rx_status & MVNETA_RXD_ERR_SUMMARY)) { -- GitLab From 5e6b4b9b28b72acd98729ad098e720a0606de2fd Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 21 Jun 2018 14:16:02 -0700 Subject: [PATCH 0105/1001] net/packet: fix use-after-free [ Upstream commit 945d015ee0c3095d2290e845565a23dedfd8027c ] We should put copy_skb in receive_queue only after a successful call to virtio_net_hdr_from_skb(). syzbot report : BUG: KASAN: use-after-free in __skb_unlink include/linux/skbuff.h:1843 [inline] BUG: KASAN: use-after-free in __skb_dequeue include/linux/skbuff.h:1863 [inline] BUG: KASAN: use-after-free in skb_dequeue+0x16a/0x180 net/core/skbuff.c:2815 Read of size 8 at addr ffff8801b044ecc0 by task syz-executor217/4553 CPU: 0 PID: 4553 Comm: syz-executor217 Not tainted 4.18.0-rc1+ #111 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x1c9/0x2b4 lib/dump_stack.c:113 print_address_description+0x6c/0x20b mm/kasan/report.c:256 kasan_report_error mm/kasan/report.c:354 [inline] kasan_report.cold.7+0x242/0x2fe mm/kasan/report.c:412 __asan_report_load8_noabort+0x14/0x20 mm/kasan/report.c:433 __skb_unlink include/linux/skbuff.h:1843 [inline] __skb_dequeue include/linux/skbuff.h:1863 [inline] skb_dequeue+0x16a/0x180 net/core/skbuff.c:2815 skb_queue_purge+0x26/0x40 net/core/skbuff.c:2852 packet_set_ring+0x675/0x1da0 net/packet/af_packet.c:4331 packet_release+0x630/0xd90 net/packet/af_packet.c:2991 __sock_release+0xd7/0x260 net/socket.c:603 sock_close+0x19/0x20 net/socket.c:1186 __fput+0x35b/0x8b0 fs/file_table.c:209 ____fput+0x15/0x20 fs/file_table.c:243 task_work_run+0x1ec/0x2a0 kernel/task_work.c:113 exit_task_work include/linux/task_work.h:22 [inline] do_exit+0x1b08/0x2750 kernel/exit.c:865 do_group_exit+0x177/0x440 kernel/exit.c:968 __do_sys_exit_group kernel/exit.c:979 [inline] __se_sys_exit_group kernel/exit.c:977 [inline] __x64_sys_exit_group+0x3e/0x50 kernel/exit.c:977 do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x4448e9 Code: Bad RIP value. RSP: 002b:00007ffd5f777ca8 EFLAGS: 00000202 ORIG_RAX: 00000000000000e7 RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00000000004448e9 RDX: 00000000004448e9 RSI: 000000000000fcfb RDI: 0000000000000001 RBP: 00000000006cf018 R08: 00007ffd0000a45b R09: 0000000000000000 R10: 00007ffd5f777e48 R11: 0000000000000202 R12: 00000000004021f0 R13: 0000000000402280 R14: 0000000000000000 R15: 0000000000000000 Allocated by task 4553: save_stack+0x43/0xd0 mm/kasan/kasan.c:448 set_track mm/kasan/kasan.c:460 [inline] kasan_kmalloc+0xc4/0xe0 mm/kasan/kasan.c:553 kasan_slab_alloc+0x12/0x20 mm/kasan/kasan.c:490 kmem_cache_alloc+0x12e/0x760 mm/slab.c:3554 skb_clone+0x1f5/0x500 net/core/skbuff.c:1282 tpacket_rcv+0x28f7/0x3200 net/packet/af_packet.c:2221 deliver_skb net/core/dev.c:1925 [inline] deliver_ptype_list_skb net/core/dev.c:1940 [inline] __netif_receive_skb_core+0x1bfb/0x3680 net/core/dev.c:4611 __netif_receive_skb+0x2c/0x1e0 net/core/dev.c:4693 netif_receive_skb_internal+0x12e/0x7d0 net/core/dev.c:4767 netif_receive_skb+0xbf/0x420 net/core/dev.c:4791 tun_rx_batched.isra.55+0x4ba/0x8c0 drivers/net/tun.c:1571 tun_get_user+0x2af1/0x42f0 drivers/net/tun.c:1981 tun_chr_write_iter+0xb9/0x154 drivers/net/tun.c:2009 call_write_iter include/linux/fs.h:1795 [inline] new_sync_write fs/read_write.c:474 [inline] __vfs_write+0x6c6/0x9f0 fs/read_write.c:487 vfs_write+0x1f8/0x560 fs/read_write.c:549 ksys_write+0x101/0x260 fs/read_write.c:598 __do_sys_write fs/read_write.c:610 [inline] __se_sys_write fs/read_write.c:607 [inline] __x64_sys_write+0x73/0xb0 fs/read_write.c:607 do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe Freed by task 4553: save_stack+0x43/0xd0 mm/kasan/kasan.c:448 set_track mm/kasan/kasan.c:460 [inline] __kasan_slab_free+0x11a/0x170 mm/kasan/kasan.c:521 kasan_slab_free+0xe/0x10 mm/kasan/kasan.c:528 __cache_free mm/slab.c:3498 [inline] kmem_cache_free+0x86/0x2d0 mm/slab.c:3756 kfree_skbmem+0x154/0x230 net/core/skbuff.c:582 __kfree_skb net/core/skbuff.c:642 [inline] kfree_skb+0x1a5/0x580 net/core/skbuff.c:659 tpacket_rcv+0x189e/0x3200 net/packet/af_packet.c:2385 deliver_skb net/core/dev.c:1925 [inline] deliver_ptype_list_skb net/core/dev.c:1940 [inline] __netif_receive_skb_core+0x1bfb/0x3680 net/core/dev.c:4611 __netif_receive_skb+0x2c/0x1e0 net/core/dev.c:4693 netif_receive_skb_internal+0x12e/0x7d0 net/core/dev.c:4767 netif_receive_skb+0xbf/0x420 net/core/dev.c:4791 tun_rx_batched.isra.55+0x4ba/0x8c0 drivers/net/tun.c:1571 tun_get_user+0x2af1/0x42f0 drivers/net/tun.c:1981 tun_chr_write_iter+0xb9/0x154 drivers/net/tun.c:2009 call_write_iter include/linux/fs.h:1795 [inline] new_sync_write fs/read_write.c:474 [inline] __vfs_write+0x6c6/0x9f0 fs/read_write.c:487 vfs_write+0x1f8/0x560 fs/read_write.c:549 ksys_write+0x101/0x260 fs/read_write.c:598 __do_sys_write fs/read_write.c:610 [inline] __se_sys_write fs/read_write.c:607 [inline] __x64_sys_write+0x73/0xb0 fs/read_write.c:607 do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe The buggy address belongs to the object at ffff8801b044ecc0 which belongs to the cache skbuff_head_cache of size 232 The buggy address is located 0 bytes inside of 232-byte region [ffff8801b044ecc0, ffff8801b044eda8) The buggy address belongs to the page: page:ffffea0006c11380 count:1 mapcount:0 mapping:ffff8801d9be96c0 index:0x0 flags: 0x2fffc0000000100(slab) raw: 02fffc0000000100 ffffea0006c17988 ffff8801d9bec248 ffff8801d9be96c0 raw: 0000000000000000 ffff8801b044e040 000000010000000c 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff8801b044eb80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ffff8801b044ec00: 00 00 00 00 00 00 00 00 00 00 00 00 00 fc fc fc >ffff8801b044ec80: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb ^ ffff8801b044ed00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff8801b044ed80: fb fb fb fb fb fc fc fc fc fc fc fc fc fc fc fc Fixes: 58d19b19cd99 ("packet: vnet_hdr support for tpacket_rcv") Signed-off-by: Eric Dumazet Reported-by: syzbot Cc: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/packet/af_packet.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 4fe2e34522d6..27dafe36f29c 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2303,6 +2303,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, if (po->stats.stats1.tp_drops) status |= TP_STATUS_LOSING; } + + if (do_vnet && + virtio_net_hdr_from_skb(skb, h.raw + macoff - + sizeof(struct virtio_net_hdr), + vio_le(), true, 0)) + goto drop_n_account; + po->stats.stats1.tp_packets++; if (copy_skb) { status |= TP_STATUS_COPY; @@ -2310,15 +2317,6 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, } spin_unlock(&sk->sk_receive_queue.lock); - if (do_vnet) { - if (virtio_net_hdr_from_skb(skb, h.raw + macoff - - sizeof(struct virtio_net_hdr), - vio_le(), true, 0)) { - spin_lock(&sk->sk_receive_queue.lock); - goto drop_n_account; - } - } - skb_copy_bits(skb, 0, h.raw + macoff, snaplen); if (!(ts_status = tpacket_get_timestamp(skb, &ts, po->tp_tstamp))) -- GitLab From b36f997add36c35c893c3dff7e1e01caa9541a13 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Fri, 15 Jun 2018 13:27:31 +0300 Subject: [PATCH 0106/1001] net_sched: blackhole: tell upper qdisc about dropped packets [ Upstream commit 7e85dc8cb35abf16455f1511f0670b57c1a84608 ] When blackhole is used on top of classful qdisc like hfsc it breaks qlen and backlog counters because packets are disappear without notice. In HFSC non-zero qlen while all classes are inactive triggers warning: WARNING: ... at net/sched/sch_hfsc.c:1393 hfsc_dequeue+0xba4/0xe90 [sch_hfsc] and schedules watchdog work endlessly. This patch return __NET_XMIT_BYPASS in addition to NET_XMIT_SUCCESS, this flag tells upper layer: this packet is gone and isn't queued. Signed-off-by: Konstantin Khlebnikov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/sch_blackhole.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_blackhole.c b/net/sched/sch_blackhole.c index c98a61e980ba..9c4c2bb547d7 100644 --- a/net/sched/sch_blackhole.c +++ b/net/sched/sch_blackhole.c @@ -21,7 +21,7 @@ static int blackhole_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) { qdisc_drop(skb, sch, to_free); - return NET_XMIT_SUCCESS; + return NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; } static struct sk_buff *blackhole_dequeue(struct Qdisc *sch) -- GitLab From b3c66b54d8fef1d032580d3f7660279cdd277576 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 19 Jun 2018 19:18:50 -0700 Subject: [PATCH 0107/1001] net: sungem: fix rx checksum support [ Upstream commit 12b03558cef6d655d0d394f5e98a6fd07c1f6c0f ] After commit 88078d98d1bb ("net: pskb_trim_rcsum() and CHECKSUM_COMPLETE are friends"), sungem owners reported the infamous "eth0: hw csum failure" message. CHECKSUM_COMPLETE has in fact never worked for this driver, but this was masked by the fact that upper stacks had to strip the FCS, and therefore skb->ip_summed was set back to CHECKSUM_NONE before my recent change. Driver configures a number of bytes to skip when the chip computes the checksum, and for some reason only half of the Ethernet header was skipped. Then a second problem is that we should strip the FCS by default, unless the driver is updated to eventually support NETIF_F_RXFCS in the future. Finally, a driver should check if NETIF_F_RXCSUM feature is enabled or not, so that the admin can turn off rx checksum if wanted. Many thanks to Andreas Schwab and Mathieu Malaterre for their help in debugging this issue. Signed-off-by: Eric Dumazet Reported-by: Meelis Roos Reported-by: Mathieu Malaterre Reported-by: Andreas Schwab Tested-by: Andreas Schwab Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/sun/sungem.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c index fa607d062cb3..15cd086e3f47 100644 --- a/drivers/net/ethernet/sun/sungem.c +++ b/drivers/net/ethernet/sun/sungem.c @@ -59,8 +59,7 @@ #include #include "sungem.h" -/* Stripping FCS is causing problems, disabled for now */ -#undef STRIP_FCS +#define STRIP_FCS #define DEFAULT_MSG (NETIF_MSG_DRV | \ NETIF_MSG_PROBE | \ @@ -434,7 +433,7 @@ static int gem_rxmac_reset(struct gem *gp) writel(desc_dma & 0xffffffff, gp->regs + RXDMA_DBLOW); writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK); val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) | - ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128); + (ETH_HLEN << 13) | RXDMA_CFG_FTHRESH_128); writel(val, gp->regs + RXDMA_CFG); if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN) writel(((5 & RXDMA_BLANK_IPKTS) | @@ -759,7 +758,6 @@ static int gem_rx(struct gem *gp, int work_to_do) struct net_device *dev = gp->dev; int entry, drops, work_done = 0; u32 done; - __sum16 csum; if (netif_msg_rx_status(gp)) printk(KERN_DEBUG "%s: rx interrupt, done: %d, rx_new: %d\n", @@ -854,9 +852,13 @@ static int gem_rx(struct gem *gp, int work_to_do) skb = copy_skb; } - csum = (__force __sum16)htons((status & RXDCTRL_TCPCSUM) ^ 0xffff); - skb->csum = csum_unfold(csum); - skb->ip_summed = CHECKSUM_COMPLETE; + if (likely(dev->features & NETIF_F_RXCSUM)) { + __sum16 csum; + + csum = (__force __sum16)htons((status & RXDCTRL_TCPCSUM) ^ 0xffff); + skb->csum = csum_unfold(csum); + skb->ip_summed = CHECKSUM_COMPLETE; + } skb->protocol = eth_type_trans(skb, gp->dev); napi_gro_receive(&gp->napi, skb); @@ -1760,7 +1762,7 @@ static void gem_init_dma(struct gem *gp) writel(0, gp->regs + TXDMA_KICK); val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) | - ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128); + (ETH_HLEN << 13) | RXDMA_CFG_FTHRESH_128); writel(val, gp->regs + RXDMA_CFG); writel(desc_dma >> 32, gp->regs + RXDMA_DBHI); @@ -2986,8 +2988,8 @@ static int gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, dev); /* We can do scatter/gather and HW checksum */ - dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; - dev->features |= dev->hw_features | NETIF_F_RXCSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM; + dev->features = dev->hw_features; if (pci_using_dac) dev->features |= NETIF_F_HIGHDMA; -- GitLab From 35e324ebeee0fed7d7d30b6ed9873a3f06f86e94 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 18 Jun 2018 12:30:37 -0700 Subject: [PATCH 0108/1001] net/tcp: Fix socket lookups with SO_BINDTODEVICE [ Upstream commit 8c43bd1706885ba1acfa88da02bc60a2ec16f68c ] Similar to 69678bcd4d2d ("udp: fix SO_BINDTODEVICE"), TCP socket lookups need to fail if dev_match is not true. Currently, a packet to a given port can match a socket bound to device when it should not. In the VRF case, this causes the lookup to hit a VRF socket and not a global socket resulting in a response trying to go through the VRF when it should not. Fixes: 3fa6f616a7a4d ("net: ipv4: add second dif to inet socket lookups") Fixes: 4297a0ef08572 ("net: ipv6: add second dif to inet6 socket lookups") Reported-by: Lou Berger Diagnosed-by: Renato Westphal Tested-by: Renato Westphal Signed-off-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/inet_hashtables.c | 4 ++-- net/ipv6/inet6_hashtables.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index e7d15fb0d94d..24b066c32e06 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -188,9 +188,9 @@ static inline int compute_score(struct sock *sk, struct net *net, bool dev_match = (sk->sk_bound_dev_if == dif || sk->sk_bound_dev_if == sdif); - if (exact_dif && !dev_match) + if (!dev_match) return -1; - if (sk->sk_bound_dev_if && dev_match) + if (sk->sk_bound_dev_if) score += 4; } if (sk->sk_incoming_cpu == raw_smp_processor_id()) diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index b01858f5deb1..6dc93ac28261 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -113,9 +113,9 @@ static inline int compute_score(struct sock *sk, struct net *net, bool dev_match = (sk->sk_bound_dev_if == dif || sk->sk_bound_dev_if == sdif); - if (exact_dif && !dev_match) + if (!dev_match) return -1; - if (sk->sk_bound_dev_if && dev_match) + if (sk->sk_bound_dev_if) score++; } if (sk->sk_incoming_cpu == raw_smp_processor_id()) -- GitLab From d725fde81ffc40e6e481c0705985471ee74a6a75 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Sun, 1 Jul 2018 20:03:08 -0700 Subject: [PATCH 0109/1001] qede: Adverstise software timestamp caps when PHC is not available. [ Upstream commit 82a4e71b1565dea8387f54503e806cf374e779ec ] When ptp clock is not available for a PF (e.g., higher PFs in NPAR mode), get-tsinfo() callback should return the software timestamp capabilities instead of returning the error. Fixes: 4c55215c ("qede: Add driver support for PTP") Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Michal Kalderon Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/qede/qede_ptp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qede/qede_ptp.c b/drivers/net/ethernet/qlogic/qede/qede_ptp.c index 9b2280badaf7..475f6ae5d4b3 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ptp.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ptp.c @@ -337,8 +337,14 @@ int qede_ptp_get_ts_info(struct qede_dev *edev, struct ethtool_ts_info *info) { struct qede_ptp *ptp = edev->ptp; - if (!ptp) - return -EIO; + if (!ptp) { + info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE; + info->phc_index = -1; + + return 0; + } info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | SOF_TIMESTAMPING_RX_SOFTWARE | -- GitLab From 4c2849931b239432020a7d77d955817b9b5e049b Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Sun, 1 Jul 2018 20:03:06 -0700 Subject: [PATCH 0110/1001] qed: Fix setting of incorrect eswitch mode. [ Upstream commit 538f8d00ba8bb417c4d9e76c61dee59d812d8287 ] By default, driver sets the eswitch mode incorrectly as VEB (virtual Ethernet bridging). Need to set VEB eswitch mode only when sriov is enabled, and it should be to set NONE by default. The patch incorporates this change. Fixes: 0fefbfbaa ("qed*: Management firmware - notifications and defaults") Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Michal Kalderon Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 2 +- drivers/net/ethernet/qlogic/qed/qed_sriov.c | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 58a689fb04db..ef2374699726 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -1782,7 +1782,7 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) DP_INFO(p_hwfn, "Failed to update driver state\n"); rc = qed_mcp_ov_update_eswitch(p_hwfn, p_hwfn->p_main_ptt, - QED_OV_ESWITCH_VEB); + QED_OV_ESWITCH_NONE); if (rc) DP_INFO(p_hwfn, "Failed to update eswitch mode\n"); } diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index 3f40b1de7957..d08fe350ab6c 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -4396,6 +4396,8 @@ static void qed_sriov_enable_qid_config(struct qed_hwfn *hwfn, static int qed_sriov_enable(struct qed_dev *cdev, int num) { struct qed_iov_vf_init_params params; + struct qed_hwfn *hwfn; + struct qed_ptt *ptt; int i, j, rc; if (num >= RESC_NUM(&cdev->hwfns[0], QED_VPORT)) { @@ -4408,8 +4410,8 @@ static int qed_sriov_enable(struct qed_dev *cdev, int num) /* Initialize HW for VF access */ for_each_hwfn(cdev, j) { - struct qed_hwfn *hwfn = &cdev->hwfns[j]; - struct qed_ptt *ptt = qed_ptt_acquire(hwfn); + hwfn = &cdev->hwfns[j]; + ptt = qed_ptt_acquire(hwfn); /* Make sure not to use more than 16 queues per VF */ params.num_queues = min_t(int, @@ -4445,6 +4447,19 @@ static int qed_sriov_enable(struct qed_dev *cdev, int num) goto err; } + hwfn = QED_LEADING_HWFN(cdev); + ptt = qed_ptt_acquire(hwfn); + if (!ptt) { + DP_ERR(hwfn, "Failed to acquire ptt\n"); + rc = -EBUSY; + goto err; + } + + rc = qed_mcp_ov_update_eswitch(hwfn, ptt, QED_OV_ESWITCH_VEB); + if (rc) + DP_INFO(cdev, "Failed to update eswitch mode\n"); + qed_ptt_release(hwfn, ptt); + return num; err: -- GitLab From 023a2043bc8aacbf4418d41ee849b73c83e1cd3c Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Sun, 1 Jul 2018 20:03:07 -0700 Subject: [PATCH 0111/1001] qed: Fix use of incorrect size in memcpy call. [ Upstream commit cc9b27cdf7bd3c86df73439758ac1564bc8f5bbe ] Use the correct size value while copying chassis/port id values. Fixes: 6ad8c632e ("qed: Add support for query/config dcbx.") Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Michal Kalderon Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/qed/qed_dcbx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c index 8f6ccc0c39e5..b306961b02fd 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c @@ -700,9 +700,9 @@ qed_dcbx_get_local_lldp_params(struct qed_hwfn *p_hwfn, p_local = &p_hwfn->p_dcbx_info->lldp_local[LLDP_NEAREST_BRIDGE]; memcpy(params->lldp_local.local_chassis_id, p_local->local_chassis_id, - ARRAY_SIZE(p_local->local_chassis_id)); + sizeof(p_local->local_chassis_id)); memcpy(params->lldp_local.local_port_id, p_local->local_port_id, - ARRAY_SIZE(p_local->local_port_id)); + sizeof(p_local->local_port_id)); } static void @@ -714,9 +714,9 @@ qed_dcbx_get_remote_lldp_params(struct qed_hwfn *p_hwfn, p_remote = &p_hwfn->p_dcbx_info->lldp_remote[LLDP_NEAREST_BRIDGE]; memcpy(params->lldp_remote.peer_chassis_id, p_remote->peer_chassis_id, - ARRAY_SIZE(p_remote->peer_chassis_id)); + sizeof(p_remote->peer_chassis_id)); memcpy(params->lldp_remote.peer_port_id, p_remote->peer_port_id, - ARRAY_SIZE(p_remote->peer_port_id)); + sizeof(p_remote->peer_port_id)); } static int -- GitLab From dd537828bf733a81c2748a4ba90876b24d0720c5 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Sun, 1 Jul 2018 20:03:05 -0700 Subject: [PATCH 0112/1001] qed: Limit msix vectors in kdump kernel to the minimum required count. [ Upstream commit bb7858ba1102f82470a917e041fd23e6385c31be ] Memory size is limited in the kdump kernel environment. Allocation of more msix-vectors (or queues) consumes few tens of MBs of memory, which might lead to the kdump kernel failure. This patch adds changes to limit the number of MSI-X vectors in kdump kernel to minimum required value (i.e., 2 per engine). Fixes: fe56b9e6a ("qed: Add module with basic common support") Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Michal Kalderon Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/qed/qed_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 27832885a87f..2c958921dfb3 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -779,6 +779,14 @@ static int qed_slowpath_setup_int(struct qed_dev *cdev, /* We want a minimum of one slowpath and one fastpath vector per hwfn */ cdev->int_params.in.min_msix_cnt = cdev->num_hwfns * 2; + if (is_kdump_kernel()) { + DP_INFO(cdev, + "Kdump kernel: Limit the max number of requested MSI-X vectors to %hd\n", + cdev->int_params.in.min_msix_cnt); + cdev->int_params.in.num_vectors = + cdev->int_params.in.min_msix_cnt; + } + rc = qed_set_int_mode(cdev, false); if (rc) { DP_ERR(cdev, "qed_slowpath_setup_int ERR\n"); -- GitLab From d8c1603d0bb47caafbaeaf76100842e8e0c46de8 Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Sat, 23 Jun 2018 23:22:52 +0200 Subject: [PATCH 0113/1001] qmi_wwan: add support for the Dell Wireless 5821e module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit e7e197edd09c25774b4f12cab19f9d5462f240f4 ] This module exposes two USB configurations: a QMI+AT capable setup on USB config #1 and a MBIM capable setup on USB config #2. By default the kernel will choose the MBIM capable configuration as long as the cdc_mbim driver is available. This patch adds support for the QMI port in the secondary configuration. Signed-off-by: Aleksander Morgado Acked-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index b23ee948e7c9..0db500bf86d9 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1245,6 +1245,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x413c, 0x81b3, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */ {QMI_FIXED_INTF(0x413c, 0x81b6, 8)}, /* Dell Wireless 5811e */ {QMI_FIXED_INTF(0x413c, 0x81b6, 10)}, /* Dell Wireless 5811e */ + {QMI_FIXED_INTF(0x413c, 0x81d7, 1)}, /* Dell Wireless 5821e */ {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */ {QMI_FIXED_INTF(0x03f0, 0x9d1d, 1)}, /* HP lt4120 Snapdragon X5 LTE */ {QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */ -- GitLab From 5e90946baa576df0c28b74cbde16db236f2afd79 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 25 Jun 2018 09:26:27 +0200 Subject: [PATCH 0114/1001] r8152: napi hangup fix after disconnect [ Upstream commit 0ee1f4734967af8321ecebaf9c74221ace34f2d5 ] When unplugging an r8152 adapter while the interface is UP, the NIC becomes unusable. usb->disconnect (aka rtl8152_disconnect) deletes napi. Then, rtl8152_disconnect calls unregister_netdev and that invokes netdev->ndo_stop (aka rtl8152_close). rtl8152_close tries to napi_disable, but the napi is already deleted by disconnect above. So the first while loop in napi_disable never finishes. This results in complete deadlock of the network layer as there is rtnl_mutex held by unregister_netdev. So avoid the call to napi_disable in rtl8152_close when the device is already gone. The other calls to usb_kill_urb, cancel_delayed_work_sync, netif_stop_queue etc. seem to be fine. The urb and netdev is not destroyed yet. Signed-off-by: Jiri Slaby Cc: linux-usb@vger.kernel.org Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/r8152.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index aa88b640cb6c..0fa64cc1a011 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -3959,7 +3959,8 @@ static int rtl8152_close(struct net_device *netdev) #ifdef CONFIG_PM_SLEEP unregister_pm_notifier(&tp->pm_notifier); #endif - napi_disable(&tp->napi); + if (!test_bit(RTL8152_UNPLUG, &tp->flags)) + napi_disable(&tp->napi); clear_bit(WORK_ENABLE, &tp->flags); usb_kill_urb(tp->intr_urb); cancel_delayed_work_sync(&tp->schedule); -- GitLab From 32761addd300814d4d8e76a9db1587b1b74e1cf8 Mon Sep 17 00:00:00 2001 From: Bhadram Varka Date: Sun, 17 Jun 2018 20:02:05 +0530 Subject: [PATCH 0115/1001] stmmac: fix DMA channel hang in half-duplex mode [ Upstream commit b6cfffa7ad923c73f317ea50fd4ebcb3b4b6669c ] HW does not support Half-duplex mode in multi-queue scenario. Fix it by not advertising the Half-Duplex mode if multi-queue enabled. Signed-off-by: Bhadram Varka Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 9866d2e34cdd..27f2e650e27b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -914,6 +914,7 @@ static void stmmac_check_pcs_mode(struct stmmac_priv *priv) static int stmmac_init_phy(struct net_device *dev) { struct stmmac_priv *priv = netdev_priv(dev); + u32 tx_cnt = priv->plat->tx_queues_to_use; struct phy_device *phydev; char phy_id_fmt[MII_BUS_ID_SIZE + 3]; char bus_id[MII_BUS_ID_SIZE]; @@ -954,6 +955,15 @@ static int stmmac_init_phy(struct net_device *dev) phydev->advertising &= ~(SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full); + /* + * Half-duplex mode not supported with multiqueue + * half-duplex can only works with single queue + */ + if (tx_cnt > 1) + phydev->supported &= ~(SUPPORTED_1000baseT_Half | + SUPPORTED_100baseT_Half | + SUPPORTED_10baseT_Half); + /* * Broken HW is sometimes missing the pull-up resistor on the * MDIO line, which results in reads to non-existent devices returning -- GitLab From 4f5f7bce308eebcfc8cf63134d4147ccfa8ccb32 Mon Sep 17 00:00:00 2001 From: Doron Roberts-Kedes Date: Tue, 26 Jun 2018 18:33:33 -0700 Subject: [PATCH 0116/1001] strparser: Remove early eaten to fix full tcp receive buffer stall [ Upstream commit 977c7114ebda2e746a114840d3a875e0cdb826fb ] On receving an incomplete message, the existing code stores the remaining length of the cloned skb in the early_eaten field instead of incrementing the value returned by __strp_recv. This defers invocation of sock_rfree for the current skb until the next invocation of __strp_recv, which returns early_eaten if early_eaten is non-zero. This behavior causes a stall when the current message occupies the very tail end of a massive skb, and strp_peek/need_bytes indicates that the remainder of the current message has yet to arrive on the socket. The TCP receive buffer is totally full, causing the TCP window to go to zero, so the remainder of the message will never arrive. Incrementing the value returned by __strp_recv by the amount otherwise stored in early_eaten prevents stalls of this nature. Signed-off-by: Doron Roberts-Kedes Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/strparser/strparser.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c index c741365f77da..a68c754e84ea 100644 --- a/net/strparser/strparser.c +++ b/net/strparser/strparser.c @@ -35,7 +35,6 @@ struct _strp_msg { */ struct strp_msg strp; int accum_len; - int early_eaten; }; static inline struct _strp_msg *_strp_msg(struct sk_buff *skb) @@ -115,20 +114,6 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, head = strp->skb_head; if (head) { /* Message already in progress */ - - stm = _strp_msg(head); - if (unlikely(stm->early_eaten)) { - /* Already some number of bytes on the receive sock - * data saved in skb_head, just indicate they - * are consumed. - */ - eaten = orig_len <= stm->early_eaten ? - orig_len : stm->early_eaten; - stm->early_eaten -= eaten; - - return eaten; - } - if (unlikely(orig_offset)) { /* Getting data with a non-zero offset when a message is * in progress is not expected. If it does happen, we @@ -297,9 +282,9 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, } stm->accum_len += cand_len; + eaten += cand_len; strp->need_bytes = stm->strp.full_len - stm->accum_len; - stm->early_eaten = cand_len; STRP_STATS_ADD(strp->stats.bytes, cand_len); desc->count = 0; /* Stop reading socket */ break; -- GitLab From 3373d6d056d7b9d1de397498389891b8b95dfd8a Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Wed, 27 Jun 2018 16:04:48 -0700 Subject: [PATCH 0117/1001] tcp: fix Fast Open key endianness [ Upstream commit c860e997e9170a6d68f9d1e6e2cf61f572191aaf ] Fast Open key could be stored in different endian based on the CPU. Previously hosts in different endianness in a server farm using the same key config (sysctl value) would produce different cookies. This patch fixes it by always storing it as little endian to keep same API for LE hosts. Reported-by: Daniele Iamartino Signed-off-by: Yuchung Cheng Signed-off-by: Eric Dumazet Signed-off-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/sysctl_net_ipv4.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 0989e739d098..5a29dc5083a3 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -258,8 +258,9 @@ static int proc_tcp_fastopen_key(struct ctl_table *ctl, int write, { struct ctl_table tbl = { .maxlen = (TCP_FASTOPEN_KEY_LENGTH * 2 + 10) }; struct tcp_fastopen_context *ctxt; - int ret; u32 user_key[4]; /* 16 bytes, matching TCP_FASTOPEN_KEY_LENGTH */ + __le32 key[4]; + int ret, i; tbl.data = kmalloc(tbl.maxlen, GFP_KERNEL); if (!tbl.data) @@ -268,11 +269,14 @@ static int proc_tcp_fastopen_key(struct ctl_table *ctl, int write, rcu_read_lock(); ctxt = rcu_dereference(tcp_fastopen_ctx); if (ctxt) - memcpy(user_key, ctxt->key, TCP_FASTOPEN_KEY_LENGTH); + memcpy(key, ctxt->key, TCP_FASTOPEN_KEY_LENGTH); else - memset(user_key, 0, sizeof(user_key)); + memset(key, 0, sizeof(key)); rcu_read_unlock(); + for (i = 0; i < ARRAY_SIZE(key); i++) + user_key[i] = le32_to_cpu(key[i]); + snprintf(tbl.data, tbl.maxlen, "%08x-%08x-%08x-%08x", user_key[0], user_key[1], user_key[2], user_key[3]); ret = proc_dostring(&tbl, write, buffer, lenp, ppos); @@ -288,12 +292,16 @@ static int proc_tcp_fastopen_key(struct ctl_table *ctl, int write, * first invocation of tcp_fastopen_cookie_gen */ tcp_fastopen_init_key_once(false); - tcp_fastopen_reset_cipher(user_key, TCP_FASTOPEN_KEY_LENGTH); + + for (i = 0; i < ARRAY_SIZE(user_key); i++) + key[i] = cpu_to_le32(user_key[i]); + + tcp_fastopen_reset_cipher(key, TCP_FASTOPEN_KEY_LENGTH); } bad_key: pr_debug("proc FO key set 0x%x-%x-%x-%x <- 0x%s: %u\n", - user_key[0], user_key[1], user_key[2], user_key[3], + user_key[0], user_key[1], user_key[2], user_key[3], (char *)tbl.data, ret); kfree(tbl.data); return ret; -- GitLab From 2dc4696ee6d9471ce110157fb695f75b8fd912e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 29 Jun 2018 13:07:53 +0300 Subject: [PATCH 0118/1001] tcp: prevent bogus FRTO undos with non-SACK flows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 1236f22fbae15df3736ab4a984c64c0c6ee6254c ] If SACK is not enabled and the first cumulative ACK after the RTO retransmission covers more than the retransmitted skb, a spurious FRTO undo will trigger (assuming FRTO is enabled for that RTO). The reason is that any non-retransmitted segment acknowledged will set FLAG_ORIG_SACK_ACKED in tcp_clean_rtx_queue even if there is no indication that it would have been delivered for real (the scoreboard is not kept with TCPCB_SACKED_ACKED bits in the non-SACK case so the check for that bit won't help like it does with SACK). Having FLAG_ORIG_SACK_ACKED set results in the spurious FRTO undo in tcp_process_loss. We need to use more strict condition for non-SACK case and check that none of the cumulatively ACKed segments were retransmitted to prove that progress is due to original transmissions. Only then keep FLAG_ORIG_SACK_ACKED set, allowing FRTO undo to proceed in non-SACK case. (FLAG_ORIG_SACK_ACKED is planned to be renamed to FLAG_ORIG_PROGRESS to better indicate its purpose but to keep this change minimal, it will be done in another patch). Besides burstiness and congestion control violations, this problem can result in RTO loop: When the loss recovery is prematurely undoed, only new data will be transmitted (if available) and the next retransmission can occur only after a new RTO which in case of multiple losses (that are not for consecutive packets) requires one RTO per loss to recover. Signed-off-by: Ilpo Järvinen Tested-by: Neal Cardwell Acked-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index f0caff3139ed..5711b1b12d28 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3194,6 +3194,15 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets, if (tcp_is_reno(tp)) { tcp_remove_reno_sacks(sk, pkts_acked); + + /* If any of the cumulatively ACKed segments was + * retransmitted, non-SACK case cannot confirm that + * progress was due to original transmission due to + * lack of TCPCB_SACKED_ACKED bits even if some of + * the packets may have been never retransmitted. + */ + if (flag & FLAG_RETRANS_DATA_ACKED) + flag &= ~FLAG_ORIG_SACK_ACKED; } else { int delta; -- GitLab From 7eba6537c3d17ca582d4b3ab38af4463020563d9 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 21 Jun 2018 13:11:31 +0800 Subject: [PATCH 0119/1001] vhost_net: validate sock before trying to put its fd [ Upstream commit b8f1f65882f07913157c44673af7ec0b308d03eb ] Sock will be NULL if we pass -1 to vhost_net_set_backend(), but when we meet errors during ubuf allocation, the code does not check for NULL before calling sockfd_put(), this will lead NULL dereferencing. Fixing by checking sock pointer before. Fixes: bab632d69ee4 ("vhost: vhost TX zero-copy support") Reported-by: Dan Carpenter Signed-off-by: Jason Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/vhost/net.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index b0d606b2d06c..6123b4dd8638 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -1186,7 +1186,8 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) if (ubufs) vhost_net_ubuf_put_wait_and_free(ubufs); err_ubufs: - sockfd_put(sock); + if (sock) + sockfd_put(sock); err_vq: mutex_unlock(&vq->mutex); err: -- GitLab From d8530e891edde17506727af174d66d3f0b4e6b34 Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Wed, 20 Jun 2018 15:51:51 +0200 Subject: [PATCH 0120/1001] VSOCK: fix loopback on big-endian systems [ Upstream commit e5ab564c9ebee77794842ca7d7476147b83d6a27 ] The dst_cid and src_cid are 64 bits, therefore 64 bit accessors should be used, and in fact in virtio_transport_common.c only 64 bit accessors are used. Using 32 bit accessors for 64 bit values breaks big endian systems. This patch fixes a wrong use of le32_to_cpu in virtio_transport_send_pkt. Fixes: b9116823189e85ccf384 ("VSOCK: add loopback to virtio_transport") Signed-off-by: Claudio Imbrenda Reviewed-by: Stefan Hajnoczi Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/vmw_vsock/virtio_transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c index 403d86e80162..fdb294441682 100644 --- a/net/vmw_vsock/virtio_transport.c +++ b/net/vmw_vsock/virtio_transport.c @@ -201,7 +201,7 @@ virtio_transport_send_pkt(struct virtio_vsock_pkt *pkt) return -ENODEV; } - if (le32_to_cpu(pkt->hdr.dst_cid) == vsock->guest_cid) + if (le64_to_cpu(pkt->hdr.dst_cid) == vsock->guest_cid) return virtio_transport_send_pkt_loopback(vsock, pkt); if (pkt->reply) -- GitLab From 3caea5150c15c4258a8d9ee0c5758d53d4753009 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 16 Jul 2018 20:59:58 -0500 Subject: [PATCH 0121/1001] net: cxgb3_main: fix potential Spectre v1 commit 676bcfece19f83621e905aa55b5ed2d45cc4f2d3 upstream. t.qset_idx can be indirectly controlled by user-space, hence leading to a potential exploitation of the Spectre variant 1 vulnerability. This issue was detected with the help of Smatch: drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c:2286 cxgb_extension_ioctl() warn: potential spectre issue 'adapter->msix_info' Fix this by sanitizing t.qset_idx before using it to index adapter->msix_info Notice that given that speculation windows are large, the policy is to kill the speculation on the first load and not worry if it can be completed with a dependent load/store [1]. [1] https://marc.info/?l=linux-kernel&m=152449131114778&w=2 Cc: stable@vger.kernel.org Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c index 6a015362c340..bf291e90cdb0 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c @@ -51,6 +51,7 @@ #include #include #include +#include #include "common.h" #include "cxgb3_ioctl.h" @@ -2268,6 +2269,7 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) if (t.qset_idx >= nqsets) return -EINVAL; + t.qset_idx = array_index_nospec(t.qset_idx, nqsets); q = &adapter->params.sge.qset[q1 + t.qset_idx]; t.rspq_size = q->rspq_size; -- GitLab From ee8d2e719c1e5ade96524d4480cffc17f8c756a8 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 22 Jun 2018 13:31:57 +0800 Subject: [PATCH 0122/1001] rtlwifi: Fix kernel Oops "Fw download fail!!" commit 12dfa2f68ab659636e092db13b5d17cf9aac82af upstream. When connecting to AP, mac80211 asks driver to enter and leave PS quickly, but driver deinit doesn't wait for delayed work complete when entering PS, then driver reinit procedure and delay work are running simultaneously. This will cause unpredictable kernel oops or crash like rtl8723be: error H2C cmd because of Fw download fail!!! WARNING: CPU: 3 PID: 159 at drivers/net/wireless/realtek/rtlwifi/ rtl8723be/fw.c:227 rtl8723be_fill_h2c_cmd+0x182/0x510 [rtl8723be] CPU: 3 PID: 159 Comm: kworker/3:2 Tainted: G O 4.16.13-2-ARCH #1 Hardware name: ASUSTeK COMPUTER INC. X556UF/X556UF, BIOS X556UF.406 10/21/2016 Workqueue: rtl8723be_pci rtl_c2hcmd_wq_callback [rtlwifi] RIP: 0010:rtl8723be_fill_h2c_cmd+0x182/0x510 [rtl8723be] RSP: 0018:ffffa6ab01e1bd70 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffffa26069071520 RCX: 0000000000000001 RDX: 0000000080000001 RSI: ffffffff8be70e9c RDI: 00000000ffffffff RBP: 0000000000000000 R08: 0000000000000048 R09: 0000000000000348 R10: 0000000000000000 R11: 0000000000000001 R12: 0000000000000000 R13: ffffa26069071520 R14: 0000000000000000 R15: ffffa2607d205f70 FS: 0000000000000000(0000) GS:ffffa26081d80000(0000) knlGS:000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000443b39d3000 CR3: 000000037700a005 CR4: 00000000003606e0 Call Trace: ? halbtc_send_bt_mp_operation.constprop.17+0xd5/0xe0 [btcoexist] ? ex_btc8723b1ant_bt_info_notify+0x3b8/0x820 [btcoexist] ? rtl_c2hcmd_launcher+0xab/0x110 [rtlwifi] ? process_one_work+0x1d1/0x3b0 ? worker_thread+0x2b/0x3d0 ? process_one_work+0x3b0/0x3b0 ? kthread+0x112/0x130 ? kthread_create_on_node+0x60/0x60 ? ret_from_fork+0x35/0x40 Code: 00 76 b4 e9 e2 fe ff ff 4c 89 ee 4c 89 e7 e8 56 22 86 ca e9 5e ... This patch ensures all delayed works done before entering PS to satisfy our expectation, so use cancel_delayed_work_sync() instead. An exception is delayed work ips_nic_off_wq because running task may be itself, so add a parameter ips_wq to deinit function to handle this case. This issue is reported and fixed in below threads: https://github.com/lwfinger/rtlwifi_new/issues/367 https://github.com/lwfinger/rtlwifi_new/issues/366 Tested-by: Evgeny Kapun # 8723DE Tested-by: Shivam Kakkar # 8723BE on 4.18-rc1 Signed-off-by: Ping-Ke Shih Fixes: cceb0a597320 ("rtlwifi: Add work queue for c2h cmd.") Cc: Stable # 4.11+ Reviewed-by: Larry Finger Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/realtek/rtlwifi/base.c | 17 ++++++++++------- drivers/net/wireless/realtek/rtlwifi/base.h | 2 +- drivers/net/wireless/realtek/rtlwifi/core.c | 2 +- drivers/net/wireless/realtek/rtlwifi/pci.c | 2 +- drivers/net/wireless/realtek/rtlwifi/ps.c | 4 ++-- drivers/net/wireless/realtek/rtlwifi/usb.c | 2 +- 6 files changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index 93256f8bc0b5..ec82c1c3f12e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -483,18 +483,21 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw) } -void rtl_deinit_deferred_work(struct ieee80211_hw *hw) +void rtl_deinit_deferred_work(struct ieee80211_hw *hw, bool ips_wq) { struct rtl_priv *rtlpriv = rtl_priv(hw); del_timer_sync(&rtlpriv->works.watchdog_timer); - cancel_delayed_work(&rtlpriv->works.watchdog_wq); - cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq); - cancel_delayed_work(&rtlpriv->works.ps_work); - cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); - cancel_delayed_work(&rtlpriv->works.fwevt_wq); - cancel_delayed_work(&rtlpriv->works.c2hcmd_wq); + cancel_delayed_work_sync(&rtlpriv->works.watchdog_wq); + if (ips_wq) + cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq); + else + cancel_delayed_work_sync(&rtlpriv->works.ips_nic_off_wq); + cancel_delayed_work_sync(&rtlpriv->works.ps_work); + cancel_delayed_work_sync(&rtlpriv->works.ps_rfon_wq); + cancel_delayed_work_sync(&rtlpriv->works.fwevt_wq); + cancel_delayed_work_sync(&rtlpriv->works.c2hcmd_wq); } EXPORT_SYMBOL_GPL(rtl_deinit_deferred_work); diff --git a/drivers/net/wireless/realtek/rtlwifi/base.h b/drivers/net/wireless/realtek/rtlwifi/base.h index b56d1b7f5567..cbbb5be36a09 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.h +++ b/drivers/net/wireless/realtek/rtlwifi/base.h @@ -121,7 +121,7 @@ void rtl_init_rfkill(struct ieee80211_hw *hw); void rtl_deinit_rfkill(struct ieee80211_hw *hw); void rtl_watch_dog_timer_callback(unsigned long data); -void rtl_deinit_deferred_work(struct ieee80211_hw *hw); +void rtl_deinit_deferred_work(struct ieee80211_hw *hw, bool ips_wq); bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); int rtlwifi_rate_mapping(struct ieee80211_hw *hw, bool isht, diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index c53cbf3d52bd..93f1779ea23e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -196,7 +196,7 @@ static void rtl_op_stop(struct ieee80211_hw *hw) /* reset sec info */ rtl_cam_reset_sec_info(hw); - rtl_deinit_deferred_work(hw); + rtl_deinit_deferred_work(hw, false); } rtlpriv->intf_ops->adapter_stop(hw); diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index d7331225c5f3..457a0f725c8a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -2359,7 +2359,7 @@ void rtl_pci_disconnect(struct pci_dev *pdev) ieee80211_unregister_hw(hw); rtlmac->mac80211_registered = 0; } else { - rtl_deinit_deferred_work(hw); + rtl_deinit_deferred_work(hw, false); rtlpriv->intf_ops->adapter_stop(hw); } rtlpriv->cfg->ops->disable_interrupt(hw); diff --git a/drivers/net/wireless/realtek/rtlwifi/ps.c b/drivers/net/wireless/realtek/rtlwifi/ps.c index 07ee3096f50e..f6d00613c53d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/ps.c +++ b/drivers/net/wireless/realtek/rtlwifi/ps.c @@ -66,7 +66,7 @@ bool rtl_ps_disable_nic(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); /*<1> Stop all timer */ - rtl_deinit_deferred_work(hw); + rtl_deinit_deferred_work(hw, true); /*<2> Disable Interrupt */ rtlpriv->cfg->ops->disable_interrupt(hw); @@ -287,7 +287,7 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw) struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); enum rf_pwrstate rtstate; - cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq); + cancel_delayed_work_sync(&rtlpriv->works.ips_nic_off_wq); spin_lock(&rtlpriv->locks.ips_lock); if (ppsc->inactiveps) { diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index 5590d07d0918..820c42ff5384 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -1150,7 +1150,7 @@ void rtl_usb_disconnect(struct usb_interface *intf) ieee80211_unregister_hw(hw); rtlmac->mac80211_registered = 0; } else { - rtl_deinit_deferred_work(hw); + rtl_deinit_deferred_work(hw, false); rtlpriv->intf_ops->adapter_stop(hw); } /*deinit rfkill */ -- GitLab From 12c0949a07458103b539eaba2330763873ef4cb5 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 28 Jun 2018 10:02:27 +0800 Subject: [PATCH 0123/1001] rtlwifi: rtl8821ae: fix firmware is not ready to run commit 9a98302de19991d51e067b88750585203b2a3ab6 upstream. Without this patch, firmware will not run properly on rtl8821ae, and it causes bad user experience. For example, bad connection performance with low rate, higher power consumption, and so on. rtl8821ae uses two kinds of firmwares for normal and WoWlan cases, and each firmware has firmware data buffer and size individually. Original code always overwrite size of normal firmware rtlpriv->rtlhal.fwsize, and this mismatch causes firmware checksum error, then firmware can't start. In this situation, driver gives message "Firmware is not ready to run!". Fixes: fe89707f0afa ("rtlwifi: rtl8821ae: Simplify loading of WOWLAN firmware") Signed-off-by: Ping-Ke Shih Cc: Stable # 4.0+ Reviewed-by: Larry Finger Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/realtek/rtlwifi/core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 93f1779ea23e..b01123138797 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -130,7 +130,6 @@ static void rtl_fw_do_work(const struct firmware *firmware, void *context, firmware->size); rtlpriv->rtlhal.wowlan_fwsize = firmware->size; } - rtlpriv->rtlhal.fwsize = firmware->size; release_firmware(firmware); } -- GitLab From 2be27d444f61c5542df5c00892817124582428a4 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 15 Jul 2018 21:53:20 +0200 Subject: [PATCH 0124/1001] net: lan78xx: Fix race in tx pending skb size calculation commit dea39aca1d7aef1e2b95b07edeacf04cc8863a2e upstream. The skb size calculation in lan78xx_tx_bh is in race with the start_xmit, which could lead to rare kernel oopses. So protect the whole skb walk with a spin lock. As a benefit we can unlink the skb directly. This patch was tested on Raspberry Pi 3B+ Link: https://github.com/raspberrypi/linux/issues/2608 Fixes: 55d7de9de6c3 ("Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet") Cc: stable Signed-off-by: Floris Bos Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/lan78xx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 9881edc568ba..0aa91ab9a0fb 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -3197,6 +3197,7 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev) pkt_cnt = 0; count = 0; length = 0; + spin_lock_irqsave(&tqp->lock, flags); for (skb = tqp->next; pkt_cnt < tqp->qlen; skb = skb->next) { if (skb_is_gso(skb)) { if (pkt_cnt) { @@ -3205,7 +3206,8 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev) } count = 1; length = skb->len - TX_OVERHEAD; - skb2 = skb_dequeue(tqp); + __skb_unlink(skb, tqp); + spin_unlock_irqrestore(&tqp->lock, flags); goto gso_skb; } @@ -3214,6 +3216,7 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev) skb_totallen = skb->len + roundup(skb_totallen, sizeof(u32)); pkt_cnt++; } + spin_unlock_irqrestore(&tqp->lock, flags); /* copy to a single skb */ skb = alloc_skb(skb_totallen, GFP_ATOMIC); -- GitLab From 67f7c68a9085957a291e91ee5a177f2b208aeda6 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Mon, 14 May 2018 11:57:23 +0300 Subject: [PATCH 0125/1001] xhci: Fix USB3 NULL pointer dereference at logical disconnect. commit 2278446e2b7cd33ad894b32e7eb63afc7db6c86e upstream. Hub driver will try to disable a USB3 device twice at logical disconnect, racing with xhci_free_dev() callback from the first port disable. This can be triggered with "udisksctl power-off --block-device " or by writing "1" to the "remove" sysfs file for a USB3 device in 4.17-rc4. USB3 devices don't have a similar disabled link state as USB2 devices, and use a U3 suspended link state instead. In this state the port is still enabled and connected. hub_port_connect() first disconnects the device, then later it notices that device is still enabled (due to U3 states) it will try to disable the port again (set to U3). The xhci_free_dev() called during device disable is async, so checking for existing xhci->devs[i] when setting link state to U3 the second time was successful, even if device was being freed. The regression was caused by, and whole thing revealed by, Commit 44a182b9d177 ("xhci: Fix use-after-free in xhci_free_virt_device") which sets xhci->devs[i]->udev to NULL before xhci_virt_dev() returned. and causes a NULL pointer dereference the second time we try to set U3. Fix this by checking xhci->devs[i]->udev exists before setting link state. The original patch went to stable so this fix needs to be applied there as well. Fixes: 44a182b9d177 ("xhci: Fix use-after-free in xhci_free_virt_device") Cc: Reported-by: Jordan Glover Tested-by: Jordan Glover Signed-off-by: Mathias Nyman Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 00b8d4cdcac3..c01d1f3a1c7d 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -366,7 +366,7 @@ int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci, slot_id = 0; for (i = 0; i < MAX_HC_SLOTS; i++) { - if (!xhci->devs[i]) + if (!xhci->devs[i] || !xhci->devs[i]->udev) continue; speed = xhci->devs[i]->udev->speed; if (((speed >= USB_SPEED_SUPER) == (hcd->speed >= HCD_USB3)) -- GitLab From a406abeb7416501355668222164919836da67034 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 6 Mar 2018 08:57:57 -0500 Subject: [PATCH 0126/1001] media: rc: oops in ir_timer_keyup after device unplug commit 8d4068810d9926250dd2435719a080b889eb44c3 upstream. If there is IR in the raw kfifo when ir_raw_event_unregister() is called, then kthread_stop() causes ir_raw_event_thread to be scheduled, decode some scancodes and re-arm timer_keyup. The timer_keyup then fires when the rc device is long gone. Cc: stable@vger.kernel.org Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/media/rc/rc-main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 72f381522cb2..a22828713c1c 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1824,11 +1824,11 @@ void rc_unregister_device(struct rc_dev *dev) if (!dev) return; - del_timer_sync(&dev->timer_keyup); - if (dev->driver_type == RC_DRIVER_IR_RAW) ir_raw_event_unregister(dev); + del_timer_sync(&dev->timer_keyup); + rc_free_rx_device(dev); device_del(&dev->dev); -- GitLab From 16b3ae12337eb1695de0031fe4e030fb7fd6c2d9 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 30 Apr 2018 12:00:11 +0200 Subject: [PATCH 0127/1001] clocksource: Initialize cs->wd_list commit 5b9e886a4af97574ca3ce1147f35545da0e7afc7 upstream. A number of places relies on list_empty(&cs->wd_list), however the list_head does not get initialized. Do so upon registration, such that thereafter it is possible to rely on list_empty() correctly reflecting the list membership status. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner Tested-by: Diego Viola Reviewed-by: Rafael J. Wysocki Cc: stable@vger.kernel.org Cc: len.brown@intel.com Cc: rjw@rjwysocki.net Cc: rui.zhang@intel.com Link: https://lkml.kernel.org/r/20180430100344.472662715@infradead.org Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- kernel/time/clocksource.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 03918a19cf2d..3b71d859ee38 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -322,6 +322,8 @@ static void clocksource_enqueue_watchdog(struct clocksource *cs) { unsigned long flags; + INIT_LIST_HEAD(&cs->wd_list); + spin_lock_irqsave(&watchdog_lock, flags); if (cs->flags & CLOCK_SOURCE_MUST_VERIFY) { /* cs is a clocksource to be watched. */ -- GitLab From c4bfed85bae8eba6cce22f9b9cce530720527411 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sat, 7 Jul 2018 20:41:47 +0200 Subject: [PATCH 0128/1001] crypto: af_alg - Initialize sg_num_bytes in error code path commit 2546da99212f22034aecf279da9c47cbfac6c981 upstream. The RX SGL in processing is already registered with the RX SGL tracking list to support proper cleanup. The cleanup code path uses the sg_num_bytes variable which must therefore be always initialized, even in the error code path. Signed-off-by: Stephan Mueller Reported-by: syzbot+9c251bdd09f83b92ba95@syzkaller.appspotmail.com #syz test: https://github.com/google/kmsan.git master CC: #4.14 Fixes: e870456d8e7c ("crypto: algif_skcipher - overhaul memory management") Fixes: d887c52d6ae4 ("crypto: algif_aead - overhaul memory management") Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/af_alg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 815ee1075574..42dfdd1fd6d8 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -1183,8 +1183,10 @@ int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags, /* make one iovec available as scatterlist */ err = af_alg_make_sg(&rsgl->sgl, &msg->msg_iter, seglen); - if (err < 0) + if (err < 0) { + rsgl->sg_num_bytes = 0; return err; + } /* chain the new scatterlist with previous one */ if (areq->last_rsgl) -- GitLab From f1059632a4fcb0a73b1c315082cdb623a3b3ef52 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 23 Jun 2018 01:06:34 +0900 Subject: [PATCH 0129/1001] mtd: rawnand: denali_dt: set clk_x_rate to 200 MHz unconditionally commit 3f6e6986045d47f87bd982910821b7ab9758487e upstream. Since commit 1bb88666775e ("mtd: nand: denali: handle timing parameters by setup_data_interface()"), denali_dt.c gets the clock rate from the clock driver. The driver expects the frequency of the bus interface clock, whereas the clock driver of SOCFPGA provides the core clock. Thus, the setup_data_interface() hook calculates timing parameters based on a wrong frequency. To make it work without relying on the clock driver, hard-code the clock frequency, 200MHz. This is fine for existing DT of UniPhier, and also fixes the issue of SOCFPGA because both platforms use 200 MHz for the bus interface clock. Fixes: 1bb88666775e ("mtd: nand: denali: handle timing parameters by setup_data_interface()") Cc: linux-stable #4.14+ Reported-by: Philipp Rosenberger Suggested-by: Boris Brezillon Signed-off-by: Masahiro Yamada Tested-by: Richard Weinberger Signed-off-by: Boris Brezillon Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/denali_dt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index 56e2e177644d..3f4f4aea0e8b 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -122,7 +122,11 @@ static int denali_dt_probe(struct platform_device *pdev) if (ret) return ret; - denali->clk_x_rate = clk_get_rate(dt->clk); + /* + * Hardcode the clock rate for the backward compatibility. + * This works for both SOCFPGA and UniPhier. + */ + denali->clk_x_rate = 200000000; ret = denali_init(denali); if (ret) -- GitLab From aa6be396714c79c44d5fa6b4ae09c8090fef8727 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Thu, 12 Apr 2018 19:11:58 +0100 Subject: [PATCH 0130/1001] block: do not use interruptible wait anywhere commit 1dc3039bc87ae7d19a990c3ee71cfd8a9068f428 upstream. When blk_queue_enter() waits for a queue to unfreeze, or unset the PREEMPT_ONLY flag, do not allow it to be interrupted by a signal. The PREEMPT_ONLY flag was introduced later in commit 3a0a529971ec ("block, scsi: Make SCSI quiesce and resume work reliably"). Note the SCSI device is resumed asynchronously, i.e. after un-freezing userspace tasks. So that commit exposed the bug as a regression in v4.15. A mysterious SIGBUS (or -EIO) sometimes happened during the time the device was being resumed. Most frequently, there was no kernel log message, and we saw Xorg or Xwayland killed by SIGBUS.[1] [1] E.g. https://bugzilla.redhat.com/show_bug.cgi?id=1553979 Without this fix, I get an IO error in this test: # dd if=/dev/sda of=/dev/null iflag=direct & \ while killall -SIGUSR1 dd; do sleep 0.1; done & \ echo mem > /sys/power/state ; \ sleep 5; killall dd # stop after 5 seconds The interruptible wait was added to blk_queue_enter in commit 3ef28e83ab15 ("block: generic request_queue reference counting"). Before then, the interruptible wait was only in blk-mq, but I don't think it could ever have been correct. Reviewed-by: Bart Van Assche Cc: stable@vger.kernel.org Signed-off-by: Alan Jenkins Signed-off-by: Jens Axboe Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- block/blk-core.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index 6f6e21821d2d..68bae6338ad4 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -779,7 +779,6 @@ EXPORT_SYMBOL(blk_alloc_queue); int blk_queue_enter(struct request_queue *q, bool nowait) { while (true) { - int ret; if (percpu_ref_tryget_live(&q->q_usage_counter)) return 0; @@ -796,13 +795,11 @@ int blk_queue_enter(struct request_queue *q, bool nowait) */ smp_rmb(); - ret = wait_event_interruptible(q->mq_freeze_wq, - !atomic_read(&q->mq_freeze_depth) || - blk_queue_dying(q)); + wait_event(q->mq_freeze_wq, + !atomic_read(&q->mq_freeze_depth) || + blk_queue_dying(q)); if (blk_queue_dying(q)) return -ENODEV; - if (ret) - return ret; } } -- GitLab From b5199c61e95c58fdfd9478bcbf368f1575d61da1 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 9 Jul 2018 13:16:07 -0500 Subject: [PATCH 0131/1001] PCI: hv: Disable/enable IRQs rather than BH in hv_compose_msi_msg() commit 35a88a18d7ea58600e11590405bc93b08e16e7f5 upstream. Commit de0aa7b2f97d ("PCI: hv: Fix 2 hang issues in hv_compose_msi_msg()") uses local_bh_disable()/enable(), because hv_pci_onchannelcallback() can also run in tasklet context as the channel event callback, so bottom halves should be disabled to prevent a race condition. With CONFIG_PROVE_LOCKING=y in the recent mainline, or old kernels that don't have commit f71b74bca637 ("irq/softirqs: Use lockdep to assert IRQs are disabled/enabled"), when the upper layer IRQ code calls hv_compose_msi_msg() with local IRQs disabled, we'll see a warning at the beginning of __local_bh_enable_ip(): IRQs not enabled as expected WARNING: CPU: 0 PID: 408 at kernel/softirq.c:162 __local_bh_enable_ip The warning exposes an issue in de0aa7b2f97d: local_bh_enable() can potentially call do_softirq(), which is not supposed to run when local IRQs are disabled. Let's fix this by using local_irq_save()/restore() instead. Note: hv_pci_onchannelcallback() is not a hot path because it's only called when the PCI device is hot added and removed, which is infrequent. Fixes: de0aa7b2f97d ("PCI: hv: Fix 2 hang issues in hv_compose_msi_msg()") Signed-off-by: Dexuan Cui Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Haiyang Zhang Cc: stable@vger.kernel.org Cc: Stephen Hemminger Cc: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/pci/host/pci-hyperv.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c index caea7c618207..4523d7e1bcb9 100644 --- a/drivers/pci/host/pci-hyperv.c +++ b/drivers/pci/host/pci-hyperv.c @@ -1091,6 +1091,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) struct pci_bus *pbus; struct pci_dev *pdev; struct cpumask *dest; + unsigned long flags; struct compose_comp_ctxt comp; struct tran_int_desc *int_desc; struct { @@ -1182,14 +1183,15 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) * the channel callback directly when channel->target_cpu is * the current CPU. When the higher level interrupt code * calls us with interrupt enabled, let's add the - * local_bh_disable()/enable() to avoid race. + * local_irq_save()/restore() to avoid race: + * hv_pci_onchannelcallback() can also run in tasklet. */ - local_bh_disable(); + local_irq_save(flags); if (hbus->hdev->channel->target_cpu == smp_processor_id()) hv_pci_onchannelcallback(hbus); - local_bh_enable(); + local_irq_restore(flags); if (hpdev->state == hv_pcichild_ejecting) { dev_err_once(&hbus->hdev->device, -- GitLab From 766a7ad6639b4b2026d19cb217ada2ed8a2cfe57 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 6 Jun 2018 12:14:56 +0200 Subject: [PATCH 0132/1001] netfilter: ebtables: reject non-bridge targets commit 11ff7288beb2b7da889a014aff0a7b80bf8efcf3 upstream. the ebtables evaluation loop expects targets to return positive values (jumps), or negative values (absolute verdicts). This is completely different from what xtables does. In xtables, targets are expected to return the standard netfilter verdicts, i.e. NF_DROP, NF_ACCEPT, etc. ebtables will consider these as jumps. Therefore reject any target found due to unspec fallback. v2: also reject watchers. ebtables ignores their return value, so a target that assumes skb ownership (and returns NF_STOLEN) causes use-after-free. The only watchers in the 'ebtables' front-end are log and nflog; both have AF_BRIDGE specific wrappers on kernel side. Reported-by: syzbot+2b43f681169a2a0d306a@syzkaller.appspotmail.com Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/bridge/netfilter/ebtables.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 25738b20676d..54c7fe68040f 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -398,6 +398,12 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par, watcher = xt_request_find_target(NFPROTO_BRIDGE, w->u.name, 0); if (IS_ERR(watcher)) return PTR_ERR(watcher); + + if (watcher->family != NFPROTO_BRIDGE) { + module_put(watcher->me); + return -ENOENT; + } + w->u.watcher = watcher; par->target = watcher; @@ -719,6 +725,13 @@ ebt_check_entry(struct ebt_entry *e, struct net *net, goto cleanup_watchers; } + /* Reject UNSPEC, xtables verdicts/return values are incompatible */ + if (target->family != NFPROTO_BRIDGE) { + module_put(target->me); + ret = -ENOENT; + goto cleanup_watchers; + } + t->u.target = target; if (t->u.target == &ebt_standard_target) { if (gap < sizeof(struct ebt_standard_target)) { -- GitLab From cba5008502f2238b716334d7cb6d847560ce01b4 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 13 Jul 2018 16:59:27 -0700 Subject: [PATCH 0133/1001] reiserfs: fix buffer overflow with long warning messages commit fe10e398e860955bac4d28ec031b701d358465e4 upstream. ReiserFS prepares log messages into a 1024-byte buffer with no bounds checks. Long messages, such as the "unknown mount option" warning when userspace passes a crafted mount options string, overflow this buffer. This causes KASAN to report a global-out-of-bounds write. Fix it by truncating messages to the buffer size. Link: http://lkml.kernel.org/r/20180707203621.30922-1-ebiggers3@gmail.com Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: syzbot+b890b3335a4d8c608963@syzkaller.appspotmail.com Signed-off-by: Eric Biggers Reviewed-by: Andrew Morton Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/reiserfs/prints.c | 141 +++++++++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 60 deletions(-) diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c index 64f49cafbc5b..cfb0c9ac2de4 100644 --- a/fs/reiserfs/prints.c +++ b/fs/reiserfs/prints.c @@ -76,83 +76,99 @@ static char *le_type(struct reiserfs_key *key) } /* %k */ -static void sprintf_le_key(char *buf, struct reiserfs_key *key) +static int scnprintf_le_key(char *buf, size_t size, struct reiserfs_key *key) { if (key) - sprintf(buf, "[%d %d %s %s]", le32_to_cpu(key->k_dir_id), - le32_to_cpu(key->k_objectid), le_offset(key), - le_type(key)); + return scnprintf(buf, size, "[%d %d %s %s]", + le32_to_cpu(key->k_dir_id), + le32_to_cpu(key->k_objectid), le_offset(key), + le_type(key)); else - sprintf(buf, "[NULL]"); + return scnprintf(buf, size, "[NULL]"); } /* %K */ -static void sprintf_cpu_key(char *buf, struct cpu_key *key) +static int scnprintf_cpu_key(char *buf, size_t size, struct cpu_key *key) { if (key) - sprintf(buf, "[%d %d %s %s]", key->on_disk_key.k_dir_id, - key->on_disk_key.k_objectid, reiserfs_cpu_offset(key), - cpu_type(key)); + return scnprintf(buf, size, "[%d %d %s %s]", + key->on_disk_key.k_dir_id, + key->on_disk_key.k_objectid, + reiserfs_cpu_offset(key), cpu_type(key)); else - sprintf(buf, "[NULL]"); + return scnprintf(buf, size, "[NULL]"); } -static void sprintf_de_head(char *buf, struct reiserfs_de_head *deh) +static int scnprintf_de_head(char *buf, size_t size, + struct reiserfs_de_head *deh) { if (deh) - sprintf(buf, - "[offset=%d dir_id=%d objectid=%d location=%d state=%04x]", - deh_offset(deh), deh_dir_id(deh), deh_objectid(deh), - deh_location(deh), deh_state(deh)); + return scnprintf(buf, size, + "[offset=%d dir_id=%d objectid=%d location=%d state=%04x]", + deh_offset(deh), deh_dir_id(deh), + deh_objectid(deh), deh_location(deh), + deh_state(deh)); else - sprintf(buf, "[NULL]"); + return scnprintf(buf, size, "[NULL]"); } -static void sprintf_item_head(char *buf, struct item_head *ih) +static int scnprintf_item_head(char *buf, size_t size, struct item_head *ih) { if (ih) { - strcpy(buf, - (ih_version(ih) == KEY_FORMAT_3_6) ? "*3.6* " : "*3.5*"); - sprintf_le_key(buf + strlen(buf), &(ih->ih_key)); - sprintf(buf + strlen(buf), ", item_len %d, item_location %d, " - "free_space(entry_count) %d", - ih_item_len(ih), ih_location(ih), ih_free_space(ih)); + char *p = buf; + char * const end = buf + size; + + p += scnprintf(p, end - p, "%s", + (ih_version(ih) == KEY_FORMAT_3_6) ? + "*3.6* " : "*3.5*"); + + p += scnprintf_le_key(p, end - p, &ih->ih_key); + + p += scnprintf(p, end - p, + ", item_len %d, item_location %d, free_space(entry_count) %d", + ih_item_len(ih), ih_location(ih), + ih_free_space(ih)); + return p - buf; } else - sprintf(buf, "[NULL]"); + return scnprintf(buf, size, "[NULL]"); } -static void sprintf_direntry(char *buf, struct reiserfs_dir_entry *de) +static int scnprintf_direntry(char *buf, size_t size, + struct reiserfs_dir_entry *de) { char name[20]; memcpy(name, de->de_name, de->de_namelen > 19 ? 19 : de->de_namelen); name[de->de_namelen > 19 ? 19 : de->de_namelen] = 0; - sprintf(buf, "\"%s\"==>[%d %d]", name, de->de_dir_id, de->de_objectid); + return scnprintf(buf, size, "\"%s\"==>[%d %d]", + name, de->de_dir_id, de->de_objectid); } -static void sprintf_block_head(char *buf, struct buffer_head *bh) +static int scnprintf_block_head(char *buf, size_t size, struct buffer_head *bh) { - sprintf(buf, "level=%d, nr_items=%d, free_space=%d rdkey ", - B_LEVEL(bh), B_NR_ITEMS(bh), B_FREE_SPACE(bh)); + return scnprintf(buf, size, + "level=%d, nr_items=%d, free_space=%d rdkey ", + B_LEVEL(bh), B_NR_ITEMS(bh), B_FREE_SPACE(bh)); } -static void sprintf_buffer_head(char *buf, struct buffer_head *bh) +static int scnprintf_buffer_head(char *buf, size_t size, struct buffer_head *bh) { - sprintf(buf, - "dev %pg, size %zd, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)", - bh->b_bdev, bh->b_size, - (unsigned long long)bh->b_blocknr, atomic_read(&(bh->b_count)), - bh->b_state, bh->b_page, - buffer_uptodate(bh) ? "UPTODATE" : "!UPTODATE", - buffer_dirty(bh) ? "DIRTY" : "CLEAN", - buffer_locked(bh) ? "LOCKED" : "UNLOCKED"); + return scnprintf(buf, size, + "dev %pg, size %zd, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)", + bh->b_bdev, bh->b_size, + (unsigned long long)bh->b_blocknr, + atomic_read(&(bh->b_count)), + bh->b_state, bh->b_page, + buffer_uptodate(bh) ? "UPTODATE" : "!UPTODATE", + buffer_dirty(bh) ? "DIRTY" : "CLEAN", + buffer_locked(bh) ? "LOCKED" : "UNLOCKED"); } -static void sprintf_disk_child(char *buf, struct disk_child *dc) +static int scnprintf_disk_child(char *buf, size_t size, struct disk_child *dc) { - sprintf(buf, "[dc_number=%d, dc_size=%u]", dc_block_number(dc), - dc_size(dc)); + return scnprintf(buf, size, "[dc_number=%d, dc_size=%u]", + dc_block_number(dc), dc_size(dc)); } static char *is_there_reiserfs_struct(char *fmt, int *what) @@ -189,55 +205,60 @@ static void prepare_error_buf(const char *fmt, va_list args) char *fmt1 = fmt_buf; char *k; char *p = error_buf; + char * const end = &error_buf[sizeof(error_buf)]; int what; spin_lock(&error_lock); - strcpy(fmt1, fmt); + if (WARN_ON(strscpy(fmt_buf, fmt, sizeof(fmt_buf)) < 0)) { + strscpy(error_buf, "format string too long", end - error_buf); + goto out_unlock; + } while ((k = is_there_reiserfs_struct(fmt1, &what)) != NULL) { *k = 0; - p += vsprintf(p, fmt1, args); + p += vscnprintf(p, end - p, fmt1, args); switch (what) { case 'k': - sprintf_le_key(p, va_arg(args, struct reiserfs_key *)); + p += scnprintf_le_key(p, end - p, + va_arg(args, struct reiserfs_key *)); break; case 'K': - sprintf_cpu_key(p, va_arg(args, struct cpu_key *)); + p += scnprintf_cpu_key(p, end - p, + va_arg(args, struct cpu_key *)); break; case 'h': - sprintf_item_head(p, va_arg(args, struct item_head *)); + p += scnprintf_item_head(p, end - p, + va_arg(args, struct item_head *)); break; case 't': - sprintf_direntry(p, - va_arg(args, - struct reiserfs_dir_entry *)); + p += scnprintf_direntry(p, end - p, + va_arg(args, struct reiserfs_dir_entry *)); break; case 'y': - sprintf_disk_child(p, - va_arg(args, struct disk_child *)); + p += scnprintf_disk_child(p, end - p, + va_arg(args, struct disk_child *)); break; case 'z': - sprintf_block_head(p, - va_arg(args, struct buffer_head *)); + p += scnprintf_block_head(p, end - p, + va_arg(args, struct buffer_head *)); break; case 'b': - sprintf_buffer_head(p, - va_arg(args, struct buffer_head *)); + p += scnprintf_buffer_head(p, end - p, + va_arg(args, struct buffer_head *)); break; case 'a': - sprintf_de_head(p, - va_arg(args, - struct reiserfs_de_head *)); + p += scnprintf_de_head(p, end - p, + va_arg(args, struct reiserfs_de_head *)); break; } - p += strlen(p); fmt1 = k + 2; } - vsprintf(p, fmt1, args); + p += vscnprintf(p, end - p, fmt1, args); +out_unlock: spin_unlock(&error_lock); } -- GitLab From d9bb71d76c07d287f3904c463d1234e6b7b8049d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 11 Jul 2018 10:46:29 -0700 Subject: [PATCH 0134/1001] KEYS: DNS: fix parsing multiple options commit c604cb767049b78b3075497b80ebb8fd530ea2cc upstream. My recent fix for dns_resolver_preparse() printing very long strings was incomplete, as shown by syzbot which still managed to hit the WARN_ONCE() in set_precision() by adding a crafted "dns_resolver" key: precision 50001 too large WARNING: CPU: 7 PID: 864 at lib/vsprintf.c:2164 vsnprintf+0x48a/0x5a0 The bug this time isn't just a printing bug, but also a logical error when multiple options ("#"-separated strings) are given in the key payload. Specifically, when separating an option string into name and value, if there is no value then the name is incorrectly considered to end at the end of the key payload, rather than the end of the current option. This bypasses validation of the option length, and also means that specifying multiple options is broken -- which presumably has gone unnoticed as there is currently only one valid option anyway. A similar problem also applied to option values, as the kstrtoul() when parsing the "dnserror" option will read past the end of the current option and into the next option. Fix these bugs by correctly computing the length of the option name and by copying the option value, null-terminated, into a temporary buffer. Reproducer for the WARN_ONCE() that syzbot hit: perl -e 'print "#A#", "\0" x 50000' | keyctl padd dns_resolver desc @s Reproducer for "dnserror" option being parsed incorrectly (expected behavior is to fail when seeing the unknown option "foo", actual behavior was to read the dnserror value as "1#foo" and fail there): perl -e 'print "#dnserror=1#foo\0"' | keyctl padd dns_resolver desc @s Reported-by: syzbot Fixes: 4a2d789267e0 ("DNS: If the DNS server returns an error, allow that to be cached [ver #2]") Signed-off-by: Eric Biggers Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/dns_resolver/dns_key.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index f0252768ecf4..5f5d9eafccf5 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c @@ -87,35 +87,39 @@ dns_resolver_preparse(struct key_preparsed_payload *prep) opt++; kdebug("options: '%s'", opt); do { + int opt_len, opt_nlen; const char *eq; - int opt_len, opt_nlen, opt_vlen, tmp; + char optval[128]; next_opt = memchr(opt, '#', end - opt) ?: end; opt_len = next_opt - opt; - if (opt_len <= 0 || opt_len > 128) { + if (opt_len <= 0 || opt_len > sizeof(optval)) { pr_warn_ratelimited("Invalid option length (%d) for dns_resolver key\n", opt_len); return -EINVAL; } - eq = memchr(opt, '=', opt_len) ?: end; - opt_nlen = eq - opt; - eq++; - opt_vlen = next_opt - eq; /* will be -1 if no value */ + eq = memchr(opt, '=', opt_len); + if (eq) { + opt_nlen = eq - opt; + eq++; + memcpy(optval, eq, next_opt - eq); + optval[next_opt - eq] = '\0'; + } else { + opt_nlen = opt_len; + optval[0] = '\0'; + } - tmp = opt_vlen >= 0 ? opt_vlen : 0; - kdebug("option '%*.*s' val '%*.*s'", - opt_nlen, opt_nlen, opt, tmp, tmp, eq); + kdebug("option '%*.*s' val '%s'", + opt_nlen, opt_nlen, opt, optval); /* see if it's an error number representing a DNS error * that's to be recorded as the result in this key */ if (opt_nlen == sizeof(DNS_ERRORNO_OPTION) - 1 && memcmp(opt, DNS_ERRORNO_OPTION, opt_nlen) == 0) { kdebug("dns error number option"); - if (opt_vlen <= 0) - goto bad_option_value; - ret = kstrtoul(eq, 10, &derrno); + ret = kstrtoul(optval, 10, &derrno); if (ret < 0) goto bad_option_value; -- GitLab From 30a7a7b04f8b4e38b1af9acda2a4dd533e260ed2 Mon Sep 17 00:00:00 2001 From: Dave Watson Date: Thu, 12 Jul 2018 08:03:43 -0700 Subject: [PATCH 0135/1001] tls: Stricter error checking in zerocopy sendmsg path commit 32da12216e467dea70a09cd7094c30779ce0f9db upstream. In the zerocopy sendmsg() path, there are error checks to revert the zerocopy if we get any error code. syzkaller has discovered that tls_push_record can return -ECONNRESET, which is fatal, and happens after the point at which it is safe to revert the iter, as we've already passed the memory to do_tcp_sendpages. Previously this code could return -ENOMEM and we would want to revert the iter, but AFAIK this no longer returns ENOMEM after a447da7d004 ("tls: fix waitall behavior in tls_sw_recvmsg"), so we fail for all error codes. Reported-by: syzbot+c226690f7b3126c5ee04@syzkaller.appspotmail.com Reported-by: syzbot+709f2810a6a05f11d4d3@syzkaller.appspotmail.com Signed-off-by: Dave Watson Fixes: 3c4d7559159b ("tls: kernel TLS support") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/tls/tls_sw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 3c86614462f6..8ee4e667a414 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -449,7 +449,7 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) ret = tls_push_record(sk, msg->msg_flags, record_type); if (!ret) continue; - if (ret == -EAGAIN) + if (ret < 0) goto send_end; copied -= try_to_copy; -- GitLab From 00235ab80007696f1274eca9c0529b8f7c85def0 Mon Sep 17 00:00:00 2001 From: Tomas Bortoli Date: Fri, 13 Jul 2018 16:58:59 -0700 Subject: [PATCH 0136/1001] autofs: fix slab out of bounds read in getname_kernel() commit 02f51d45937f7bc7f4dee21e9f85b2d5eac37104 upstream. The autofs subsystem does not check that the "path" parameter is present for all cases where it is required when it is passed in via the "param" struct. In particular it isn't checked for the AUTOFS_DEV_IOCTL_OPENMOUNT_CMD ioctl command. To solve it, modify validate_dev_ioctl(function to check that a path has been provided for ioctl commands that require it. Link: http://lkml.kernel.org/r/153060031527.26631.18306637892746301555.stgit@pluto.themaw.net Signed-off-by: Tomas Bortoli Signed-off-by: Ian Kent Reported-by: syzbot+60c837b428dc84e83a93@syzkaller.appspotmail.com Cc: Dmitry Vyukov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/autofs4/dev-ioctl.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c index b7c816f39404..6dd63981787a 100644 --- a/fs/autofs4/dev-ioctl.c +++ b/fs/autofs4/dev-ioctl.c @@ -148,6 +148,15 @@ static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param) cmd); goto out; } + } else { + unsigned int inr = _IOC_NR(cmd); + + if (inr == AUTOFS_DEV_IOCTL_OPENMOUNT_CMD || + inr == AUTOFS_DEV_IOCTL_REQUESTER_CMD || + inr == AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD) { + err = -EINVAL; + goto out; + } } err = 0; @@ -284,7 +293,8 @@ static int autofs_dev_ioctl_openmount(struct file *fp, dev_t devid; int err, fd; - /* param->path has already been checked */ + /* param->path has been checked in validate_dev_ioctl() */ + if (!param->openmount.devid) return -EINVAL; @@ -446,10 +456,7 @@ static int autofs_dev_ioctl_requester(struct file *fp, dev_t devid; int err = -ENOENT; - if (param->size <= AUTOFS_DEV_IOCTL_SIZE) { - err = -EINVAL; - goto out; - } + /* param->path has been checked in validate_dev_ioctl() */ devid = sbi->sb->s_dev; @@ -534,10 +541,7 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp, unsigned int devid, magic; int err = -ENOENT; - if (param->size <= AUTOFS_DEV_IOCTL_SIZE) { - err = -EINVAL; - goto out; - } + /* param->path has been checked in validate_dev_ioctl() */ name = param->path; type = param->ismountpoint.in.type; -- GitLab From b124e97f3ef528e81f28c783b6ddce5ee0faf119 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Wed, 11 Jul 2018 12:00:44 -0400 Subject: [PATCH 0137/1001] nsh: set mac len based on inner packet commit bab2c80e5a6c855657482eac9e97f5f3eedb509a upstream. When pulling the NSH header in nsh_gso_segment, set the mac length based on the encapsulated packet type. skb_reset_mac_len computes an offset to the network header, which here still points to the outer packet: > skb_reset_network_header(skb); > [...] > __skb_pull(skb, nsh_len); > skb_reset_mac_header(skb); // now mac hdr starts nsh_len == 8B after net hdr > skb_reset_mac_len(skb); // mac len = net hdr - mac hdr == (u16) -8 == 65528 > [..] > skb_mac_gso_segment(skb, ..) Link: http://lkml.kernel.org/r/CAF=yD-KeAcTSOn4AxirAxL8m7QAS8GBBe1w09eziYwvPbbUeYA@mail.gmail.com Reported-by: syzbot+7b9ed9872dab8c32305d@syzkaller.appspotmail.com Fixes: c411ed854584 ("nsh: add GSO support") Signed-off-by: Willem de Bruijn Acked-by: Jiri Benc Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/nsh/nsh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/nsh/nsh.c b/net/nsh/nsh.c index 6df6f58a8103..5647905c88d6 100644 --- a/net/nsh/nsh.c +++ b/net/nsh/nsh.c @@ -42,7 +42,7 @@ static struct sk_buff *nsh_gso_segment(struct sk_buff *skb, __skb_pull(skb, nsh_len); skb_reset_mac_header(skb); - skb_reset_mac_len(skb); + skb->mac_len = proto == htons(ETH_P_TEB) ? ETH_HLEN : 0; skb->protocol = proto; features &= NETIF_F_SG; -- GitLab From 28c74ff85efd192aeca9005499ca50c24d795f61 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 9 Jul 2018 13:43:38 +0200 Subject: [PATCH 0138/1001] netfilter: ipv6: nf_defrag: drop skb dst before queueing commit 84379c9afe011020e797e3f50a662b08a6355dcf upstream. Eric Dumazet reports: Here is a reproducer of an annoying bug detected by syzkaller on our production kernel [..] ./b78305423 enable_conntrack Then : sleep 60 dmesg | tail -10 [ 171.599093] unregister_netdevice: waiting for lo to become free. Usage count = 2 [ 181.631024] unregister_netdevice: waiting for lo to become free. Usage count = 2 [ 191.687076] unregister_netdevice: waiting for lo to become free. Usage count = 2 [ 201.703037] unregister_netdevice: waiting for lo to become free. Usage count = 2 [ 211.711072] unregister_netdevice: waiting for lo to become free. Usage count = 2 [ 221.959070] unregister_netdevice: waiting for lo to become free. Usage count = 2 Reproducer sends ipv6 fragment that hits nfct defrag via LOCAL_OUT hook. skb gets queued until frag timer expiry -- 1 minute. Normally nf_conntrack_reasm gets called during prerouting, so skb has no dst yet which might explain why this wasn't spotted earlier. Reported-by: Eric Dumazet Reported-by: John Sperbeck Signed-off-by: Florian Westphal Tested-by: Eric Dumazet Reported-by: syzbot Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/ipv6/netfilter/nf_conntrack_reasm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 64ec23388450..722a9db8c6a7 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -618,6 +618,8 @@ int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user) fq->q.meat == fq->q.len && nf_ct_frag6_reasm(fq, skb, dev)) ret = 0; + else + skb_dst_drop(skb); out_unlock: spin_unlock_bh(&fq->q.lock); -- GitLab From 1bbe05e27af1d67b0c9c113d1f62373e933205ec Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 18 Jun 2018 15:46:58 +0200 Subject: [PATCH 0139/1001] bdi: Fix another oops in wb_workfn() commit 3ee7e8697d5860b173132606d80a9cd35e7113ee upstream. syzbot is reporting NULL pointer dereference at wb_workfn() [1] due to wb->bdi->dev being NULL. And Dmitry confirmed that wb->state was WB_shutting_down after wb->bdi->dev became NULL. This indicates that unregister_bdi() failed to call wb_shutdown() on one of wb objects. The problem is in cgwb_bdi_unregister() which does cgwb_kill() and thus drops bdi's reference to wb structures before going through the list of wbs again and calling wb_shutdown() on each of them. This way the loop iterating through all wbs can easily miss a wb if that wb has already passed through cgwb_remove_from_bdi_list() called from wb_shutdown() from cgwb_release_workfn() and as a result fully shutdown bdi although wb_workfn() for this wb structure is still running. In fact there are also other ways cgwb_bdi_unregister() can race with cgwb_release_workfn() leading e.g. to use-after-free issues: CPU1 CPU2 cgwb_bdi_unregister() cgwb_kill(*slot); cgwb_release() queue_work(cgwb_release_wq, &wb->release_work); cgwb_release_workfn() wb = list_first_entry(&bdi->wb_list, ...) spin_unlock_irq(&cgwb_lock); wb_shutdown(wb); ... kfree_rcu(wb, rcu); wb_shutdown(wb); -> oops use-after-free We solve these issues by synchronizing writeback structure shutdown from cgwb_bdi_unregister() with cgwb_release_workfn() using a new mutex. That way we also no longer need synchronization using WB_shutting_down as the mutex provides it for CONFIG_CGROUP_WRITEBACK case and without CONFIG_CGROUP_WRITEBACK wb_shutdown() can be called only once from bdi_unregister(). Reported-by: syzbot Acked-by: Tejun Heo Signed-off-by: Jan Kara Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- include/linux/backing-dev-defs.h | 2 +- mm/backing-dev.c | 20 +++++++------------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h index eac387a3bfef..3c1beffc861a 100644 --- a/include/linux/backing-dev-defs.h +++ b/include/linux/backing-dev-defs.h @@ -22,7 +22,6 @@ struct dentry; */ enum wb_state { WB_registered, /* bdi_register() was done */ - WB_shutting_down, /* wb_shutdown() in progress */ WB_writeback_running, /* Writeback is in progress */ WB_has_dirty_io, /* Dirty inodes on ->b_{dirty|io|more_io} */ }; @@ -165,6 +164,7 @@ struct backing_dev_info { #ifdef CONFIG_CGROUP_WRITEBACK struct radix_tree_root cgwb_tree; /* radix tree of active cgroup wbs */ struct rb_root cgwb_congested_tree; /* their congested states */ + struct mutex cgwb_release_mutex; /* protect shutdown of wb structs */ #else struct bdi_writeback_congested *wb_congested; #endif diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 6774e0369ebe..9386c98dac12 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -356,15 +356,8 @@ static void wb_shutdown(struct bdi_writeback *wb) spin_lock_bh(&wb->work_lock); if (!test_and_clear_bit(WB_registered, &wb->state)) { spin_unlock_bh(&wb->work_lock); - /* - * Wait for wb shutdown to finish if someone else is just - * running wb_shutdown(). Otherwise we could proceed to wb / - * bdi destruction before wb_shutdown() is finished. - */ - wait_on_bit(&wb->state, WB_shutting_down, TASK_UNINTERRUPTIBLE); return; } - set_bit(WB_shutting_down, &wb->state); spin_unlock_bh(&wb->work_lock); cgwb_remove_from_bdi_list(wb); @@ -376,12 +369,6 @@ static void wb_shutdown(struct bdi_writeback *wb) mod_delayed_work(bdi_wq, &wb->dwork, 0); flush_delayed_work(&wb->dwork); WARN_ON(!list_empty(&wb->work_list)); - /* - * Make sure bit gets cleared after shutdown is finished. Matches with - * the barrier provided by test_and_clear_bit() above. - */ - smp_wmb(); - clear_and_wake_up_bit(WB_shutting_down, &wb->state); } static void wb_exit(struct bdi_writeback *wb) @@ -505,10 +492,12 @@ static void cgwb_release_workfn(struct work_struct *work) struct bdi_writeback *wb = container_of(work, struct bdi_writeback, release_work); + mutex_lock(&wb->bdi->cgwb_release_mutex); wb_shutdown(wb); css_put(wb->memcg_css); css_put(wb->blkcg_css); + mutex_unlock(&wb->bdi->cgwb_release_mutex); fprop_local_destroy_percpu(&wb->memcg_completions); percpu_ref_exit(&wb->refcnt); @@ -694,6 +683,7 @@ static int cgwb_bdi_init(struct backing_dev_info *bdi) INIT_RADIX_TREE(&bdi->cgwb_tree, GFP_ATOMIC); bdi->cgwb_congested_tree = RB_ROOT; + mutex_init(&bdi->cgwb_release_mutex); ret = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL); if (!ret) { @@ -714,7 +704,10 @@ static void cgwb_bdi_unregister(struct backing_dev_info *bdi) spin_lock_irq(&cgwb_lock); radix_tree_for_each_slot(slot, &bdi->cgwb_tree, &iter, 0) cgwb_kill(*slot); + spin_unlock_irq(&cgwb_lock); + mutex_lock(&bdi->cgwb_release_mutex); + spin_lock_irq(&cgwb_lock); while (!list_empty(&bdi->wb_list)) { wb = list_first_entry(&bdi->wb_list, struct bdi_writeback, bdi_node); @@ -723,6 +716,7 @@ static void cgwb_bdi_unregister(struct backing_dev_info *bdi) spin_lock_irq(&cgwb_lock); } spin_unlock_irq(&cgwb_lock); + mutex_unlock(&bdi->cgwb_release_mutex); } /** -- GitLab From a4b57440d971f4ee139a923a0b953f91c3769d70 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Thu, 14 Jun 2018 11:52:34 -0700 Subject: [PATCH 0140/1001] rds: avoid unenecessary cong_update in loop transport commit f1693c63ab133d16994cc50f773982b5905af264 upstream. Loop transport which is self loopback, remote port congestion update isn't relevant. Infact the xmit path already ignores it. Receive path needs to do the same. Reported-by: syzbot+4c20b3866171ce8441d2@syzkaller.appspotmail.com Reviewed-by: Sowmini Varadhan Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/rds/loop.c | 1 + net/rds/rds.h | 5 +++++ net/rds/recv.c | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/net/rds/loop.c b/net/rds/loop.c index f2bf78de5688..dac6218a460e 100644 --- a/net/rds/loop.c +++ b/net/rds/loop.c @@ -193,4 +193,5 @@ struct rds_transport rds_loop_transport = { .inc_copy_to_user = rds_message_inc_copy_to_user, .inc_free = rds_loop_inc_free, .t_name = "loopback", + .t_type = RDS_TRANS_LOOP, }; diff --git a/net/rds/rds.h b/net/rds/rds.h index d09f6c1facb4..f685d8b514e5 100644 --- a/net/rds/rds.h +++ b/net/rds/rds.h @@ -454,6 +454,11 @@ struct rds_notifier { int n_status; }; +/* Available as part of RDS core, so doesn't need to participate + * in get_preferred transport etc + */ +#define RDS_TRANS_LOOP 3 + /** * struct rds_transport - transport specific behavioural hooks * diff --git a/net/rds/recv.c b/net/rds/recv.c index 555f07ccf0dc..c27cceae52e1 100644 --- a/net/rds/recv.c +++ b/net/rds/recv.c @@ -103,6 +103,11 @@ static void rds_recv_rcvbuf_delta(struct rds_sock *rs, struct sock *sk, rds_stats_add(s_recv_bytes_added_to_socket, delta); else rds_stats_add(s_recv_bytes_removed_from_socket, -delta); + + /* loop transport doesn't send/recv congestion updates */ + if (rs->rs_transport->t_type == RDS_TRANS_LOOP) + return; + now_congested = rs->rs_rcv_bytes > rds_sk_rcvbuf(rs); rdsdebug("rs %p (%pI4:%u) recv bytes %d buf %d " -- GitLab From 115df2a7c5ba248360e4f92d78102c34f45977ee Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 18 Jul 2018 18:57:27 +0900 Subject: [PATCH 0141/1001] net/nfc: Avoid stalls when nfc_alloc_send_skb() returned NULL. commit 3bc53be9db21040b5d2de4d455f023c8c494aa68 upstream. syzbot is reporting stalls at nfc_llcp_send_ui_frame() [1]. This is because nfc_llcp_send_ui_frame() is retrying the loop without any delay when nonblocking nfc_alloc_send_skb() returned NULL. Since there is no need to use MSG_DONTWAIT if we retry until sock_alloc_send_pskb() succeeds, let's use blocking call. Also, in case an unexpected error occurred, let's break the loop if blocking nfc_alloc_send_skb() failed. [1] https://syzkaller.appspot.com/bug?id=4a131cc571c3733e0eff6bc673f4e36ae48f19c6 Signed-off-by: Tetsuo Handa Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/nfc/llcp_commands.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c index 2ceefa183cee..6a196e438b6c 100644 --- a/net/nfc/llcp_commands.c +++ b/net/nfc/llcp_commands.c @@ -752,11 +752,14 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap, pr_debug("Fragment %zd bytes remaining %zd", frag_len, remaining_len); - pdu = nfc_alloc_send_skb(sock->dev, &sock->sk, MSG_DONTWAIT, + pdu = nfc_alloc_send_skb(sock->dev, &sock->sk, 0, frag_len + LLCP_HEADER_SIZE, &err); if (pdu == NULL) { - pr_err("Could not allocate PDU\n"); - continue; + pr_err("Could not allocate PDU (error=%d)\n", err); + len -= remaining_len; + if (len == 0) + len = err; + break; } pdu = llcp_add_header(pdu, dsap, ssap, LLCP_PDU_UI); -- GitLab From ed812b882599c0ec27a9f58831fc6bfb4efdac80 Mon Sep 17 00:00:00 2001 From: James Morse Date: Fri, 20 Jul 2018 10:52:51 +0100 Subject: [PATCH 0142/1001] KVM: arm64: Store vcpu on the stack during __guest_enter() Commit 32b03d1059667a39e089c45ee38ec9c16332430f upstream. KVM uses tpidr_el2 as its private vcpu register, which makes sense for non-vhe world switch as only KVM can access this register. This means vhe Linux has to use tpidr_el1, which KVM has to save/restore as part of the host context. If the SDEI handler code runs behind KVMs back, it mustn't access any per-cpu variables. To allow this on systems with vhe we need to make the host use tpidr_el2, saving KVM from save/restoring it. __guest_enter() stores the host_ctxt on the stack, do the same with the vcpu. Signed-off-by: James Morse Reviewed-by: Christoffer Dall Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kvm/hyp/entry.S | 10 +++++++--- arch/arm64/kvm/hyp/hyp-entry.S | 6 +++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S index 9c45c6af1f58..fe4678f20a85 100644 --- a/arch/arm64/kvm/hyp/entry.S +++ b/arch/arm64/kvm/hyp/entry.S @@ -62,8 +62,8 @@ ENTRY(__guest_enter) // Store the host regs save_callee_saved_regs x1 - // Store the host_ctxt for use at exit time - str x1, [sp, #-16]! + // Store host_ctxt and vcpu for use at exit time + stp x1, x0, [sp, #-16]! add x18, x0, #VCPU_CONTEXT @@ -159,6 +159,10 @@ abort_guest_exit_end: ENDPROC(__guest_exit) ENTRY(__fpsimd_guest_restore) + // x0: esr + // x1: vcpu + // x2-x29,lr: vcpu regs + // vcpu x0-x1 on the stack stp x2, x3, [sp, #-16]! stp x4, lr, [sp, #-16]! @@ -173,7 +177,7 @@ alternative_else alternative_endif isb - mrs x3, tpidr_el2 + mov x3, x1 ldr x0, [x3, #VCPU_HOST_CONTEXT] kern_hyp_va x0 diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S index f49b53331d28..fc1613955090 100644 --- a/arch/arm64/kvm/hyp/hyp-entry.S +++ b/arch/arm64/kvm/hyp/hyp-entry.S @@ -120,6 +120,7 @@ el1_trap: /* * x0: ESR_EC */ + ldr x1, [sp, #16 + 8] // vcpu stored by __guest_enter /* * We trap the first access to the FP/SIMD to save the host context @@ -132,19 +133,18 @@ alternative_if_not ARM64_HAS_NO_FPSIMD b.eq __fpsimd_guest_restore alternative_else_nop_endif - mrs x1, tpidr_el2 mov x0, #ARM_EXCEPTION_TRAP b __guest_exit el1_irq: stp x0, x1, [sp, #-16]! - mrs x1, tpidr_el2 + ldr x1, [sp, #16 + 8] mov x0, #ARM_EXCEPTION_IRQ b __guest_exit el1_error: stp x0, x1, [sp, #-16]! - mrs x1, tpidr_el2 + ldr x1, [sp, #16 + 8] mov x0, #ARM_EXCEPTION_EL1_SERROR b __guest_exit -- GitLab From 8ad56472d67cf8ce638876558d36f3c83975294a Mon Sep 17 00:00:00 2001 From: James Morse Date: Fri, 20 Jul 2018 10:52:52 +0100 Subject: [PATCH 0143/1001] KVM: arm/arm64: Convert kvm_host_cpu_state to a static per-cpu allocation Commit 36989e7fd386a9a5822c48691473863f8fbb404d upstream. kvm_host_cpu_state is a per-cpu allocation made from kvm_arch_init() used to store the host EL1 registers when KVM switches to a guest. Make it easier for ASM to generate pointers into this per-cpu memory by making it a static allocation. Signed-off-by: James Morse Acked-by: Christoffer Dall Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- virt/kvm/arm/arm.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 9bee849db682..4aede98b92eb 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -51,8 +51,8 @@ __asm__(".arch_extension virt"); #endif +DEFINE_PER_CPU(kvm_cpu_context_t, kvm_host_cpu_state); static DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page); -static kvm_cpu_context_t __percpu *kvm_host_cpu_state; /* Per-CPU variable containing the currently running vcpu. */ static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_arm_running_vcpu); @@ -351,7 +351,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) } vcpu->cpu = cpu; - vcpu->arch.host_cpu_context = this_cpu_ptr(kvm_host_cpu_state); + vcpu->arch.host_cpu_context = this_cpu_ptr(&kvm_host_cpu_state); kvm_arm_set_running_vcpu(vcpu); @@ -1259,19 +1259,8 @@ static inline void hyp_cpu_pm_exit(void) } #endif -static void teardown_common_resources(void) -{ - free_percpu(kvm_host_cpu_state); -} - static int init_common_resources(void) { - kvm_host_cpu_state = alloc_percpu(kvm_cpu_context_t); - if (!kvm_host_cpu_state) { - kvm_err("Cannot allocate host CPU state\n"); - return -ENOMEM; - } - /* set size of VMID supported by CPU */ kvm_vmid_bits = kvm_get_vmid_bits(); kvm_info("%d-bit VMID\n", kvm_vmid_bits); @@ -1413,7 +1402,7 @@ static int init_hyp_mode(void) for_each_possible_cpu(cpu) { kvm_cpu_context_t *cpu_ctxt; - cpu_ctxt = per_cpu_ptr(kvm_host_cpu_state, cpu); + cpu_ctxt = per_cpu_ptr(&kvm_host_cpu_state, cpu); err = create_hyp_mappings(cpu_ctxt, cpu_ctxt + 1, PAGE_HYP); if (err) { @@ -1497,7 +1486,6 @@ int kvm_arch_init(void *opaque) if (!in_hyp_mode) teardown_hyp_mode(); out_err: - teardown_common_resources(); return err; } -- GitLab From 6256b86e851942f4ec145d36a0c8f3673390b9d9 Mon Sep 17 00:00:00 2001 From: James Morse Date: Fri, 20 Jul 2018 10:52:53 +0100 Subject: [PATCH 0144/1001] KVM: arm64: Change hyp_panic()s dependency on tpidr_el2 Commit c97e166e54b662717d20ec2e36761758d2b6a7c2 upstream. Make tpidr_el2 a cpu-offset for per-cpu variables in the same way the host uses tpidr_el1. This lets tpidr_el{1,2} have the same value, and on VHE they can be the same register. KVM calls hyp_panic() when anything unexpected happens. This may occur while a guest owns the EL1 registers. KVM stashes the vcpu pointer in tpidr_el2, which it uses to find the host context in order to restore the host EL1 registers before parachuting into the host's panic(). The host context is a struct kvm_cpu_context allocated in the per-cpu area, and mapped to hyp. Given the per-cpu offset for this CPU, this is easy to find. Change hyp_panic() to take a pointer to the struct kvm_cpu_context. Wrap these calls with an asm function that retrieves the struct kvm_cpu_context from the host's per-cpu area. Copy the per-cpu offset from the hosts tpidr_el1 into tpidr_el2 during kvm init. (Later patches will make this unnecessary for VHE hosts) We print out the vcpu pointer as part of the panic message. Add a back reference to the 'running vcpu' in the host cpu context to preserve this. Signed-off-by: James Morse Reviewed-by: Christoffer Dall Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/kvm_host.h | 2 ++ arch/arm64/kvm/hyp/hyp-entry.S | 12 ++++++++++++ arch/arm64/kvm/hyp/s2-setup.c | 3 +++ arch/arm64/kvm/hyp/switch.c | 25 +++++++++++++------------ 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 8abec9f7f430..7b373e56750f 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -194,6 +194,8 @@ struct kvm_cpu_context { u64 sys_regs[NR_SYS_REGS]; u32 copro[NR_COPRO_REGS]; }; + + struct kvm_vcpu *__hyp_running_vcpu; }; typedef struct kvm_cpu_context kvm_cpu_context_t; diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S index fc1613955090..f36464bd57c5 100644 --- a/arch/arm64/kvm/hyp/hyp-entry.S +++ b/arch/arm64/kvm/hyp/hyp-entry.S @@ -179,6 +179,18 @@ ENTRY(__hyp_do_panic) eret ENDPROC(__hyp_do_panic) +ENTRY(__hyp_panic) + /* + * '=kvm_host_cpu_state' is a host VA from the constant pool, it may + * not be accessible by this address from EL2, hyp_panic() converts + * it with kern_hyp_va() before use. + */ + ldr x0, =kvm_host_cpu_state + mrs x1, tpidr_el2 + add x0, x0, x1 + b hyp_panic +ENDPROC(__hyp_panic) + .macro invalid_vector label, target = __hyp_panic .align 2 \label: diff --git a/arch/arm64/kvm/hyp/s2-setup.c b/arch/arm64/kvm/hyp/s2-setup.c index a81f5e10fc8c..7fb88274eba1 100644 --- a/arch/arm64/kvm/hyp/s2-setup.c +++ b/arch/arm64/kvm/hyp/s2-setup.c @@ -84,5 +84,8 @@ u32 __hyp_text __init_stage2_translation(void) write_sysreg(val, vtcr_el2); + /* copy tpidr_el1 into tpidr_el2 for use by HYP */ + write_sysreg(read_sysreg(tpidr_el1), tpidr_el2); + return parange; } diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c index e08ae6b6b63e..8875bca6868a 100644 --- a/arch/arm64/kvm/hyp/switch.c +++ b/arch/arm64/kvm/hyp/switch.c @@ -289,9 +289,9 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) u64 exit_code; vcpu = kern_hyp_va(vcpu); - write_sysreg(vcpu, tpidr_el2); host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context); + host_ctxt->__hyp_running_vcpu = vcpu; guest_ctxt = &vcpu->arch.ctxt; __sysreg_save_host_state(host_ctxt); @@ -406,7 +406,8 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) static const char __hyp_panic_string[] = "HYP panic:\nPS:%08llx PC:%016llx ESR:%08llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%p\n"; -static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par) +static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par, + struct kvm_vcpu *vcpu) { unsigned long str_va; @@ -420,35 +421,35 @@ static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par) __hyp_do_panic(str_va, spsr, elr, read_sysreg(esr_el2), read_sysreg_el2(far), - read_sysreg(hpfar_el2), par, - (void *)read_sysreg(tpidr_el2)); + read_sysreg(hpfar_el2), par, vcpu); } -static void __hyp_text __hyp_call_panic_vhe(u64 spsr, u64 elr, u64 par) +static void __hyp_text __hyp_call_panic_vhe(u64 spsr, u64 elr, u64 par, + struct kvm_vcpu *vcpu) { panic(__hyp_panic_string, spsr, elr, read_sysreg_el2(esr), read_sysreg_el2(far), - read_sysreg(hpfar_el2), par, - (void *)read_sysreg(tpidr_el2)); + read_sysreg(hpfar_el2), par, vcpu); } static hyp_alternate_select(__hyp_call_panic, __hyp_call_panic_nvhe, __hyp_call_panic_vhe, ARM64_HAS_VIRT_HOST_EXTN); -void __hyp_text __noreturn __hyp_panic(void) +void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt) { + struct kvm_vcpu *vcpu = NULL; + u64 spsr = read_sysreg_el2(spsr); u64 elr = read_sysreg_el2(elr); u64 par = read_sysreg(par_el1); if (read_sysreg(vttbr_el2)) { - struct kvm_vcpu *vcpu; struct kvm_cpu_context *host_ctxt; - vcpu = (struct kvm_vcpu *)read_sysreg(tpidr_el2); - host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context); + host_ctxt = kern_hyp_va(__host_ctxt); + vcpu = host_ctxt->__hyp_running_vcpu; __timer_save_state(vcpu); __deactivate_traps(vcpu); __deactivate_vm(vcpu); @@ -456,7 +457,7 @@ void __hyp_text __noreturn __hyp_panic(void) } /* Call panic for real */ - __hyp_call_panic()(spsr, elr, par); + __hyp_call_panic()(spsr, elr, par, vcpu); unreachable(); } -- GitLab From 0dac9f10d9525f9617eaf383e1629ae976e2f170 Mon Sep 17 00:00:00 2001 From: James Morse Date: Fri, 20 Jul 2018 10:52:54 +0100 Subject: [PATCH 0145/1001] arm64: alternatives: use tpidr_el2 on VHE hosts Commit 6d99b68933fbcf51f84fcbba49246ce1209ec193 upstream. Now that KVM uses tpidr_el2 in the same way as Linux's cpu_offset in tpidr_el1, merge the two. This saves KVM from save/restoring tpidr_el1 on VHE hosts, and allows future code to blindly access per-cpu variables without triggering world-switch. Signed-off-by: James Morse Reviewed-by: Christoffer Dall Reviewed-by: Catalin Marinas Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/alternative.h | 2 ++ arch/arm64/include/asm/assembler.h | 8 ++++++++ arch/arm64/include/asm/percpu.h | 11 +++++++++-- arch/arm64/kernel/alternative.c | 9 +++++---- arch/arm64/kernel/cpufeature.c | 17 +++++++++++++++++ arch/arm64/mm/proc.S | 8 ++++++++ 6 files changed, 49 insertions(+), 6 deletions(-) diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h index 4a85c6952a22..669028172fd6 100644 --- a/arch/arm64/include/asm/alternative.h +++ b/arch/arm64/include/asm/alternative.h @@ -12,6 +12,8 @@ #include #include +extern int alternatives_applied; + struct alt_instr { s32 orig_offset; /* offset to original instruction */ s32 alt_offset; /* offset to replacement instruction */ diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index 25b2a4161c7a..66aea4aa455d 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -260,7 +260,11 @@ lr .req x30 // link register #else adr_l \dst, \sym #endif +alternative_if_not ARM64_HAS_VIRT_HOST_EXTN mrs \tmp, tpidr_el1 +alternative_else + mrs \tmp, tpidr_el2 +alternative_endif add \dst, \dst, \tmp .endm @@ -271,7 +275,11 @@ lr .req x30 // link register */ .macro ldr_this_cpu dst, sym, tmp adr_l \dst, \sym +alternative_if_not ARM64_HAS_VIRT_HOST_EXTN mrs \tmp, tpidr_el1 +alternative_else + mrs \tmp, tpidr_el2 +alternative_endif ldr \dst, [\dst, \tmp] .endm diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h index 3bd498e4de4c..43393208229e 100644 --- a/arch/arm64/include/asm/percpu.h +++ b/arch/arm64/include/asm/percpu.h @@ -16,11 +16,15 @@ #ifndef __ASM_PERCPU_H #define __ASM_PERCPU_H +#include #include static inline void set_my_cpu_offset(unsigned long off) { - asm volatile("msr tpidr_el1, %0" :: "r" (off) : "memory"); + asm volatile(ALTERNATIVE("msr tpidr_el1, %0", + "msr tpidr_el2, %0", + ARM64_HAS_VIRT_HOST_EXTN) + :: "r" (off) : "memory"); } static inline unsigned long __my_cpu_offset(void) @@ -31,7 +35,10 @@ static inline unsigned long __my_cpu_offset(void) * We want to allow caching the value, so avoid using volatile and * instead use a fake stack read to hazard against barrier(). */ - asm("mrs %0, tpidr_el1" : "=r" (off) : + asm(ALTERNATIVE("mrs %0, tpidr_el1", + "mrs %0, tpidr_el2", + ARM64_HAS_VIRT_HOST_EXTN) + : "=r" (off) : "Q" (*(const unsigned long *)current_stack_pointer)); return off; diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c index 6dd0a3a3e5c9..414288a558c8 100644 --- a/arch/arm64/kernel/alternative.c +++ b/arch/arm64/kernel/alternative.c @@ -32,6 +32,8 @@ #define ALT_ORIG_PTR(a) __ALT_PTR(a, orig_offset) #define ALT_REPL_PTR(a) __ALT_PTR(a, alt_offset) +int alternatives_applied; + struct alt_region { struct alt_instr *begin; struct alt_instr *end; @@ -143,7 +145,6 @@ static void __apply_alternatives(void *alt_region, bool use_linear_alias) */ static int __apply_alternatives_multi_stop(void *unused) { - static int patched = 0; struct alt_region region = { .begin = (struct alt_instr *)__alt_instructions, .end = (struct alt_instr *)__alt_instructions_end, @@ -151,14 +152,14 @@ static int __apply_alternatives_multi_stop(void *unused) /* We always have a CPU 0 at this point (__init) */ if (smp_processor_id()) { - while (!READ_ONCE(patched)) + while (!READ_ONCE(alternatives_applied)) cpu_relax(); isb(); } else { - BUG_ON(patched); + BUG_ON(alternatives_applied); __apply_alternatives(®ion, true); /* Barriers provided by the cache flushing */ - WRITE_ONCE(patched, 1); + WRITE_ONCE(alternatives_applied, 1); } return 0; diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 718822ab6e4b..376cf12edf0c 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -880,6 +880,22 @@ static int __init parse_kpti(char *str) early_param("kpti", parse_kpti); #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */ +static int cpu_copy_el2regs(void *__unused) +{ + /* + * Copy register values that aren't redirected by hardware. + * + * Before code patching, we only set tpidr_el1, all CPUs need to copy + * this value to tpidr_el2 before we patch the code. Once we've done + * that, freshly-onlined CPUs will set tpidr_el2, so we don't need to + * do anything here. + */ + if (!alternatives_applied) + write_sysreg(read_sysreg(tpidr_el1), tpidr_el2); + + return 0; +} + static const struct arm64_cpu_capabilities arm64_features[] = { { .desc = "GIC system register CPU interface", @@ -949,6 +965,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .capability = ARM64_HAS_VIRT_HOST_EXTN, .def_scope = SCOPE_SYSTEM, .matches = runs_at_el2, + .enable = cpu_copy_el2regs, }, { .desc = "32-bit EL0 Support", diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index bf0821b7b1ab..10c835f13f62 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -70,7 +70,11 @@ ENTRY(cpu_do_suspend) mrs x8, mdscr_el1 mrs x9, oslsr_el1 mrs x10, sctlr_el1 +alternative_if_not ARM64_HAS_VIRT_HOST_EXTN mrs x11, tpidr_el1 +alternative_else + mrs x11, tpidr_el2 +alternative_endif mrs x12, sp_el0 stp x2, x3, [x0] stp x4, xzr, [x0, #16] @@ -116,7 +120,11 @@ ENTRY(cpu_do_resume) msr mdscr_el1, x10 msr sctlr_el1, x12 +alternative_if_not ARM64_HAS_VIRT_HOST_EXTN msr tpidr_el1, x13 +alternative_else + msr tpidr_el2, x13 +alternative_endif msr sp_el0, x14 /* * Restore oslsr_el1 by writing oslar_el1 -- GitLab From 286950e0831b9bf7180c09b2dd06ec88922fcc12 Mon Sep 17 00:00:00 2001 From: James Morse Date: Fri, 20 Jul 2018 10:52:55 +0100 Subject: [PATCH 0146/1001] KVM: arm64: Stop save/restoring host tpidr_el1 on VHE Commit 1f742679c33bc083722cb0b442a95d458c491b56 upstream. Now that a VHE host uses tpidr_el2 for the cpu offset we no longer need KVM to save/restore tpidr_el1. Move this from the 'common' code into the non-vhe code. While we're at it, on VHE we don't need to save the ELR or SPSR as kernel_entry in entry.S will have pushed these onto the kernel stack, and will restore them from there. Move these to the non-vhe code as we need them to get back to the host. Finally remove the always-copy-tpidr we hid in the stage2 setup code, cpufeature's enable callback will do this for VHE, we only need KVM to do it for non-vhe. Add the copy into kvm-init instead. Signed-off-by: James Morse Reviewed-by: Christoffer Dall Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kvm/hyp-init.S | 4 ++++ arch/arm64/kvm/hyp/s2-setup.c | 3 --- arch/arm64/kvm/hyp/sysreg-sr.c | 16 ++++++++-------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/arch/arm64/kvm/hyp-init.S b/arch/arm64/kvm/hyp-init.S index 870828c364c5..dea20651a5f1 100644 --- a/arch/arm64/kvm/hyp-init.S +++ b/arch/arm64/kvm/hyp-init.S @@ -122,6 +122,10 @@ CPU_BE( orr x4, x4, #SCTLR_ELx_EE) kern_hyp_va x2 msr vbar_el2, x2 + /* copy tpidr_el1 into tpidr_el2 for use by HYP */ + mrs x1, tpidr_el1 + msr tpidr_el2, x1 + /* Hello, World! */ eret ENDPROC(__kvm_hyp_init) diff --git a/arch/arm64/kvm/hyp/s2-setup.c b/arch/arm64/kvm/hyp/s2-setup.c index 7fb88274eba1..a81f5e10fc8c 100644 --- a/arch/arm64/kvm/hyp/s2-setup.c +++ b/arch/arm64/kvm/hyp/s2-setup.c @@ -84,8 +84,5 @@ u32 __hyp_text __init_stage2_translation(void) write_sysreg(val, vtcr_el2); - /* copy tpidr_el1 into tpidr_el2 for use by HYP */ - write_sysreg(read_sysreg(tpidr_el1), tpidr_el2); - return parange; } diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c index 934137647837..c54cc2afb92b 100644 --- a/arch/arm64/kvm/hyp/sysreg-sr.c +++ b/arch/arm64/kvm/hyp/sysreg-sr.c @@ -27,8 +27,8 @@ static void __hyp_text __sysreg_do_nothing(struct kvm_cpu_context *ctxt) { } /* * Non-VHE: Both host and guest must save everything. * - * VHE: Host must save tpidr*_el[01], actlr_el1, mdscr_el1, sp0, pc, - * pstate, and guest must save everything. + * VHE: Host must save tpidr*_el0, actlr_el1, mdscr_el1, sp_el0, + * and guest must save everything. */ static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt) @@ -36,11 +36,8 @@ static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt) ctxt->sys_regs[ACTLR_EL1] = read_sysreg(actlr_el1); ctxt->sys_regs[TPIDR_EL0] = read_sysreg(tpidr_el0); ctxt->sys_regs[TPIDRRO_EL0] = read_sysreg(tpidrro_el0); - ctxt->sys_regs[TPIDR_EL1] = read_sysreg(tpidr_el1); ctxt->sys_regs[MDSCR_EL1] = read_sysreg(mdscr_el1); ctxt->gp_regs.regs.sp = read_sysreg(sp_el0); - ctxt->gp_regs.regs.pc = read_sysreg_el2(elr); - ctxt->gp_regs.regs.pstate = read_sysreg_el2(spsr); } static void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt) @@ -62,10 +59,13 @@ static void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt) ctxt->sys_regs[AMAIR_EL1] = read_sysreg_el1(amair); ctxt->sys_regs[CNTKCTL_EL1] = read_sysreg_el1(cntkctl); ctxt->sys_regs[PAR_EL1] = read_sysreg(par_el1); + ctxt->sys_regs[TPIDR_EL1] = read_sysreg(tpidr_el1); ctxt->gp_regs.sp_el1 = read_sysreg(sp_el1); ctxt->gp_regs.elr_el1 = read_sysreg_el1(elr); ctxt->gp_regs.spsr[KVM_SPSR_EL1]= read_sysreg_el1(spsr); + ctxt->gp_regs.regs.pc = read_sysreg_el2(elr); + ctxt->gp_regs.regs.pstate = read_sysreg_el2(spsr); } static hyp_alternate_select(__sysreg_call_save_host_state, @@ -89,11 +89,8 @@ static void __hyp_text __sysreg_restore_common_state(struct kvm_cpu_context *ctx write_sysreg(ctxt->sys_regs[ACTLR_EL1], actlr_el1); write_sysreg(ctxt->sys_regs[TPIDR_EL0], tpidr_el0); write_sysreg(ctxt->sys_regs[TPIDRRO_EL0], tpidrro_el0); - write_sysreg(ctxt->sys_regs[TPIDR_EL1], tpidr_el1); write_sysreg(ctxt->sys_regs[MDSCR_EL1], mdscr_el1); write_sysreg(ctxt->gp_regs.regs.sp, sp_el0); - write_sysreg_el2(ctxt->gp_regs.regs.pc, elr); - write_sysreg_el2(ctxt->gp_regs.regs.pstate, spsr); } static void __hyp_text __sysreg_restore_state(struct kvm_cpu_context *ctxt) @@ -115,10 +112,13 @@ static void __hyp_text __sysreg_restore_state(struct kvm_cpu_context *ctxt) write_sysreg_el1(ctxt->sys_regs[AMAIR_EL1], amair); write_sysreg_el1(ctxt->sys_regs[CNTKCTL_EL1], cntkctl); write_sysreg(ctxt->sys_regs[PAR_EL1], par_el1); + write_sysreg(ctxt->sys_regs[TPIDR_EL1], tpidr_el1); write_sysreg(ctxt->gp_regs.sp_el1, sp_el1); write_sysreg_el1(ctxt->gp_regs.elr_el1, elr); write_sysreg_el1(ctxt->gp_regs.spsr[KVM_SPSR_EL1],spsr); + write_sysreg_el2(ctxt->gp_regs.regs.pc, elr); + write_sysreg_el2(ctxt->gp_regs.regs.pstate, spsr); } static hyp_alternate_select(__sysreg_call_restore_host_state, -- GitLab From e77175fafa7dd941873dc248ab0f20aa56fe3431 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 20 Jul 2018 10:52:56 +0100 Subject: [PATCH 0147/1001] arm64: alternatives: Add dynamic patching feature Commit dea5e2a4c5bcf196f879a66cebdcca07793e8ba4 upstream. We've so far relied on a patching infrastructure that only gave us a single alternative, without any way to provide a range of potential replacement instructions. For a single feature, this is an all or nothing thing. It would be interesting to have a more flexible grained way of patching the kernel though, where we could dynamically tune the code that gets injected. In order to achive this, let's introduce a new form of dynamic patching, assiciating a callback to a patching site. This callback gets source and target locations of the patching request, as well as the number of instructions to be patched. Dynamic patching is declared with the new ALTERNATIVE_CB and alternative_cb directives: asm volatile(ALTERNATIVE_CB("mov %0, #0\n", callback) : "r" (v)); or alternative_cb callback mov x0, #0 alternative_cb_end where callback is the C function computing the alternative. Reviewed-by: Christoffer Dall Reviewed-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/alternative.h | 41 +++++++++++++++++++++++--- arch/arm64/kernel/alternative.c | 43 +++++++++++++++++++++------- 2 files changed, 69 insertions(+), 15 deletions(-) diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h index 669028172fd6..a91933b1e2e6 100644 --- a/arch/arm64/include/asm/alternative.h +++ b/arch/arm64/include/asm/alternative.h @@ -5,6 +5,8 @@ #include #include +#define ARM64_CB_PATCH ARM64_NCAPS + #ifndef __ASSEMBLY__ #include @@ -22,12 +24,19 @@ struct alt_instr { u8 alt_len; /* size of new instruction(s), <= orig_len */ }; +typedef void (*alternative_cb_t)(struct alt_instr *alt, + __le32 *origptr, __le32 *updptr, int nr_inst); + void __init apply_alternatives_all(void); void apply_alternatives(void *start, size_t length); -#define ALTINSTR_ENTRY(feature) \ +#define ALTINSTR_ENTRY(feature,cb) \ " .word 661b - .\n" /* label */ \ + " .if " __stringify(cb) " == 0\n" \ " .word 663f - .\n" /* new instruction */ \ + " .else\n" \ + " .word " __stringify(cb) "- .\n" /* callback */ \ + " .endif\n" \ " .hword " __stringify(feature) "\n" /* feature bit */ \ " .byte 662b-661b\n" /* source len */ \ " .byte 664f-663f\n" /* replacement len */ @@ -45,15 +54,18 @@ void apply_alternatives(void *start, size_t length); * but most assemblers die if insn1 or insn2 have a .inst. This should * be fixed in a binutils release posterior to 2.25.51.0.2 (anything * containing commit 4e4d08cf7399b606 or c1baaddf8861). + * + * Alternatives with callbacks do not generate replacement instructions. */ -#define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled) \ +#define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled, cb) \ ".if "__stringify(cfg_enabled)" == 1\n" \ "661:\n\t" \ oldinstr "\n" \ "662:\n" \ ".pushsection .altinstructions,\"a\"\n" \ - ALTINSTR_ENTRY(feature) \ + ALTINSTR_ENTRY(feature,cb) \ ".popsection\n" \ + " .if " __stringify(cb) " == 0\n" \ ".pushsection .altinstr_replacement, \"a\"\n" \ "663:\n\t" \ newinstr "\n" \ @@ -61,11 +73,17 @@ void apply_alternatives(void *start, size_t length); ".popsection\n\t" \ ".org . - (664b-663b) + (662b-661b)\n\t" \ ".org . - (662b-661b) + (664b-663b)\n" \ + ".else\n\t" \ + "663:\n\t" \ + "664:\n\t" \ + ".endif\n" \ ".endif\n" #define _ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg, ...) \ - __ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg)) + __ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg), 0) +#define ALTERNATIVE_CB(oldinstr, cb) \ + __ALTERNATIVE_CFG(oldinstr, "NOT_AN_INSTRUCTION", ARM64_CB_PATCH, 1, cb) #else #include @@ -132,6 +150,14 @@ void apply_alternatives(void *start, size_t length); 661: .endm +.macro alternative_cb cb + .set .Lasm_alt_mode, 0 + .pushsection .altinstructions, "a" + altinstruction_entry 661f, \cb, ARM64_CB_PATCH, 662f-661f, 0 + .popsection +661: +.endm + /* * Provide the other half of the alternative code sequence. */ @@ -157,6 +183,13 @@ void apply_alternatives(void *start, size_t length); .org . - (662b-661b) + (664b-663b) .endm +/* + * Callback-based alternative epilogue + */ +.macro alternative_cb_end +662: +.endm + /* * Provides a trivial alternative or default sequence consisting solely * of NOPs. The number of NOPs is chosen automatically to match the diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c index 414288a558c8..5c4bce4ac381 100644 --- a/arch/arm64/kernel/alternative.c +++ b/arch/arm64/kernel/alternative.c @@ -107,32 +107,53 @@ static u32 get_alt_insn(struct alt_instr *alt, __le32 *insnptr, __le32 *altinsnp return insn; } +static void patch_alternative(struct alt_instr *alt, + __le32 *origptr, __le32 *updptr, int nr_inst) +{ + __le32 *replptr; + int i; + + replptr = ALT_REPL_PTR(alt); + for (i = 0; i < nr_inst; i++) { + u32 insn; + + insn = get_alt_insn(alt, origptr + i, replptr + i); + updptr[i] = cpu_to_le32(insn); + } +} + static void __apply_alternatives(void *alt_region, bool use_linear_alias) { struct alt_instr *alt; struct alt_region *region = alt_region; - __le32 *origptr, *replptr, *updptr; + __le32 *origptr, *updptr; + alternative_cb_t alt_cb; for (alt = region->begin; alt < region->end; alt++) { - u32 insn; - int i, nr_inst; + int nr_inst; - if (!cpus_have_cap(alt->cpufeature)) + /* Use ARM64_CB_PATCH as an unconditional patch */ + if (alt->cpufeature < ARM64_CB_PATCH && + !cpus_have_cap(alt->cpufeature)) continue; - BUG_ON(alt->alt_len != alt->orig_len); + if (alt->cpufeature == ARM64_CB_PATCH) + BUG_ON(alt->alt_len != 0); + else + BUG_ON(alt->alt_len != alt->orig_len); pr_info_once("patching kernel code\n"); origptr = ALT_ORIG_PTR(alt); - replptr = ALT_REPL_PTR(alt); updptr = use_linear_alias ? lm_alias(origptr) : origptr; - nr_inst = alt->alt_len / sizeof(insn); + nr_inst = alt->orig_len / AARCH64_INSN_SIZE; - for (i = 0; i < nr_inst; i++) { - insn = get_alt_insn(alt, origptr + i, replptr + i); - updptr[i] = cpu_to_le32(insn); - } + if (alt->cpufeature < ARM64_CB_PATCH) + alt_cb = patch_alternative; + else + alt_cb = ALT_REPL_PTR(alt); + + alt_cb(alt, origptr, updptr, nr_inst); flush_icache_range((uintptr_t)origptr, (uintptr_t)(origptr + nr_inst)); -- GitLab From dca7815605aff032d0b7f9c4f1d98af0e529cdee Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 20 Jul 2018 10:52:57 +0100 Subject: [PATCH 0148/1001] KVM: arm/arm64: Do not use kern_hyp_va() with kvm_vgic_global_state Commit 44a497abd621a71c645f06d3d545ae2f46448830 upstream. kvm_vgic_global_state is part of the read-only section, and is usually accessed using a PC-relative address generation (adrp + add). It is thus useless to use kern_hyp_va() on it, and actively problematic if kern_hyp_va() becomes non-idempotent. On the other hand, there is no way that the compiler is going to guarantee that such access is always PC relative. So let's bite the bullet and provide our own accessor. Acked-by: Catalin Marinas Reviewed-by: James Morse Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/kvm_mmu.h | 7 +++++++ arch/arm64/include/asm/kvm_mmu.h | 20 ++++++++++++++++++++ virt/kvm/arm/hyp/vgic-v2-sr.c | 2 +- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h index 08cd720eae01..4d6b17e23d31 100644 --- a/arch/arm/include/asm/kvm_mmu.h +++ b/arch/arm/include/asm/kvm_mmu.h @@ -28,6 +28,13 @@ */ #define kern_hyp_va(kva) (kva) +/* Contrary to arm64, there is no need to generate a PC-relative address */ +#define hyp_symbol_addr(s) \ + ({ \ + typeof(s) *addr = &(s); \ + addr; \ + }) + /* * KVM_MMU_CACHE_MIN_PAGES is the number of stage2 page table translation levels. */ diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index fe55b516f018..c84e95e0e522 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -130,6 +130,26 @@ static inline unsigned long __kern_hyp_va(unsigned long v) #define kern_hyp_va(v) ((typeof(v))(__kern_hyp_va((unsigned long)(v)))) +/* + * Obtain the PC-relative address of a kernel symbol + * s: symbol + * + * The goal of this macro is to return a symbol's address based on a + * PC-relative computation, as opposed to a loading the VA from a + * constant pool or something similar. This works well for HYP, as an + * absolute VA is guaranteed to be wrong. Only use this if trying to + * obtain the address of a symbol (i.e. not something you obtained by + * following a pointer). + */ +#define hyp_symbol_addr(s) \ + ({ \ + typeof(s) *addr; \ + asm("adrp %0, %1\n" \ + "add %0, %0, :lo12:%1\n" \ + : "=r" (addr) : "S" (&s)); \ + addr; \ + }) + /* * We currently only support a 40bit IPA. */ diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c index d7fd46fe9efb..4b4221b0d4ba 100644 --- a/virt/kvm/arm/hyp/vgic-v2-sr.c +++ b/virt/kvm/arm/hyp/vgic-v2-sr.c @@ -139,7 +139,7 @@ int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu) return -1; rd = kvm_vcpu_dabt_get_rd(vcpu); - addr = kern_hyp_va((kern_hyp_va(&kvm_vgic_global_state))->vcpu_base_va); + addr = kern_hyp_va(hyp_symbol_addr(kvm_vgic_global_state)->vcpu_base_va); addr += fault_ipa - vgic->vgic_cpu_base; if (kvm_vcpu_dabt_iswrite(vcpu)) { -- GitLab From 2cdc2e62a6ac829832c2bf4ccb1098fccc67f82c Mon Sep 17 00:00:00 2001 From: Christoffer Dall Date: Fri, 20 Jul 2018 10:52:58 +0100 Subject: [PATCH 0149/1001] KVM: arm64: Avoid storing the vcpu pointer on the stack Commit 4464e210de9e80e38de59df052fe09ea2ff80b1b upstream. We already have the percpu area for the host cpu state, which points to the VCPU, so there's no need to store the VCPU pointer on the stack on every context switch. We can be a little more clever and just use tpidr_el2 for the percpu offset and load the VCPU pointer from the host context. This has the benefit of being able to retrieve the host context even when our stack is corrupted, and it has a potential performance benefit because we trade a store plus a load for an mrs and a load on a round trip to the guest. This does require us to calculate the percpu offset without including the offset from the kernel mapping of the percpu array to the linear mapping of the array (which is what we store in tpidr_el1), because a PC-relative generated address in EL2 is already giving us the hyp alias of the linear mapping of a kernel address. We do this in __cpu_init_hyp_mode() by using kvm_ksym_ref(). The code that accesses ESR_EL2 was previously using an alternative to use the _EL1 accessor on VHE systems, but this was actually unnecessary as the _EL1 accessor aliases the ESR_EL2 register on VHE, and the _EL2 accessor does the same thing on both systems. Cc: Ard Biesheuvel Reviewed-by: Marc Zyngier Reviewed-by: Andrew Jones Signed-off-by: Christoffer Dall Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/kvm_asm.h | 15 +++++++++++++++ arch/arm64/include/asm/kvm_host.h | 15 +++++++++++++++ arch/arm64/kernel/asm-offsets.c | 1 + arch/arm64/kvm/hyp/entry.S | 6 +----- arch/arm64/kvm/hyp/hyp-entry.S | 28 ++++++++++------------------ arch/arm64/kvm/hyp/switch.c | 5 +---- arch/arm64/kvm/hyp/sysreg-sr.c | 5 +++++ 7 files changed, 48 insertions(+), 27 deletions(-) diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index a7ef5a051911..1ed5cb9c322c 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -33,6 +33,7 @@ #define KVM_ARM64_DEBUG_DIRTY_SHIFT 0 #define KVM_ARM64_DEBUG_DIRTY (1 << KVM_ARM64_DEBUG_DIRTY_SHIFT) +/* Translate a kernel address of @sym into its equivalent linear mapping */ #define kvm_ksym_ref(sym) \ ({ \ void *val = &sym; \ @@ -68,6 +69,20 @@ extern u32 __init_stage2_translation(void); extern void __qcom_hyp_sanitize_btac_predictors(void); +#else /* __ASSEMBLY__ */ + +.macro get_host_ctxt reg, tmp + adr_l \reg, kvm_host_cpu_state + mrs \tmp, tpidr_el2 + add \reg, \reg, \tmp +.endm + +.macro get_vcpu_ptr vcpu, ctxt + get_host_ctxt \ctxt, \vcpu + ldr \vcpu, [\ctxt, #HOST_CONTEXT_VCPU] + kern_hyp_va \vcpu +.endm + #endif #endif /* __ARM_KVM_ASM_H__ */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 7b373e56750f..147389bd87b9 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -350,10 +350,15 @@ int kvm_perf_teardown(void); struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr); +void __kvm_set_tpidr_el2(u64 tpidr_el2); +DECLARE_PER_CPU(kvm_cpu_context_t, kvm_host_cpu_state); + static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr, unsigned long hyp_stack_ptr, unsigned long vector_ptr) { + u64 tpidr_el2; + /* * Call initialization code, and switch to the full blown HYP code. * If the cpucaps haven't been finalized yet, something has gone very @@ -362,6 +367,16 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr, */ BUG_ON(!static_branch_likely(&arm64_const_caps_ready)); __kvm_call_hyp((void *)pgd_ptr, hyp_stack_ptr, vector_ptr); + + /* + * Calculate the raw per-cpu offset without a translation from the + * kernel's mapping to the linear mapping, and store it in tpidr_el2 + * so that we can use adr_l to access per-cpu variables in EL2. + */ + tpidr_el2 = (u64)this_cpu_ptr(&kvm_host_cpu_state) + - (u64)kvm_ksym_ref(kvm_host_cpu_state); + + kvm_call_hyp(__kvm_set_tpidr_el2, tpidr_el2); } static inline void kvm_arch_hardware_unsetup(void) {} diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index af247d10252f..2a1a04c87e9a 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -136,6 +136,7 @@ int main(void) DEFINE(CPU_FP_REGS, offsetof(struct kvm_regs, fp_regs)); DEFINE(VCPU_FPEXC32_EL2, offsetof(struct kvm_vcpu, arch.ctxt.sys_regs[FPEXC32_EL2])); DEFINE(VCPU_HOST_CONTEXT, offsetof(struct kvm_vcpu, arch.host_cpu_context)); + DEFINE(HOST_CONTEXT_VCPU, offsetof(struct kvm_cpu_context, __hyp_running_vcpu)); #endif #ifdef CONFIG_CPU_PM DEFINE(CPU_SUSPEND_SZ, sizeof(struct cpu_suspend_ctx)); diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S index fe4678f20a85..a7b3c198d4de 100644 --- a/arch/arm64/kvm/hyp/entry.S +++ b/arch/arm64/kvm/hyp/entry.S @@ -62,9 +62,6 @@ ENTRY(__guest_enter) // Store the host regs save_callee_saved_regs x1 - // Store host_ctxt and vcpu for use at exit time - stp x1, x0, [sp, #-16]! - add x18, x0, #VCPU_CONTEXT // Restore guest regs x0-x17 @@ -118,8 +115,7 @@ ENTRY(__guest_exit) // Store the guest regs x19-x29, lr save_callee_saved_regs x1 - // Restore the host_ctxt from the stack - ldr x2, [sp], #16 + get_host_ctxt x2, x3 // Now restore the host regs restore_callee_saved_regs x2 diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S index f36464bd57c5..82fbc368f738 100644 --- a/arch/arm64/kvm/hyp/hyp-entry.S +++ b/arch/arm64/kvm/hyp/hyp-entry.S @@ -57,13 +57,8 @@ ENDPROC(__vhe_hyp_call) el1_sync: // Guest trapped into EL2 stp x0, x1, [sp, #-16]! -alternative_if_not ARM64_HAS_VIRT_HOST_EXTN - mrs x1, esr_el2 -alternative_else - mrs x1, esr_el1 -alternative_endif - lsr x0, x1, #ESR_ELx_EC_SHIFT - + mrs x0, esr_el2 + lsr x0, x0, #ESR_ELx_EC_SHIFT cmp x0, #ESR_ELx_EC_HVC64 ccmp x0, #ESR_ELx_EC_HVC32, #4, ne b.ne el1_trap @@ -117,10 +112,14 @@ el1_hvc_guest: eret el1_trap: + get_vcpu_ptr x1, x0 + + mrs x0, esr_el2 + lsr x0, x0, #ESR_ELx_EC_SHIFT /* * x0: ESR_EC + * x1: vcpu pointer */ - ldr x1, [sp, #16 + 8] // vcpu stored by __guest_enter /* * We trap the first access to the FP/SIMD to save the host context @@ -138,13 +137,13 @@ alternative_else_nop_endif el1_irq: stp x0, x1, [sp, #-16]! - ldr x1, [sp, #16 + 8] + get_vcpu_ptr x1, x0 mov x0, #ARM_EXCEPTION_IRQ b __guest_exit el1_error: stp x0, x1, [sp, #-16]! - ldr x1, [sp, #16 + 8] + get_vcpu_ptr x1, x0 mov x0, #ARM_EXCEPTION_EL1_SERROR b __guest_exit @@ -180,14 +179,7 @@ ENTRY(__hyp_do_panic) ENDPROC(__hyp_do_panic) ENTRY(__hyp_panic) - /* - * '=kvm_host_cpu_state' is a host VA from the constant pool, it may - * not be accessible by this address from EL2, hyp_panic() converts - * it with kern_hyp_va() before use. - */ - ldr x0, =kvm_host_cpu_state - mrs x1, tpidr_el2 - add x0, x0, x1 + get_host_ctxt x0, x1 b hyp_panic ENDPROC(__hyp_panic) diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c index 8875bca6868a..1f41b0fe59bc 100644 --- a/arch/arm64/kvm/hyp/switch.c +++ b/arch/arm64/kvm/hyp/switch.c @@ -437,7 +437,7 @@ static hyp_alternate_select(__hyp_call_panic, __hyp_call_panic_nvhe, __hyp_call_panic_vhe, ARM64_HAS_VIRT_HOST_EXTN); -void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt) +void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *host_ctxt) { struct kvm_vcpu *vcpu = NULL; @@ -446,9 +446,6 @@ void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt) u64 par = read_sysreg(par_el1); if (read_sysreg(vttbr_el2)) { - struct kvm_cpu_context *host_ctxt; - - host_ctxt = kern_hyp_va(__host_ctxt); vcpu = host_ctxt->__hyp_running_vcpu; __timer_save_state(vcpu); __deactivate_traps(vcpu); diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c index c54cc2afb92b..e19d89cabf2a 100644 --- a/arch/arm64/kvm/hyp/sysreg-sr.c +++ b/arch/arm64/kvm/hyp/sysreg-sr.c @@ -183,3 +183,8 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu) if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY) write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2); } + +void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2) +{ + asm("msr tpidr_el2, %0": : "r" (tpidr_el2)); +} -- GitLab From 1de2719134b5fe1156d04ef2a31a1b8b2307d3ba Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 20 Jul 2018 10:52:59 +0100 Subject: [PATCH 0150/1001] arm/arm64: smccc: Add SMCCC-specific return codes commit eff0e9e1078ea7dc1d794dc50e31baef984c46d7 upstream. We've so far used the PSCI return codes for SMCCC because they were extremely similar. But with the new ARM DEN 0070A specification, "NOT_REQUIRED" (-2) is clashing with PSCI's "PSCI_RET_INVALID_PARAMS". Let's bite the bullet and add SMCCC specific return codes. Users can be repainted as and when required. Acked-by: Will Deacon Reviewed-by: Mark Rutland Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- include/linux/arm-smccc.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h index a031897fca76..c89da86de99f 100644 --- a/include/linux/arm-smccc.h +++ b/include/linux/arm-smccc.h @@ -291,5 +291,10 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1, */ #define arm_smccc_1_1_hvc(...) __arm_smccc_1_1(SMCCC_HVC_INST, __VA_ARGS__) +/* Return codes defined in ARM DEN 0070A */ +#define SMCCC_RET_SUCCESS 0 +#define SMCCC_RET_NOT_SUPPORTED -1 +#define SMCCC_RET_NOT_REQUIRED -2 + #endif /*__ASSEMBLY__*/ #endif /*__LINUX_ARM_SMCCC_H*/ -- GitLab From 5ad09d2abb5a0e4193b81c147efc828e13caf2ca Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 20 Jul 2018 10:53:00 +0100 Subject: [PATCH 0151/1001] arm64: Call ARCH_WORKAROUND_2 on transitions between EL0 and EL1 commit 8e2906245f1e3b0d027169d9f2e55ce0548cb96e upstream. In order for the kernel to protect itself, let's call the SSBD mitigation implemented by the higher exception level (either hypervisor or firmware) on each transition between userspace and kernel. We must take the PSCI conduit into account in order to target the right exception level, hence the introduction of a runtime patching callback. Reviewed-by: Mark Rutland Reviewed-by: Julien Grall Acked-by: Will Deacon Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/cpu_errata.c | 24 ++++++++++++++++++++++++ arch/arm64/kernel/entry.S | 22 ++++++++++++++++++++++ include/linux/arm-smccc.h | 5 +++++ 3 files changed, 51 insertions(+) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index b5a28336c077..44798a700f6c 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -228,6 +228,30 @@ static int qcom_enable_link_stack_sanitization(void *data) } #endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ +#ifdef CONFIG_ARM64_SSBD +void __init arm64_update_smccc_conduit(struct alt_instr *alt, + __le32 *origptr, __le32 *updptr, + int nr_inst) +{ + u32 insn; + + BUG_ON(nr_inst != 1); + + switch (psci_ops.conduit) { + case PSCI_CONDUIT_HVC: + insn = aarch64_insn_get_hvc_value(); + break; + case PSCI_CONDUIT_SMC: + insn = aarch64_insn_get_smc_value(); + break; + default: + return; + } + + *updptr = cpu_to_le32(insn); +} +#endif /* CONFIG_ARM64_SSBD */ + #define MIDR_RANGE(model, min, max) \ .def_scope = SCOPE_LOCAL_CPU, \ .matches = is_affected_midr_range, \ diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 93958d1341bb..f9473efee9c5 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -18,6 +18,7 @@ * along with this program. If not, see . */ +#include #include #include @@ -137,6 +138,18 @@ alternative_else_nop_endif add \dst, \dst, #(\sym - .entry.tramp.text) .endm + // This macro corrupts x0-x3. It is the caller's duty + // to save/restore them if required. + .macro apply_ssbd, state +#ifdef CONFIG_ARM64_SSBD + mov w0, #ARM_SMCCC_ARCH_WORKAROUND_2 + mov w1, #\state +alternative_cb arm64_update_smccc_conduit + nop // Patched to SMC/HVC #0 +alternative_cb_end +#endif + .endm + .macro kernel_entry, el, regsize = 64 .if \regsize == 32 mov w0, w0 // zero upper 32 bits of x0 @@ -163,6 +176,13 @@ alternative_else_nop_endif ldr x19, [tsk, #TSK_TI_FLAGS] // since we can unmask debug disable_step_tsk x19, x20 // exceptions when scheduling. + apply_ssbd 1 + +#ifdef CONFIG_ARM64_SSBD + ldp x0, x1, [sp, #16 * 0] + ldp x2, x3, [sp, #16 * 1] +#endif + mov x29, xzr // fp pointed to user-space .else add x21, sp, #S_FRAME_SIZE @@ -301,6 +321,8 @@ alternative_if ARM64_WORKAROUND_845719 alternative_else_nop_endif #endif 3: + apply_ssbd 0 + .endif msr elr_el1, x21 // set up the return data diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h index c89da86de99f..ca1d2cc2cdfa 100644 --- a/include/linux/arm-smccc.h +++ b/include/linux/arm-smccc.h @@ -80,6 +80,11 @@ ARM_SMCCC_SMC_32, \ 0, 0x8000) +#define ARM_SMCCC_ARCH_WORKAROUND_2 \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + 0, 0x7fff) + #ifndef __ASSEMBLY__ #include -- GitLab From 1bffd48690119d79468355ebcf992475beefb0b5 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 20 Jul 2018 10:53:01 +0100 Subject: [PATCH 0152/1001] arm64: Add per-cpu infrastructure to call ARCH_WORKAROUND_2 commit 5cf9ce6e5ea50f805c6188c04ed0daaec7b6887d upstream. In a heterogeneous system, we can end up with both affected and unaffected CPUs. Let's check their status before calling into the firmware. Reviewed-by: Julien Grall Reviewed-by: Mark Rutland Acked-by: Will Deacon Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/cpu_errata.c | 2 ++ arch/arm64/kernel/entry.S | 11 +++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 44798a700f6c..62530ba60497 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -229,6 +229,8 @@ static int qcom_enable_link_stack_sanitization(void *data) #endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ #ifdef CONFIG_ARM64_SSBD +DEFINE_PER_CPU_READ_MOSTLY(u64, arm64_ssbd_callback_required); + void __init arm64_update_smccc_conduit(struct alt_instr *alt, __le32 *origptr, __le32 *updptr, int nr_inst) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index f9473efee9c5..caa77d060af1 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -140,8 +140,10 @@ alternative_else_nop_endif // This macro corrupts x0-x3. It is the caller's duty // to save/restore them if required. - .macro apply_ssbd, state + .macro apply_ssbd, state, targ, tmp1, tmp2 #ifdef CONFIG_ARM64_SSBD + ldr_this_cpu \tmp2, arm64_ssbd_callback_required, \tmp1 + cbz \tmp2, \targ mov w0, #ARM_SMCCC_ARCH_WORKAROUND_2 mov w1, #\state alternative_cb arm64_update_smccc_conduit @@ -176,12 +178,13 @@ alternative_cb_end ldr x19, [tsk, #TSK_TI_FLAGS] // since we can unmask debug disable_step_tsk x19, x20 // exceptions when scheduling. - apply_ssbd 1 + apply_ssbd 1, 1f, x22, x23 #ifdef CONFIG_ARM64_SSBD ldp x0, x1, [sp, #16 * 0] ldp x2, x3, [sp, #16 * 1] #endif +1: mov x29, xzr // fp pointed to user-space .else @@ -321,8 +324,8 @@ alternative_if ARM64_WORKAROUND_845719 alternative_else_nop_endif #endif 3: - apply_ssbd 0 - + apply_ssbd 0, 5f, x0, x1 +5: .endif msr elr_el1, x21 // set up the return data -- GitLab From 837c87c233c1cbf53c8576c2c1a269dce8d68d65 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 20 Jul 2018 10:53:02 +0100 Subject: [PATCH 0153/1001] arm64: Add ARCH_WORKAROUND_2 probing commit a725e3dda1813ed306734823ac4c65ca04e38500 upstream. As for Spectre variant-2, we rely on SMCCC 1.1 to provide the discovery mechanism for detecting the SSBD mitigation. A new capability is also allocated for that purpose, and a config option. Reviewed-by: Julien Grall Reviewed-by: Mark Rutland Acked-by: Will Deacon Reviewed-by: Suzuki K Poulose Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm64/Kconfig | 9 +++++ arch/arm64/include/asm/cpucaps.h | 3 +- arch/arm64/kernel/cpu_errata.c | 69 ++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 2d5f7aca156d..1bbb89d37f57 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -849,6 +849,15 @@ config HARDEN_BRANCH_PREDICTOR If unsure, say Y. +config ARM64_SSBD + bool "Speculative Store Bypass Disable" if EXPERT + default y + help + This enables mitigation of the bypassing of previous stores + by speculative loads. + + If unsure, say Y. + menuconfig ARMV8_DEPRECATED bool "Emulate deprecated/obsolete ARMv8 instructions" depends on COMPAT diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h index 2e7b236bc596..76c0d23ca161 100644 --- a/arch/arm64/include/asm/cpucaps.h +++ b/arch/arm64/include/asm/cpucaps.h @@ -43,7 +43,8 @@ #define ARM64_UNMAP_KERNEL_AT_EL0 23 #define ARM64_HARDEN_BRANCH_PREDICTOR 24 #define ARM64_HARDEN_BP_POST_GUEST_EXIT 25 +#define ARM64_SSBD 26 -#define ARM64_NCAPS 26 +#define ARM64_NCAPS 27 #endif /* __ASM_CPUCAPS_H */ diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 62530ba60497..86cd3b690f35 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -252,6 +252,67 @@ void __init arm64_update_smccc_conduit(struct alt_instr *alt, *updptr = cpu_to_le32(insn); } + +static void arm64_set_ssbd_mitigation(bool state) +{ + switch (psci_ops.conduit) { + case PSCI_CONDUIT_HVC: + arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_2, state, NULL); + break; + + case PSCI_CONDUIT_SMC: + arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_2, state, NULL); + break; + + default: + WARN_ON_ONCE(1); + break; + } +} + +static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, + int scope) +{ + struct arm_smccc_res res; + bool supported = true; + + WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible()); + + if (psci_ops.smccc_version == SMCCC_VERSION_1_0) + return false; + + /* + * The probe function return value is either negative + * (unsupported or mitigated), positive (unaffected), or zero + * (requires mitigation). We only need to do anything in the + * last case. + */ + switch (psci_ops.conduit) { + case PSCI_CONDUIT_HVC: + arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, + ARM_SMCCC_ARCH_WORKAROUND_2, &res); + if ((int)res.a0 != 0) + supported = false; + break; + + case PSCI_CONDUIT_SMC: + arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, + ARM_SMCCC_ARCH_WORKAROUND_2, &res); + if ((int)res.a0 != 0) + supported = false; + break; + + default: + supported = false; + } + + if (supported) { + __this_cpu_write(arm64_ssbd_callback_required, 1); + arm64_set_ssbd_mitigation(true); + } + + return supported; +} #endif /* CONFIG_ARM64_SSBD */ #define MIDR_RANGE(model, min, max) \ @@ -451,6 +512,14 @@ const struct arm64_cpu_capabilities arm64_errata[] = { MIDR_ALL_VERSIONS(MIDR_CAVIUM_THUNDERX2), .enable = enable_smccc_arch_workaround_1, }, +#endif +#ifdef CONFIG_ARM64_SSBD + { + .desc = "Speculative Store Bypass Disable", + .def_scope = SCOPE_LOCAL_CPU, + .capability = ARM64_SSBD, + .matches = has_ssbd_mitigation, + }, #endif { } -- GitLab From 45808ab2f9245c2921b6e81025fde46ae6325013 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 20 Jul 2018 10:53:03 +0100 Subject: [PATCH 0154/1001] arm64: Add 'ssbd' command-line option commit a43ae4dfe56a01f5b98ba0cb2f784b6a43bafcc6 upstream. On a system where the firmware implements ARCH_WORKAROUND_2, it may be useful to either permanently enable or disable the workaround for cases where the user decides that they'd rather not get a trap overhead, and keep the mitigation permanently on or off instead of switching it on exception entry/exit. In any case, default to the mitigation being enabled. Reviewed-by: Julien Grall Reviewed-by: Mark Rutland Acked-by: Will Deacon Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- .../admin-guide/kernel-parameters.txt | 17 +++ arch/arm64/include/asm/cpufeature.h | 6 + arch/arm64/kernel/cpu_errata.c | 103 +++++++++++++++--- 3 files changed, 110 insertions(+), 16 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 0380a45ecf4b..d6d7669e667f 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3997,6 +3997,23 @@ expediting. Set to zero to disable automatic expediting. + ssbd= [ARM64,HW] + Speculative Store Bypass Disable control + + On CPUs that are vulnerable to the Speculative + Store Bypass vulnerability and offer a + firmware based mitigation, this parameter + indicates how the mitigation should be used: + + force-on: Unconditionally enable mitigation for + for both kernel and userspace + force-off: Unconditionally disable mitigation for + for both kernel and userspace + kernel: Always enable mitigation in the + kernel, and offer a prctl interface + to allow userspace to register its + interest in being mitigated too. + stack_guard_gap= [MM] override the default stack gap protection. The value is in page units and it defines how many pages prior diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 428ee1f2468c..0bd5ebfb328e 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -262,6 +262,12 @@ static inline bool system_uses_ttbr0_pan(void) !cpus_have_const_cap(ARM64_HAS_PAN); } +#define ARM64_SSBD_UNKNOWN -1 +#define ARM64_SSBD_FORCE_DISABLE 0 +#define ARM64_SSBD_KERNEL 1 +#define ARM64_SSBD_FORCE_ENABLE 2 +#define ARM64_SSBD_MITIGATED 3 + #endif /* __ASSEMBLY__ */ #endif diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 86cd3b690f35..b3df8e5986e0 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -231,6 +231,38 @@ static int qcom_enable_link_stack_sanitization(void *data) #ifdef CONFIG_ARM64_SSBD DEFINE_PER_CPU_READ_MOSTLY(u64, arm64_ssbd_callback_required); +int ssbd_state __read_mostly = ARM64_SSBD_KERNEL; + +static const struct ssbd_options { + const char *str; + int state; +} ssbd_options[] = { + { "force-on", ARM64_SSBD_FORCE_ENABLE, }, + { "force-off", ARM64_SSBD_FORCE_DISABLE, }, + { "kernel", ARM64_SSBD_KERNEL, }, +}; + +static int __init ssbd_cfg(char *buf) +{ + int i; + + if (!buf || !buf[0]) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(ssbd_options); i++) { + int len = strlen(ssbd_options[i].str); + + if (strncmp(buf, ssbd_options[i].str, len)) + continue; + + ssbd_state = ssbd_options[i].state; + return 0; + } + + return -EINVAL; +} +early_param("ssbd", ssbd_cfg); + void __init arm64_update_smccc_conduit(struct alt_instr *alt, __le32 *origptr, __le32 *updptr, int nr_inst) @@ -274,44 +306,83 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, int scope) { struct arm_smccc_res res; - bool supported = true; + bool required = true; + s32 val; WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible()); - if (psci_ops.smccc_version == SMCCC_VERSION_1_0) + if (psci_ops.smccc_version == SMCCC_VERSION_1_0) { + ssbd_state = ARM64_SSBD_UNKNOWN; return false; + } - /* - * The probe function return value is either negative - * (unsupported or mitigated), positive (unaffected), or zero - * (requires mitigation). We only need to do anything in the - * last case. - */ switch (psci_ops.conduit) { case PSCI_CONDUIT_HVC: arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_ARCH_WORKAROUND_2, &res); - if ((int)res.a0 != 0) - supported = false; break; case PSCI_CONDUIT_SMC: arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_ARCH_WORKAROUND_2, &res); - if ((int)res.a0 != 0) - supported = false; break; default: - supported = false; + ssbd_state = ARM64_SSBD_UNKNOWN; + return false; + } + + val = (s32)res.a0; + + switch (val) { + case SMCCC_RET_NOT_SUPPORTED: + ssbd_state = ARM64_SSBD_UNKNOWN; + return false; + + case SMCCC_RET_NOT_REQUIRED: + pr_info_once("%s mitigation not required\n", entry->desc); + ssbd_state = ARM64_SSBD_MITIGATED; + return false; + + case SMCCC_RET_SUCCESS: + required = true; + break; + + case 1: /* Mitigation not required on this CPU */ + required = false; + break; + + default: + WARN_ON(1); + return false; } - if (supported) { - __this_cpu_write(arm64_ssbd_callback_required, 1); + switch (ssbd_state) { + case ARM64_SSBD_FORCE_DISABLE: + pr_info_once("%s disabled from command-line\n", entry->desc); + arm64_set_ssbd_mitigation(false); + required = false; + break; + + case ARM64_SSBD_KERNEL: + if (required) { + __this_cpu_write(arm64_ssbd_callback_required, 1); + arm64_set_ssbd_mitigation(true); + } + break; + + case ARM64_SSBD_FORCE_ENABLE: + pr_info_once("%s forced from command-line\n", entry->desc); arm64_set_ssbd_mitigation(true); + required = true; + break; + + default: + WARN_ON(1); + break; } - return supported; + return required; } #endif /* CONFIG_ARM64_SSBD */ -- GitLab From 8d6907af4583eec62e4eb7f839da3c33d570556e Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 20 Jul 2018 10:53:04 +0100 Subject: [PATCH 0155/1001] arm64: ssbd: Add global mitigation state accessor commit c32e1736ca03904c03de0e4459a673be194f56fd upstream. We're about to need the mitigation state in various parts of the kernel in order to do the right thing for userspace and guests. Let's expose an accessor that will let other subsystems know about the state. Reviewed-by: Julien Grall Reviewed-by: Mark Rutland Acked-by: Will Deacon Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/cpufeature.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 0bd5ebfb328e..a2415ee6b8a3 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -268,6 +268,16 @@ static inline bool system_uses_ttbr0_pan(void) #define ARM64_SSBD_FORCE_ENABLE 2 #define ARM64_SSBD_MITIGATED 3 +static inline int arm64_get_ssbd_state(void) +{ +#ifdef CONFIG_ARM64_SSBD + extern int ssbd_state; + return ssbd_state; +#else + return ARM64_SSBD_UNKNOWN; +#endif +} + #endif /* __ASSEMBLY__ */ #endif -- GitLab From 02e26bd9ad58197533a7d5fcd62f975891a9e936 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 20 Jul 2018 10:53:05 +0100 Subject: [PATCH 0156/1001] arm64: ssbd: Skip apply_ssbd if not using dynamic mitigation commit 986372c4367f46b34a3c0f6918d7fb95cbdf39d6 upstream. In order to avoid checking arm64_ssbd_callback_required on each kernel entry/exit even if no mitigation is required, let's add yet another alternative that by default jumps over the mitigation, and that gets nop'ed out if we're doing dynamic mitigation. Think of it as a poor man's static key... Reviewed-by: Julien Grall Reviewed-by: Mark Rutland Acked-by: Will Deacon Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/cpu_errata.c | 14 ++++++++++++++ arch/arm64/kernel/entry.S | 3 +++ 2 files changed, 17 insertions(+) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index b3df8e5986e0..012dab9d9a01 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -285,6 +285,20 @@ void __init arm64_update_smccc_conduit(struct alt_instr *alt, *updptr = cpu_to_le32(insn); } +void __init arm64_enable_wa2_handling(struct alt_instr *alt, + __le32 *origptr, __le32 *updptr, + int nr_inst) +{ + BUG_ON(nr_inst != 1); + /* + * Only allow mitigation on EL1 entry/exit and guest + * ARCH_WORKAROUND_2 handling if the SSBD state allows it to + * be flipped. + */ + if (arm64_get_ssbd_state() == ARM64_SSBD_KERNEL) + *updptr = cpu_to_le32(aarch64_insn_gen_nop()); +} + static void arm64_set_ssbd_mitigation(bool state) { switch (psci_ops.conduit) { diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index caa77d060af1..5a585976d14c 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -142,6 +142,9 @@ alternative_else_nop_endif // to save/restore them if required. .macro apply_ssbd, state, targ, tmp1, tmp2 #ifdef CONFIG_ARM64_SSBD +alternative_cb arm64_enable_wa2_handling + b \targ +alternative_cb_end ldr_this_cpu \tmp2, arm64_ssbd_callback_required, \tmp1 cbz \tmp2, \targ mov w0, #ARM_SMCCC_ARCH_WORKAROUND_2 -- GitLab From c5c89bb4deb8e1f0eed0968f37dfa936f6b5e4c1 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 20 Jul 2018 10:53:06 +0100 Subject: [PATCH 0157/1001] arm64: ssbd: Restore mitigation status on CPU resume commit 647d0519b53f440a55df163de21c52a8205431cc upstream. On a system where firmware can dynamically change the state of the mitigation, the CPU will always come up with the mitigation enabled, including when coming back from suspend. If the user has requested "no mitigation" via a command line option, let's enforce it by calling into the firmware again to disable it. Similarily, for a resume from hibernate, the mitigation could have been disabled by the boot kernel. Let's ensure that it is set back on in that case. Acked-by: Will Deacon Reviewed-by: Mark Rutland Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/cpufeature.h | 6 ++++++ arch/arm64/kernel/cpu_errata.c | 2 +- arch/arm64/kernel/hibernate.c | 11 +++++++++++ arch/arm64/kernel/suspend.c | 8 ++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index a2415ee6b8a3..c5bc80a03515 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -278,6 +278,12 @@ static inline int arm64_get_ssbd_state(void) #endif } +#ifdef CONFIG_ARM64_SSBD +void arm64_set_ssbd_mitigation(bool state); +#else +static inline void arm64_set_ssbd_mitigation(bool state) {} +#endif + #endif /* __ASSEMBLY__ */ #endif diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 012dab9d9a01..eccdb28b4a39 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -299,7 +299,7 @@ void __init arm64_enable_wa2_handling(struct alt_instr *alt, *updptr = cpu_to_le32(aarch64_insn_gen_nop()); } -static void arm64_set_ssbd_mitigation(bool state) +void arm64_set_ssbd_mitigation(bool state) { switch (psci_ops.conduit) { case PSCI_CONDUIT_HVC: diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c index 095d3c170f5d..a028cc95afe1 100644 --- a/arch/arm64/kernel/hibernate.c +++ b/arch/arm64/kernel/hibernate.c @@ -313,6 +313,17 @@ int swsusp_arch_suspend(void) sleep_cpu = -EINVAL; __cpu_suspend_exit(); + + /* + * Just in case the boot kernel did turn the SSBD + * mitigation off behind our back, let's set the state + * to what we expect it to be. + */ + switch (arm64_get_ssbd_state()) { + case ARM64_SSBD_FORCE_ENABLE: + case ARM64_SSBD_KERNEL: + arm64_set_ssbd_mitigation(true); + } } local_dbg_restore(flags); diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c index 77cd655e6eb7..7a655e60cf4b 100644 --- a/arch/arm64/kernel/suspend.c +++ b/arch/arm64/kernel/suspend.c @@ -62,6 +62,14 @@ void notrace __cpu_suspend_exit(void) */ if (hw_breakpoint_restore) hw_breakpoint_restore(cpu); + + /* + * On resume, firmware implementing dynamic mitigation will + * have turned the mitigation on. If the user has forcefully + * disabled it, make sure their wishes are obeyed. + */ + if (arm64_get_ssbd_state() == ARM64_SSBD_FORCE_DISABLE) + arm64_set_ssbd_mitigation(false); } /* -- GitLab From e7d02797288f12ca257cdab49d19ccf9b3d2cb12 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 20 Jul 2018 10:53:07 +0100 Subject: [PATCH 0158/1001] arm64: ssbd: Introduce thread flag to control userspace mitigation commit 9dd9614f5476687abbff8d4b12cd08ae70d7c2ad upstream. In order to allow userspace to be mitigated on demand, let's introduce a new thread flag that prevents the mitigation from being turned off when exiting to userspace, and doesn't turn it on on entry into the kernel (with the assumption that the mitigation is always enabled in the kernel itself). This will be used by a prctl interface introduced in a later patch. Reviewed-by: Mark Rutland Acked-by: Will Deacon Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/thread_info.h | 1 + arch/arm64/kernel/entry.S | 2 ++ 2 files changed, 3 insertions(+) diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index ddded6497a8a..fc786d344e46 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -92,6 +92,7 @@ void arch_setup_new_exec(void); #define TIF_RESTORE_SIGMASK 20 #define TIF_SINGLESTEP 21 #define TIF_32BIT 22 /* 32bit process */ +#define TIF_SSBD 23 /* Wants SSB mitigation */ #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 5a585976d14c..c1ffa95c0ad2 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -147,6 +147,8 @@ alternative_cb arm64_enable_wa2_handling alternative_cb_end ldr_this_cpu \tmp2, arm64_ssbd_callback_required, \tmp1 cbz \tmp2, \targ + ldr \tmp2, [tsk, #TSK_TI_FLAGS] + tbnz \tmp2, #TIF_SSBD, \targ mov w0, #ARM_SMCCC_ARCH_WORKAROUND_2 mov w1, #\state alternative_cb arm64_update_smccc_conduit -- GitLab From b769d86ea9d4b2d77387791cc747462b19e8af22 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 20 Jul 2018 10:53:08 +0100 Subject: [PATCH 0159/1001] arm64: ssbd: Add prctl interface for per-thread mitigation commit 9cdc0108baa8ef87c76ed834619886a46bd70cbe upstream. If running on a system that performs dynamic SSBD mitigation, allow userspace to request the mitigation for itself. This is implemented as a prctl call, allowing the mitigation to be enabled or disabled at will for this particular thread. Acked-by: Will Deacon Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/ssbd.c | 108 +++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 arch/arm64/kernel/ssbd.c diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index def8d5623fd1..714fe90dbf66 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -54,6 +54,7 @@ arm64-obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o \ arm64-obj-$(CONFIG_ARM64_RELOC_TEST) += arm64-reloc-test.o arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o +arm64-obj-$(CONFIG_ARM64_SSBD) += ssbd.o ifeq ($(CONFIG_KVM),y) arm64-obj-$(CONFIG_HARDEN_BRANCH_PREDICTOR) += bpi.o diff --git a/arch/arm64/kernel/ssbd.c b/arch/arm64/kernel/ssbd.c new file mode 100644 index 000000000000..0560738c1d5c --- /dev/null +++ b/arch/arm64/kernel/ssbd.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 ARM Ltd, All Rights Reserved. + */ + +#include +#include +#include +#include + +#include + +/* + * prctl interface for SSBD + */ +static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl) +{ + int state = arm64_get_ssbd_state(); + + /* Unsupported */ + if (state == ARM64_SSBD_UNKNOWN) + return -EINVAL; + + /* Treat the unaffected/mitigated state separately */ + if (state == ARM64_SSBD_MITIGATED) { + switch (ctrl) { + case PR_SPEC_ENABLE: + return -EPERM; + case PR_SPEC_DISABLE: + case PR_SPEC_FORCE_DISABLE: + return 0; + } + } + + /* + * Things are a bit backward here: the arm64 internal API + * *enables the mitigation* when the userspace API *disables + * speculation*. So much fun. + */ + switch (ctrl) { + case PR_SPEC_ENABLE: + /* If speculation is force disabled, enable is not allowed */ + if (state == ARM64_SSBD_FORCE_ENABLE || + task_spec_ssb_force_disable(task)) + return -EPERM; + task_clear_spec_ssb_disable(task); + clear_tsk_thread_flag(task, TIF_SSBD); + break; + case PR_SPEC_DISABLE: + if (state == ARM64_SSBD_FORCE_DISABLE) + return -EPERM; + task_set_spec_ssb_disable(task); + set_tsk_thread_flag(task, TIF_SSBD); + break; + case PR_SPEC_FORCE_DISABLE: + if (state == ARM64_SSBD_FORCE_DISABLE) + return -EPERM; + task_set_spec_ssb_disable(task); + task_set_spec_ssb_force_disable(task); + set_tsk_thread_flag(task, TIF_SSBD); + break; + default: + return -ERANGE; + } + + return 0; +} + +int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which, + unsigned long ctrl) +{ + switch (which) { + case PR_SPEC_STORE_BYPASS: + return ssbd_prctl_set(task, ctrl); + default: + return -ENODEV; + } +} + +static int ssbd_prctl_get(struct task_struct *task) +{ + switch (arm64_get_ssbd_state()) { + case ARM64_SSBD_UNKNOWN: + return -EINVAL; + case ARM64_SSBD_FORCE_ENABLE: + return PR_SPEC_DISABLE; + case ARM64_SSBD_KERNEL: + if (task_spec_ssb_force_disable(task)) + return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE; + if (task_spec_ssb_disable(task)) + return PR_SPEC_PRCTL | PR_SPEC_DISABLE; + return PR_SPEC_PRCTL | PR_SPEC_ENABLE; + case ARM64_SSBD_FORCE_DISABLE: + return PR_SPEC_ENABLE; + default: + return PR_SPEC_NOT_AFFECTED; + } +} + +int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which) +{ + switch (which) { + case PR_SPEC_STORE_BYPASS: + return ssbd_prctl_get(task); + default: + return -ENODEV; + } +} -- GitLab From 0592871918f0acf369cec5c88de1fa76dbf2c1a2 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 20 Jul 2018 10:53:09 +0100 Subject: [PATCH 0160/1001] arm64: KVM: Add HYP per-cpu accessors commit 85478bab409171de501b719971fd25a3d5d639f9 upstream. As we're going to require to access per-cpu variables at EL2, let's craft the minimum set of accessors required to implement reading a per-cpu variable, relying on tpidr_el2 to contain the per-cpu offset. Reviewed-by: Christoffer Dall Reviewed-by: Mark Rutland Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/kvm_asm.h | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index 1ed5cb9c322c..b956418f73bd 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -69,14 +69,37 @@ extern u32 __init_stage2_translation(void); extern void __qcom_hyp_sanitize_btac_predictors(void); +/* Home-grown __this_cpu_{ptr,read} variants that always work at HYP */ +#define __hyp_this_cpu_ptr(sym) \ + ({ \ + void *__ptr = hyp_symbol_addr(sym); \ + __ptr += read_sysreg(tpidr_el2); \ + (typeof(&sym))__ptr; \ + }) + +#define __hyp_this_cpu_read(sym) \ + ({ \ + *__hyp_this_cpu_ptr(sym); \ + }) + #else /* __ASSEMBLY__ */ -.macro get_host_ctxt reg, tmp - adr_l \reg, kvm_host_cpu_state +.macro hyp_adr_this_cpu reg, sym, tmp + adr_l \reg, \sym mrs \tmp, tpidr_el2 add \reg, \reg, \tmp .endm +.macro hyp_ldr_this_cpu reg, sym, tmp + adr_l \reg, \sym + mrs \tmp, tpidr_el2 + ldr \reg, [\reg, \tmp] +.endm + +.macro get_host_ctxt reg, tmp + hyp_adr_this_cpu \reg, kvm_host_cpu_state, \tmp +.endm + .macro get_vcpu_ptr vcpu, ctxt get_host_ctxt \ctxt, \vcpu ldr \vcpu, [\ctxt, #HOST_CONTEXT_VCPU] -- GitLab From 805357aa65bbc419451fb9556968687c7fd1d2e1 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 20 Jul 2018 10:53:10 +0100 Subject: [PATCH 0161/1001] arm64: KVM: Add ARCH_WORKAROUND_2 support for guests commit 55e3748e8902ff641e334226bdcb432f9a5d78d3 upstream. In order to offer ARCH_WORKAROUND_2 support to guests, we need a bit of infrastructure. Let's add a flag indicating whether or not the guest uses SSBD mitigation. Depending on the state of this flag, allow KVM to disable ARCH_WORKAROUND_2 before entering the guest, and enable it when exiting it. Reviewed-by: Christoffer Dall Reviewed-by: Mark Rutland Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/kvm_mmu.h | 5 ++++ arch/arm64/include/asm/kvm_asm.h | 3 +++ arch/arm64/include/asm/kvm_host.h | 3 +++ arch/arm64/include/asm/kvm_mmu.h | 24 +++++++++++++++++++ arch/arm64/kvm/hyp/switch.c | 38 +++++++++++++++++++++++++++++++ virt/kvm/arm/arm.c | 4 ++++ 6 files changed, 77 insertions(+) diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h index 4d6b17e23d31..8a098e65f5f8 100644 --- a/arch/arm/include/asm/kvm_mmu.h +++ b/arch/arm/include/asm/kvm_mmu.h @@ -254,6 +254,11 @@ static inline int kvm_map_vectors(void) return 0; } +static inline int hyp_map_aux_data(void) +{ + return 0; +} + #endif /* !__ASSEMBLY__ */ #endif /* __ARM_KVM_MMU_H__ */ diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index b956418f73bd..1a6d02350fc6 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -33,6 +33,9 @@ #define KVM_ARM64_DEBUG_DIRTY_SHIFT 0 #define KVM_ARM64_DEBUG_DIRTY (1 << KVM_ARM64_DEBUG_DIRTY_SHIFT) +#define VCPU_WORKAROUND_2_FLAG_SHIFT 0 +#define VCPU_WORKAROUND_2_FLAG (_AC(1, UL) << VCPU_WORKAROUND_2_FLAG_SHIFT) + /* Translate a kernel address of @sym into its equivalent linear mapping */ #define kvm_ksym_ref(sym) \ ({ \ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 147389bd87b9..3d1774bcf108 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -210,6 +210,9 @@ struct kvm_vcpu_arch { /* Exception Information */ struct kvm_vcpu_fault_info fault; + /* State of various workarounds, see kvm_asm.h for bit assignment */ + u64 workaround_flags; + /* Guest debug state */ u64 debug_flags; diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index c84e95e0e522..e42c1f0ae6cf 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -383,5 +383,29 @@ static inline int kvm_map_vectors(void) } #endif +#ifdef CONFIG_ARM64_SSBD +DECLARE_PER_CPU_READ_MOSTLY(u64, arm64_ssbd_callback_required); + +static inline int hyp_map_aux_data(void) +{ + int cpu, err; + + for_each_possible_cpu(cpu) { + u64 *ptr; + + ptr = per_cpu_ptr(&arm64_ssbd_callback_required, cpu); + err = create_hyp_mappings(ptr, ptr + 1, PAGE_HYP); + if (err) + return err; + } + return 0; +} +#else +static inline int hyp_map_aux_data(void) +{ + return 0; +} +#endif + #endif /* __ASSEMBLY__ */ #endif /* __ARM64_KVM_MMU_H__ */ diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c index 1f41b0fe59bc..b2f1992c6234 100644 --- a/arch/arm64/kvm/hyp/switch.c +++ b/arch/arm64/kvm/hyp/switch.c @@ -15,6 +15,7 @@ * along with this program. If not, see . */ +#include #include #include #include @@ -281,6 +282,39 @@ static void __hyp_text __skip_instr(struct kvm_vcpu *vcpu) write_sysreg_el2(*vcpu_pc(vcpu), elr); } +static inline bool __hyp_text __needs_ssbd_off(struct kvm_vcpu *vcpu) +{ + if (!cpus_have_const_cap(ARM64_SSBD)) + return false; + + return !(vcpu->arch.workaround_flags & VCPU_WORKAROUND_2_FLAG); +} + +static void __hyp_text __set_guest_arch_workaround_state(struct kvm_vcpu *vcpu) +{ +#ifdef CONFIG_ARM64_SSBD + /* + * The host runs with the workaround always present. If the + * guest wants it disabled, so be it... + */ + if (__needs_ssbd_off(vcpu) && + __hyp_this_cpu_read(arm64_ssbd_callback_required)) + arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_2, 0, NULL); +#endif +} + +static void __hyp_text __set_host_arch_workaround_state(struct kvm_vcpu *vcpu) +{ +#ifdef CONFIG_ARM64_SSBD + /* + * If the guest has disabled the workaround, bring it back on. + */ + if (__needs_ssbd_off(vcpu) && + __hyp_this_cpu_read(arm64_ssbd_callback_required)) + arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_2, 1, NULL); +#endif +} + int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) { struct kvm_cpu_context *host_ctxt; @@ -311,6 +345,8 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) __sysreg_restore_guest_state(guest_ctxt); __debug_restore_state(vcpu, kern_hyp_va(vcpu->arch.debug_ptr), guest_ctxt); + __set_guest_arch_workaround_state(vcpu); + /* Jump in the fire! */ again: exit_code = __guest_enter(vcpu, host_ctxt); @@ -367,6 +403,8 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) /* 0 falls through to be handled out of EL2 */ } + __set_host_arch_workaround_state(vcpu); + if (cpus_have_const_cap(ARM64_HARDEN_BP_POST_GUEST_EXIT)) { u32 midr = read_cpuid_id(); diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 4aede98b92eb..d5f1d8364571 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -1411,6 +1411,10 @@ static int init_hyp_mode(void) } } + err = hyp_map_aux_data(); + if (err) + kvm_err("Cannot map host auxilary data: %d\n", err); + return 0; out_err: -- GitLab From 1b749f8a241639951a9c65e64f51e7a6ac5b6ae9 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 20 Jul 2018 10:53:11 +0100 Subject: [PATCH 0162/1001] arm64: KVM: Handle guest's ARCH_WORKAROUND_2 requests commit b4f18c063a13dfb33e3a63fe1844823e19c2265e upstream. In order to forward the guest's ARCH_WORKAROUND_2 calls to EL3, add a small(-ish) sequence to handle it at EL2. Special care must be taken to track the state of the guest itself by updating the workaround flags. We also rely on patching to enable calls into the firmware. Note that since we need to execute branches, this always executes after the Spectre-v2 mitigation has been applied. Reviewed-by: Mark Rutland Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/asm-offsets.c | 1 + arch/arm64/kvm/hyp/hyp-entry.S | 38 ++++++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 2a1a04c87e9a..b5e43b01b396 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -131,6 +131,7 @@ int main(void) BLANK(); #ifdef CONFIG_KVM_ARM_HOST DEFINE(VCPU_CONTEXT, offsetof(struct kvm_vcpu, arch.ctxt)); + DEFINE(VCPU_WORKAROUND_FLAGS, offsetof(struct kvm_vcpu, arch.workaround_flags)); DEFINE(CPU_GP_REGS, offsetof(struct kvm_cpu_context, gp_regs)); DEFINE(CPU_USER_PT_REGS, offsetof(struct kvm_regs, regs)); DEFINE(CPU_FP_REGS, offsetof(struct kvm_regs, fp_regs)); diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S index 82fbc368f738..3c283fd8c8f5 100644 --- a/arch/arm64/kvm/hyp/hyp-entry.S +++ b/arch/arm64/kvm/hyp/hyp-entry.S @@ -106,8 +106,44 @@ el1_hvc_guest: */ ldr x1, [sp] // Guest's x0 eor w1, w1, #ARM_SMCCC_ARCH_WORKAROUND_1 + cbz w1, wa_epilogue + + /* ARM_SMCCC_ARCH_WORKAROUND_2 handling */ + eor w1, w1, #(ARM_SMCCC_ARCH_WORKAROUND_1 ^ \ + ARM_SMCCC_ARCH_WORKAROUND_2) cbnz w1, el1_trap - mov x0, x1 + +#ifdef CONFIG_ARM64_SSBD +alternative_cb arm64_enable_wa2_handling + b wa2_end +alternative_cb_end + get_vcpu_ptr x2, x0 + ldr x0, [x2, #VCPU_WORKAROUND_FLAGS] + + // Sanitize the argument and update the guest flags + ldr x1, [sp, #8] // Guest's x1 + clz w1, w1 // Murphy's device: + lsr w1, w1, #5 // w1 = !!w1 without using + eor w1, w1, #1 // the flags... + bfi x0, x1, #VCPU_WORKAROUND_2_FLAG_SHIFT, #1 + str x0, [x2, #VCPU_WORKAROUND_FLAGS] + + /* Check that we actually need to perform the call */ + hyp_ldr_this_cpu x0, arm64_ssbd_callback_required, x2 + cbz x0, wa2_end + + mov w0, #ARM_SMCCC_ARCH_WORKAROUND_2 + smc #0 + + /* Don't leak data from the SMC call */ + mov x3, xzr +wa2_end: + mov x2, xzr + mov x1, xzr +#endif + +wa_epilogue: + mov x0, xzr add sp, sp, #16 eret -- GitLab From 96fd60c8160c16dd16542efe4491f0d096d5c1b4 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 20 Jul 2018 10:53:12 +0100 Subject: [PATCH 0163/1001] arm64: KVM: Add ARCH_WORKAROUND_2 discovery through ARCH_FEATURES_FUNC_ID commit 5d81f7dc9bca4f4963092433e27b508cbe524a32 upstream. Now that all our infrastructure is in place, let's expose the availability of ARCH_WORKAROUND_2 to guests. We take this opportunity to tidy up a couple of SMCCC constants. Acked-by: Christoffer Dall Reviewed-by: Mark Rutland Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/kvm_host.h | 12 ++++++++++++ arch/arm64/include/asm/kvm_host.h | 23 +++++++++++++++++++++++ arch/arm64/kvm/reset.c | 4 ++++ virt/kvm/arm/psci.c | 18 ++++++++++++++++-- 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 8f973e3b7348..65572e14306c 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -302,4 +302,16 @@ static inline bool kvm_arm_harden_branch_predictor(void) return false; } +#define KVM_SSBD_UNKNOWN -1 +#define KVM_SSBD_FORCE_DISABLE 0 +#define KVM_SSBD_KERNEL 1 +#define KVM_SSBD_FORCE_ENABLE 2 +#define KVM_SSBD_MITIGATED 3 + +static inline int kvm_arm_have_ssbd(void) +{ + /* No way to detect it yet, pretend it is not there. */ + return KVM_SSBD_UNKNOWN; +} + #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 3d1774bcf108..b01ad3489bd8 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -412,4 +412,27 @@ static inline bool kvm_arm_harden_branch_predictor(void) return cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR); } +#define KVM_SSBD_UNKNOWN -1 +#define KVM_SSBD_FORCE_DISABLE 0 +#define KVM_SSBD_KERNEL 1 +#define KVM_SSBD_FORCE_ENABLE 2 +#define KVM_SSBD_MITIGATED 3 + +static inline int kvm_arm_have_ssbd(void) +{ + switch (arm64_get_ssbd_state()) { + case ARM64_SSBD_FORCE_DISABLE: + return KVM_SSBD_FORCE_DISABLE; + case ARM64_SSBD_KERNEL: + return KVM_SSBD_KERNEL; + case ARM64_SSBD_FORCE_ENABLE: + return KVM_SSBD_FORCE_ENABLE; + case ARM64_SSBD_MITIGATED: + return KVM_SSBD_MITIGATED; + case ARM64_SSBD_UNKNOWN: + default: + return KVM_SSBD_UNKNOWN; + } +} + #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 3256b9228e75..a74311beda35 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -122,6 +122,10 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) /* Reset PMU */ kvm_pmu_vcpu_reset(vcpu); + /* Default workaround setup is enabled (if supported) */ + if (kvm_arm_have_ssbd() == KVM_SSBD_KERNEL) + vcpu->arch.workaround_flags |= VCPU_WORKAROUND_2_FLAG; + /* Reset timer */ return kvm_timer_vcpu_reset(vcpu); } diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c index c4762bef13c6..c95ab4c5a475 100644 --- a/virt/kvm/arm/psci.c +++ b/virt/kvm/arm/psci.c @@ -405,7 +405,7 @@ static int kvm_psci_call(struct kvm_vcpu *vcpu) int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) { u32 func_id = smccc_get_function(vcpu); - u32 val = PSCI_RET_NOT_SUPPORTED; + u32 val = SMCCC_RET_NOT_SUPPORTED; u32 feature; switch (func_id) { @@ -417,7 +417,21 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) switch(feature) { case ARM_SMCCC_ARCH_WORKAROUND_1: if (kvm_arm_harden_branch_predictor()) - val = 0; + val = SMCCC_RET_SUCCESS; + break; + case ARM_SMCCC_ARCH_WORKAROUND_2: + switch (kvm_arm_have_ssbd()) { + case KVM_SSBD_FORCE_DISABLE: + case KVM_SSBD_UNKNOWN: + break; + case KVM_SSBD_KERNEL: + val = SMCCC_RET_SUCCESS; + break; + case KVM_SSBD_FORCE_ENABLE: + case KVM_SSBD_MITIGATED: + val = SMCCC_RET_NOT_REQUIRED; + break; + } break; } break; -- GitLab From 779128d80cb01e6434936e13754fc25a1cc30929 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Jan 2018 07:21:15 -0800 Subject: [PATCH 0164/1001] string: drop __must_check from strscpy() and restore strscpy() usages in cgroup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 08a77676f9c5fc69a681ccd2cd8140e65dcb26c7 upstream. e7fd37ba1217 ("cgroup: avoid copying strings longer than the buffers") converted possibly unsafe strncpy() usages in cgroup to strscpy(). However, although the callsites are completely fine with truncated copied, because strscpy() is marked __must_check, it led to the following warnings. kernel/cgroup/cgroup.c: In function ‘cgroup_file_name’: kernel/cgroup/cgroup.c:1400:10: warning: ignoring return value of ‘strscpy’, declared with attribute warn_unused_result [-Wunused-result] strscpy(buf, cft->name, CGROUP_FILE_NAME_MAX); ^ To avoid the warnings, 50034ed49645 ("cgroup: use strlcpy() instead of strscpy() to avoid spurious warning") switched them to strlcpy(). strlcpy() is worse than strlcpy() because it unconditionally runs strlen() on the source string, and the only reason we switched to strlcpy() here was because it was lacking __must_check, which doesn't reflect any material differences between the two function. It's just that someone added __must_check to strscpy() and not to strlcpy(). These basic string copy operations are used in variety of ways, and one of not-so-uncommon use cases is safely handling truncated copies, where the caller naturally doesn't care about the return value. The __must_check doesn't match the actual use cases and forces users to opt for inferior variants which lack __must_check by happenstance or spread ugly (void) casts. Remove __must_check from strscpy() and restore strscpy() usages in cgroup. Signed-off-by: Tejun Heo Suggested-by: Linus Torvalds Cc: Ma Shimiao Cc: Arnd Bergmann Cc: Chris Metcalf [backport only the string.h portion to remove build warnings starting to show up - gregkh] Signed-off-by: Greg Kroah-Hartman --- include/linux/string.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/string.h b/include/linux/string.h index cfd83eb2f926..96115bf561b4 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -28,7 +28,7 @@ extern char * strncpy(char *,const char *, __kernel_size_t); size_t strlcpy(char *, const char *, size_t); #endif #ifndef __HAVE_ARCH_STRSCPY -ssize_t __must_check strscpy(char *, const char *, size_t); +ssize_t strscpy(char *, const char *, size_t); #endif #ifndef __HAVE_ARCH_STRCAT extern char * strcat(char *, const char *); -- GitLab From ecc160ece609498c946e73710e5c7c54c62b966a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 22 Jul 2018 14:28:52 +0200 Subject: [PATCH 0165/1001] Linux 4.14.57 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index acbb0e3d29c9..a44d6b2adb76 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 56 +SUBLEVEL = 57 EXTRAVERSION = NAME = Petit Gorille -- GitLab From ebb9209484abff8f80757a616e9ef5148cb063a4 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Wed, 21 Jun 2017 09:22:45 +0530 Subject: [PATCH 0166/1001] ANDROID: uid_sys_stats: Replace tasklist lock with RCU in uid_cputime_show Tasklist lock is acuquired in uid_cputime_show for updating the stats for all tasks in the system. This can potentially disable preemption for several milli seconds. Replace tasklist_lock with RCU read side primitives. Change-Id: Ife69cb577bfdceaae6eb21b9bda09a0fe687e140 Signed-off-by: Pavankumar Kondeti --- drivers/misc/uid_sys_stats.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index fbf7db598d55..88dc1cd3a204 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -346,13 +346,13 @@ static int uid_cputime_show(struct seq_file *m, void *v) uid_entry->active_utime = 0; } - read_lock(&tasklist_lock); + rcu_read_lock(); do_each_thread(temp, task) { uid = from_kuid_munged(user_ns, task_uid(task)); if (!uid_entry || uid_entry->uid != uid) uid_entry = find_or_register_uid(uid); if (!uid_entry) { - read_unlock(&tasklist_lock); + rcu_read_unlock(); rt_mutex_unlock(&uid_lock); pr_err("%s: failed to find the uid_entry for uid %d\n", __func__, uid); @@ -362,7 +362,7 @@ static int uid_cputime_show(struct seq_file *m, void *v) uid_entry->active_utime += utime; uid_entry->active_stime += stime; } while_each_thread(temp, task); - read_unlock(&tasklist_lock); + rcu_read_unlock(); hash_for_each(hash_table, bkt, uid_entry, hash) { u64 total_utime = uid_entry->utime + -- GitLab From 0392f0424af2f7776581dbd98e8e8f93409a06b5 Mon Sep 17 00:00:00 2001 From: Suresh Vankadara Date: Mon, 16 Jul 2018 14:46:36 +0530 Subject: [PATCH 0167/1001] msm: camera: cpas: Add cpas support for camera v150 platform Add register info, QoS settings info to program camera static setting for chipsets having camera v150 Change-Id: I93378cc9ec4bd2f91bb0340155c5b3c938bdd2fc Signed-off-by: Suresh Vankadara --- .../camera/cam_cpas/cpas_top/cam_cpastop_hw.c | 4 + .../cam_cpas/cpas_top/cpastop_v150_100.h | 537 ++++++++++++++++++ .../camera/cam_cpas/include/cam_cpas_api.h | 1 + 3 files changed, 542 insertions(+) create mode 100644 drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v150_100.h diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c index 1166f2080191..1e51e552d1bf 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -20,6 +20,7 @@ #include "cam_io_util.h" #include "cam_cpas_soc.h" #include "cpastop100.h" +#include "cpastop_v150_100.h" #include "cpastop_v170_110.h" #include "cpastop_v175_100.h" #include "cpastop_v175_101.h" @@ -578,6 +579,9 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw, case CAM_CPAS_TITAN_175_V101: camnoc_info = &cam175_cpas101_camnoc_info; break; + case CAM_CPAS_TITAN_150_V100: + camnoc_info = &cam150_cpas100_camnoc_info; + break; default: CAM_ERR(CAM_CPAS, "Camera Version not supported %d.%d.%d", hw_caps->camera_version.major, diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v150_100.h b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v150_100.h new file mode 100644 index 000000000000..ceb3c02f1d15 --- /dev/null +++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v150_100.h @@ -0,0 +1,537 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CPASTOP_V150_100_H_ +#define _CPASTOP_V150_100_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v150_100_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2040, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v150_100_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x1190, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v150_100_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */ + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE02, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */ + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE13, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */ + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = false, + }, + { + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2088, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam150_cpas100_err_logger_offsets = { + .mainctrl = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x2720, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x2724, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x2728, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x272c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x2730, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x2734, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x2738, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x273c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam150_cpas100_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2100, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam150_cpas100_camnoc_info = { + .specific = &cam_cpas_v150_100_camnoc_specific[0], + .specific_size = sizeof(cam_cpas_v150_100_camnoc_specific) / + sizeof(cam_cpas_v150_100_camnoc_specific[0]), + .irq_sbm = &cam_cpas_v150_100_irq_sbm, + .irq_err = &cam_cpas_v150_100_irq_err[0], + .irq_err_size = sizeof(cam_cpas_v150_100_irq_err) / + sizeof(cam_cpas_v150_100_irq_err[0]), + .err_logger = &cam150_cpas100_err_logger_offsets, + .errata_wa_list = &cam150_cpas100_errata_wa_list, +}; + +#endif /* _CPASTOP_V150_100_H_ */ diff --git a/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h b/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h index 8760ad17c2c9..02c4d01ae7d6 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h +++ b/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h @@ -41,6 +41,7 @@ enum cam_cpas_reg_base { */ enum cam_cpas_hw_version { CAM_CPAS_TITAN_NONE = 0, + CAM_CPAS_TITAN_150_V100 = 0x150100, CAM_CPAS_TITAN_170_V100 = 0x170100, CAM_CPAS_TITAN_170_V110 = 0x170110, CAM_CPAS_TITAN_170_V120 = 0x170120, -- GitLab From f1740cd86c5eb1c82a262e914d8960e51b1ac32e Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 23 Jul 2018 12:37:47 -0700 Subject: [PATCH 0168/1001] ARM: dts: msm: Correct pinctrl entry for cci device for sm8150 Pinctrl active and suspend pin entry for i2c/data is not correct for cci1 device. This change fix pinctrl entries for cci1 device. Change-Id: Iad0247b432137cb67c89beca38a3a189d204fb83 Signed-off-by: Jigarkumar Zala --- arch/arm64/boot/dts/qcom/sm8150-camera.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi b/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi index 5bfc2b8e562a..8acc37dddd57 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi @@ -242,8 +242,8 @@ clock-cntl-level = "lowsvs"; clock-rates = <37500000 0>; pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cci2_active &cci2_active>; - pinctrl-1 = <&cci3_suspend &cci3_suspend>; + pinctrl-0 = <&cci2_active &cci3_active>; + pinctrl-1 = <&cci2_suspend &cci3_suspend>; gpios = <&tlmm 31 0>, <&tlmm 32 0>, <&tlmm 33 0>, -- GitLab From 71d63f0d63c535bfc7f272383f1eaaa63b7e141b Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 23 Jul 2018 15:55:07 -0700 Subject: [PATCH 0169/1001] msm: camera: Remove sysfs bind/unbind files This change disables dynamic bind/unbind capability for camera driver modules since it is not currently supported. Change-Id: I22a7490ae9670f6b4305356a2267a68d9781466b Signed-off-by: Jigarkumar Zala --- drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c | 1 + drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf.c | 1 + drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c | 1 + drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c | 1 + .../platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c | 1 + drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c | 1 + drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c | 1 + .../media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c | 1 + .../media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c | 1 + drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c | 1 + .../cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c | 1 + .../isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c | 1 + .../camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c | 1 + drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c | 1 + .../msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c | 1 + .../msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c | 1 + drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.c | 1 + .../msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c | 1 + drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c | 2 ++ .../camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c | 1 + .../platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c | 1 + .../msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c | 1 + .../msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c | 1 + .../msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c | 1 + .../msm/camera/cam_sensor_module/cam_res_mgr/cam_res_mgr.c | 1 + .../msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c | 1 + drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c | 1 + drivers/media/platform/msm/camera/cam_sync/cam_sync.c | 1 + 28 files changed, 29 insertions(+) diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c index 9e602544523e..cddbd8309ece 100644 --- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c @@ -1125,6 +1125,7 @@ static struct platform_driver cam_hw_cdm_driver = { .name = "msm_cam_cdm", .owner = THIS_MODULE, .of_match_table = msm_cam_hw_cdm_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf.c index db377e02a87a..871276170ac4 100644 --- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf.c +++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf.c @@ -562,6 +562,7 @@ static struct platform_driver cam_cdm_intf_driver = { .name = "msm_cam_cdm_intf", .owner = THIS_MODULE, .of_match_table = msm_cam_cdm_intf_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c index 13d59d6755bb..cdc8a3baef28 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c +++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c @@ -642,6 +642,7 @@ static struct platform_driver cam_cpas_driver = { .name = CAM_CPAS_DEV_NAME, .owner = THIS_MODULE, .of_match_table = cam_cpas_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c b/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c index 3f0124436b9e..d5068ca26971 100644 --- a/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c +++ b/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c @@ -194,6 +194,7 @@ static struct platform_driver cam_fd_driver = { .name = "cam_fd", .owner = THIS_MODULE, .of_match_table = cam_fd_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c index 5d6c9fa80769..8a84c0ee7e99 100644 --- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c +++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c @@ -221,6 +221,7 @@ static struct platform_driver cam_fd_hw_driver = { .name = "cam_fd_hw", .owner = THIS_MODULE, .of_match_table = cam_fd_hw_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c b/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c index a9804caed564..fa714c8c7fea 100644 --- a/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c +++ b/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c @@ -238,6 +238,7 @@ static struct platform_driver cam_icp_driver = { .name = "cam_icp", .owner = THIS_MODULE, .of_match_table = cam_icp_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c index 6518c67f98af..3b652e72466e 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c @@ -215,6 +215,7 @@ static struct platform_driver cam_a5_driver = { .name = "cam-a5", .owner = THIS_MODULE, .of_match_table = cam_a5_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c index 6e51b1e91b14..56abb4b8e6e9 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c @@ -194,6 +194,7 @@ static struct platform_driver cam_bps_driver = { .name = "cam-bps", .owner = THIS_MODULE, .of_match_table = cam_bps_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c index 456d45e08b74..a01d114bae7b 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c @@ -186,6 +186,7 @@ static struct platform_driver cam_ipe_driver = { .name = "cam-ipe", .owner = THIS_MODULE, .of_match_table = cam_ipe_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c index c4020a04ad92..5eefcae859e0 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c @@ -135,6 +135,7 @@ static struct platform_driver isp_driver = { .name = "cam_isp", .owner = THIS_MODULE, .of_match_table = cam_isp_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c index 13eb2887667c..0df2fdddb1be 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c @@ -52,6 +52,7 @@ static struct platform_driver cam_ife_csid17x_driver = { .name = CAM_CSID_DRV_NAME, .owner = THIS_MODULE, .of_match_table = cam_ife_csid17x_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c index a1c77d15b64b..5fdb52a2d9f0 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c @@ -41,6 +41,7 @@ static struct platform_driver cam_ife_csid_lite_driver = { .name = CAM_CSID_LITE_DRV_NAME, .owner = THIS_MODULE, .of_match_table = cam_ife_csid_lite_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c index 28ca7c25533b..c94b64e2b28c 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c @@ -46,6 +46,7 @@ static struct platform_driver cam_vfe_driver = { .name = "cam_vfe17x", .owner = THIS_MODULE, .of_match_table = cam_vfe_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c index 60feeacde477..46cc08f7ea5f 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c @@ -138,6 +138,7 @@ static struct platform_driver jpeg_driver = { .name = "cam_jpeg", .owner = THIS_MODULE, .of_match_table = cam_jpeg_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c index ef10406b823a..fd4fdab19fa7 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c @@ -220,6 +220,7 @@ static struct platform_driver cam_jpeg_dma_driver = { .name = "cam-jpeg-dma", .owner = THIS_MODULE, .of_match_table = cam_jpeg_dma_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c index d1eb526428e2..d4daa6dde308 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c @@ -218,6 +218,7 @@ static struct platform_driver cam_jpeg_enc_driver = { .name = "cam-jpeg-enc", .owner = THIS_MODULE, .of_match_table = cam_jpeg_enc_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.c b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.c index c58e9f386291..a4ee1040e4c8 100644 --- a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.c +++ b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.c @@ -214,6 +214,7 @@ static struct platform_driver cam_lrme_driver = { .name = "cam_lrme", .owner = THIS_MODULE, .of_match_table = cam_lrme_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c index ec392f5d0752..ec4297822fb7 100644 --- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c +++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c @@ -300,6 +300,7 @@ static struct platform_driver cam_lrme_hw_driver = { .name = "cam_lrme_hw", .owner = THIS_MODULE, .of_match_table = cam_lrme_hw_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c index 9a93feba1ac5..543e3329fc52 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c @@ -591,6 +591,7 @@ static int cam_req_mgr_remove(struct platform_device *pdev) cam_v4l2_device_cleanup(); mutex_destroy(&g_dev.dev_lock); g_dev.state = false; + g_dev.subdev_nodes_created = false; return 0; } @@ -680,6 +681,7 @@ static struct platform_driver cam_req_mgr_driver = { .name = "cam_req_mgr", .owner = THIS_MODULE, .of_match_table = cam_req_mgr_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c index 733c9e870637..7d23f900199e 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c @@ -397,6 +397,7 @@ static struct platform_driver cam_actuator_platform_driver = { .name = "qcom,actuator", .owner = THIS_MODULE, .of_match_table = cam_actuator_driver_dt_match, + .suppress_bind_attrs = true, }, .remove = cam_actuator_platform_remove, }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c index 8d44bcf3ce22..a763d3ffb39e 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -382,6 +382,7 @@ static struct platform_driver cci_driver = { .name = CAMX_CCI_DEV_NAME, .owner = THIS_MODULE, .of_match_table = cam_cci_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c index a560b00d8add..32bb34bb257b 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c @@ -233,6 +233,7 @@ static struct platform_driver csiphy_driver = { .name = CAMX_CSIPHY_DEV_NAME, .owner = THIS_MODULE, .of_match_table = cam_csiphy_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c index c7a9a32e4d0d..dbeb4af4820e 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c @@ -506,6 +506,7 @@ static struct platform_driver cam_eeprom_platform_driver = { .name = "qcom,eeprom", .owner = THIS_MODULE, .of_match_table = cam_eeprom_dt_match, + .suppress_bind_attrs = true, }, .probe = cam_eeprom_platform_driver_probe, .remove = cam_eeprom_platform_driver_remove, diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c index f9411fcfa4b3..d9b5f6406058 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -394,6 +394,7 @@ static struct platform_driver cam_flash_platform_driver = { .name = "CAM-FLASH-DRIVER", .owner = THIS_MODULE, .of_match_table = cam_flash_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_res_mgr/cam_res_mgr.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_res_mgr/cam_res_mgr.c index 43513e8c1485..d03faef4d3a6 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_res_mgr/cam_res_mgr.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_res_mgr/cam_res_mgr.c @@ -718,6 +718,7 @@ static struct platform_driver cam_res_mgr_driver = { .name = "cam_res_mgr", .owner = THIS_MODULE, .of_match_table = cam_res_mgr_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c index e3b2ffc5f45e..6cf40f8b0f10 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c @@ -339,6 +339,7 @@ static struct platform_driver cam_sensor_platform_driver = { .name = "qcom,camera", .owner = THIS_MODULE, .of_match_table = cam_sensor_driver_dt_match, + .suppress_bind_attrs = true, }, .remove = cam_sensor_platform_remove, }; diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c index 43902c977a49..75a841222718 100644 --- a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c +++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c @@ -3407,6 +3407,7 @@ static struct platform_driver cam_smmu_driver = { .name = "msm_cam_smmu", .owner = THIS_MODULE, .of_match_table = msm_cam_smmu_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c index cb5187a7f5c0..08ae4cee812d 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c @@ -1095,6 +1095,7 @@ static struct platform_driver cam_sync_driver = { .driver = { .name = "cam_sync", .owner = THIS_MODULE, + .suppress_bind_attrs = true, }, }; -- GitLab From f4dd5a77a319840b4952023316e2cc6753b21ba1 Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Wed, 27 Jun 2018 12:08:09 -0700 Subject: [PATCH 0170/1001] defconfig: sm8150: Build uncompressed kernel image Configure to build uncompressed kernel image for sm8150 platform. Change-Id: I9414832e400c2e599366f02f1369adcaed37064d Signed-off-by: Raghavendra Rao Ananta --- arch/arm64/configs/vendor/sm8150-perf_defconfig | 1 + arch/arm64/configs/vendor/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/vendor/sm8150-perf_defconfig b/arch/arm64/configs/vendor/sm8150-perf_defconfig index 85331abeccf4..816f85a6f539 100644 --- a/arch/arm64/configs/vendor/sm8150-perf_defconfig +++ b/arch/arm64/configs/vendor/sm8150-perf_defconfig @@ -79,6 +79,7 @@ CONFIG_SETEND_EMULATION=y CONFIG_RANDOMIZE_BASE=y # CONFIG_EFI is not set CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y CONFIG_PM_AUTOSLEEP=y diff --git a/arch/arm64/configs/vendor/sm8150_defconfig b/arch/arm64/configs/vendor/sm8150_defconfig index 9d4e63b5918c..8d7d5434b3b3 100644 --- a/arch/arm64/configs/vendor/sm8150_defconfig +++ b/arch/arm64/configs/vendor/sm8150_defconfig @@ -85,6 +85,7 @@ CONFIG_SETEND_EMULATION=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y CONFIG_PM_AUTOSLEEP=y -- GitLab From 763ccb4d1980155e1f71290f9fc7950065ec77a6 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Tue, 3 Jul 2018 15:23:58 +0900 Subject: [PATCH 0171/1001] scsi: sd_zbc: Fix variable type and bogus comment commit f13cff6c25bd8986627365346d123312ee7baa78 upstream. Fix the description of sd_zbc_check_zone_size() to correctly explain that the returned value is a number of device blocks, not bytes. Additionally, the 32 bits "ret" variable used in this function may truncate the 64 bits zone_blocks variable value upon return. To fix this, change "ret" type to s64. Fixes: ccce20fc79 ("sd_zbc: Avoid that resetting a zone fails sporadically") Signed-off-by: Damien Le Moal Cc: Bart Van Assche Cc: stable@kernel.org Reviewed-by: Hannes Reinecke Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sd_zbc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index ea9e1e0ed5b8..f4944dde6c8e 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -430,7 +430,8 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp, * Check that all zones of the device are equal. The last zone can however * be smaller. The zone size must also be a power of two number of LBAs. * - * Returns the zone size in bytes upon success or an error code upon failure. + * Returns the zone size in number of blocks upon success or an error code + * upon failure. */ static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp) { @@ -440,7 +441,7 @@ static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp) unsigned char *rec; unsigned int buf_len; unsigned int list_length; - int ret; + s64 ret; u8 same; /* Get a buffer */ -- GitLab From 3a46a033bfa81d624a649bc11b92dad37d2f8d8b Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Thu, 21 Dec 2017 21:10:36 -0500 Subject: [PATCH 0172/1001] KVM/Eventfd: Avoid crash when assign and deassign specific eventfd in parallel. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b5020a8e6b54d2ece80b1e7dedb33c79a40ebd47 upstream. Syzbot reports crashes in kvm_irqfd_assign(), caused by use-after-free when kvm_irqfd_assign() and kvm_irqfd_deassign() run in parallel for one specific eventfd. When the assign path hasn't finished but irqfd has been added to kvm->irqfds.items list, another thead may deassign the eventfd and free struct kvm_kernel_irqfd(). The assign path then uses the struct kvm_kernel_irqfd that has been freed by deassign path. To avoid such issue, keep irqfd under kvm->irq_srcu protection after the irqfd has been added to kvm->irqfds.items list, and call synchronize_srcu() in irq_shutdown() to make sure that irqfd has been fully initialized in the assign path. Reported-by: Dmitry Vyukov Cc: Paolo Bonzini Cc: Radim Krčmář Cc: Dmitry Vyukov Signed-off-by: Tianyu Lan Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman --- virt/kvm/eventfd.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c index f2ac53ab8243..58a9b31b0dd5 100644 --- a/virt/kvm/eventfd.c +++ b/virt/kvm/eventfd.c @@ -119,8 +119,12 @@ irqfd_shutdown(struct work_struct *work) { struct kvm_kernel_irqfd *irqfd = container_of(work, struct kvm_kernel_irqfd, shutdown); + struct kvm *kvm = irqfd->kvm; u64 cnt; + /* Make sure irqfd has been initalized in assign path. */ + synchronize_srcu(&kvm->irq_srcu); + /* * Synchronize with the wait-queue and unhook ourselves to prevent * further events. @@ -387,7 +391,6 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args) idx = srcu_read_lock(&kvm->irq_srcu); irqfd_update(kvm, irqfd); - srcu_read_unlock(&kvm->irq_srcu, idx); list_add_tail(&irqfd->list, &kvm->irqfds.items); @@ -421,6 +424,7 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args) } #endif + srcu_read_unlock(&kvm->irq_srcu, idx); return 0; fail: -- GitLab From b4108288eab85f74e0fbe7ba781e319f365a26e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 9 Jul 2018 16:35:34 +0300 Subject: [PATCH 0173/1001] x86/apm: Don't access __preempt_count with zeroed fs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 6f6060a5c9cc76fdbc22748264e6aa3779ec2427 upstream. APM_DO_POP_SEGS does not restore fs/gs which were zeroed by APM_DO_ZERO_SEGS. Trying to access __preempt_count with zeroed fs doesn't really work. Move the ibrs call outside the APM_DO_SAVE_SEGS/APM_DO_RESTORE_SEGS invocations so that fs is actually restored before calling preempt_enable(). Fixes the following sort of oopses: [ 0.313581] general protection fault: 0000 [#1] PREEMPT SMP [ 0.313803] Modules linked in: [ 0.314040] CPU: 0 PID: 268 Comm: kapmd Not tainted 4.16.0-rc1-triton-bisect-00090-gdd84441a7971 #19 [ 0.316161] EIP: __apm_bios_call_simple+0xc8/0x170 [ 0.316161] EFLAGS: 00210016 CPU: 0 [ 0.316161] EAX: 00000102 EBX: 00000000 ECX: 00000102 EDX: 00000000 [ 0.316161] ESI: 0000530e EDI: dea95f64 EBP: dea95f18 ESP: dea95ef0 [ 0.316161] DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068 [ 0.316161] CR0: 80050033 CR2: 00000000 CR3: 015d3000 CR4: 000006d0 [ 0.316161] Call Trace: [ 0.316161] ? cpumask_weight.constprop.15+0x20/0x20 [ 0.316161] on_cpu0+0x44/0x70 [ 0.316161] apm+0x54e/0x720 [ 0.316161] ? __switch_to_asm+0x26/0x40 [ 0.316161] ? __schedule+0x17d/0x590 [ 0.316161] kthread+0xc0/0xf0 [ 0.316161] ? proc_apm_show+0x150/0x150 [ 0.316161] ? kthread_create_worker_on_cpu+0x20/0x20 [ 0.316161] ret_from_fork+0x2e/0x38 [ 0.316161] Code: da 8e c2 8e e2 8e ea 57 55 2e ff 1d e0 bb 5d b1 0f 92 c3 5d 5f 07 1f 89 47 0c 90 8d b4 26 00 00 00 00 90 8d b4 26 00 00 00 00 90 <64> ff 0d 84 16 5c b1 74 7f 8b 45 dc 8e e0 8b 45 d8 8e e8 8b 45 [ 0.316161] EIP: __apm_bios_call_simple+0xc8/0x170 SS:ESP: 0068:dea95ef0 [ 0.316161] ---[ end trace 656253db2deaa12c ]--- Fixes: dd84441a7971 ("x86/speculation: Use IBRS if available before calling into firmware") Signed-off-by: Ville Syrjälä Signed-off-by: Thomas Gleixner Cc: stable@vger.kernel.org Cc: David Woodhouse Cc: "H. Peter Anvin" Cc: x86@kernel.org Cc: David Woodhouse Cc: "H. Peter Anvin" Link: https://lkml.kernel.org/r/20180709133534.5963-1-ville.syrjala@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/apm.h | 6 ------ arch/x86/kernel/apm_32.c | 5 +++++ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/arch/x86/include/asm/apm.h b/arch/x86/include/asm/apm.h index c356098b6fb9..4d4015ddcf26 100644 --- a/arch/x86/include/asm/apm.h +++ b/arch/x86/include/asm/apm.h @@ -7,8 +7,6 @@ #ifndef _ASM_X86_MACH_DEFAULT_APM_H #define _ASM_X86_MACH_DEFAULT_APM_H -#include - #ifdef APM_ZERO_SEGS # define APM_DO_ZERO_SEGS \ "pushl %%ds\n\t" \ @@ -34,7 +32,6 @@ static inline void apm_bios_call_asm(u32 func, u32 ebx_in, u32 ecx_in, * N.B. We do NOT need a cld after the BIOS call * because we always save and restore the flags. */ - firmware_restrict_branch_speculation_start(); __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" @@ -47,7 +44,6 @@ static inline void apm_bios_call_asm(u32 func, u32 ebx_in, u32 ecx_in, "=S" (*esi) : "a" (func), "b" (ebx_in), "c" (ecx_in) : "memory", "cc"); - firmware_restrict_branch_speculation_end(); } static inline bool apm_bios_call_simple_asm(u32 func, u32 ebx_in, @@ -60,7 +56,6 @@ static inline bool apm_bios_call_simple_asm(u32 func, u32 ebx_in, * N.B. We do NOT need a cld after the BIOS call * because we always save and restore the flags. */ - firmware_restrict_branch_speculation_start(); __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" @@ -73,7 +68,6 @@ static inline bool apm_bios_call_simple_asm(u32 func, u32 ebx_in, "=S" (si) : "a" (func), "b" (ebx_in), "c" (ecx_in) : "memory", "cc"); - firmware_restrict_branch_speculation_end(); return error; } diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 2a7fd56e67b3..63d3e6a6b5ef 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -240,6 +240,7 @@ #include #include #include +#include #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) extern int (*console_blank_hook)(int); @@ -614,11 +615,13 @@ static long __apm_bios_call(void *_call) gdt[0x40 / 8] = bad_bios_desc; apm_irq_save(flags); + firmware_restrict_branch_speculation_start(); APM_DO_SAVE_SEGS; apm_bios_call_asm(call->func, call->ebx, call->ecx, &call->eax, &call->ebx, &call->ecx, &call->edx, &call->esi); APM_DO_RESTORE_SEGS; + firmware_restrict_branch_speculation_end(); apm_irq_restore(flags); gdt[0x40 / 8] = save_desc_40; put_cpu(); @@ -690,10 +693,12 @@ static long __apm_bios_call_simple(void *_call) gdt[0x40 / 8] = bad_bios_desc; apm_irq_save(flags); + firmware_restrict_branch_speculation_start(); APM_DO_SAVE_SEGS; error = apm_bios_call_simple_asm(call->func, call->ebx, call->ecx, &call->eax); APM_DO_RESTORE_SEGS; + firmware_restrict_branch_speculation_end(); apm_irq_restore(flags); gdt[0x40 / 8] = save_desc_40; put_cpu(); -- GitLab From aa49e48232ee4dc78d736939f83057dc12d04366 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Sat, 14 Jul 2018 12:58:07 -0700 Subject: [PATCH 0174/1001] x86/events/intel/ds: Fix bts_interrupt_threshold alignment commit 2c991e408df6a407476dbc453d725e1e975479e7 upstream. Markus reported that BTS is sporadically missing the tail of the trace in the perf_event data buffer: [decode error (1): instruction overflow] shown in GDB; and bisected it to the conversion of debug_store to PTI. A little "optimization" crept into alloc_bts_buffer(), which mistakenly placed bts_interrupt_threshold away from the 24-byte record boundary. Intel SDM Vol 3B 17.4.9 says "This address must point to an offset from the BTS buffer base that is a multiple of the BTS record size." Revert "max" from a byte count to a record count, to calculate the bts_interrupt_threshold correctly: which turns out to fix problem seen. Fixes: c1961a4631da ("x86/events/intel/ds: Map debug buffers in cpu_entry_area") Reported-and-tested-by: Markus T Metzger Signed-off-by: Hugh Dickins Signed-off-by: Thomas Gleixner Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Andi Kleen Cc: Dave Hansen Cc: Stephane Eranian Cc: stable@vger.kernel.org # v4.14+ Link: https://lkml.kernel.org/r/alpine.LSU.2.11.1807141248290.1614@eggly.anvils Signed-off-by: Greg Kroah-Hartman --- arch/x86/events/intel/ds.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c index 10b39d44981c..25386be0d757 100644 --- a/arch/x86/events/intel/ds.c +++ b/arch/x86/events/intel/ds.c @@ -410,9 +410,11 @@ static int alloc_bts_buffer(int cpu) ds->bts_buffer_base = (unsigned long) cea; ds_update_cea(cea, buffer, BTS_BUFFER_SIZE, PAGE_KERNEL); ds->bts_index = ds->bts_buffer_base; - max = BTS_RECORD_SIZE * (BTS_BUFFER_SIZE / BTS_RECORD_SIZE); - ds->bts_absolute_maximum = ds->bts_buffer_base + max; - ds->bts_interrupt_threshold = ds->bts_absolute_maximum - (max / 16); + max = BTS_BUFFER_SIZE / BTS_RECORD_SIZE; + ds->bts_absolute_maximum = ds->bts_buffer_base + + max * BTS_RECORD_SIZE; + ds->bts_interrupt_threshold = ds->bts_absolute_maximum - + (max / 16) * BTS_RECORD_SIZE; return 0; } -- GitLab From 1450a7c5da03292fe4b022e58a92c9a9b91b27aa Mon Sep 17 00:00:00 2001 From: Dewet Thibaut Date: Mon, 16 Jul 2018 10:49:27 +0200 Subject: [PATCH 0175/1001] x86/MCE: Remove min interval polling limitation commit fbdb328c6bae0a7c78d75734a738b66b86dffc96 upstream. commit b3b7c4795c ("x86/MCE: Serialize sysfs changes") introduced a min interval limitation when setting the check interval for polled MCEs. However, the logic is that 0 disables polling for corrected MCEs, see Documentation/x86/x86_64/machinecheck. The limitation prevents disabling. Remove this limitation and allow the value 0 to disable polling again. Fixes: b3b7c4795c ("x86/MCE: Serialize sysfs changes") Signed-off-by: Dewet Thibaut Signed-off-by: Alexander Sverdlin [ Massage commit message. ] Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Cc: Tony Luck Cc: linux-edac Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/20180716084927.24869-1-alexander.sverdlin@nokia.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/mcheck/mce.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 58f887f5e036..98e4e4dc4a3b 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -2150,9 +2150,6 @@ static ssize_t store_int_with_restart(struct device *s, if (check_interval == old_check_interval) return ret; - if (check_interval < 1) - check_interval = 1; - mutex_lock(&mce_sysfs_mutex); mce_restart(); mutex_unlock(&mce_sysfs_mutex); -- GitLab From 321089a0aa35bcc09f423180847aa15b69dc4f9f Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Fri, 20 Jul 2018 17:53:42 -0700 Subject: [PATCH 0176/1001] fat: fix memory allocation failure handling of match_strdup() commit 35033ab988c396ad7bce3b6d24060c16a9066db8 upstream. In parse_options(), if match_strdup() failed, parse_options() leaves opts->iocharset in unexpected state (i.e. still pointing the freed string). And this can be the cause of double free. To fix, this initialize opts->iocharset always when freeing. Link: http://lkml.kernel.org/r/8736wp9dzc.fsf@mail.parknet.co.jp Signed-off-by: OGAWA Hirofumi Reported-by: syzbot+90b8e10515ae88228a92@syzkaller.appspotmail.com Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/fat/inode.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/fs/fat/inode.c b/fs/fat/inode.c index c7a4dee206b9..3b40937b942a 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -696,13 +696,21 @@ static void fat_set_state(struct super_block *sb, brelse(bh); } +static void fat_reset_iocharset(struct fat_mount_options *opts) +{ + if (opts->iocharset != fat_default_iocharset) { + /* Note: opts->iocharset can be NULL here */ + kfree(opts->iocharset); + opts->iocharset = fat_default_iocharset; + } +} + static void delayed_free(struct rcu_head *p) { struct msdos_sb_info *sbi = container_of(p, struct msdos_sb_info, rcu); unload_nls(sbi->nls_disk); unload_nls(sbi->nls_io); - if (sbi->options.iocharset != fat_default_iocharset) - kfree(sbi->options.iocharset); + fat_reset_iocharset(&sbi->options); kfree(sbi); } @@ -1117,7 +1125,7 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, opts->fs_fmask = opts->fs_dmask = current_umask(); opts->allow_utime = -1; opts->codepage = fat_default_codepage; - opts->iocharset = fat_default_iocharset; + fat_reset_iocharset(opts); if (is_vfat) { opts->shortname = VFAT_SFN_DISPLAY_WINNT|VFAT_SFN_CREATE_WIN95; opts->rodir = 0; @@ -1274,8 +1282,7 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, /* vfat specific */ case Opt_charset: - if (opts->iocharset != fat_default_iocharset) - kfree(opts->iocharset); + fat_reset_iocharset(opts); iocharset = match_strdup(&args[0]); if (!iocharset) return -ENOMEM; @@ -1866,8 +1873,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, iput(fat_inode); unload_nls(sbi->nls_io); unload_nls(sbi->nls_disk); - if (sbi->options.iocharset != fat_default_iocharset) - kfree(sbi->options.iocharset); + fat_reset_iocharset(&sbi->options); sb->s_fs_info = NULL; kfree(sbi); return error; -- GitLab From 5d251646ab1588077b26e89dcaa116aba105d097 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 17 Jul 2018 17:26:43 +0200 Subject: [PATCH 0177/1001] ALSA: rawmidi: Change resized buffers atomically commit 39675f7a7c7e7702f7d5341f1e0d01db746543a0 upstream. The SNDRV_RAWMIDI_IOCTL_PARAMS ioctl may resize the buffers and the current code is racy. For example, the sequencer client may write to buffer while it being resized. As a simple workaround, let's switch to the resized buffer inside the stream runtime lock. Reported-by: syzbot+52f83f0ea8df16932f7f@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/rawmidi.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index f055ca10bbc1..abacbbc0b0e8 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -635,7 +635,7 @@ static int snd_rawmidi_info_select_user(struct snd_card *card, int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params * params) { - char *newbuf; + char *newbuf, *oldbuf; struct snd_rawmidi_runtime *runtime = substream->runtime; if (substream->append && substream->use_count > 1) @@ -648,13 +648,17 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, return -EINVAL; } if (params->buffer_size != runtime->buffer_size) { - newbuf = krealloc(runtime->buffer, params->buffer_size, - GFP_KERNEL); + newbuf = kmalloc(params->buffer_size, GFP_KERNEL); if (!newbuf) return -ENOMEM; + spin_lock_irq(&runtime->lock); + oldbuf = runtime->buffer; runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; runtime->avail = runtime->buffer_size; + runtime->appl_ptr = runtime->hw_ptr = 0; + spin_unlock_irq(&runtime->lock); + kfree(oldbuf); } runtime->avail_min = params->avail_min; substream->active_sensing = !params->no_active_sensing; @@ -665,7 +669,7 @@ EXPORT_SYMBOL(snd_rawmidi_output_params); int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params * params) { - char *newbuf; + char *newbuf, *oldbuf; struct snd_rawmidi_runtime *runtime = substream->runtime; snd_rawmidi_drain_input(substream); @@ -676,12 +680,16 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, return -EINVAL; } if (params->buffer_size != runtime->buffer_size) { - newbuf = krealloc(runtime->buffer, params->buffer_size, - GFP_KERNEL); + newbuf = kmalloc(params->buffer_size, GFP_KERNEL); if (!newbuf) return -ENOMEM; + spin_lock_irq(&runtime->lock); + oldbuf = runtime->buffer; runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; + runtime->appl_ptr = runtime->hw_ptr = 0; + spin_unlock_irq(&runtime->lock); + kfree(oldbuf); } runtime->avail_min = params->avail_min; return 0; -- GitLab From feefc072d10d646ee441289184b44d9db7ff2213 Mon Sep 17 00:00:00 2001 From: YOKOTA Hiroshi Date: Sun, 1 Jul 2018 18:30:01 +0900 Subject: [PATCH 0178/1001] ALSA: hda/realtek - Add Panasonic CF-SZ6 headset jack quirk commit 0fca97a29b83e3f315c14ed2372cfd0f9ee0a006 upstream. This adds some required quirk when uses headset or headphone on Panasonic CF-SZ6. Signed-off-by: YOKOTA Hiroshi Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index bf7737fc3b28..dcc9e6551b51 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6402,6 +6402,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x10cf, 0x1629, "Lifebook U7x7", ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC), SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), SND_PCI_QUIRK(0x10ec, 0x10f2, "Intel Reference board", ALC700_FIXUP_INTEL_REFERENCE), + SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_HEADSET_MODE), SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8), SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC), -- GitLab From a82d4478337a366dc2f95ac961a81260c6b4589e Mon Sep 17 00:00:00 2001 From: Po-Hsu Lin Date: Mon, 16 Jul 2018 15:50:08 +0800 Subject: [PATCH 0179/1001] ALSA: hda: add mute led support for HP ProBook 455 G5 commit 9a6249d2a145226ec1b294116fcb08744cf7ab56 upstream. Audio mute led does not work on HP ProBook 455 G5, this can be fixed by using CXT_FIXUP_MUTE_LED_GPIO to support it. BugLink: https://bugs.launchpad.net/bugs/1781763 Reported-by: James Buren Signed-off-by: Po-Hsu Lin Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_conexant.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index ba9a7e552183..88ce2f1022e1 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -965,6 +965,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC), SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO), + SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x8455, "HP Z2 G4", CXT_FIXUP_HP_MIC_NO_PRESENCE), -- GitLab From edb5e3eeb14a5260e19010d0e3bb4cd0ebb3ca82 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 17 Jul 2018 15:21:56 -0700 Subject: [PATCH 0180/1001] ARCv2: [plat-hsdk]: Save accl reg pair by default commit af1fc5baa724c63ce1733dfcf855bad5ef6078e3 upstream. This manifsted as strace segfaulting on HSDK because gcc was targetting the accumulator registers as GPRs, which kernek was not saving/restoring by default. Cc: stable@vger.kernel.org #4.14+ Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman --- arch/arc/Kconfig | 2 +- arch/arc/plat-hsdk/Kconfig | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 4383313b064a..5c8caf85c350 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -408,7 +408,7 @@ config ARC_HAS_DIV_REM config ARC_HAS_ACCL_REGS bool "Reg Pair ACCL:ACCH (FPU and/or MPY > 6)" - default n + default y help Depending on the configuration, CPU can contain accumulator reg-pair (also referred to as r58:r59). These can also be used by gcc as GPR so diff --git a/arch/arc/plat-hsdk/Kconfig b/arch/arc/plat-hsdk/Kconfig index 19ab3cf98f0f..fcc9a9e27e9c 100644 --- a/arch/arc/plat-hsdk/Kconfig +++ b/arch/arc/plat-hsdk/Kconfig @@ -7,5 +7,7 @@ menuconfig ARC_SOC_HSDK bool "ARC HS Development Kit SOC" + depends on ISA_ARCV2 + select ARC_HAS_ACCL_REGS select CLK_HSDK select RESET_HSDK -- GitLab From 13e5197d7ef6662f68fd033630f47c2d62d7ccd6 Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Thu, 28 Jun 2018 16:59:14 -0700 Subject: [PATCH 0181/1001] ARC: Fix CONFIG_SWAP commit 6e3761145a9ba3ce267c330b6bff51cf6a057b06 upstream. swap was broken on ARC due to silly copy-paste issue. We encode offset from swapcache page in __swp_entry() as (off << 13) but were not decoding back in __swp_offset() as (off >> 13) - it was still (off << 13). This finally fixes swap usage on ARC. | # mkswap /dev/sda2 | | # swapon -a -e /dev/sda2 | Adding 500728k swap on /dev/sda2. Priority:-2 extents:1 across:500728k | | # free | total used free shared buffers cached | Mem: 765104 13456 751648 4736 8 4736 | -/+ buffers/cache: 8712 756392 | Swap: 500728 0 500728 Cc: stable@vger.kernel.org Signed-off-by: Alexey Brodkin Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman --- arch/arc/include/asm/pgtable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arc/include/asm/pgtable.h b/arch/arc/include/asm/pgtable.h index 08fe33830d4b..77676e18da69 100644 --- a/arch/arc/include/asm/pgtable.h +++ b/arch/arc/include/asm/pgtable.h @@ -379,7 +379,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, /* Decode a PTE containing swap "identifier "into constituents */ #define __swp_type(pte_lookalike) (((pte_lookalike).val) & 0x1f) -#define __swp_offset(pte_lookalike) ((pte_lookalike).val << 13) +#define __swp_offset(pte_lookalike) ((pte_lookalike).val >> 13) /* NOPs, to keep generic kernel happy */ #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) -- GitLab From 3c732b3ab3a5fbfba43165140a8aa8d2d32592c7 Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Wed, 6 Jun 2018 15:59:38 +0300 Subject: [PATCH 0182/1001] ARC: configs: Remove CONFIG_INITRAMFS_SOURCE from defconfigs commit 64234961c145606b36eaa82c47b11be842b21049 upstream. We used to have pre-set CONFIG_INITRAMFS_SOURCE with local path to intramfs in ARC defconfigs. This was quite convenient for in-house development but not that convenient for newcomers who obviusly don't have folders like "arc_initramfs" next to the Linux source tree. Which leads to quite surprising failure of defconfig building: ------------------------------->8----------------------------- ../scripts/gen_initramfs_list.sh: Cannot open '../../arc_initramfs_hs/' ../usr/Makefile:57: recipe for target 'usr/initramfs_data.cpio.gz' failed make[2]: *** [usr/initramfs_data.cpio.gz] Error 1 ------------------------------->8----------------------------- So now when more and more people start to deal with our defconfigs let's make their life easier with removal of CONFIG_INITRAMFS_SOURCE. Signed-off-by: Alexey Brodkin Cc: Kevin Hilman Cc: stable@vger.kernel.org Signed-off-by: Alexey Brodkin Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman --- arch/arc/configs/axs101_defconfig | 1 - arch/arc/configs/axs103_defconfig | 1 - arch/arc/configs/axs103_smp_defconfig | 1 - arch/arc/configs/haps_hs_defconfig | 1 - arch/arc/configs/haps_hs_smp_defconfig | 1 - arch/arc/configs/hsdk_defconfig | 1 - arch/arc/configs/nsim_700_defconfig | 1 - arch/arc/configs/nsim_hs_defconfig | 1 - arch/arc/configs/nsim_hs_smp_defconfig | 1 - arch/arc/configs/nsimosci_defconfig | 1 - arch/arc/configs/nsimosci_hs_defconfig | 1 - arch/arc/configs/nsimosci_hs_smp_defconfig | 1 - 12 files changed, 12 deletions(-) diff --git a/arch/arc/configs/axs101_defconfig b/arch/arc/configs/axs101_defconfig index ec7c849a5c8e..a8242362e551 100644 --- a/arch/arc/configs/axs101_defconfig +++ b/arch/arc/configs/axs101_defconfig @@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../arc_initramfs/" CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/arc/configs/axs103_defconfig b/arch/arc/configs/axs103_defconfig index 63d3cf69e0b0..ef3c31cd7737 100644 --- a/arch/arc/configs/axs103_defconfig +++ b/arch/arc/configs/axs103_defconfig @@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../../arc_initramfs_hs/" CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/arc/configs/axs103_smp_defconfig b/arch/arc/configs/axs103_smp_defconfig index f613ecac14a7..1757ac9cecbc 100644 --- a/arch/arc/configs/axs103_smp_defconfig +++ b/arch/arc/configs/axs103_smp_defconfig @@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../../arc_initramfs_hs/" CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/arc/configs/haps_hs_defconfig b/arch/arc/configs/haps_hs_defconfig index db04ea4dd2d9..aa8240a92b60 100644 --- a/arch/arc/configs/haps_hs_defconfig +++ b/arch/arc/configs/haps_hs_defconfig @@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../../arc_initramfs_hs/" CONFIG_EXPERT=y CONFIG_PERF_EVENTS=y # CONFIG_COMPAT_BRK is not set diff --git a/arch/arc/configs/haps_hs_smp_defconfig b/arch/arc/configs/haps_hs_smp_defconfig index 3507be2af6fe..bc5a24ea6cf7 100644 --- a/arch/arc/configs/haps_hs_smp_defconfig +++ b/arch/arc/configs/haps_hs_smp_defconfig @@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../../arc_initramfs_hs/" CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/arc/configs/hsdk_defconfig b/arch/arc/configs/hsdk_defconfig index 7b8f8faf8a24..762b1fcd93dc 100644 --- a/arch/arc/configs/hsdk_defconfig +++ b/arch/arc/configs/hsdk_defconfig @@ -9,7 +9,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../../arc_initramfs_hs/" CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y # CONFIG_VM_EVENT_COUNTERS is not set diff --git a/arch/arc/configs/nsim_700_defconfig b/arch/arc/configs/nsim_700_defconfig index 6dff83a238b8..b1a78222699c 100644 --- a/arch/arc/configs/nsim_700_defconfig +++ b/arch/arc/configs/nsim_700_defconfig @@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../arc_initramfs/" CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y diff --git a/arch/arc/configs/nsim_hs_defconfig b/arch/arc/configs/nsim_hs_defconfig index 31ee51b987e7..217d7ea3c956 100644 --- a/arch/arc/configs/nsim_hs_defconfig +++ b/arch/arc/configs/nsim_hs_defconfig @@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../../arc_initramfs_hs/" CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y diff --git a/arch/arc/configs/nsim_hs_smp_defconfig b/arch/arc/configs/nsim_hs_smp_defconfig index 8d3b1f67cae4..e733e4f1a320 100644 --- a/arch/arc/configs/nsim_hs_smp_defconfig +++ b/arch/arc/configs/nsim_hs_smp_defconfig @@ -9,7 +9,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../arc_initramfs_hs/" CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y diff --git a/arch/arc/configs/nsimosci_defconfig b/arch/arc/configs/nsimosci_defconfig index 6168ce2ac2ef..14377b8234f7 100644 --- a/arch/arc/configs/nsimosci_defconfig +++ b/arch/arc/configs/nsimosci_defconfig @@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../arc_initramfs/" CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y diff --git a/arch/arc/configs/nsimosci_hs_defconfig b/arch/arc/configs/nsimosci_hs_defconfig index a70bdeb2b3fd..7e61c923a3cd 100644 --- a/arch/arc/configs/nsimosci_hs_defconfig +++ b/arch/arc/configs/nsimosci_hs_defconfig @@ -11,7 +11,6 @@ CONFIG_NAMESPACES=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../arc_initramfs_hs/" CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y diff --git a/arch/arc/configs/nsimosci_hs_smp_defconfig b/arch/arc/configs/nsimosci_hs_smp_defconfig index ef96406c446e..299fbe8003b2 100644 --- a/arch/arc/configs/nsimosci_hs_smp_defconfig +++ b/arch/arc/configs/nsimosci_hs_smp_defconfig @@ -9,7 +9,6 @@ CONFIG_IKCONFIG_PROC=y # CONFIG_UTS_NS is not set # CONFIG_PID_NS is not set CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="../arc_initramfs_hs/" CONFIG_PERF_EVENTS=y # CONFIG_COMPAT_BRK is not set CONFIG_KPROBES=y -- GitLab From 95c58105bd974153505a3343537b009773e63b77 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Wed, 11 Jul 2018 10:42:20 -0700 Subject: [PATCH 0183/1001] ARC: mm: allow mprotect to make stack mappings executable commit 93312b6da4df31e4102ce5420e6217135a16c7ea upstream. mprotect(EXEC) was failing for stack mappings as default vm flags was missing MAYEXEC. This was triggered by glibc test suite nptl/tst-execstack testcase What is surprising is that despite running LTP for years on, we didn't catch this issue as it lacks a directed test case. gcc dejagnu tests with nested functions also requiring exec stack work fine though because they rely on the GNU_STACK segment spit out by compiler and handled in kernel elf loader. This glibc case is different as the stack is non exec to begin with and a dlopen of shared lib with GNU_STACK segment triggers the exec stack proceedings using a mprotect(PROT_EXEC) which was broken. CC: stable@vger.kernel.org Signed-off-by: Vineet Gupta Signed-off-by: Greg Kroah-Hartman --- arch/arc/include/asm/page.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h index 109baa06831c..09ddddf71cc5 100644 --- a/arch/arc/include/asm/page.h +++ b/arch/arc/include/asm/page.h @@ -105,7 +105,7 @@ typedef pte_t * pgtable_t; #define virt_addr_valid(kaddr) pfn_valid(virt_to_pfn(kaddr)) /* Default Permissions for stack/heaps pages (Non Executable) */ -#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE) +#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) #define WANT_PAGE_VIRTUAL 1 -- GitLab From be2657752e9eae45f21d69ffdd732f36e347cf62 Mon Sep 17 00:00:00 2001 From: Jing Xia Date: Fri, 20 Jul 2018 17:53:48 -0700 Subject: [PATCH 0184/1001] mm: memcg: fix use after free in mem_cgroup_iter() commit 9f15bde671355c351cf20d9f879004b234353100 upstream. It was reported that a kernel crash happened in mem_cgroup_iter(), which can be triggered if the legacy cgroup-v1 non-hierarchical mode is used. Unable to handle kernel paging request at virtual address 6b6b6b6b6b6b8f ...... Call trace: mem_cgroup_iter+0x2e0/0x6d4 shrink_zone+0x8c/0x324 balance_pgdat+0x450/0x640 kswapd+0x130/0x4b8 kthread+0xe8/0xfc ret_from_fork+0x10/0x20 mem_cgroup_iter(): ...... if (css_tryget(css)) <-- crash here break; ...... The crashing reason is that mem_cgroup_iter() uses the memcg object whose pointer is stored in iter->position, which has been freed before and filled with POISON_FREE(0x6b). And the root cause of the use-after-free issue is that invalidate_reclaim_iterators() fails to reset the value of iter->position to NULL when the css of the memcg is released in non- hierarchical mode. Link: http://lkml.kernel.org/r/1531994807-25639-1-git-send-email-jing.xia@unisoc.com Fixes: 6df38689e0e9 ("mm: memcontrol: fix possible memcg leak due to interrupted reclaim") Signed-off-by: Jing Xia Acked-by: Michal Hocko Cc: Johannes Weiner Cc: Vladimir Davydov Cc: Cc: Shakeel Butt Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/memcontrol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 942d9342b63b..db69d938e9ed 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -879,7 +879,7 @@ static void invalidate_reclaim_iterators(struct mem_cgroup *dead_memcg) int nid; int i; - while ((memcg = parent_mem_cgroup(memcg))) { + for (; memcg; memcg = parent_mem_cgroup(memcg)) { for_each_node(nid) { mz = mem_cgroup_nodeinfo(memcg, nid); for (i = 0; i <= DEF_PRIORITY; i++) { -- GitLab From 70ef1db1f21d5a9ee2ec997e57f9307cbbbbf5bb Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Fri, 20 Jul 2018 17:53:45 -0700 Subject: [PATCH 0185/1001] mm/huge_memory.c: fix data loss when splitting a file pmd commit e1f1b1572e8db87a56609fd05bef76f98f0e456a upstream. __split_huge_pmd_locked() must check if the cleared huge pmd was dirty, and propagate that to PageDirty: otherwise, data may be lost when a huge tmpfs page is modified then split then reclaimed. How has this taken so long to be noticed? Because there was no problem when the huge page is written by a write system call (shmem_write_end() calls set_page_dirty()), nor when the page is allocated for a write fault (fault_dirty_shared_page() calls set_page_dirty()); but when allocated for a read fault (which MAP_POPULATE simulates), no set_page_dirty(). Link: http://lkml.kernel.org/r/alpine.LSU.2.11.1807111741430.1106@eggly.anvils Fixes: d21b9e57c74c ("thp: handle file pages in split_huge_pmd()") Signed-off-by: Hugh Dickins Reported-by: Ashwin Chaugule Reviewed-by: Yang Shi Reviewed-by: Kirill A. Shutemov Cc: "Huang, Ying" Cc: [4.8+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/huge_memory.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 8af604f3b370..255469f78217 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2069,6 +2069,8 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd, if (vma_is_dax(vma)) return; page = pmd_page(_pmd); + if (!PageDirty(page) && pmd_dirty(_pmd)) + set_page_dirty(page); if (!PageReferenced(page) && pmd_young(_pmd)) SetPageReferenced(page); page_remove_rmap(page, true); -- GitLab From dfc328156ddea2385394240c373a49bb42320b4c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 18 Jul 2018 13:38:37 +0200 Subject: [PATCH 0186/1001] cpufreq: intel_pstate: Register when ACPI PCCH is present commit 95d6c0857e54b788982746071130d822a795026b upstream. Currently, intel_pstate doesn't register if _PSS is not present on HP Proliant systems, because it expects the firmware to take over CPU performance scaling in that case. However, if ACPI PCCH is present, the firmware expects the kernel to use it for CPU performance scaling and the pcc-cpufreq driver is loaded for that. Unfortunately, the firmware interface used by that driver is not scalable for fundamental reasons, so pcc-cpufreq is way suboptimal on systems with more than just a few CPUs. In fact, it is better to avoid using it at all. For this reason, modify intel_pstate to look for ACPI PCCH if _PSS is not present and register if it is there. Also prevent the pcc-cpufreq driver from trying to initialize itself if intel_pstate has been registered already. Fixes: fbbcdc0744da (intel_pstate: skip the driver if ACPI has power mgmt option) Reported-by: Andreas Herrmann Reviewed-by: Andreas Herrmann Acked-by: Srinivas Pandruvada Tested-by: Andreas Herrmann Cc: 4.16+ # 4.16+ Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/cpufreq/intel_pstate.c | 17 ++++++++++++++++- drivers/cpufreq/pcc-cpufreq.c | 4 ++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index a905bbb45667..114dfe67015b 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -2188,6 +2188,18 @@ static bool __init intel_pstate_no_acpi_pss(void) return true; } +static bool __init intel_pstate_no_acpi_pcch(void) +{ + acpi_status status; + acpi_handle handle; + + status = acpi_get_handle(NULL, "\\_SB", &handle); + if (ACPI_FAILURE(status)) + return true; + + return !acpi_has_method(handle, "PCCH"); +} + static bool __init intel_pstate_has_acpi_ppc(void) { int i; @@ -2247,7 +2259,10 @@ static bool __init intel_pstate_platform_pwr_mgmt_exists(void) switch (plat_info[idx].data) { case PSS: - return intel_pstate_no_acpi_pss(); + if (!intel_pstate_no_acpi_pss()) + return false; + + return intel_pstate_no_acpi_pcch(); case PPC: return intel_pstate_has_acpi_ppc() && !force_load; } diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c index 3f0ce2ae35ee..0c56c9759672 100644 --- a/drivers/cpufreq/pcc-cpufreq.c +++ b/drivers/cpufreq/pcc-cpufreq.c @@ -580,6 +580,10 @@ static int __init pcc_cpufreq_init(void) { int ret; + /* Skip initialization if another cpufreq driver is there. */ + if (cpufreq_get_current_driver()) + return 0; + if (acpi_disabled) return 0; -- GitLab From a5b8eae536723d3377d21fe60cb2f294332bb322 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 17 Jul 2018 12:39:00 -0500 Subject: [PATCH 0187/1001] vfio/pci: Fix potential Spectre v1 commit 0e714d27786ce1fb3efa9aac58abc096e68b1c2a upstream. info.index can be indirectly controlled by user-space, hence leading to a potential exploitation of the Spectre variant 1 vulnerability. This issue was detected with the help of Smatch: drivers/vfio/pci/vfio_pci.c:734 vfio_pci_ioctl() warn: potential spectre issue 'vdev->region' Fix this by sanitizing info.index before indirectly using it to index vdev->region Notice that given that speculation windows are large, the policy is to kill the speculation on the first load and not worry if it can be completed with a dependent load/store [1]. [1] https://marc.info/?l=linux-kernel&m=152449131114778&w=2 Cc: stable@vger.kernel.org Signed-off-by: Gustavo A. R. Silva Signed-off-by: Alex Williamson Signed-off-by: Greg Kroah-Hartman --- drivers/vfio/pci/vfio_pci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index f041b1a6cf66..695b9d1a1aae 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "vfio_pci_private.h" @@ -746,6 +747,9 @@ static long vfio_pci_ioctl(void *device_data, if (info.index >= VFIO_PCI_NUM_REGIONS + vdev->num_regions) return -EINVAL; + info.index = array_index_nospec(info.index, + VFIO_PCI_NUM_REGIONS + + vdev->num_regions); i = info.index - VFIO_PCI_NUM_REGIONS; -- GitLab From 9a2e4a01ded2c88e11ef6640443462862c990a9b Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Tue, 17 Jul 2018 17:19:12 +1000 Subject: [PATCH 0188/1001] vfio/spapr: Use IOMMU pageshift rather than pagesize commit 1463edca6734d42ab4406fa2896e20b45478ea36 upstream. The size is always equal to 1 page so let's use this. Later on this will be used for other checks which use page shifts to check the granularity of access. This should cause no behavioral change. Cc: stable@vger.kernel.org # v4.12+ Reviewed-by: David Gibson Acked-by: Alex Williamson Signed-off-by: Alexey Kardashevskiy Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- drivers/vfio/vfio_iommu_spapr_tce.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index 63112c36ab2d..b751dd60e41a 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -457,13 +457,13 @@ static void tce_iommu_unuse_page(struct tce_container *container, } static int tce_iommu_prereg_ua_to_hpa(struct tce_container *container, - unsigned long tce, unsigned long size, + unsigned long tce, unsigned long shift, unsigned long *phpa, struct mm_iommu_table_group_mem_t **pmem) { long ret = 0; struct mm_iommu_table_group_mem_t *mem; - mem = mm_iommu_lookup(container->mm, tce, size); + mem = mm_iommu_lookup(container->mm, tce, 1ULL << shift); if (!mem) return -EINVAL; @@ -487,7 +487,7 @@ static void tce_iommu_unuse_page_v2(struct tce_container *container, if (!pua) return; - ret = tce_iommu_prereg_ua_to_hpa(container, *pua, IOMMU_PAGE_SIZE(tbl), + ret = tce_iommu_prereg_ua_to_hpa(container, *pua, tbl->it_page_shift, &hpa, &mem); if (ret) pr_debug("%s: tce %lx at #%lx was not cached, ret=%d\n", @@ -609,7 +609,7 @@ static long tce_iommu_build_v2(struct tce_container *container, entry + i); ret = tce_iommu_prereg_ua_to_hpa(container, - tce, IOMMU_PAGE_SIZE(tbl), &hpa, &mem); + tce, tbl->it_page_shift, &hpa, &mem); if (ret) break; -- GitLab From d21fb63010c4c8ca6768c3744cfe9ed2c399c130 Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Tue, 3 Jul 2018 15:02:14 -0700 Subject: [PATCH 0189/1001] stop_machine: Disable preemption when waking two stopper threads commit 9fb8d5dc4b649dd190e1af4ead670753e71bf907 upstream. When cpu_stop_queue_two_works() begins to wake the stopper threads, it does so without preemption disabled, which leads to the following race condition: The source CPU calls cpu_stop_queue_two_works(), with cpu1 as the source CPU, and cpu2 as the destination CPU. When adding the stopper threads to the wake queue used in this function, the source CPU stopper thread is added first, and the destination CPU stopper thread is added last. When wake_up_q() is invoked to wake the stopper threads, the threads are woken up in the order that they are queued in, so the source CPU's stopper thread is woken up first, and it preempts the thread running on the source CPU. The stopper thread will then execute on the source CPU, disable preemption, and begin executing multi_cpu_stop(), and wait for an ack from the destination CPU's stopper thread, with preemption still disabled. Since the worker thread that woke up the stopper thread on the source CPU is affine to the source CPU, and preemption is disabled on the source CPU, that thread will never run to dequeue the destination CPU's stopper thread from the wake queue, and thus, the destination CPU's stopper thread will never run, causing the source CPU's stopper thread to wait forever, and stall. Disable preemption when waking the stopper threads in cpu_stop_queue_two_works(). Fixes: 0b26351b910f ("stop_machine, sched: Fix migrate_swap() vs. active_balance() deadlock") Co-Developed-by: Prasad Sodagudi Signed-off-by: Prasad Sodagudi Co-Developed-by: Pavankumar Kondeti Signed-off-by: Pavankumar Kondeti Signed-off-by: Isaac J. Manjarres Signed-off-by: Thomas Gleixner Cc: peterz@infradead.org Cc: matt@codeblueprint.co.uk Cc: bigeasy@linutronix.de Cc: gregkh@linuxfoundation.org Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/1530655334-4601-1-git-send-email-isaacm@codeaurora.org Signed-off-by: Greg Kroah-Hartman --- kernel/stop_machine.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index 64c0291b579c..2f6fa95de2d8 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c @@ -270,7 +270,11 @@ static int cpu_stop_queue_two_works(int cpu1, struct cpu_stop_work *work1, goto retry; } - wake_up_q(&wakeq); + if (!err) { + preempt_disable(); + wake_up_q(&wakeq); + preempt_enable(); + } return err; } -- GitLab From 387362c3ed80bd266ab8cfdf971311044adbd478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 14 Jun 2018 20:56:25 +0300 Subject: [PATCH 0190/1001] drm/i915: Fix hotplug irq ack on i965/g4x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 96a85cc517a9ee4ae5e8d7f5a36cba05023784eb upstream. Just like with PIPESTAT, the edge triggered IIR on i965/g4x also causes problems for hotplug interrupts. To make sure we don't get the IIR port interrupt bit stuck low with the ISR bit high we must force an edge in ISR. Unfortunately we can't borrow the PIPESTAT trick and toggle the enable bits in PORT_HOTPLUG_EN as that act itself generates hotplug interrupts. Instead we just have to loop until we've cleared PORT_HOTPLUG_STAT, or we just give up and WARN. v2: Don't frob with PORT_HOTPLUG_EN Cc: stable@vger.kernel.org Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180614175625.1615-1-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak (cherry picked from commit 0ba7c51a6fd80a89236f6ceb52e63f8a7f62bfd3) Signed-off-by: Rodrigo Vivi Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_irq.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b63893eeca73..20a471ad0ad2 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1786,10 +1786,38 @@ static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv, static u32 i9xx_hpd_irq_ack(struct drm_i915_private *dev_priv) { - u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); + u32 hotplug_status = 0, hotplug_status_mask; + int i; + + if (IS_G4X(dev_priv) || + IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) + hotplug_status_mask = HOTPLUG_INT_STATUS_G4X | + DP_AUX_CHANNEL_MASK_INT_STATUS_G4X; + else + hotplug_status_mask = HOTPLUG_INT_STATUS_I915; - if (hotplug_status) + /* + * We absolutely have to clear all the pending interrupt + * bits in PORT_HOTPLUG_STAT. Otherwise the ISR port + * interrupt bit won't have an edge, and the i965/g4x + * edge triggered IIR will not notice that an interrupt + * is still pending. We can't use PORT_HOTPLUG_EN to + * guarantee the edge as the act of toggling the enable + * bits can itself generate a new hotplug interrupt :( + */ + for (i = 0; i < 10; i++) { + u32 tmp = I915_READ(PORT_HOTPLUG_STAT) & hotplug_status_mask; + + if (tmp == 0) + return hotplug_status; + + hotplug_status |= tmp; I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); + } + + WARN_ONCE(1, + "PORT_HOTPLUG_STAT did not clear (0x%08x)\n", + I915_READ(PORT_HOTPLUG_STAT)); return hotplug_status; } -- GitLab From 22c4488c864922b19dfed41c16ebf9568f78743b Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Fri, 13 Jul 2018 13:06:32 -0400 Subject: [PATCH 0191/1001] drm/nouveau: Use drm_connector_list_iter_* for iterating connectors commit 22b76bbe089cd901f5260ecb9a3dc41f9edb97a0 upstream. Every codepath in nouveau that loops through the connector list currently does so using the old method, which is prone to race conditions from MST connectors being created and destroyed. This has been causing a multitude of problems, including memory corruption from trying to access connectors that have already been freed! Signed-off-by: Lyude Paul Cc: stable@vger.kernel.org Cc: Karol Herbst Signed-off-by: Ben Skeggs Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nouveau_backlight.c | 6 ++++-- drivers/gpu/drm/nouveau/nouveau_connector.c | 9 +++++++-- drivers/gpu/drm/nouveau/nouveau_connector.h | 14 ++++++++++---- drivers/gpu/drm/nouveau/nouveau_display.c | 10 ++++++++-- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index debbbf0fd4bd..408b955e5c39 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -267,6 +267,7 @@ nouveau_backlight_init(struct drm_device *dev) struct nouveau_drm *drm = nouveau_drm(dev); struct nvif_device *device = &drm->client.device; struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; INIT_LIST_HEAD(&drm->bl_connectors); @@ -275,7 +276,8 @@ nouveau_backlight_init(struct drm_device *dev) return 0; } - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && connector->connector_type != DRM_MODE_CONNECTOR_eDP) continue; @@ -292,7 +294,7 @@ nouveau_backlight_init(struct drm_device *dev) break; } } - + drm_connector_list_iter_end(&conn_iter); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index c902a851eb51..53d93d95701f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -1208,14 +1208,19 @@ nouveau_connector_create(struct drm_device *dev, int index) struct nouveau_display *disp = nouveau_display(dev); struct nouveau_connector *nv_connector = NULL; struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; int type, ret = 0; bool dummy; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { nv_connector = nouveau_connector(connector); - if (nv_connector->index == index) + if (nv_connector->index == index) { + drm_connector_list_iter_end(&conn_iter); return connector; + } } + drm_connector_list_iter_end(&conn_iter); nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL); if (!nv_connector) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index a4d1a059bd3d..a8cbb4b56fc7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -65,14 +65,20 @@ nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc) { struct drm_device *dev = nv_crtc->base.dev; struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; + struct nouveau_connector *nv_connector = NULL; struct drm_crtc *crtc = to_drm_crtc(nv_crtc); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder && connector->encoder->crtc == crtc) - return nouveau_connector(connector); + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + if (connector->encoder && connector->encoder->crtc == crtc) { + nv_connector = nouveau_connector(connector); + break; + } } + drm_connector_list_iter_end(&conn_iter); - return NULL; + return nv_connector; } struct drm_connector * diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 2e7785f49e6d..3ab765b83be7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -405,6 +405,7 @@ nouveau_display_init(struct drm_device *dev) struct nouveau_display *disp = nouveau_display(dev); struct nouveau_drm *drm = nouveau_drm(dev); struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; int ret; ret = disp->init(dev); @@ -412,10 +413,12 @@ nouveau_display_init(struct drm_device *dev) return ret; /* enable hotplug interrupts */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { struct nouveau_connector *conn = nouveau_connector(connector); nvif_notify_get(&conn->hpd); } + drm_connector_list_iter_end(&conn_iter); /* enable flip completion events */ nvif_notify_get(&drm->flip); @@ -428,6 +431,7 @@ nouveau_display_fini(struct drm_device *dev, bool suspend) struct nouveau_display *disp = nouveau_display(dev); struct nouveau_drm *drm = nouveau_drm(dev); struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; if (!suspend) { if (drm_drv_uses_atomic_modeset(dev)) @@ -440,10 +444,12 @@ nouveau_display_fini(struct drm_device *dev, bool suspend) nvif_notify_put(&drm->flip); /* disable hotplug interrupts */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { struct nouveau_connector *conn = nouveau_connector(connector); nvif_notify_put(&conn->hpd); } + drm_connector_list_iter_end(&conn_iter); drm_kms_helper_poll_disable(dev); disp->fini(dev); -- GitLab From dd1363ca743eebf1dd7ccb6f9010b9d6de3afafc Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Fri, 13 Jul 2018 13:06:33 -0400 Subject: [PATCH 0192/1001] drm/nouveau: Avoid looping through fake MST connectors commit 37afe55b4ae0600deafe7c0e0e658593c4754f1b upstream. When MST and atomic were introduced to nouveau, another structure that could contain a drm_connector embedded within it was introduced; struct nv50_mstc. This meant that we no longer would be able to simply loop through our connector list and assume that nouveau_connector() would return a proper pointer for each connector, since the assertion that all connectors coming from nouveau have a full nouveau_connector struct became invalid. Unfortunately, none of the actual code that looped through connectors ever got updated, which means that we've been causing invalid memory accesses for quite a while now. An example that was caught by KASAN: [ 201.038698] ================================================================== [ 201.038792] BUG: KASAN: slab-out-of-bounds in nvif_notify_get+0x190/0x1a0 [nouveau] [ 201.038797] Read of size 4 at addr ffff88076738c650 by task kworker/0:3/718 [ 201.038800] [ 201.038822] CPU: 0 PID: 718 Comm: kworker/0:3 Tainted: G O 4.18.0-rc4Lyude-Test+ #1 [ 201.038825] Hardware name: LENOVO 20EQS64N0B/20EQS64N0B, BIOS N1EET78W (1.51 ) 05/18/2018 [ 201.038882] Workqueue: events nouveau_display_hpd_work [nouveau] [ 201.038887] Call Trace: [ 201.038894] dump_stack+0xa4/0xfd [ 201.038900] print_address_description+0x71/0x239 [ 201.038929] ? nvif_notify_get+0x190/0x1a0 [nouveau] [ 201.038935] kasan_report.cold.6+0x242/0x2fe [ 201.038942] __asan_report_load4_noabort+0x19/0x20 [ 201.038970] nvif_notify_get+0x190/0x1a0 [nouveau] [ 201.038998] ? nvif_notify_put+0x1f0/0x1f0 [nouveau] [ 201.039003] ? kmsg_dump_rewind_nolock+0xe4/0xe4 [ 201.039049] nouveau_display_init.cold.12+0x34/0x39 [nouveau] [ 201.039089] ? nouveau_user_framebuffer_create+0x120/0x120 [nouveau] [ 201.039133] nouveau_display_resume+0x5c0/0x810 [nouveau] [ 201.039173] ? nvkm_client_ioctl+0x20/0x20 [nouveau] [ 201.039215] nouveau_do_resume+0x19f/0x570 [nouveau] [ 201.039256] nouveau_pmops_runtime_resume+0xd8/0x2a0 [nouveau] [ 201.039264] pci_pm_runtime_resume+0x130/0x250 [ 201.039269] ? pci_restore_standard_config+0x70/0x70 [ 201.039275] __rpm_callback+0x1f2/0x5d0 [ 201.039279] ? rpm_resume+0x560/0x18a0 [ 201.039283] ? pci_restore_standard_config+0x70/0x70 [ 201.039287] ? pci_restore_standard_config+0x70/0x70 [ 201.039291] ? pci_restore_standard_config+0x70/0x70 [ 201.039296] rpm_callback+0x175/0x210 [ 201.039300] ? pci_restore_standard_config+0x70/0x70 [ 201.039305] rpm_resume+0xcc3/0x18a0 [ 201.039312] ? rpm_callback+0x210/0x210 [ 201.039317] ? __pm_runtime_resume+0x9e/0x100 [ 201.039322] ? kasan_check_write+0x14/0x20 [ 201.039326] ? do_raw_spin_lock+0xc2/0x1c0 [ 201.039333] __pm_runtime_resume+0xac/0x100 [ 201.039374] nouveau_display_hpd_work+0x67/0x1f0 [nouveau] [ 201.039380] process_one_work+0x7a0/0x14d0 [ 201.039388] ? cancel_delayed_work_sync+0x20/0x20 [ 201.039392] ? lock_acquire+0x113/0x310 [ 201.039398] ? kasan_check_write+0x14/0x20 [ 201.039402] ? do_raw_spin_lock+0xc2/0x1c0 [ 201.039409] worker_thread+0x86/0xb50 [ 201.039418] kthread+0x2e9/0x3a0 [ 201.039422] ? process_one_work+0x14d0/0x14d0 [ 201.039426] ? kthread_create_worker_on_cpu+0xc0/0xc0 [ 201.039431] ret_from_fork+0x3a/0x50 [ 201.039441] [ 201.039444] Allocated by task 79: [ 201.039449] save_stack+0x43/0xd0 [ 201.039452] kasan_kmalloc+0xc4/0xe0 [ 201.039456] kmem_cache_alloc_trace+0x10a/0x260 [ 201.039494] nv50_mstm_add_connector+0x9a/0x340 [nouveau] [ 201.039504] drm_dp_add_port+0xff5/0x1fc0 [drm_kms_helper] [ 201.039511] drm_dp_send_link_address+0x4a7/0x740 [drm_kms_helper] [ 201.039518] drm_dp_check_and_send_link_address+0x1a7/0x210 [drm_kms_helper] [ 201.039525] drm_dp_mst_link_probe_work+0x71/0xb0 [drm_kms_helper] [ 201.039529] process_one_work+0x7a0/0x14d0 [ 201.039533] worker_thread+0x86/0xb50 [ 201.039537] kthread+0x2e9/0x3a0 [ 201.039541] ret_from_fork+0x3a/0x50 [ 201.039543] [ 201.039546] Freed by task 0: [ 201.039549] (stack is not available) [ 201.039551] [ 201.039555] The buggy address belongs to the object at ffff88076738c1a8 which belongs to the cache kmalloc-2048 of size 2048 [ 201.039559] The buggy address is located 1192 bytes inside of 2048-byte region [ffff88076738c1a8, ffff88076738c9a8) [ 201.039563] The buggy address belongs to the page: [ 201.039567] page:ffffea001d9ce200 count:1 mapcount:0 mapping:ffff88084000d0c0 index:0x0 compound_mapcount: 0 [ 201.039573] flags: 0x8000000000008100(slab|head) [ 201.039578] raw: 8000000000008100 ffffea001da3be08 ffffea001da25a08 ffff88084000d0c0 [ 201.039582] raw: 0000000000000000 00000000000d000d 00000001ffffffff 0000000000000000 [ 201.039585] page dumped because: kasan: bad access detected [ 201.039588] [ 201.039591] Memory state around the buggy address: [ 201.039594] ffff88076738c500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 201.039598] ffff88076738c580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 201.039601] >ffff88076738c600: 00 00 00 00 00 00 00 00 00 00 fc fc fc fc fc fc [ 201.039604] ^ [ 201.039607] ffff88076738c680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 201.039611] ffff88076738c700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 201.039613] ================================================================== Signed-off-by: Lyude Paul Cc: stable@vger.kernel.org Cc: Karol Herbst Signed-off-by: Ben Skeggs Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nouveau_connector.c | 2 +- drivers/gpu/drm/nouveau/nouveau_connector.h | 24 ++++++++++++++++++++- drivers/gpu/drm/nouveau/nouveau_display.c | 4 ++-- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 53d93d95701f..430830d63a33 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -1213,7 +1213,7 @@ nouveau_connector_create(struct drm_device *dev, int index) bool dummy; drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { + nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) { nv_connector = nouveau_connector(connector); if (nv_connector->index == index) { drm_connector_list_iter_end(&conn_iter); diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index a8cbb4b56fc7..dc7454e7f19a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -33,6 +33,7 @@ #include #include #include "nouveau_crtc.h" +#include "nouveau_encoder.h" struct nvkm_i2c_port; @@ -60,6 +61,27 @@ static inline struct nouveau_connector *nouveau_connector( return container_of(con, struct nouveau_connector, base); } +static inline bool +nouveau_connector_is_mst(struct drm_connector *connector) +{ + const struct nouveau_encoder *nv_encoder; + const struct drm_encoder *encoder; + + if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) + return false; + + nv_encoder = find_encoder(connector, DCB_OUTPUT_ANY); + if (!nv_encoder) + return false; + + encoder = &nv_encoder->base.base; + return encoder->encoder_type == DRM_MODE_ENCODER_DPMST; +} + +#define nouveau_for_each_non_mst_connector_iter(connector, iter) \ + drm_for_each_connector_iter(connector, iter) \ + for_each_if(!nouveau_connector_is_mst(connector)) + static inline struct nouveau_connector * nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc) { @@ -70,7 +92,7 @@ nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc) struct drm_crtc *crtc = to_drm_crtc(nv_crtc); drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { + nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) { if (connector->encoder && connector->encoder->crtc == crtc) { nv_connector = nouveau_connector(connector); break; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 3ab765b83be7..caf53503c0f7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -414,7 +414,7 @@ nouveau_display_init(struct drm_device *dev) /* enable hotplug interrupts */ drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { + nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) { struct nouveau_connector *conn = nouveau_connector(connector); nvif_notify_get(&conn->hpd); } @@ -445,7 +445,7 @@ nouveau_display_fini(struct drm_device *dev, bool suspend) /* disable hotplug interrupts */ drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { + nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) { struct nouveau_connector *conn = nouveau_connector(connector); nvif_notify_put(&conn->hpd); } -- GitLab From c8347d91cfd7134e4fb242ac0a16511b589d7a5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= Date: Mon, 2 Jul 2018 22:52:20 +0200 Subject: [PATCH 0193/1001] gen_stats: Fix netlink stats dumping in the presence of padding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit d5a672ac9f48f81b20b1cad1d9ed7bbf4e418d4c ] The gen_stats facility will add a header for the toplevel nlattr of type TCA_STATS2 that contains all stats added by qdisc callbacks. A reference to this header is stored in the gnet_dump struct, and when all the per-qdisc callbacks have finished adding their stats, the length of the containing header will be adjusted to the right value. However, on architectures that need padding (i.e., that don't set CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), the padding nlattr is added before the stats, which means that the stored pointer will point to the padding, and so when the header is fixed up, the result is just a very big padding nlattr. Because most qdiscs also supply the legacy TCA_STATS struct, this problem has been mostly invisible, but we exposed it with the netlink attribute-based statistics in CAKE. Fix the issue by fixing up the stored pointer if it points to a padding nlattr. Tested-by: Pete Heist Tested-by: Kevin Darbyshire-Bryant Signed-off-by: Toke Høiland-Jørgensen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/gen_stats.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c index 87f28557b329..441c04adedba 100644 --- a/net/core/gen_stats.c +++ b/net/core/gen_stats.c @@ -77,8 +77,20 @@ gnet_stats_start_copy_compat(struct sk_buff *skb, int type, int tc_stats_type, d->lock = lock; spin_lock_bh(lock); } - if (d->tail) - return gnet_stats_copy(d, type, NULL, 0, padattr); + if (d->tail) { + int ret = gnet_stats_copy(d, type, NULL, 0, padattr); + + /* The initial attribute added in gnet_stats_copy() may be + * preceded by a padding attribute, in which case d->tail will + * end up pointing at the padding instead of the real attribute. + * Fix this so gnet_stats_finish_copy() adjusts the length of + * the right attribute. + */ + if (ret == 0 && d->tail->nla_type == padattr) + d->tail = (struct nlattr *)((char *)d->tail + + NLA_ALIGN(d->tail->nla_len)); + return ret; + } return 0; } -- GitLab From 0348dcd98af3b9bf3ddf4785e74b335bdc65bc4d Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Thu, 5 Jul 2018 18:49:23 +0000 Subject: [PATCH 0194/1001] ipv4: Return EINVAL when ping_group_range sysctl doesn't map to user ns [ Upstream commit 70ba5b6db96ff7324b8cfc87e0d0383cf59c9677 ] The low and high values of the net.ipv4.ping_group_range sysctl were being silently forced to the default disabled state when a write to the sysctl contained GIDs that didn't map to the associated user namespace. Confusingly, the sysctl's write operation would return success and then a subsequent read of the sysctl would indicate that the low and high values are the overflowgid. This patch changes the behavior by clearly returning an error when the sysctl write operation receives a GID range that doesn't map to the associated user namespace. In such a situation, the previous value of the sysctl is preserved and that range will be returned in a subsequent read of the sysctl. Signed-off-by: Tyler Hicks Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/sysctl_net_ipv4.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 5a29dc5083a3..d82e8344fc54 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -186,8 +186,9 @@ static int ipv4_ping_group_range(struct ctl_table *table, int write, if (write && ret == 0) { low = make_kgid(user_ns, urange[0]); high = make_kgid(user_ns, urange[1]); - if (!gid_valid(low) || !gid_valid(high) || - (urange[1] < urange[0]) || gid_lt(high, low)) { + if (!gid_valid(low) || !gid_valid(high)) + return -EINVAL; + if (urange[1] < urange[0] || gid_lt(high, low)) { low = make_kgid(&init_user_ns, 1); high = make_kgid(&init_user_ns, 0); } -- GitLab From a5d33d38bd37a16b4af224d35f4abfc686bfab01 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 17 Jul 2018 17:12:39 +0100 Subject: [PATCH 0195/1001] ipv6: fix useless rol32 call on hash [ Upstream commit 169dc027fb02492ea37a0575db6a658cf922b854 ] The rol32 call is currently rotating hash but the rol'd value is being discarded. I believe the current code is incorrect and hash should be assigned the rotated value returned from rol32. Thanks to David Lebrun for spotting this. Signed-off-by: Colin Ian King Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/ipv6.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index a54b8c58ccb7..e59f385da38e 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -795,7 +795,7 @@ static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb, * to minimize possbility that any useful information to an * attacker is leaked. Only lower 20 bits are relevant. */ - rol32(hash, 16); + hash = rol32(hash, 16); flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK; -- GitLab From 9f7276ce825bb1324dca2515d7b5e5d320af77f2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 18 Jul 2018 10:48:56 +0200 Subject: [PATCH 0196/1001] ipv6: ila: select CONFIG_DST_CACHE [ Upstream commit 83ed7d1fe2d2d4a11b30660dec20168bb473d9c1 ] My randconfig builds came across an old missing dependency for ILA: ERROR: "dst_cache_set_ip6" [net/ipv6/ila/ila.ko] undefined! ERROR: "dst_cache_get" [net/ipv6/ila/ila.ko] undefined! ERROR: "dst_cache_init" [net/ipv6/ila/ila.ko] undefined! ERROR: "dst_cache_destroy" [net/ipv6/ila/ila.ko] undefined! We almost never run into this by accident because randconfig builds end up selecting DST_CACHE from some other tunnel protocol, and this one appears to be the only one missing the explicit 'select'. >From all I can tell, this problem first appeared in linux-4.9 when dst_cache support got added to ILA. Fixes: 79ff2fc31e0f ("ila: Cache a route to translated address") Cc: Tom Herbert Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index ea71e4b0ab7a..2d36fd097299 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -109,6 +109,7 @@ config IPV6_MIP6 config IPV6_ILA tristate "IPv6: Identifier Locator Addressing (ILA)" depends on NETFILTER + select DST_CACHE select LWTUNNEL ---help--- Support for IPv6 Identifier Locator Addressing (ILA). -- GitLab From cfb876dc30429879584dde6ced2b18f8d0757b3e Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Mon, 16 Jul 2018 13:26:13 -0700 Subject: [PATCH 0197/1001] lib/rhashtable: consider param->min_size when setting initial table size [ Upstream commit 107d01f5ba10f4162c38109496607eb197059064 ] rhashtable_init() currently does not take into account the user-passed min_size parameter unless param->nelem_hint is set as well. As such, the default size (number of buckets) will always be HASH_DEFAULT_SIZE even if the smallest allowed size is larger than that. Remediate this by unconditionally calling into rounded_hashtable_size() and handling things accordingly. Signed-off-by: Davidlohr Bueso Acked-by: Herbert Xu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- lib/rhashtable.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/rhashtable.c b/lib/rhashtable.c index b734ce731a7a..39215c724fc7 100644 --- a/lib/rhashtable.c +++ b/lib/rhashtable.c @@ -878,8 +878,16 @@ EXPORT_SYMBOL_GPL(rhashtable_walk_stop); static size_t rounded_hashtable_size(const struct rhashtable_params *params) { - return max(roundup_pow_of_two(params->nelem_hint * 4 / 3), - (unsigned long)params->min_size); + size_t retsize; + + if (params->nelem_hint) + retsize = max(roundup_pow_of_two(params->nelem_hint * 4 / 3), + (unsigned long)params->min_size); + else + retsize = max(HASH_DEFAULT_SIZE, + (unsigned long)params->min_size); + + return retsize; } static u32 rhashtable_jhash2(const void *key, u32 length, u32 seed) @@ -936,8 +944,6 @@ int rhashtable_init(struct rhashtable *ht, struct bucket_table *tbl; size_t size; - size = HASH_DEFAULT_SIZE; - if ((!params->key_len && !params->obj_hashfn) || (params->obj_hashfn && !params->obj_cmpfn)) return -EINVAL; @@ -964,8 +970,7 @@ int rhashtable_init(struct rhashtable *ht, ht->p.min_size = max_t(u16, ht->p.min_size, HASH_MIN_SIZE); - if (params->nelem_hint) - size = rounded_hashtable_size(&ht->p); + size = rounded_hashtable_size(&ht->p); if (params->locks_mul) ht->p.locks_mul = roundup_pow_of_two(params->locks_mul); -- GitLab From cc0ab64759c89a640e8d57c106e85e6816380337 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sat, 7 Jul 2018 16:31:40 +0900 Subject: [PATCH 0198/1001] net: diag: Don't double-free TCP_NEW_SYN_RECV sockets in tcp_abort [ Upstream commit acc2cf4e37174646a24cba42fa53c668b2338d4e ] When tcp_diag_destroy closes a TCP_NEW_SYN_RECV socket, it first frees it by calling inet_csk_reqsk_queue_drop_and_and_put in tcp_abort, and then frees it again by calling sock_gen_put. Since tcp_abort only has one caller, and all the other codepaths in tcp_abort don't free the socket, just remove the free in that function. Cc: David Ahern Tested: passes Android sock_diag_test.py, which exercises this codepath Fixes: d7226c7a4dd1 ("net: diag: Fix refcnt leak in error path destroying socket") Signed-off-by: Lorenzo Colitti Signed-off-by: Eric Dumazet Reviewed-by: David Ahern Tested-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index e3ece12f0250..e81ff9d545a4 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3415,8 +3415,7 @@ int tcp_abort(struct sock *sk, int err) struct request_sock *req = inet_reqsk(sk); local_bh_disable(); - inet_csk_reqsk_queue_drop_and_put(req->rsk_listener, - req); + inet_csk_reqsk_queue_drop(req->rsk_listener, req); local_bh_enable(); return 0; } -- GitLab From 6403b54a4f7e097842d7814fe20124b32e5d3e1d Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Wed, 11 Jul 2018 14:39:42 +0200 Subject: [PATCH 0199/1001] net: Don't copy pfmemalloc flag in __copy_skb_header() [ Upstream commit 8b7008620b8452728cadead460a36f64ed78c460 ] The pfmemalloc flag indicates that the skb was allocated from the PFMEMALLOC reserves, and the flag is currently copied on skb copy and clone. However, an skb copied from an skb flagged with pfmemalloc wasn't necessarily allocated from PFMEMALLOC reserves, and on the other hand an skb allocated that way might be copied from an skb that wasn't. So we should not copy the flag on skb copy, and rather decide whether to allow an skb to be associated with sockets unrelated to page reclaim depending only on how it was allocated. Move the pfmemalloc flag before headers_start[0] using an existing 1-bit hole, so that __copy_skb_header() doesn't copy it. When cloning, we'll now take care of this flag explicitly, contravening to the warning comment of __skb_clone(). While at it, restore the newline usage introduced by commit b19372273164 ("net: reorganize sk_buff for faster __copy_skb_header()") to visually separate bytes used in bitfields after headers_start[0], that was gone after commit a9e419dc7be6 ("netfilter: merge ctinfo into nfct pointer storage area"), and describe the pfmemalloc flag in the kernel-doc structure comment. This doesn't change the size of sk_buff or cacheline boundaries, but consolidates the 15 bits hole before tc_index into a 2 bytes hole before csum, that could now be filled more easily. Reported-by: Patrick Talbert Fixes: c93bdd0e03e8 ("netvm: allow skb allocation to use PFMEMALLOC reserves") Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/skbuff.h | 10 +++++----- net/core/skbuff.c | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index be45224b01d7..9cf971c68401 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -624,6 +624,7 @@ typedef unsigned char *sk_buff_data_t; * @hash: the packet hash * @queue_mapping: Queue mapping for multiqueue devices * @xmit_more: More SKBs are pending for this queue + * @pfmemalloc: skbuff was allocated from PFMEMALLOC reserves * @ndisc_nodetype: router type (from link layer) * @ooo_okay: allow the mapping of a socket to a queue to be changed * @l4_hash: indicate hash is a canonical 4-tuple hash over transport @@ -722,7 +723,7 @@ struct sk_buff { peeked:1, head_frag:1, xmit_more:1, - __unused:1; /* one bit hole */ + pfmemalloc:1; /* fields enclosed in headers_start/headers_end are copied * using a single memcpy() in __copy_skb_header() @@ -741,31 +742,30 @@ struct sk_buff { __u8 __pkt_type_offset[0]; __u8 pkt_type:3; - __u8 pfmemalloc:1; __u8 ignore_df:1; - __u8 nf_trace:1; __u8 ip_summed:2; __u8 ooo_okay:1; + __u8 l4_hash:1; __u8 sw_hash:1; __u8 wifi_acked_valid:1; __u8 wifi_acked:1; - __u8 no_fcs:1; /* Indicates the inner headers are valid in the skbuff. */ __u8 encapsulation:1; __u8 encap_hdr_csum:1; __u8 csum_valid:1; + __u8 csum_complete_sw:1; __u8 csum_level:2; __u8 csum_not_inet:1; - __u8 dst_pending_confirm:1; #ifdef CONFIG_IPV6_NDISC_NODETYPE __u8 ndisc_nodetype:2; #endif __u8 ipvs_property:1; + __u8 inner_protocol_type:1; __u8 remcsum_offload:1; #ifdef CONFIG_NET_SWITCHDEV diff --git a/net/core/skbuff.c b/net/core/skbuff.c index c132eca9e383..159518a80a46 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -858,6 +858,8 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb) n->cloned = 1; n->nohdr = 0; n->peeked = 0; + if (skb->pfmemalloc) + n->pfmemalloc = 1; n->destructor = NULL; C(tail); C(end); -- GitLab From 829f4fd66354560fa66c83a3d199453036bef7ed Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Fri, 13 Jul 2018 13:21:07 +0200 Subject: [PATCH 0200/1001] skbuff: Unconditionally copy pfmemalloc in __skb_clone() [ Upstream commit e78bfb0751d4e312699106ba7efbed2bab1a53ca ] Commit 8b7008620b84 ("net: Don't copy pfmemalloc flag in __copy_skb_header()") introduced a different handling for the pfmemalloc flag in copy and clone paths. In __skb_clone(), now, the flag is set only if it was set in the original skb, but not cleared if it wasn't. This is wrong and might lead to socket buffers being flagged with pfmemalloc even if the skb data wasn't allocated from pfmemalloc reserves. Copy the flag instead of ORing it. Reported-by: Sabrina Dubroca Fixes: 8b7008620b84 ("net: Don't copy pfmemalloc flag in __copy_skb_header()") Signed-off-by: Stefano Brivio Tested-by: Sabrina Dubroca Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/skbuff.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 159518a80a46..23041b5c0b27 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -858,8 +858,7 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb) n->cloned = 1; n->nohdr = 0; n->peeked = 0; - if (skb->pfmemalloc) - n->pfmemalloc = 1; + C(pfmemalloc); n->destructor = NULL; C(tail); C(end); -- GitLab From 78382d78bb4a99ba312bfeef8b23006eb9f2e368 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sat, 7 Jul 2018 16:15:26 -0700 Subject: [PATCH 0201/1001] net/ipv4: Set oif in fib_compute_spec_dst [ Upstream commit e7372197e15856ec4ee66b668020a662994db103 ] Xin reported that icmp replies may not use the address on the device the echo request is received if the destination address is broadcast. Instead a route lookup is done without considering VRF context. Fix by setting oif in flow struct to the master device if it is enslaved. That directs the lookup to the VRF table. If the device is not enslaved, oif is still 0 so no affect. Fixes: cd2fbe1b6b51 ("net: Use VRF device index for lookups on RX") Reported-by: Xin Long Signed-off-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/fib_frontend.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index df8fd3ce713d..67eebcb113f3 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -290,6 +290,7 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb) if (!ipv4_is_zeronet(ip_hdr(skb)->saddr)) { struct flowi4 fl4 = { .flowi4_iif = LOOPBACK_IFINDEX, + .flowi4_oif = l3mdev_master_ifindex_rcu(dev), .daddr = ip_hdr(skb)->saddr, .flowi4_tos = RT_TOS(ip_hdr(skb)->tos), .flowi4_scope = scope, -- GitLab From 811ad4b366a60a7e05b20c3c8262bb95e69d4ade Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 3 Jul 2018 22:34:54 +0200 Subject: [PATCH 0202/1001] net: phy: fix flag masking in __set_phy_supported [ Upstream commit df8ed346d4a806a6eef2db5924285e839604b3f9 ] Currently also the pause flags are removed from phydev->supported because they're not included in PHY_DEFAULT_FEATURES. I don't think this is intended, especially when considering that this function can be called via phy_set_max_speed() anywhere in a driver. Change the masking to mask out only the values we're going to change. In addition remove the misleading comment, job of this small function is just to adjust the supported and advertised speeds. Fixes: f3a6bd393c2c ("phylib: Add phy_set_max_speed helper") Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/phy_device.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index a1e7ea4d4b16..a174d05a9752 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1686,11 +1686,8 @@ EXPORT_SYMBOL(genphy_loopback); static int __set_phy_supported(struct phy_device *phydev, u32 max_speed) { - /* The default values for phydev->supported are provided by the PHY - * driver "features" member, we want to reset to sane defaults first - * before supporting higher speeds. - */ - phydev->supported &= PHY_DEFAULT_FEATURES; + phydev->supported &= ~(PHY_1000BT_FEATURES | PHY_100BT_FEATURES | + PHY_10BT_FEATURES); switch (max_speed) { default: -- GitLab From 294dc77bb75e358c9e8350fd6217305c680bf1b3 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 17 Jul 2018 20:17:33 -0500 Subject: [PATCH 0203/1001] ptp: fix missing break in switch [ Upstream commit 9ba8376ce1e2cbf4ce44f7e4bee1d0648e10d594 ] It seems that a *break* is missing in order to avoid falling through to the default case. Otherwise, checking *chan* makes no sense. Fixes: 72df7a7244c0 ("ptp: Allow reassigning calibration pin function") Signed-off-by: Gustavo A. R. Silva Acked-by: Richard Cochran Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/ptp/ptp_chardev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index 58a97d420572..51364621f77c 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c @@ -89,6 +89,7 @@ int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin, case PTP_PF_PHYSYNC: if (chan != 0) return -EINVAL; + break; default: return -EINVAL; } -- GitLab From c84c7d8383c29effa009a03f05555ded0dce9bf3 Mon Sep 17 00:00:00 2001 From: Matevz Vucnik Date: Wed, 4 Jul 2018 18:12:48 +0200 Subject: [PATCH 0204/1001] qmi_wwan: add support for Quectel EG91 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 38cd58ed9c4e389799b507bcffe02a7a7a180b33 ] This adds the USB id of LTE modem Quectel EG91. It requires the same quirk as other Quectel modems to make it work. Signed-off-by: Matevz Vucnik Acked-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 0db500bf86d9..6d3811c869fd 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1252,6 +1252,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x1e0e, 0x9001, 5)}, /* SIMCom 7230E */ {QMI_QUIRK_SET_DTR(0x2c7c, 0x0125, 4)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ {QMI_QUIRK_SET_DTR(0x2c7c, 0x0121, 4)}, /* Quectel EC21 Mini PCIe */ + {QMI_QUIRK_SET_DTR(0x2c7c, 0x0191, 4)}, /* Quectel EG91 */ {QMI_FIXED_INTF(0x2c7c, 0x0296, 4)}, /* Quectel BG96 */ {QMI_QUIRK_SET_DTR(0x2c7c, 0x0306, 4)}, /* Quectel EP06 Mini PCIe */ -- GitLab From c7daaa272ddab653e2f2144e9dd497ded53a5bf7 Mon Sep 17 00:00:00 2001 From: Sanjeev Bansal Date: Mon, 16 Jul 2018 11:13:32 +0530 Subject: [PATCH 0205/1001] tg3: Add higher cpu clock for 5762. [ Upstream commit 3a498606bb04af603a46ebde8296040b2de350d1 ] This patch has fix for TX timeout while running bi-directional traffic with 100 Mbps using 5762. Signed-off-by: Sanjeev Bansal Signed-off-by: Siva Reddy Kallam Reviewed-by: Michael Chan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/tg3.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 9a8ef630466f..1b1d2a67f412 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -9279,6 +9279,15 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_restore_clk(tp); + /* Increase the core clock speed to fix tx timeout issue for 5762 + * with 100Mbps link speed. + */ + if (tg3_asic_rev(tp) == ASIC_REV_5762) { + val = tr32(TG3_CPMU_CLCK_ORIDE_ENABLE); + tw32(TG3_CPMU_CLCK_ORIDE_ENABLE, val | + TG3_CPMU_MAC_ORIDE_ENABLE); + } + /* Reprobe ASF enable state. */ tg3_flag_clear(tp, ENABLE_ASF); tp->phy_flags &= ~(TG3_PHYFLG_1G_ON_VAUX_OK | -- GitLab From 7e7fefde7dec77475457453f3e7e28acf3be1171 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Tue, 17 Jul 2018 17:11:13 +0000 Subject: [PATCH 0206/1001] hv_netvsc: Fix napi reschedule while receive completion is busy [ Upstream commit 6b81b193b83e87da1ea13217d684b54fccf8ee8a ] If out ring is full temporarily and receive completion cannot go out, we may still need to reschedule napi if certain conditions are met. Otherwise the napi poll might be stopped forever, and cause network disconnect. Fixes: 7426b1a51803 ("netvsc: optimize receive completions") Signed-off-by: Stephen Hemminger Signed-off-by: Haiyang Zhang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/hyperv/netvsc.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 701be5d81062..806239b89990 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -1250,6 +1250,7 @@ int netvsc_poll(struct napi_struct *napi, int budget) struct hv_device *device = netvsc_channel_to_device(channel); struct net_device *ndev = hv_get_drvdata(device); int work_done = 0; + int ret; /* If starting a new interval */ if (!nvchan->desc) @@ -1261,16 +1262,18 @@ int netvsc_poll(struct napi_struct *napi, int budget) nvchan->desc = hv_pkt_iter_next(channel, nvchan->desc); } - /* If send of pending receive completions suceeded - * and did not exhaust NAPI budget this time - * and not doing busy poll + /* Send any pending receive completions */ + ret = send_recv_completions(ndev, net_device, nvchan); + + /* If it did not exhaust NAPI budget this time + * and not doing busy poll * then re-enable host interrupts - * and reschedule if ring is not empty. + * and reschedule if ring is not empty + * or sending receive completion failed. */ - if (send_recv_completions(ndev, net_device, nvchan) == 0 && - work_done < budget && + if (work_done < budget && napi_complete_done(napi, work_done) && - hv_end_read(&channel->inbound) && + (ret || hv_end_read(&channel->inbound)) && napi_schedule_prep(napi)) { hv_begin_read(&channel->inbound); __napi_schedule(napi); -- GitLab From 65851c6b6d6ef51cfd37bd19e00a8045a58812ef Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Sun, 15 Jul 2018 13:54:39 +0300 Subject: [PATCH 0207/1001] net/mlx4_en: Don't reuse RX page when XDP is set [ Upstream commit 432e629e56432064761be63bcd5e263c0920430d ] When a new rx packet arrives, the rx path will decide whether to reuse the remainder of the page or not according to one of the below conditions: 1. frag_info->frag_stride == PAGE_SIZE / 2 2. frags->page_offset + frag_info->frag_size > PAGE_SIZE; The first condition is no met for when XDP is set. For XDP, page_offset is always set to priv->rx_headroom which is XDP_PACKET_HEADROOM and frag_info->frag_size is around mtu size + some padding, still the 2nd release condition will hold since XDP_PACKET_HEADROOM + 1536 < PAGE_SIZE, as a result the page will not be released and will be _wrongly_ reused for next free rx descriptor. In XDP there is an assumption to have a page per packet and reuse can break such assumption and might cause packet data corruptions. Fix this by adding an extra condition (!priv->rx_headroom) to the 2nd case to avoid page reuse when XDP is set, since rx_headroom is set to 0 for non XDP setup and set to XDP_PACKET_HEADROOM for XDP setup. No additional cache line is required for the new condition. Fixes: 34db548bfb95 ("mlx4: add page recycling in receive path") Signed-off-by: Saeed Mahameed Signed-off-by: Tariq Toukan Suggested-by: Martin KaFai Lau CC: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index b97a55c827eb..ab2a9dbb46c7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -472,10 +472,10 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv, { const struct mlx4_en_frag_info *frag_info = priv->frag_info; unsigned int truesize = 0; + bool release = true; int nr, frag_size; struct page *page; dma_addr_t dma; - bool release; /* Collect used fragments while replacing them in the HW descriptors */ for (nr = 0;; frags++) { @@ -498,7 +498,11 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv, release = page_count(page) != 1 || page_is_pfmemalloc(page) || page_to_nid(page) != numa_mem_id(); - } else { + } else if (!priv->rx_headroom) { + /* rx_headroom for non XDP setup is always 0. + * When XDP is set, the above condition will + * guarantee page is always released. + */ u32 sz_align = ALIGN(frag_size, SMP_CACHE_BYTES); frags->page_offset += sz_align; -- GitLab From 7c14cf21867cee5cb8f6b830d08769f01c1b69a7 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 11 Jul 2018 02:47:58 -0700 Subject: [PATCH 0208/1001] net: systemport: Fix CRC forwarding check for SYSTEMPORT Lite [ Upstream commit 9e3bff923913729d76d87f0015848ee7b8ff7083 ] SYSTEMPORT Lite reversed the logic compared to SYSTEMPORT, the GIB_FCS_STRIP bit is set when the Ethernet FCS is stripped, and that bit is not set by default. Fix the logic such that we properly check whether that bit is set or not and we don't forward an extra 4 bytes to the network stack. Fixes: 44a4524c54af ("net: systemport: Add support for SYSTEMPORT Lite") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bcmsysport.c | 4 ++-- drivers/net/ethernet/broadcom/bcmsysport.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 1e856e8b9a92..0fff2432ab4c 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -1851,8 +1851,8 @@ static int bcm_sysport_open(struct net_device *dev) if (!priv->is_lite) priv->crc_fwd = !!(umac_readl(priv, UMAC_CMD) & CMD_CRC_FWD); else - priv->crc_fwd = !!(gib_readl(priv, GIB_CONTROL) & - GIB_FCS_STRIP); + priv->crc_fwd = !((gib_readl(priv, GIB_CONTROL) & + GIB_FCS_STRIP) >> GIB_FCS_STRIP_SHIFT); phydev = of_phy_connect(dev, priv->phy_dn, bcm_sysport_adj_link, 0, priv->phy_interface); diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h index a2006f5fc26f..86ae751ccb5c 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.h +++ b/drivers/net/ethernet/broadcom/bcmsysport.h @@ -277,7 +277,8 @@ struct bcm_rsb { #define GIB_GTX_CLK_EXT_CLK (0 << GIB_GTX_CLK_SEL_SHIFT) #define GIB_GTX_CLK_125MHZ (1 << GIB_GTX_CLK_SEL_SHIFT) #define GIB_GTX_CLK_250MHZ (2 << GIB_GTX_CLK_SEL_SHIFT) -#define GIB_FCS_STRIP (1 << 6) +#define GIB_FCS_STRIP_SHIFT 6 +#define GIB_FCS_STRIP (1 << GIB_FCS_STRIP_SHIFT) #define GIB_LCL_LOOP_EN (1 << 7) #define GIB_LCL_LOOP_TXEN (1 << 8) #define GIB_RMT_LOOP_EN (1 << 9) -- GitLab From bbf9b1a46420191fe147a3d83bdce71fe594fea3 Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Fri, 13 Jul 2018 17:21:42 +0200 Subject: [PATCH 0209/1001] ipv6: make DAD fail with enhanced DAD when nonce length differs [ Upstream commit e66515999b627368892ccc9b3a13a506f2ea1357 ] Commit adc176c54722 ("ipv6 addrconf: Implemented enhanced DAD (RFC7527)") added enhanced DAD with a nonce length of 6 bytes. However, RFC7527 doesn't specify the length of the nonce, other than being 6 + 8*k bytes, with integer k >= 0 (RFC3971 5.3.2). The current implementation simply assumes that the nonce will always be 6 bytes, but others systems are free to choose different sizes. If another system sends a nonce of different length but with the same 6 bytes prefix, it shouldn't be considered as the same nonce. Thus, check that the length of the received nonce is the same as the length we sent. Ugly scapy test script running on veth0: def loop(): pkt=sniff(iface="veth0", filter="icmp6", count=1) pkt = pkt[0] b = bytearray(pkt[Raw].load) b[1] += 1 b += b'\xde\xad\xbe\xef\xde\xad\xbe\xef' pkt[Raw].load = bytes(b) pkt[IPv6].plen += 8 # fixup checksum after modifying the payload pkt[IPv6].payload.cksum -= 0x3b44 if pkt[IPv6].payload.cksum < 0: pkt[IPv6].payload.cksum += 0xffff sendp(pkt, iface="veth0") This should result in DAD failure for any address added to veth0's peer, but is currently ignored. Fixes: adc176c54722 ("ipv6 addrconf: Implemented enhanced DAD (RFC7527)") Signed-off-by: Sabrina Dubroca Reviewed-by: Stefano Brivio Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ndisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index d081db125905..528218460bc5 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -803,7 +803,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) return; } } - if (ndopts.nd_opts_nonce) + if (ndopts.nd_opts_nonce && ndopts.nd_opts_nonce->nd_opt_len == 1) memcpy(&nonce, (u8 *)(ndopts.nd_opts_nonce + 1), 6); inc = ipv6_addr_is_multicast(daddr); -- GitLab From 78cdeb665fb1f4cdc8fdbb95c584f916ba11f0f1 Mon Sep 17 00:00:00 2001 From: Alexander Couzens Date: Tue, 17 Jul 2018 13:17:09 +0200 Subject: [PATCH 0210/1001] net: usb: asix: replace mii_nway_restart in resume path [ Upstream commit 5c968f48021a9b3faa61ac2543cfab32461c0e05 ] mii_nway_restart is not pm aware which results in a rtnl deadlock. Implement mii_nway_restart manual by setting BMCR_ANRESTART if BMCR_ANENABLE is set. To reproduce: * plug an asix based usb network interface * wait until the device enters PM (~5 sec) * `ip link set eth1 up` will never return Fixes: d9fe64e51114 ("net: asix: Add in_pm parameter") Signed-off-by: Alexander Couzens Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/asix_devices.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 3d4f7959dabb..b1b3d8f7e67d 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -642,10 +642,12 @@ static void ax88772_restore_phy(struct usbnet *dev) priv->presvd_phy_advertise); /* Restore BMCR */ + if (priv->presvd_phy_bmcr & BMCR_ANENABLE) + priv->presvd_phy_bmcr |= BMCR_ANRESTART; + asix_mdio_write_nopm(dev->net, dev->mii.phy_id, MII_BMCR, priv->presvd_phy_bmcr); - mii_nway_restart(&dev->mii); priv->presvd_phy_advertise = 0; priv->presvd_phy_bmcr = 0; } -- GitLab From b12c7d0847e224301fb2323b5a85d866ead87199 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Jul 2018 15:07:11 +0100 Subject: [PATCH 0211/1001] alpha: fix osf_wait4() breakage commit f88a333b44318643282b8acc92af90deda441f5e upstream. kernel_wait4() expects a userland address for status - it's only rusage that goes as a kernel one (and needs a copyout afterwards) [ Also, fix the prototype of kernel_wait4() to have that __user annotation - Linus ] Fixes: 92ebce5ac55d ("osf_wait4: switch to kernel_wait4()") Cc: stable@kernel.org # v4.13+ Signed-off-by: Al Viro Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/alpha/kernel/osf_sys.c | 5 +---- include/linux/sched/task.h | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 75a5c35a2067..a48976dc9bcd 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -1183,13 +1183,10 @@ SYSCALL_DEFINE2(osf_getrusage, int, who, struct rusage32 __user *, ru) SYSCALL_DEFINE4(osf_wait4, pid_t, pid, int __user *, ustatus, int, options, struct rusage32 __user *, ur) { - unsigned int status = 0; struct rusage r; - long err = kernel_wait4(pid, &status, options, &r); + long err = kernel_wait4(pid, ustatus, options, &r); if (err <= 0) return err; - if (put_user(status, ustatus)) - return -EFAULT; if (!ur) return err; if (put_tv32(&ur->ru_utime, &r.ru_utime)) diff --git a/include/linux/sched/task.h b/include/linux/sched/task.h index 05b8650f06f5..a74ec619ac51 100644 --- a/include/linux/sched/task.h +++ b/include/linux/sched/task.h @@ -75,7 +75,7 @@ extern long _do_fork(unsigned long, unsigned long, unsigned long, int __user *, extern long do_fork(unsigned long, unsigned long, unsigned long, int __user *, int __user *); struct task_struct *fork_idle(int); extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); -extern long kernel_wait4(pid_t, int *, int, struct rusage *); +extern long kernel_wait4(pid_t, int __user *, int, struct rusage *); extern void free_task(struct task_struct *tsk); -- GitLab From ea8a50e5f829ad3e855f45b29e96612a92bb1418 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 9 Jun 2018 09:43:13 -0400 Subject: [PATCH 0212/1001] cxl_getfile(): fix double-iput() on alloc_file() failures commit d202797f480c0e5918e7642d6716cdc62b3ab5c9 upstream. Doing iput() after path_put() is wrong. Cc: stable@vger.kernel.org Acked-by: Linus Torvalds Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cxl/api.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c index a0c44d16bf30..c75daba57fd7 100644 --- a/drivers/misc/cxl/api.c +++ b/drivers/misc/cxl/api.c @@ -102,15 +102,15 @@ static struct file *cxl_getfile(const char *name, d_instantiate(path.dentry, inode); file = alloc_file(&path, OPEN_FMODE(flags), fops); - if (IS_ERR(file)) - goto err_dput; + if (IS_ERR(file)) { + path_put(&path); + goto err_fs; + } file->f_flags = flags & (O_ACCMODE | O_NONBLOCK); file->private_data = priv; return file; -err_dput: - path_put(&path); err_inode: iput(inode); err_fs: -- GitLab From ff42682f21d7084e0808171a973b0bcecd14ec14 Mon Sep 17 00:00:00 2001 From: "Gautham R. Shenoy" Date: Wed, 18 Jul 2018 14:03:16 +0530 Subject: [PATCH 0213/1001] powerpc/powernv: Fix save/restore of SPRG3 on entry/exit from stop (idle) commit b03897cf318dfc47de33a7ecbc7655584266f034 upstream. On 64-bit servers, SPRN_SPRG3 and its userspace read-only mirror SPRN_USPRG3 are used as userspace VDSO write and read registers respectively. SPRN_SPRG3 is lost when we enter stop4 and above, and is currently not restored. As a result, any read from SPRN_USPRG3 returns zero on an exit from stop4 (Power9 only) and above. Thus in this situation, on POWER9, any call from sched_getcpu() always returns zero, as on powerpc, we call __kernel_getcpu() which relies upon SPRN_USPRG3 to report the CPU and NUMA node information. Fix this by restoring SPRN_SPRG3 on wake up from a deep stop state with the sprg_vdso value that is cached in PACA. Fixes: e1c1cfed5432 ("powerpc/powernv: Save/Restore additional SPRs for stop4 cpuidle") Cc: stable@vger.kernel.org # v4.14+ Reported-by: Florian Weimer Signed-off-by: Gautham R. Shenoy Reviewed-by: Michael Ellerman Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/idle_book3s.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/kernel/idle_book3s.S b/arch/powerpc/kernel/idle_book3s.S index e35cebd45c35..4efbde0984b2 100644 --- a/arch/powerpc/kernel/idle_book3s.S +++ b/arch/powerpc/kernel/idle_book3s.S @@ -140,6 +140,8 @@ power9_restore_additional_sprs: ld r4, STOP_MMCR2(r13) mtspr SPRN_MMCR1, r3 mtspr SPRN_MMCR2, r4 + ld r4, PACA_SPRG_VDSO(r13) + mtspr SPRN_SPRG3, r4 blr /* -- GitLab From 3fcc143edcdd2ce497c9d2a0327c9b7ca1bbf403 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 21 Jun 2018 16:19:41 +0300 Subject: [PATCH 0214/1001] xhci: Fix perceived dead host due to runtime suspend race with event handler commit 229bc19fd7aca4f37964af06e3583c1c8f36b5d6 upstream. Don't rely on event interrupt (EINT) bit alone to detect pending port change in resume. If no change event is detected the host may be suspended again, oterwise roothubs are resumed. There is a lag in xHC setting EINT. If we don't notice the pending change in resume, and the controller is runtime suspeded again, it causes the event handler to assume host is dead as it will fail to read xHC registers once PCI puts the controller to D3 state. [ 268.520969] xhci_hcd: xhci_resume: starting port polling. [ 268.520985] xhci_hcd: xhci_hub_status_data: stopping port polling. [ 268.521030] xhci_hcd: xhci_suspend: stopping port polling. [ 268.521040] xhci_hcd: // Setting command ring address to 0x349bd001 [ 268.521139] xhci_hcd: Port Status Change Event for port 3 [ 268.521149] xhci_hcd: resume root hub [ 268.521163] xhci_hcd: port resume event for port 3 [ 268.521168] xhci_hcd: xHC is not running. [ 268.521174] xhci_hcd: handle_port_status: starting port polling. [ 268.596322] xhci_hcd: xhci_hc_died: xHCI host controller not responding, assume dead The EINT lag is described in a additional note in xhci specs 4.19.2: "Due to internal xHC scheduling and system delays, there will be a lag between a change bit being set and the Port Status Change Event that it generated being written to the Event Ring. If SW reads the PORTSC and sees a change bit set, there is no guarantee that the corresponding Port Status Change Event has already been written into the Event Ring." Cc: Signed-off-by: Mathias Nyman Signed-off-by: Kai-Heng Feng Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 40 +++++++++++++++++++++++++++++++++++++--- drivers/usb/host/xhci.h | 4 ++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index e5bccc6d49cf..fe84b36627ec 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -856,6 +856,41 @@ static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci) spin_unlock_irqrestore(&xhci->lock, flags); } +static bool xhci_pending_portevent(struct xhci_hcd *xhci) +{ + __le32 __iomem **port_array; + int port_index; + u32 status; + u32 portsc; + + status = readl(&xhci->op_regs->status); + if (status & STS_EINT) + return true; + /* + * Checking STS_EINT is not enough as there is a lag between a change + * bit being set and the Port Status Change Event that it generated + * being written to the Event Ring. See note in xhci 1.1 section 4.19.2. + */ + + port_index = xhci->num_usb2_ports; + port_array = xhci->usb2_ports; + while (port_index--) { + portsc = readl(port_array[port_index]); + if (portsc & PORT_CHANGE_MASK || + (portsc & PORT_PLS_MASK) == XDEV_RESUME) + return true; + } + port_index = xhci->num_usb3_ports; + port_array = xhci->usb3_ports; + while (port_index--) { + portsc = readl(port_array[port_index]); + if (portsc & PORT_CHANGE_MASK || + (portsc & PORT_PLS_MASK) == XDEV_RESUME) + return true; + } + return false; +} + /* * Stop HC (not bus-specific) * @@ -955,7 +990,7 @@ EXPORT_SYMBOL_GPL(xhci_suspend); */ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) { - u32 command, temp = 0, status; + u32 command, temp = 0; struct usb_hcd *hcd = xhci_to_hcd(xhci); struct usb_hcd *secondary_hcd; int retval = 0; @@ -1077,8 +1112,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) done: if (retval == 0) { /* Resume root hubs only when have pending events. */ - status = readl(&xhci->op_regs->status); - if (status & STS_EINT) { + if (xhci_pending_portevent(xhci)) { usb_hcd_resume_root_hub(xhci->shared_hcd); usb_hcd_resume_root_hub(hcd); } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 2a72060dda1b..11232e62b898 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -392,6 +392,10 @@ struct xhci_op_regs { #define PORT_PLC (1 << 22) /* port configure error change - port failed to configure its link partner */ #define PORT_CEC (1 << 23) +#define PORT_CHANGE_MASK (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \ + PORT_RC | PORT_PLC | PORT_CEC) + + /* Cold Attach Status - xHC can set this bit to report device attached during * Sx state. Warm port reset should be perfomed to clear this bit and move port * to connected state. -- GitLab From f952480a8fc14ea24a4de9582e425924f98c92d3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 25 Jul 2018 11:25:11 +0200 Subject: [PATCH 0215/1001] Linux 4.14.58 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a44d6b2adb76..ffc9b4e3867e 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 57 +SUBLEVEL = 58 EXTRAVERSION = NAME = Petit Gorille -- GitLab From 14ab23a0e6eb1e2955d04b062914d01e317598b3 Mon Sep 17 00:00:00 2001 From: Harsh Shah Date: Tue, 10 Jul 2018 15:28:33 -0700 Subject: [PATCH 0216/1001] msm: camera: isp: Fix race condition in tasklet stop This change sets the atomic variable tasklet_active to 0 in stop before calling flush. This also adds call to tasklet_kill before tasklet_disable in stop. This will fix a race condition between tasklet stop/enqueue. And it will ensure the tasklet is correctly halted and will not be raised repeatedly. Change-Id: Ibf9f78b41e3201be50cdee8653dd4e64d2142fbd Signed-off-by: Harsh Shah --- .../isp_hw_mgr/hw_utils/cam_tasklet_util.c | 60 +++++++++---------- .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 3 +- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c index b9c51de98dcc..2c08e4d3cf85 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c @@ -93,14 +93,14 @@ int cam_tasklet_get_cmd( } if (!atomic_read(&tasklet->tasklet_active)) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet is not active!\n"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet is not active"); rc = -EPIPE; return rc; } spin_lock_irqsave(&tasklet->tasklet_lock, flags); if (list_empty(&tasklet->free_cmd_list)) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "No more free tasklet cmd!\n"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "No more free tasklet cmd"); rc = -ENODEV; goto spin_unlock; } else { @@ -163,12 +163,6 @@ static int cam_tasklet_dequeue_cmd( *tasklet_cmd = NULL; - if (!atomic_read(&tasklet->tasklet_active)) { - CAM_ERR(CAM_ISP, "Tasklet is not active!"); - rc = -EPIPE; - return rc; - } - CAM_DBG(CAM_ISP, "Dequeue before lock."); spin_lock_irqsave(&tasklet->tasklet_lock, flags); if (list_empty(&tasklet->used_cmd_list)) { @@ -199,27 +193,28 @@ void cam_tasklet_enqueue_cmd( struct cam_tasklet_info *tasklet = bottom_half; if (!bottom_half) { - CAM_ERR(CAM_ISP, "NULL bottom half"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "NULL bottom half"); return; } if (!bh_cmd) { - CAM_ERR(CAM_ISP, "NULL bh cmd"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "NULL bh cmd"); return; } - if (tasklet_cmd) { - CAM_DBG(CAM_ISP, "Enqueue tasklet cmd"); - tasklet_cmd->bottom_half_handler = bottom_half_handler; - tasklet_cmd->payload = evt_payload_priv; - spin_lock_irqsave(&tasklet->tasklet_lock, flags); - list_add_tail(&tasklet_cmd->list, - &tasklet->used_cmd_list); - spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); - tasklet_schedule(&tasklet->tasklet); - } else { - CAM_ERR(CAM_ISP, "tasklet cmd is NULL!"); + if (!atomic_read(&tasklet->tasklet_active)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet is not active\n"); + return; } + + CAM_DBG(CAM_ISP, "Enqueue tasklet cmd"); + tasklet_cmd->bottom_half_handler = bottom_half_handler; + tasklet_cmd->payload = evt_payload_priv; + spin_lock_irqsave(&tasklet->tasklet_lock, flags); + list_add_tail(&tasklet_cmd->list, + &tasklet->used_cmd_list); + spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); + tasklet_schedule(&tasklet->tasklet); } int cam_tasklet_init( @@ -251,7 +246,7 @@ int cam_tasklet_init( } tasklet_init(&tasklet->tasklet, cam_tasklet_action, (unsigned long)tasklet); - cam_tasklet_stop(tasklet); + tasklet_disable(&tasklet->tasklet); *tasklet_info = tasklet; @@ -262,19 +257,18 @@ void cam_tasklet_deinit(void **tasklet_info) { struct cam_tasklet_info *tasklet = *tasklet_info; - atomic_set(&tasklet->tasklet_active, 0); - tasklet_kill(&tasklet->tasklet); + if (atomic_read(&tasklet->tasklet_active)) { + atomic_set(&tasklet->tasklet_active, 0); + tasklet_kill(&tasklet->tasklet); + tasklet_disable(&tasklet->tasklet); + } kfree(tasklet); *tasklet_info = NULL; } -static void cam_tasklet_flush(void *tasklet_info) +static inline void cam_tasklet_flush(struct cam_tasklet_info *tasklet_info) { - unsigned long data; - struct cam_tasklet_info *tasklet = tasklet_info; - - data = (unsigned long)tasklet; - cam_tasklet_action(data); + cam_tasklet_action((unsigned long) tasklet_info); } int cam_tasklet_start(void *tasklet_info) @@ -287,7 +281,6 @@ int cam_tasklet_start(void *tasklet_info) tasklet->index); return -EBUSY; } - atomic_set(&tasklet->tasklet_active, 1); /* clean up the command queue first */ for (i = 0; i < CAM_TASKLETQ_SIZE; i++) { @@ -296,6 +289,8 @@ int cam_tasklet_start(void *tasklet_info) &tasklet->free_cmd_list); } + atomic_set(&tasklet->tasklet_active, 1); + tasklet_enable(&tasklet->tasklet); return 0; @@ -305,9 +300,10 @@ void cam_tasklet_stop(void *tasklet_info) { struct cam_tasklet_info *tasklet = tasklet_info; - cam_tasklet_flush(tasklet); atomic_set(&tasklet->tasklet_active, 0); + tasklet_kill(&tasklet->tasklet); tasklet_disable(&tasklet->tasklet); + cam_tasklet_flush(tasklet); } /* diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index 2379bdc8e206..bab5f204b3ff 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -639,10 +639,11 @@ int cam_vfe_stop(void *hw_priv, void *stop_args, uint32_t arg_size) if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_IN) { cam_irq_controller_unsubscribe_irq( core_info->vfe_irq_controller, isp_res->irq_handle); + isp_res->irq_handle = 0; + rc = core_info->vfe_top->hw_ops.stop( core_info->vfe_top->top_priv, isp_res, sizeof(struct cam_isp_resource_node)); - } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) { rc = core_info->vfe_bus->hw_ops.stop(isp_res, NULL, 0); } else { -- GitLab From 79b6d79d0b0262e3fb63cb65a6df85b041dcad11 Mon Sep 17 00:00:00 2001 From: Suraj Dongre Date: Fri, 13 Jul 2018 13:54:37 -0700 Subject: [PATCH 0217/1001] msm: camera: jpeg: Fix flush with request id This change fixes page fault because of wrong type casting. This happens when flush is called with a request id. Also add code to stop processing request. Change-Id: I6d9aa9c3d71f5f83242d2ee8580bfe8380cfe36d Signed-off-by: Suraj Dongre --- .../camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 146 +++++++++++------- .../jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c | 2 +- 2 files changed, 94 insertions(+), 54 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index 8d033cd23d4d..74e0dacb4bf3 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -729,15 +729,59 @@ static int cam_jpeg_mgr_prepare_hw_update(void *hw_mgr_priv, return rc; } +static void cam_jpeg_mgr_stop_deinit_dev(struct cam_jpeg_hw_mgr *hw_mgr, + struct cam_jpeg_hw_cfg_req *p_cfg_req, uint32_t dev_type) +{ + int rc = 0; + struct cam_jpeg_set_irq_cb irq_cb; + + /* stop reset Unregister CB and deinit */ + irq_cb.jpeg_hw_mgr_cb = cam_jpeg_hw_mgr_cb; + irq_cb.data = NULL; + irq_cb.b_set_cb = false; + if (hw_mgr->devices[dev_type][0]->hw_ops.process_cmd) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.process_cmd( + hw_mgr->devices[dev_type][0]->hw_priv, + CAM_JPEG_CMD_SET_IRQ_CB, + &irq_cb, sizeof(irq_cb)); + if (rc) + CAM_ERR(CAM_JPEG, "SET_IRQ_CB fail %d", rc); + } else { + CAM_ERR(CAM_JPEG, "process_cmd null %d", dev_type); + } + + if (hw_mgr->devices[dev_type][0]->hw_ops.stop) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.stop( + hw_mgr->devices[dev_type][0]->hw_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_JPEG, "stop fail %d", rc); + } else { + CAM_ERR(CAM_JPEG, "op stop null %d", dev_type); + } + + if (hw_mgr->devices[dev_type][0]->hw_ops.deinit) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.deinit( + hw_mgr->devices[dev_type][0]->hw_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_JPEG, "Failed to Deinit %d HW %d", + dev_type, rc); + } else { + CAM_ERR(CAM_JPEG, "op deinit null %d", dev_type); + } + + hw_mgr->device_in_use[dev_type][0] = false; + hw_mgr->dev_hw_cfg_args[dev_type][0] = NULL; +} + static int cam_jpeg_mgr_flush(void *hw_mgr_priv, struct cam_jpeg_hw_ctx_data *ctx_data) { - int rc = 0; struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; uint32_t dev_type; struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL; struct cam_jpeg_hw_cfg_req *cfg_req = NULL, *req_temp = NULL; - struct cam_jpeg_set_irq_cb irq_cb; CAM_DBG(CAM_JPEG, "E: JPEG flush ctx"); @@ -753,51 +797,12 @@ static int cam_jpeg_mgr_flush(void *hw_mgr_priv, p_cfg_req != NULL) { if ((struct cam_jpeg_hw_ctx_data *) p_cfg_req->hw_cfg_args.ctxt_to_hw_map == ctx_data) { - /* stop reset Unregister CB and deinit */ - irq_cb.jpeg_hw_mgr_cb = cam_jpeg_hw_mgr_cb; - irq_cb.data = NULL; - irq_cb.b_set_cb = false; - if (hw_mgr->devices[dev_type][0]->hw_ops.process_cmd) { - rc = - hw_mgr->devices[dev_type][0]->hw_ops.process_cmd - (hw_mgr->devices[dev_type][0]->hw_priv, - CAM_JPEG_CMD_SET_IRQ_CB, &irq_cb, - sizeof(irq_cb)); - if (rc) - CAM_ERR(CAM_JPEG, - "CMD_SET_IRQ_CB failed %d", rc); - - } else { - CAM_ERR(CAM_JPEG, "process_cmd null "); - } - - if (hw_mgr->devices[dev_type][0]->hw_ops.stop) { - rc = hw_mgr->devices[dev_type][0]->hw_ops.stop( - hw_mgr->devices[dev_type][0]->hw_priv, - NULL, 0); - if (rc) - CAM_ERR(CAM_JPEG, "stop fail %d", rc); - } else { - CAM_ERR(CAM_JPEG, "op stop null "); - } - - if (hw_mgr->devices[dev_type][0]->hw_ops.deinit) { - rc = hw_mgr->devices[dev_type][0] - ->hw_ops.deinit( - hw_mgr->devices[dev_type][0]->hw_priv, - NULL, 0); - if (rc) - CAM_ERR(CAM_JPEG, - "Failed to Deinit %d HW", - dev_type); - } else { - CAM_ERR(CAM_JPEG, "op deinit null"); - } + cam_jpeg_mgr_stop_deinit_dev(hw_mgr, p_cfg_req, + dev_type); + list_del_init(&p_cfg_req->list); + list_add_tail(&p_cfg_req->list, + &hw_mgr->free_req_list); } - - hw_mgr->device_in_use[dev_type][0] = false; - p_cfg_req = hw_mgr->dev_hw_cfg_args[dev_type][0]; - hw_mgr->dev_hw_cfg_args[dev_type][0] = NULL; } list_for_each_entry_safe(cfg_req, req_temp, @@ -807,14 +812,14 @@ static int cam_jpeg_mgr_flush(void *hw_mgr_priv, continue; list_del_init(&cfg_req->list); + list_add_tail(&cfg_req->list, &hw_mgr->free_req_list); } - CAM_DBG(CAM_JPEG, "X: JPEG flush ctx with rc: %d", rc); + CAM_DBG(CAM_JPEG, "X: JPEG flush ctx"); - return rc; + return 0; } - static int cam_jpeg_mgr_flush_req(void *hw_mgr_priv, struct cam_jpeg_hw_ctx_data *ctx_data, struct cam_hw_flush_args *flush_args) @@ -822,7 +827,10 @@ static int cam_jpeg_mgr_flush_req(void *hw_mgr_priv, struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; struct cam_jpeg_hw_cfg_req *cfg_req = NULL; struct cam_jpeg_hw_cfg_req *req_temp = NULL; - int64_t request_id; + int64_t request_id = 0; + uint32_t dev_type; + struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL; + bool b_req_found = false; CAM_DBG(CAM_JPEG, "E: JPEG flush req"); @@ -834,7 +842,33 @@ static int cam_jpeg_mgr_flush_req(void *hw_mgr_priv, if (flush_args->num_req_pending) return 0; - request_id = *(int64_t *)flush_args->flush_req_active[0]; + request_id = (int64_t)flush_args->flush_req_active[0]; + + if (!flush_args->num_req_active) + return 0; + + if (request_id <= 0) { + CAM_ERR(CAM_JPEG, "Invalid red id %lld", request_id); + return -EINVAL; + } + + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + + p_cfg_req = hw_mgr->dev_hw_cfg_args[dev_type][0]; + if (hw_mgr->device_in_use[dev_type][0] == true && + p_cfg_req != NULL) { + if (((struct cam_jpeg_hw_ctx_data *) + p_cfg_req->hw_cfg_args.ctxt_to_hw_map == ctx_data) && + (p_cfg_req->req_id == request_id)) { + cam_jpeg_mgr_stop_deinit_dev(hw_mgr, p_cfg_req, + dev_type); + list_del_init(&p_cfg_req->list); + list_add_tail(&p_cfg_req->list, + &hw_mgr->free_req_list); + b_req_found = true; + } + } + list_for_each_entry_safe(cfg_req, req_temp, &hw_mgr->hw_config_req_list, list) { if ((struct cam_jpeg_hw_ctx_data *) @@ -845,10 +879,17 @@ static int cam_jpeg_mgr_flush_req(void *hw_mgr_priv, continue; list_del_init(&cfg_req->list); + list_add_tail(&cfg_req->list, &hw_mgr->free_req_list); + b_req_found = true; + break; } - CAM_DBG(CAM_JPEG, "X: JPEG flush req"); + if (!b_req_found) { + CAM_ERR(CAM_JPEG, "req not found %lld", request_id); + return -EINVAL; + } + CAM_DBG(CAM_JPEG, "X: JPEG flush req"); return 0; } @@ -888,7 +929,6 @@ static int cam_jpeg_mgr_hw_flush(void *hw_mgr_priv, void *flush_hw_args) break; case CAM_FLUSH_TYPE_REQ: rc = cam_jpeg_mgr_flush_req(hw_mgr_priv, ctx_data, flush_args); - CAM_ERR(CAM_JPEG, "Flush per request is not supported"); break; default: CAM_ERR(CAM_JPEG, "Invalid flush type: %d", diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c index 9fa691b2bff6..7fcc1ada1a36 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c @@ -349,7 +349,7 @@ int cam_jpeg_enc_stop_hw(void *data, hw_info = core_info->jpeg_enc_hw_info; mem_base = soc_info->reg_map[0].mem_base; - mutex_unlock(&core_info->core_mutex); + mutex_lock(&core_info->core_mutex); spin_lock(&jpeg_enc_dev->hw_lock); if (core_info->core_state == CAM_JPEG_ENC_CORE_ABORTING) { CAM_ERR(CAM_JPEG, "alrady stopping"); -- GitLab From b1e5d705925f7b59e2146995c78dd7a499bd3b35 Mon Sep 17 00:00:00 2001 From: Shankar Ravi Date: Mon, 23 Jul 2018 11:30:04 +0530 Subject: [PATCH 0218/1001] msm: camera: Check for valid per frame i2c data. Add check for valid i2c data per frame before consuming in the flush request for actuator. Change-Id: Iac18bce96eeb276f8244a033cec6f7f05fac5177 Signed-off-by: Shankar Ravi --- .../cam_sensor_module/cam_actuator/cam_actuator_core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c index a48cfa239293..ed0a26b70eff 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -878,6 +878,11 @@ int32_t cam_actuator_flush_request(struct cam_req_mgr_flush_request *flush_req) return -EINVAL; } + if (a_ctrl->i2c_data.per_frame == NULL) { + CAM_ERR(CAM_ACTUATOR, "i2c frame data is NULL"); + return -EINVAL; + } + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { i2c_set = &(a_ctrl->i2c_data.per_frame[i]); -- GitLab From e3be2f2aa4aed74aa8f406b3f32d03f263c686c2 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 25 Jul 2018 16:17:25 -0700 Subject: [PATCH 0219/1001] msm: camera: cpas: Modify error check The change fixes the error check while voting for axi clk. Change-Id: I1f32e8276c455878b9832fd45ec0f7596b3d9ff6 Signed-off-by: Karthik Anantha Ram --- drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c index e68e1614afa1..13417bd74a4e 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c +++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c @@ -597,7 +597,7 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( required_camnoc_bw, clk_rate); rc = cam_soc_util_set_src_clk_rate(soc_info, clk_rate); - if (!rc) + if (rc) CAM_ERR(CAM_CPAS, "Failed in setting camnoc axi clk %llu %d %d", required_camnoc_bw, clk_rate, rc); -- GitLab From 7569ff453ee759f340695a3eed6deec79f6bbb8f Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Wed, 18 Jul 2018 07:16:42 -0700 Subject: [PATCH 0220/1001] ANDROID: verity: fix android-verity Kconfig dependencies Bug: 72722987 Test: Android verity now shows up in 'make menuconfig' Change-Id: I21c2f36c17f45e5eb0daa1257f5817f9d56527e7 Signed-off-by: Sandeep Patil --- drivers/md/Kconfig | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 9f8b4e0dc3cc..fbe545a6183e 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -557,10 +557,11 @@ config DM_ZONED config DM_ANDROID_VERITY bool "Android verity target support" + depends on BLK_DEV_DM depends on DM_VERITY depends on X509_CERTIFICATE_PARSER depends on SYSTEM_TRUSTED_KEYRING - depends on PUBLIC_KEY_ALGO_RSA + depends on CRYPTO_RSA depends on KEYS depends on ASYMMETRIC_KEY_TYPE depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE @@ -575,8 +576,8 @@ config DM_ANDROID_VERITY config DM_ANDROID_VERITY_AT_MOST_ONCE_DEFAULT_ENABLED bool "Verity will validate blocks at most once" - depends on DM_VERITY - ---help--- + depends on DM_VERITY + ---help--- Default enables at_most_once option for dm-verity Verify data blocks only the first time they are read from the -- GitLab From cded2782129aaa3117e1ca2cb2485a65ca43e949 Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Tue, 24 Jul 2018 09:40:07 -0700 Subject: [PATCH 0221/1001] ANDROID: android-verity: Add API to verify signature with builtin keys. The builtin keyring was exported prior to this which allowed android-verity to simply lookup the key in the builtin keyring and verify the signature of the verity metadata. This is now broken as the kernel expects the signature to be in pkcs#7 format (same used for module signing). Obviously, this doesn't work with the verity metadata as we just append the raw signature in the metadata .. sigh. *This one time*, add an API to accept arbitrary signature and verify that with a key from system's trusted keyring. Bug: 72722987 Test: $ adb push verity_fs.img /data/local/tmp/ $ adb root && adb shell > cd /data/local/tmp > losetup /dev/block/loop0 verity_fs.img > dmctl create verity-fs android-verity 0 4200 Android:#7e4333f9bba00adfe0ede979e28ed1920492b40f 7:0 > mount -t ext4 /dev/block/dm-0 temp/ > cat temp/foo.txt temp/bar.txt Change-Id: I0c14f3cb2b587b73a4c75907367769688756213e Signed-off-by: Sandeep Patil --- certs/system_keyring.c | 43 +++++++++++++++++++++++++++++++++++- include/linux/verification.h | 8 +++++-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/certs/system_keyring.c b/certs/system_keyring.c index 6251d1b27f0c..0e1ea235c12a 100644 --- a/certs/system_keyring.c +++ b/certs/system_keyring.c @@ -263,5 +263,46 @@ int verify_pkcs7_signature(const void *data, size_t len, return ret; } EXPORT_SYMBOL_GPL(verify_pkcs7_signature); - #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */ + +/** + * verify_signature_one - Verify a signature with keys from given keyring + * @sig: The signature to be verified + * @trusted_keys: Trusted keys to use (NULL for builtin trusted keys only, + * (void *)1UL for all trusted keys). + * @keyid: key description (not partial) + */ +int verify_signature_one(const struct public_key_signature *sig, + struct key *trusted_keys, const char *keyid) +{ + key_ref_t ref; + struct key *key; + int ret; + + if (!sig) + return -EBADMSG; + if (!trusted_keys) { + trusted_keys = builtin_trusted_keys; + } else if (trusted_keys == (void *)1UL) { +#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING + trusted_keys = secondary_trusted_keys; +#else + trusted_keys = builtin_trusted_keys; +#endif + } + + ref = keyring_search(make_key_ref(trusted_keys, 1), + &key_type_asymmetric, keyid); + if (IS_ERR(ref)) { + pr_err("Asymmetric key (%s) not found in keyring(%s)\n", + keyid, trusted_keys->description); + return -ENOKEY; + } + + key = key_ref_to_ptr(ref); + ret = verify_signature(key, sig); + key_put(key); + return ret; +} +EXPORT_SYMBOL_GPL(verify_signature_one); + diff --git a/include/linux/verification.h b/include/linux/verification.h index a10549a6c7cd..5a088dab92e2 100644 --- a/include/linux/verification.h +++ b/include/linux/verification.h @@ -26,9 +26,13 @@ enum key_being_used_for { }; extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR]; -#ifdef CONFIG_SYSTEM_DATA_VERIFICATION - struct key; +struct public_key_signature; + +extern int verify_signature_one(const struct public_key_signature *sig, + struct key *trusted_keys, const char *keyid); + +#ifdef CONFIG_SYSTEM_DATA_VERIFICATION extern int verify_pkcs7_signature(const void *data, size_t len, const void *raw_pkcs7, size_t pkcs7_len, -- GitLab From 76905cc1d7e57925dd4b4f736b3f972f2e89509b Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Mon, 23 Jul 2018 16:31:32 -0700 Subject: [PATCH 0222/1001] ANDROID: android-verity: Make it work with newer kernels Fixed bio API calls as they changed from 4.4 to 4.9. Fixed the driver to use the new verify_signature_one() API. Remove the dead code resulted from the rebase. Bug: 72722987 Test: Build and boot hikey with system partition mounted as root using android-verity Signed-off-by: Sandeep Patil Change-Id: I1e29111d57b62f0451404c08d49145039dd00737 --- drivers/md/dm-android-verity.c | 194 +++++++++++++++------------------ drivers/md/dm-android-verity.h | 5 +- 2 files changed, 88 insertions(+), 111 deletions(-) diff --git a/drivers/md/dm-android-verity.c b/drivers/md/dm-android-verity.c index 0dd69244f77c..ce8dcfdee264 100644 --- a/drivers/md/dm-android-verity.c +++ b/drivers/md/dm-android-verity.c @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -122,75 +123,6 @@ static inline bool is_unlocked(void) return !strncmp(verifiedbootstate, unlocked, sizeof(unlocked)); } -static int table_extract_mpi_array(struct public_key_signature *pks, - const void *data, size_t len) -{ - MPI mpi = mpi_read_raw_data(data, len); - - if (!mpi) { - DMERR("Error while allocating mpi array"); - return -ENOMEM; - } - - pks->mpi[0] = mpi; - pks->nr_mpi = 1; - return 0; -} - -static struct public_key_signature *table_make_digest( - enum hash_algo hash, - const void *table, - unsigned long table_len) -{ - struct public_key_signature *pks = NULL; - struct crypto_shash *tfm; - struct shash_desc *desc; - size_t digest_size, desc_size; - int ret; - - /* Allocate the hashing algorithm we're going to need and find out how - * big the hash operational data will be. - */ - tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0); - if (IS_ERR(tfm)) - return ERR_CAST(tfm); - - desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); - digest_size = crypto_shash_digestsize(tfm); - - /* We allocate the hash operational data storage on the end of out - * context data and the digest output buffer on the end of that. - */ - ret = -ENOMEM; - pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL); - if (!pks) - goto error; - - pks->pkey_hash_algo = hash; - pks->digest = (u8 *)pks + sizeof(*pks) + desc_size; - pks->digest_size = digest_size; - - desc = (struct shash_desc *)(pks + 1); - desc->tfm = tfm; - desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; - - ret = crypto_shash_init(desc); - if (ret < 0) - goto error; - - ret = crypto_shash_finup(desc, table, table_len, pks->digest); - if (ret < 0) - goto error; - - crypto_free_shash(tfm); - return pks; - -error: - kfree(pks); - crypto_free_shash(tfm); - return ERR_PTR(ret); -} - static int read_block_dev(struct bio_read *payload, struct block_device *bdev, sector_t offset, int length) { @@ -205,8 +137,9 @@ static int read_block_dev(struct bio_read *payload, struct block_device *bdev, return -ENOMEM; } - bio->bi_bdev = bdev; + bio_set_dev(bio, bdev); bio->bi_iter.bi_sector = offset; + bio_set_op_attrs(bio, REQ_OP_READ, 0); payload->page_io = kzalloc(sizeof(struct page *) * payload->number_of_pages, GFP_KERNEL); @@ -230,7 +163,7 @@ static int read_block_dev(struct bio_read *payload, struct block_device *bdev, } } - if (!submit_bio_wait(READ, bio)) + if (!submit_bio_wait(bio)) /* success */ goto free_bio; DMERR("bio read failed"); @@ -567,28 +500,85 @@ static int verity_mode(void) return DM_VERITY_MODE_EIO; } +static void handle_error(void) +{ + int mode = verity_mode(); + if (mode == DM_VERITY_MODE_RESTART) { + DMERR("triggering restart"); + kernel_restart("dm-verity device corrupted"); + } else { + DMERR("Mounting verity root failed"); + } +} + +static struct public_key_signature *table_make_digest( + enum hash_algo hash, + const void *table, + unsigned long table_len) +{ + struct public_key_signature *pks = NULL; + struct crypto_shash *tfm; + struct shash_desc *desc; + size_t digest_size, desc_size; + int ret; + + /* Allocate the hashing algorithm we're going to need and find out how + * big the hash operational data will be. + */ + tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0); + if (IS_ERR(tfm)) + return ERR_CAST(tfm); + + desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); + digest_size = crypto_shash_digestsize(tfm); + + /* We allocate the hash operational data storage on the end of out + * context data and the digest output buffer on the end of that. + */ + ret = -ENOMEM; + pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL); + if (!pks) + goto error; + + pks->pkey_algo = "rsa"; + pks->hash_algo = hash_algo_name[hash]; + pks->digest = (u8 *)pks + sizeof(*pks) + desc_size; + pks->digest_size = digest_size; + + desc = (struct shash_desc *)(pks + 1); + desc->tfm = tfm; + desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; + + ret = crypto_shash_init(desc); + if (ret < 0) + goto error; + + ret = crypto_shash_finup(desc, table, table_len, pks->digest); + if (ret < 0) + goto error; + + crypto_free_shash(tfm); + return pks; + +error: + kfree(pks); + crypto_free_shash(tfm); + return ERR_PTR(ret); +} + + static int verify_verity_signature(char *key_id, struct android_metadata *metadata) { - key_ref_t key_ref; - struct key *key; struct public_key_signature *pks = NULL; int retval = -EINVAL; - key_ref = keyring_search(make_key_ref(system_trusted_keyring, 1), - &key_type_asymmetric, key_id); - - if (IS_ERR(key_ref)) { - DMERR("keyring: key not found"); - return -ENOKEY; - } - - key = key_ref_to_ptr(key_ref); + if (!key_id) + goto error; pks = table_make_digest(HASH_ALGO_SHA256, (const void *)metadata->verity_table, le32_to_cpu(metadata->header->table_length)); - if (IS_ERR(pks)) { DMERR("hashing failed"); retval = PTR_ERR(pks); @@ -596,33 +586,20 @@ static int verify_verity_signature(char *key_id, goto error; } - retval = table_extract_mpi_array(pks, &metadata->header->signature[0], - RSANUMBYTES); - if (retval < 0) { - DMERR("Error extracting mpi %d", retval); + pks->s = kmemdup(&metadata->header->signature[0], RSANUMBYTES, GFP_KERNEL); + if (!pks->s) { + DMERR("Error allocating memory for signature"); goto error; } + pks->s_size = RSANUMBYTES; - retval = verify_signature(key, pks); - mpi_free(pks->rsa.s); + retval = verify_signature_one(pks, NULL, key_id); + kfree(pks->s); error: kfree(pks); - key_put(key); - return retval; } -static void handle_error(void) -{ - int mode = verity_mode(); - if (mode == DM_VERITY_MODE_RESTART) { - DMERR("triggering restart"); - kernel_restart("dm-verity device corrupted"); - } else { - DMERR("Mounting verity root failed"); - } -} - static inline bool test_mult_overflow(sector_t a, u32 b) { sector_t r = (sector_t)~0ULL; @@ -696,8 +673,8 @@ static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv) dev_t uninitialized_var(dev); struct android_metadata *metadata = NULL; int err = 0, i, mode; - char *key_id, *table_ptr, dummy, *target_device, - *verity_table_args[VERITY_TABLE_ARGS + 2 + VERITY_TABLE_OPT_FEC_ARGS]; + char *key_id = NULL, *table_ptr, dummy, *target_device; + char *verity_table_args[VERITY_TABLE_ARGS + 2 + VERITY_TABLE_OPT_FEC_ARGS]; /* One for specifying number of opt args and one for mode */ sector_t data_sectors; u32 data_block_size; @@ -879,12 +856,11 @@ static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv) } err = verity_ctr(ti, no_of_args, verity_table_args); - - if (err) - DMERR("android-verity failed to mount as verity target"); - else { + if (err) { + DMERR("android-verity failed to create a verity target"); + } else { target_added = true; - DMINFO("android-verity mounted as verity target"); + DMINFO("android-verity created as verity target"); } free_metadata: diff --git a/drivers/md/dm-android-verity.h b/drivers/md/dm-android-verity.h index ed67d567f3ee..ef406c136fcd 100644 --- a/drivers/md/dm-android-verity.h +++ b/drivers/md/dm-android-verity.h @@ -120,8 +120,9 @@ extern int dm_linear_prepare_ioctl(struct dm_target *ti, extern int dm_linear_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data); extern int dm_linear_ctr(struct dm_target *ti, unsigned int argc, char **argv); -extern long dm_linear_dax_direct_access(struct dm_target *ti, sector_t sector, - void **kaddr, pfn_t *pfn, long size); +extern long dm_linear_dax_direct_access(struct dm_target *ti, pgoff_t pgoff, + long nr_pages, void **kaddr, + pfn_t *pfn); extern size_t dm_linear_dax_copy_from_iter(struct dm_target *ti, pgoff_t pgoff, void *addr, size_t bytes, struct iov_iter *i); #endif /* DM_ANDROID_VERITY_H */ -- GitLab From 5a591f8982317b5aba452dc0e117b7fdd157312c Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Tue, 24 Jul 2018 16:59:40 -0700 Subject: [PATCH 0223/1001] ANDROID: android-verity: Fix broken parameter handling. android-verity documentation states that the target expectets the key, followed by the backing device on the commandline as follows "dm=system none ro,0 1 android-verity " However, the code actually expects the backing device as the first parameter. Fix that. Bug: 72722987 Change-Id: Ibd56c0220f6003bdfb95aa2d611f787e75a65c97 Signed-off-by: Sandeep Patil --- drivers/md/dm-android-verity.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/md/dm-android-verity.c b/drivers/md/dm-android-verity.c index ce8dcfdee264..20e05936551f 100644 --- a/drivers/md/dm-android-verity.c +++ b/drivers/md/dm-android-verity.c @@ -693,16 +693,16 @@ static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv) handle_error(); return -EINVAL; } - } else if (argc == 2) - key_id = argv[1]; - else { + target_device = argv[0]; + } else if (argc == 2) { + key_id = argv[0]; + target_device = argv[1]; + } else { DMERR("Incorrect number of arguments"); handle_error(); return -EINVAL; } - target_device = argv[0]; - dev = name_to_dev_t(target_device); if (!dev) { DMERR("no dev found for %s", target_device); -- GitLab From 6dbe26267cb425b4ab09dc9cf8c221129541c35f Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Wed, 25 Jul 2018 16:11:38 -0700 Subject: [PATCH 0224/1001] x86_64_cuttlefish_defconfig: enable verity cert Bug: 72722987 Test: Build, boot and verify in /proc/keys Change-Id: Ia55b94d56827003a88cb6083a75340ee31347470 Signed-off-by: Alistair Strachan --- arch/x86/configs/x86_64_cuttlefish_defconfig | 5 ++++ verity_dev_keys.x509 | 24 ++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 verity_dev_keys.x509 diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 26a42b91140b..e33b351b1538 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -450,3 +450,8 @@ CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 # CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set CONFIG_CRYPTO_SHA512=y CONFIG_CRYPTO_DEV_VIRTIO=y +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="verity_dev_keys.x509" diff --git a/verity_dev_keys.x509 b/verity_dev_keys.x509 new file mode 100644 index 000000000000..86399c3c1dd7 --- /dev/null +++ b/verity_dev_keys.x509 @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID/TCCAuWgAwIBAgIJAJcPmDkJqolJMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4g +VmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEQMA4GA1UE +AwwHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe +Fw0xNDExMDYxOTA3NDBaFw00MjAzMjQxOTA3NDBaMIGUMQswCQYDVQQGEwJVUzET +MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4G +A1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEQMA4GA1UEAwwHQW5kcm9p +ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAOjreE0vTVSRenuzO9vnaWfk0eQzYab0gqpi +6xAzi6dmD+ugoEKJmbPiuE5Dwf21isZ9uhUUu0dQM46dK4ocKxMRrcnmGxydFn6o +fs3ODJMXOkv2gKXL/FdbEPdDbxzdu8z3yk+W67udM/fW7WbaQ3DO0knu+izKak/3 +T41c5uoXmQ81UNtAzRGzGchNVXMmWuTGOkg6U+0I2Td7K8yvUMWhAWPPpKLtVH9r +AL5TzjYNR92izdKcz3AjRsI3CTjtpiVABGeX0TcjRSuZB7K9EK56HV+OFNS6I1NP +jdD7FIShyGlqqZdUOkAUZYanbpgeT5N7QL6uuqcGpoTOkalu6kkCAwEAAaNQME4w +HQYDVR0OBBYEFH5DM/m7oArf4O3peeKO0ZIEkrQPMB8GA1UdIwQYMBaAFH5DM/m7 +oArf4O3peeKO0ZIEkrQPMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB +AHO3NSvDE5jFvMehGGtS8BnFYdFKRIglDMc4niWSzhzOVYRH4WajxdtBWc5fx0ix +NF/+hVKVhP6AIOQa+++sk+HIi7RvioPPbhjcsVlZe7cUEGrLSSveGouQyc+j0+m6 +JF84kszIl5GGNMTnx0XRPO+g8t6h5LWfnVydgZfpGRRg+WHewk1U2HlvTjIceb0N +dcoJ8WKJAFWdcuE7VIm4w+vF/DYX/A2Oyzr2+QRhmYSv1cusgAeC1tvH4ap+J1Lg +UnOu5Kh/FqPLLSwNVQp4Bu7b9QFfqK8Moj84bj88NqRGZgDyqzuTrFxn6FW7dmyA +yttuAJAEAymk1mipd9+zp38= +-----END CERTIFICATE----- -- GitLab From c1f37d3222e01b7dd6da846f0998afe9fab53d58 Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Wed, 25 Jul 2018 16:11:09 -0700 Subject: [PATCH 0225/1001] x86_64_cuttlefish_defconfig: Enable android-verity Bug: 72722987 Test: Build & boot with x86_64_cuttlefish_defconfig Change-Id: I961e6aaa944b5ab0c005cb39604a52f8dc98fb06 Signed-off-by: Alistair Strachan --- arch/x86/configs/x86_64_cuttlefish_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index e33b351b1538..19e3a812306b 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -219,7 +219,9 @@ CONFIG_DM_MIRROR=y CONFIG_DM_ZERO=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_HASH_PREFETCH_MIN_SIZE=1 CONFIG_DM_VERITY_FEC=y +CONFIG_DM_ANDROID_VERITY=y CONFIG_NETDEVICES=y CONFIG_NETCONSOLE=y CONFIG_NETCONSOLE_DYNAMIC=y @@ -447,6 +449,7 @@ CONFIG_SECURITY_PATH=y CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +CONFIG_CRYPTO_RSA=y # CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set CONFIG_CRYPTO_SHA512=y CONFIG_CRYPTO_DEV_VIRTIO=y -- GitLab From 842b0c071608da781cb9727a0101732d74f864e5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 23 Jul 2018 09:28:17 -0700 Subject: [PATCH 0226/1001] tcp: free batches of packets in tcp_prune_ofo_queue() [ Upstream commit 72cd43ba64fc172a443410ce01645895850844c8 ] Juha-Matti Tilli reported that malicious peers could inject tiny packets in out_of_order_queue, forcing very expensive calls to tcp_collapse_ofo_queue() and tcp_prune_ofo_queue() for every incoming packet. out_of_order_queue rb-tree can contain thousands of nodes, iterating over all of them is not nice. Before linux-4.9, we would have pruned all packets in ofo_queue in one go, every XXXX packets. XXXX depends on sk_rcvbuf and skbs truesize, but is about 7000 packets with tcp_rmem[2] default of 6 MB. Since we plan to increase tcp_rmem[2] in the future to cope with modern BDP, can not revert to the old behavior, without great pain. Strategy taken in this patch is to purge ~12.5 % of the queue capacity. Fixes: 36a6503fedda ("tcp: refine tcp_prune_ofo_queue() to not drop all packets") Signed-off-by: Eric Dumazet Reported-by: Juha-Matti Tilli Acked-by: Yuchung Cheng Acked-by: Soheil Hassas Yeganeh Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/skbuff.h | 2 ++ net/ipv4/tcp_input.c | 15 +++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index be45224b01d7..7bd63ee56dcc 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3167,6 +3167,8 @@ static inline int __skb_grow_rcsum(struct sk_buff *skb, unsigned int len) return __skb_grow(skb, len); } +#define rb_to_skb(rb) rb_entry_safe(rb, struct sk_buff, rbnode) + #define skb_queue_walk(queue, skb) \ for (skb = (queue)->next; \ skb != (struct sk_buff *)(queue); \ diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 5aae038c58b2..93878387ffa9 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4915,6 +4915,7 @@ static void tcp_collapse_ofo_queue(struct sock *sk) * 2) not add too big latencies if thousands of packets sit there. * (But if application shrinks SO_RCVBUF, we could still end up * freeing whole queue here) + * 3) Drop at least 12.5 % of sk_rcvbuf to avoid malicious attacks. * * Return true if queue has shrunk. */ @@ -4922,20 +4923,26 @@ static bool tcp_prune_ofo_queue(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); struct rb_node *node, *prev; + int goal; if (RB_EMPTY_ROOT(&tp->out_of_order_queue)) return false; NET_INC_STATS(sock_net(sk), LINUX_MIB_OFOPRUNED); + goal = sk->sk_rcvbuf >> 3; node = &tp->ooo_last_skb->rbnode; do { prev = rb_prev(node); rb_erase(node, &tp->out_of_order_queue); + goal -= rb_to_skb(node)->truesize; tcp_drop(sk, rb_entry(node, struct sk_buff, rbnode)); - sk_mem_reclaim(sk); - if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf && - !tcp_under_memory_pressure(sk)) - break; + if (!prev || goal <= 0) { + sk_mem_reclaim(sk); + if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf && + !tcp_under_memory_pressure(sk)) + break; + goal = sk->sk_rcvbuf >> 3; + } node = prev; } while (node); tp->ooo_last_skb = rb_entry(prev, struct sk_buff, rbnode); -- GitLab From b83a3d16a2393fe659e57c2b8c82fca04d57329f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 23 Jul 2018 09:28:18 -0700 Subject: [PATCH 0227/1001] tcp: avoid collapses in tcp_prune_queue() if possible [ Upstream commit f4a3313d8e2ca9fd8d8f45e40a2903ba782607e7 ] Right after a TCP flow is created, receiving tiny out of order packets allways hit the condition : if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) tcp_clamp_window(sk); tcp_clamp_window() increases sk_rcvbuf to match sk_rmem_alloc (guarded by tcp_rmem[2]) Calling tcp_collapse_ofo_queue() in this case is not useful, and offers a O(N^2) surface attack to malicious peers. Better not attempt anything before full queue capacity is reached, forcing attacker to spend lots of resource and allow us to more easily detect the abuse. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Acked-by: Yuchung Cheng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 93878387ffa9..f7eb63624692 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4977,6 +4977,9 @@ static int tcp_prune_queue(struct sock *sk) else if (tcp_under_memory_pressure(sk)) tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss); + if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) + return 0; + tcp_collapse_ofo_queue(sk); if (!skb_queue_empty(&sk->sk_receive_queue)) tcp_collapse(sk, &sk->sk_receive_queue, NULL, -- GitLab From 9175929203716d227813e9c6381e5018de90651a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 23 Jul 2018 09:28:19 -0700 Subject: [PATCH 0228/1001] tcp: detect malicious patterns in tcp_collapse_ofo_queue() [ Upstream commit 3d4bf93ac12003f9b8e1e2de37fe27983deebdcf ] In case an attacker feeds tiny packets completely out of order, tcp_collapse_ofo_queue() might scan the whole rb-tree, performing expensive copies, but not changing socket memory usage at all. 1) Do not attempt to collapse tiny skbs. 2) Add logic to exit early when too many tiny skbs are detected. We prefer not doing aggressive collapsing (which copies packets) for pathological flows, and revert to tcp_prune_ofo_queue() which will be less expensive. In the future, we might add the possibility of terminating flows that are proven to be malicious. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index f7eb63624692..ffdb0e66bf4e 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4868,6 +4868,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *root, static void tcp_collapse_ofo_queue(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); + u32 range_truesize, sum_tiny = 0; struct sk_buff *skb, *head; struct rb_node *p; u32 start, end; @@ -4886,6 +4887,7 @@ static void tcp_collapse_ofo_queue(struct sock *sk) } start = TCP_SKB_CB(skb)->seq; end = TCP_SKB_CB(skb)->end_seq; + range_truesize = skb->truesize; for (head = skb;;) { skb = tcp_skb_next(skb, NULL); @@ -4896,11 +4898,20 @@ static void tcp_collapse_ofo_queue(struct sock *sk) if (!skb || after(TCP_SKB_CB(skb)->seq, end) || before(TCP_SKB_CB(skb)->end_seq, start)) { - tcp_collapse(sk, NULL, &tp->out_of_order_queue, - head, skb, start, end); + /* Do not attempt collapsing tiny skbs */ + if (range_truesize != head->truesize || + end - start >= SKB_WITH_OVERHEAD(SK_MEM_QUANTUM)) { + tcp_collapse(sk, NULL, &tp->out_of_order_queue, + head, skb, start, end); + } else { + sum_tiny += range_truesize; + if (sum_tiny > sk->sk_rcvbuf >> 3) + return; + } goto new_range; } + range_truesize += skb->truesize; if (unlikely(before(TCP_SKB_CB(skb)->seq, start))) start = TCP_SKB_CB(skb)->seq; if (after(TCP_SKB_CB(skb)->end_seq, end)) -- GitLab From 9c6547184d37c1d81c8b715da98b046f8b2c2fe4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 23 Jul 2018 09:28:20 -0700 Subject: [PATCH 0229/1001] tcp: call tcp_drop() from tcp_data_queue_ofo() [ Upstream commit 8541b21e781a22dce52a74fef0b9bed00404a1cd ] In order to be able to give better diagnostics and detect malicious traffic, we need to have better sk->sk_drops tracking. Fixes: 9f5afeae5152 ("tcp: use an RB tree for ooo receive queue") Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Acked-by: Yuchung Cheng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index ffdb0e66bf4e..c404406d507f 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4483,7 +4483,7 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) /* All the bits are present. Drop. */ NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPOFOMERGE); - __kfree_skb(skb); + tcp_drop(sk, skb); skb = NULL; tcp_dsack_set(sk, seq, end_seq); goto add_sack; @@ -4502,7 +4502,7 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) TCP_SKB_CB(skb1)->end_seq); NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPOFOMERGE); - __kfree_skb(skb1); + tcp_drop(sk, skb1); goto merge_right; } } else if (tcp_try_coalesce(sk, OOO_QUEUE, skb1, -- GitLab From b4ffded8f9839596c8546d16919328b03834676d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 23 Jul 2018 09:28:21 -0700 Subject: [PATCH 0230/1001] tcp: add tcp_ooo_try_coalesce() helper [ Upstream commit 58152ecbbcc6a0ce7fddd5bf5f6ee535834ece0c ] In case skb in out_or_order_queue is the result of multiple skbs coalescing, we would like to get a proper gso_segs counter tracking, so that future tcp_drop() can report an accurate number. I chose to not implement this tracking for skbs in receive queue, since they are not dropped, unless socket is disconnected. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Acked-by: Yuchung Cheng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c404406d507f..59a1fb811c00 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4323,6 +4323,23 @@ static bool tcp_try_coalesce(struct sock *sk, return true; } +static bool tcp_ooo_try_coalesce(struct sock *sk, + struct sk_buff *to, + struct sk_buff *from, + bool *fragstolen) +{ + bool res = tcp_try_coalesce(sk, OOO_QUEUE, to, from, fragstolen); + + /* In case tcp_drop() is called later, update to->gso_segs */ + if (res) { + u32 gso_segs = max_t(u16, 1, skb_shinfo(to)->gso_segs) + + max_t(u16, 1, skb_shinfo(from)->gso_segs); + + skb_shinfo(to)->gso_segs = min_t(u32, gso_segs, 0xFFFF); + } + return res; +} + static void tcp_drop(struct sock *sk, struct sk_buff *skb) { sk_drops_add(sk, skb); @@ -4454,8 +4471,8 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) /* In the typical case, we are adding an skb to the end of the list. * Use of ooo_last_skb avoids the O(Log(N)) rbtree lookup. */ - if (tcp_try_coalesce(sk, OOO_QUEUE, tp->ooo_last_skb, - skb, &fragstolen)) { + if (tcp_ooo_try_coalesce(sk, tp->ooo_last_skb, + skb, &fragstolen)) { coalesce_done: tcp_grow_window(sk, skb); kfree_skb_partial(skb, fragstolen); @@ -4505,8 +4522,8 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) tcp_drop(sk, skb1); goto merge_right; } - } else if (tcp_try_coalesce(sk, OOO_QUEUE, skb1, - skb, &fragstolen)) { + } else if (tcp_ooo_try_coalesce(sk, skb1, + skb, &fragstolen)) { goto coalesce_done; } p = &parent->rb_right; -- GitLab From 627e3b5d46be0e445cd2fdaf0f5c16789924f50a Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Fri, 27 Jul 2018 09:18:28 -0700 Subject: [PATCH 0231/1001] ANDROID: verity: really fix android-verity Kconfig The change "ANDROID: verity: fix android-verity Kconfig dependencies" relaxed the dependency on DM_VERITY=y to just DM_VERITY, but this is not correct because there are parts of the verity and dm-mod API that android-verity is using but which are not exported to modules. Work around this problem by disallowing android-verity to be built-in when the dm/verity core is built modularly. Bug: 72722987 Change-Id: I3cfaa2acca8e4a4b5c459afdddd958ac9f8c1eb3 Signed-off-by: Alistair Strachan --- drivers/md/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index fbe545a6183e..d87c4725ed5b 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -557,8 +557,8 @@ config DM_ZONED config DM_ANDROID_VERITY bool "Android verity target support" - depends on BLK_DEV_DM - depends on DM_VERITY + depends on BLK_DEV_DM=y + depends on DM_VERITY=y depends on X509_CERTIFICATE_PARSER depends on SYSTEM_TRUSTED_KEYRING depends on CRYPTO_RSA -- GitLab From 33f3a7f43653301c4d20807a9304f8dc7103a101 Mon Sep 17 00:00:00 2001 From: Alok Pandey Date: Mon, 16 Jul 2018 23:11:08 +0530 Subject: [PATCH 0232/1001] msm: camera: sync: resolve race condition between merge and signal During merge, it ensures the state of merged fence and remaining count are serialized with any of the child node sync call. Change-Id: I443a82a39c2b6a52b70fe66b131fc9972b363c85 Signed-off-by: Alok Pandey Signed-off-by: Junzhe Zou --- .../platform/msm/camera/cam_sync/cam_sync.c | 39 ++- .../msm/camera/cam_sync/cam_sync_util.c | 222 ++++++------------ .../msm/camera/cam_sync/cam_sync_util.h | 19 +- 3 files changed, 99 insertions(+), 181 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c index 08ae4cee812d..efd3728d207c 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c @@ -43,7 +43,8 @@ int cam_sync_create(int32_t *sync_obj, const char *name) } while (bit); spin_lock_bh(&sync_dev->row_spinlocks[idx]); - rc = cam_sync_init_object(sync_dev->sync_table, idx, name); + rc = cam_sync_init_row(sync_dev->sync_table, idx, name, + CAM_SYNC_TYPE_INDV); if (rc) { CAM_ERR(CAM_SYNC, "Error: Unable to init row at idx = %ld", idx); @@ -183,6 +184,7 @@ int cam_sync_signal(int32_t sync_obj, uint32_t status) struct list_head sync_list; struct cam_signalable_info *list_info = NULL; struct cam_signalable_info *temp_list_info = NULL; + struct list_head parents_list; /* Objects to be signaled will be added into this list */ INIT_LIST_HEAD(&sync_list); @@ -237,20 +239,36 @@ int cam_sync_signal(int32_t sync_obj, uint32_t status) return rc; } + /* copy parent list to local and release child lock */ + INIT_LIST_HEAD(&parents_list); + list_splice_init(&row->parents_list, &parents_list); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + + if (list_empty(&parents_list)) + goto dispatch_cb; + /* * Now iterate over all parents of this object and if they too need to * be signaled add them to the list */ list_for_each_entry(parent_info, - &row->parents_list, + &parents_list, list) { parent_row = sync_dev->sync_table + parent_info->sync_id; spin_lock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); parent_row->remaining--; - parent_row->state = cam_sync_util_get_state( - parent_row->state, + rc = cam_sync_util_update_parent_state( + parent_row, status); + if (rc) { + CAM_ERR(CAM_SYNC, "Invalid parent state %d", + parent_row->state); + spin_unlock_bh( + &sync_dev->row_spinlocks[parent_info->sync_id]); + kfree(parent_info); + continue; + } if (!parent_row->remaining) { rc = cam_sync_util_add_to_signalable_list @@ -261,15 +279,13 @@ int cam_sync_signal(int32_t sync_obj, uint32_t status) spin_unlock_bh( &sync_dev->row_spinlocks[ parent_info->sync_id]); - spin_unlock_bh( - &sync_dev->row_spinlocks[sync_obj]); - return rc; + continue; } } spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); } - spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); +dispatch_cb: /* * Now dispatch the various sync objects collected so far, in our @@ -354,10 +370,8 @@ int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) return -EINVAL; } - rc = cam_sync_util_validate_merge(sync_obj, - num_objs); - if (rc < 0) { - CAM_ERR(CAM_SYNC, "Validation failed, Merge not allowed"); + if (num_objs <= 1) { + CAM_ERR(CAM_SYNC, "Single object merge is not allowed"); return -EINVAL; } @@ -369,7 +383,6 @@ int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) } while (bit); spin_lock_bh(&sync_dev->row_spinlocks[idx]); - rc = cam_sync_init_group_object(sync_dev->sync_table, idx, sync_obj, num_objs); diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c index 43bce513bff2..f391c8c8d51d 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c @@ -31,20 +31,21 @@ int cam_sync_util_find_and_set_empty_row(struct sync_device *sync_dev, return rc; } -int cam_sync_init_object(struct sync_table_row *table, - uint32_t idx, - const char *name) +int cam_sync_init_row(struct sync_table_row *table, + uint32_t idx, const char *name, uint32_t type) { struct sync_table_row *row = table + idx; if (!table || idx <= 0 || idx >= CAM_SYNC_MAX_OBJS) return -EINVAL; + memset(row, 0, sizeof(*row)); + if (name) strlcpy(row->name, name, SYNC_DEBUG_NAME_LEN); INIT_LIST_HEAD(&row->parents_list); INIT_LIST_HEAD(&row->children_list); - row->type = CAM_SYNC_TYPE_INDV; + row->type = type; row->sync_id = idx; row->state = CAM_SYNC_STATE_ACTIVE; row->remaining = 0; @@ -58,147 +59,95 @@ int cam_sync_init_object(struct sync_table_row *table, return 0; } -uint32_t cam_sync_util_get_group_object_state(struct sync_table_row *table, +int cam_sync_init_group_object(struct sync_table_row *table, + uint32_t idx, uint32_t *sync_objs, uint32_t num_objs) { - int i; + int i, rc = 0; + struct sync_child_info *child_info; + struct sync_parent_info *parent_info; + struct sync_table_row *row = table + idx; struct sync_table_row *child_row = NULL; - int success_count = 0; - int active_count = 0; - if (!table || !sync_objs) - return CAM_SYNC_STATE_SIGNALED_ERROR; + cam_sync_init_row(table, idx, "merged_fence", CAM_SYNC_TYPE_GROUP); /* - * We need to arrive at the state of the merged object based on - * counts of error, active and success states of all children objects + * While traversing for children, parent's row list is updated with + * child info and each child's row is updated with parent info. + * If any child state is ERROR or SUCCESS, it will not be added to list. */ for (i = 0; i < num_objs; i++) { - spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); child_row = table + sync_objs[i]; - switch (child_row->state) { - case CAM_SYNC_STATE_SIGNALED_ERROR: + spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + + /* validate child */ + if ((child_row->type == CAM_SYNC_TYPE_GROUP) || + (child_row->state == CAM_SYNC_STATE_INVALID)) { spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); - return CAM_SYNC_STATE_SIGNALED_ERROR; - case CAM_SYNC_STATE_SIGNALED_SUCCESS: - success_count++; - break; - case CAM_SYNC_STATE_ACTIVE: - active_count++; - break; - default: CAM_ERR(CAM_SYNC, - "Invalid state of child object during merge"); - spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); - return CAM_SYNC_STATE_SIGNALED_ERROR; + "Invalid child fence:%i state:%u type:%u", + child_row->sync_id, child_row->state, + child_row->type); + rc = -EINVAL; + goto clean_children_info; } - spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); - } - - if (active_count) - return CAM_SYNC_STATE_ACTIVE; - - if (success_count == num_objs) - return CAM_SYNC_STATE_SIGNALED_SUCCESS; - - return CAM_SYNC_STATE_SIGNALED_ERROR; -} - -static int cam_sync_util_get_group_object_remaining_count( - struct sync_table_row *table, - uint32_t *sync_objs, - uint32_t num_objs) -{ - int i; - struct sync_table_row *child_row = NULL; - int remaining_count = 0; - if (!table || !sync_objs) - return -EINVAL; - - for (i = 0; i < num_objs; i++) { - child_row = table + sync_objs[i]; - if (child_row->state == CAM_SYNC_STATE_ACTIVE) - remaining_count++; - } - - return remaining_count; -} - -int cam_sync_init_group_object(struct sync_table_row *table, - uint32_t idx, - uint32_t *sync_objs, - uint32_t num_objs) -{ - int i; - int remaining; - struct sync_child_info *child_info; - struct sync_parent_info *parent_info; - struct sync_table_row *row = table + idx; - struct sync_table_row *child_row = NULL; + /* check for child's state */ + if (child_row->state == CAM_SYNC_STATE_SIGNALED_ERROR) { + row->state = CAM_SYNC_STATE_SIGNALED_ERROR; + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + continue; + } + if (child_row->state != CAM_SYNC_STATE_ACTIVE) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + continue; + } - INIT_LIST_HEAD(&row->parents_list); + row->remaining++; - INIT_LIST_HEAD(&row->children_list); - - /* - * While traversing parents and children, we allocate in a loop and in - * case allocation fails, we call the clean up function which frees up - * all memory allocation thus far - */ - for (i = 0; i < num_objs; i++) { + /* Add child info */ child_info = kzalloc(sizeof(*child_info), GFP_ATOMIC); - if (!child_info) { - cam_sync_util_cleanup_children_list(row, - SYNC_LIST_CLEAN_ALL, 0); - return -ENOMEM; + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + rc = -ENOMEM; + goto clean_children_info; } - child_info->sync_id = sync_objs[i]; list_add_tail(&child_info->list, &row->children_list); - } - for (i = 0; i < num_objs; i++) { - /* This gets us the row corresponding to the sync object */ - child_row = table + sync_objs[i]; - spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + /* Add parent info */ parent_info = kzalloc(sizeof(*parent_info), GFP_ATOMIC); if (!parent_info) { - cam_sync_util_cleanup_parents_list(child_row, - SYNC_LIST_CLEAN_ALL, 0); - cam_sync_util_cleanup_children_list(row, - SYNC_LIST_CLEAN_ALL, 0); spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); - return -ENOMEM; + rc = -ENOMEM; + goto clean_children_info; } parent_info->sync_id = idx; list_add_tail(&parent_info->list, &child_row->parents_list); spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); } - row->type = CAM_SYNC_TYPE_GROUP; - row->sync_id = idx; - row->state = cam_sync_util_get_group_object_state(table, - sync_objs, num_objs); - remaining = cam_sync_util_get_group_object_remaining_count(table, - sync_objs, num_objs); - if (remaining < 0) { - CAM_ERR(CAM_SYNC, "Failed getting remaining count"); - return -ENODEV; + if (!row->remaining) { + if (row->state != CAM_SYNC_STATE_SIGNALED_ERROR) + row->state = CAM_SYNC_STATE_SIGNALED_SUCCESS; + complete_all(&row->signaled); } - row->remaining = remaining; - - init_completion(&row->signaled); - INIT_LIST_HEAD(&row->callback_list); - INIT_LIST_HEAD(&row->user_payload_list); + return 0; - if (row->state != CAM_SYNC_STATE_ACTIVE) - complete_all(&row->signaled); +clean_children_info: + row->state = CAM_SYNC_STATE_INVALID; + for (i = i-1; i >= 0; i--) { + spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + child_row = table + sync_objs[i]; + cam_sync_util_cleanup_parents_list(child_row, + SYNC_LIST_CLEAN_ONE, idx); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + } - return 0; + cam_sync_util_cleanup_children_list(row, SYNC_LIST_CLEAN_ALL, 0); + return rc; } int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx) @@ -363,32 +312,6 @@ void cam_sync_util_send_v4l2_event(uint32_t id, sync_obj); } -int cam_sync_util_validate_merge(uint32_t *sync_obj, uint32_t num_objs) -{ - int i; - struct sync_table_row *row = NULL; - - if (num_objs <= 1) { - CAM_ERR(CAM_SYNC, "Single object merge is not allowed"); - return -EINVAL; - } - - for (i = 0; i < num_objs; i++) { - row = sync_dev->sync_table + sync_obj[i]; - spin_lock_bh(&sync_dev->row_spinlocks[sync_obj[i]]); - if (row->type == CAM_SYNC_TYPE_GROUP || - row->state == CAM_SYNC_STATE_INVALID) { - CAM_ERR(CAM_SYNC, - "Group obj %d can't be merged or obj UNINIT", - sync_obj[i]); - spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj[i]]); - return -EINVAL; - } - spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj[i]]); - } - return 0; -} - int cam_sync_util_add_to_signalable_list(int32_t sync_obj, uint32_t status, struct list_head *sync_list) @@ -409,34 +332,27 @@ int cam_sync_util_add_to_signalable_list(int32_t sync_obj, return 0; } -int cam_sync_util_get_state(int current_state, +int cam_sync_util_update_parent_state(struct sync_table_row *parent_row, int new_state) { - int result = CAM_SYNC_STATE_SIGNALED_ERROR; - - if (new_state != CAM_SYNC_STATE_SIGNALED_SUCCESS && - new_state != CAM_SYNC_STATE_SIGNALED_ERROR) - return CAM_SYNC_STATE_SIGNALED_ERROR; - - switch (current_state) { - case CAM_SYNC_STATE_INVALID: - result = CAM_SYNC_STATE_SIGNALED_ERROR; - break; + int rc = 0; + switch (parent_row->state) { case CAM_SYNC_STATE_ACTIVE: case CAM_SYNC_STATE_SIGNALED_SUCCESS: - if (new_state == CAM_SYNC_STATE_SIGNALED_ERROR) - result = CAM_SYNC_STATE_SIGNALED_ERROR; - else if (new_state == CAM_SYNC_STATE_SIGNALED_SUCCESS) - result = CAM_SYNC_STATE_SIGNALED_SUCCESS; + parent_row->state = new_state; break; case CAM_SYNC_STATE_SIGNALED_ERROR: - result = CAM_SYNC_STATE_SIGNALED_ERROR; + break; + + case CAM_SYNC_STATE_INVALID: + default: + rc = -EINVAL; break; } - return result; + return rc; } void cam_sync_util_cleanup_children_list(struct sync_table_row *row, diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h index adb47dec07b4..a9d6f86c1709 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h @@ -41,12 +41,11 @@ int cam_sync_util_find_and_set_empty_row(struct sync_device *sync_dev, * @param idx : Index of row to initialize * @param name : Optional string representation of the sync object. Should be * 63 characters or less - * + * @param type : type of row to be initialized * @return Status of operation. Negative in case of error. Zero otherwise. */ -int cam_sync_init_object(struct sync_table_row *table, - uint32_t idx, - const char *name); +int cam_sync_init_row(struct sync_table_row *table, + uint32_t idx, const char *name, uint32_t type); /** * @brief: Function to uninitialize a row in the sync table @@ -103,16 +102,6 @@ void cam_sync_util_send_v4l2_event(uint32_t id, void *payload, int len); -/** - * @brief: Function to validate sync merge arguments - * - * @param sync_obj : Array of sync objects to merge - * @param num_objs : Number of sync objects in the array - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ -int cam_sync_util_validate_merge(uint32_t *sync_obj, uint32_t num_objs); - /** * @brief: Function which adds sync object information to the signalable list * @@ -135,7 +124,7 @@ int cam_sync_util_add_to_signalable_list(int32_t sync_obj, * * @return Next state of the sync object */ -int cam_sync_util_get_state(int current_state, +int cam_sync_util_update_parent_state(struct sync_table_row *parent_row, int new_state); /** -- GitLab From 4168a84223646130203c7b566c27f9a74abef7ea Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 26 Jul 2018 12:19:48 +0200 Subject: [PATCH 0233/1001] Revert "cifs: Fix slab-out-of-bounds in send_set_info() on SMB2 ACE setting" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 748144f35514aef14c4fdef5bcaa0db99cb9367a which is commit f46ecbd97f508e68a7806291a139499794874f3d upstream. Philip reports: seems adding "cifs: Fix slab-out-of-bounds in send_set_info() on SMB2 ACE setting" (commit 748144f) [1] created a regression within linux v4.14 kernel series. Writing to a mounted cifs either freezes on writing or crashes the PC. A more detailed explanation you may find in our forums [2]. Reverting the patch, seems to "fix" it. Thoughts? [2] https://forum.manjaro.org/t/53250 Reported-by: Philip Müller Cc: Jianhong Yin Cc: Stefano Brivio Cc: Aurelien Aptel Cc: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/smb2pdu.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 0480cd9a9e81..71b81980787f 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -338,10 +338,7 @@ smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon, return rc; /* BB eventually switch this to SMB2 specific small buf size */ - if (smb2_command == SMB2_SET_INFO) - *request_buf = cifs_buf_get(); - else - *request_buf = cifs_small_buf_get(); + *request_buf = cifs_small_buf_get(); if (*request_buf == NULL) { /* BB should we add a retry in here if not a writepage? */ return -ENOMEM; @@ -3171,7 +3168,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, } rc = SendReceive2(xid, ses, iov, num, &resp_buftype, flags, &rsp_iov); - cifs_buf_release(req); + cifs_small_buf_release(req); rsp = (struct smb2_set_info_rsp *)rsp_iov.iov_base; if (rc != 0) -- GitLab From 4c686d73bc3e090c8d8d55a07a1010955dcce9df Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 20 Jul 2018 13:58:21 +0200 Subject: [PATCH 0234/1001] MIPS: ath79: fix register address in ath79_ddr_wb_flush() commit bc88ad2efd11f29e00a4fd60fcd1887abfe76833 upstream. ath79_ddr_wb_flush_base has the type void __iomem *, so register offsets need to be a multiple of 4 in order to access the intended register. Signed-off-by: Felix Fietkau Signed-off-by: John Crispin Signed-off-by: Paul Burton Fixes: 24b0e3e84fbf ("MIPS: ath79: Improve the DDR controller interface") Patchwork: https://patchwork.linux-mips.org/patch/19912/ Cc: Alban Bedel Cc: James Hogan Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: stable@vger.kernel.org # 4.2+ Signed-off-by: Greg Kroah-Hartman --- arch/mips/ath79/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/ath79/common.c b/arch/mips/ath79/common.c index 10a405d593df..c782b10ddf50 100644 --- a/arch/mips/ath79/common.c +++ b/arch/mips/ath79/common.c @@ -58,7 +58,7 @@ EXPORT_SYMBOL_GPL(ath79_ddr_ctrl_init); void ath79_ddr_wb_flush(u32 reg) { - void __iomem *flush_reg = ath79_ddr_wb_flush_base + reg; + void __iomem *flush_reg = ath79_ddr_wb_flush_base + (reg * 4); /* Flush the DDR write buffer. */ __raw_writel(0x1, flush_reg); -- GitLab From de019e7857fb743bb50db9b82dd447d4894b5610 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 12 Jul 2018 09:33:04 -0700 Subject: [PATCH 0235/1001] MIPS: Fix off-by-one in pci_resource_to_user() commit 38c0a74fe06da3be133cae3fb7bde6a9438e698b upstream. The MIPS implementation of pci_resource_to_user() introduced in v3.12 by commit 4c2924b725fb ("MIPS: PCI: Use pci_resource_to_user to map pci memory space properly") incorrectly sets *end to the address of the byte after the resource, rather than the last byte of the resource. This results in userland seeing resources as a byte larger than they actually are, for example a 32 byte BAR will be reported by a tool such as lspci as being 33 bytes in size: Region 2: I/O ports at 1000 [disabled] [size=33] Correct this by subtracting one from the calculated end address, reporting the correct address to userland. Signed-off-by: Paul Burton Reported-by: Rui Wang Fixes: 4c2924b725fb ("MIPS: PCI: Use pci_resource_to_user to map pci memory space properly") Cc: James Hogan Cc: Ralf Baechle Cc: Wolfgang Grandegger Cc: linux-mips@linux-mips.org Cc: stable@vger.kernel.org # v3.12+ Patchwork: https://patchwork.linux-mips.org/patch/19829/ Signed-off-by: Greg Kroah-Hartman --- arch/mips/pci/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index 9632436d74d7..c2e94cf5ecda 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -54,5 +54,5 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar, phys_addr_t size = resource_size(rsrc); *start = fixup_bigphys_addr(rsrc->start, size); - *end = rsrc->start + size; + *end = rsrc->start + size - 1; } -- GitLab From 14500f14e0b6dd3fff66eec70b6bb1cf4d108dfa Mon Sep 17 00:00:00 2001 From: Boris Ostrovsky Date: Tue, 8 May 2018 19:56:22 -0400 Subject: [PATCH 0236/1001] xen/PVH: Set up GS segment for stack canary commit 98014068328c5574de9a4a30b604111fd9d8f901 upstream. We are making calls to C code (e.g. xen_prepare_pvh()) which may use stack canary (stored in GS segment). Signed-off-by: Boris Ostrovsky Reviewed-by: Juergen Gross Signed-off-by: Juergen Gross Cc: Jason Andryuk Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/xen-pvh.S | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/arch/x86/xen/xen-pvh.S b/arch/x86/xen/xen-pvh.S index e1a5fbeae08d..5d7554c025fd 100644 --- a/arch/x86/xen/xen-pvh.S +++ b/arch/x86/xen/xen-pvh.S @@ -54,6 +54,9 @@ * charge of setting up it's own stack, GDT and IDT. */ +#define PVH_GDT_ENTRY_CANARY 4 +#define PVH_CANARY_SEL (PVH_GDT_ENTRY_CANARY * 8) + ENTRY(pvh_start_xen) cld @@ -98,6 +101,12 @@ ENTRY(pvh_start_xen) /* 64-bit entry point. */ .code64 1: + /* Set base address in stack canary descriptor. */ + mov $MSR_GS_BASE,%ecx + mov $_pa(canary), %eax + xor %edx, %edx + wrmsr + call xen_prepare_pvh /* startup_64 expects boot_params in %rsi. */ @@ -107,6 +116,17 @@ ENTRY(pvh_start_xen) #else /* CONFIG_X86_64 */ + /* Set base address in stack canary descriptor. */ + movl $_pa(gdt_start),%eax + movl $_pa(canary),%ecx + movw %cx, (PVH_GDT_ENTRY_CANARY * 8) + 2(%eax) + shrl $16, %ecx + movb %cl, (PVH_GDT_ENTRY_CANARY * 8) + 4(%eax) + movb %ch, (PVH_GDT_ENTRY_CANARY * 8) + 7(%eax) + + mov $PVH_CANARY_SEL,%eax + mov %eax,%gs + call mk_early_pgtbl_32 mov $_pa(initial_page_table), %eax @@ -150,9 +170,13 @@ gdt_start: .quad GDT_ENTRY(0xc09a, 0, 0xfffff) /* __KERNEL_CS */ #endif .quad GDT_ENTRY(0xc092, 0, 0xfffff) /* __KERNEL_DS */ + .quad GDT_ENTRY(0x4090, 0, 0x18) /* PVH_CANARY_SEL */ gdt_end: - .balign 4 + .balign 16 +canary: + .fill 48, 1, 0 + early_stack: .fill 256, 1, 0 early_stack_end: -- GitLab From 58113603a4ea409a2b77daa1e1caa663c648c748 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Tue, 17 Jul 2018 17:19:13 +1000 Subject: [PATCH 0237/1001] KVM: PPC: Check if IOMMU page is contained in the pinned physical page commit 76fa4975f3ed12d15762bc979ca44078598ed8ee upstream. A VM which has: - a DMA capable device passed through to it (eg. network card); - running a malicious kernel that ignores H_PUT_TCE failure; - capability of using IOMMU pages bigger that physical pages can create an IOMMU mapping that exposes (for example) 16MB of the host physical memory to the device when only 64K was allocated to the VM. The remaining 16MB - 64K will be some other content of host memory, possibly including pages of the VM, but also pages of host kernel memory, host programs or other VMs. The attacking VM does not control the location of the page it can map, and is only allowed to map as many pages as it has pages of RAM. We already have a check in drivers/vfio/vfio_iommu_spapr_tce.c that an IOMMU page is contained in the physical page so the PCI hardware won't get access to unassigned host memory; however this check is missing in the KVM fastpath (H_PUT_TCE accelerated code). We were lucky so far and did not hit this yet as the very first time when the mapping happens we do not have tbl::it_userspace allocated yet and fall back to the userspace which in turn calls VFIO IOMMU driver, this fails and the guest does not retry, This stores the smallest preregistered page size in the preregistered region descriptor and changes the mm_iommu_xxx API to check this against the IOMMU page size. This calculates maximum page size as a minimum of the natural region alignment and compound page size. For the page shift this uses the shift returned by find_linux_pte() which indicates how the page is mapped to the current userspace - if the page is huge and this is not a zero, then it is a leaf pte and the page is mapped within the range. Fixes: 121f80ba68f1 ("KVM: PPC: VFIO: Add in-kernel acceleration for VFIO") Cc: stable@vger.kernel.org # v4.12+ Signed-off-by: Alexey Kardashevskiy Reviewed-by: David Gibson Signed-off-by: Michael Ellerman Signed-off-by: Alexey Kardashevskiy Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/mmu_context.h | 4 +-- arch/powerpc/kvm/book3s_64_vio.c | 2 +- arch/powerpc/kvm/book3s_64_vio_hv.c | 6 +++-- arch/powerpc/mm/mmu_context_iommu.c | 37 ++++++++++++++++++++++++-- drivers/vfio/vfio_iommu_spapr_tce.c | 2 +- 5 files changed, 43 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h index 44fdf4786638..6f67ff5a5267 100644 --- a/arch/powerpc/include/asm/mmu_context.h +++ b/arch/powerpc/include/asm/mmu_context.h @@ -35,9 +35,9 @@ extern struct mm_iommu_table_group_mem_t *mm_iommu_lookup_rm( extern struct mm_iommu_table_group_mem_t *mm_iommu_find(struct mm_struct *mm, unsigned long ua, unsigned long entries); extern long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem, - unsigned long ua, unsigned long *hpa); + unsigned long ua, unsigned int pageshift, unsigned long *hpa); extern long mm_iommu_ua_to_hpa_rm(struct mm_iommu_table_group_mem_t *mem, - unsigned long ua, unsigned long *hpa); + unsigned long ua, unsigned int pageshift, unsigned long *hpa); extern long mm_iommu_mapped_inc(struct mm_iommu_table_group_mem_t *mem); extern void mm_iommu_mapped_dec(struct mm_iommu_table_group_mem_t *mem); #endif diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c index 4dffa611376d..e14cec6bc339 100644 --- a/arch/powerpc/kvm/book3s_64_vio.c +++ b/arch/powerpc/kvm/book3s_64_vio.c @@ -433,7 +433,7 @@ long kvmppc_tce_iommu_map(struct kvm *kvm, struct iommu_table *tbl, /* This only handles v2 IOMMU type, v1 is handled via ioctl() */ return H_TOO_HARD; - if (WARN_ON_ONCE(mm_iommu_ua_to_hpa(mem, ua, &hpa))) + if (WARN_ON_ONCE(mm_iommu_ua_to_hpa(mem, ua, tbl->it_page_shift, &hpa))) return H_HARDWARE; if (mm_iommu_mapped_inc(mem)) diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c index c32e9bfe75b1..648cf6c01348 100644 --- a/arch/powerpc/kvm/book3s_64_vio_hv.c +++ b/arch/powerpc/kvm/book3s_64_vio_hv.c @@ -262,7 +262,8 @@ static long kvmppc_rm_tce_iommu_map(struct kvm *kvm, struct iommu_table *tbl, if (!mem) return H_TOO_HARD; - if (WARN_ON_ONCE_RM(mm_iommu_ua_to_hpa_rm(mem, ua, &hpa))) + if (WARN_ON_ONCE_RM(mm_iommu_ua_to_hpa_rm(mem, ua, tbl->it_page_shift, + &hpa))) return H_HARDWARE; pua = (void *) vmalloc_to_phys(pua); @@ -431,7 +432,8 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu, mem = mm_iommu_lookup_rm(vcpu->kvm->mm, ua, IOMMU_PAGE_SIZE_4K); if (mem) - prereg = mm_iommu_ua_to_hpa_rm(mem, ua, &tces) == 0; + prereg = mm_iommu_ua_to_hpa_rm(mem, ua, + IOMMU_PAGE_SHIFT_4K, &tces) == 0; } if (!prereg) { diff --git a/arch/powerpc/mm/mmu_context_iommu.c b/arch/powerpc/mm/mmu_context_iommu.c index e0a2d8e806ed..816055927ee4 100644 --- a/arch/powerpc/mm/mmu_context_iommu.c +++ b/arch/powerpc/mm/mmu_context_iommu.c @@ -19,6 +19,7 @@ #include #include #include +#include static DEFINE_MUTEX(mem_list_mutex); @@ -27,6 +28,7 @@ struct mm_iommu_table_group_mem_t { struct rcu_head rcu; unsigned long used; atomic64_t mapped; + unsigned int pageshift; u64 ua; /* userspace address */ u64 entries; /* number of entries in hpas[] */ u64 *hpas; /* vmalloc'ed */ @@ -126,6 +128,8 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries, { struct mm_iommu_table_group_mem_t *mem; long i, j, ret = 0, locked_entries = 0; + unsigned int pageshift; + unsigned long flags; struct page *page = NULL; mutex_lock(&mem_list_mutex); @@ -160,6 +164,12 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries, goto unlock_exit; } + /* + * For a starting point for a maximum page size calculation + * we use @ua and @entries natural alignment to allow IOMMU pages + * smaller than huge pages but still bigger than PAGE_SIZE. + */ + mem->pageshift = __ffs(ua | (entries << PAGE_SHIFT)); mem->hpas = vzalloc(entries * sizeof(mem->hpas[0])); if (!mem->hpas) { kfree(mem); @@ -200,6 +210,23 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries, } } populate: + pageshift = PAGE_SHIFT; + if (PageCompound(page)) { + pte_t *pte; + struct page *head = compound_head(page); + unsigned int compshift = compound_order(head); + + local_irq_save(flags); /* disables as well */ + pte = find_linux_pte(mm->pgd, ua, NULL, &pageshift); + local_irq_restore(flags); + + /* Double check it is still the same pinned page */ + if (pte && pte_page(*pte) == head && + pageshift == compshift) + pageshift = max_t(unsigned int, pageshift, + PAGE_SHIFT); + } + mem->pageshift = min(mem->pageshift, pageshift); mem->hpas[i] = page_to_pfn(page) << PAGE_SHIFT; } @@ -350,7 +377,7 @@ struct mm_iommu_table_group_mem_t *mm_iommu_find(struct mm_struct *mm, EXPORT_SYMBOL_GPL(mm_iommu_find); long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem, - unsigned long ua, unsigned long *hpa) + unsigned long ua, unsigned int pageshift, unsigned long *hpa) { const long entry = (ua - mem->ua) >> PAGE_SHIFT; u64 *va = &mem->hpas[entry]; @@ -358,6 +385,9 @@ long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem, if (entry >= mem->entries) return -EFAULT; + if (pageshift > mem->pageshift) + return -EFAULT; + *hpa = *va | (ua & ~PAGE_MASK); return 0; @@ -365,7 +395,7 @@ long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem, EXPORT_SYMBOL_GPL(mm_iommu_ua_to_hpa); long mm_iommu_ua_to_hpa_rm(struct mm_iommu_table_group_mem_t *mem, - unsigned long ua, unsigned long *hpa) + unsigned long ua, unsigned int pageshift, unsigned long *hpa) { const long entry = (ua - mem->ua) >> PAGE_SHIFT; void *va = &mem->hpas[entry]; @@ -374,6 +404,9 @@ long mm_iommu_ua_to_hpa_rm(struct mm_iommu_table_group_mem_t *mem, if (entry >= mem->entries) return -EFAULT; + if (pageshift > mem->pageshift) + return -EFAULT; + pa = (void *) vmalloc_to_phys(va); if (!pa) return -EFAULT; diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index b751dd60e41a..b4c68f3b82be 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -467,7 +467,7 @@ static int tce_iommu_prereg_ua_to_hpa(struct tce_container *container, if (!mem) return -EINVAL; - ret = mm_iommu_ua_to_hpa(mem, tce, phpa); + ret = mm_iommu_ua_to_hpa(mem, tce, shift, phpa); if (ret) return -EINVAL; -- GitLab From d0bd2c70ffcbf83ad02d551ad6f1c1a1a6664ef1 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Thu, 12 Jul 2018 13:02:53 -0400 Subject: [PATCH 0238/1001] drm/nouveau/drm/nouveau: Fix runtime PM leak in nv50_disp_atomic_commit() commit e5d54f1935722f83df7619f3978f774c2b802cd8 upstream. A CRTC being enabled doesn't mean it's on! It doesn't even necessarily mean it's being used. This fixes runtime PM leaks on the P50 I've got next to me. Signed-off-by: Lyude Paul Cc: stable@vger.kernel.org Signed-off-by: Ben Skeggs Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nv50_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index a29474528e85..8ce39f460866 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -4150,7 +4150,7 @@ nv50_disp_atomic_commit(struct drm_device *dev, nv50_disp_atomic_commit_tail(state); drm_for_each_crtc(crtc, dev) { - if (crtc->state->enable) { + if (crtc->state->active) { if (!drm->have_disp_power_ref) { drm->have_disp_power_ref = true; return 0; -- GitLab From 7e454c18b76f07ff14666853aba38a4e6890921f Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 3 Jul 2018 16:31:41 -0400 Subject: [PATCH 0239/1001] drm/nouveau: Set DRIVER_ATOMIC cap earlier to fix debugfs commit eb493fbc150f4a28151ae1ee84f24395989f3600 upstream. Currently nouveau doesn't actually expose the state debugfs file that's usually provided for any modesetting driver that supports atomic, even if nouveau is loaded with atomic=1. This is due to the fact that the standard debugfs files that DRM creates for atomic drivers is called when drm_get_pci_dev() is called from nouveau_drm.c. This happens well before we've initialized the display core, which is currently responsible for setting the DRIVER_ATOMIC cap. So, move the atomic option into nouveau_drm.c and just add the DRIVER_ATOMIC cap whenever it's enabled on the kernel commandline. This shouldn't cause any actual issues, as the atomic ioctl will still fail as expected even if the display core doesn't disable it until later in the init sequence. This also provides the added benefit of being able to use the state debugfs file to check the current display state even if clients aren't allowed to modify it through anything other than the legacy ioctls. Additionally, disable the DRIVER_ATOMIC cap in nv04's display core, as this was already disabled there previously. Signed-off-by: Lyude Paul Cc: stable@vger.kernel.org Signed-off-by: Ben Skeggs Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/dispnv04/disp.c | 3 +++ drivers/gpu/drm/nouveau/nouveau_drm.c | 7 +++++++ drivers/gpu/drm/nouveau/nv50_display.c | 6 ------ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.c b/drivers/gpu/drm/nouveau/dispnv04/disp.c index 5b9d549aa791..e7926da59214 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/disp.c @@ -55,6 +55,9 @@ nv04_display_create(struct drm_device *dev) nouveau_display(dev)->init = nv04_display_init; nouveau_display(dev)->fini = nv04_display_fini; + /* Pre-nv50 doesn't support atomic, so don't expose the ioctls */ + dev->driver->driver_features &= ~DRIVER_ATOMIC; + nouveau_hw_save_vga_fonts(dev, 1); nv04_crtc_create(dev, 0); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 595630d1fb9e..362a34cb435d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -79,6 +79,10 @@ MODULE_PARM_DESC(modeset, "enable driver (default: auto, " int nouveau_modeset = -1; module_param_named(modeset, nouveau_modeset, int, 0400); +MODULE_PARM_DESC(atomic, "Expose atomic ioctl (default: disabled)"); +static int nouveau_atomic = 0; +module_param_named(atomic, nouveau_atomic, int, 0400); + MODULE_PARM_DESC(runpm, "disable (0), force enable (1), optimus only default (-1)"); static int nouveau_runtime_pm = -1; module_param_named(runpm, nouveau_runtime_pm, int, 0400); @@ -383,6 +387,9 @@ static int nouveau_drm_probe(struct pci_dev *pdev, pci_set_master(pdev); + if (nouveau_atomic) + driver_pci.driver_features |= DRIVER_ATOMIC; + ret = drm_get_pci_dev(pdev, pent, &driver_pci); if (ret) { nvkm_device_del(&device); diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 8ce39f460866..926ec51ba5be 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -4398,10 +4398,6 @@ nv50_display_destroy(struct drm_device *dev) kfree(disp); } -MODULE_PARM_DESC(atomic, "Expose atomic ioctl (default: disabled)"); -static int nouveau_atomic = 0; -module_param_named(atomic, nouveau_atomic, int, 0400); - int nv50_display_create(struct drm_device *dev) { @@ -4426,8 +4422,6 @@ nv50_display_create(struct drm_device *dev) disp->disp = &nouveau_display(dev)->disp; dev->mode_config.funcs = &nv50_disp_func; dev->driver->driver_features |= DRIVER_PREFER_XBGR_30BPP; - if (nouveau_atomic) - dev->driver->driver_features |= DRIVER_ATOMIC; /* small shared memory area we use for notifiers and semaphores */ ret = nouveau_bo_new(&drm->client, 4096, 0x1000, TTM_PL_FLAG_VRAM, -- GitLab From f1fb27fc256ce822ce22838c0edd862c76b04dc6 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Wed, 18 Jul 2018 14:49:36 -0400 Subject: [PATCH 0240/1001] bonding: set default miimon value for non-arp modes if not set [ Upstream commit c1f897ce186a529a494441642125479d38727a3d ] For some time now, if you load the bonding driver and configure bond parameters via sysfs using minimal config options, such as specifying nothing but the mode, relying on defaults for everything else, modes that cannot use arp monitoring (802.3ad, balance-tlb, balance-alb) all wind up with both arp_interval=0 (as it should be) and miimon=0, which means the miimon monitor thread never actually runs. This is particularly problematic for 802.3ad. For example, from an LNST recipe I've set up: $ modprobe bonding max_bonds=0" $ echo "+t_bond0" > /sys/class/net/bonding_masters" $ ip link set t_bond0 down" $ echo "802.3ad" > /sys/class/net/t_bond0/bonding/mode" $ ip link set ens1f1 down" $ echo "+ens1f1" > /sys/class/net/t_bond0/bonding/slaves" $ ip link set ens1f0 down" $ echo "+ens1f0" > /sys/class/net/t_bond0/bonding/slaves" $ ethtool -i t_bond0" $ ip link set ens1f1 up" $ ip link set ens1f0 up" $ ip link set t_bond0 up" $ ip addr add 192.168.9.1/24 dev t_bond0" $ ip addr add 2002::1/64 dev t_bond0" This bond comes up okay, but things look slightly suspect in /proc/net/bonding/t_bond0 output: $ grep -i mii /proc/net/bonding/t_bond0 MII Status: up MII Polling Interval (ms): 0 MII Status: up MII Status: up Now, pull a cable on one of the ports in the bond, then reconnect it, and you'll see: Slave Interface: ens1f0 MII Status: down Speed: 1000 Mbps Duplex: full I believe this became a major issue as of commit 4d2c0cda0744, which for 802.3ad bonds, sets slave->link = BOND_LINK_DOWN, with a comment about relying on link monitoring via miimon to set it correctly, but since the miimon work queue never runs, the link just stays marked down. If we simply tweak bond_option_mode_set() slightly, we can check for the non-arp modes having no miimon value set, and insert BOND_DEFAULT_MIIMON, which gets things back in full working order. This problem exists as far back as 4.14, and might be worth fixing in all stable trees since, though the work-around is to simply specify an miimon value yourself. Reported-by: Bob Ball Signed-off-by: Jarod Wilson Acked-by: Mahesh Bandewar Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_options.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 61084ba69a99..3d154eb63dcf 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -743,15 +743,20 @@ const struct bond_option *bond_opt_get(unsigned int option) static int bond_option_mode_set(struct bonding *bond, const struct bond_opt_value *newval) { - if (!bond_mode_uses_arp(newval->value) && bond->params.arp_interval) { - netdev_dbg(bond->dev, "%s mode is incompatible with arp monitoring, start mii monitoring\n", - newval->string); - /* disable arp monitoring */ - bond->params.arp_interval = 0; - /* set miimon to default value */ - bond->params.miimon = BOND_DEFAULT_MIIMON; - netdev_dbg(bond->dev, "Setting MII monitoring interval to %d\n", - bond->params.miimon); + if (!bond_mode_uses_arp(newval->value)) { + if (bond->params.arp_interval) { + netdev_dbg(bond->dev, "%s mode is incompatible with arp monitoring, start mii monitoring\n", + newval->string); + /* disable arp monitoring */ + bond->params.arp_interval = 0; + } + + if (!bond->params.miimon) { + /* set miimon to default value */ + bond->params.miimon = BOND_DEFAULT_MIIMON; + netdev_dbg(bond->dev, "Setting MII monitoring interval to %d\n", + bond->params.miimon); + } } if (newval->value == BOND_MODE_ALB) -- GitLab From c2ce657fd68cd617e7b8e014a141a2e15e799584 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Mon, 23 Jul 2018 16:50:48 +0200 Subject: [PATCH 0241/1001] ip: hash fragments consistently [ Upstream commit 3dd1c9a1270736029ffca670e9bd0265f4120600 ] The skb hash for locally generated ip[v6] fragments belonging to the same datagram can vary in several circumstances: * for connected UDP[v6] sockets, the first fragment get its hash via set_owner_w()/skb_set_hash_from_sk() * for unconnected IPv6 UDPv6 sockets, the first fragment can get its hash via ip6_make_flowlabel()/skb_get_hash_flowi6(), if auto_flowlabel is enabled For the following frags the hash is usually computed via skb_get_hash(). The above can cause OoO for unconnected IPv6 UDPv6 socket: in that scenario the egress tx queue can be selected on a per packet basis via the skb hash. It may also fool flow-oriented schedulers to place fragments belonging to the same datagram in different flows. Fix the issue by copying the skb hash from the head frag into the others at fragmentation time. Before this commit: perf probe -a "dev_queue_xmit skb skb->hash skb->l4_hash:b1@0/8 skb->sw_hash:b1@1/8" netperf -H $IPV4 -t UDP_STREAM -l 5 -- -m 2000 -n & perf record -e probe:dev_queue_xmit -e probe:skb_set_owner_w -a sleep 0.1 perf script probe:dev_queue_xmit: (ffffffff8c6b1b20) hash=3713014309 l4_hash=1 sw_hash=0 probe:dev_queue_xmit: (ffffffff8c6b1b20) hash=0 l4_hash=0 sw_hash=0 After this commit: probe:dev_queue_xmit: (ffffffff8c6b1b20) hash=2171763177 l4_hash=1 sw_hash=0 probe:dev_queue_xmit: (ffffffff8c6b1b20) hash=2171763177 l4_hash=1 sw_hash=0 Fixes: b73c3d0e4f0e ("net: Save TX flow hash in sock and set in skbuf on xmit") Fixes: 67800f9b1f4e ("ipv6: Call skb_get_hash_flowi6 to get skb->hash in ip6_make_flowlabel") Signed-off-by: Paolo Abeni Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ip_output.c | 2 ++ net/ipv6/ip6_output.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 63d5d66e040a..e2dd325bed9b 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -523,6 +523,8 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) to->dev = from->dev; to->mark = from->mark; + skb_copy_hash(to, from); + /* Copy the flags to each fragment. */ IPCB(to)->flags = IPCB(from)->flags; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 32fcce711855..1da021527fcd 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -595,6 +595,8 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) to->dev = from->dev; to->mark = from->mark; + skb_copy_hash(to, from); + #ifdef CONFIG_NET_SCHED to->tc_index = from->tc_index; #endif -- GitLab From df20f746d68b6982923f0c318cc6a9347c96454f Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Mon, 23 Jul 2018 19:36:48 -0400 Subject: [PATCH 0242/1001] ip: in cmsg IP(V6)_ORIGDSTADDR call pskb_may_pull [ Upstream commit 2efd4fca703a6707cad16ab486eaab8fc7f0fd49 ] Syzbot reported a read beyond the end of the skb head when returning IPV6_ORIGDSTADDR: BUG: KMSAN: kernel-infoleak in put_cmsg+0x5ef/0x860 net/core/scm.c:242 CPU: 0 PID: 4501 Comm: syz-executor128 Not tainted 4.17.0+ #9 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:113 kmsan_report+0x188/0x2a0 mm/kmsan/kmsan.c:1125 kmsan_internal_check_memory+0x138/0x1f0 mm/kmsan/kmsan.c:1219 kmsan_copy_to_user+0x7a/0x160 mm/kmsan/kmsan.c:1261 copy_to_user include/linux/uaccess.h:184 [inline] put_cmsg+0x5ef/0x860 net/core/scm.c:242 ip6_datagram_recv_specific_ctl+0x1cf3/0x1eb0 net/ipv6/datagram.c:719 ip6_datagram_recv_ctl+0x41c/0x450 net/ipv6/datagram.c:733 rawv6_recvmsg+0x10fb/0x1460 net/ipv6/raw.c:521 [..] This logic and its ipv4 counterpart read the destination port from the packet at skb_transport_offset(skb) + 4. With MSG_MORE and a local SOCK_RAW sender, syzbot was able to cook a packet that stores headers exactly up to skb_transport_offset(skb) in the head and the remainder in a frag. Call pskb_may_pull before accessing the pointer to ensure that it lies in skb head. Link: http://lkml.kernel.org/r/CAF=yD-LEJwZj5a1-bAAj2Oy_hKmGygV6rsJ_WOrAYnv-fnayiQ@mail.gmail.com Reported-by: syzbot+9adb4b567003cac781f0@syzkaller.appspotmail.com Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ip_sockglue.c | 7 +++++-- net/ipv6/datagram.c | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index d07ba4d5917b..048d5f6dd320 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -148,15 +148,18 @@ static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb) { struct sockaddr_in sin; const struct iphdr *iph = ip_hdr(skb); - __be16 *ports = (__be16 *)skb_transport_header(skb); + __be16 *ports; + int end; - if (skb_transport_offset(skb) + 4 > (int)skb->len) + end = skb_transport_offset(skb) + 4; + if (end > 0 && !pskb_may_pull(skb, end)) return; /* All current transport protocols have the port numbers in the * first four bytes of the transport header and this function is * written with this assumption in mind. */ + ports = (__be16 *)skb_transport_header(skb); sin.sin_family = AF_INET; sin.sin_addr.s_addr = iph->daddr; diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 453dc3726199..461825e0680f 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -708,13 +708,16 @@ void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg, } if (np->rxopt.bits.rxorigdstaddr) { struct sockaddr_in6 sin6; - __be16 *ports = (__be16 *) skb_transport_header(skb); + __be16 *ports; + int end; - if (skb_transport_offset(skb) + 4 <= (int)skb->len) { + end = skb_transport_offset(skb) + 4; + if (end <= 0 || pskb_may_pull(skb, end)) { /* All current transport protocols have the port numbers in the * first four bytes of the transport header and this function is * written with this assumption in mind. */ + ports = (__be16 *)skb_transport_header(skb); sin6.sin6_family = AF_INET6; sin6.sin6_addr = ipv6_hdr(skb)->daddr; -- GitLab From 6e92f04a4fef1dd178fe1e285e7304bc3bb42ba2 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Tue, 24 Jul 2018 14:27:55 +0300 Subject: [PATCH 0243/1001] net/mlx4_core: Save the qpn from the input modifier in RST2INIT wrapper [ Upstream commit 958c696f5a7274d9447a458ad7aa70719b29a50a ] Function mlx4_RST2INIT_QP_wrapper saved the qp number passed in the qp context, rather than the one passed in the input modifier. However, the qp number in the qp context is not defined as a required parameter by the FW. Therefore, drivers may choose to not specify the qp number in the qp context for the reset-to-init transition. Thus, we must save the qp number passed in the command input modifier -- which is always present. (This saved qp number is used as the input modifier for command 2RST_QP when a slave's qp's are destroyed). Fixes: c82e9aa0a8bc ("mlx4_core: resource tracking for HCA resources used by guests") Signed-off-by: Jack Morgenstein Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index a069fcc823c3..b26da0952a4d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -2957,7 +2957,7 @@ int mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, u32 srqn = qp_get_srqn(qpc) & 0xffffff; int use_srq = (qp_get_srqn(qpc) >> 24) & 1; struct res_srq *srq; - int local_qpn = be32_to_cpu(qpc->local_qpn) & 0xffffff; + int local_qpn = vhcr->in_modifier & 0xffffff; err = adjust_qp_sched_queue(dev, slave, qpc, inbox); if (err) -- GitLab From f208fbad98fde951c9783194e83ecfe004327b33 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 19 Jul 2018 16:04:38 -0700 Subject: [PATCH 0244/1001] net: skb_segment() should not return NULL [ Upstream commit ff907a11a0d68a749ce1a321f4505c03bf72190c ] syzbot caught a NULL deref [1], caused by skb_segment() skb_segment() has many "goto err;" that assume the @err variable contains -ENOMEM. A successful call to __skb_linearize() should not clear @err, otherwise a subsequent memory allocation error could return NULL. While we are at it, we might use -EINVAL instead of -ENOMEM when MAX_SKB_FRAGS limit is reached. [1] kasan: CONFIG_KASAN_INLINE enabled kasan: GPF could be caused by NULL-ptr deref or user memory access general protection fault: 0000 [#1] SMP KASAN CPU: 0 PID: 13285 Comm: syz-executor3 Not tainted 4.18.0-rc4+ #146 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:tcp_gso_segment+0x3dc/0x1780 net/ipv4/tcp_offload.c:106 Code: f0 ff ff 0f 87 1c fd ff ff e8 00 88 0b fb 48 8b 75 d0 48 b9 00 00 00 00 00 fc ff df 48 8d be 90 00 00 00 48 89 f8 48 c1 e8 03 <0f> b6 14 08 48 8d 86 94 00 00 00 48 89 c6 83 e0 07 48 c1 ee 03 0f RSP: 0018:ffff88019b7fd060 EFLAGS: 00010206 RAX: 0000000000000012 RBX: 0000000000000020 RCX: dffffc0000000000 RDX: 0000000000040000 RSI: 0000000000000000 RDI: 0000000000000090 RBP: ffff88019b7fd0f0 R08: ffff88019510e0c0 R09: ffffed003b5c46d6 R10: ffffed003b5c46d6 R11: ffff8801dae236b3 R12: 0000000000000001 R13: ffff8801d6c581f4 R14: 0000000000000000 R15: ffff8801d6c58128 FS: 00007fcae64d6700(0000) GS:ffff8801dae00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000004e8664 CR3: 00000001b669b000 CR4: 00000000001406f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: tcp4_gso_segment+0x1c3/0x440 net/ipv4/tcp_offload.c:54 inet_gso_segment+0x64e/0x12d0 net/ipv4/af_inet.c:1342 inet_gso_segment+0x64e/0x12d0 net/ipv4/af_inet.c:1342 skb_mac_gso_segment+0x3b5/0x740 net/core/dev.c:2792 __skb_gso_segment+0x3c3/0x880 net/core/dev.c:2865 skb_gso_segment include/linux/netdevice.h:4099 [inline] validate_xmit_skb+0x640/0xf30 net/core/dev.c:3104 __dev_queue_xmit+0xc14/0x3910 net/core/dev.c:3561 dev_queue_xmit+0x17/0x20 net/core/dev.c:3602 neigh_hh_output include/net/neighbour.h:473 [inline] neigh_output include/net/neighbour.h:481 [inline] ip_finish_output2+0x1063/0x1860 net/ipv4/ip_output.c:229 ip_finish_output+0x841/0xfa0 net/ipv4/ip_output.c:317 NF_HOOK_COND include/linux/netfilter.h:276 [inline] ip_output+0x223/0x880 net/ipv4/ip_output.c:405 dst_output include/net/dst.h:444 [inline] ip_local_out+0xc5/0x1b0 net/ipv4/ip_output.c:124 iptunnel_xmit+0x567/0x850 net/ipv4/ip_tunnel_core.c:91 ip_tunnel_xmit+0x1598/0x3af1 net/ipv4/ip_tunnel.c:778 ipip_tunnel_xmit+0x264/0x2c0 net/ipv4/ipip.c:308 __netdev_start_xmit include/linux/netdevice.h:4148 [inline] netdev_start_xmit include/linux/netdevice.h:4157 [inline] xmit_one net/core/dev.c:3034 [inline] dev_hard_start_xmit+0x26c/0xc30 net/core/dev.c:3050 __dev_queue_xmit+0x29ef/0x3910 net/core/dev.c:3569 dev_queue_xmit+0x17/0x20 net/core/dev.c:3602 neigh_direct_output+0x15/0x20 net/core/neighbour.c:1403 neigh_output include/net/neighbour.h:483 [inline] ip_finish_output2+0xa67/0x1860 net/ipv4/ip_output.c:229 ip_finish_output+0x841/0xfa0 net/ipv4/ip_output.c:317 NF_HOOK_COND include/linux/netfilter.h:276 [inline] ip_output+0x223/0x880 net/ipv4/ip_output.c:405 dst_output include/net/dst.h:444 [inline] ip_local_out+0xc5/0x1b0 net/ipv4/ip_output.c:124 ip_queue_xmit+0x9df/0x1f80 net/ipv4/ip_output.c:504 tcp_transmit_skb+0x1bf9/0x3f10 net/ipv4/tcp_output.c:1168 tcp_write_xmit+0x1641/0x5c20 net/ipv4/tcp_output.c:2363 __tcp_push_pending_frames+0xb2/0x290 net/ipv4/tcp_output.c:2536 tcp_push+0x638/0x8c0 net/ipv4/tcp.c:735 tcp_sendmsg_locked+0x2ec5/0x3f00 net/ipv4/tcp.c:1410 tcp_sendmsg+0x2f/0x50 net/ipv4/tcp.c:1447 inet_sendmsg+0x1a1/0x690 net/ipv4/af_inet.c:798 sock_sendmsg_nosec net/socket.c:641 [inline] sock_sendmsg+0xd5/0x120 net/socket.c:651 __sys_sendto+0x3d7/0x670 net/socket.c:1797 __do_sys_sendto net/socket.c:1809 [inline] __se_sys_sendto net/socket.c:1805 [inline] __x64_sys_sendto+0xe1/0x1a0 net/socket.c:1805 do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x455ab9 Code: 1d ba fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 eb b9 fb ff c3 66 2e 0f 1f 84 00 00 00 00 RSP: 002b:00007fcae64d5c68 EFLAGS: 00000246 ORIG_RAX: 000000000000002c RAX: ffffffffffffffda RBX: 00007fcae64d66d4 RCX: 0000000000455ab9 RDX: 0000000000000001 RSI: 0000000020000200 RDI: 0000000000000013 RBP: 000000000072bea0 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000014 R13: 00000000004c1145 R14: 00000000004d1818 R15: 0000000000000006 Modules linked in: Dumping ftrace buffer: (ftrace buffer empty) Fixes: ddff00d42043 ("net: Move skb_has_shared_frag check out of GRE code and into segmentation") Signed-off-by: Eric Dumazet Cc: Alexander Duyck Reported-by: syzbot Acked-by: Alexander Duyck Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/skbuff.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 23041b5c0b27..2e5eeba97de9 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3675,6 +3675,7 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, net_warn_ratelimited( "skb_segment: too many frags: %u %u\n", pos, mss); + err = -EINVAL; goto err; } @@ -3713,11 +3714,10 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, perform_csum_check: if (!csum) { - if (skb_has_shared_frag(nskb)) { - err = __skb_linearize(nskb); - if (err) - goto err; - } + if (skb_has_shared_frag(nskb) && + __skb_linearize(nskb)) + goto err; + if (!nskb->remcsum_offload) nskb->ip_summed = CHECKSUM_NONE; SKB_GSO_CB(nskb)->csum = -- GitLab From 291d99ac4dc273b64b7d98b98f494e18da716744 Mon Sep 17 00:00:00 2001 From: Ariel Levkovich Date: Mon, 25 Jun 2018 19:12:02 +0300 Subject: [PATCH 0245/1001] net/mlx5: Adjust clock overflow work period [ Upstream commit 33180bee86a8940a84950edca46315cd9dd6deb5 ] When driver converts HW timestamp to wall clock time it subtracts the last saved cycle counter from the HW timestamp and converts the difference to nanoseconds. The conversion is done by multiplying the cycles difference with the clock multiplier value as a first step and therefore the cycles difference should be small enough so that the multiplication product doesn't exceed 64bit. The overflow handling routine is in charge of updating the last saved cycle counter in driver and it is called periodically using kernel delayed workqueue. The delay period for this work is calculated using the max HW cycle counter value (a 41 bit mask) as a base which doesn't take the 64bit limit into account so the delay period may be incorrect and too long to prevent a large difference between the HW counter and the last saved counter in SW. This change adjusts the work period for the HW clock overflow work by taking the minimum between the previous value and the quotient of max u64 value and the clock multiplier value. Fixes: ef9814deafd0 ("net/mlx5e: Add HW timestamping (TS) support") Signed-off-by: Ariel Levkovich Reviewed-by: Eran Ben Elisha Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/en_clock.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c b/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c index 84dd63e74041..27040009d87a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c @@ -545,6 +545,7 @@ void mlx5e_pps_event_handler(struct mlx5e_priv *priv, void mlx5e_timestamp_init(struct mlx5e_priv *priv) { struct mlx5e_tstamp *tstamp = &priv->tstamp; + u64 overflow_cycles; u64 ns; u64 frac = 0; u32 dev_freq; @@ -569,10 +570,17 @@ void mlx5e_timestamp_init(struct mlx5e_priv *priv) /* Calculate period in seconds to call the overflow watchdog - to make * sure counter is checked at least once every wrap around. + * The period is calculated as the minimum between max HW cycles count + * (The clock source mask) and max amount of cycles that can be + * multiplied by clock multiplier where the result doesn't exceed + * 64bits. */ - ns = cyclecounter_cyc2ns(&tstamp->cycles, tstamp->cycles.mask, + overflow_cycles = div64_u64(~0ULL >> 1, tstamp->cycles.mult); + overflow_cycles = min(overflow_cycles, tstamp->cycles.mask >> 1); + + ns = cyclecounter_cyc2ns(&tstamp->cycles, overflow_cycles, frac, &frac); - do_div(ns, NSEC_PER_SEC / 2 / HZ); + do_div(ns, NSEC_PER_SEC / HZ); tstamp->overflow_period = ns; INIT_WORK(&tstamp->pps_info.out_work, mlx5e_pps_out); -- GitLab From c83cd44202b503269388347a959017ebb6573963 Mon Sep 17 00:00:00 2001 From: Eran Ben Elisha Date: Sun, 8 Jul 2018 14:52:12 +0300 Subject: [PATCH 0246/1001] net/mlx5e: Don't allow aRFS for encapsulated packets [ Upstream commit d2e1c57bcf9a07cbb67f30ecf238f298799bce1c ] Driver is yet to support aRFS for encapsulated packets, return early error in such case. Fixes: 18c908e477dc ("net/mlx5e: Add accelerated RFS support") Signed-off-by: Eran Ben Elisha Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c index 12d3ced61114..0f0c1d7b80c0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c @@ -711,6 +711,9 @@ int mlx5e_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, skb->protocol != htons(ETH_P_IPV6)) return -EPROTONOSUPPORT; + if (skb->encapsulation) + return -EPROTONOSUPPORT; + arfs_t = arfs_get_table(arfs, arfs_get_ip_proto(skb), skb->protocol); if (!arfs_t) return -EPROTONOSUPPORT; -- GitLab From 047af2d8ced33f16815e3650bfd5e6c732229634 Mon Sep 17 00:00:00 2001 From: Eran Ben Elisha Date: Sun, 8 Jul 2018 13:08:55 +0300 Subject: [PATCH 0247/1001] net/mlx5e: Fix quota counting in aRFS expire flow [ Upstream commit 2630bae8018823c3b88788b69fb9f16ea3b4a11e ] Quota should follow the amount of rules which do expire, and not the number of rules that were examined, fixed that. Fixes: 18c908e477dc ("net/mlx5e: Add accelerated RFS support") Signed-off-by: Eran Ben Elisha Reviewed-by: Maor Gottlieb Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c index 0f0c1d7b80c0..e87923e046c9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c @@ -381,14 +381,14 @@ static void arfs_may_expire_flow(struct mlx5e_priv *priv) HLIST_HEAD(del_list); spin_lock_bh(&priv->fs.arfs.arfs_lock); mlx5e_for_each_arfs_rule(arfs_rule, htmp, priv->fs.arfs.arfs_tables, i, j) { - if (quota++ > MLX5E_ARFS_EXPIRY_QUOTA) - break; if (!work_pending(&arfs_rule->arfs_work) && rps_may_expire_flow(priv->netdev, arfs_rule->rxq, arfs_rule->flow_id, arfs_rule->filter_id)) { hlist_del_init(&arfs_rule->hlist); hlist_add_head(&arfs_rule->hlist, &del_list); + if (quota++ > MLX5E_ARFS_EXPIRY_QUOTA) + break; } } spin_unlock_bh(&priv->fs.arfs.arfs_lock); -- GitLab From 6d5b7d68f45b1208493385a8490b65ff38c4fafe Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 19 Jul 2018 12:41:18 -0700 Subject: [PATCH 0248/1001] net/ipv6: Fix linklocal to global address with VRF [ Upstream commit 24b711edfc34bc45777a3f068812b7d1ed004a5d ] Example setup: host: ip -6 addr add dev eth1 2001:db8:104::4 where eth1 is enslaved to a VRF switch: ip -6 ro add 2001:db8:104::4/128 dev br1 where br1 only has an LLA ping6 2001:db8:104::4 ssh 2001:db8:104::4 (NOTE: UDP works fine if the PKTINFO has the address set to the global address and ifindex is set to the index of eth1 with a destination an LLA). For ICMP, icmp6_iif needs to be updated to check if skb->dev is an L3 master. If it is then return the ifindex from rt6i_idev similar to what is done for loopback. For TCP, restore the original tcp_v6_iif definition which is needed in most places and add a new tcp_v6_iif_l3_slave that considers the l3_slave variability. This latter check is only needed for socket lookups. Fixes: 9ff74384600a ("net: vrf: Handle ipv6 multicast and link-local addresses") Signed-off-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/tcp.h | 5 +++++ net/ipv6/icmp.c | 5 +++-- net/ipv6/tcp_ipv6.c | 6 ++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index fb653736f335..3b49f3aafed7 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -857,6 +857,11 @@ struct tcp_skb_cb { * as TCP moves IP6CB into a different location in skb->cb[] */ static inline int tcp_v6_iif(const struct sk_buff *skb) +{ + return TCP_SKB_CB(skb)->header.h6.iif; +} + +static inline int tcp_v6_iif_l3_slave(const struct sk_buff *skb) { bool l3_slave = ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags); diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 5acb54405b10..c5f2b17b7ee1 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -405,9 +405,10 @@ static int icmp6_iif(const struct sk_buff *skb) /* for local traffic to local address, skb dev is the loopback * device. Check if there is a dst attached to the skb and if so - * get the real device index. + * get the real device index. Same is needed for replies to a link + * local address on a device enslaved to an L3 master device */ - if (unlikely(iif == LOOPBACK_IFINDEX)) { + if (unlikely(iif == LOOPBACK_IFINDEX || netif_is_l3_master(skb->dev))) { const struct rt6_info *rt6 = skb_rt6_info(skb); if (rt6) diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 35e8aef9ceed..ba8586aadffa 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -918,7 +918,8 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) &tcp_hashinfo, NULL, 0, &ipv6h->saddr, th->source, &ipv6h->daddr, - ntohs(th->source), tcp_v6_iif(skb), + ntohs(th->source), + tcp_v6_iif_l3_slave(skb), tcp_v6_sdif(skb)); if (!sk1) goto out; @@ -1573,7 +1574,8 @@ static int tcp_v6_rcv(struct sk_buff *skb) skb, __tcp_hdrlen(th), &ipv6_hdr(skb)->saddr, th->source, &ipv6_hdr(skb)->daddr, - ntohs(th->dest), tcp_v6_iif(skb), + ntohs(th->dest), + tcp_v6_iif_l3_slave(skb), sdif); if (sk2) { struct inet_timewait_sock *tw = inet_twsk(sk); -- GitLab From 46f9e1d0bd4e52cd4fefcc6a7a28066f877857af Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 20 Jul 2018 14:04:27 +0800 Subject: [PATCH 0249/1001] multicast: do not restore deleted record source filter mode to new one There are two scenarios that we will restore deleted records. The first is when device down and up(or unmap/remap). In this scenario the new filter mode is same with previous one. Because we get it from in_dev->mc_list and we do not touch it during device down and up. The other scenario is when a new socket join a group which was just delete and not finish sending status reports. In this scenario, we should use the current filter mode instead of restore old one. Here are 4 cases in total. old_socket new_socket before_fix after_fix IN(A) IN(A) ALLOW(A) ALLOW(A) IN(A) EX( ) TO_IN( ) TO_EX( ) EX( ) IN(A) TO_EX( ) ALLOW(A) EX( ) EX( ) TO_EX( ) TO_EX( ) Fixes: 24803f38a5c0b (igmp: do not remove igmp souce list info when set link down) Fixes: 1666d49e1d416 (mld: do not remove mld souce list info when set link down) Signed-off-by: Hangbin Liu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/igmp.c | 3 +-- net/ipv6/mcast.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index fbeb35ad804b..502aae3e3ab8 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1201,8 +1201,7 @@ static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im) if (pmc) { im->interface = pmc->interface; im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv; - im->sfmode = pmc->sfmode; - if (pmc->sfmode == MCAST_INCLUDE) { + if (im->sfmode == MCAST_INCLUDE) { im->tomb = pmc->tomb; im->sources = pmc->sources; for (psf = im->sources; psf; psf = psf->sf_next) diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 9a38a2c641fa..6fd913d63835 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -771,8 +771,7 @@ static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im) if (pmc) { im->idev = pmc->idev; im->mca_crcount = idev->mc_qrv; - im->mca_sfmode = pmc->mca_sfmode; - if (pmc->mca_sfmode == MCAST_INCLUDE) { + if (im->mca_sfmode == MCAST_INCLUDE) { im->mca_tomb = pmc->mca_tomb; im->mca_sources = pmc->mca_sources; for (psf = im->mca_sources; psf; psf = psf->sf_next) -- GitLab From 50b464d33964282fb09be7d6d8a6063475f63814 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 19 Jul 2018 08:15:16 +0200 Subject: [PATCH 0250/1001] net: phy: consider PHY_IGNORE_INTERRUPT in phy_start_aneg_priv [ Upstream commit 215d08a85b9acf5e1fe9dbf50f1774cde333efef ] The situation described in the comment can occur also with PHY_IGNORE_INTERRUPT, therefore change the condition to include it. Fixes: f555f34fdc58 ("net: phy: fix auto-negotiation stall due to unavailable interrupt") Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index dba6d17ad885..47d2ef2fb9b3 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -511,7 +511,7 @@ static int phy_start_aneg_priv(struct phy_device *phydev, bool sync) * negotiation may already be done and aneg interrupt may not be * generated. */ - if (phy_interrupt_is_valid(phydev) && (phydev->state == PHY_AN)) { + if (phydev->irq != PHY_POLL && phydev->state == PHY_AN) { err = phy_aneg_done(phydev); if (err > 0) { trigger = true; -- GitLab From 464e2326a7f5cd39d82f96750bb56a9d302edf8d Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 23 Jul 2018 22:37:54 +0200 Subject: [PATCH 0251/1001] sock: fix sg page frag coalescing in sk_alloc_sg [ Upstream commit 144fe2bfd236dc814eae587aea7e2af03dbdd755 ] Current sg coalescing logic in sk_alloc_sg() (latter is used by tls and sockmap) is not quite correct in that we do fetch the previous sg entry, however the subsequent check whether the refilled page frag from the socket is still the same as from the last entry with prior offset and length matching the start of the current buffer is comparing always the first sg list entry instead of the prior one. Fixes: 3c4d7559159b ("tls: kernel TLS support") Signed-off-by: Daniel Borkmann Acked-by: Dave Watson Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/tls/tls_sw.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 8ee4e667a414..fb79caf56d0e 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -135,9 +135,10 @@ static int alloc_sg(struct sock *sk, int len, struct scatterlist *sg, pfrag->offset += use; sge = sg + num_elem - 1; - if (num_elem > first_coalesce && sg_page(sg) == pfrag->page && - sg->offset + sg->length == orig_offset) { - sg->length += use; + + if (num_elem > first_coalesce && sg_page(sge) == pfrag->page && + sge->offset + sge->length == orig_offset) { + sge->length += use; } else { sge++; sg_unmark_end(sge); -- GitLab From 23557c5d34b96e1129c8567a26764faa587dd659 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Fri, 20 Jul 2018 13:21:01 -0700 Subject: [PATCH 0252/1001] rtnetlink: add rtnl_link_state check in rtnl_configure_link [ Upstream commit 5025f7f7d506fba9b39e7fe8ca10f6f34cb9bc2d ] rtnl_configure_link sets dev->rtnl_link_state to RTNL_LINK_INITIALIZED and unconditionally calls __dev_notify_flags to notify user-space of dev flags. current call sequence for rtnl_configure_link rtnetlink_newlink rtnl_link_ops->newlink rtnl_configure_link (unconditionally notifies userspace of default and new dev flags) If a newlink handler wants to call rtnl_configure_link early, we will end up with duplicate notifications to user-space. This patch fixes rtnl_configure_link to check rtnl_link_state and call __dev_notify_flags with gchanges = 0 if already RTNL_LINK_INITIALIZED. Later in the series, this patch will help the following sequence where a driver implementing newlink can call rtnl_configure_link to initialize the link early. makes the following call sequence work: rtnetlink_newlink rtnl_link_ops->newlink (vxlan) -> rtnl_configure_link (initializes link and notifies user-space of default dev flags) rtnl_configure_link (updates dev flags if requested by user ifm and notifies user-space of new dev flags) Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/rtnetlink.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 4cfdad08aca0..efe396cc77b5 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2402,9 +2402,12 @@ int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm) return err; } - dev->rtnl_link_state = RTNL_LINK_INITIALIZED; - - __dev_notify_flags(dev, old_flags, ~0U); + if (dev->rtnl_link_state == RTNL_LINK_INITIALIZED) { + __dev_notify_flags(dev, old_flags, 0U); + } else { + dev->rtnl_link_state = RTNL_LINK_INITIALIZED; + __dev_notify_flags(dev, old_flags, ~0U); + } return 0; } EXPORT_SYMBOL(rtnl_configure_link); -- GitLab From 1c345a5292587b29a99d30074fbb1759bccc43b5 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Fri, 20 Jul 2018 13:21:02 -0700 Subject: [PATCH 0253/1001] vxlan: add new fdb alloc and create helpers [ Upstream commit 7431016b107c95cb5b2014aa1901fcb115f746bc ] - Add new vxlan_fdb_alloc helper - rename existing vxlan_fdb_create into vxlan_fdb_update: because it really creates or updates an existing fdb entry - move new fdb creation into a separate vxlan_fdb_create Main motivation for this change is to introduce the ability to decouple vxlan fdb creation and notify, used in a later patch. Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/vxlan.c | 91 ++++++++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 29 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index bbdb46916dc3..d72c24d504d8 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -636,8 +636,61 @@ static int vxlan_gro_complete(struct sock *sk, struct sk_buff *skb, int nhoff) return eth_gro_complete(skb, nhoff + sizeof(struct vxlanhdr)); } -/* Add new entry to forwarding table -- assumes lock held */ +static struct vxlan_fdb *vxlan_fdb_alloc(struct vxlan_dev *vxlan, + const u8 *mac, __u16 state, + __be32 src_vni, __u8 ndm_flags) +{ + struct vxlan_fdb *f; + + f = kmalloc(sizeof(*f), GFP_ATOMIC); + if (!f) + return NULL; + f->state = state; + f->flags = ndm_flags; + f->updated = f->used = jiffies; + f->vni = src_vni; + INIT_LIST_HEAD(&f->remotes); + memcpy(f->eth_addr, mac, ETH_ALEN); + + return f; +} + static int vxlan_fdb_create(struct vxlan_dev *vxlan, + const u8 *mac, union vxlan_addr *ip, + __u16 state, __be16 port, __be32 src_vni, + __be32 vni, __u32 ifindex, __u8 ndm_flags, + struct vxlan_fdb **fdb) +{ + struct vxlan_rdst *rd = NULL; + struct vxlan_fdb *f; + int rc; + + if (vxlan->cfg.addrmax && + vxlan->addrcnt >= vxlan->cfg.addrmax) + return -ENOSPC; + + netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip); + f = vxlan_fdb_alloc(vxlan, mac, state, src_vni, ndm_flags); + if (!f) + return -ENOMEM; + + rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd); + if (rc < 0) { + kfree(f); + return rc; + } + + ++vxlan->addrcnt; + hlist_add_head_rcu(&f->hlist, + vxlan_fdb_head(vxlan, mac, src_vni)); + + *fdb = f; + + return 0; +} + +/* Add new entry to forwarding table -- assumes lock held */ +static int vxlan_fdb_update(struct vxlan_dev *vxlan, const u8 *mac, union vxlan_addr *ip, __u16 state, __u16 flags, __be16 port, __be32 src_vni, __be32 vni, @@ -687,37 +740,17 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan, if (!(flags & NLM_F_CREATE)) return -ENOENT; - if (vxlan->cfg.addrmax && - vxlan->addrcnt >= vxlan->cfg.addrmax) - return -ENOSPC; - /* Disallow replace to add a multicast entry */ if ((flags & NLM_F_REPLACE) && (is_multicast_ether_addr(mac) || is_zero_ether_addr(mac))) return -EOPNOTSUPP; netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip); - f = kmalloc(sizeof(*f), GFP_ATOMIC); - if (!f) - return -ENOMEM; - - notify = 1; - f->state = state; - f->flags = ndm_flags; - f->updated = f->used = jiffies; - f->vni = src_vni; - INIT_LIST_HEAD(&f->remotes); - memcpy(f->eth_addr, mac, ETH_ALEN); - - rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd); - if (rc < 0) { - kfree(f); + rc = vxlan_fdb_create(vxlan, mac, ip, state, port, src_vni, + vni, ifindex, ndm_flags, &f); + if (rc < 0) return rc; - } - - ++vxlan->addrcnt; - hlist_add_head_rcu(&f->hlist, - vxlan_fdb_head(vxlan, mac, src_vni)); + notify = 1; } if (notify) { @@ -863,7 +896,7 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], return -EAFNOSUPPORT; spin_lock_bh(&vxlan->hash_lock); - err = vxlan_fdb_create(vxlan, addr, &ip, ndm->ndm_state, flags, + err = vxlan_fdb_update(vxlan, addr, &ip, ndm->ndm_state, flags, port, src_vni, vni, ifindex, ndm->ndm_flags); spin_unlock_bh(&vxlan->hash_lock); @@ -1006,7 +1039,7 @@ static bool vxlan_snoop(struct net_device *dev, /* close off race between vxlan_flush and incoming packets */ if (netif_running(dev)) - vxlan_fdb_create(vxlan, src_mac, src_ip, + vxlan_fdb_update(vxlan, src_mac, src_ip, NUD_REACHABLE, NLM_F_EXCL|NLM_F_CREATE, vxlan->cfg.dst_port, @@ -3167,7 +3200,7 @@ static int __vxlan_dev_create(struct net *net, struct net_device *dev, /* create an fdb entry for a valid default destination */ if (!vxlan_addr_any(&vxlan->default_dst.remote_ip)) { - err = vxlan_fdb_create(vxlan, all_zeros_mac, + err = vxlan_fdb_update(vxlan, all_zeros_mac, &vxlan->default_dst.remote_ip, NUD_REACHABLE | NUD_PERMANENT, NLM_F_EXCL | NLM_F_CREATE, @@ -3441,7 +3474,7 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], old_dst.remote_ifindex, 0); if (!vxlan_addr_any(&dst->remote_ip)) { - err = vxlan_fdb_create(vxlan, all_zeros_mac, + err = vxlan_fdb_update(vxlan, all_zeros_mac, &dst->remote_ip, NUD_REACHABLE | NUD_PERMANENT, NLM_F_CREATE | NLM_F_APPEND, -- GitLab From bb0335aacfddee9b7d06a1e2fdca0b62140c791c Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Fri, 20 Jul 2018 13:21:03 -0700 Subject: [PATCH 0254/1001] vxlan: make netlink notify in vxlan_fdb_destroy optional [ Upstream commit f6e053858671bb156b6e44ad66418acc8c7f4e77 ] Add a new option do_notify to vxlan_fdb_destroy to make sending netlink notify optional. Used by a later patch. Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/vxlan.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index d72c24d504d8..5ee0f6d9f7bc 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -774,13 +774,15 @@ static void vxlan_fdb_free(struct rcu_head *head) kfree(f); } -static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f) +static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f, + bool do_notify) { netdev_dbg(vxlan->dev, "delete %pM\n", f->eth_addr); --vxlan->addrcnt; - vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_DELNEIGH); + if (do_notify) + vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_DELNEIGH); hlist_del_rcu(&f->hlist); call_rcu(&f->rcu, vxlan_fdb_free); @@ -930,7 +932,7 @@ static int __vxlan_fdb_delete(struct vxlan_dev *vxlan, goto out; } - vxlan_fdb_destroy(vxlan, f); + vxlan_fdb_destroy(vxlan, f, true); out: return 0; @@ -2393,7 +2395,7 @@ static void vxlan_cleanup(unsigned long arg) "garbage collect %pM\n", f->eth_addr); f->state = NUD_STALE; - vxlan_fdb_destroy(vxlan, f); + vxlan_fdb_destroy(vxlan, f, true); } else if (time_before(timeout, next_timer)) next_timer = timeout; } @@ -2444,7 +2446,7 @@ static void vxlan_fdb_delete_default(struct vxlan_dev *vxlan, __be32 vni) spin_lock_bh(&vxlan->hash_lock); f = __vxlan_find_mac(vxlan, all_zeros_mac, vni); if (f) - vxlan_fdb_destroy(vxlan, f); + vxlan_fdb_destroy(vxlan, f, true); spin_unlock_bh(&vxlan->hash_lock); } @@ -2498,7 +2500,7 @@ static void vxlan_flush(struct vxlan_dev *vxlan, bool do_all) continue; /* the all_zeros_mac entry is deleted at vxlan_uninit */ if (!is_zero_ether_addr(f->eth_addr)) - vxlan_fdb_destroy(vxlan, f); + vxlan_fdb_destroy(vxlan, f, true); } } spin_unlock_bh(&vxlan->hash_lock); -- GitLab From 68974d0b9c8662744afdad22dbcb7d93b29a7b94 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Fri, 20 Jul 2018 13:21:04 -0700 Subject: [PATCH 0255/1001] vxlan: fix default fdb entry netlink notify ordering during netdev create [ Upstream commit e99465b952861533d9ba748fdbecc96d9a36da3e ] Problem: In vxlan_newlink, a default fdb entry is added before register_netdev. The default fdb creation function also notifies user-space of the fdb entry on the vxlan device which user-space does not know about yet. (RTM_NEWNEIGH goes before RTM_NEWLINK for the same ifindex). This patch fixes the user-space netlink notification ordering issue with the following changes: - decouple fdb notify from fdb create. - Move fdb notify after register_netdev. - Call rtnl_configure_link in vxlan newlink handler to notify userspace about the newlink before fdb notify and hence avoiding the user-space race. Fixes: afbd8bae9c79 ("vxlan: add implicit fdb entry for default destination") Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/vxlan.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 5ee0f6d9f7bc..13d39a72fe0d 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -3192,6 +3192,7 @@ static int __vxlan_dev_create(struct net *net, struct net_device *dev, { struct vxlan_net *vn = net_generic(net, vxlan_net_id); struct vxlan_dev *vxlan = netdev_priv(dev); + struct vxlan_fdb *f = NULL; int err; err = vxlan_dev_configure(net, dev, conf, false, extack); @@ -3202,27 +3203,38 @@ static int __vxlan_dev_create(struct net *net, struct net_device *dev, /* create an fdb entry for a valid default destination */ if (!vxlan_addr_any(&vxlan->default_dst.remote_ip)) { - err = vxlan_fdb_update(vxlan, all_zeros_mac, + err = vxlan_fdb_create(vxlan, all_zeros_mac, &vxlan->default_dst.remote_ip, NUD_REACHABLE | NUD_PERMANENT, - NLM_F_EXCL | NLM_F_CREATE, vxlan->cfg.dst_port, vxlan->default_dst.remote_vni, vxlan->default_dst.remote_vni, vxlan->default_dst.remote_ifindex, - NTF_SELF); + NTF_SELF, &f); if (err) return err; } err = register_netdevice(dev); + if (err) + goto errout; + + err = rtnl_configure_link(dev, NULL); if (err) { - vxlan_fdb_delete_default(vxlan, vxlan->default_dst.remote_vni); - return err; + unregister_netdevice(dev); + goto errout; } + /* notify default fdb entry */ + if (f) + vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH); + list_add(&vxlan->next, &vn->vxlan_list); return 0; +errout: + if (f) + vxlan_fdb_destroy(vxlan, f, false); + return err; } static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], @@ -3451,6 +3463,7 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], struct vxlan_rdst *dst = &vxlan->default_dst; struct vxlan_rdst old_dst; struct vxlan_config conf; + struct vxlan_fdb *f = NULL; int err; err = vxlan_nl2conf(tb, data, @@ -3476,19 +3489,19 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], old_dst.remote_ifindex, 0); if (!vxlan_addr_any(&dst->remote_ip)) { - err = vxlan_fdb_update(vxlan, all_zeros_mac, + err = vxlan_fdb_create(vxlan, all_zeros_mac, &dst->remote_ip, NUD_REACHABLE | NUD_PERMANENT, - NLM_F_CREATE | NLM_F_APPEND, vxlan->cfg.dst_port, dst->remote_vni, dst->remote_vni, dst->remote_ifindex, - NTF_SELF); + NTF_SELF, &f); if (err) { spin_unlock_bh(&vxlan->hash_lock); return err; } + vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH); } spin_unlock_bh(&vxlan->hash_lock); } -- GitLab From 68c9bdfc8b425671003e37b27a400e77d288a8fb Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Thu, 12 Jul 2018 06:04:52 -0700 Subject: [PATCH 0256/1001] tcp: fix dctcp delayed ACK schedule [ Upstream commit b0c05d0e99d98d7f0cd41efc1eeec94efdc3325d ] Previously, when a data segment was sent an ACK was piggybacked on the data segment without generating a CA_EVENT_NON_DELAYED_ACK event to notify congestion control modules. So the DCTCP ca->delayed_ack_reserved flag could incorrectly stay set when in fact there were no delayed ACKs being reserved. This could result in sending a special ECN notification ACK that carries an older ACK sequence, when in fact there was no need for such an ACK. DCTCP keeps track of the delayed ACK status with its own separate state ca->delayed_ack_reserved. Previously it may accidentally cancel the delayed ACK without updating this field upon sending a special ACK that carries a older ACK sequence. This inconsistency would lead to DCTCP receiver never acknowledging the latest data until the sender times out and retry in some cases. Packetdrill script (provided by Larry Brakmo) 0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 0.000 setsockopt(3, SOL_TCP, TCP_CONGESTION, "dctcp", 5) = 0 0.000 bind(3, ..., ...) = 0 0.000 listen(3, 1) = 0 0.100 < [ect0] SEW 0:0(0) win 32792 0.100 > SE. 0:0(0) ack 1 0.110 < [ect0] . 1:1(0) ack 1 win 257 0.200 accept(3, ..., ...) = 4 0.200 < [ect0] . 1:1001(1000) ack 1 win 257 0.200 > [ect01] . 1:1(0) ack 1001 0.200 write(4, ..., 1) = 1 0.200 > [ect01] P. 1:2(1) ack 1001 0.200 < [ect0] . 1001:2001(1000) ack 2 win 257 0.200 write(4, ..., 1) = 1 0.200 > [ect01] P. 2:3(1) ack 2001 0.200 < [ect0] . 2001:3001(1000) ack 3 win 257 0.200 < [ect0] . 3001:4001(1000) ack 3 win 257 0.200 > [ect01] . 3:3(0) ack 4001 0.210 < [ce] P. 4001:4501(500) ack 3 win 257 +0.001 read(4, ..., 4500) = 4500 +0 write(4, ..., 1) = 1 +0 > [ect01] PE. 3:4(1) ack 4501 +0.010 < [ect0] W. 4501:5501(1000) ack 4 win 257 // Previously the ACK sequence below would be 4501, causing a long RTO +0.040~+0.045 > [ect01] . 4:4(0) ack 5501 // delayed ack +0.311 < [ect0] . 5501:6501(1000) ack 4 win 257 // More data +0 > [ect01] . 4:4(0) ack 6501 // now acks everything +0.500 < F. 9501:9501(0) ack 4 win 257 Reported-by: Larry Brakmo Signed-off-by: Yuchung Cheng Signed-off-by: Eric Dumazet Acked-by: Neal Cardwell Acked-by: Lawrence Brakmo Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_dctcp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c index 5f5e5936760e..89f88b0d8167 100644 --- a/net/ipv4/tcp_dctcp.c +++ b/net/ipv4/tcp_dctcp.c @@ -134,7 +134,8 @@ static void dctcp_ce_state_0_to_1(struct sock *sk) /* State has changed from CE=0 to CE=1 and delayed * ACK has not sent yet. */ - if (!ca->ce_state && ca->delayed_ack_reserved) { + if (!ca->ce_state && + inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) { u32 tmp_rcv_nxt; /* Save current rcv_nxt. */ @@ -164,7 +165,8 @@ static void dctcp_ce_state_1_to_0(struct sock *sk) /* State has changed from CE=1 to CE=0 and delayed * ACK has not sent yet. */ - if (ca->ce_state && ca->delayed_ack_reserved) { + if (ca->ce_state && + inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) { u32 tmp_rcv_nxt; /* Save current rcv_nxt. */ -- GitLab From f7f24b36938367d6e97d43f7dd53f0c5714cce1a Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Wed, 18 Jul 2018 13:56:34 -0700 Subject: [PATCH 0257/1001] tcp: helpers to send special DCTCP ack [ Upstream commit 2987babb6982306509380fc11b450227a844493b ] Refactor and create helpers to send the special ACK in DCTCP. Signed-off-by: Yuchung Cheng Acked-by: Neal Cardwell Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_output.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index abae5196cd3a..c8da25f37ae4 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -984,8 +984,8 @@ static void tcp_internal_pacing(struct sock *sk, const struct sk_buff *skb) * We are working here with either a clone of the original * SKB, or a fresh unique copy made by the retransmit engine. */ -static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, - gfp_t gfp_mask) +static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, + int clone_it, gfp_t gfp_mask, u32 rcv_nxt) { const struct inet_connection_sock *icsk = inet_csk(sk); struct inet_sock *inet; @@ -1057,7 +1057,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, th->source = inet->inet_sport; th->dest = inet->inet_dport; th->seq = htonl(tcb->seq); - th->ack_seq = htonl(tp->rcv_nxt); + th->ack_seq = htonl(rcv_nxt); *(((__be16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) | tcb->tcp_flags); @@ -1135,6 +1135,13 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, return err; } +static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, + gfp_t gfp_mask) +{ + return __tcp_transmit_skb(sk, skb, clone_it, gfp_mask, + tcp_sk(sk)->rcv_nxt); +} + /* This routine just queues the buffer for sending. * * NOTE: probe0 timer is not checked, do not forget tcp_push_pending_frames, @@ -3551,7 +3558,7 @@ void tcp_send_delayed_ack(struct sock *sk) } /* This routine sends an ack and also updates the window. */ -void tcp_send_ack(struct sock *sk) +void __tcp_send_ack(struct sock *sk, u32 rcv_nxt) { struct sk_buff *buff; @@ -3586,7 +3593,12 @@ void tcp_send_ack(struct sock *sk) skb_set_tcp_pure_ack(buff); /* Send it off, this clears delayed acks for us. */ - tcp_transmit_skb(sk, buff, 0, (__force gfp_t)0); + __tcp_transmit_skb(sk, buff, 0, (__force gfp_t)0, rcv_nxt); +} + +void tcp_send_ack(struct sock *sk) +{ + __tcp_send_ack(sk, tcp_sk(sk)->rcv_nxt); } EXPORT_SYMBOL_GPL(tcp_send_ack); -- GitLab From 78636179f6e69f71f2d16e8716c096f297be9356 Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Wed, 18 Jul 2018 13:56:35 -0700 Subject: [PATCH 0258/1001] tcp: do not cancel delay-AcK on DCTCP special ACK [ Upstream commit 27cde44a259c380a3c09066fc4b42de7dde9b1ad ] Currently when a DCTCP receiver delays an ACK and receive a data packet with a different CE mark from the previous one's, it sends two immediate ACKs acking previous and latest sequences respectly (for ECN accounting). Previously sending the first ACK may mark off the delayed ACK timer (tcp_event_ack_sent). This may subsequently prevent sending the second ACK to acknowledge the latest sequence (tcp_ack_snd_check). The culprit is that tcp_send_ack() assumes it always acknowleges the latest sequence, which is not true for the first special ACK. The fix is to not make the assumption in tcp_send_ack and check the actual ack sequence before cancelling the delayed ACK. Further it's safer to pass the ack sequence number as a local variable into tcp_send_ack routine, instead of intercepting tp->rcv_nxt to avoid future bugs like this. Reported-by: Neal Cardwell Signed-off-by: Yuchung Cheng Acked-by: Neal Cardwell Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/tcp.h | 1 + net/ipv4/tcp_dctcp.c | 34 ++++------------------------------ net/ipv4/tcp_output.c | 11 ++++++++--- 3 files changed, 13 insertions(+), 33 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 3b49f3aafed7..62af4ae27430 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -560,6 +560,7 @@ void tcp_send_fin(struct sock *sk); void tcp_send_active_reset(struct sock *sk, gfp_t priority); int tcp_send_synack(struct sock *); void tcp_push_one(struct sock *, unsigned int mss_now); +void __tcp_send_ack(struct sock *sk, u32 rcv_nxt); void tcp_send_ack(struct sock *sk); void tcp_send_delayed_ack(struct sock *sk); void tcp_send_loss_probe(struct sock *sk); diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c index 89f88b0d8167..39d96d27ff94 100644 --- a/net/ipv4/tcp_dctcp.c +++ b/net/ipv4/tcp_dctcp.c @@ -135,21 +135,8 @@ static void dctcp_ce_state_0_to_1(struct sock *sk) * ACK has not sent yet. */ if (!ca->ce_state && - inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) { - u32 tmp_rcv_nxt; - - /* Save current rcv_nxt. */ - tmp_rcv_nxt = tp->rcv_nxt; - - /* Generate previous ack with CE=0. */ - tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; - tp->rcv_nxt = ca->prior_rcv_nxt; - - tcp_send_ack(sk); - - /* Recover current rcv_nxt. */ - tp->rcv_nxt = tmp_rcv_nxt; - } + inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) + __tcp_send_ack(sk, ca->prior_rcv_nxt); ca->prior_rcv_nxt = tp->rcv_nxt; ca->ce_state = 1; @@ -166,21 +153,8 @@ static void dctcp_ce_state_1_to_0(struct sock *sk) * ACK has not sent yet. */ if (ca->ce_state && - inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) { - u32 tmp_rcv_nxt; - - /* Save current rcv_nxt. */ - tmp_rcv_nxt = tp->rcv_nxt; - - /* Generate previous ack with CE=1. */ - tp->ecn_flags |= TCP_ECN_DEMAND_CWR; - tp->rcv_nxt = ca->prior_rcv_nxt; - - tcp_send_ack(sk); - - /* Recover current rcv_nxt. */ - tp->rcv_nxt = tmp_rcv_nxt; - } + inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) + __tcp_send_ack(sk, ca->prior_rcv_nxt); ca->prior_rcv_nxt = tp->rcv_nxt; ca->ce_state = 0; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index c8da25f37ae4..3d8f6f342cb1 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -175,8 +175,13 @@ static void tcp_event_data_sent(struct tcp_sock *tp, } /* Account for an ACK we sent. */ -static inline void tcp_event_ack_sent(struct sock *sk, unsigned int pkts) +static inline void tcp_event_ack_sent(struct sock *sk, unsigned int pkts, + u32 rcv_nxt) { + struct tcp_sock *tp = tcp_sk(sk); + + if (unlikely(rcv_nxt != tp->rcv_nxt)) + return; /* Special ACK sent by DCTCP to reflect ECN */ tcp_dec_quickack_mode(sk, pkts); inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK); } @@ -1098,7 +1103,7 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, icsk->icsk_af_ops->send_check(sk, skb); if (likely(tcb->tcp_flags & TCPHDR_ACK)) - tcp_event_ack_sent(sk, tcp_skb_pcount(skb)); + tcp_event_ack_sent(sk, tcp_skb_pcount(skb), rcv_nxt); if (skb->len != tcp_header_size) { tcp_event_data_sent(tp, sk); @@ -3595,12 +3600,12 @@ void __tcp_send_ack(struct sock *sk, u32 rcv_nxt) /* Send it off, this clears delayed acks for us. */ __tcp_transmit_skb(sk, buff, 0, (__force gfp_t)0, rcv_nxt); } +EXPORT_SYMBOL_GPL(__tcp_send_ack); void tcp_send_ack(struct sock *sk) { __tcp_send_ack(sk, tcp_sk(sk)->rcv_nxt); } -EXPORT_SYMBOL_GPL(tcp_send_ack); /* This routine sends a packet with an out of date sequence * number. It assumes the other end will try to ack it. -- GitLab From ae70b61531979a4caaed63be4f19b76fd58e7932 Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Wed, 18 Jul 2018 13:56:36 -0700 Subject: [PATCH 0259/1001] tcp: do not delay ACK in DCTCP upon CE status change [ Upstream commit a0496ef2c23b3b180902dd185d0d63ccbc624cf8 ] Per DCTCP RFC8257 (Section 3.2) the ACK reflecting the CE status change has to be sent immediately so the sender can respond quickly: """ When receiving packets, the CE codepoint MUST be processed as follows: 1. If the CE codepoint is set and DCTCP.CE is false, set DCTCP.CE to true and send an immediate ACK. 2. If the CE codepoint is not set and DCTCP.CE is true, set DCTCP.CE to false and send an immediate ACK. """ Previously DCTCP implementation may continue to delay the ACK. This patch fixes that to implement the RFC by forcing an immediate ACK. Tested with this packetdrill script provided by Larry Brakmo 0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 0.000 setsockopt(3, SOL_TCP, TCP_CONGESTION, "dctcp", 5) = 0 0.000 bind(3, ..., ...) = 0 0.000 listen(3, 1) = 0 0.100 < [ect0] SEW 0:0(0) win 32792 0.100 > SE. 0:0(0) ack 1 0.110 < [ect0] . 1:1(0) ack 1 win 257 0.200 accept(3, ..., ...) = 4 +0 setsockopt(4, SOL_SOCKET, SO_DEBUG, [1], 4) = 0 0.200 < [ect0] . 1:1001(1000) ack 1 win 257 0.200 > [ect01] . 1:1(0) ack 1001 0.200 write(4, ..., 1) = 1 0.200 > [ect01] P. 1:2(1) ack 1001 0.200 < [ect0] . 1001:2001(1000) ack 2 win 257 +0.005 < [ce] . 2001:3001(1000) ack 2 win 257 +0.000 > [ect01] . 2:2(0) ack 2001 // Previously the ACK below would be delayed by 40ms +0.000 > [ect01] E. 2:2(0) ack 3001 +0.500 < F. 9501:9501(0) ack 4 win 257 Signed-off-by: Yuchung Cheng Acked-by: Neal Cardwell Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/tcp.h | 1 + net/ipv4/tcp_dctcp.c | 30 ++++++++++++++++++------------ net/ipv4/tcp_input.c | 3 ++- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 62af4ae27430..3173dd12b8cc 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -372,6 +372,7 @@ ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); +void tcp_enter_quickack_mode(struct sock *sk); static inline void tcp_dec_quickack_mode(struct sock *sk, const unsigned int pkts) { diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c index 39d96d27ff94..c78fb53988a1 100644 --- a/net/ipv4/tcp_dctcp.c +++ b/net/ipv4/tcp_dctcp.c @@ -131,12 +131,15 @@ static void dctcp_ce_state_0_to_1(struct sock *sk) struct dctcp *ca = inet_csk_ca(sk); struct tcp_sock *tp = tcp_sk(sk); - /* State has changed from CE=0 to CE=1 and delayed - * ACK has not sent yet. - */ - if (!ca->ce_state && - inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) - __tcp_send_ack(sk, ca->prior_rcv_nxt); + if (!ca->ce_state) { + /* State has changed from CE=0 to CE=1, force an immediate + * ACK to reflect the new CE state. If an ACK was delayed, + * send that first to reflect the prior CE state. + */ + if (inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) + __tcp_send_ack(sk, ca->prior_rcv_nxt); + tcp_enter_quickack_mode(sk); + } ca->prior_rcv_nxt = tp->rcv_nxt; ca->ce_state = 1; @@ -149,12 +152,15 @@ static void dctcp_ce_state_1_to_0(struct sock *sk) struct dctcp *ca = inet_csk_ca(sk); struct tcp_sock *tp = tcp_sk(sk); - /* State has changed from CE=1 to CE=0 and delayed - * ACK has not sent yet. - */ - if (ca->ce_state && - inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) - __tcp_send_ack(sk, ca->prior_rcv_nxt); + if (ca->ce_state) { + /* State has changed from CE=1 to CE=0, force an immediate + * ACK to reflect the new CE state. If an ACK was delayed, + * send that first to reflect the prior CE state. + */ + if (inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) + __tcp_send_ack(sk, ca->prior_rcv_nxt); + tcp_enter_quickack_mode(sk); + } ca->prior_rcv_nxt = tp->rcv_nxt; ca->ce_state = 0; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 5711b1b12d28..03fd2ff4007b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -209,13 +209,14 @@ static void tcp_incr_quickack(struct sock *sk) icsk->icsk_ack.quick = min(quickacks, TCP_MAX_QUICKACKS); } -static void tcp_enter_quickack_mode(struct sock *sk) +void tcp_enter_quickack_mode(struct sock *sk) { struct inet_connection_sock *icsk = inet_csk(sk); tcp_incr_quickack(sk); icsk->icsk_ack.pingpong = 0; icsk->icsk_ack.ato = TCP_ATO_MIN; } +EXPORT_SYMBOL(tcp_enter_quickack_mode); /* Send ACKs quickly, if "quick" count is not exhausted * and the session is not interactive. -- GitLab From f3a5ba6310e11df370f6888ed716d1486896d983 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 23 Jul 2018 09:28:17 -0700 Subject: [PATCH 0260/1001] tcp: free batches of packets in tcp_prune_ofo_queue() [ Upstream commit 72cd43ba64fc172a443410ce01645895850844c8 ] Juha-Matti Tilli reported that malicious peers could inject tiny packets in out_of_order_queue, forcing very expensive calls to tcp_collapse_ofo_queue() and tcp_prune_ofo_queue() for every incoming packet. out_of_order_queue rb-tree can contain thousands of nodes, iterating over all of them is not nice. Before linux-4.9, we would have pruned all packets in ofo_queue in one go, every XXXX packets. XXXX depends on sk_rcvbuf and skbs truesize, but is about 7000 packets with tcp_rmem[2] default of 6 MB. Since we plan to increase tcp_rmem[2] in the future to cope with modern BDP, can not revert to the old behavior, without great pain. Strategy taken in this patch is to purge ~12.5 % of the queue capacity. Fixes: 36a6503fedda ("tcp: refine tcp_prune_ofo_queue() to not drop all packets") Signed-off-by: Eric Dumazet Reported-by: Juha-Matti Tilli Acked-by: Yuchung Cheng Acked-by: Soheil Hassas Yeganeh Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/skbuff.h | 2 ++ net/ipv4/tcp_input.c | 15 +++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 9cf971c68401..6dd77767fd5b 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3167,6 +3167,8 @@ static inline int __skb_grow_rcsum(struct sk_buff *skb, unsigned int len) return __skb_grow(skb, len); } +#define rb_to_skb(rb) rb_entry_safe(rb, struct sk_buff, rbnode) + #define skb_queue_walk(queue, skb) \ for (skb = (queue)->next; \ skb != (struct sk_buff *)(queue); \ diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 03fd2ff4007b..1e7175bd3b59 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4924,6 +4924,7 @@ static void tcp_collapse_ofo_queue(struct sock *sk) * 2) not add too big latencies if thousands of packets sit there. * (But if application shrinks SO_RCVBUF, we could still end up * freeing whole queue here) + * 3) Drop at least 12.5 % of sk_rcvbuf to avoid malicious attacks. * * Return true if queue has shrunk. */ @@ -4931,20 +4932,26 @@ static bool tcp_prune_ofo_queue(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); struct rb_node *node, *prev; + int goal; if (RB_EMPTY_ROOT(&tp->out_of_order_queue)) return false; NET_INC_STATS(sock_net(sk), LINUX_MIB_OFOPRUNED); + goal = sk->sk_rcvbuf >> 3; node = &tp->ooo_last_skb->rbnode; do { prev = rb_prev(node); rb_erase(node, &tp->out_of_order_queue); + goal -= rb_to_skb(node)->truesize; tcp_drop(sk, rb_entry(node, struct sk_buff, rbnode)); - sk_mem_reclaim(sk); - if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf && - !tcp_under_memory_pressure(sk)) - break; + if (!prev || goal <= 0) { + sk_mem_reclaim(sk); + if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf && + !tcp_under_memory_pressure(sk)) + break; + goal = sk->sk_rcvbuf >> 3; + } node = prev; } while (node); tp->ooo_last_skb = rb_entry(prev, struct sk_buff, rbnode); -- GitLab From 81e6b01d1c10015811f52bf04ec125bdb291b4b5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 23 Jul 2018 09:28:18 -0700 Subject: [PATCH 0261/1001] tcp: avoid collapses in tcp_prune_queue() if possible [ Upstream commit f4a3313d8e2ca9fd8d8f45e40a2903ba782607e7 ] Right after a TCP flow is created, receiving tiny out of order packets allways hit the condition : if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) tcp_clamp_window(sk); tcp_clamp_window() increases sk_rcvbuf to match sk_rmem_alloc (guarded by tcp_rmem[2]) Calling tcp_collapse_ofo_queue() in this case is not useful, and offers a O(N^2) surface attack to malicious peers. Better not attempt anything before full queue capacity is reached, forcing attacker to spend lots of resource and allow us to more easily detect the abuse. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Acked-by: Yuchung Cheng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 1e7175bd3b59..023d2b016f5d 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4986,6 +4986,9 @@ static int tcp_prune_queue(struct sock *sk) else if (tcp_under_memory_pressure(sk)) tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss); + if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) + return 0; + tcp_collapse_ofo_queue(sk); if (!skb_queue_empty(&sk->sk_receive_queue)) tcp_collapse(sk, &sk->sk_receive_queue, NULL, -- GitLab From 6285a74a536f1ee807488436547cc17cda3306d8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 23 Jul 2018 09:28:19 -0700 Subject: [PATCH 0262/1001] tcp: detect malicious patterns in tcp_collapse_ofo_queue() [ Upstream commit 3d4bf93ac12003f9b8e1e2de37fe27983deebdcf ] In case an attacker feeds tiny packets completely out of order, tcp_collapse_ofo_queue() might scan the whole rb-tree, performing expensive copies, but not changing socket memory usage at all. 1) Do not attempt to collapse tiny skbs. 2) Add logic to exit early when too many tiny skbs are detected. We prefer not doing aggressive collapsing (which copies packets) for pathological flows, and revert to tcp_prune_ofo_queue() which will be less expensive. In the future, we might add the possibility of terminating flows that are proven to be malicious. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 023d2b016f5d..6f09c45dc20c 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4877,6 +4877,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *root, static void tcp_collapse_ofo_queue(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); + u32 range_truesize, sum_tiny = 0; struct sk_buff *skb, *head; struct rb_node *p; u32 start, end; @@ -4895,6 +4896,7 @@ static void tcp_collapse_ofo_queue(struct sock *sk) } start = TCP_SKB_CB(skb)->seq; end = TCP_SKB_CB(skb)->end_seq; + range_truesize = skb->truesize; for (head = skb;;) { skb = tcp_skb_next(skb, NULL); @@ -4905,11 +4907,20 @@ static void tcp_collapse_ofo_queue(struct sock *sk) if (!skb || after(TCP_SKB_CB(skb)->seq, end) || before(TCP_SKB_CB(skb)->end_seq, start)) { - tcp_collapse(sk, NULL, &tp->out_of_order_queue, - head, skb, start, end); + /* Do not attempt collapsing tiny skbs */ + if (range_truesize != head->truesize || + end - start >= SKB_WITH_OVERHEAD(SK_MEM_QUANTUM)) { + tcp_collapse(sk, NULL, &tp->out_of_order_queue, + head, skb, start, end); + } else { + sum_tiny += range_truesize; + if (sum_tiny > sk->sk_rcvbuf >> 3) + return; + } goto new_range; } + range_truesize += skb->truesize; if (unlikely(before(TCP_SKB_CB(skb)->seq, start))) start = TCP_SKB_CB(skb)->seq; if (after(TCP_SKB_CB(skb)->end_seq, end)) -- GitLab From ec645ae62309a85522c2bc8f700afc6e152e62b9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 23 Jul 2018 09:28:20 -0700 Subject: [PATCH 0263/1001] tcp: call tcp_drop() from tcp_data_queue_ofo() [ Upstream commit 8541b21e781a22dce52a74fef0b9bed00404a1cd ] In order to be able to give better diagnostics and detect malicious traffic, we need to have better sk->sk_drops tracking. Fixes: 9f5afeae5152 ("tcp: use an RB tree for ooo receive queue") Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Acked-by: Yuchung Cheng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 6f09c45dc20c..35b0e38fe31a 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4492,7 +4492,7 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) /* All the bits are present. Drop. */ NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPOFOMERGE); - __kfree_skb(skb); + tcp_drop(sk, skb); skb = NULL; tcp_dsack_set(sk, seq, end_seq); goto add_sack; @@ -4511,7 +4511,7 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) TCP_SKB_CB(skb1)->end_seq); NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPOFOMERGE); - __kfree_skb(skb1); + tcp_drop(sk, skb1); goto merge_right; } } else if (tcp_try_coalesce(sk, OOO_QUEUE, skb1, -- GitLab From 22e3d3178b18115ba60cae7c968a67718f070da0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 23 Jul 2018 09:28:21 -0700 Subject: [PATCH 0264/1001] tcp: add tcp_ooo_try_coalesce() helper [ Upstream commit 58152ecbbcc6a0ce7fddd5bf5f6ee535834ece0c ] In case skb in out_or_order_queue is the result of multiple skbs coalescing, we would like to get a proper gso_segs counter tracking, so that future tcp_drop() can report an accurate number. I chose to not implement this tracking for skbs in receive queue, since they are not dropped, unless socket is disconnected. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Acked-by: Yuchung Cheng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 35b0e38fe31a..b86e7b8beb1d 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4332,6 +4332,23 @@ static bool tcp_try_coalesce(struct sock *sk, return true; } +static bool tcp_ooo_try_coalesce(struct sock *sk, + struct sk_buff *to, + struct sk_buff *from, + bool *fragstolen) +{ + bool res = tcp_try_coalesce(sk, OOO_QUEUE, to, from, fragstolen); + + /* In case tcp_drop() is called later, update to->gso_segs */ + if (res) { + u32 gso_segs = max_t(u16, 1, skb_shinfo(to)->gso_segs) + + max_t(u16, 1, skb_shinfo(from)->gso_segs); + + skb_shinfo(to)->gso_segs = min_t(u32, gso_segs, 0xFFFF); + } + return res; +} + static void tcp_drop(struct sock *sk, struct sk_buff *skb) { sk_drops_add(sk, skb); @@ -4463,8 +4480,8 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) /* In the typical case, we are adding an skb to the end of the list. * Use of ooo_last_skb avoids the O(Log(N)) rbtree lookup. */ - if (tcp_try_coalesce(sk, OOO_QUEUE, tp->ooo_last_skb, - skb, &fragstolen)) { + if (tcp_ooo_try_coalesce(sk, tp->ooo_last_skb, + skb, &fragstolen)) { coalesce_done: tcp_grow_window(sk, skb); kfree_skb_partial(skb, fragstolen); @@ -4514,8 +4531,8 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) tcp_drop(sk, skb1); goto merge_right; } - } else if (tcp_try_coalesce(sk, OOO_QUEUE, skb1, - skb, &fragstolen)) { + } else if (tcp_ooo_try_coalesce(sk, skb1, + skb, &fragstolen)) { goto coalesce_done; } p = &parent->rb_right; -- GitLab From ab9489c4db894cc60f30430f80464eec8ccdf066 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Fri, 13 Jul 2018 00:29:36 +0200 Subject: [PATCH 0265/1001] staging: speakup: fix wraparound in uaccess length check commit b96fba8d5855c3617adbfb43ca4723a808cac954 upstream. If softsynthx_read() is called with `count < 3`, `count - 3` wraps, causing the loop to copy as much data as available to the provided buffer. If softsynthx_read() is invoked through sys_splice(), this causes an unbounded kernel write; but even when userspace just reads from it normally, a small size could cause userspace crashes. Fixes: 425e586cf95b ("speakup: add unicode variant of /dev/softsynth") Cc: stable@vger.kernel.org Signed-off-by: Samuel Thibault Signed-off-by: Jann Horn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/speakup/speakup_soft.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/staging/speakup/speakup_soft.c b/drivers/staging/speakup/speakup_soft.c index d99daf69e501..fe229d63deec 100644 --- a/drivers/staging/speakup/speakup_soft.c +++ b/drivers/staging/speakup/speakup_soft.c @@ -207,11 +207,15 @@ static ssize_t softsynthx_read(struct file *fp, char __user *buf, size_t count, int chars_sent = 0; char __user *cp; char *init; + size_t bytes_per_ch = unicode ? 3 : 1; u16 ch; int empty; unsigned long flags; DEFINE_WAIT(wait); + if (count < bytes_per_ch) + return -EINVAL; + spin_lock_irqsave(&speakup_info.spinlock, flags); while (1) { prepare_to_wait(&speakup_event, &wait, TASK_INTERRUPTIBLE); @@ -237,7 +241,7 @@ static ssize_t softsynthx_read(struct file *fp, char __user *buf, size_t count, init = get_initstring(); /* Keep 3 bytes available for a 16bit UTF-8-encoded character */ - while (chars_sent <= count - 3) { + while (chars_sent <= count - bytes_per_ch) { if (speakup_info.flushing) { speakup_info.flushing = 0; ch = '\x18'; -- GitLab From e089c305af4903793dae85dc9d9b706e0d17bfb3 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 10 Jul 2018 08:28:49 +0200 Subject: [PATCH 0266/1001] usb: cdc_acm: Add quirk for Castles VEGA3000 commit 1445cbe476fc3dd09c0b380b206526a49403c071 upstream. The device (a POS terminal) implements CDC ACM, but has not union descriptor. Signed-off-by: Lubomir Rintel Acked-by: Oliver Neukum Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 3b9aadd007f5..f2f31fc16f29 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1844,6 +1844,9 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x09d8, 0x0320), /* Elatec GmbH TWN3 */ .driver_info = NO_UNION_NORMAL, /* has misplaced union descriptor */ }, + { USB_DEVICE(0x0ca6, 0xa050), /* Castles VEGA3000 */ + .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ + }, { USB_DEVICE(0x2912, 0x0001), /* ATOL FPrint */ .driver_info = CLEAR_HALT_CONDITIONS, -- GitLab From ac3f65c6b6351b729be072debc44cd28a22e0d0e Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 19 Jul 2018 14:39:37 -0500 Subject: [PATCH 0267/1001] usb: core: handle hub C_PORT_OVER_CURRENT condition commit 249a32b7eeb3edb6897dd38f89651a62163ac4ed upstream. Based on USB2.0 Spec Section 11.12.5, "If a hub has per-port power switching and per-port current limiting, an over-current on one port may still cause the power on another port to fall below specific minimums. In this case, the affected port is placed in the Power-Off state and C_PORT_OVER_CURRENT is set for the port, but PORT_OVER_CURRENT is not set." so let's check C_PORT_OVER_CURRENT too for over current condition. Fixes: 08d1dec6f405 ("usb:hub set hub->change_bits when over-current happens") Cc: Tested-by: Alessandro Antenucci Signed-off-by: Bin Liu Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index e5f77e611451..a8bc48b26c23 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1141,10 +1141,14 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) if (!udev || udev->state == USB_STATE_NOTATTACHED) { /* Tell hub_wq to disconnect the device or - * check for a new connection + * check for a new connection or over current condition. + * Based on USB2.0 Spec Section 11.12.5, + * C_PORT_OVER_CURRENT could be set while + * PORT_OVER_CURRENT is not. So check for any of them. */ if (udev || (portstatus & USB_PORT_STAT_CONNECTION) || - (portstatus & USB_PORT_STAT_OVERCURRENT)) + (portstatus & USB_PORT_STAT_OVERCURRENT) || + (portchange & USB_PORT_STAT_C_OVERCURRENT)) set_bit(port1, hub->change_bits); } else if (portstatus & USB_PORT_STAT_ENABLE) { -- GitLab From 68fc92a0f3913d539d1ac68a861f895e34099e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20Sepp=C3=A4l=C3=A4?= Date: Thu, 5 Jul 2018 17:31:53 +0300 Subject: [PATCH 0268/1001] usb: dwc2: Fix DMA alignment to start at allocated boundary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 56406e017a883b54b339207b230f85599f4d70ae upstream. The commit 3bc04e28a030 ("usb: dwc2: host: Get aligned DMA in a more supported way") introduced a common way to align DMA allocations. The code in the commit aligns the struct dma_aligned_buffer but the actual DMA address pointed by data[0] gets aligned to an offset from the allocated boundary by the kmalloc_ptr and the old_xfer_buffer pointers. This is against the recommendation in Documentation/DMA-API.txt which states: Therefore, it is recommended that driver writers who don't take special care to determine the cache line size at run time only map virtual regions that begin and end on page boundaries (which are guaranteed also to be cache line boundaries). The effect of this is that architectures with non-coherent DMA caches may run into memory corruption or kernel crashes with Unhandled kernel unaligned accesses exceptions. Fix the alignment by positioning the DMA area in front of the allocation and use memory at the end of the area for storing the orginal transfer_buffer pointer. This may have the added benefit of increased performance as the DMA area is now fully aligned on all architectures. Tested with Lantiq xRX200 (MIPS) and RPi Model B Rev 2 (ARM). Fixes: 3bc04e28a030 ("usb: dwc2: host: Get aligned DMA in a more supported way") Cc: Reviewed-by: Douglas Anderson Signed-off-by: Antti Seppälä Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/hcd.c | 44 ++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 87484f71b2ab..46d3b0fc00c5 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -2606,34 +2606,29 @@ static void dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg, #define DWC2_USB_DMA_ALIGN 4 -struct dma_aligned_buffer { - void *kmalloc_ptr; - void *old_xfer_buffer; - u8 data[0]; -}; - static void dwc2_free_dma_aligned_buffer(struct urb *urb) { - struct dma_aligned_buffer *temp; + void *stored_xfer_buffer; if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER)) return; - temp = container_of(urb->transfer_buffer, - struct dma_aligned_buffer, data); + /* Restore urb->transfer_buffer from the end of the allocated area */ + memcpy(&stored_xfer_buffer, urb->transfer_buffer + + urb->transfer_buffer_length, sizeof(urb->transfer_buffer)); if (usb_urb_dir_in(urb)) - memcpy(temp->old_xfer_buffer, temp->data, + memcpy(stored_xfer_buffer, urb->transfer_buffer, urb->transfer_buffer_length); - urb->transfer_buffer = temp->old_xfer_buffer; - kfree(temp->kmalloc_ptr); + kfree(urb->transfer_buffer); + urb->transfer_buffer = stored_xfer_buffer; urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER; } static int dwc2_alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags) { - struct dma_aligned_buffer *temp, *kmalloc_ptr; + void *kmalloc_ptr; size_t kmalloc_size; if (urb->num_sgs || urb->sg || @@ -2641,22 +2636,29 @@ static int dwc2_alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags) !((uintptr_t)urb->transfer_buffer & (DWC2_USB_DMA_ALIGN - 1))) return 0; - /* Allocate a buffer with enough padding for alignment */ + /* + * Allocate a buffer with enough padding for original transfer_buffer + * pointer. This allocation is guaranteed to be aligned properly for + * DMA + */ kmalloc_size = urb->transfer_buffer_length + - sizeof(struct dma_aligned_buffer) + DWC2_USB_DMA_ALIGN - 1; + sizeof(urb->transfer_buffer); kmalloc_ptr = kmalloc(kmalloc_size, mem_flags); if (!kmalloc_ptr) return -ENOMEM; - /* Position our struct dma_aligned_buffer such that data is aligned */ - temp = PTR_ALIGN(kmalloc_ptr + 1, DWC2_USB_DMA_ALIGN) - 1; - temp->kmalloc_ptr = kmalloc_ptr; - temp->old_xfer_buffer = urb->transfer_buffer; + /* + * Position value of original urb->transfer_buffer pointer to the end + * of allocation for later referencing + */ + memcpy(kmalloc_ptr + urb->transfer_buffer_length, + &urb->transfer_buffer, sizeof(urb->transfer_buffer)); + if (usb_urb_dir_out(urb)) - memcpy(temp->data, urb->transfer_buffer, + memcpy(kmalloc_ptr, urb->transfer_buffer, urb->transfer_buffer_length); - urb->transfer_buffer = temp->data; + urb->transfer_buffer = kmalloc_ptr; urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER; -- GitLab From 5421694d8cd76e258a3aa2923794f772f2e6a4de Mon Sep 17 00:00:00 2001 From: Jerry Zhang Date: Mon, 2 Jul 2018 12:48:08 -0700 Subject: [PATCH 0269/1001] usb: gadget: f_fs: Only return delayed status when len is 0 commit 4d644abf25698362bd33d17c9ddc8f7122c30f17 upstream. Commit 1b9ba000 ("Allow function drivers to pause control transfers") states that USB_GADGET_DELAYED_STATUS is only supported if data phase is 0 bytes. It seems that when the length is not 0 bytes, there is no need to explicitly delay the data stage since the transfer is not completed until the user responds. However, when the length is 0, there is no data stage and the transfer is finished once setup() returns, hence there is a need to explicitly delay completion. This manifests as the following bugs: Prior to 946ef68ad4e4 ('Let setup() return USB_GADGET_DELAYED_STATUS'), when setup is 0 bytes, ffs would require user to queue a 0 byte request in order to clear setup state. However, that 0 byte request was actually not needed and would hang and cause errors in other setup requests. After the above commit, 0 byte setups work since the gadget now accepts empty queues to ep0 to clear the delay, but all other setups hang. Fixes: 946ef68ad4e4 ("Let setup() return USB_GADGET_DELAYED_STATUS") Signed-off-by: Jerry Zhang Cc: stable Acked-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 7b53ac548b1a..52e6897fa35a 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -3243,7 +3243,7 @@ static int ffs_func_setup(struct usb_function *f, __ffs_event_add(ffs, FUNCTIONFS_SETUP); spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags); - return USB_GADGET_DELAYED_STATUS; + return creq->wLength == 0 ? USB_GADGET_DELAYED_STATUS : 0; } static bool ffs_func_req_match(struct usb_function *f, -- GitLab From 55cb8f40c8d7ee1adb1575257cf739be26561e9e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 10 Jul 2018 14:51:33 +0200 Subject: [PATCH 0270/1001] driver core: Partially revert "driver core: correct device's shutdown order" commit 722e5f2b1eec7de61117b7c0a7914761e3da2eda upstream. Commit 52cdbdd49853 (driver core: correct device's shutdown order) introduced a regression by breaking device shutdown on some systems. Namely, the devices_kset_move_last() call in really_probe() added by that commit is a mistake as it may cause parents to follow children in the devices_kset list which then causes shutdown to fail. For example, if a device has children before really_probe() is called for it (which is not uncommon), that call will cause it to be reordered after the children in the devices_kset list and the ordering of that list will not reflect the correct device shutdown order any more. Also it causes the devices_kset list to be constantly reordered until all drivers have been probed which is totally pointless overhead in the majority of cases and it only covered an issue with system shutdown, while system-wide suspend/resume potentially had the same issue on the affected platforms (which was not covered). Moreover, the shutdown issue originally addressed by the change in really_probe() made by commit 52cdbdd49853 is not present in 4.18-rc any more, since dra7 started to use the sdhci-omap driver which doesn't disable any regulators during shutdown, so the really_probe() part of commit 52cdbdd49853 can be safely reverted. [The original issue was related to the omap_hsmmc driver used by dra7 previously.] For the above reasons, revert the really_probe() modifications made by commit 52cdbdd49853. The other code changes made by commit 52cdbdd49853 are useful and they need not be reverted. Fixes: 52cdbdd49853 (driver core: correct device's shutdown order) Link: https://lore.kernel.org/lkml/CAFgQCTt7VfqM=UyCnvNFxrSw8Z6cUtAi3HUwR4_xPAc03SgHjQ@mail.gmail.com/ Reported-by: Pingfan Liu Tested-by: Pingfan Liu Reviewed-by: Kishon Vijay Abraham I Signed-off-by: Rafael J. Wysocki Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index ad44b40fe284..55fc31f6fe7f 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -401,14 +401,6 @@ static int really_probe(struct device *dev, struct device_driver *drv) goto probe_failed; } - /* - * Ensure devices are listed in devices_kset in correct order - * It's important to move Dev to the end of devices_kset before - * calling .probe, because it could be recursive and parent Dev - * should always go first - */ - devices_kset_move_last(dev); - if (dev->bus->probe) { ret = dev->bus->probe(dev); if (ret) -- GitLab From 464a3f9139f4ebea238f15db83705eac9561d2bc Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Tue, 7 Feb 2017 17:01:14 +0200 Subject: [PATCH 0271/1001] can: xilinx_can: fix RX loop if RXNEMP is asserted without RXOK commit 32852c561bffd613d4ed7ec464b1e03e1b7b6c5c upstream. If the device gets into a state where RXNEMP (RX FIFO not empty) interrupt is asserted without RXOK (new frame received successfully) interrupt being asserted, xcan_rx_poll() will continue to try to clear RXNEMP without actually reading frames from RX FIFO. If the RX FIFO is not empty, the interrupt will not be cleared and napi_schedule() will just be called again. This situation can occur when: (a) xcan_rx() returns without reading RX FIFO due to an error condition. The code tries to clear both RXOK and RXNEMP but RXNEMP will not clear due to a frame still being in the FIFO. The frame will never be read from the FIFO as RXOK is no longer set. (b) A frame is received between xcan_rx_poll() reading interrupt status and clearing RXOK. RXOK will be cleared, but RXNEMP will again remain set as the new message is still in the FIFO. I'm able to trigger case (b) by flooding the bus with frames under load. There does not seem to be any benefit in using both RXNEMP and RXOK in the way the driver does, and the polling example in the reference manual (UG585 v1.10 18.3.7 Read Messages from RxFIFO) also says that either RXOK or RXNEMP can be used for detecting incoming messages. Fix the issue and simplify the RX processing by only using RXNEMP without RXOK. Tested with the integrated CAN on Zynq-7000 SoC. Fixes: b1201e44f50b ("can: xilinx CAN controller support") Signed-off-by: Anssi Hannula Cc: Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/xilinx_can.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 89aec07c225f..05ea2820d27b 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -101,7 +101,7 @@ enum xcan_reg { #define XCAN_INTR_ALL (XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |\ XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | \ XCAN_IXR_RXNEMP_MASK | XCAN_IXR_ERROR_MASK | \ - XCAN_IXR_ARBLST_MASK | XCAN_IXR_RXOK_MASK) + XCAN_IXR_ARBLST_MASK) /* CAN register bit shift - XCAN___SHIFT */ #define XCAN_BTR_SJW_SHIFT 7 /* Synchronous jump width */ @@ -709,15 +709,7 @@ static int xcan_rx_poll(struct napi_struct *napi, int quota) isr = priv->read_reg(priv, XCAN_ISR_OFFSET); while ((isr & XCAN_IXR_RXNEMP_MASK) && (work_done < quota)) { - if (isr & XCAN_IXR_RXOK_MASK) { - priv->write_reg(priv, XCAN_ICR_OFFSET, - XCAN_IXR_RXOK_MASK); - work_done += xcan_rx(ndev); - } else { - priv->write_reg(priv, XCAN_ICR_OFFSET, - XCAN_IXR_RXNEMP_MASK); - break; - } + work_done += xcan_rx(ndev); priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_RXNEMP_MASK); isr = priv->read_reg(priv, XCAN_ISR_OFFSET); } @@ -728,7 +720,7 @@ static int xcan_rx_poll(struct napi_struct *napi, int quota) if (work_done < quota) { napi_complete_done(napi, work_done); ier = priv->read_reg(priv, XCAN_IER_OFFSET); - ier |= (XCAN_IXR_RXOK_MASK | XCAN_IXR_RXNEMP_MASK); + ier |= XCAN_IXR_RXNEMP_MASK; priv->write_reg(priv, XCAN_IER_OFFSET, ier); } return work_done; @@ -800,9 +792,9 @@ static irqreturn_t xcan_interrupt(int irq, void *dev_id) } /* Check for the type of receive interrupt and Processing it */ - if (isr & (XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK)) { + if (isr & XCAN_IXR_RXNEMP_MASK) { ier = priv->read_reg(priv, XCAN_IER_OFFSET); - ier &= ~(XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK); + ier &= ~XCAN_IXR_RXNEMP_MASK; priv->write_reg(priv, XCAN_IER_OFFSET, ier); napi_schedule(&priv->napi); } -- GitLab From f820de2a08b65bbe84372108c1975737f0d5d044 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Thu, 17 May 2018 15:41:19 +0300 Subject: [PATCH 0272/1001] can: xilinx_can: fix power management handling commit 8ebd83bdb027f29870d96649dba18b91581ea829 upstream. There are several issues with the suspend/resume handling code of the driver: - The device is attached and detached in the runtime_suspend() and runtime_resume() callbacks if the interface is running. However, during xcan_chip_start() the interface is considered running, causing the resume handler to incorrectly call netif_start_queue() at the beginning of xcan_chip_start(), and on xcan_chip_start() error return the suspend handler detaches the device leaving the user unable to bring-up the device anymore. - The device is not brought properly up on system resume. A reset is done and the code tries to determine the bus state after that. However, after reset the device is always in Configuration mode (down), so the state checking code does not make sense and communication will also not work. - The suspend callback tries to set the device to sleep mode (low-power mode which monitors the bus and brings the device back to normal mode on activity), but then immediately disables the clocks (possibly before the device reaches the sleep mode), which does not make sense to me. If a clean shutdown is wanted before disabling clocks, we can just bring it down completely instead of only sleep mode. Reorganize the PM code so that only the clock logic remains in the runtime PM callbacks and the system PM callbacks contain the device bring-up/down logic. This makes calling the runtime PM callbacks during e.g. xcan_chip_start() safe. The system PM callbacks now simply call common code to start/stop the HW if the interface was running, replacing the broken code from before. xcan_chip_stop() is updated to use the common reset code so that it will wait for the reset to complete. Reset also disables all interrupts so do not do that separately. Also, the device_may_wakeup() checks are removed as the driver does not have wakeup support. Tested on Zynq-7000 integrated CAN. Signed-off-by: Anssi Hannula Cc: Michal Simek Cc: Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/xilinx_can.c | 69 +++++++++++++++--------------------- 1 file changed, 28 insertions(+), 41 deletions(-) diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 05ea2820d27b..88446ae11815 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -811,13 +811,9 @@ static irqreturn_t xcan_interrupt(int irq, void *dev_id) static void xcan_chip_stop(struct net_device *ndev) { struct xcan_priv *priv = netdev_priv(ndev); - u32 ier; /* Disable interrupts and leave the can in configuration mode */ - ier = priv->read_reg(priv, XCAN_IER_OFFSET); - ier &= ~XCAN_INTR_ALL; - priv->write_reg(priv, XCAN_IER_OFFSET, ier); - priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); + set_reset_mode(ndev); priv->can.state = CAN_STATE_STOPPED; } @@ -950,10 +946,15 @@ static const struct net_device_ops xcan_netdev_ops = { */ static int __maybe_unused xcan_suspend(struct device *dev) { - if (!device_may_wakeup(dev)) - return pm_runtime_force_suspend(dev); + struct net_device *ndev = dev_get_drvdata(dev); - return 0; + if (netif_running(ndev)) { + netif_stop_queue(ndev); + netif_device_detach(ndev); + xcan_chip_stop(ndev); + } + + return pm_runtime_force_suspend(dev); } /** @@ -965,11 +966,27 @@ static int __maybe_unused xcan_suspend(struct device *dev) */ static int __maybe_unused xcan_resume(struct device *dev) { - if (!device_may_wakeup(dev)) - return pm_runtime_force_resume(dev); + struct net_device *ndev = dev_get_drvdata(dev); + int ret; - return 0; + ret = pm_runtime_force_resume(dev); + if (ret) { + dev_err(dev, "pm_runtime_force_resume failed on resume\n"); + return ret; + } + + if (netif_running(ndev)) { + ret = xcan_chip_start(ndev); + if (ret) { + dev_err(dev, "xcan_chip_start failed on resume\n"); + return ret; + } + + netif_device_attach(ndev); + netif_start_queue(ndev); + } + return 0; } /** @@ -984,14 +1001,6 @@ static int __maybe_unused xcan_runtime_suspend(struct device *dev) struct net_device *ndev = dev_get_drvdata(dev); struct xcan_priv *priv = netdev_priv(ndev); - if (netif_running(ndev)) { - netif_stop_queue(ndev); - netif_device_detach(ndev); - } - - priv->write_reg(priv, XCAN_MSR_OFFSET, XCAN_MSR_SLEEP_MASK); - priv->can.state = CAN_STATE_SLEEPING; - clk_disable_unprepare(priv->bus_clk); clk_disable_unprepare(priv->can_clk); @@ -1010,7 +1019,6 @@ static int __maybe_unused xcan_runtime_resume(struct device *dev) struct net_device *ndev = dev_get_drvdata(dev); struct xcan_priv *priv = netdev_priv(ndev); int ret; - u32 isr, status; ret = clk_prepare_enable(priv->bus_clk); if (ret) { @@ -1024,27 +1032,6 @@ static int __maybe_unused xcan_runtime_resume(struct device *dev) return ret; } - priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); - isr = priv->read_reg(priv, XCAN_ISR_OFFSET); - status = priv->read_reg(priv, XCAN_SR_OFFSET); - - if (netif_running(ndev)) { - if (isr & XCAN_IXR_BSOFF_MASK) { - priv->can.state = CAN_STATE_BUS_OFF; - priv->write_reg(priv, XCAN_SRR_OFFSET, - XCAN_SRR_RESET_MASK); - } else if ((status & XCAN_SR_ESTAT_MASK) == - XCAN_SR_ESTAT_MASK) { - priv->can.state = CAN_STATE_ERROR_PASSIVE; - } else if (status & XCAN_SR_ERRWRN_MASK) { - priv->can.state = CAN_STATE_ERROR_WARNING; - } else { - priv->can.state = CAN_STATE_ERROR_ACTIVE; - } - netif_device_attach(ndev); - netif_start_queue(ndev); - } - return 0; } -- GitLab From c5846b2fd57b593180210f74d2f5e937f9e421cc Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Wed, 8 Feb 2017 13:13:40 +0200 Subject: [PATCH 0273/1001] can: xilinx_can: fix recovery from error states not being propagated commit 877e0b75947e2c7acf5624331bb17ceb093c98ae upstream. The xilinx_can driver contains no mechanism for propagating recovery from CAN_STATE_ERROR_WARNING and CAN_STATE_ERROR_PASSIVE. Add such a mechanism by factoring the handling of XCAN_STATE_ERROR_PASSIVE and XCAN_STATE_ERROR_WARNING out of xcan_err_interrupt and checking for recovery after RX and TX if the interface is in one of those states. Tested with the integrated CAN on Zynq-7000 SoC. Fixes: b1201e44f50b ("can: xilinx CAN controller support") Signed-off-by: Anssi Hannula Cc: Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/xilinx_can.c | 155 ++++++++++++++++++++++++++++------- 1 file changed, 127 insertions(+), 28 deletions(-) diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 88446ae11815..cc954a794f5a 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -2,6 +2,7 @@ * * Copyright (C) 2012 - 2014 Xilinx, Inc. * Copyright (C) 2009 PetaLogix. All rights reserved. + * Copyright (C) 2017 Sandvik Mining and Construction Oy * * Description: * This driver is developed for Axi CAN IP and for Zynq CANPS Controller. @@ -529,6 +530,123 @@ static int xcan_rx(struct net_device *ndev) return 1; } +/** + * xcan_current_error_state - Get current error state from HW + * @ndev: Pointer to net_device structure + * + * Checks the current CAN error state from the HW. Note that this + * only checks for ERROR_PASSIVE and ERROR_WARNING. + * + * Return: + * ERROR_PASSIVE or ERROR_WARNING if either is active, ERROR_ACTIVE + * otherwise. + */ +static enum can_state xcan_current_error_state(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + u32 status = priv->read_reg(priv, XCAN_SR_OFFSET); + + if ((status & XCAN_SR_ESTAT_MASK) == XCAN_SR_ESTAT_MASK) + return CAN_STATE_ERROR_PASSIVE; + else if (status & XCAN_SR_ERRWRN_MASK) + return CAN_STATE_ERROR_WARNING; + else + return CAN_STATE_ERROR_ACTIVE; +} + +/** + * xcan_set_error_state - Set new CAN error state + * @ndev: Pointer to net_device structure + * @new_state: The new CAN state to be set + * @cf: Error frame to be populated or NULL + * + * Set new CAN error state for the device, updating statistics and + * populating the error frame if given. + */ +static void xcan_set_error_state(struct net_device *ndev, + enum can_state new_state, + struct can_frame *cf) +{ + struct xcan_priv *priv = netdev_priv(ndev); + u32 ecr = priv->read_reg(priv, XCAN_ECR_OFFSET); + u32 txerr = ecr & XCAN_ECR_TEC_MASK; + u32 rxerr = (ecr & XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT; + + priv->can.state = new_state; + + if (cf) { + cf->can_id |= CAN_ERR_CRTL; + cf->data[6] = txerr; + cf->data[7] = rxerr; + } + + switch (new_state) { + case CAN_STATE_ERROR_PASSIVE: + priv->can.can_stats.error_passive++; + if (cf) + cf->data[1] = (rxerr > 127) ? + CAN_ERR_CRTL_RX_PASSIVE : + CAN_ERR_CRTL_TX_PASSIVE; + break; + case CAN_STATE_ERROR_WARNING: + priv->can.can_stats.error_warning++; + if (cf) + cf->data[1] |= (txerr > rxerr) ? + CAN_ERR_CRTL_TX_WARNING : + CAN_ERR_CRTL_RX_WARNING; + break; + case CAN_STATE_ERROR_ACTIVE: + if (cf) + cf->data[1] |= CAN_ERR_CRTL_ACTIVE; + break; + default: + /* non-ERROR states are handled elsewhere */ + WARN_ON(1); + break; + } +} + +/** + * xcan_update_error_state_after_rxtx - Update CAN error state after RX/TX + * @ndev: Pointer to net_device structure + * + * If the device is in a ERROR-WARNING or ERROR-PASSIVE state, check if + * the performed RX/TX has caused it to drop to a lesser state and set + * the interface state accordingly. + */ +static void xcan_update_error_state_after_rxtx(struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + enum can_state old_state = priv->can.state; + enum can_state new_state; + + /* changing error state due to successful frame RX/TX can only + * occur from these states + */ + if (old_state != CAN_STATE_ERROR_WARNING && + old_state != CAN_STATE_ERROR_PASSIVE) + return; + + new_state = xcan_current_error_state(ndev); + + if (new_state != old_state) { + struct sk_buff *skb; + struct can_frame *cf; + + skb = alloc_can_err_skb(ndev, &cf); + + xcan_set_error_state(ndev, new_state, skb ? cf : NULL); + + if (skb) { + struct net_device_stats *stats = &ndev->stats; + + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + netif_rx(skb); + } + } +} + /** * xcan_err_interrupt - error frame Isr * @ndev: net_device pointer @@ -544,16 +662,12 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) struct net_device_stats *stats = &ndev->stats; struct can_frame *cf; struct sk_buff *skb; - u32 err_status, status, txerr = 0, rxerr = 0; + u32 err_status; skb = alloc_can_err_skb(ndev, &cf); err_status = priv->read_reg(priv, XCAN_ESR_OFFSET); priv->write_reg(priv, XCAN_ESR_OFFSET, err_status); - txerr = priv->read_reg(priv, XCAN_ECR_OFFSET) & XCAN_ECR_TEC_MASK; - rxerr = ((priv->read_reg(priv, XCAN_ECR_OFFSET) & - XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT); - status = priv->read_reg(priv, XCAN_SR_OFFSET); if (isr & XCAN_IXR_BSOFF_MASK) { priv->can.state = CAN_STATE_BUS_OFF; @@ -563,28 +677,10 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) can_bus_off(ndev); if (skb) cf->can_id |= CAN_ERR_BUSOFF; - } else if ((status & XCAN_SR_ESTAT_MASK) == XCAN_SR_ESTAT_MASK) { - priv->can.state = CAN_STATE_ERROR_PASSIVE; - priv->can.can_stats.error_passive++; - if (skb) { - cf->can_id |= CAN_ERR_CRTL; - cf->data[1] = (rxerr > 127) ? - CAN_ERR_CRTL_RX_PASSIVE : - CAN_ERR_CRTL_TX_PASSIVE; - cf->data[6] = txerr; - cf->data[7] = rxerr; - } - } else if (status & XCAN_SR_ERRWRN_MASK) { - priv->can.state = CAN_STATE_ERROR_WARNING; - priv->can.can_stats.error_warning++; - if (skb) { - cf->can_id |= CAN_ERR_CRTL; - cf->data[1] |= (txerr > rxerr) ? - CAN_ERR_CRTL_TX_WARNING : - CAN_ERR_CRTL_RX_WARNING; - cf->data[6] = txerr; - cf->data[7] = rxerr; - } + } else { + enum can_state new_state = xcan_current_error_state(ndev); + + xcan_set_error_state(ndev, new_state, skb ? cf : NULL); } /* Check for Arbitration lost interrupt */ @@ -714,8 +810,10 @@ static int xcan_rx_poll(struct napi_struct *napi, int quota) isr = priv->read_reg(priv, XCAN_ISR_OFFSET); } - if (work_done) + if (work_done) { can_led_event(ndev, CAN_LED_EVENT_RX); + xcan_update_error_state_after_rxtx(ndev); + } if (work_done < quota) { napi_complete_done(napi, work_done); @@ -746,6 +844,7 @@ static void xcan_tx_interrupt(struct net_device *ndev, u32 isr) isr = priv->read_reg(priv, XCAN_ISR_OFFSET); } can_led_event(ndev, CAN_LED_EVENT_TX); + xcan_update_error_state_after_rxtx(ndev); netif_wake_queue(ndev); } -- GitLab From 96bf3257c86655b7f6bac8566d916f25cd3aa946 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Tue, 7 Feb 2017 13:23:04 +0200 Subject: [PATCH 0274/1001] can: xilinx_can: fix device dropping off bus on RX overrun commit 2574fe54515ed3487405de329e4e9f13d7098c10 upstream. The xilinx_can driver performs a software reset when an RX overrun is detected. This causes the device to enter Configuration mode where no messages are received or transmitted. The documentation does not mention any need to perform a reset on an RX overrun, and testing by inducing an RX overflow also indicated that the device continues to work just fine without a reset. Remove the software reset. Tested with the integrated CAN on Zynq-7000 SoC. Fixes: b1201e44f50b ("can: xilinx CAN controller support") Signed-off-by: Anssi Hannula Cc: Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/xilinx_can.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index cc954a794f5a..8a94489aa125 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -696,7 +696,6 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) if (isr & XCAN_IXR_RXOFLW_MASK) { stats->rx_over_errors++; stats->rx_errors++; - priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); if (skb) { cf->can_id |= CAN_ERR_CRTL; cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; -- GitLab From 189c7890f33b21764289e05dde76a196ebf64587 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Thu, 23 Feb 2017 14:50:03 +0200 Subject: [PATCH 0275/1001] can: xilinx_can: keep only 1-2 frames in TX FIFO to fix TX accounting commit 620050d9c2be15c47017ba95efe59e0832e99a56 upstream. The xilinx_can driver assumes that the TXOK interrupt only clears after it has been acknowledged as many times as there have been successfully sent frames. However, the documentation does not mention such behavior, instead saying just that the interrupt is cleared when the clear bit is set. Similarly, testing seems to also suggest that it is immediately cleared regardless of the amount of frames having been sent. Performing some heavy TX load and then going back to idle has the tx_head drifting further away from tx_tail over time, steadily reducing the amount of frames the driver keeps in the TX FIFO (but not to zero, as the TXOK interrupt always frees up space for 1 frame from the driver's perspective, so frames continue to be sent) and delaying the local echo frames. The TX FIFO tracking is also otherwise buggy as it does not account for TX FIFO being cleared after software resets, causing BUG!, TX FIFO full when queue awake! messages to be output. There does not seem to be any way to accurately track the state of the TX FIFO for local echo support while using the full TX FIFO. The Zynq version of the HW (but not the soft-AXI version) has watermark programming support and with it an additional TX-FIFO-empty interrupt bit. Modify the driver to only put 1 frame into TX FIFO at a time on soft-AXI and 2 frames at a time on Zynq. On Zynq the TXFEMP interrupt bit is used to detect whether 1 or 2 frames have been sent at interrupt processing time. Tested with the integrated CAN on Zynq-7000 SoC. The 1-frame-FIFO mode was also tested. An alternative way to solve this would be to drop local echo support but keep using the full TX FIFO. v2: Add FIFO space check before TX queue wake with locking to synchronize with queue stop. This avoids waking the queue when xmit() had just filled it. v3: Keep local echo support and reduce the amount of frames in FIFO instead as suggested by Marc Kleine-Budde. Fixes: b1201e44f50b ("can: xilinx CAN controller support") Signed-off-by: Anssi Hannula Cc: Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/xilinx_can.c | 139 +++++++++++++++++++++++++++++++---- 1 file changed, 123 insertions(+), 16 deletions(-) diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 8a94489aa125..63f4d3eddb0f 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -26,8 +26,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -119,6 +121,7 @@ enum xcan_reg { /** * struct xcan_priv - This definition define CAN driver instance * @can: CAN private data structure. + * @tx_lock: Lock for synchronizing TX interrupt handling * @tx_head: Tx CAN packets ready to send on the queue * @tx_tail: Tx CAN packets successfully sended on the queue * @tx_max: Maximum number packets the driver can send @@ -133,6 +136,7 @@ enum xcan_reg { */ struct xcan_priv { struct can_priv can; + spinlock_t tx_lock; unsigned int tx_head; unsigned int tx_tail; unsigned int tx_max; @@ -160,6 +164,11 @@ static const struct can_bittiming_const xcan_bittiming_const = { .brp_inc = 1, }; +#define XCAN_CAP_WATERMARK 0x0001 +struct xcan_devtype_data { + unsigned int caps; +}; + /** * xcan_write_reg_le - Write a value to the device register little endian * @priv: Driver private data structure @@ -239,6 +248,10 @@ static int set_reset_mode(struct net_device *ndev) usleep_range(500, 10000); } + /* reset clears FIFOs */ + priv->tx_head = 0; + priv->tx_tail = 0; + return 0; } @@ -393,6 +406,7 @@ static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) struct net_device_stats *stats = &ndev->stats; struct can_frame *cf = (struct can_frame *)skb->data; u32 id, dlc, data[2] = {0, 0}; + unsigned long flags; if (can_dropped_invalid_skb(ndev, skb)) return NETDEV_TX_OK; @@ -440,6 +454,9 @@ static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) data[1] = be32_to_cpup((__be32 *)(cf->data + 4)); can_put_echo_skb(skb, ndev, priv->tx_head % priv->tx_max); + + spin_lock_irqsave(&priv->tx_lock, flags); + priv->tx_head++; /* Write the Frame to Xilinx CAN TX FIFO */ @@ -455,10 +472,16 @@ static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) stats->tx_bytes += cf->can_dlc; } + /* Clear TX-FIFO-empty interrupt for xcan_tx_interrupt() */ + if (priv->tx_max > 1) + priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXFEMP_MASK); + /* Check if the TX buffer is full */ if ((priv->tx_head - priv->tx_tail) == priv->tx_max) netif_stop_queue(ndev); + spin_unlock_irqrestore(&priv->tx_lock, flags); + return NETDEV_TX_OK; } @@ -832,19 +855,71 @@ static void xcan_tx_interrupt(struct net_device *ndev, u32 isr) { struct xcan_priv *priv = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; + unsigned int frames_in_fifo; + int frames_sent = 1; /* TXOK => at least 1 frame was sent */ + unsigned long flags; + int retries = 0; + + /* Synchronize with xmit as we need to know the exact number + * of frames in the FIFO to stay in sync due to the TXFEMP + * handling. + * This also prevents a race between netif_wake_queue() and + * netif_stop_queue(). + */ + spin_lock_irqsave(&priv->tx_lock, flags); + + frames_in_fifo = priv->tx_head - priv->tx_tail; - while ((priv->tx_head - priv->tx_tail > 0) && - (isr & XCAN_IXR_TXOK_MASK)) { + if (WARN_ON_ONCE(frames_in_fifo == 0)) { + /* clear TXOK anyway to avoid getting back here */ priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK); + spin_unlock_irqrestore(&priv->tx_lock, flags); + return; + } + + /* Check if 2 frames were sent (TXOK only means that at least 1 + * frame was sent). + */ + if (frames_in_fifo > 1) { + WARN_ON(frames_in_fifo > priv->tx_max); + + /* Synchronize TXOK and isr so that after the loop: + * (1) isr variable is up-to-date at least up to TXOK clear + * time. This avoids us clearing a TXOK of a second frame + * but not noticing that the FIFO is now empty and thus + * marking only a single frame as sent. + * (2) No TXOK is left. Having one could mean leaving a + * stray TXOK as we might process the associated frame + * via TXFEMP handling as we read TXFEMP *after* TXOK + * clear to satisfy (1). + */ + while ((isr & XCAN_IXR_TXOK_MASK) && !WARN_ON(++retries == 100)) { + priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK); + isr = priv->read_reg(priv, XCAN_ISR_OFFSET); + } + + if (isr & XCAN_IXR_TXFEMP_MASK) { + /* nothing in FIFO anymore */ + frames_sent = frames_in_fifo; + } + } else { + /* single frame in fifo, just clear TXOK */ + priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK); + } + + while (frames_sent--) { can_get_echo_skb(ndev, priv->tx_tail % priv->tx_max); priv->tx_tail++; stats->tx_packets++; - isr = priv->read_reg(priv, XCAN_ISR_OFFSET); } + + netif_wake_queue(ndev); + + spin_unlock_irqrestore(&priv->tx_lock, flags); + can_led_event(ndev, CAN_LED_EVENT_TX); xcan_update_error_state_after_rxtx(ndev); - netif_wake_queue(ndev); } /** @@ -1138,6 +1213,18 @@ static const struct dev_pm_ops xcan_dev_pm_ops = { SET_RUNTIME_PM_OPS(xcan_runtime_suspend, xcan_runtime_resume, NULL) }; +static const struct xcan_devtype_data xcan_zynq_data = { + .caps = XCAN_CAP_WATERMARK, +}; + +/* Match table for OF platform binding */ +static const struct of_device_id xcan_of_match[] = { + { .compatible = "xlnx,zynq-can-1.0", .data = &xcan_zynq_data }, + { .compatible = "xlnx,axi-can-1.00.a", }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(of, xcan_of_match); + /** * xcan_probe - Platform registration call * @pdev: Handle to the platform device structure @@ -1152,8 +1239,10 @@ static int xcan_probe(struct platform_device *pdev) struct resource *res; /* IO mem resources */ struct net_device *ndev; struct xcan_priv *priv; + const struct of_device_id *of_id; + int caps = 0; void __iomem *addr; - int ret, rx_max, tx_max; + int ret, rx_max, tx_max, tx_fifo_depth; /* Get the virtual base address for the device */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1163,7 +1252,8 @@ static int xcan_probe(struct platform_device *pdev) goto err; } - ret = of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", &tx_max); + ret = of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", + &tx_fifo_depth); if (ret < 0) goto err; @@ -1171,6 +1261,30 @@ static int xcan_probe(struct platform_device *pdev) if (ret < 0) goto err; + of_id = of_match_device(xcan_of_match, &pdev->dev); + if (of_id) { + const struct xcan_devtype_data *devtype_data = of_id->data; + + if (devtype_data) + caps = devtype_data->caps; + } + + /* There is no way to directly figure out how many frames have been + * sent when the TXOK interrupt is processed. If watermark programming + * is supported, we can have 2 frames in the FIFO and use TXFEMP + * to determine if 1 or 2 frames have been sent. + * Theoretically we should be able to use TXFWMEMP to determine up + * to 3 frames, but it seems that after putting a second frame in the + * FIFO, with watermark at 2 frames, it can happen that TXFWMEMP (less + * than 2 frames in FIFO) is set anyway with no TXOK (a frame was + * sent), which is not a sensible state - possibly TXFWMEMP is not + * completely synchronized with the rest of the bits? + */ + if (caps & XCAN_CAP_WATERMARK) + tx_max = min(tx_fifo_depth, 2); + else + tx_max = 1; + /* Create a CAN device instance */ ndev = alloc_candev(sizeof(struct xcan_priv), tx_max); if (!ndev) @@ -1185,6 +1299,7 @@ static int xcan_probe(struct platform_device *pdev) CAN_CTRLMODE_BERR_REPORTING; priv->reg_base = addr; priv->tx_max = tx_max; + spin_lock_init(&priv->tx_lock); /* Get IRQ for the device */ ndev->irq = platform_get_irq(pdev, 0); @@ -1249,9 +1364,9 @@ static int xcan_probe(struct platform_device *pdev) pm_runtime_put(&pdev->dev); - netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx fifo depth:%d\n", + netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx fifo depth: actual %d, using %d\n", priv->reg_base, ndev->irq, priv->can.clock.freq, - priv->tx_max); + tx_fifo_depth, priv->tx_max); return 0; @@ -1285,14 +1400,6 @@ static int xcan_remove(struct platform_device *pdev) return 0; } -/* Match table for OF platform binding */ -static const struct of_device_id xcan_of_match[] = { - { .compatible = "xlnx,zynq-can-1.0", }, - { .compatible = "xlnx,axi-can-1.00.a", }, - { /* end of list */ }, -}; -MODULE_DEVICE_TABLE(of, xcan_of_match); - static struct platform_driver xcan_driver = { .probe = xcan_probe, .remove = xcan_remove, -- GitLab From 19c756e01b094e06f025f4a1facd006932455875 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Mon, 26 Feb 2018 14:39:59 +0200 Subject: [PATCH 0276/1001] can: xilinx_can: fix incorrect clear of non-processed interrupts commit 2f4f0f338cf453bfcdbcf089e177c16f35f023c8 upstream. xcan_interrupt() clears ERROR|RXOFLV|BSOFF|ARBLST interrupts if any of them is asserted. This does not take into account that some of them could have been asserted between interrupt status read and interrupt clear, therefore clearing them without handling them. Fix the code to only clear those interrupts that it knows are asserted and therefore going to be processed in xcan_err_interrupt(). Fixes: b1201e44f50b ("can: xilinx CAN controller support") Signed-off-by: Anssi Hannula Cc: Michal Simek Cc: Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/xilinx_can.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 63f4d3eddb0f..62a58bf23dc8 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -938,6 +938,7 @@ static irqreturn_t xcan_interrupt(int irq, void *dev_id) struct net_device *ndev = (struct net_device *)dev_id; struct xcan_priv *priv = netdev_priv(ndev); u32 isr, ier; + u32 isr_errors; /* Get the interrupt status from Xilinx CAN */ isr = priv->read_reg(priv, XCAN_ISR_OFFSET); @@ -956,11 +957,10 @@ static irqreturn_t xcan_interrupt(int irq, void *dev_id) xcan_tx_interrupt(ndev, isr); /* Check for the type of error interrupt and Processing it */ - if (isr & (XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK | - XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK)) { - priv->write_reg(priv, XCAN_ICR_OFFSET, (XCAN_IXR_ERROR_MASK | - XCAN_IXR_RXOFLW_MASK | XCAN_IXR_BSOFF_MASK | - XCAN_IXR_ARBLST_MASK)); + isr_errors = isr & (XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK | + XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK); + if (isr_errors) { + priv->write_reg(priv, XCAN_ICR_OFFSET, isr_errors); xcan_err_interrupt(ndev, isr); } -- GitLab From 60454a9715df60af6f1538826a59b8e0b7d0156f Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Mon, 26 Feb 2018 14:27:13 +0200 Subject: [PATCH 0277/1001] can: xilinx_can: fix RX overflow interrupt not being enabled commit 83997997252f5d3fc7f04abc24a89600c2b504ab upstream. RX overflow interrupt (RXOFLW) is disabled even though xcan_interrupt() processes it. This means that an RX overflow interrupt will only be processed when another interrupt gets asserted (e.g. for RX/TX). Fix that by enabling the RXOFLW interrupt. Fixes: b1201e44f50b ("can: xilinx CAN controller support") Signed-off-by: Anssi Hannula Cc: Michal Simek Cc: Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/xilinx_can.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 62a58bf23dc8..5a24039733ef 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -104,7 +104,7 @@ enum xcan_reg { #define XCAN_INTR_ALL (XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |\ XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | \ XCAN_IXR_RXNEMP_MASK | XCAN_IXR_ERROR_MASK | \ - XCAN_IXR_ARBLST_MASK) + XCAN_IXR_RXOFLW_MASK | XCAN_IXR_ARBLST_MASK) /* CAN register bit shift - XCAN___SHIFT */ #define XCAN_BTR_SJW_SHIFT 7 /* Synchronous jump width */ -- GitLab From a55d3d73d45787b091b1fadf1b1c0c23613860c1 Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Thu, 21 Jun 2018 15:23:31 +0200 Subject: [PATCH 0278/1001] can: peak_canfd: fix firmware < v3.3.0: limit allocation to 32-bit DMA addr only commit 5d4c94ed9f564224d7b37dbee13f7c5d4a8a01ac upstream. The DMA logic in firmwares < v3.3.0 embedded in the PCAN-PCIe FD cards family is not capable of handling a mix of 32-bit and 64-bit logical addresses. If the board is equipped with 2 or 4 CAN ports, then such a situation might lead to a PCIe Bus Error "Malformed TLP" packet as well as "irq xx: nobody cared" issue. This patch adds a workaround that requests only 32-bit DMA addresses when these might be allocated outside of the 4 GB area. This issue has been fixed in firmware v3.3.0 and next. Signed-off-by: Stephane Grosjean Cc: linux-stable Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/peak_canfd/peak_pciefd_main.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/net/can/peak_canfd/peak_pciefd_main.c b/drivers/net/can/peak_canfd/peak_pciefd_main.c index 3c51a884db87..fa689854f16b 100644 --- a/drivers/net/can/peak_canfd/peak_pciefd_main.c +++ b/drivers/net/can/peak_canfd/peak_pciefd_main.c @@ -58,6 +58,10 @@ MODULE_LICENSE("GPL v2"); #define PCIEFD_REG_SYS_VER1 0x0040 /* version reg #1 */ #define PCIEFD_REG_SYS_VER2 0x0044 /* version reg #2 */ +#define PCIEFD_FW_VERSION(x, y, z) (((u32)(x) << 24) | \ + ((u32)(y) << 16) | \ + ((u32)(z) << 8)) + /* System Control Registers Bits */ #define PCIEFD_SYS_CTL_TS_RST 0x00000001 /* timestamp clock */ #define PCIEFD_SYS_CTL_CLK_EN 0x00000002 /* system clock */ @@ -783,6 +787,21 @@ static int peak_pciefd_probe(struct pci_dev *pdev, "%ux CAN-FD PCAN-PCIe FPGA v%u.%u.%u:\n", can_count, hw_ver_major, hw_ver_minor, hw_ver_sub); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + /* FW < v3.3.0 DMA logic doesn't handle correctly the mix of 32-bit and + * 64-bit logical addresses: this workaround forces usage of 32-bit + * DMA addresses only when such a fw is detected. + */ + if (PCIEFD_FW_VERSION(hw_ver_major, hw_ver_minor, hw_ver_sub) < + PCIEFD_FW_VERSION(3, 3, 0)) { + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (err) + dev_warn(&pdev->dev, + "warning: can't set DMA mask %llxh (err %d)\n", + DMA_BIT_MASK(32), err); + } +#endif + /* stop system clock */ pciefd_sys_writereg(pciefd, PCIEFD_SYS_CTL_CLK_EN, PCIEFD_REG_SYS_CTL_CLR); -- GitLab From 08382d3a1be25a41d9d82b8bba9a26c9b2b22cf3 Mon Sep 17 00:00:00 2001 From: Roman Fietze Date: Wed, 11 Jul 2018 15:36:14 +0200 Subject: [PATCH 0279/1001] can: m_can.c: fix setup of CCCR register: clear CCCR NISO bit before checking can.ctrlmode commit 393753b217f05474e714aea36c37501546ed1202 upstream. Inside m_can_chip_config(), when setting up the new value of the CCCR, the CCCR_NISO bit is not cleared like the others, CCCR_TEST, CCCR_MON, CCCR_BRSE and CCCR_FDOE, before checking the can.ctrlmode bits for CAN_CTRLMODE_FD_NON_ISO. This way once the controller was configured for CAN_CTRLMODE_FD_NON_ISO, this mode could never be cleared again. This fix is only relevant for controllers with version 3.1.x or 3.2.x. Older versions do not support NISO. Signed-off-by: Roman Fietze Cc: linux-stable Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/m_can/m_can.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 5d4e61741476..ca3fa82316c2 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -1073,7 +1073,8 @@ static void m_can_chip_config(struct net_device *dev) } else { /* Version 3.1.x or 3.2.x */ - cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_BRSE | CCCR_FDOE); + cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_BRSE | CCCR_FDOE | + CCCR_NISO); /* Only 3.2.x has NISO Bit implemented */ if (priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) -- GitLab From e94f784fddd58418bf5d97a23cf331d04a1bf5b1 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 26 Jul 2018 10:13:22 +0200 Subject: [PATCH 0280/1001] turn off -Wattribute-alias Starting with gcc-8.1, we get a warning about all system call definitions, which use an alias between functions with incompatible prototypes, e.g.: In file included from ../mm/process_vm_access.c:19: ../include/linux/syscalls.h:211:18: warning: 'sys_process_vm_readv' alias between functions of incompatible types 'long int(pid_t, const struct iovec *, long unsigned int, const struct iovec *, long unsigned int, long unsigned int)' {aka 'long int(int, const struct iovec *, long unsigned int, const struct iovec *, long unsigned int, long unsigned int)'} and 'long int(long int, long int, long int, long int, long int, long int)' [-Wattribute-alias] asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \ ^~~ ../include/linux/syscalls.h:207:2: note: in expansion of macro '__SYSCALL_DEFINEx' __SYSCALL_DEFINEx(x, sname, __VA_ARGS__) ^~~~~~~~~~~~~~~~~ ../include/linux/syscalls.h:201:36: note: in expansion of macro 'SYSCALL_DEFINEx' #define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__) ^~~~~~~~~~~~~~~ ../mm/process_vm_access.c:300:1: note: in expansion of macro 'SYSCALL_DEFINE6' SYSCALL_DEFINE6(process_vm_readv, pid_t, pid, const struct iovec __user *, lvec, ^~~~~~~~~~~~~~~ ../include/linux/syscalls.h:215:18: note: aliased declaration here asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ ^~~ ../include/linux/syscalls.h:207:2: note: in expansion of macro '__SYSCALL_DEFINEx' __SYSCALL_DEFINEx(x, sname, __VA_ARGS__) ^~~~~~~~~~~~~~~~~ ../include/linux/syscalls.h:201:36: note: in expansion of macro 'SYSCALL_DEFINEx' #define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__) ^~~~~~~~~~~~~~~ ../mm/process_vm_access.c:300:1: note: in expansion of macro 'SYSCALL_DEFINE6' SYSCALL_DEFINE6(process_vm_readv, pid_t, pid, const struct iovec __user *, lvec, This is really noisy and does not indicate a real problem. In the latest mainline kernel, this was addressed by commit bee20031772a ("disable -Wattribute-alias warning for SYSCALL_DEFINEx()"), which seems too invasive to backport. This takes a much simpler approach and just disables the warning across the kernel. Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index ffc9b4e3867e..7c886c9ed9c8 100644 --- a/Makefile +++ b/Makefile @@ -642,6 +642,7 @@ KBUILD_CFLAGS += $(call cc-disable-warning,frame-address,) KBUILD_CFLAGS += $(call cc-disable-warning, format-truncation) KBUILD_CFLAGS += $(call cc-disable-warning, format-overflow) KBUILD_CFLAGS += $(call cc-disable-warning, int-in-bool-context) +KBUILD_CFLAGS += $(call cc-disable-warning, attribute-alias) ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE KBUILD_CFLAGS += $(call cc-option,-Oz,-Os) -- GitLab From 53208e12faa5b8c6eac4eb1d23d6e3fae450fc5a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 28 Jul 2018 07:55:45 +0200 Subject: [PATCH 0281/1001] Linux 4.14.59 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7c886c9ed9c8..81b0e99dce80 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 58 +SUBLEVEL = 59 EXTRAVERSION = NAME = Petit Gorille -- GitLab From c25d7c2220d78e7a342ceef26818f092d0b493ca Mon Sep 17 00:00:00 2001 From: Om Parkash Date: Tue, 31 Jul 2018 12:27:54 +0530 Subject: [PATCH 0282/1001] msm: camera: csiphy: Add support for 14nm csiphy Add driver for 14nm csiphy for sm6150. Change-Id: I41f090e4813ae3d6c871f1209829606ed160fb23 Signed-off-by: Om Parkash --- .../cam_csiphy/cam_csiphy_core.c | 31 +- .../cam_csiphy/cam_csiphy_dev.h | 2 + .../cam_csiphy/cam_csiphy_soc.c | 15 + .../cam_csiphy/cam_csiphy_soc.h | 1 + .../cam_csiphy/include/cam_csiphy_2_0_hwreg.h | 294 ++++++++++++++++++ 5 files changed, 340 insertions(+), 3 deletions(-) create mode 100644 drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index 754646ce4c89..b0b4db53e494 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -246,10 +246,17 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) mask <<= 1; } } else { - if (csiphy_dev->csiphy_info.combo_mode == 1) - reg_array = + if (csiphy_dev->csiphy_info.combo_mode == 1) { + if (csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg) + reg_array = csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg; - else + else { + reg_array = + csiphy_dev->ctrl_reg->csiphy_3ph_reg; + CAM_ERR(CAM_CSIPHY, + "Unsupported configuration, Falling back to CPHY mode"); + } + } else reg_array = csiphy_dev->ctrl_reg->csiphy_3ph_reg; csiphy_dev->num_irq_registers = 11; @@ -283,6 +290,24 @@ int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) usleep_range(csiphy_common_reg->delay * 1000, csiphy_common_reg->delay * 1000 + 10); break; + case CSIPHY_2PH_REGS: + if (!csiphy_dev->csiphy_info.csiphy_3phase) { + cam_io_w_mb(csiphy_common_reg->reg_data, + csiphybase + + csiphy_common_reg->reg_addr); + usleep_range(csiphy_common_reg->delay * 1000, + csiphy_common_reg->delay * 1000 + 10); + } + break; + case CSIPHY_3PH_REGS: + if (csiphy_dev->csiphy_info.csiphy_3phase) { + cam_io_w_mb(csiphy_common_reg->reg_data, + csiphybase + + csiphy_common_reg->reg_addr); + usleep_range(csiphy_common_reg->delay * 1000, + csiphy_common_reg->delay * 1000 + 10); + } + break; default: break; } diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h index 5e871ad1f813..68f20b4acd59 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h @@ -57,6 +57,8 @@ #define CSIPHY_SETTLE_CNT_LOWER_BYTE 2 #define CSIPHY_SETTLE_CNT_HIGHER_BYTE 3 #define CSIPHY_DNP_PARAMS 4 +#define CSIPHY_2PH_REGS 5 +#define CSIPHY_3PH_REGS 6 #define ENABLE_IRQ false diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c index 8199087908b4..0b9f52f9d333 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -14,6 +14,7 @@ #include "cam_csiphy_core.h" #include "include/cam_csiphy_1_1_hwreg.h" #include "include/cam_csiphy_1_0_hwreg.h" +#include "include/cam_csiphy_2_0_hwreg.h" #define BYTES_PER_REGISTER 4 #define NUM_REGISTER_PER_LINE 4 @@ -192,6 +193,20 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; csiphy_dev->hw_version = CSIPHY_VERSION_V11; csiphy_dev->clk_lane = 0; + } else if (of_device_is_compatible(soc_info->dev->of_node, + "qcom,csiphy-v2.0")) { + csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v2_0_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg = + csiphy_2ph_v2_0_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v2_0_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = NULL; + csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_2_0; + csiphy_dev->ctrl_reg->csiphy_common_reg = csiphy_common_reg_2_0; + csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_2_0; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v2_0; + csiphy_dev->hw_version = CSIPHY_VERSION_V20; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->clk_lane = 0; } else { CAM_ERR(CAM_CSIPHY, "invalid hw version : 0x%x", csiphy_dev->hw_version); diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h index c7792d6acebb..972fff99b8e8 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h @@ -37,6 +37,7 @@ #define CSIPHY_VERSION_V35 0x35 #define CSIPHY_VERSION_V10 0x10 #define CSIPHY_VERSION_V11 0x11 +#define CSIPHY_VERSION_V20 0x20 /** * @csiphy_dev: CSIPhy device structure diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h new file mode 100644 index 000000000000..04b827f9cb79 --- /dev/null +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h @@ -0,0 +1,294 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CAM_CSIPHY_2_0_HWREG_H_ +#define _CAM_CSIPHY_2_0_HWREG_H_ + +#include "../cam_csiphy_dev.h" + +struct csiphy_reg_parms_t csiphy_v2_0 = { + .mipi_csiphy_interrupt_status0_addr = 0x8B0, + .mipi_csiphy_interrupt_clear0_addr = 0x858, + .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_common_array_size = 6, + .csiphy_reset_array_size = 3, + .csiphy_2ph_config_array_size = 15, + .csiphy_3ph_config_array_size = 17, +}; + +struct csiphy_reg_t csiphy_common_reg_2_0[] = { + {0x0814, 0x00, 0x00, CSIPHY_LANE_ENABLE}, + {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x06, 0x00, CSIPHY_3PH_REGS}, + {0x0164, 0x00, 0x00, CSIPHY_2PH_REGS}, + {0x0364, 0x00, 0x00, CSIPHY_2PH_REGS}, + {0x0564, 0x00, 0x00, CSIPHY_2PH_REGS}, +}; + +struct csiphy_reg_t csiphy_reset_reg_2_0[] = { + {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, + {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_irq_reg_2_0[] = { + {0x082c, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0830, 0xff, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0834, 0xfb, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0838, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x083c, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0840, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0844, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0848, 0xef, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x084c, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0850, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0854, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_2ph_v2_0_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0730, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0230, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0430, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0630, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t + csiphy_2ph_v2_0_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0730, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0230, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0430, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0630, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t csiphy_3ph_v2_0_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x015C, 0x23, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0x70, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0x17, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x035C, 0x23, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0x70, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0x17, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x055C, 0x23, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0x70, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0x17, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +#endif /* _CAM_CSIPHY_2_0_HWREG_H_ */ -- GitLab From e9d9471c94ee520e0c3b2d6974bcd69732311465 Mon Sep 17 00:00:00 2001 From: Junzhe Zou Date: Tue, 24 Jul 2018 17:14:51 -0700 Subject: [PATCH 0283/1001] msm: camera: icp: release mutex properly in flush function Mutex lock was not released when there is nothing to be flushed in ICP driver and recovery is not enabled, which will cause issue when release HW tries to acquire same mutex. This change properly release the mutex lock in such scenario. Change-Id: I86804b529694e64fdea1550ac36834c2c356cdd4 Signed-off-by: Junzhe Zou --- .../msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index 1e84175f1c4a..4cfc3b5e1456 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -3850,11 +3850,9 @@ static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) switch (flush_args->flush_type) { case CAM_FLUSH_TYPE_ALL: mutex_lock(&hw_mgr->hw_mgr_mutex); - if (!hw_mgr->recovery) { - if (flush_args->num_req_active) { - mutex_unlock(&hw_mgr->hw_mgr_mutex); - cam_icp_mgr_abort_handle(ctx_data); - } + if (!hw_mgr->recovery && flush_args->num_req_active) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + cam_icp_mgr_abort_handle(ctx_data); } else { mutex_unlock(&hw_mgr->hw_mgr_mutex); } -- GitLab From ddaf45936c8d9ac46f355402c1ead5a0cd574cc8 Mon Sep 17 00:00:00 2001 From: Lynus Vaz Date: Thu, 2 Aug 2018 12:47:28 +0530 Subject: [PATCH 0284/1001] ARM: dts: msm: Update the L3 GPU vote for sm8150 v2 The L3 clock can run at a higher frequency on sm8150 v2. Update the L3 GPU vote to take advantage of the higher frequency. Change-Id: I3bb9f8c66be231391a2c072859d4e0e58906ac14 Signed-off-by: Lynus Vaz --- arch/arm64/boot/dts/qcom/sm8150-v2.dtsi | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi b/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi index efb00ff3ef07..7dc41b7c9f9b 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi @@ -422,6 +422,28 @@ qcom,bus-max = <0>; }; }; + + qcom,l3-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "qcom,l3-pwrlevels"; + + qcom,l3-pwrlevel@0 { + reg = <0>; + qcom,l3-freq = <0>; + }; + + qcom,l3-pwrlevel@1 { + reg = <1>; + qcom,l3-freq = <1344000000>; + }; + + qcom,l3-pwrlevel@2 { + reg = <2>; + qcom,l3-freq = <1612800000>; + }; + }; }; /* NPU overrides */ -- GitLab From d97e66506d08661394bd3fbfa4486eaebd029ffa Mon Sep 17 00:00:00 2001 From: Suresh Vankadara Date: Fri, 6 Jul 2018 14:48:21 +0530 Subject: [PATCH 0285/1001] ARM: dts: msm: Add camera dts for sm6150 Add camera nodes for camera dtsi entries. Change-Id: Iab5097dd7a23bae57f40f4fbd9524312e5af6ce0 Signed-off-by: Alok Pandey Signed-off-by: Om Parkash --- .../bindings/media/video/msm-cam-csiphy.txt | 2 +- .../dts/qcom/sm6150-camera-sensor-idp.dtsi | 378 ++++++ arch/arm64/boot/dts/qcom/sm6150-camera.dtsi | 1055 +++++++++++++++++ .../boot/dts/qcom/sm6150-idp-overlay.dts | 1 + arch/arm64/boot/dts/qcom/sm6150-idp.dtsi | 1 + arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi | 278 +++++ arch/arm64/boot/dts/qcom/sm6150.dtsi | 1 + 7 files changed, 1715 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sm6150-camera.dtsi diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt b/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt index 33865b225231..249dd04cc6e2 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt @@ -14,7 +14,7 @@ First Level Node - CSIPHY device Usage: required Value type: Definition: Should be "qcom,csiphy-v1.0", - "qcom,csiphy-v1.1", "qcom,csiphy". + "qcom,csiphy-v1.1", "qcom,csiphy-v2.0", "qcom,csiphy". - cell-index: csiphy hardware core index Usage: required diff --git a/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi new file mode 100644 index 000000000000..eaf3c8a9ab61 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + + led_flash_rear: qcom,camera-flash@0 { + cell-index = <0>; + reg = <0x00 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash0>; + torch-source = <&pm6150l_torch1>; + switch-source = <&pm6150l_switch0>; + status = "ok"; + }; + + led_flash_rear_aux: qcom,camera-flash@1 { + cell-index = <1>; + reg = <0x01 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash1>; + torch-source = <&pm6150l_torch1>; + switch-source = <&pm6150l_switch1>; + status = "ok"; + }; + + led_flash_front: qcom,camera-flash@2 { + cell-index = <2>; + reg = <0x02 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash2>; + torch-source = <&pm6150l_torch2>; + switch-source = <&pm6150l_switch2>; + status = "ok"; + enable-active-high; + gpio = <&tlmm 38 0>; + pinctrl-names = "default"; + pinctrl-0 = <&flash_led3_front_en>; + }; + + camera_ldo: gpio-regulator@0 { + compatible = "regulator-fixed"; + reg = <0x00 0x00>; + regulator-name = "camera_ldo"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-enable-ramp-delay = <135>; + enable-active-high; + gpio = <&pm6150l_gpios 3 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_dvdd_en>; + vin-supply = <&pm6150l_s8>; + }; + + camera_vana0_ldo: gpio-regulator@1 { + compatible = "regulator-fixed"; + reg = <0x01 0x00>; + regulator-name = "camera_vana0_ldo"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&pm6150l_gpios 9 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_0_vana>; + vin-supply = <&pm6150l_bob>; + }; + + camera_vana1_2_ldo: gpio-regulator@2 { + compatible = "regulator-fixed"; + reg = <0x02 0x00>; + regulator-name = "camera_vana1_2_ldo"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&pm6150l_gpios 4 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_1_2_vana>; + vin-supply = <&pm6150l_bob>; + }; +}; + +&cam_cci { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; + + actuator_rear: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm6150_l19>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_front: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&pm6150_l19>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + ois_rear: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + cci-master = <0>; + cam_vaf-supply = <&pm6150_l19>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + status = "disabled"; + }; + + eeprom_rear: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm6150_l13>; + cam_vana-supply = <&camera_vana0_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm6150_l19>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-max-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend>; + gpios = <&tlmm 28 0>, + <&tlmm 47 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_rear_aux: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm6150_l13>; + cam_vana-supply = <&camera_vana1_2_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm6150_l19>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-max-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-load-current = <105000 0 80000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 29 0>, + <&tlmm 45 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_front: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm6150_l13>; + cam_vana-supply = <&camera_vana1_2_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm6150_l19>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-max-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_front_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 30 0>, + <&tlmm 37 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear>; + ois-src = <&ois_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&pm6150_l13>; + cam_vana-supply = <&camera_vana0_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0>; + rgltr-max-voltage = <1800000 2850000 1200000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend>; + gpios = <&tlmm 28 0>, + <&tlmm 47 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear_aux>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&pm6150_l13>; + cam_vana-supply = <&camera_vana1_2_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0>; + rgltr-max-voltage = <1800000 2850000 1200000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 29 0>, + <&tlmm 45 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + actuator-src = <&actuator_front>; + led-flash-src = <&led_flash_front>; + cam_vio-supply = <&pm6150_l13>; + cam_vana-supply = <&camera_vana1_2_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0>; + rgltr-max-voltage = <1800000 2850000 1200000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_front_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 30 0>, + <&tlmm 37 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi b/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi new file mode 100644 index 000000000000..5076b603c074 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi @@ -0,0 +1,1055 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + qcom,cam-req-mgr { + compatible = "qcom,cam-req-mgr"; + status = "ok"; + }; + + cam_csiphy0: qcom,csiphy@ac65000 { + cell-index = <0>; + compatible = "qcom,csiphy-v2.0", "qcom,csiphy"; + reg = <0x0ac65000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x65000>; + interrupts = <0 477 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr"; + gdscr-supply = <&titan_top_gdsc>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm6150l_l3>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY0_CLK>, + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy0_clk", + "csi0phytimer_clk_src", + "csi0phytimer_clk"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + status = "ok"; + }; + + cam_csiphy1: qcom,csiphy@ac66000{ + cell-index = <1>; + compatible = "qcom,csiphy-v2.0", "qcom,csiphy"; + reg = <0xac66000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x66000>; + interrupts = <0 478 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr"; + gdscr-supply = <&titan_top_gdsc>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm6150l_l3>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY1_CLK>, + <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy1_clk", + "csi1phytimer_clk_src", + "csi1phytimer_clk"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + + status = "ok"; + }; + + cam_csiphy2: qcom,csiphy@ac67000 { + cell-index = <2>; + compatible = "qcom,csiphy-v2.0", "qcom,csiphy"; + reg = <0xac67000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x67000>; + interrupts = <0 479 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr"; + gdscr-supply = <&titan_top_gdsc>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm6150l_l3>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY2_CLK>, + <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy2_clk", + "csi2phytimer_clk_src", + "csi2phytimer_clk"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + status = "ok"; + }; + + cam_cci: qcom,cci@ac4a000 { + cell-index = <0>; + compatible = "qcom,cci"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xac4a000 0x4000>; + reg-names = "cci"; + reg-cam-base = <0x4a000>; + interrupt-names = "cci"; + interrupts = <0 460 0>; + status = "ok"; + gdscr-supply = <&titan_top_gdsc>; + regulator-names = "gdscr"; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CCI_CLK>, + <&clock_camcc CAM_CC_CCI_CLK_SRC>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cci_clk", + "cci_clk_src"; + src-clock-name = "cci_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <0 0 0 0 0 37500000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cci0_active &cci1_active>; + pinctrl-1 = <&cci0_suspend &cci1_suspend>; + gpios = <&tlmm 17 0>, + <&tlmm 18 0>, + <&tlmm 19 0>, + <&tlmm 20 0>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 1 1 1>; + gpio-req-tbl-label = "CCI_I2C_DATA0", + "CCI_I2C_CLK0", + "CCI_I2C_DATA1", + "CCI_I2C_CLK1"; + + i2c_freq_100Khz: qcom,i2c_standard_mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz: qcom,i2c_fast_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_custom: qcom,i2c_custom_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz: qcom,i2c_fast_plus_mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <0>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + qcom,cam_smmu { + compatible = "qcom,msm-cam-smmu"; + status = "ok"; + + msm_cam_smmu_ife { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x820 0x0>, + <&apps_smmu 0x840 0x0>, + <&apps_smmu 0x860 0x0>; + label = "ife"; + ife_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_lrme { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x0cc0 0x0>, + <&apps_smmu 0x0d40 0x0>; + label = "lrme"; + lrme_iova_mem_map: iova-mem-map { + iova-mem-region-shared { + /* Shared region is 100MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x6400000>; + iova-region-id = <0x1>; + status = "ok"; + }; + /* IO region is approximately 3.3 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0xd800000>; + iova-region-len = <0xd2800000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_jpeg { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1060 0x8>; + label = "jpeg"; + jpeg_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_icp_fw { + compatible = "qcom,msm-cam-smmu-fw-dev"; + label="icp"; + memory-region = <&pil_camera_mem>; + }; + + msm_cam_smmu_icp { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x0de2 0x0>, + <&apps_smmu 0x0c80 0x0>, + <&apps_smmu 0x0ca0 0x0>, + <&apps_smmu 0x0d00 0x0>, + <&apps_smmu 0x0d20 0x0>; + label = "icp"; + icp_iova_mem_map: iova-mem-map { + iova-mem-region-firmware { + /* Firmware region is 5MB */ + iova-region-name = "firmware"; + iova-region-start = <0x0>; + iova-region-len = <0x500000>; + iova-region-id = <0x0>; + status = "ok"; + }; + + iova-mem-region-shared { + /* Shared region is 100MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x6400000>; + iova-region-id = <0x1>; + iova-granularity = <0x15>; + status = "ok"; + }; + + iova-mem-region-secondary-heap { + /* Secondary heap region is 1MB long */ + iova-region-name = "secheap"; + iova-region-start = <0xd800000>; + iova-region-len = <0x100000>; + iova-region-id = <0x4>; + status = "ok"; + }; + + iova-mem-region-io { + /* IO region is approximately 3 GB */ + iova-region-name = "io"; + iova-region-start = <0xd911000>; + iova-region-len = <0xd26ef000>; + iova-region-id = <0x3>; + status = "ok"; + }; + + iova-mem-qdss-region { + /* qdss region is approximately 64K */ + iova-region-name = "qdss"; + iova-region-start = <0xd900000>; + iova-region-len = <0x10000>; + iova-region-id = <0x5>; + qdss-phy-addr = <0x16790000>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_cpas_cdm { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x0c00 0x0>, + <&apps_smmu 0x0c01 0x0>; + label = "cpas-cdm0"; + cpas_cdm_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 3.4 GB */ + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_secure { + compatible = "qcom,msm-cam-smmu-cb"; + label = "cam-secure"; + qcom,secure-cb; + }; + }; + + qcom,cam-cpas@ac40000 { + cell-index = <0>; + compatible = "qcom,cam-cpas"; + label = "cpas"; + arch-compat = "cpas_top"; + status = "ok"; + reg-names = "cam_cpas_top", "cam_camnoc"; + reg = <0xac40000 0x1000>, + <0xac42000 0x5000>; + reg-cam-base = <0x40000 0x42000>; + interrupt-names = "cpas_camnoc"; + interrupts = <0 459 0>; + qcom,cpas-hw-ver = <0x150100>; /* Titan v150 v1.0.0 */ + camnoc-axi-min-ib-bw = <3000000000>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_ahb_clk", + "gcc_axi_clk", + "soc_ahb_clk", + "slow_ahb_clk_src", + "cpas_ahb_clk", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + src-clock-name = "slow_ahb_clk_src"; + clock-rates = <0 0 0 0 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>; + clock-cntl-level = "suspend", "minsvs", "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + qcom,msm-bus,name = "cam_ahb"; + qcom,msm-bus,num-cases = <7>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + , + , + , + , + ; + vdd-corners = ; + vdd-corner-ahb-mapping = "suspend", "suspend", + "minsvs", "lowsvs", "svs", "svs_l1", + "nominal", "nominal", "nominal", + "turbo", "turbo"; + client-id-based; + client-names = + "csiphy0", "csiphy1", "csiphy2", "cci0", + "csid0", "csid1", "csid2", + "ife0", "ife1", "ife2", "ipe0", + "ipe1", "cam-cdm-intf0", "cpas-cdm0", "bps0", + "icp0", "jpeg-dma0", "jpeg-enc0", "lrmecpas"; + client-axi-port-names = + "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", + "cam_hf_1", "cam_hf_2", "cam_hf_2", + "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", + "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1", + "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1"; + client-bus-camnoc-based; + qcom,axi-port-list { + qcom,axi-port1 { + qcom,axi-port-name = "cam_hf_1"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_hf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_hf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + qcom,axi-port2 { + qcom,axi-port-name = "cam_hf_2"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_hf_2_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_hf_2_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + qcom,axi-port3 { + qcom,axi-port-name = "cam_sf_1"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_sf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_sf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + }; + }; + + qcom,cam-cdm-intf { + compatible = "qcom,cam-cdm-intf"; + cell-index = <0>; + label = "cam-cdm-intf"; + num-hw-cdm = <1>; + cdm-client-names = "vfe", + "jpegdma", + "jpegenc", + "lrmecdm"; + status = "ok"; + }; + + qcom,cpas-cdm0@ac48000 { + cell-index = <0>; + compatible = "qcom,cam170-cpas-cdm0"; + label = "cpas-cdm"; + reg = <0xac48000 0x1000>; + reg-names = "cpas-cdm"; + reg-cam-base = <0x48000>; + interrupts = <0 461 0>; + interrupt-names = "cpas-cdm"; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "gcc_camera_ahb", + "gcc_camera_axi", + "cam_cc_soc_ahb_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-rates = <0 0 0 0 0>; + clock-cntl-level = "svs"; + cdm-client-names = "ife"; + status = "ok"; + }; + + qcom,cam-isp { + compatible = "qcom,cam-isp"; + arch-compat = "ife"; + status = "ok"; + }; + + cam_csid0: qcom,csid0@acb3000 { + cell-index = <0>; + compatible = "qcom,csid170"; + reg-names = "csid"; + reg = <0xacb3000 0x1000>; + reg-cam-base = <0xb3000>; + interrupt-names = "csid"; + interrupts = <0 464 0>; + regulator-names = "camss", "ife0"; + camss-supply = <&titan_top_gdsc>; + ife0-supply = <&ife_0_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_0_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 200000000 0 0 0 360000000 0 0>, + <0 0 0 0 0 0 540000000 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe0: qcom,vfe0@acaf000 { + cell-index = <0>; + compatible = "qcom,vfe170"; + reg-names = "ife"; + reg = <0xacaf000 0x4000>; + reg-cam-base = <0xaf000>; + interrupt-names = "ife"; + interrupts = <0 465 0>; + regulator-names = "camss", "ife0"; + camss-supply = <&titan_top_gdsc>; + ife0-supply = <&ife_0_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_0_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 360000000 0 0>, + <0 0 0 0 0 0 432000000 0 0>, + <0 0 0 0 0 0 540000000 0 0>, + <0 0 0 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "svs_l1", "nominal", "turbo"; + src-clock-name = "ife_clk_src"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&clock_camcc CAM_CC_IFE_0_DSP_CLK>; + clock-rates-option = <600000000>; + status = "ok"; + }; + + cam_csid1: qcom,csid1@acba000 { + cell-index = <1>; + compatible = "qcom,csid170"; + reg-names = "csid"; + reg = <0xacba000 0x1000>; + reg-cam-base = <0xba000>; + interrupt-names = "csid"; + interrupts = <0 466 0>; + regulator-names = "camss", "ife1"; + camss-supply = <&titan_top_gdsc>; + ife1-supply = <&ife_1_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_1_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CLK>, + <&clock_camcc CAM_CC_IFE_1_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_1_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 200000000 0 0 0 360000000 0 0>, + <0 0 0 0 0 0 540000000 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe1: qcom,vfe1@acb6000 { + cell-index = <1>; + compatible = "qcom,vfe170"; + reg-names = "ife"; + reg = <0xacb6000 0x4000>; + reg-cam-base = <0xb6000>; + interrupt-names = "ife"; + interrupts = <0 467 0>; + regulator-names = "camss", "ife1"; + camss-supply = <&titan_top_gdsc>; + ife1-supply = <&ife_1_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CLK>, + <&clock_camcc CAM_CC_IFE_1_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_1_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 360000000 0 0>, + <0 0 0 0 0 0 432000000 0 0>, + <0 0 0 0 0 0 540000000 0 0>, + <0 0 0 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "svs_l1", "nominal", "turbo"; + src-clock-name = "ife_clk_src"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&clock_camcc CAM_CC_IFE_1_DSP_CLK>; + clock-rates-option = <600000000>; + status = "ok"; + }; + + cam_csid_lite: qcom,csid-lite@acc8000 { + cell-index = <2>; + compatible = "qcom,csid-lite170"; + reg-names = "csid-lite"; + reg = <0xacc8000 0x1000>; + reg-cam-base = <0xc8000>; + interrupt-names = "csid-lite"; + interrupts = <0 468 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 200000000 0 0 0 360000000 0>, + <0 0 0 0 0 0 540000000 0 0 0 600000000 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe_lite: qcom,vfe-lite@acc4000 { + cell-index = <2>; + compatible = "qcom,vfe-lite170"; + reg-names = "ife-lite"; + reg = <0xacc4000 0x4000>; + reg-cam-base = <0xc4000>; + interrupt-names = "ife-lite"; + interrupts = <0 469 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 360000000 0>, + <0 0 0 0 0 0 432000000 0>, + <0 0 0 0 0 0 540000000 0>, + <0 0 0 0 0 0 600000000 0>; + clock-cntl-level = "svs", "svs_l1", "nominal", "turbo"; + src-clock-name = "ife_clk_src"; + status = "ok"; + }; + + qcom,cam-icp { + compatible = "qcom,cam-icp"; + compat-hw-name = "qcom,a5", + "qcom,ipe0", + "qcom,bps"; + num-a5 = <1>; + num-ipe = <1>; + num-bps = <1>; + status = "ok"; + }; + + cam_a5: qcom,a5@ac00000 { + cell-index = <0>; + compatible = "qcom,cam-a5"; + reg = <0xac00000 0x6000>, + <0xac10000 0x8000>, + <0xac18000 0x3000>; + reg-names = "a5_qgic", "a5_sierra", "a5_csr"; + reg-cam-base = <0x00000 0x10000 0x18000>; + interrupts = <0 463 0>; + interrupt-names = "a5"; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_cam_ahb_clk", + "gcc_cam_axi_clk", + "soc_fast_ahb", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "icp_clk", + "icp_clk_src"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_ICP_CLK>, + <&clock_camcc CAM_CC_ICP_CLK_SRC>; + + clock-rates = + <0 0 200000000 0 0 0 0 360000000>, + <0 0 200000000 0 0 0 0 600000000>; + clock-cntl-level = "svs", "turbo"; + fw_name = "CAMERA_ICP.elf"; + ubwc-cfg = <0x73 0x1CF>; + status = "ok"; + }; + + cam_ipe0: qcom,ipe0 { + cell-index = <0>; + compatible = "qcom,cam-ipe"; + regulator-names = "ipe0-vdd"; + ipe0-vdd-supply = <&ipe_0_gdsc>; + clock-names = "ipe_0_ahb_clk", + "ipe_0_areg_clk", + "ipe_0_axi_clk", + "ipe_0_clk", + "ipe_0_clk_src"; + src-clock-name = "ipe_0_clk_src"; + clocks = <&clock_camcc CAM_CC_IPE_0_AHB_CLK>, + <&clock_camcc CAM_CC_IPE_0_AREG_CLK>, + <&clock_camcc CAM_CC_IPE_0_AXI_CLK>, + <&clock_camcc CAM_CC_IPE_0_CLK>, + <&clock_camcc CAM_CC_IPE_0_CLK_SRC>; + + clock-rates = + <0 0 0 0 360000000>, + <0 0 0 0 432000000>, + <0 0 0 0 480000000>, + <0 0 0 0 540000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "svs", + "svs_l1", "nominal", "nominal_l1", "turbo"; + status = "ok"; + }; + + cam_bps: qcom,bps { + cell-index = <0>; + compatible = "qcom,cam-bps"; + regulator-names = "bps-vdd"; + bps-vdd-supply = <&bps_gdsc>; + clock-names = "bps_ahb_clk", + "bps_areg_clk", + "bps_axi_clk", + "bps_clk", + "bps_clk_src"; + src-clock-name = "bps_clk_src"; + clocks = <&clock_camcc CAM_CC_BPS_AHB_CLK>, + <&clock_camcc CAM_CC_BPS_AREG_CLK>, + <&clock_camcc CAM_CC_BPS_AXI_CLK>, + <&clock_camcc CAM_CC_BPS_CLK>, + <&clock_camcc CAM_CC_BPS_CLK_SRC>; + + clock-rates = + <0 0 0 0 360000000>, + <0 0 0 0 432000000>, + <0 0 0 0 480000000>, + <0 0 0 0 540000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "svs", + "svs_l1", "nominal", "nominal_l1", "turbo"; + status = "ok"; + }; + + qcom,cam-jpeg { + compatible = "qcom,cam-jpeg"; + compat-hw-name = "qcom,jpegenc", + "qcom,jpegdma"; + num-jpeg-enc = <1>; + num-jpeg-dma = <1>; + status = "ok"; + }; + + cam_jpeg_enc: qcom,jpegenc@ac4e000 { + cell-index = <0>; + compatible = "qcom,cam_jpeg_enc"; + reg-names = "jpege_hw"; + reg = <0xac4e000 0x4000>; + reg-cam-base = <0x4e000>; + interrupt-names = "jpeg"; + interrupts = <0 474 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "jpegenc_clk_src", + "jpegenc_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_JPEG_CLK_SRC>, + <&clock_camcc CAM_CC_JPEG_CLK>; + + clock-rates = <0 0 0 0 0 320000000 0>; + src-clock-name = "jpegenc_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + cam_jpeg_dma: qcom,jpegdma@0xac52000{ + cell-index = <0>; + compatible = "qcom,cam_jpeg_dma"; + reg-names = "jpegdma_hw"; + reg = <0xac52000 0x4000>; + reg-cam-base = <0x52000>; + interrupt-names = "jpegdma"; + interrupts = <0 475 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "jpegdma_clk_src", + "jpegdma_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_JPEG_CLK_SRC>, + <&clock_camcc CAM_CC_JPEG_CLK>; + + clock-rates = <0 0 0 0 0 320000000 0>; + src-clock-name = "jpegdma_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + qcom,cam-lrme { + compatible = "qcom,cam-lrme"; + arch-compat = "lrme"; + status = "ok"; + }; + + cam_lrme: qcom,lrme@ac6b000 { + cell-index = <0>; + compatible = "qcom,lrme"; + reg-names = "lrme"; + reg = <0xac6b000 0xa00>; + reg-cam-base = <0x6b000>; + interrupt-names = "lrme"; + interrupts = <0 476 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "lrme_clk_src", + "lrme_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_LRME_CLK_SRC>, + <&clock_camcc CAM_CC_LRME_CLK>; + clock-rates = <0 0 0 0 0 200000000 200000000>, + <0 0 0 0 0 216000000 216000000>, + <0 0 0 0 0 300000000 300000000>, + <0 0 0 0 0 404000000 404000000>, + <0 0 0 0 0 404000000 404000000>, + <0 0 0 0 0 404000000 404000000>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal", + "nominal_l1", "turbo"; + src-clock-name = "lrme_clk_src"; + status = "ok"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts index ae891836ed6b..de09032f4db1 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts @@ -14,6 +14,7 @@ /plugin/; #include +#include #include "sm6150-idp.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi index f9f7bc31ec86..698609b4fcbf 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi @@ -10,6 +10,7 @@ * GNU General Public License for more details. */ +#include "sm6150-camera-sensor-idp.dtsi" &soc { }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi index 5e62775e0761..a22754aefc93 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi @@ -580,5 +580,283 @@ drive-strength = <2>; /* 2 MA */ }; }; + + cci0_active: cci0_active { + mux { + /* CLK, DATA */ + pins = "gpio32", "gpio33"; + function = "cci_i2c"; + }; + + config { + pins = "gpio32", "gpio33"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci0_suspend: cci0_suspend { + mux { + /* CLK, DATA */ + pins = "gpio32", "gpio33"; + function = "cci_i2c"; + }; + + config { + pins = "gpio32", "gpio33"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_active: cci1_active { + mux { + /* CLK, DATA */ + pins = "gpio34", "gpio35"; + function = "cci_i2c"; + }; + + config { + pins = "gpio34", "gpio35"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_suspend: cci1_suspend { + mux { + /* CLK, DATA */ + pins = "gpio34", "gpio35"; + function = "cci_i2c"; + }; + + config { + pins = "gpio34", "gpio35"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_active: cam_sensor_mclk0_active { + /* MCLK0 */ + mux { + pins = "gpio28"; + function = "cam_mclk"; + }; + + config { + pins = "gpio28"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_suspend: cam_sensor_mclk0_suspend { + /* MCLK0 */ + mux { + pins = "gpio28"; + function = "cam_mclk"; + }; + + config { + pins = "gpio28"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_active: cam_sensor_rear_active { + /* RESET */ + mux { + pins = "gpio47"; + function = "gpio"; + }; + + config { + pins = "gpio47"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_suspend: cam_sensor_rear_suspend { + /* RESET */ + mux { + pins = "gpio47"; + function = "gpio"; + }; + + config { + pins = "gpio47"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_front_active: cam_sensor_front_active { + /* RESET */ + mux { + pins = "gpio37"; + function = "gpio"; + }; + + config { + pins = "gpio37"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_suspend: cam_sensor_front_suspend { + /* RESET */ + mux { + pins = "gpio37"; + function = "gpio"; + }; + + config { + pins = "gpio37"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_rear2_active: cam_sensor_rear2_active { + /* RESET */ + mux { + pins = "gpio45"; + function = "gpio"; + }; + + config { + pins = "gpio45"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear2_suspend: cam_sensor_rear2_suspend { + /* RESET */ + mux { + pins = "gpio45"; + function = "gpio"; + }; + + config { + pins = "gpio45"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_mclk1_active: cam_sensor_mclk1_active { + /* MCLK1 */ + mux { + pins = "gpio29"; + function = "cam_mclk"; + }; + + config { + pins = "gpio29"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_suspend: cam_sensor_mclk1_suspend { + /* MCLK1 */ + mux { + pins = "gpio29"; + function = "cam_mclk"; + }; + + config { + pins = "gpio29"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_active: cam_sensor_mclk2_active { + /* MCLK2 */ + mux { + pins = "gpio30"; + function = "cam_mclk"; + }; + + config { + pins = "gpio30"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_suspend: cam_sensor_mclk2_suspend { + /* MCLK2 */ + mux { + pins = "gpio30"; + function = "cam_mclk"; + }; + + config { + pins = "gpio30"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + flash_led3_front { + flash_led3_front_en: flash_led3_front_en { + mux { + pins = "gpio38"; + function = "gpio"; + }; + + config { + pins = "gpio38"; + drive_strength = <2>; + output-high; + bias-disable; + }; + }; + + flash_led3_front_dis: flash_led3_front_dis { + mux { + pins = "gpio38"; + function = "gpio"; + }; + + config { + pins = "gpio38"; + drive_strength = <2>; + output-low; + bias-disable; + }; + }; + }; + }; +}; + +&pm6150l_gpios { + cam_sensor_dvdd_en: cam_sensor_dvdd_en { + pins = "gpio3"; + function = "normal"; + power-source = <0>; + output-low; + }; + cam_sensor_0_vana: cam_sensor_0_vana { + pins = "gpio9"; + function = "normal"; + power-source = <0>; + output-low; + }; + cam_sensor_1_2_vana: cam_sensor_1_2_vana { + pins = "gpio4"; + function = "normal"; + power-source = <0>; + output-low; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 7a4fd67bf018..ff8bf79dd766 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -1935,6 +1935,7 @@ status = "ok"; }; +#include "sm6150-camera.dtsi" #include "sm6150-ion.dtsi" #include "msm-arm-smmu-sm6150.dtsi" #include "sm6150-coresight.dtsi" -- GitLab From cf85425e818ba54dbabd3edcc1d13226297d8554 Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Thu, 26 Jul 2018 16:08:10 -0700 Subject: [PATCH 0286/1001] defconfig: Enable SSR notification timeouts on SM8150 Enable timeouts for SSR notifications on SM8150, such that when a timeout expires, cause a kernel panic. Change-Id: I413c2063a7e52368cdcd4918373f4d22640c2bf4 Signed-off-by: Isaac J. Manjarres --- arch/arm64/configs/vendor/sm8150-perf_defconfig | 2 ++ arch/arm64/configs/vendor/sm8150_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm64/configs/vendor/sm8150-perf_defconfig b/arch/arm64/configs/vendor/sm8150-perf_defconfig index 557bbeb3d20c..edb84c4bfa40 100644 --- a/arch/arm64/configs/vendor/sm8150-perf_defconfig +++ b/arch/arm64/configs/vendor/sm8150-perf_defconfig @@ -535,6 +535,8 @@ CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_SYSMON_QMI_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_SETUP_SSR_NOTIF_TIMEOUTS=y +CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y CONFIG_MSM_BOOT_STATS=y CONFIG_QCOM_DCC_V2=y CONFIG_QCOM_SECURE_BUFFER=y diff --git a/arch/arm64/configs/vendor/sm8150_defconfig b/arch/arm64/configs/vendor/sm8150_defconfig index 0b4cfcc55eb2..1b6c35a0015f 100644 --- a/arch/arm64/configs/vendor/sm8150_defconfig +++ b/arch/arm64/configs/vendor/sm8150_defconfig @@ -558,6 +558,8 @@ CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_SYSMON_QMI_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_SETUP_SSR_NOTIF_TIMEOUTS=y +CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_QCOM_DCC_V2=y -- GitLab From eabecf4bf23d3fdec06d01c5d6c92794845d877d Mon Sep 17 00:00:00 2001 From: David Dai Date: Thu, 2 Aug 2018 10:58:42 -0700 Subject: [PATCH 0287/1001] clk: qcom: debugcc-sm8150: Add measurement support for CDSP clock Add support to measure the rate of the turing_axi_clk which is also known as the compute dsp noc. Change-Id: Ie7df8eac862f6c641a70481d2d351feb2c01d1c0 Signed-off-by: David Dai --- drivers/clk/qcom/debugcc-sm8150.c | 3 +++ drivers/clk/qcom/gcc-sm8150.c | 9 +++++++++ include/dt-bindings/clock/qcom,gcc-sm8150.h | 1 + 3 files changed, 13 insertions(+) diff --git a/drivers/clk/qcom/debugcc-sm8150.c b/drivers/clk/qcom/debugcc-sm8150.c index d30acb6ce87e..3ff1a6d22c97 100644 --- a/drivers/clk/qcom/debugcc-sm8150.c +++ b/drivers/clk/qcom/debugcc-sm8150.c @@ -118,6 +118,7 @@ static const char *const debug_mux_parent_names[] = { "disp_cc_mdss_rscc_vsync_clk", "disp_cc_mdss_vsync_clk", "disp_cc_xo_clk", + "measure_only_cdsp_clk", "measure_only_snoc_clk", "measure_only_cnoc_clk", "measure_only_bimc_clk", @@ -464,6 +465,8 @@ static struct clk_debug_mux gcc_debug_mux = { 0x14, 0xFF, 0, 0x3, 0, 4, 0x7000, 0x5008, 0x500C }, { "disp_cc_xo_clk", 0x56, 1, DISP_CC, 0x36, 0xFF, 0, 0x3, 0, 4, 0x7000, 0x5008, 0x500C }, + { "measure_only_cdsp_clk", 0xDB, 2, GCC, + 0xDB, 0x3FF, 0, 0xF, 0, 2, 0x62000, 0x62004, 0x62008 }, { "measure_only_snoc_clk", 0x7, 1, GCC, 0x7, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "measure_only_cnoc_clk", 0x19, 1, GCC, diff --git a/drivers/clk/qcom/gcc-sm8150.c b/drivers/clk/qcom/gcc-sm8150.c index d7f5f65a782e..d7e2486d6fb8 100644 --- a/drivers/clk/qcom/gcc-sm8150.c +++ b/drivers/clk/qcom/gcc-sm8150.c @@ -177,6 +177,14 @@ static const char * const gcc_parent_names_7[] = { "core_bi_pll_test_se", }; +static struct clk_dummy measure_only_cdsp_clk = { + .rrate = 1000, + .hw.init = &(struct clk_init_data){ + .name = "measure_only_cdsp_clk", + .ops = &clk_dummy_ops, + }, +}; + static struct clk_dummy measure_only_snoc_clk = { .rrate = 1000, .hw.init = &(struct clk_init_data){ @@ -3899,6 +3907,7 @@ static struct clk_branch gcc_video_xo_clk = { }; struct clk_hw *gcc_sm8150_hws[] = { + [MEASURE_ONLY_CDSP_CLK] = &measure_only_cdsp_clk.hw, [MEASURE_ONLY_SNOC_CLK] = &measure_only_snoc_clk.hw, [MEASURE_ONLY_CNOC_CLK] = &measure_only_cnoc_clk.hw, [MEASURE_ONLY_BIMC_CLK] = &measure_only_bimc_clk.hw, diff --git a/include/dt-bindings/clock/qcom,gcc-sm8150.h b/include/dt-bindings/clock/qcom,gcc-sm8150.h index 6a0a0ab5c70e..063e09772369 100644 --- a/include/dt-bindings/clock/qcom,gcc-sm8150.h +++ b/include/dt-bindings/clock/qcom,gcc-sm8150.h @@ -254,5 +254,6 @@ #define MEASURE_ONLY_BIMC_CLK 2 #define MEASURE_ONLY_IPA_2X_CLK 3 #define MMCX_CLK 4 +#define MEASURE_ONLY_CDSP_CLK 5 #endif -- GitLab From 2d5fc7ffa84bfa0d778c30b96072295ad36a1030 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 20 Apr 2018 14:55:31 -0700 Subject: [PATCH 0288/1001] fork: unconditionally clear stack on fork commit e01e80634ecdde1dd113ac43b3adad21b47f3957 upstream. One of the classes of kernel stack content leaks[1] is exposing the contents of prior heap or stack contents when a new process stack is allocated. Normally, those stacks are not zeroed, and the old contents remain in place. In the face of stack content exposure flaws, those contents can leak to userspace. Fixing this will make the kernel no longer vulnerable to these flaws, as the stack will be wiped each time a stack is assigned to a new process. There's not a meaningful change in runtime performance; it almost looks like it provides a benefit. Performing back-to-back kernel builds before: Run times: 157.86 157.09 158.90 160.94 160.80 Mean: 159.12 Std Dev: 1.54 and after: Run times: 159.31 157.34 156.71 158.15 160.81 Mean: 158.46 Std Dev: 1.46 Instead of making this a build or runtime config, Andy Lutomirski recommended this just be enabled by default. [1] A noisy search for many kinds of stack content leaks can be seen here: https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=linux+kernel+stack+leak I did some more with perf and cycle counts on running 100,000 execs of /bin/true. before: Cycles: 218858861551 218853036130 214727610969 227656844122 224980542841 Mean: 221015379122.60 Std Dev: 4662486552.47 after: Cycles: 213868945060 213119275204 211820169456 224426673259 225489986348 Mean: 217745009865.40 Std Dev: 5935559279.99 It continues to look like it's faster, though the deviation is rather wide, but I'm not sure what I could do that would be less noisy. I'm open to ideas! Link: http://lkml.kernel.org/r/20180221021659.GA37073@beast Signed-off-by: Kees Cook Acked-by: Michal Hocko Reviewed-by: Andrew Morton Cc: Andy Lutomirski Cc: Laura Abbott Cc: Rasmus Villemoes Cc: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/thread_info.h | 6 +----- kernel/fork.c | 3 +-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h index 34f053a150a9..cf2862bd134a 100644 --- a/include/linux/thread_info.h +++ b/include/linux/thread_info.h @@ -43,11 +43,7 @@ enum { #define THREAD_ALIGN THREAD_SIZE #endif -#if IS_ENABLED(CONFIG_DEBUG_STACK_USAGE) || IS_ENABLED(CONFIG_DEBUG_KMEMLEAK) -# define THREADINFO_GFP (GFP_KERNEL_ACCOUNT | __GFP_ZERO) -#else -# define THREADINFO_GFP (GFP_KERNEL_ACCOUNT) -#endif +#define THREADINFO_GFP (GFP_KERNEL_ACCOUNT | __GFP_ZERO) /* * flag set/clear/test wrappers diff --git a/kernel/fork.c b/kernel/fork.c index 98c91bd341b4..91907a3701ce 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -215,10 +215,9 @@ static unsigned long *alloc_thread_stack_node(struct task_struct *tsk, int node) if (!s) continue; -#ifdef CONFIG_DEBUG_KMEMLEAK /* Clear stale pointers from reused stack. */ memset(s->addr, 0, THREAD_SIZE); -#endif + tsk->stack_vm_area = s; return s->addr; } -- GitLab From c0b86d269bf097fd100e275574ae50f1aec248ad Mon Sep 17 00:00:00 2001 From: Lixin Wang Date: Mon, 27 Nov 2017 15:06:55 +0800 Subject: [PATCH 0289/1001] i2c: core: decrease reference count of device node in i2c_unregister_device commit e0638fa400eaccf9fa8060f67140264c4e276552 upstream. Reference count of device node was increased in of_i2c_register_device, but without decreasing it in i2c_unregister_device. Then the added device node will never be released. Fix this by adding the of_node_put. Signed-off-by: Lixin Wang Tested-by: Wolfram Sang Signed-off-by: Wolfram Sang Cc: stable@kernel.org Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/i2c-core-base.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 56e46581b84b..6f2fe63e8f5a 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -808,8 +808,11 @@ EXPORT_SYMBOL_GPL(i2c_new_device); */ void i2c_unregister_device(struct i2c_client *client) { - if (client->dev.of_node) + if (client->dev.of_node) { of_node_clear_flag(client->dev.of_node, OF_POPULATED); + of_node_put(client->dev.of_node); + } + if (ACPI_COMPANION(&client->dev)) acpi_device_clear_enumerated(ACPI_COMPANION(&client->dev)); device_unregister(&client->dev); -- GitLab From 3af618717e710a4b4d635eaef87645bc0e99c71a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 1 Mar 2018 14:00:28 -0800 Subject: [PATCH 0290/1001] RDMA/core: Avoid that ib_drain_qp() triggers an out-of-bounds stack access commit a1ae7d0345edd593d6725d3218434d903a0af95d upstream. This patch fixes the following KASAN complaint: ================================================================== BUG: KASAN: stack-out-of-bounds in rxe_post_send+0x77d/0x9b0 [rdma_rxe] Read of size 8 at addr ffff880061aef860 by task 01/1080 CPU: 2 PID: 1080 Comm: 01 Not tainted 4.16.0-rc3-dbg+ #2 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.0.0-prebuilt.qemu-project.org 04/01/2014 Call Trace: dump_stack+0x85/0xc7 print_address_description+0x65/0x270 kasan_report+0x231/0x350 rxe_post_send+0x77d/0x9b0 [rdma_rxe] __ib_drain_sq+0x1ad/0x250 [ib_core] ib_drain_qp+0x9/0x30 [ib_core] srp_destroy_qp+0x51/0x70 [ib_srp] srp_free_ch_ib+0xfc/0x380 [ib_srp] srp_create_target+0x1071/0x19e0 [ib_srp] kernfs_fop_write+0x180/0x210 __vfs_write+0xb1/0x2e0 vfs_write+0xf6/0x250 SyS_write+0x99/0x110 do_syscall_64+0xee/0x2b0 entry_SYSCALL_64_after_hwframe+0x42/0xb7 The buggy address belongs to the page: page:ffffea000186bbc0 count:0 mapcount:0 mapping:0000000000000000 index:0x0 flags: 0x4000000000000000() raw: 4000000000000000 0000000000000000 0000000000000000 00000000ffffffff raw: 0000000000000000 ffffea000186bbe0 0000000000000000 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff880061aef700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ffff880061aef780: 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 >ffff880061aef800: f2 f2 f2 f2 f2 f2 f2 00 00 00 00 00 f2 f2 f2 f2 ^ ffff880061aef880: f2 f2 f2 00 00 00 00 00 00 00 00 00 00 00 f2 f2 ffff880061aef900: f2 f2 f2 00 00 00 00 00 00 00 00 00 00 00 00 00 ================================================================== Fixes: 765d67748bcf ("IB: new common API for draining queues") Signed-off-by: Bart Van Assche Cc: Steve Wise Cc: Sagi Grimberg Cc: stable@vger.kernel.org Signed-off-by: Jason Gunthorpe Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/verbs.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 9032f77cc38d..195f0bc3f4ee 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -2115,10 +2115,15 @@ static void __ib_drain_sq(struct ib_qp *qp) struct ib_cq *cq = qp->send_cq; struct ib_qp_attr attr = { .qp_state = IB_QPS_ERR }; struct ib_drain_cqe sdrain; - struct ib_send_wr swr = {}, *bad_swr; + struct ib_send_wr *bad_swr; + struct ib_rdma_wr swr = { + .wr = { + .opcode = IB_WR_RDMA_WRITE, + .wr_cqe = &sdrain.cqe, + }, + }; int ret; - swr.wr_cqe = &sdrain.cqe; sdrain.cqe.done = ib_drain_qp_done; init_completion(&sdrain.done); @@ -2128,7 +2133,7 @@ static void __ib_drain_sq(struct ib_qp *qp) return; } - ret = ib_post_send(qp, &swr, &bad_swr); + ret = ib_post_send(qp, &swr.wr, &bad_swr); if (ret) { WARN_ONCE(ret, "failed to drain send queue: %d\n", ret); return; -- GitLab From d02c9c8bfef147c790985db5a348a91ab0deec66 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 13 Mar 2018 14:51:57 -0700 Subject: [PATCH 0291/1001] drivers/infiniband/core/verbs.c: fix build with gcc-4.4.4 commit 6ee687735e745eafae9e6b93d1ea70bc52e7ad07 upstream. gcc-4.4.4 has issues with initialization of anonymous unions. drivers/infiniband/core/verbs.c: In function '__ib_drain_sq': drivers/infiniband/core/verbs.c:2204: error: unknown field 'wr_cqe' specified in initializer drivers/infiniband/core/verbs.c:2204: warning: initialization makes integer from pointer without a cast Work around this. Fixes: a1ae7d0345edd5 ("RDMA/core: Avoid that ib_drain_qp() triggers an out-of-bounds stack access") Cc: Bart Van Assche Cc: Steve Wise Cc: Sagi Grimberg Cc: Jason Gunthorpe Cc: Signed-off-by: Andrew Morton Signed-off-by: Doug Ledford Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/verbs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 195f0bc3f4ee..feb80dbb5948 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -2118,8 +2118,9 @@ static void __ib_drain_sq(struct ib_qp *qp) struct ib_send_wr *bad_swr; struct ib_rdma_wr swr = { .wr = { + .next = NULL, + { .wr_cqe = &sdrain.cqe, }, .opcode = IB_WR_RDMA_WRITE, - .wr_cqe = &sdrain.cqe, }, }; int ret; -- GitLab From 1e8bb2e9c9df0d0e491e5022ce80a2b96b757ac3 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 1 Mar 2018 14:00:30 -0800 Subject: [PATCH 0292/1001] IB/srpt: Fix an out-of-bounds stack access in srpt_zerolength_write() commit 2a78cb4db487372152bed2055c038f9634d595e8 upstream. Avoid triggering an out-of-bounds stack access by changing the type of 'wr' from ib_send_wr into ib_rdma_wr. This patch fixes the following KASAN bug report: BUG: KASAN: stack-out-of-bounds in rxe_post_send+0x7a9/0x9a0 [rdma_rxe] Read of size 8 at addr ffff880068197a48 by task kworker/2:1/44 Workqueue: ib_cm cm_work_handler [ib_cm] Call Trace: dump_stack+0x8e/0xcd print_address_description+0x6f/0x280 kasan_report+0x25a/0x380 __asan_load8+0x54/0x90 rxe_post_send+0x7a9/0x9a0 [rdma_rxe] srpt_zerolength_write+0xf0/0x180 [ib_srpt] srpt_cm_rtu_recv+0x68/0x110 [ib_srpt] srpt_rdma_cm_handler+0xbb/0x15b [ib_srpt] cma_ib_handler+0x1aa/0x4a0 [rdma_cm] cm_process_work+0x30/0x100 [ib_cm] cm_work_handler+0xa86/0x351b [ib_cm] process_one_work+0x475/0x9f0 worker_thread+0x69/0x690 kthread+0x1ad/0x1d0 ret_from_fork+0x3a/0x50 Fixes: aaf45bd83eba ("IB/srpt: Detect session shutdown reliably") Signed-off-by: Bart Van Assche Cc: Christoph Hellwig Cc: stable@vger.kernel.org Signed-off-by: Jason Gunthorpe Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/srpt/ib_srpt.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index ee578fa713c2..5a5e1343b386 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -787,13 +787,16 @@ static int srpt_post_recv(struct srpt_device *sdev, */ static int srpt_zerolength_write(struct srpt_rdma_ch *ch) { - struct ib_send_wr wr, *bad_wr; + struct ib_send_wr *bad_wr; + struct ib_rdma_wr wr = { + .wr = { + .opcode = IB_WR_RDMA_WRITE, + .wr_cqe = &ch->zw_cqe, + .send_flags = IB_SEND_SIGNALED, + } + }; - memset(&wr, 0, sizeof(wr)); - wr.opcode = IB_WR_RDMA_WRITE; - wr.wr_cqe = &ch->zw_cqe; - wr.send_flags = IB_SEND_SIGNALED; - return ib_post_send(ch->qp, &wr, &bad_wr); + return ib_post_send(ch->qp, &wr.wr, &bad_wr); } static void srpt_zerolength_write_done(struct ib_cq *cq, struct ib_wc *wc) -- GitLab From e581f7c590cca70b7338f43b73f4cfa081077c00 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 13 Mar 2018 15:06:45 -0700 Subject: [PATCH 0293/1001] drivers/infiniband/ulp/srpt/ib_srpt.c: fix build with gcc-4.4.4 commit 06892cc190550807d332c95a0114c7e175584012 upstream. gcc-4.4.4 has issues with initialization of anonymous unions: drivers/infiniband/ulp/srpt/ib_srpt.c: In function 'srpt_zerolength_write': drivers/infiniband/ulp/srpt/ib_srpt.c:854: error: unknown field 'wr_cqe' specified in initializer drivers/infiniband/ulp/srpt/ib_srpt.c:854: warning: initialization makes integer from pointer without a cast Work aound this. Fixes: 2a78cb4db487 ("IB/srpt: Fix an out-of-bounds stack access in srpt_zerolength_write()") Cc: Bart Van Assche Cc: Christoph Hellwig Cc: Jason Gunthorpe Cc: Signed-off-by: Andrew Morton Signed-off-by: Doug Ledford Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/srpt/ib_srpt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 5a5e1343b386..97c2225829ea 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -790,8 +790,9 @@ static int srpt_zerolength_write(struct srpt_rdma_ch *ch) struct ib_send_wr *bad_wr; struct ib_rdma_wr wr = { .wr = { + .next = NULL, + { .wr_cqe = &ch->zw_cqe, }, .opcode = IB_WR_RDMA_WRITE, - .wr_cqe = &ch->zw_cqe, .send_flags = IB_SEND_SIGNALED, } }; -- GitLab From c09032b71fc6fa7d8a010b3a58ee4ca2ae9e1a09 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 16 May 2018 10:42:39 +0200 Subject: [PATCH 0294/1001] spi: spi-s3c64xx: Fix system resume support commit e935dba111621bd6a0c5d48e6511a4d9885103b4 upstream. Since Linux v4.10 release (commit 1d9174fbc55e "PM / Runtime: Defer resuming of the device in pm_runtime_force_resume()"), pm_runtime_force_resume() function doesn't runtime resume device if it was not runtime active before system suspend. Thus, driver should not do any register access after pm_runtime_force_resume() without checking the runtime status of the device. To fix this issue, simply move s3c64xx_spi_hwinit() call to s3c64xx_spi_runtime_resume() to ensure that hardware is always properly initialized. This fixes Synchronous external abort issue on system suspend/resume cycle on newer Exynos SoCs. Signed-off-by: Marek Szyprowski Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-s3c64xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index b392cca8fa4f..1a6ec226d6e4 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -1273,8 +1273,6 @@ static int s3c64xx_spi_resume(struct device *dev) if (ret < 0) return ret; - s3c64xx_spi_hwinit(sdd, sdd->port_id); - return spi_master_resume(master); } #endif /* CONFIG_PM_SLEEP */ @@ -1312,6 +1310,8 @@ static int s3c64xx_spi_runtime_resume(struct device *dev) if (ret != 0) goto err_disable_src_clk; + s3c64xx_spi_hwinit(sdd, sdd->port_id); + return 0; err_disable_src_clk: -- GitLab From b4667635de2e60b1ffb059f03d3d2977258849f0 Mon Sep 17 00:00:00 2001 From: Donald Shanty III Date: Wed, 4 Jul 2018 15:50:47 +0000 Subject: [PATCH 0295/1001] Input: elan_i2c - add ACPI ID for lenovo ideapad 330 commit 938f45008d8bc391593c97508bc798cc95a52b9b upstream. This allows Elan driver to bind to the touchpad found in Lenovo Ideapad 330 series laptops. Signed-off-by: Donald Shanty III Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/mouse/elan_i2c_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 7b5fa501bbcf..471c3e1a533a 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1262,6 +1262,7 @@ static const struct acpi_device_id elan_acpi_id[] = { { "ELAN0611", 0 }, { "ELAN0612", 0 }, { "ELAN0618", 0 }, + { "ELAN061D", 0 }, { "ELAN1000", 0 }, { } }; -- GitLab From e0e385e2126e0b73af8f54301b818499d2b3e6db Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 18 Jul 2018 17:24:35 +0000 Subject: [PATCH 0296/1001] Input: i8042 - add Lenovo LaVie Z to the i8042 reset list commit 384cf4285b34e08917e3e66603382f2b0c4f6e1b upstream. The Lenovo LaVie Z laptop requires i8042 to be reset in order to consistently detect its Elantech touchpad. The nomux and kbdreset quirks are not sufficient. It's possible the other LaVie Z models from NEC require this as well. Cc: stable@vger.kernel.org Signed-off-by: Chen-Yu Tsai Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/serio/i8042-x86ia64io.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index b353d494ad40..136f6e7bf797 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -527,6 +527,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "N24_25BU"), }, }, + { + /* Lenovo LaVie Z */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo LaVie Z"), + }, + }, { } }; -- GitLab From ca6427facd967cbb7067422c1f3ab085874bb037 Mon Sep 17 00:00:00 2001 From: KT Liao Date: Mon, 16 Jul 2018 12:10:03 +0000 Subject: [PATCH 0297/1001] Input: elan_i2c - add another ACPI ID for Lenovo Ideapad 330-15AST commit 6f88a6439da5d94de334a341503bc2c7f4a7ea7f upstream. Add ELAN0622 to ACPI mapping table to support Elan touchpad found in Ideapad 330-15AST. Signed-off-by: KT Liao Reported-by: Anant Shende Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/mouse/elan_i2c_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 471c3e1a533a..696e540304fd 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1263,6 +1263,7 @@ static const struct acpi_device_id elan_acpi_id[] = { { "ELAN0612", 0 }, { "ELAN0618", 0 }, { "ELAN061D", 0 }, + { "ELAN0622", 0 }, { "ELAN1000", 0 }, { } }; -- GitLab From 8eead4f5dea9fdf01ac254171e3cc141181b825b Mon Sep 17 00:00:00 2001 From: Shakeel Butt Date: Thu, 26 Jul 2018 16:37:45 -0700 Subject: [PATCH 0298/1001] kvm, mm: account shadow page tables to kmemcg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit d97e5e6160c0e0a23963ec198c7cb1c69e6bf9e8 upstream. The size of kvm's shadow page tables corresponds to the size of the guest virtual machines on the system. Large VMs can spend a significant amount of memory as shadow page tables which can not be left as system memory overhead. So, account shadow page tables to the kmemcg. [shakeelb@google.com: replace (GFP_KERNEL|__GFP_ACCOUNT) with GFP_KERNEL_ACCOUNT] Link: http://lkml.kernel.org/r/20180629140224.205849-1-shakeelb@google.com Link: http://lkml.kernel.org/r/20180627181349.149778-1-shakeelb@google.com Signed-off-by: Shakeel Butt Cc: Michal Hocko Cc: Johannes Weiner Cc: Vladimir Davydov Cc: Paolo Bonzini Cc: Greg Thelen Cc: Radim Krčmář Cc: Peter Feiner Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 43bbece92632..2ef2f1fe875b 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -890,7 +890,7 @@ static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache, if (cache->nobjs >= min) return 0; while (cache->nobjs < ARRAY_SIZE(cache->objects)) { - page = (void *)__get_free_page(GFP_KERNEL); + page = (void *)__get_free_page(GFP_KERNEL_ACCOUNT); if (!page) return -ENOMEM; cache->objects[cache->nobjs++] = page; -- GitLab From a2f85c02810f91af6f2b7dd5de6a0ffb4c835b67 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 26 Jul 2018 16:37:08 -0700 Subject: [PATCH 0299/1001] delayacct: fix crash in delayacct_blkio_end() after delayacct init failure commit b512719f771a82180211c9a315b8a7f628832b3d upstream. While forking, if delayacct init fails due to memory shortage, it continues expecting all delayacct users to check task->delays pointer against NULL before dereferencing it, which all of them used to do. Commit c96f5471ce7d ("delayacct: Account blkio completion on the correct task"), while updating delayacct_blkio_end() to take the target task instead of always using %current, made the function test NULL on %current->delays and then continue to operated on @p->delays. If %current succeeded init while @p didn't, it leads to the following crash. BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: __delayacct_blkio_end+0xc/0x40 PGD 8000001fd07e1067 P4D 8000001fd07e1067 PUD 1fcffbb067 PMD 0 Oops: 0000 [#1] SMP PTI CPU: 4 PID: 25774 Comm: QIOThread0 Not tainted 4.16.0-9_fbk1_rc2_1180_g6b593215b4d7 #9 RIP: 0010:__delayacct_blkio_end+0xc/0x40 Call Trace: try_to_wake_up+0x2c0/0x600 autoremove_wake_function+0xe/0x30 __wake_up_common+0x74/0x120 wake_up_page_bit+0x9c/0xe0 mpage_end_io+0x27/0x70 blk_update_request+0x78/0x2c0 scsi_end_request+0x2c/0x1e0 scsi_io_completion+0x20b/0x5f0 blk_mq_complete_request+0xa2/0x100 ata_scsi_qc_complete+0x79/0x400 ata_qc_complete_multiple+0x86/0xd0 ahci_handle_port_interrupt+0xc9/0x5c0 ahci_handle_port_intr+0x54/0xb0 ahci_single_level_irq_intr+0x3b/0x60 __handle_irq_event_percpu+0x43/0x190 handle_irq_event_percpu+0x20/0x50 handle_irq_event+0x2a/0x50 handle_edge_irq+0x80/0x1c0 handle_irq+0xaf/0x120 do_IRQ+0x41/0xc0 common_interrupt+0xf/0xf Fix it by updating delayacct_blkio_end() check @p->delays instead. Link: http://lkml.kernel.org/r/20180724175542.GP1934745@devbig577.frc2.facebook.com Fixes: c96f5471ce7d ("delayacct: Account blkio completion on the correct task") Signed-off-by: Tejun Heo Reported-by: Dave Jones Debugged-by: Dave Jones Reviewed-by: Andrew Morton Cc: Josh Snyder Cc: [4.15+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/delayacct.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/delayacct.h b/include/linux/delayacct.h index 5e335b6203f4..41ee6dea7531 100644 --- a/include/linux/delayacct.h +++ b/include/linux/delayacct.h @@ -124,7 +124,7 @@ static inline void delayacct_blkio_start(void) static inline void delayacct_blkio_end(struct task_struct *p) { - if (current->delays) + if (p->delays) __delayacct_blkio_end(p); delayacct_clear_flag(DELAYACCT_PF_BLKIO); } -- GitLab From 9158a7debe5351688515de22fd18a5a8b006f458 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Tue, 24 Jul 2018 19:13:31 -0400 Subject: [PATCH 0300/1001] tracing: Fix double free of event_trigger_data commit 1863c387259b629e4ebfb255495f67cd06aa229b upstream. Running the following: # cd /sys/kernel/debug/tracing # echo 500000 > buffer_size_kb [ Or some other number that takes up most of memory ] # echo snapshot > events/sched/sched_switch/trigger Triggers the following bug: ------------[ cut here ]------------ kernel BUG at mm/slub.c:296! invalid opcode: 0000 [#1] SMP DEBUG_PAGEALLOC PTI CPU: 6 PID: 6878 Comm: bash Not tainted 4.18.0-rc6-test+ #1066 Hardware name: Hewlett-Packard HP Compaq Pro 6300 SFF/339A, BIOS K01 v03.03 07/14/2016 RIP: 0010:kfree+0x16c/0x180 Code: 05 41 0f b6 72 51 5b 5d 41 5c 4c 89 d7 e9 ac b3 f8 ff 48 89 d9 48 89 da 41 b8 01 00 00 00 5b 5d 41 5c 4c 89 d6 e9 f4 f3 ff ff <0f> 0b 0f 0b 48 8b 3d d9 d8 f9 00 e9 c1 fe ff ff 0f 1f 40 00 0f 1f RSP: 0018:ffffb654436d3d88 EFLAGS: 00010246 RAX: ffff91a9d50f3d80 RBX: ffff91a9d50f3d80 RCX: ffff91a9d50f3d80 RDX: 00000000000006a4 RSI: ffff91a9de5a60e0 RDI: ffff91a9d9803500 RBP: ffffffff8d267c80 R08: 00000000000260e0 R09: ffffffff8c1a56be R10: fffff0d404543cc0 R11: 0000000000000389 R12: ffffffff8c1a56be R13: ffff91a9d9930e18 R14: ffff91a98c0c2890 R15: ffffffff8d267d00 FS: 00007f363ea64700(0000) GS:ffff91a9de580000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000055c1cacc8e10 CR3: 00000000d9b46003 CR4: 00000000001606e0 Call Trace: event_trigger_callback+0xee/0x1d0 event_trigger_write+0xfc/0x1a0 __vfs_write+0x33/0x190 ? handle_mm_fault+0x115/0x230 ? _cond_resched+0x16/0x40 vfs_write+0xb0/0x190 ksys_write+0x52/0xc0 do_syscall_64+0x5a/0x160 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x7f363e16ab50 Code: 73 01 c3 48 8b 0d 38 83 2c 00 f7 d8 64 89 01 48 83 c8 ff c3 66 0f 1f 44 00 00 83 3d 79 db 2c 00 00 75 10 b8 01 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 1e e3 01 00 48 89 04 24 RSP: 002b:00007fff9a4c6378 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 0000000000000009 RCX: 00007f363e16ab50 RDX: 0000000000000009 RSI: 000055c1cacc8e10 RDI: 0000000000000001 RBP: 000055c1cacc8e10 R08: 00007f363e435740 R09: 00007f363ea64700 R10: 0000000000000073 R11: 0000000000000246 R12: 0000000000000009 R13: 0000000000000001 R14: 00007f363e4345e0 R15: 00007f363e4303c0 Modules linked in: ip6table_filter ip6_tables snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_seq snd_seq_device i915 snd_pcm snd_timer i2c_i801 snd soundcore i2c_algo_bit drm_kms_helper 86_pkg_temp_thermal video kvm_intel kvm irqbypass wmi e1000e ---[ end trace d301afa879ddfa25 ]--- The cause is because the register_snapshot_trigger() call failed to allocate the snapshot buffer, and then called unregister_trigger() which freed the data that was passed to it. Then on return to the function that called register_snapshot_trigger(), as it sees it failed to register, it frees the trigger_data again and causes a double free. By calling event_trigger_init() on the trigger_data (which only ups the reference counter for it), and then event_trigger_free() afterward, the trigger_data would not get freed by the registering trigger function as it would only up and lower the ref count for it. If the register trigger function fails, then the event_trigger_free() called after it will free the trigger data normally. Link: http://lkml.kernel.org/r/20180724191331.738eb819@gandalf.local.home Cc: stable@vger.kerne.org Fixes: 93e31ffbf417 ("tracing: Add 'snapshot' event trigger command") Reported-by: Masami Hiramatsu Reviewed-by: Masami Hiramatsu Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_events_trigger.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c index b413fab7d75b..d656e32dc853 100644 --- a/kernel/trace/trace_events_trigger.c +++ b/kernel/trace/trace_events_trigger.c @@ -680,6 +680,8 @@ event_trigger_callback(struct event_command *cmd_ops, goto out_free; out_reg: + /* Up the trigger_data count to make sure reg doesn't free it on failure */ + event_trigger_init(trigger_ops, trigger_data); ret = cmd_ops->reg(glob, trigger_ops, trigger_data, file); /* * The above returns on success the # of functions enabled, @@ -687,11 +689,13 @@ event_trigger_callback(struct event_command *cmd_ops, * Consider no functions a failure too. */ if (!ret) { + cmd_ops->unreg(glob, trigger_ops, trigger_data, file); ret = -ENOENT; - goto out_free; - } else if (ret < 0) - goto out_free; - ret = 0; + } else if (ret > 0) + ret = 0; + + /* Down the counter of trigger_data or free it if not used anymore */ + event_trigger_free(trigger_ops, trigger_data); out: return ret; -- GitLab From 10419b0c16d41e7fa3848e83e6bf7521aa9407ef Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Wed, 25 Jul 2018 16:02:06 -0400 Subject: [PATCH 0301/1001] tracing: Fix possible double free in event_enable_trigger_func() commit 15cc78644d0075e76d59476a4467e7143860f660 upstream. There was a case that triggered a double free in event_trigger_callback() due to the called reg() function freeing the trigger_data and then it getting freed again by the error return by the caller. The solution there was to up the trigger_data ref count. Code inspection found that event_enable_trigger_func() has the same issue, but is not as easy to trigger (requires harder to trigger failures). It needs to be solved slightly different as it needs more to clean up when the reg() function fails. Link: http://lkml.kernel.org/r/20180725124008.7008e586@gandalf.local.home Cc: stable@vger.kernel.org Fixes: 7862ad1846e99 ("tracing: Add 'enable_event' and 'disable_event' event trigger commands") Reivewed-by: Masami Hiramatsu Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_events_trigger.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c index d656e32dc853..43254c5e7e16 100644 --- a/kernel/trace/trace_events_trigger.c +++ b/kernel/trace/trace_events_trigger.c @@ -1396,6 +1396,9 @@ int event_enable_trigger_func(struct event_command *cmd_ops, goto out; } + /* Up the trigger_data count to make sure nothing frees it on failure */ + event_trigger_init(trigger_ops, trigger_data); + if (trigger) { number = strsep(&trigger, ":"); @@ -1446,6 +1449,7 @@ int event_enable_trigger_func(struct event_command *cmd_ops, goto out_disable; /* Just return zero, not the number of enabled functions */ ret = 0; + event_trigger_free(trigger_ops, trigger_data); out: return ret; @@ -1456,7 +1460,7 @@ int event_enable_trigger_func(struct event_command *cmd_ops, out_free: if (cmd_ops->set_filter) cmd_ops->set_filter(NULL, trigger_data, NULL); - kfree(trigger_data); + event_trigger_free(trigger_ops, trigger_data); kfree(enable_data); goto out; } -- GitLab From f957456878eb3b5fd8c41412686a76d2cce6c504 Mon Sep 17 00:00:00 2001 From: Snild Dolkow Date: Thu, 26 Jul 2018 09:15:39 +0200 Subject: [PATCH 0302/1001] kthread, tracing: Don't expose half-written comm when creating kthreads commit 3e536e222f2930534c252c1cc7ae799c725c5ff9 upstream. There is a window for racing when printing directly to task->comm, allowing other threads to see a non-terminated string. The vsnprintf function fills the buffer, counts the truncated chars, then finally writes the \0 at the end. creator other vsnprintf: fill (not terminated) count the rest trace_sched_waking(p): ... memcpy(comm, p->comm, TASK_COMM_LEN) write \0 The consequences depend on how 'other' uses the string. In our case, it was copied into the tracing system's saved cmdlines, a buffer of adjacent TASK_COMM_LEN-byte buffers (note the 'n' where 0 should be): crash-arm64> x/1024s savedcmd->saved_cmdlines | grep 'evenk' 0xffffffd5b3818640: "irq/497-pwr_evenkworker/u16:12" ...and a strcpy out of there would cause stack corruption: [224761.522292] Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: ffffff9bf9783c78 crash-arm64> kbt | grep 'comm\|trace_print_context' #6 0xffffff9bf9783c78 in trace_print_context+0x18c(+396) comm (char [16]) = "irq/497-pwr_even" crash-arm64> rd 0xffffffd4d0e17d14 8 ffffffd4d0e17d14: 2f71726900000000 5f7277702d373934 ....irq/497-pwr_ ffffffd4d0e17d24: 726f776b6e657665 3a3631752f72656b evenkworker/u16: ffffffd4d0e17d34: f9780248ff003231 cede60e0ffffff9b 12..H.x......`.. ffffffd4d0e17d44: cede60c8ffffffd4 00000fffffffffd4 .....`.......... The workaround in e09e28671 (use strlcpy in __trace_find_cmdline) was likely needed because of this same bug. Solved by vsnprintf:ing to a local buffer, then using set_task_comm(). This way, there won't be a window where comm is not terminated. Link: http://lkml.kernel.org/r/20180726071539.188015-1-snild@sony.com Cc: stable@vger.kernel.org Fixes: bc0c38d139ec7 ("ftrace: latency tracer infrastructure") Reviewed-by: Steven Rostedt (VMware) Signed-off-by: Snild Dolkow Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/kthread.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kernel/kthread.c b/kernel/kthread.c index 1ef8f3a5b072..4e6d85b63201 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -311,8 +311,14 @@ struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data), task = create->result; if (!IS_ERR(task)) { static const struct sched_param param = { .sched_priority = 0 }; + char name[TASK_COMM_LEN]; - vsnprintf(task->comm, sizeof(task->comm), namefmt, args); + /* + * task is already visible to other tasks, so updating + * COMM must be protected. + */ + vsnprintf(name, sizeof(name), namefmt, args); + set_task_comm(task, name); /* * root may have changed our (kthreadd's) priority or CPU mask. * The kernel thread should not inherit these properties. -- GitLab From 86428ec165ee9c25618794b442827ab78b3da087 Mon Sep 17 00:00:00 2001 From: Artem Savkov Date: Wed, 25 Jul 2018 16:20:38 +0200 Subject: [PATCH 0303/1001] tracing/kprobes: Fix trace_probe flags on enable_trace_kprobe() failure commit 57ea2a34adf40f3a6e88409aafcf803b8945619a upstream. If enable_trace_kprobe fails to enable the probe in enable_k(ret)probe it returns an error, but does not unset the tp flags it set previously. This results in a probe being considered enabled and failures like being unable to remove the probe through kprobe_events file since probes_open() expects every probe to be disabled. Link: http://lkml.kernel.org/r/20180725102826.8300-1-asavkov@redhat.com Link: http://lkml.kernel.org/r/20180725142038.4765-1-asavkov@redhat.com Cc: Ingo Molnar Cc: stable@vger.kernel.org Fixes: 41a7dd420c57 ("tracing/kprobes: Support ftrace_event_file base multibuffer") Acked-by: Masami Hiramatsu Reviewed-by: Josh Poimboeuf Signed-off-by: Artem Savkov Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_kprobe.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index f8d3bd974bcc..474ada34ef26 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -376,11 +376,10 @@ static struct trace_kprobe *find_trace_kprobe(const char *event, static int enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file) { + struct event_file_link *link; int ret = 0; if (file) { - struct event_file_link *link; - link = kmalloc(sizeof(*link), GFP_KERNEL); if (!link) { ret = -ENOMEM; @@ -400,6 +399,16 @@ enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file) else ret = enable_kprobe(&tk->rp.kp); } + + if (ret) { + if (file) { + list_del_rcu(&link->list); + kfree(link); + tk->tp.flags &= ~TP_FLAG_TRACE; + } else { + tk->tp.flags &= ~TP_FLAG_PROFILE; + } + } out: return ret; } -- GitLab From 4681e8820f99aea022801ed94a279d61746b9523 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Wed, 25 Jul 2018 22:28:56 -0400 Subject: [PATCH 0304/1001] tracing: Quiet gcc warning about maybe unused link variable commit 2519c1bbe38d7acacc9aacba303ca6f97482ed53 upstream. Commit 57ea2a34adf4 ("tracing/kprobes: Fix trace_probe flags on enable_trace_kprobe() failure") added an if statement that depends on another if statement that gcc doesn't see will initialize the "link" variable and gives the warning: "warning: 'link' may be used uninitialized in this function" It is really a false positive, but to quiet the warning, and also to make sure that it never actually is used uninitialized, initialize the "link" variable to NULL and add an if (!WARN_ON_ONCE(!link)) where the compiler thinks it could be used uninitialized. Cc: stable@vger.kernel.org Fixes: 57ea2a34adf4 ("tracing/kprobes: Fix trace_probe flags on enable_trace_kprobe() failure") Reported-by: kbuild test robot Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_kprobe.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 474ada34ef26..ea20274a105a 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -376,7 +376,7 @@ static struct trace_kprobe *find_trace_kprobe(const char *event, static int enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file) { - struct event_file_link *link; + struct event_file_link *link = NULL; int ret = 0; if (file) { @@ -402,7 +402,9 @@ enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file) if (ret) { if (file) { - list_del_rcu(&link->list); + /* Notice the if is true on not WARN() */ + if (!WARN_ON_ONCE(!link)) + list_del_rcu(&link->list); kfree(link); tk->tp.flags &= ~TP_FLAG_TRACE; } else { -- GitLab From c1550e0141351e38af1dc781b18e7d2c5ebd42b4 Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Mon, 23 Jul 2018 10:18:23 -0400 Subject: [PATCH 0305/1001] arm64: fix vmemmap BUILD_BUG_ON() triggering on !vmemmap setups commit 7b0eb6b41a08fa1fa0d04b1c53becd62b5fbfaee upstream. Arnd reports the following arm64 randconfig build error with the PSI patches that add another page flag: /git/arm-soc/arch/arm64/mm/init.c: In function 'mem_init': /git/arm-soc/include/linux/compiler.h:357:38: error: call to '__compiletime_assert_618' declared with attribute error: BUILD_BUG_ON failed: sizeof(struct page) > (1 << STRUCT_PAGE_MAX_SHIFT) The additional page flag causes other information stored in page->flags to get bumped into their own struct page member: #if SECTIONS_WIDTH+ZONES_WIDTH+NODES_SHIFT+LAST_CPUPID_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS #define LAST_CPUPID_WIDTH LAST_CPUPID_SHIFT #else #define LAST_CPUPID_WIDTH 0 #endif #if defined(CONFIG_NUMA_BALANCING) && LAST_CPUPID_WIDTH == 0 #define LAST_CPUPID_NOT_IN_PAGE_FLAGS #endif which in turn causes the struct page size to exceed the size set in STRUCT_PAGE_MAX_SHIFT. This value is an an estimate used to size the VMEMMAP page array according to address space and struct page size. However, the check is performed - and triggers here - on a !VMEMMAP config, which consumes an additional 22 page bits for the sparse section id. When VMEMMAP is enabled, those bits are returned, cpupid doesn't need its own member, and the page passes the VMEMMAP check. Restrict that check to the situation it was meant to check: that we are sizing the VMEMMAP page array correctly. Says Arnd: Further experiments show that the build error already existed before, but was only triggered with larger values of CONFIG_NR_CPU and/or CONFIG_NODES_SHIFT that might be used in actual configurations but not in randconfig builds. With longer CPU and node masks, I could recreate the problem with kernels as old as linux-4.7 when arm64 NUMA support got added. Reported-by: Arnd Bergmann Tested-by: Arnd Bergmann Cc: stable@vger.kernel.org Fixes: 1a2db300348b ("arm64, numa: Add NUMA support for arm64 platforms.") Fixes: 3e1907d5bf5a ("arm64: mm: move vmemmap region right below the linear region") Signed-off-by: Johannes Weiner Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman --- arch/arm64/mm/init.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 00e7b900ca41..1190d90e01e6 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -651,11 +651,13 @@ void __init mem_init(void) BUILD_BUG_ON(TASK_SIZE_32 > TASK_SIZE_64); #endif +#ifdef CONFIG_SPARSEMEM_VMEMMAP /* * Make sure we chose the upper bound of sizeof(struct page) - * correctly. + * correctly when sizing the VMEMMAP array. */ BUILD_BUG_ON(sizeof(struct page) > (1 << STRUCT_PAGE_MAX_SHIFT)); +#endif if (PAGE_SIZE >= 16384 && get_num_physpages() <= 128) { extern int sysctl_overcommit_memory; -- GitLab From 73990abb1a04a526c011780e1c06b9c80d613e1a Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 15 Jun 2018 16:23:38 +0300 Subject: [PATCH 0306/1001] mlxsw: spectrum_switchdev: Fix port_vlan refcounting [ Upstream commit 9e25826ffc942e985b8595b2f1cf2065d3880514 ] Switchdev notifications for addition of SWITCHDEV_OBJ_ID_PORT_VLAN are distributed not only on clean addition, but also when flags on an existing VLAN are changed. mlxsw_sp_bridge_port_vlan_add() calls mlxsw_sp_port_vlan_get() to get at the port_vlan in question, which implicitly references the object. This then leads to discrepancies in reference counting when the VLAN is removed. spectrum.c warns about the problem when the module is removed: [13578.493090] WARNING: CPU: 0 PID: 2454 at drivers/net/ethernet/mellanox/mlxsw/spectrum.c:2973 mlxsw_sp_port_remove+0xfd/0x110 [mlxsw_spectrum] [...] [13578.627106] Call Trace: [13578.629617] mlxsw_sp_fini+0x2a/0xe0 [mlxsw_spectrum] [13578.634748] mlxsw_core_bus_device_unregister+0x3e/0x130 [mlxsw_core] [13578.641290] mlxsw_pci_remove+0x13/0x40 [mlxsw_pci] [13578.646238] pci_device_remove+0x31/0xb0 [13578.650244] device_release_driver_internal+0x14f/0x220 [13578.655562] driver_detach+0x32/0x70 [13578.659183] bus_remove_driver+0x47/0xa0 [13578.663134] pci_unregister_driver+0x1e/0x80 [13578.667486] mlxsw_sp_module_exit+0xc/0x3fa [mlxsw_spectrum] [13578.673207] __x64_sys_delete_module+0x13b/0x1e0 [13578.677888] ? exit_to_usermode_loop+0x78/0x80 [13578.682374] do_syscall_64+0x39/0xe0 [13578.685976] entry_SYSCALL_64_after_hwframe+0x44/0xa9 Fix by putting the port_vlan when mlxsw_sp_port_vlan_bridge_join() determines it's a flag-only change. Fixes: b3529af6bb0d ("spectrum: Reference count VLAN entries") Signed-off-by: Petr Machata Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 42a6afcaae03..7924f241e3ad 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -912,8 +912,10 @@ mlxsw_sp_port_vlan_bridge_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, int err; /* No need to continue if only VLAN flags were changed */ - if (mlxsw_sp_port_vlan->bridge_port) + if (mlxsw_sp_port_vlan->bridge_port) { + mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); return 0; + } err = mlxsw_sp_port_vlan_fid_join(mlxsw_sp_port_vlan, bridge_port); if (err) -- GitLab From a45f5ee6850b35b8ecd81e8360b153ae685ecac7 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 14 Jun 2018 15:27:34 -0700 Subject: [PATCH 0307/1001] kcov: ensure irq code sees a valid area [ Upstream commit c9484b986ef03492357fddd50afbdd02929cfa72 ] Patch series "kcov: fix unexpected faults". These patches fix a few issues where KCOV code could trigger recursive faults, discovered while debugging a patch enabling KCOV for arch/arm: * On CONFIG_PREEMPT kernels, there's a small race window where __sanitizer_cov_trace_pc() can see a bogus kcov_area. * Lazy faulting of the vmalloc area can cause mutual recursion between fault handling code and __sanitizer_cov_trace_pc(). * During the context switch, switching the mm can cause the kcov_area to be transiently unmapped. These are prerequisites for enabling KCOV on arm, but the issues themsevles are generic -- we just happen to avoid them by chance rather than design on x86-64 and arm64. This patch (of 3): For kernels built with CONFIG_PREEMPT, some C code may execute before or after the interrupt handler, while the hardirq count is zero. In these cases, in_task() can return true. A task can be interrupted in the middle of a KCOV_DISABLE ioctl while it resets the task's kcov data via kcov_task_init(). Instrumented code executed during this period will call __sanitizer_cov_trace_pc(), and as in_task() returns true, will inspect t->kcov_mode before trying to write to t->kcov_area. In kcov_init_task() we update t->kcov_{mode,area,size} with plain stores, which may be re-ordered, torn, etc. Thus __sanitizer_cov_trace_pc() may see bogus values for any of these fields, and may attempt to write to memory which is not mapped. Let's avoid this by using WRITE_ONCE() to set t->kcov_mode, with a barrier() to ensure this is ordered before we clear t->kov_{area,size}. This ensures that any code execute while kcov_init_task() is preempted will either see valid values for t->kcov_{area,size}, or will see that t->kcov_mode is KCOV_MODE_DISABLED, and bail out without touching t->kcov_area. Link: http://lkml.kernel.org/r/20180504135535.53744-2-mark.rutland@arm.com Signed-off-by: Mark Rutland Acked-by: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Ingo Molnar Cc: Peter Zijlstra Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/kcov.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/kcov.c b/kernel/kcov.c index b11ef6e51f7e..f1e060b04ef6 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -108,7 +108,8 @@ static void kcov_put(struct kcov *kcov) void kcov_task_init(struct task_struct *t) { - t->kcov_mode = KCOV_MODE_DISABLED; + WRITE_ONCE(t->kcov_mode, KCOV_MODE_DISABLED); + barrier(); t->kcov_size = 0; t->kcov_area = NULL; t->kcov = NULL; -- GitLab From 51b694070738e93ef319c464208a7f524b2b5b15 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Tue, 12 Jun 2018 08:57:53 +0200 Subject: [PATCH 0308/1001] xen/netfront: raise max number of slots in xennet_get_responses() [ Upstream commit 57f230ab04d2910a06d17d988f1c4d7586a59113 ] The max number of slots used in xennet_get_responses() is set to MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD). In old kernel-xen MAX_SKB_FRAGS was 18, while nowadays it is 17. This difference is resulting in frequent messages "too many slots" and a reduced network throughput for some workloads (factor 10 below that of a kernel-xen based guest). Replacing MAX_SKB_FRAGS by XEN_NETIF_NR_SLOTS_MIN for calculation of the max number of slots to use solves that problem (tests showed no more messages "too many slots" and throughput was as high as with the kernel-xen based guest system). Replace MAX_SKB_FRAGS-2 by XEN_NETIF_NR_SLOTS_MIN-1 in netfront_tx_slot_available() for making it clearer what is really being tested without actually modifying the tested value. Signed-off-by: Juergen Gross Reviewed-by: Boris Ostrovsky Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/xen-netfront.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index f07b9c9bb5ba..04e0765be5e7 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -239,7 +239,7 @@ static void rx_refill_timeout(unsigned long data) static int netfront_tx_slot_available(struct netfront_queue *queue) { return (queue->tx.req_prod_pvt - queue->tx.rsp_cons) < - (NET_TX_RING_SIZE - MAX_SKB_FRAGS - 2); + (NET_TX_RING_SIZE - XEN_NETIF_NR_SLOTS_MIN - 1); } static void xennet_maybe_wake_tx(struct netfront_queue *queue) @@ -790,7 +790,7 @@ static int xennet_get_responses(struct netfront_queue *queue, RING_IDX cons = queue->rx.rsp_cons; struct sk_buff *skb = xennet_get_rx_skb(queue, cons); grant_ref_t ref = xennet_get_rx_ref(queue, cons); - int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD); + int max = XEN_NETIF_NR_SLOTS_MIN + (rx->status <= RX_COPY_THRESHOLD); int slots = 1; int err = 0; unsigned long ret; -- GitLab From 0a84c912f575c083e2cdc123bcae93e0847f9e63 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 11 Jun 2018 12:44:55 -0700 Subject: [PATCH 0309/1001] hv_netvsc: fix network namespace issues with VF support [ Upstream commit 7bf7bb37f16a80465ee3bd7c6c966f96f5a075a6 ] When finding the parent netvsc device, the search needs to be across all netvsc device instances (independent of network namespace). Find parent device of VF using upper_dev_get routine which searches only adjacent list. Fixes: e8ff40d4bff1 ("hv_netvsc: improve VF device matching") Signed-off-by: Stephen Hemminger netns aware byref Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/hyperv/hyperv_net.h | 2 ++ drivers/net/hyperv/netvsc_drv.c | 43 +++++++++++++++------------------ 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index cb250cacf721..e33a6c672a0a 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -724,6 +724,8 @@ struct net_device_context { struct hv_device *device_ctx; /* netvsc_device */ struct netvsc_device __rcu *nvdev; + /* list of netvsc net_devices */ + struct list_head list; /* reconfigure work */ struct delayed_work dwork; /* last reconfig time */ diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index aeabeb107fed..6a77ef38c549 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -66,6 +66,8 @@ static int debug = -1; module_param(debug, int, S_IRUGO); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); +static LIST_HEAD(netvsc_dev_list); + static void netvsc_change_rx_flags(struct net_device *net, int change) { struct net_device_context *ndev_ctx = netdev_priv(net); @@ -1749,13 +1751,10 @@ static void netvsc_link_change(struct work_struct *w) static struct net_device *get_netvsc_bymac(const u8 *mac) { - struct net_device *dev; - - ASSERT_RTNL(); + struct net_device_context *ndev_ctx; - for_each_netdev(&init_net, dev) { - if (dev->netdev_ops != &device_ops) - continue; /* not a netvsc device */ + list_for_each_entry(ndev_ctx, &netvsc_dev_list, list) { + struct net_device *dev = hv_get_drvdata(ndev_ctx->device_ctx); if (ether_addr_equal(mac, dev->perm_addr)) return dev; @@ -1766,25 +1765,18 @@ static struct net_device *get_netvsc_bymac(const u8 *mac) static struct net_device *get_netvsc_byref(struct net_device *vf_netdev) { + struct net_device_context *net_device_ctx; struct net_device *dev; - ASSERT_RTNL(); - - for_each_netdev(&init_net, dev) { - struct net_device_context *net_device_ctx; + dev = netdev_master_upper_dev_get(vf_netdev); + if (!dev || dev->netdev_ops != &device_ops) + return NULL; /* not a netvsc device */ - if (dev->netdev_ops != &device_ops) - continue; /* not a netvsc device */ + net_device_ctx = netdev_priv(dev); + if (!rtnl_dereference(net_device_ctx->nvdev)) + return NULL; /* device is removed */ - net_device_ctx = netdev_priv(dev); - if (!rtnl_dereference(net_device_ctx->nvdev)) - continue; /* device is removed */ - - if (rtnl_dereference(net_device_ctx->vf_netdev) == vf_netdev) - return dev; /* a match */ - } - - return NULL; + return dev; } /* Called when VF is injecting data into network stack. @@ -2065,15 +2057,19 @@ static int netvsc_probe(struct hv_device *dev, else net->max_mtu = ETH_DATA_LEN; - ret = register_netdev(net); + rtnl_lock(); + ret = register_netdevice(net); if (ret != 0) { pr_err("Unable to register netdev.\n"); goto register_failed; } - return ret; + list_add(&net_device_ctx->list, &netvsc_dev_list); + rtnl_unlock(); + return 0; register_failed: + rtnl_unlock(); rndis_filter_device_remove(dev, nvdev); rndis_failed: free_percpu(net_device_ctx->vf_stats); @@ -2119,6 +2115,7 @@ static int netvsc_remove(struct hv_device *dev) rndis_filter_device_remove(dev, nvdev); unregister_netdevice(net); + list_del(&ndev_ctx->list); rtnl_unlock(); rcu_read_unlock(); -- GitLab From 44a78f7d175792dbd376cbe77ce1abc3f82e5400 Mon Sep 17 00:00:00 2001 From: Olga Kornievskaia Date: Mon, 11 Jun 2018 15:32:06 -0400 Subject: [PATCH 0310/1001] skip LAYOUTRETURN if layout is invalid [ Upstream commit 93b7f7ad2018d2037559b1d0892417864c78b371 ] Currently, when IO to DS fails, client returns the layout and retries against the MDS. However, then on umounting (inode eviction) it returns the layout again. This is because pnfs_return_layout() was changed in commit d78471d32bb6 ("pnfs/blocklayout: set PNFS_LAYOUTRETURN_ON_ERROR") to always set NFS_LAYOUT_RETURN_REQUESTED so even if we returned the layout, it will be returned again. Instead, let's also check if we have already marked the layout invalid. Signed-off-by: Olga Kornievskaia Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/nfs/pnfs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 7b34534210ce..96867fb159bf 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1126,7 +1126,7 @@ _pnfs_return_layout(struct inode *ino) LIST_HEAD(tmp_list); nfs4_stateid stateid; int status = 0; - bool send; + bool send, valid_layout; dprintk("NFS: %s for inode %lu\n", __func__, ino->i_ino); @@ -1147,6 +1147,7 @@ _pnfs_return_layout(struct inode *ino) goto out_put_layout_hdr; spin_lock(&ino->i_lock); } + valid_layout = pnfs_layout_is_valid(lo); pnfs_clear_layoutcommit(ino, &tmp_list); pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL, 0); @@ -1160,7 +1161,8 @@ _pnfs_return_layout(struct inode *ino) } /* Don't send a LAYOUTRETURN if list was initially empty */ - if (!test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags)) { + if (!test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags) || + !valid_layout) { spin_unlock(&ino->i_lock); dprintk("NFS: %s no layout segments to return\n", __func__); goto out_put_layout_hdr; -- GitLab From 40ff9a54dd9b7d587abb398e40147e9237eec5e3 Mon Sep 17 00:00:00 2001 From: Zhouyang Jia Date: Mon, 11 Jun 2018 16:18:40 +0800 Subject: [PATCH 0311/1001] ALSA: emu10k1: add error handling for snd_ctl_add [ Upstream commit 6d531e7b972cb62ded011c2dfcc2d9f72ea6c421 ] When snd_ctl_add fails, the lack of error-handling code may cause unexpected results. This patch adds error-handling code after calling snd_ctl_add. Signed-off-by: Zhouyang Jia Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/pci/emu10k1/emupcm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 2683b9717215..56be1630bd3e 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1850,7 +1850,9 @@ int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device) if (!kctl) return -ENOMEM; kctl->id.device = device; - snd_ctl_add(emu->card, kctl); + err = snd_ctl_add(emu->card, kctl); + if (err < 0) + return err; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); -- GitLab From 42b1df406a296d28f0a86d6a73b4fdca446ae18e Mon Sep 17 00:00:00 2001 From: Zhouyang Jia Date: Mon, 11 Jun 2018 16:04:06 +0800 Subject: [PATCH 0312/1001] ALSA: fm801: add error handling for snd_ctl_add [ Upstream commit ef1ffbe7889e99f5b5cccb41c89e5c94f50f3218 ] When snd_ctl_add fails, the lack of error-handling code may cause unexpected results. This patch adds error-handling code after calling snd_ctl_add. Signed-off-by: Zhouyang Jia Acked-by: Andy Shevchenko Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/pci/fm801.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 73a67bc3586b..e3fb9c61017c 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1068,11 +1068,19 @@ static int snd_fm801_mixer(struct fm801 *chip) if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97_sec)) < 0) return err; } - for (i = 0; i < FM801_CONTROLS; i++) - snd_ctl_add(chip->card, snd_ctl_new1(&snd_fm801_controls[i], chip)); + for (i = 0; i < FM801_CONTROLS; i++) { + err = snd_ctl_add(chip->card, + snd_ctl_new1(&snd_fm801_controls[i], chip)); + if (err < 0) + return err; + } if (chip->multichannel) { - for (i = 0; i < FM801_CONTROLS_MULTI; i++) - snd_ctl_add(chip->card, snd_ctl_new1(&snd_fm801_controls_multi[i], chip)); + for (i = 0; i < FM801_CONTROLS_MULTI; i++) { + err = snd_ctl_add(chip->card, + snd_ctl_new1(&snd_fm801_controls_multi[i], chip)); + if (err < 0) + return err; + } } return 0; } -- GitLab From baad2bf4477003eb27b40a8c608d8af37b187917 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 9 Jun 2018 19:10:31 -0400 Subject: [PATCH 0313/1001] NFSv4.1: Fix the client behaviour on NFS4ERR_SEQ_FALSE_RETRY [ Upstream commit f9312a541050007ec59eb0106273a0a10718cd83 ] If the server returns NFS4ERR_SEQ_FALSE_RETRY or NFS4ERR_RETRY_UNCACHED_REP, then it thinks we're trying to replay an existing request. If so, then let's just bump the sequence ID and retry the operation. Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4proc.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 928bbc397818..df0455cf03af 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -745,6 +745,13 @@ static int nfs41_sequence_process(struct rpc_task *task, slot->slot_nr, slot->seq_nr); goto out_retry; + case -NFS4ERR_RETRY_UNCACHED_REP: + case -NFS4ERR_SEQ_FALSE_RETRY: + /* + * The server thinks we tried to replay a request. + * Retry the call after bumping the sequence ID. + */ + goto retry_new_seq; case -NFS4ERR_BADSLOT: /* * The slot id we used was probably retired. Try again @@ -769,10 +776,6 @@ static int nfs41_sequence_process(struct rpc_task *task, goto retry_nowait; } goto session_recover; - case -NFS4ERR_SEQ_FALSE_RETRY: - if (interrupted) - goto retry_new_seq; - goto session_recover; default: /* Just update the slot sequence no. */ slot->seq_done = 1; -- GitLab From 5a47fe3efd4dba912fce172e1f3e4b823cdf1c9d Mon Sep 17 00:00:00 2001 From: Scott Mayhew Date: Fri, 8 Jun 2018 16:31:46 -0400 Subject: [PATCH 0314/1001] nfsd: fix potential use-after-free in nfsd4_decode_getdeviceinfo [ Upstream commit 3171822fdcdd6e6d536047c425af6dc7a92dc585 ] When running a fuzz tester against a KASAN-enabled kernel, the following splat periodically occurs. The problem occurs when the test sends a GETDEVICEINFO request with a malformed xdr array (size but no data) for gdia_notify_types and the array size is > 0x3fffffff, which results in an overflow in the value of nbytes which is passed to read_buf(). If the array size is 0x40000000, 0x80000000, or 0xc0000000, then after the overflow occurs, the value of nbytes 0, and when that happens the pointer returned by read_buf() points to the end of the xdr data (i.e. argp->end) when really it should be returning NULL. Fix this by returning NFS4ERR_BAD_XDR if the array size is > 1000 (this value is arbitrary, but it's the same threshold used by nfsd4_decode_bitmap()... in could really be any value >= 1 since it's expected to get at most a single bitmap in gdia_notify_types). [ 119.256854] ================================================================== [ 119.257611] BUG: KASAN: use-after-free in nfsd4_decode_getdeviceinfo+0x5a4/0x5b0 [nfsd] [ 119.258422] Read of size 4 at addr ffff880113ada000 by task nfsd/538 [ 119.259146] CPU: 0 PID: 538 Comm: nfsd Not tainted 4.17.0+ #1 [ 119.259662] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.9.3-1.fc25 04/01/2014 [ 119.261202] Call Trace: [ 119.262265] dump_stack+0x71/0xab [ 119.263371] print_address_description+0x6a/0x270 [ 119.264609] kasan_report+0x258/0x380 [ 119.265854] ? nfsd4_decode_getdeviceinfo+0x5a4/0x5b0 [nfsd] [ 119.267291] nfsd4_decode_getdeviceinfo+0x5a4/0x5b0 [nfsd] [ 119.268549] ? nfs4svc_decode_compoundargs+0xa5b/0x13c0 [nfsd] [ 119.269873] ? nfsd4_decode_sequence+0x490/0x490 [nfsd] [ 119.271095] nfs4svc_decode_compoundargs+0xa5b/0x13c0 [nfsd] [ 119.272393] ? nfsd4_release_compoundargs+0x1b0/0x1b0 [nfsd] [ 119.273658] nfsd_dispatch+0x183/0x850 [nfsd] [ 119.274918] svc_process+0x161c/0x31a0 [sunrpc] [ 119.276172] ? svc_printk+0x190/0x190 [sunrpc] [ 119.277386] ? svc_xprt_release+0x451/0x680 [sunrpc] [ 119.278622] nfsd+0x2b9/0x430 [nfsd] [ 119.279771] ? nfsd_destroy+0x1c0/0x1c0 [nfsd] [ 119.281157] kthread+0x2db/0x390 [ 119.282347] ? kthread_create_worker_on_cpu+0xc0/0xc0 [ 119.283756] ret_from_fork+0x35/0x40 [ 119.286041] Allocated by task 436: [ 119.287525] kasan_kmalloc+0xa0/0xd0 [ 119.288685] kmem_cache_alloc+0xe9/0x1f0 [ 119.289900] get_empty_filp+0x7b/0x410 [ 119.291037] path_openat+0xca/0x4220 [ 119.292242] do_filp_open+0x182/0x280 [ 119.293411] do_sys_open+0x216/0x360 [ 119.294555] do_syscall_64+0xa0/0x2f0 [ 119.295721] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 119.298068] Freed by task 436: [ 119.299271] __kasan_slab_free+0x130/0x180 [ 119.300557] kmem_cache_free+0x78/0x210 [ 119.301823] rcu_process_callbacks+0x35b/0xbd0 [ 119.303162] __do_softirq+0x192/0x5ea [ 119.305443] The buggy address belongs to the object at ffff880113ada000 which belongs to the cache filp of size 256 [ 119.308556] The buggy address is located 0 bytes inside of 256-byte region [ffff880113ada000, ffff880113ada100) [ 119.311376] The buggy address belongs to the page: [ 119.312728] page:ffffea00044eb680 count:1 mapcount:0 mapping:0000000000000000 index:0xffff880113ada780 [ 119.314428] flags: 0x17ffe000000100(slab) [ 119.315740] raw: 0017ffe000000100 0000000000000000 ffff880113ada780 00000001000c0001 [ 119.317379] raw: ffffea0004553c60 ffffea00045c11e0 ffff88011b167e00 0000000000000000 [ 119.319050] page dumped because: kasan: bad access detected [ 119.321652] Memory state around the buggy address: [ 119.322993] ffff880113ad9f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 119.324515] ffff880113ad9f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 119.326087] >ffff880113ada000: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 119.327547] ^ [ 119.328730] ffff880113ada080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 119.330218] ffff880113ada100: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb [ 119.331740] ================================================================== Signed-off-by: Scott Mayhew Signed-off-by: J. Bruce Fields Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4xdr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index f6588cc6816c..c1e923334012 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1586,6 +1586,8 @@ nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp, gdev->gd_maxcount = be32_to_cpup(p++); num = be32_to_cpup(p++); if (num) { + if (num > 1000) + goto xdr_error; READ_BUF(4 * num); gdev->gd_notify_types = be32_to_cpup(p++); for (i = 1; i < num; i++) { -- GitLab From ca014df110e97a4765f7e581376b414f26496db7 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 11 Apr 2018 11:15:48 +0200 Subject: [PATCH 0315/1001] vfio: platform: Fix reset module leak in error path [ Upstream commit 28a68387888997e8a7fa57940ea5d55f2e16b594 ] If the IOMMU group setup fails, the reset module is not released. Fixes: b5add544d677d363 ("vfio, platform: make reset driver a requirement by default") Signed-off-by: Geert Uytterhoeven Reviewed-by: Eric Auger Reviewed-by: Simon Horman Acked-by: Eric Auger Signed-off-by: Alex Williamson Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/vfio/platform/vfio_platform_common.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/vfio/platform/vfio_platform_common.c b/drivers/vfio/platform/vfio_platform_common.c index 4c27f4be3c3d..aa9e792110e3 100644 --- a/drivers/vfio/platform/vfio_platform_common.c +++ b/drivers/vfio/platform/vfio_platform_common.c @@ -681,18 +681,23 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev, group = vfio_iommu_group_get(dev); if (!group) { pr_err("VFIO: No IOMMU group for device %s\n", vdev->name); - return -EINVAL; + ret = -EINVAL; + goto put_reset; } ret = vfio_add_group_dev(dev, &vfio_platform_ops, vdev); - if (ret) { - vfio_iommu_group_put(group, dev); - return ret; - } + if (ret) + goto put_iommu; mutex_init(&vdev->igate); return 0; + +put_iommu: + vfio_iommu_group_put(group, dev); +put_reset: + vfio_platform_put_reset(vdev); + return ret; } EXPORT_SYMBOL_GPL(vfio_platform_probe_common); -- GitLab From 8f38152f2ae22b09589a6160086f5d71881ae30b Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 15 May 2018 13:53:55 -0600 Subject: [PATCH 0316/1001] vfio/mdev: Check globally for duplicate devices [ Upstream commit 002fe996f67f4f46d8917b14cfb6e4313c20685a ] When we create an mdev device, we check for duplicates against the parent device and return -EEXIST if found, but the mdev device namespace is global since we'll link all devices from the bus. We do catch this later in sysfs_do_create_link_sd() to return -EEXIST, but with it comes a kernel warning and stack trace for trying to create duplicate sysfs links, which makes it an undesirable response. Therefore we should really be looking for duplicates across all mdev parent devices, or as implemented here, against our mdev device list. Using mdev_list to prevent duplicates means that we can remove mdev_parent.lock, but in order not to serialize mdev device creation and removal globally, we add mdev_device.active which allows UUIDs to be reserved such that we can drop the mdev_list_lock before the mdev device is fully in place. Two behavioral notes; first, mdev_parent.lock had the side-effect of serializing mdev create and remove ops per parent device. This was an implementation detail, not an intentional guarantee provided to the mdev vendor drivers. Vendor drivers can trivially provide this serialization internally if necessary. Second, review comments note the new -EAGAIN behavior when the device, and in particular the remove attribute, becomes visible in sysfs. If a remove is triggered prior to completion of mdev_device_create() the user will see a -EAGAIN error. While the errno is different, receiving an error during this period is not, the previous implementation returned -ENODEV for the same condition. Furthermore, the consistency to the user is improved in the case where mdev_device_remove_ops() returns error. Previously concurrent calls to mdev_device_remove() could see the device disappear with -ENODEV and return in the case of error. Now a user would see -EAGAIN while the device is in this transitory state. Reviewed-by: Kirti Wankhede Reviewed-by: Cornelia Huck Acked-by: Halil Pasic Acked-by: Zhenyu Wang Signed-off-by: Alex Williamson Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- Documentation/vfio-mediated-device.txt | 5 ++ drivers/vfio/mdev/mdev_core.c | 102 +++++++++---------------- drivers/vfio/mdev/mdev_private.h | 2 +- 3 files changed, 42 insertions(+), 67 deletions(-) diff --git a/Documentation/vfio-mediated-device.txt b/Documentation/vfio-mediated-device.txt index 1b3950346532..c3f69bcaf96e 100644 --- a/Documentation/vfio-mediated-device.txt +++ b/Documentation/vfio-mediated-device.txt @@ -145,6 +145,11 @@ The functions in the mdev_parent_ops structure are as follows: * create: allocate basic resources in a driver for a mediated device * remove: free resources in a driver when a mediated device is destroyed +(Note that mdev-core provides no implicit serialization of create/remove +callbacks per mdev parent device, per mdev type, or any other categorization. +Vendor drivers are expected to be fully asynchronous in this respect or +provide their own internal resource protection.) + The callbacks in the mdev_parent_ops structure are as follows: * open: open callback of mediated device diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c index 126991046eb7..0212f0ee8aea 100644 --- a/drivers/vfio/mdev/mdev_core.c +++ b/drivers/vfio/mdev/mdev_core.c @@ -66,34 +66,6 @@ uuid_le mdev_uuid(struct mdev_device *mdev) } EXPORT_SYMBOL(mdev_uuid); -static int _find_mdev_device(struct device *dev, void *data) -{ - struct mdev_device *mdev; - - if (!dev_is_mdev(dev)) - return 0; - - mdev = to_mdev_device(dev); - - if (uuid_le_cmp(mdev->uuid, *(uuid_le *)data) == 0) - return 1; - - return 0; -} - -static bool mdev_device_exist(struct mdev_parent *parent, uuid_le uuid) -{ - struct device *dev; - - dev = device_find_child(parent->dev, &uuid, _find_mdev_device); - if (dev) { - put_device(dev); - return true; - } - - return false; -} - /* Should be called holding parent_list_lock */ static struct mdev_parent *__find_parent_device(struct device *dev) { @@ -221,7 +193,6 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops) } kref_init(&parent->ref); - mutex_init(&parent->lock); parent->dev = dev; parent->ops = ops; @@ -297,6 +268,10 @@ static void mdev_device_release(struct device *dev) { struct mdev_device *mdev = to_mdev_device(dev); + mutex_lock(&mdev_list_lock); + list_del(&mdev->next); + mutex_unlock(&mdev_list_lock); + dev_dbg(&mdev->dev, "MDEV: destroying\n"); kfree(mdev); } @@ -304,7 +279,7 @@ static void mdev_device_release(struct device *dev) int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) { int ret; - struct mdev_device *mdev; + struct mdev_device *mdev, *tmp; struct mdev_parent *parent; struct mdev_type *type = to_mdev_type(kobj); @@ -312,21 +287,28 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) if (!parent) return -EINVAL; - mutex_lock(&parent->lock); + mutex_lock(&mdev_list_lock); /* Check for duplicate */ - if (mdev_device_exist(parent, uuid)) { - ret = -EEXIST; - goto create_err; + list_for_each_entry(tmp, &mdev_list, next) { + if (!uuid_le_cmp(tmp->uuid, uuid)) { + mutex_unlock(&mdev_list_lock); + ret = -EEXIST; + goto mdev_fail; + } } mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); if (!mdev) { + mutex_unlock(&mdev_list_lock); ret = -ENOMEM; - goto create_err; + goto mdev_fail; } memcpy(&mdev->uuid, &uuid, sizeof(uuid_le)); + list_add(&mdev->next, &mdev_list); + mutex_unlock(&mdev_list_lock); + mdev->parent = parent; kref_init(&mdev->ref); @@ -338,35 +320,28 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) ret = device_register(&mdev->dev); if (ret) { put_device(&mdev->dev); - goto create_err; + goto mdev_fail; } ret = mdev_device_create_ops(kobj, mdev); if (ret) - goto create_failed; + goto create_fail; ret = mdev_create_sysfs_files(&mdev->dev, type); if (ret) { mdev_device_remove_ops(mdev, true); - goto create_failed; + goto create_fail; } mdev->type_kobj = kobj; + mdev->active = true; dev_dbg(&mdev->dev, "MDEV: created\n"); - mutex_unlock(&parent->lock); - - mutex_lock(&mdev_list_lock); - list_add(&mdev->next, &mdev_list); - mutex_unlock(&mdev_list_lock); - - return ret; + return 0; -create_failed: +create_fail: device_unregister(&mdev->dev); - -create_err: - mutex_unlock(&parent->lock); +mdev_fail: mdev_put_parent(parent); return ret; } @@ -377,44 +352,39 @@ int mdev_device_remove(struct device *dev, bool force_remove) struct mdev_parent *parent; struct mdev_type *type; int ret; - bool found = false; mdev = to_mdev_device(dev); mutex_lock(&mdev_list_lock); list_for_each_entry(tmp, &mdev_list, next) { - if (tmp == mdev) { - found = true; + if (tmp == mdev) break; - } } - if (found) - list_del(&mdev->next); + if (tmp != mdev) { + mutex_unlock(&mdev_list_lock); + return -ENODEV; + } - mutex_unlock(&mdev_list_lock); + if (!mdev->active) { + mutex_unlock(&mdev_list_lock); + return -EAGAIN; + } - if (!found) - return -ENODEV; + mdev->active = false; + mutex_unlock(&mdev_list_lock); type = to_mdev_type(mdev->type_kobj); parent = mdev->parent; - mutex_lock(&parent->lock); ret = mdev_device_remove_ops(mdev, force_remove); if (ret) { - mutex_unlock(&parent->lock); - - mutex_lock(&mdev_list_lock); - list_add(&mdev->next, &mdev_list); - mutex_unlock(&mdev_list_lock); - + mdev->active = true; return ret; } mdev_remove_sysfs_files(dev, type); device_unregister(dev); - mutex_unlock(&parent->lock); mdev_put_parent(parent); return 0; diff --git a/drivers/vfio/mdev/mdev_private.h b/drivers/vfio/mdev/mdev_private.h index a9cefd70a705..b5819b7d7ef7 100644 --- a/drivers/vfio/mdev/mdev_private.h +++ b/drivers/vfio/mdev/mdev_private.h @@ -20,7 +20,6 @@ struct mdev_parent { struct device *dev; const struct mdev_parent_ops *ops; struct kref ref; - struct mutex lock; struct list_head next; struct kset *mdev_types_kset; struct list_head type_list; @@ -34,6 +33,7 @@ struct mdev_device { struct kref ref; struct list_head next; struct kobject *type_kobj; + bool active; }; #define to_mdev_device(dev) container_of(dev, struct mdev_device, dev) -- GitLab From 827faa4eb5668e25baf7f3752dc7ae7fd46894c2 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 11 May 2018 09:05:02 -0600 Subject: [PATCH 0317/1001] vfio/type1: Fix task tracking for QEMU vCPU hotplug [ Upstream commit 48d8476b41eed63567dd2f0ad125c895b9ac648a ] MAP_DMA ioctls might be called from various threads within a process, for example when using QEMU, the vCPU threads are often generating these calls and we therefore take a reference to that vCPU task. However, QEMU also supports vCPU hotplug on some machines and the task that called MAP_DMA may have exited by the time UNMAP_DMA is called, resulting in the mm_struct pointer being NULL and thus a failure to match against the existing mapping. To resolve this, we instead take a reference to the thread group_leader, which has the same mm_struct and resource limits, but is less likely exit, at least in the QEMU case. A difficulty here is guaranteeing that the capabilities of the group_leader match that of the calling thread, which we resolve by tracking CAP_IPC_LOCK at the time of calling rather than at an indeterminate time in the future. Potentially this also results in better efficiency as this is now recorded once per MAP_DMA ioctl. Reported-by: Xu Yandong Signed-off-by: Alex Williamson Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/vfio/vfio_iommu_type1.c | 73 +++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index d639378e36ac..50eeb74ddc0a 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -83,6 +83,7 @@ struct vfio_dma { size_t size; /* Map size (bytes) */ int prot; /* IOMMU_READ/WRITE */ bool iommu_mapped; + bool lock_cap; /* capable(CAP_IPC_LOCK) */ struct task_struct *task; struct rb_root pfn_list; /* Ex-user pinned pfn list */ }; @@ -246,29 +247,25 @@ static int vfio_iova_put_vfio_pfn(struct vfio_dma *dma, struct vfio_pfn *vpfn) return ret; } -static int vfio_lock_acct(struct task_struct *task, long npage, bool *lock_cap) +static int vfio_lock_acct(struct vfio_dma *dma, long npage, bool async) { struct mm_struct *mm; - bool is_current; int ret; if (!npage) return 0; - is_current = (task->mm == current->mm); - - mm = is_current ? task->mm : get_task_mm(task); + mm = async ? get_task_mm(dma->task) : dma->task->mm; if (!mm) return -ESRCH; /* process exited */ ret = down_write_killable(&mm->mmap_sem); if (!ret) { if (npage > 0) { - if (lock_cap ? !*lock_cap : - !has_capability(task, CAP_IPC_LOCK)) { + if (!dma->lock_cap) { unsigned long limit; - limit = task_rlimit(task, + limit = task_rlimit(dma->task, RLIMIT_MEMLOCK) >> PAGE_SHIFT; if (mm->locked_vm + npage > limit) @@ -282,7 +279,7 @@ static int vfio_lock_acct(struct task_struct *task, long npage, bool *lock_cap) up_write(&mm->mmap_sem); } - if (!is_current) + if (async) mmput(mm); return ret; @@ -391,7 +388,7 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, */ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, long npage, unsigned long *pfn_base, - bool lock_cap, unsigned long limit) + unsigned long limit) { unsigned long pfn = 0; long ret, pinned = 0, lock_acct = 0; @@ -414,7 +411,7 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, * pages are already counted against the user. */ if (!rsvd && !vfio_find_vpfn(dma, iova)) { - if (!lock_cap && current->mm->locked_vm + 1 > limit) { + if (!dma->lock_cap && current->mm->locked_vm + 1 > limit) { put_pfn(*pfn_base, dma->prot); pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__, limit << PAGE_SHIFT); @@ -440,7 +437,7 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, } if (!rsvd && !vfio_find_vpfn(dma, iova)) { - if (!lock_cap && + if (!dma->lock_cap && current->mm->locked_vm + lock_acct + 1 > limit) { put_pfn(pfn, dma->prot); pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", @@ -453,7 +450,7 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, } out: - ret = vfio_lock_acct(current, lock_acct, &lock_cap); + ret = vfio_lock_acct(dma, lock_acct, false); unpin_out: if (ret) { @@ -484,7 +481,7 @@ static long vfio_unpin_pages_remote(struct vfio_dma *dma, dma_addr_t iova, } if (do_accounting) - vfio_lock_acct(dma->task, locked - unlocked, NULL); + vfio_lock_acct(dma, locked - unlocked, true); return unlocked; } @@ -501,7 +498,7 @@ static int vfio_pin_page_external(struct vfio_dma *dma, unsigned long vaddr, ret = vaddr_get_pfn(mm, vaddr, dma->prot, pfn_base); if (!ret && do_accounting && !is_invalid_reserved_pfn(*pfn_base)) { - ret = vfio_lock_acct(dma->task, 1, NULL); + ret = vfio_lock_acct(dma, 1, true); if (ret) { put_pfn(*pfn_base, dma->prot); if (ret == -ENOMEM) @@ -528,7 +525,7 @@ static int vfio_unpin_page_external(struct vfio_dma *dma, dma_addr_t iova, unlocked = vfio_iova_put_vfio_pfn(dma, vpfn); if (do_accounting) - vfio_lock_acct(dma->task, -unlocked, NULL); + vfio_lock_acct(dma, -unlocked, true); return unlocked; } @@ -723,7 +720,7 @@ static long vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma, dma->iommu_mapped = false; if (do_accounting) { - vfio_lock_acct(dma->task, -unlocked, NULL); + vfio_lock_acct(dma, -unlocked, true); return 0; } return unlocked; @@ -935,14 +932,12 @@ static int vfio_pin_map_dma(struct vfio_iommu *iommu, struct vfio_dma *dma, size_t size = map_size; long npage; unsigned long pfn, limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; - bool lock_cap = capable(CAP_IPC_LOCK); int ret = 0; while (size) { /* Pin a contiguous chunk of memory */ npage = vfio_pin_pages_remote(dma, vaddr + dma->size, - size >> PAGE_SHIFT, &pfn, - lock_cap, limit); + size >> PAGE_SHIFT, &pfn, limit); if (npage <= 0) { WARN_ON(!npage); ret = (int)npage; @@ -1017,8 +1012,36 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, dma->iova = iova; dma->vaddr = vaddr; dma->prot = prot; - get_task_struct(current); - dma->task = current; + + /* + * We need to be able to both add to a task's locked memory and test + * against the locked memory limit and we need to be able to do both + * outside of this call path as pinning can be asynchronous via the + * external interfaces for mdev devices. RLIMIT_MEMLOCK requires a + * task_struct and VM locked pages requires an mm_struct, however + * holding an indefinite mm reference is not recommended, therefore we + * only hold a reference to a task. We could hold a reference to + * current, however QEMU uses this call path through vCPU threads, + * which can be killed resulting in a NULL mm and failure in the unmap + * path when called via a different thread. Avoid this problem by + * using the group_leader as threads within the same group require + * both CLONE_THREAD and CLONE_VM and will therefore use the same + * mm_struct. + * + * Previously we also used the task for testing CAP_IPC_LOCK at the + * time of pinning and accounting, however has_capability() makes use + * of real_cred, a copy-on-write field, so we can't guarantee that it + * matches group_leader, or in fact that it might not change by the + * time it's evaluated. If a process were to call MAP_DMA with + * CAP_IPC_LOCK but later drop it, it doesn't make sense that they + * possibly see different results for an iommu_mapped vfio_dma vs + * externally mapped. Therefore track CAP_IPC_LOCK in vfio_dma at the + * time of calling MAP_DMA. + */ + get_task_struct(current->group_leader); + dma->task = current->group_leader; + dma->lock_cap = capable(CAP_IPC_LOCK); + dma->pfn_list = RB_ROOT; /* Insert zero-sized and grow as we map chunks of it */ @@ -1053,7 +1076,6 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu, struct vfio_domain *d; struct rb_node *n; unsigned long limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; - bool lock_cap = capable(CAP_IPC_LOCK); int ret; /* Arbitrarily pick the first domain in the list for lookups */ @@ -1100,8 +1122,7 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu, npage = vfio_pin_pages_remote(dma, vaddr, n >> PAGE_SHIFT, - &pfn, lock_cap, - limit); + &pfn, limit); if (npage <= 0) { WARN_ON(!npage); ret = (int)npage; @@ -1378,7 +1399,7 @@ static void vfio_iommu_unmap_unpin_reaccount(struct vfio_iommu *iommu) if (!is_invalid_reserved_pfn(vpfn->pfn)) locked++; } - vfio_lock_acct(dma->task, locked - unlocked, NULL); + vfio_lock_acct(dma, locked - unlocked, true); } } -- GitLab From 9691035cbf723c8ce7247eb5889d03b658871492 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Thu, 7 Jun 2018 17:10:34 -0700 Subject: [PATCH 0318/1001] kernel/hung_task.c: show all hung tasks before panic [ Upstream commit 401c636a0eeb0d51862fce222da1bf08e3a0ffd0 ] When we get a hung task it can often be valuable to see _all_ the hung tasks on the system before calling panic(). Quoting from https://syzkaller.appspot.com/text?tag=CrashReport&id=5316056503549952 ---------------------------------------- INFO: task syz-executor0:6540 blocked for more than 120 seconds. Not tainted 4.16.0+ #13 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. syz-executor0 D23560 6540 4521 0x80000004 Call Trace: context_switch kernel/sched/core.c:2848 [inline] __schedule+0x8fb/0x1ef0 kernel/sched/core.c:3490 schedule+0xf5/0x430 kernel/sched/core.c:3549 schedule_preempt_disabled+0x10/0x20 kernel/sched/core.c:3607 __mutex_lock_common kernel/locking/mutex.c:833 [inline] __mutex_lock+0xb7f/0x1810 kernel/locking/mutex.c:893 mutex_lock_nested+0x16/0x20 kernel/locking/mutex.c:908 lo_ioctl+0x8b/0x1b70 drivers/block/loop.c:1355 __blkdev_driver_ioctl block/ioctl.c:303 [inline] blkdev_ioctl+0x1759/0x1e00 block/ioctl.c:601 ioctl_by_bdev+0xa5/0x110 fs/block_dev.c:2060 isofs_get_last_session fs/isofs/inode.c:567 [inline] isofs_fill_super+0x2ba9/0x3bc0 fs/isofs/inode.c:660 mount_bdev+0x2b7/0x370 fs/super.c:1119 isofs_mount+0x34/0x40 fs/isofs/inode.c:1560 mount_fs+0x66/0x2d0 fs/super.c:1222 vfs_kern_mount.part.26+0xc6/0x4a0 fs/namespace.c:1037 vfs_kern_mount fs/namespace.c:2514 [inline] do_new_mount fs/namespace.c:2517 [inline] do_mount+0xea4/0x2b90 fs/namespace.c:2847 ksys_mount+0xab/0x120 fs/namespace.c:3063 SYSC_mount fs/namespace.c:3077 [inline] SyS_mount+0x39/0x50 fs/namespace.c:3074 do_syscall_64+0x281/0x940 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 (...snipped...) Showing all locks held in the system: (...snipped...) 2 locks held by syz-executor0/6540: #0: 00000000566d4c39 (&type->s_umount_key#49/1){+.+.}, at: alloc_super fs/super.c:211 [inline] #0: 00000000566d4c39 (&type->s_umount_key#49/1){+.+.}, at: sget_userns+0x3b2/0xe60 fs/super.c:502 /* down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING); */ #1: 0000000043ca8836 (&lo->lo_ctl_mutex/1){+.+.}, at: lo_ioctl+0x8b/0x1b70 drivers/block/loop.c:1355 /* mutex_lock_nested(&lo->lo_ctl_mutex, 1); */ (...snipped...) 3 locks held by syz-executor7/6541: #0: 0000000043ca8836 (&lo->lo_ctl_mutex/1){+.+.}, at: lo_ioctl+0x8b/0x1b70 drivers/block/loop.c:1355 /* mutex_lock_nested(&lo->lo_ctl_mutex, 1); */ #1: 000000007bf3d3f9 (&bdev->bd_mutex){+.+.}, at: blkdev_reread_part+0x1e/0x40 block/ioctl.c:192 #2: 00000000566d4c39 (&type->s_umount_key#50){.+.+}, at: __get_super.part.10+0x1d3/0x280 fs/super.c:663 /* down_read(&sb->s_umount); */ ---------------------------------------- When reporting an AB-BA deadlock like shown above, it would be nice if trace of PID=6541 is printed as well as trace of PID=6540 before calling panic(). Showing hung tasks up to /proc/sys/kernel/hung_task_warnings could delay calling panic() but normally there should not be so many hung tasks. Link: http://lkml.kernel.org/r/201804050705.BHE57833.HVFOFtSOMQJFOL@I-love.SAKURA.ne.jp Signed-off-by: Tetsuo Handa Acked-by: Paul E. McKenney Acked-by: Dmitry Vyukov Cc: Vegard Nossum Cc: Mandeep Singh Baines Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/hung_task.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/kernel/hung_task.c b/kernel/hung_task.c index 751593ed7c0b..32b479468e4d 100644 --- a/kernel/hung_task.c +++ b/kernel/hung_task.c @@ -44,6 +44,7 @@ int __read_mostly sysctl_hung_task_warnings = 10; static int __read_mostly did_panic; static bool hung_task_show_lock; +static bool hung_task_call_panic; static struct task_struct *watchdog_task; @@ -127,10 +128,8 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout) touch_nmi_watchdog(); if (sysctl_hung_task_panic) { - if (hung_task_show_lock) - debug_show_all_locks(); - trigger_all_cpu_backtrace(); - panic("hung_task: blocked tasks"); + hung_task_show_lock = true; + hung_task_call_panic = true; } } @@ -193,6 +192,10 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) rcu_read_unlock(); if (hung_task_show_lock) debug_show_all_locks(); + if (hung_task_call_panic) { + trigger_all_cpu_backtrace(); + panic("hung_task: blocked tasks"); + } } static long hung_timeout_jiffies(unsigned long last_checked, -- GitLab From 9e1a1fc0cd9be4d82bd9e0c1f8618c4e13ee2530 Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Thu, 7 Jun 2018 17:07:39 -0700 Subject: [PATCH 0319/1001] mm: /proc/pid/pagemap: hide swap entries from unprivileged users [ Upstream commit ab6ecf247a9321e3180e021a6a60164dee53ab2e ] In commit ab676b7d6fbf ("pagemap: do not leak physical addresses to non-privileged userspace"), the /proc/PID/pagemap is restricted to be readable only by CAP_SYS_ADMIN to address some security issue. In commit 1c90308e7a77 ("pagemap: hide physical addresses from non-privileged users"), the restriction is relieved to make /proc/PID/pagemap readable, but hide the physical addresses for non-privileged users. But the swap entries are readable for non-privileged users too. This has some security issues. For example, for page under migrating, the swap entry has physical address information. So, in this patch, the swap entries are hided for non-privileged users too. Link: http://lkml.kernel.org/r/20180508012745.7238-1-ying.huang@intel.com Fixes: 1c90308e7a77 ("pagemap: hide physical addresses from non-privileged users") Signed-off-by: "Huang, Ying" Suggested-by: Kirill A. Shutemov Reviewed-by: Naoya Horiguchi Reviewed-by: Konstantin Khlebnikov Acked-by: Michal Hocko Cc: Konstantin Khlebnikov Cc: Andrei Vagin Cc: Jerome Glisse Cc: Daniel Colascione Cc: Zi Yan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/proc/task_mmu.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 6f337fff38c4..519522d39bde 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -1275,8 +1275,9 @@ static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm, if (pte_swp_soft_dirty(pte)) flags |= PM_SOFT_DIRTY; entry = pte_to_swp_entry(pte); - frame = swp_type(entry) | - (swp_offset(entry) << MAX_SWAPFILES_SHIFT); + if (pm->show_pfn) + frame = swp_type(entry) | + (swp_offset(entry) << MAX_SWAPFILES_SHIFT); flags |= PM_SWAP; if (is_migration_entry(entry)) page = migration_entry_to_page(entry); @@ -1327,11 +1328,14 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end, #ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION else if (is_swap_pmd(pmd)) { swp_entry_t entry = pmd_to_swp_entry(pmd); - unsigned long offset = swp_offset(entry); + unsigned long offset; - offset += (addr & ~PMD_MASK) >> PAGE_SHIFT; - frame = swp_type(entry) | - (offset << MAX_SWAPFILES_SHIFT); + if (pm->show_pfn) { + offset = swp_offset(entry) + + ((addr & ~PMD_MASK) >> PAGE_SHIFT); + frame = swp_type(entry) | + (offset << MAX_SWAPFILES_SHIFT); + } flags |= PM_SWAP; if (pmd_swp_soft_dirty(pmd)) flags |= PM_SOFT_DIRTY; @@ -1349,10 +1353,12 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end, err = add_to_pagemap(addr, &pme, pm); if (err) break; - if (pm->show_pfn && (flags & PM_PRESENT)) - frame++; - else if (flags & PM_SWAP) - frame += (1 << MAX_SWAPFILES_SHIFT); + if (pm->show_pfn) { + if (flags & PM_PRESENT) + frame++; + else if (flags & PM_SWAP) + frame += (1 << MAX_SWAPFILES_SHIFT); + } } spin_unlock(ptl); return err; -- GitLab From b9d1724cf618cea52e268a61b28096d8b3a422e4 Mon Sep 17 00:00:00 2001 From: Chintan Pandya Date: Thu, 7 Jun 2018 17:06:50 -0700 Subject: [PATCH 0320/1001] mm: vmalloc: avoid racy handling of debugobjects in vunmap [ Upstream commit f3c01d2f3ade6790db67f80fef60df84424f8964 ] Currently, __vunmap flow is, 1) Release the VM area 2) Free the debug objects corresponding to that vm area. This leave some race window open. 1) Release the VM area 1.5) Some other client gets the same vm area 1.6) This client allocates new debug objects on the same vm area 2) Free the debug objects corresponding to this vm area. Here, we actually free 'other' client's debug objects. Fix this by freeing the debug objects first and then releasing the VM area. Link: http://lkml.kernel.org/r/1523961828-9485-2-git-send-email-cpandya@codeaurora.org Signed-off-by: Chintan Pandya Reviewed-by: Andrew Morton Cc: Ard Biesheuvel Cc: Byungchul Park Cc: Catalin Marinas Cc: Florian Fainelli Cc: Johannes Weiner Cc: Laura Abbott Cc: Vlastimil Babka Cc: Wei Yang Cc: Yisheng Xie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- mm/vmalloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/vmalloc.c b/mm/vmalloc.c index ebff729cc956..9ff21a12ea00 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -1519,7 +1519,7 @@ static void __vunmap(const void *addr, int deallocate_pages) addr)) return; - area = remove_vm_area(addr); + area = find_vmap_area((unsigned long)addr)->vm; if (unlikely(!area)) { WARN(1, KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n", addr); @@ -1529,6 +1529,7 @@ static void __vunmap(const void *addr, int deallocate_pages) debug_check_no_locks_freed(addr, get_vm_area_size(area)); debug_check_no_obj_freed(addr, get_vm_area_size(area)); + remove_vm_area(addr); if (deallocate_pages) { int i; -- GitLab From 191d00f8c8726320814ad4796c1818432edacb2c Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Thu, 7 Jun 2018 17:05:17 -0700 Subject: [PATCH 0321/1001] mm/slub.c: add __printf verification to slab_err() [ Upstream commit a38965bf941b7c2af50de09c96bc5f03e136caef ] __printf is useful to verify format and arguments. Remove the following warning (with W=1): mm/slub.c:721:2: warning: function might be possible candidate for `gnu_printf' format attribute [-Wsuggest-attribute=format] Link: http://lkml.kernel.org/r/20180505200706.19986-1-malat@debian.org Signed-off-by: Mathieu Malaterre Reviewed-by: Andrew Morton Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- mm/slub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/slub.c b/mm/slub.c index c38e71cea6d3..10e54c4acd19 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -708,7 +708,7 @@ void object_err(struct kmem_cache *s, struct page *page, print_trailer(s, page, object); } -static void slab_err(struct kmem_cache *s, struct page *page, +static __printf(3, 4) void slab_err(struct kmem_cache *s, struct page *page, const char *fmt, ...) { va_list args; -- GitLab From 6a929b97b7770573728611551568a4399e3c2da7 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 5 Jun 2018 23:09:14 +0200 Subject: [PATCH 0322/1001] rtc: ensure rtc_set_alarm fails when alarms are not supported [ Upstream commit abfdff44bc38e9e2ef7929f633fb8462632299d4 ] When using RTC_ALM_SET or RTC_WKALM_SET with rtc_wkalrm.enabled not set, rtc_timer_enqueue() is not called and rtc_set_alarm() may succeed but the subsequent RTC_AIE_ON ioctl will fail. RTC_ALM_READ would also fail in that case. Ensure rtc_set_alarm() fails when alarms are not supported to avoid letting programs think the alarms are working for a particular RTC when they are not. Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/interface.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 9eb32ead63db..e4f951e968a4 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -359,6 +359,11 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { int err; + if (!rtc->ops) + return -ENODEV; + else if (!rtc->ops->set_alarm) + return -EINVAL; + err = rtc_valid_tm(&alarm->time); if (err != 0) return err; -- GitLab From a47ece2b17c2e28524f8434857e0deab72ada33e Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 5 Jun 2018 14:14:16 +0200 Subject: [PATCH 0323/1001] perf tools: Fix pmu events parsing rule [ Upstream commit ceac7b79df7bd67ef9aaf464b0179a2686aff4ee ] Currently all the event parsing fails end up in the event_pmu rule, and display misleading help like: $ perf stat -e inst kill event syntax error: 'inst' \___ Cannot find PMU `inst'. Missing kernel support? ... The reason is that the event_pmu is too strong and match also single string. Changing it to force the '/' separators to be part of the rule, and getting the proper error now: $ perf stat -e inst kill event syntax error: 'inst' \___ parser error Run 'perf list' for a list of valid events ... Suggested-by: Adrian Hunter Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20180605121416.31645-1-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/parse-events.y | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index e81a20ea8d7d..988310cd3049 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -72,6 +72,7 @@ static void inc_group_count(struct list_head *list, %type value_sym %type event_config %type opt_event_config +%type opt_pmu_config %type event_term %type event_pmu %type event_legacy_symbol @@ -223,7 +224,7 @@ event_def: event_pmu | event_bpf_file event_pmu: -PE_NAME opt_event_config +PE_NAME opt_pmu_config { struct list_head *list, *orig_terms, *terms; @@ -486,6 +487,17 @@ opt_event_config: $$ = NULL; } +opt_pmu_config: +'/' event_config '/' +{ + $$ = $2; +} +| +'/' '/' +{ + $$ = NULL; +} + start_terms: event_config { struct parse_events_state *parse_state = _parse_state; -- GitLab From 52f072f580e4e5acfc65e40273e1cd4b544fbe63 Mon Sep 17 00:00:00 2001 From: Florent Fourcot Date: Mon, 4 Jun 2018 16:51:19 +0200 Subject: [PATCH 0324/1001] netfilter: ipset: forbid family for hash:mac sets [ Upstream commit cbdebe481a14b42c45aa9f4ceb5ff19b55de2c57 ] Userspace `ipset` command forbids family option for hash:mac type: ipset create test hash:mac family inet4 ipset v6.30: Unknown argument: `family' However, this check is not done in kernel itself. When someone use external netlink applications (pyroute2 python library for example), one can create hash:mac with invalid family and inconsistant results from userspace (`ipset` command cannot read set content anymore). This patch enforce the logic in kernel, and forbids insertion of hash:mac with a family set. Since IP_SET_PROTO_UNDEF is defined only for hash:mac, this patch has no impact on other hash:* sets Signed-off-by: Florent Fourcot Signed-off-by: Victorien Molle Signed-off-by: Jozsef Kadlecsik Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/netfilter/ipset/ip_set_hash_gen.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h index 51063d9ed0f7..dfd268166e42 100644 --- a/net/netfilter/ipset/ip_set_hash_gen.h +++ b/net/netfilter/ipset/ip_set_hash_gen.h @@ -1241,7 +1241,10 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set, pr_debug("Create set %s with family %s\n", set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6"); -#ifndef IP_SET_PROTO_UNDEF +#ifdef IP_SET_PROTO_UNDEF + if (set->family != NFPROTO_UNSPEC) + return -IPSET_ERR_INVALID_FAMILY; +#else if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) return -IPSET_ERR_INVALID_FAMILY; #endif -- GitLab From ff60eda504531b7730435f1730c8bf068a209221 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Thu, 31 May 2018 18:45:21 +0200 Subject: [PATCH 0325/1001] netfilter: ipset: List timing out entries with "timeout 1" instead of zero [ Upstream commit bd975e691486ba52790ba23cc9b4fecab7bc0d31 ] When listing sets with timeout support, there's a probability that just timing out entries with "0" timeout value is listed/saved. However when restoring the saved list, the zero timeout value means permanent elelements. The new behaviour is that timing out entries are listed with "timeout 1" instead of zero. Fixes netfilter bugzilla #1258. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/linux/netfilter/ipset/ip_set_timeout.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/linux/netfilter/ipset/ip_set_timeout.h b/include/linux/netfilter/ipset/ip_set_timeout.h index bfb3531fd88a..7ad8ddf9ca8a 100644 --- a/include/linux/netfilter/ipset/ip_set_timeout.h +++ b/include/linux/netfilter/ipset/ip_set_timeout.h @@ -65,8 +65,14 @@ ip_set_timeout_set(unsigned long *timeout, u32 value) static inline u32 ip_set_timeout_get(const unsigned long *timeout) { - return *timeout == IPSET_ELEM_PERMANENT ? 0 : - jiffies_to_msecs(*timeout - jiffies)/MSEC_PER_SEC; + u32 t; + + if (*timeout == IPSET_ELEM_PERMANENT) + return 0; + + t = jiffies_to_msecs(*timeout - jiffies)/MSEC_PER_SEC; + /* Zero value in userspace means no timeout */ + return t == 0 ? 1 : t; } #endif /* __KERNEL__ */ -- GitLab From d90c9b07cb325b5190f5a45ddcf66aa09ed5f552 Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Tue, 5 Jun 2018 15:27:27 +0300 Subject: [PATCH 0326/1001] irqchip/ls-scfg-msi: Map MSIs in the iommu [ Upstream commit 0cdd431c337e99177e68597f3de34bedd3a20a74 ] Add the required iommu_dma_map_msi_msg() when composing the MSI message, otherwise the interrupts will not work. Signed-off-by: Laurentiu Tudor Signed-off-by: Thomas Gleixner Cc: jason@lakedaemon.net Cc: marc.zyngier@arm.com Cc: zhiqiang.hou@nxp.com Cc: minghuan.lian@nxp.com Link: https://lkml.kernel.org/r/20180605122727.12831-1-laurentiu.tudor@nxp.com Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/irqchip/irq-ls-scfg-msi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c index 119f4ef0d421..b7f943f96068 100644 --- a/drivers/irqchip/irq-ls-scfg-msi.c +++ b/drivers/irqchip/irq-ls-scfg-msi.c @@ -21,6 +21,7 @@ #include #include #include +#include #define MSI_IRQS_PER_MSIR 32 #define MSI_MSIR_OFFSET 4 @@ -94,6 +95,8 @@ static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg) if (msi_affinity_flag) msg->data |= cpumask_first(data->common->affinity); + + iommu_dma_map_msi_msg(data->irq, msg); } static int ls_scfg_msi_set_affinity(struct irq_data *irq_data, -- GitLab From 2f6a38b131abcb447e32cf5abaac12b6d5e9131d Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Mon, 28 May 2018 08:45:45 +0200 Subject: [PATCH 0327/1001] watchdog: da9063: Fix updating timeout value [ Upstream commit 44ee54aabfdb3b35866ed909bde3ab01e9679385 ] The DA9063 watchdog has only one register field to store the timeout value and to enable the watchdog. The watchdog gets enabled if the value is not zero. There is no issue if the watchdog is already running but it leads into problems if the watchdog is disabled. If the watchdog is disabled and only the timeout value should be prepared the watchdog gets enabled too. Add a check to get the current watchdog state and update the watchdog timeout value on hw-side only if the watchdog is already active. Fixes: 5e9c16e37608 ("watchdog: Add DA9063 PMIC watchdog driver.") Signed-off-by: Marco Felsch Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/watchdog/da9063_wdt.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/da9063_wdt.c b/drivers/watchdog/da9063_wdt.c index 2a20fc163ed0..4c62ad74aec0 100644 --- a/drivers/watchdog/da9063_wdt.c +++ b/drivers/watchdog/da9063_wdt.c @@ -102,10 +102,23 @@ static int da9063_wdt_set_timeout(struct watchdog_device *wdd, { struct da9063 *da9063 = watchdog_get_drvdata(wdd); unsigned int selector; - int ret; + int ret = 0; selector = da9063_wdt_timeout_to_sel(timeout); - ret = _da9063_wdt_set_timeout(da9063, selector); + + /* + * There are two cases when a set_timeout() will be called: + * 1. The watchdog is off and someone wants to set the timeout for the + * further use. + * 2. The watchdog is already running and a new timeout value should be + * set. + * + * The watchdog can't store a timeout value not equal zero without + * enabling the watchdog, so the timeout must be buffered by the driver. + */ + if (watchdog_active(wdd)) + ret = _da9063_wdt_set_timeout(da9063, selector); + if (ret) dev_err(da9063->dev, "Failed to set watchdog timeout (err = %d)\n", ret); -- GitLab From 8dcf2dbf65efd17512db17526909de05daa0cff2 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Wed, 30 May 2018 16:03:50 +0900 Subject: [PATCH 0328/1001] printk: drop in_nmi check from printk_safe_flush_on_panic() [ Upstream commit 554755be08fba31c74f66b82a485e5513205af84 ] Drop the in_nmi() check from printk_safe_flush_on_panic() and attempt to re-init (IOW unlock) locked logbuf spinlock from panic CPU regardless of its context. Otherwise, theoretically, we can deadlock on logbuf trying to flush per-CPU buffers: a) Panic CPU is running in non-NMI context b) Panic CPU sends out shutdown IPI via reboot vector c) Panic CPU fails to stop all remote CPUs d) Panic CPU sends out shutdown IPI via NMI vector One of the CPUs that we bring down via NMI vector can hold logbuf spin lock (theoretically). Link: http://lkml.kernel.org/r/20180530070350.10131-1-sergey.senozhatsky@gmail.com To: Steven Rostedt Cc: Peter Zijlstra Cc: linux-kernel@vger.kernel.org Signed-off-by: Sergey Senozhatsky Signed-off-by: Petr Mladek Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/printk/printk_safe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c index d989cc238198..64825b2df3a5 100644 --- a/kernel/printk/printk_safe.c +++ b/kernel/printk/printk_safe.c @@ -284,7 +284,7 @@ void printk_safe_flush_on_panic(void) * Make sure that we could access the main ring buffer. * Do not risk a double release when more CPUs are up. */ - if (in_nmi() && raw_spin_is_locked(&logbuf_lock)) { + if (raw_spin_is_locked(&logbuf_lock)) { if (num_online_cpus() > 1) return; -- GitLab From cdad03c1f21e039affc8a709e5e982964d397039 Mon Sep 17 00:00:00 2001 From: Wang YanQing Date: Fri, 11 May 2018 10:52:17 +0800 Subject: [PATCH 0329/1001] bpf, arm32: fix inconsistent naming about emit_a32_lsr_{r64,i64} [ Upstream commit 68565a1af9f7012e6f2fe2bdd612f67d2d830c28 ] The names for BPF_ALU64 | BPF_ARSH are emit_a32_arsh_*, the names for BPF_ALU64 | BPF_LSH are emit_a32_lsh_*, but the names for BPF_ALU64 | BPF_RSH are emit_a32_lsr_*. For consistence reason, let's rename emit_a32_lsr_* to emit_a32_rsh_*. This patch also corrects a wrong comment. Fixes: 39c13c204bb1 ("arm: eBPF JIT compiler") Signed-off-by: Wang YanQing Cc: Shubham Bansal Cc: linux-arm-kernel@lists.infradead.org Cc: linux@armlinux.org.uk Signed-off-by: Daniel Borkmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/net/bpf_jit_32.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index 323a4df59a6c..ece2d1d43724 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c @@ -718,7 +718,7 @@ static inline void emit_a32_arsh_r64(const u8 dst[], const u8 src[], bool dstk, } /* dst = dst >> src */ -static inline void emit_a32_lsr_r64(const u8 dst[], const u8 src[], bool dstk, +static inline void emit_a32_rsh_r64(const u8 dst[], const u8 src[], bool dstk, bool sstk, struct jit_ctx *ctx) { const u8 *tmp = bpf2a32[TMP_REG_1]; const u8 *tmp2 = bpf2a32[TMP_REG_2]; @@ -734,7 +734,7 @@ static inline void emit_a32_lsr_r64(const u8 dst[], const u8 src[], bool dstk, emit(ARM_LDR_I(rm, ARM_SP, STACK_VAR(dst_hi)), ctx); } - /* Do LSH operation */ + /* Do RSH operation */ emit(ARM_RSB_I(ARM_IP, rt, 32), ctx); emit(ARM_SUBS_I(tmp2[0], rt, 32), ctx); emit(ARM_MOV_SR(ARM_LR, rd, SRTYPE_LSR, rt), ctx); @@ -784,7 +784,7 @@ static inline void emit_a32_lsh_i64(const u8 dst[], bool dstk, } /* dst = dst >> val */ -static inline void emit_a32_lsr_i64(const u8 dst[], bool dstk, +static inline void emit_a32_rsh_i64(const u8 dst[], bool dstk, const u32 val, struct jit_ctx *ctx) { const u8 *tmp = bpf2a32[TMP_REG_1]; const u8 *tmp2 = bpf2a32[TMP_REG_2]; @@ -1340,7 +1340,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) case BPF_ALU64 | BPF_RSH | BPF_K: if (unlikely(imm > 63)) return -EINVAL; - emit_a32_lsr_i64(dst, dstk, imm, ctx); + emit_a32_rsh_i64(dst, dstk, imm, ctx); break; /* dst = dst << src */ case BPF_ALU64 | BPF_LSH | BPF_X: @@ -1348,7 +1348,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) break; /* dst = dst >> src */ case BPF_ALU64 | BPF_RSH | BPF_X: - emit_a32_lsr_r64(dst, src, dstk, sstk, ctx); + emit_a32_rsh_r64(dst, src, dstk, sstk, ctx); break; /* dst = dst >> src (signed) */ case BPF_ALU64 | BPF_ARSH | BPF_X: -- GitLab From 4c717e335ae14e5479bf6017a9466cbb0648266e Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Wed, 30 May 2018 10:13:11 +0800 Subject: [PATCH 0330/1001] ceph: fix alignment of rasize [ Upstream commit c36ed50de2ad1649ce0369a4a6fc2cc11b20dfb7 ] On currently logic: when I specify rasize=0~1 then it will be 4096. when I specify rasize=2~4097 then it will be 8192. Make it the same as rsize & wsize. Signed-off-by: Chengguang Xu Reviewed-by: "Yan, Zheng" Signed-off-by: Ilya Dryomov Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/ceph/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 48ffe720bf09..b79b1211a2b5 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -254,7 +254,7 @@ static int parse_fsopt_token(char *c, void *private) case Opt_rasize: if (intval < 0) return -EINVAL; - fsopt->rasize = ALIGN(intval + PAGE_SIZE - 1, PAGE_SIZE); + fsopt->rasize = ALIGN(intval, PAGE_SIZE); break; case Opt_caps_wanted_delay_min: if (intval < 1) -- GitLab From 848f260301d0116a625eb2580956c3119790f29d Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Thu, 10 May 2018 16:28:35 +0900 Subject: [PATCH 0331/1001] e1000e: Ignore TSYNCRXCTL when getting I219 clock attributes [ Upstream commit fff200caf6f9179dd9a7fc67acd659e614c3f72f ] There have been multiple reports of crashes that look like kernel: RIP: 0010:[] timecounter_read+0xf/0x50 [...] kernel: Call Trace: kernel: [] e1000e_phc_gettime+0x2f/0x60 [e1000e] kernel: [] e1000e_systim_overflow_work+0x1d/0x80 [e1000e] kernel: [] process_one_work+0x155/0x440 kernel: [] worker_thread+0x116/0x4b0 kernel: [] kthread+0xd2/0xf0 kernel: [] ret_from_fork+0x3f/0x70 These can be traced back to the fact that e1000e_systim_reset() skips the timecounter_init() call if e1000e_get_base_timinca() returns -EINVAL, which leads to a null deref in timecounter_read(). Commit 83129b37ef35 ("e1000e: fix systim issues", v4.2-rc1) reworked e1000e_get_base_timinca() in such a way that it can return -EINVAL for e1000_pch_spt if the SYSCFI bit is not set in TSYNCRXCTL. Some experimentation has shown that on I219 (e1000_pch_spt, "MAC: 12") adapters, the E1000_TSYNCRXCTL_SYSCFI flag is unstable; TSYNCRXCTL reads sometimes don't have the SYSCFI bit set. Retrying the read shortly after finds the bit to be set. This was observed at boot (probe) but also link up and link down. Moreover, the phc (PTP Hardware Clock) seems to operate normally even after reads where SYSCFI=0. Therefore, remove this register read and unconditionally set the clock parameters. Reported-by: Achim Mildenberger Message-Id: <20180425065243.g5mqewg5irkwgwgv@f2> Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1075876 Fixes: 83129b37ef35 ("e1000e: fix systim issues") Signed-off-by: Benjamin Poirier Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/e1000e/netdev.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 7a226537877b..6265ce8915b6 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -3558,15 +3558,12 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca) } break; case e1000_pch_spt: - if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) { - /* Stable 24MHz frequency */ - incperiod = INCPERIOD_24MHZ; - incvalue = INCVALUE_24MHZ; - shift = INCVALUE_SHIFT_24MHZ; - adapter->cc.shift = shift; - break; - } - return -EINVAL; + /* Stable 24MHz frequency */ + incperiod = INCPERIOD_24MHZ; + incvalue = INCVALUE_24MHZ; + shift = INCVALUE_SHIFT_24MHZ; + adapter->cc.shift = shift; + break; case e1000_pch_cnp: if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) { /* Stable 24MHz frequency */ -- GitLab From e27dad1eb1ac7bedb5a033ac2e068543742c807b Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Fri, 1 Jun 2018 11:31:44 -0700 Subject: [PATCH 0332/1001] infiniband: fix a possible use-after-free bug [ Upstream commit cb2595c1393b4a5211534e6f0a0fbad369e21ad8 ] ucma_process_join() will free the new allocated "mc" struct, if there is any error after that, especially the copy_to_user(). But in parallel, ucma_leave_multicast() could find this "mc" through idr_find() before ucma_process_join() frees it, since it is already published. So "mc" could be used in ucma_leave_multicast() after it is been allocated and freed in ucma_process_join(), since we don't refcnt it. Fix this by separating "publish" from ID allocation, so that we can get an ID first and publish it later after copy_to_user(). Fixes: c8f6a362bf3e ("RDMA/cma: Add multicast communication support") Reported-by: Noam Rathaus Signed-off-by: Cong Wang Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index e47baf0950e3..a22b992cde38 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -218,7 +218,7 @@ static struct ucma_multicast* ucma_alloc_multicast(struct ucma_context *ctx) return NULL; mutex_lock(&mut); - mc->id = idr_alloc(&multicast_idr, mc, 0, 0, GFP_KERNEL); + mc->id = idr_alloc(&multicast_idr, NULL, 0, 0, GFP_KERNEL); mutex_unlock(&mut); if (mc->id < 0) goto error; @@ -1404,6 +1404,10 @@ static ssize_t ucma_process_join(struct ucma_file *file, goto err3; } + mutex_lock(&mut); + idr_replace(&multicast_idr, mc, mc->id); + mutex_unlock(&mut); + mutex_unlock(&file->mut); ucma_put_ctx(ctx); return 0; -- GitLab From 47b3561450178b538b99ba26a4989e0f846f2e8e Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 18 May 2018 15:01:16 +0200 Subject: [PATCH 0333/1001] powerpc/lib: Adjust .balign inside string functions for PPC32 [ Upstream commit 1128bb7813a896bd608fb622eee3c26aaf33b473 ] commit 87a156fb18fe1 ("Align hot loops of some string functions") degraded the performance of string functions by adding useless nops A simple benchmark on an 8xx calling 100000x a memchr() that matches the first byte runs in 41668 TB ticks before this patch and in 35986 TB ticks after this patch. So this gives an improvement of approx 10% Another benchmark doing the same with a memchr() matching the 128th byte runs in 1011365 TB ticks before this patch and 1005682 TB ticks after this patch, so regardless on the number of loops, removing those useless nops improves the test by 5683 TB ticks. Fixes: 87a156fb18fe1 ("Align hot loops of some string functions") Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/cache.h | 3 +++ arch/powerpc/lib/string.S | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h index c1d257aa4c2d..66298461b640 100644 --- a/arch/powerpc/include/asm/cache.h +++ b/arch/powerpc/include/asm/cache.h @@ -9,11 +9,14 @@ #if defined(CONFIG_PPC_8xx) || defined(CONFIG_403GCX) #define L1_CACHE_SHIFT 4 #define MAX_COPY_PREFETCH 1 +#define IFETCH_ALIGN_SHIFT 2 #elif defined(CONFIG_PPC_E500MC) #define L1_CACHE_SHIFT 6 #define MAX_COPY_PREFETCH 4 +#define IFETCH_ALIGN_SHIFT 3 #elif defined(CONFIG_PPC32) #define MAX_COPY_PREFETCH 4 +#define IFETCH_ALIGN_SHIFT 3 /* 603 fetches 2 insn at a time */ #if defined(CONFIG_PPC_47x) #define L1_CACHE_SHIFT 7 #else diff --git a/arch/powerpc/lib/string.S b/arch/powerpc/lib/string.S index a787776822d8..0378def28d41 100644 --- a/arch/powerpc/lib/string.S +++ b/arch/powerpc/lib/string.S @@ -12,6 +12,7 @@ #include #include #include +#include .text @@ -23,7 +24,7 @@ _GLOBAL(strncpy) mtctr r5 addi r6,r3,-1 addi r4,r4,-1 - .balign 16 + .balign IFETCH_ALIGN_BYTES 1: lbzu r0,1(r4) cmpwi 0,r0,0 stbu r0,1(r6) @@ -43,7 +44,7 @@ _GLOBAL(strncmp) mtctr r5 addi r5,r3,-1 addi r4,r4,-1 - .balign 16 + .balign IFETCH_ALIGN_BYTES 1: lbzu r3,1(r5) cmpwi 1,r3,0 lbzu r0,1(r4) @@ -77,7 +78,7 @@ _GLOBAL(memchr) beq- 2f mtctr r5 addi r3,r3,-1 - .balign 16 + .balign IFETCH_ALIGN_BYTES 1: lbzu r0,1(r3) cmpw 0,r0,r4 bdnzf 2,1b -- GitLab From 04cda3ac3312f16ef8bbffa06c55dd1b04d3aad6 Mon Sep 17 00:00:00 2001 From: Michal Suchanek Date: Tue, 24 Apr 2018 14:15:54 +1000 Subject: [PATCH 0334/1001] powerpc/64s: Add barrier_nospec [ Upstream commit a6b3964ad71a61bb7c61d80a60bea7d42187b2eb ] A no-op form of ori (or immediate of 0 into r31 and the result stored in r31) has been re-tasked as a speculation barrier. The instruction only acts as a barrier on newer machines with appropriate firmware support. On older CPUs it remains a harmless no-op. Implement barrier_nospec using this instruction. mpe: The semantics of the instruction are believed to be that it prevents execution of subsequent instructions until preceding branches have been fully resolved and are no longer executing speculatively. There is no further documentation available at this time. Signed-off-by: Michal Suchanek Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/barrier.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/powerpc/include/asm/barrier.h b/arch/powerpc/include/asm/barrier.h index c7c63959ba91..e582d2c88092 100644 --- a/arch/powerpc/include/asm/barrier.h +++ b/arch/powerpc/include/asm/barrier.h @@ -76,6 +76,21 @@ do { \ ___p1; \ }) +#ifdef CONFIG_PPC_BOOK3S_64 +/* + * Prevent execution of subsequent instructions until preceding branches have + * been fully resolved and are no longer executing speculatively. + */ +#define barrier_nospec_asm ori 31,31,0 + +// This also acts as a compiler barrier due to the memory clobber. +#define barrier_nospec() asm (stringify_in_c(barrier_nospec_asm) ::: "memory") + +#else /* !CONFIG_PPC_BOOK3S_64 */ +#define barrier_nospec_asm +#define barrier_nospec() +#endif + #include #endif /* _ASM_POWERPC_BARRIER_H */ -- GitLab From bc0b4615cc975db67ace25e9e8cc7f7dcf207d6b Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Fri, 25 May 2018 13:11:30 +1000 Subject: [PATCH 0335/1001] powerpc/eeh: Fix use-after-release of EEH driver [ Upstream commit 46d4be41b987a6b2d25a2ebdd94cafb44e21d6c5 ] Correct two cases where eeh_pcid_get() is used to reference the driver's module but the reference is dropped before the driver pointer is used. In eeh_rmv_device() also refactor a little so that only two calls to eeh_pcid_put() are needed, rather than three and the reference isn't taken at all if it wasn't needed. Signed-off-by: Sam Bobroff Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/eeh_driver.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index ca2243df9cb2..470284f9e4f6 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -450,9 +450,11 @@ static void *eeh_add_virt_device(void *data, void *userdata) driver = eeh_pcid_get(dev); if (driver) { - eeh_pcid_put(dev); - if (driver->err_handler) + if (driver->err_handler) { + eeh_pcid_put(dev); return NULL; + } + eeh_pcid_put(dev); } #ifdef CONFIG_PPC_POWERNV @@ -489,17 +491,19 @@ static void *eeh_rmv_device(void *data, void *userdata) if (eeh_dev_removed(edev)) return NULL; - driver = eeh_pcid_get(dev); - if (driver) { - eeh_pcid_put(dev); - if (removed && - eeh_pe_passed(edev->pe)) - return NULL; - if (removed && - driver->err_handler && - driver->err_handler->error_detected && - driver->err_handler->slot_reset) + if (removed) { + if (eeh_pe_passed(edev->pe)) return NULL; + driver = eeh_pcid_get(dev); + if (driver) { + if (driver->err_handler && + driver->err_handler->error_detected && + driver->err_handler->slot_reset) { + eeh_pcid_put(dev); + return NULL; + } + eeh_pcid_put(dev); + } } /* Remove it from PCI subsystem */ -- GitLab From 0aceed2d7ec10eae4bab4912cbae11e47c8ceaec Mon Sep 17 00:00:00 2001 From: Stewart Smith Date: Thu, 29 Mar 2018 17:02:46 +1100 Subject: [PATCH 0336/1001] hvc_opal: don't set tb_ticks_per_usec in udbg_init_opal_common() [ Upstream commit 447808bf500a7cc92173266a59f8a494e132b122 ] time_init() will set up tb_ticks_per_usec based on reality. time_init() is called *after* udbg_init_opal_common() during boot. from arch/powerpc/kernel/time.c: unsigned long tb_ticks_per_usec = 100; /* sane default */ Currently, all powernv systems have a timebase frequency of 512mhz (512000000/1000000 == 0x200) - although there's nothing written down anywhere that I can find saying that we couldn't make that different based on the requirements in the ISA. So, we've been (accidentally) thwacking the (currently) correct (for powernv at least) value for tb_ticks_per_usec earlier than we otherwise would have. The "sane default" seems to be adequate for our purposes between udbg_init_opal_common() and time_init() being called, and if it isn't, then we should probably be setting it somewhere that isn't hvc_opal.c! Signed-off-by: Stewart Smith Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_opal.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index 16331a90c1e8..9da8474fe50a 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -332,7 +332,6 @@ static void udbg_init_opal_common(void) udbg_putc = udbg_opal_putc; udbg_getc = udbg_opal_getc; udbg_getc_poll = udbg_opal_getc_poll; - tb_ticks_per_usec = 0x200; /* Make udelay not suck */ } void __init hvc_opal_init_early(void) -- GitLab From a23e1da9773bcf90b0caac3c3a7fc06fea351181 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 30 May 2018 20:31:22 +1000 Subject: [PATCH 0337/1001] powerpc/64s: Fix compiler store ordering to SLB shadow area [ Upstream commit 926bc2f100c24d4842b3064b5af44ae964c1d81c ] The stores to update the SLB shadow area must be made as they appear in the C code, so that the hypervisor does not see an entry with mismatched vsid and esid. Use WRITE_ONCE for this. GCC has been observed to elide the first store to esid in the update, which means that if the hypervisor interrupts the guest after storing to vsid, it could see an entry with old esid and new vsid, which may possibly result in memory corruption. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/mm/slb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 13cfe413b40d..6d9bf014b3e7 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -62,14 +62,14 @@ static inline void slb_shadow_update(unsigned long ea, int ssize, * updating it. No write barriers are needed here, provided * we only update the current CPU's SLB shadow buffer. */ - p->save_area[index].esid = 0; - p->save_area[index].vsid = cpu_to_be64(mk_vsid_data(ea, ssize, flags)); - p->save_area[index].esid = cpu_to_be64(mk_esid_data(ea, ssize, index)); + WRITE_ONCE(p->save_area[index].esid, 0); + WRITE_ONCE(p->save_area[index].vsid, cpu_to_be64(mk_vsid_data(ea, ssize, flags))); + WRITE_ONCE(p->save_area[index].esid, cpu_to_be64(mk_esid_data(ea, ssize, index))); } static inline void slb_shadow_clear(enum slb_index index) { - get_slb_shadow()->save_area[index].esid = 0; + WRITE_ONCE(get_slb_shadow()->save_area[index].esid, 0); } static inline void create_shadowed_slbe(unsigned long ea, int ssize, -- GitLab From 929e1a3906e15ca66f2e750a6000ecc30e390edd Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 29 May 2018 14:56:19 +0300 Subject: [PATCH 0338/1001] RDMA/mad: Convert BUG_ONs to error flows [ Upstream commit 2468b82d69e3a53d024f28d79ba0fdb8bf43dfbf ] Let's perform checks in-place instead of BUG_ONs. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/mad.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index d8efdc191c27..55252079faf6 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -1558,7 +1558,8 @@ static int add_oui_reg_req(struct ib_mad_reg_req *mad_reg_req, mad_reg_req->oui, 3)) { method = &(*vendor_table)->vendor_class[ vclass]->method_table[i]; - BUG_ON(!*method); + if (!*method) + goto error3; goto check_in_use; } } @@ -1568,10 +1569,12 @@ static int add_oui_reg_req(struct ib_mad_reg_req *mad_reg_req, vclass]->oui[i])) { method = &(*vendor_table)->vendor_class[ vclass]->method_table[i]; - BUG_ON(*method); /* Allocate method table for this OUI */ - if ((ret = allocate_method_table(method))) - goto error3; + if (!*method) { + ret = allocate_method_table(method); + if (ret) + goto error3; + } memcpy((*vendor_table)->vendor_class[vclass]->oui[i], mad_reg_req->oui, 3); goto check_in_use; -- GitLab From 4f5fd8a1ae16ccbb851bc2ca9243319c67f04955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Gonz=C3=A1lez?= Date: Fri, 1 Jun 2018 15:04:19 +0200 Subject: [PATCH 0339/1001] lightnvm: pblk: warn in case of corrupted write buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit e37d07983af9068de0303054542d2652ca917f58 ] When cleaning up buffer entries as we wrap up, their state should be "completed". If any of the entries is in "submitted" state, it means that something bad has happened. Trigger a warning immediately instead of waiting for the state flag to eventually be updated, thus hiding the issue. Signed-off-by: Javier González Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/lightnvm/pblk-rb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/lightnvm/pblk-rb.c b/drivers/lightnvm/pblk-rb.c index 9bc32578a766..c0dd17a82170 100644 --- a/drivers/lightnvm/pblk-rb.c +++ b/drivers/lightnvm/pblk-rb.c @@ -142,10 +142,9 @@ static void clean_wctx(struct pblk_w_ctx *w_ctx) { int flags; -try: flags = READ_ONCE(w_ctx->flags); - if (!(flags & PBLK_SUBMITTED_ENTRY)) - goto try; + WARN_ONCE(!(flags & PBLK_SUBMITTED_ENTRY), + "pblk: overwriting unsubmitted data\n"); /* Release flags on context. Protect from writes and reads */ smp_store_release(&w_ctx->flags, PBLK_WRITABLE_ENTRY); -- GitLab From 20fc8b34c1955d0a8dd2e0bca49d287b65f3f9a8 Mon Sep 17 00:00:00 2001 From: Alexey Kodanev Date: Thu, 31 May 2018 19:53:33 +0300 Subject: [PATCH 0340/1001] netfilter: nf_tables: check msg_type before nft_trans_set(trans) [ Upstream commit 9c7f96fd77b0dbe1fe7ed1f9c462c45dc48a1076 ] The patch moves the "trans->msg_type == NFT_MSG_NEWSET" check before using nft_trans_set(trans). Otherwise we can get out of bounds read. For example, KASAN reported the one when running 0001_cache_handling_0 nft test. In this case "trans->msg_type" was NFT_MSG_NEWTABLE: [75517.177808] BUG: KASAN: slab-out-of-bounds in nft_set_lookup_global+0x22f/0x270 [nf_tables] [75517.279094] Read of size 8 at addr ffff881bdb643fc8 by task nft/7356 ... [75517.375605] CPU: 26 PID: 7356 Comm: nft Tainted: G E 4.17.0-rc7.1.x86_64 #1 [75517.489587] Hardware name: Oracle Corporation SUN SERVER X4-2 [75517.618129] Call Trace: [75517.648821] dump_stack+0xd1/0x13b [75517.691040] ? show_regs_print_info+0x5/0x5 [75517.742519] ? kmsg_dump_rewind_nolock+0xf5/0xf5 [75517.799300] ? lock_acquire+0x143/0x310 [75517.846738] print_address_description+0x85/0x3a0 [75517.904547] kasan_report+0x18d/0x4b0 [75517.949892] ? nft_set_lookup_global+0x22f/0x270 [nf_tables] [75518.019153] ? nft_set_lookup_global+0x22f/0x270 [nf_tables] [75518.088420] ? nft_set_lookup_global+0x22f/0x270 [nf_tables] [75518.157689] nft_set_lookup_global+0x22f/0x270 [nf_tables] [75518.224869] nf_tables_newsetelem+0x1a5/0x5d0 [nf_tables] [75518.291024] ? nft_add_set_elem+0x2280/0x2280 [nf_tables] [75518.357154] ? nla_parse+0x1a5/0x300 [75518.401455] ? kasan_kmalloc+0xa6/0xd0 [75518.447842] nfnetlink_rcv+0xc43/0x1bdf [nfnetlink] [75518.507743] ? nfnetlink_rcv+0x7a5/0x1bdf [nfnetlink] [75518.569745] ? nfnl_err_reset+0x3c0/0x3c0 [nfnetlink] [75518.631711] ? lock_acquire+0x143/0x310 [75518.679133] ? netlink_deliver_tap+0x9b/0x1070 [75518.733840] ? kasan_unpoison_shadow+0x31/0x40 [75518.788542] netlink_unicast+0x45d/0x680 [75518.837111] ? __isolate_free_page+0x890/0x890 [75518.891913] ? netlink_attachskb+0x6b0/0x6b0 [75518.944542] netlink_sendmsg+0x6fa/0xd30 [75518.993107] ? netlink_unicast+0x680/0x680 [75519.043758] ? netlink_unicast+0x680/0x680 [75519.094402] sock_sendmsg+0xd9/0x160 [75519.138810] ___sys_sendmsg+0x64d/0x980 [75519.186234] ? copy_msghdr_from_user+0x350/0x350 [75519.243118] ? lock_downgrade+0x650/0x650 [75519.292738] ? do_raw_spin_unlock+0x5d/0x250 [75519.345456] ? _raw_spin_unlock+0x24/0x30 [75519.395065] ? __handle_mm_fault+0xbde/0x3410 [75519.448830] ? sock_setsockopt+0x3d2/0x1940 [75519.500516] ? __lock_acquire.isra.25+0xdc/0x19d0 [75519.558448] ? lock_downgrade+0x650/0x650 [75519.608057] ? __audit_syscall_entry+0x317/0x720 [75519.664960] ? __fget_light+0x58/0x250 [75519.711325] ? __sys_sendmsg+0xde/0x170 [75519.758850] __sys_sendmsg+0xde/0x170 [75519.804193] ? __ia32_sys_shutdown+0x90/0x90 [75519.856725] ? syscall_trace_enter+0x897/0x10e0 [75519.912354] ? trace_event_raw_event_sys_enter+0x920/0x920 [75519.979432] ? __audit_syscall_entry+0x720/0x720 [75520.036118] do_syscall_64+0xa3/0x3d0 [75520.081248] ? prepare_exit_to_usermode+0x47/0x1d0 [75520.139904] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [75520.201680] RIP: 0033:0x7fc153320ba0 [75520.245772] RSP: 002b:00007ffe294c3638 EFLAGS: 00000246 ORIG_RAX: 000000000000002e [75520.337708] RAX: ffffffffffffffda RBX: 00007ffe294c4820 RCX: 00007fc153320ba0 [75520.424547] RDX: 0000000000000000 RSI: 00007ffe294c46b0 RDI: 0000000000000003 [75520.511386] RBP: 00007ffe294c47b0 R08: 0000000000000004 R09: 0000000002114090 [75520.598225] R10: 00007ffe294c30a0 R11: 0000000000000246 R12: 00007ffe294c3660 [75520.684961] R13: 0000000000000001 R14: 00007ffe294c3650 R15: 0000000000000001 [75520.790946] Allocated by task 7356: [75520.833994] kasan_kmalloc+0xa6/0xd0 [75520.878088] __kmalloc+0x189/0x450 [75520.920107] nft_trans_alloc_gfp+0x20/0x190 [nf_tables] [75520.983961] nf_tables_newtable+0xcd0/0x1bd0 [nf_tables] [75521.048857] nfnetlink_rcv+0xc43/0x1bdf [nfnetlink] [75521.108655] netlink_unicast+0x45d/0x680 [75521.157013] netlink_sendmsg+0x6fa/0xd30 [75521.205271] sock_sendmsg+0xd9/0x160 [75521.249365] ___sys_sendmsg+0x64d/0x980 [75521.296686] __sys_sendmsg+0xde/0x170 [75521.341822] do_syscall_64+0xa3/0x3d0 [75521.386957] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [75521.467867] Freed by task 23454: [75521.507804] __kasan_slab_free+0x132/0x180 [75521.558137] kfree+0x14d/0x4d0 [75521.596005] free_rt_sched_group+0x153/0x280 [75521.648410] sched_autogroup_create_attach+0x19a/0x520 [75521.711330] ksys_setsid+0x2ba/0x400 [75521.755529] __ia32_sys_setsid+0xa/0x10 [75521.802850] do_syscall_64+0xa3/0x3d0 [75521.848090] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [75521.929000] The buggy address belongs to the object at ffff881bdb643f80 which belongs to the cache kmalloc-96 of size 96 [75522.079797] The buggy address is located 72 bytes inside of 96-byte region [ffff881bdb643f80, ffff881bdb643fe0) [75522.221234] The buggy address belongs to the page: [75522.280100] page:ffffea006f6d90c0 count:1 mapcount:0 mapping:0000000000000000 index:0x0 [75522.377443] flags: 0x2fffff80000100(slab) [75522.426956] raw: 002fffff80000100 0000000000000000 0000000000000000 0000000180200020 [75522.521275] raw: ffffea006e6fafc0 0000000c0000000c ffff881bf180f400 0000000000000000 [75522.615601] page dumped because: kasan: bad access detected Fixes: 37a9cc525525 ("netfilter: nf_tables: add generation mask to sets") Signed-off-by: Alexey Kodanev Acked-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/netfilter/nf_tables_api.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 85b549e84104..9a945024a0b6 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -2710,12 +2710,13 @@ static struct nft_set *nf_tables_set_lookup_byid(const struct net *net, u32 id = ntohl(nla_get_be32(nla)); list_for_each_entry(trans, &net->nft.commit_list, list) { - struct nft_set *set = nft_trans_set(trans); + if (trans->msg_type == NFT_MSG_NEWSET) { + struct nft_set *set = nft_trans_set(trans); - if (trans->msg_type == NFT_MSG_NEWSET && - id == nft_trans_set_id(trans) && - nft_active_genmask(set, genmask)) - return set; + if (id == nft_trans_set_id(trans) && + nft_active_genmask(set, genmask)) + return set; + } } return ERR_PTR(-ENOENT); } -- GitLab From 1339e2b8eaea3db8996eeeb6dafd2a0c600ee843 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 22 May 2018 11:17:16 -0400 Subject: [PATCH 0341/1001] pnfs: Don't release the sequence slot until we've processed layoutget on open [ Upstream commit ae55e59da0e401893b3c52b575fc18a00623d0a1 ] If the server recalls the layout that was just handed out, we risk hitting a race as described in RFC5661 Section 2.10.6.3 unless we ensure that we release the sequence slot after processing the LAYOUTGET operation that was sent as part of the OPEN compound. Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4proc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index df0455cf03af..43fbf4495090 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2695,7 +2695,7 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, if (ret != 0) goto out; - state = nfs4_opendata_to_nfs4_state(opendata); + state = _nfs4_opendata_to_nfs4_state(opendata); ret = PTR_ERR(state); if (IS_ERR(state)) goto out; @@ -2731,6 +2731,7 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, nfs4_schedule_stateid_recovery(server, state); } out: + nfs4_sequence_free_slot(&opendata->o_res.seq_res); return ret; } -- GitLab From 122031c292023f520befba701eb9895c3e0fc48c Mon Sep 17 00:00:00 2001 From: Anatoly Pugachev Date: Mon, 28 May 2018 02:06:37 +0300 Subject: [PATCH 0342/1001] disable loading f2fs module on PAGE_SIZE > 4KB [ Upstream commit 4071e67cffcc5c2a007116a02437471351f550eb ] The following patch disables loading of f2fs module on architectures which have PAGE_SIZE > 4096 , since it is impossible to mount f2fs on such architectures , log messages are: mount: /mnt: wrong fs type, bad option, bad superblock on /dev/vdiskb1, missing codepage or helper program, or other error. /dev/vdiskb1: F2FS filesystem, UUID=1d8b9ca4-2389-4910-af3b-10998969f09c, volume name "" May 15 18:03:13 ttip kernel: F2FS-fs (vdiskb1): Invalid page_cache_size (8192), supports only 4KB May 15 18:03:13 ttip kernel: F2FS-fs (vdiskb1): Can't find valid F2FS filesystem in 1th superblock May 15 18:03:13 ttip kernel: F2FS-fs (vdiskb1): Invalid page_cache_size (8192), supports only 4KB May 15 18:03:13 ttip kernel: F2FS-fs (vdiskb1): Can't find valid F2FS filesystem in 2th superblock May 15 18:03:13 ttip kernel: F2FS-fs (vdiskb1): Invalid page_cache_size (8192), supports only 4KB which was introduced by git commit 5c9b469295fb6b10d98923eab5e79c4edb80ed20 tested on git kernel 4.17.0-rc6-00309-gec30dcf7f425 with patch applied: modprobe: ERROR: could not insert 'f2fs': Invalid argument May 28 01:40:28 v215 kernel: F2FS not supported on PAGE_SIZE(8192) != 4096 Signed-off-by: Anatoly Pugachev Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/super.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 933c3d529e65..400c00058bad 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -2663,6 +2663,12 @@ static int __init init_f2fs_fs(void) { int err; + if (PAGE_SIZE != F2FS_BLKSIZE) { + printk("F2FS not supported on PAGE_SIZE(%lu) != %d\n", + PAGE_SIZE, F2FS_BLKSIZE); + return -EINVAL; + } + f2fs_build_trace_ios(); err = init_inodecache(); -- GitLab From f3f029197738730a7b74d1b2d25288586975df47 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 28 May 2018 16:59:27 +0800 Subject: [PATCH 0343/1001] f2fs: fix error path of move_data_page [ Upstream commit 14a28559f43ac7c0b98dd1b0e73ec9ec8ab4fc45 ] This patch fixes error path of move_data_page: - clear cold data flag if it fails to write page. - redirty page for non-ENOMEM case. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/gc.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index e5673a9b2619..f2f897cd23c9 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -768,9 +768,14 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type, set_cold_data(page); err = do_write_data_page(&fio); - if (err == -ENOMEM && is_dirty) { - congestion_wait(BLK_RW_ASYNC, HZ/50); - goto retry; + if (err) { + clear_cold_data(page); + if (err == -ENOMEM) { + congestion_wait(BLK_RW_ASYNC, HZ/50); + goto retry; + } + if (is_dirty) + set_page_dirty(page); } } out: -- GitLab From de13b2ac741f52000f6de185a78cc844b7565fe5 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Sat, 26 May 2018 18:03:34 +0800 Subject: [PATCH 0344/1001] f2fs: fix to don't trigger writeback during recovery [ Upstream commit 64c74a7ab505ea40d1b3e5d02735ecab08ae1b14 ] - f2fs_fill_super - recover_fsync_data - recover_data - del_fsync_inode - iput - iput_final - write_inode_now - f2fs_write_inode - f2fs_balance_fs - f2fs_balance_fs_bg - sync_dirty_inodes With data_flush mount option, during recovery, in order to avoid entering above writeback flow, let's detect recovery status and do skip in f2fs_balance_fs_bg. Signed-off-by: Chao Yu Signed-off-by: Yunlei He Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/segment.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 271516db8939..2793b65a1c1c 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -435,6 +435,9 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need) void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) { + if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) + return; + /* 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); -- GitLab From 4f979af7b0ad6d88723bf1ec117b6e44dca38148 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 23 Apr 2018 10:36:13 +0800 Subject: [PATCH 0345/1001] f2fs: fix to wait page writeback during revoking atomic write [ Upstream commit e5e5732d8120654159254c16834bc8663d8be124 ] After revoking atomic write, related LBA can be reused by others, so we need to wait page writeback before reusing the LBA, in order to avoid interference between old atomic written in-flight IO and new IO. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/segment.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 2793b65a1c1c..7c05bd4222b2 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -225,6 +225,8 @@ static int __revoke_inmem_pages(struct inode *inode, lock_page(page); + f2fs_wait_on_page_writeback(page, DATA, true); + if (recover) { struct dnode_of_data dn; struct node_info ni; -- GitLab From c92d09e35d2ddf8ec3e3e3c755241cfde670236c Mon Sep 17 00:00:00 2001 From: Sahitya Tummala Date: Fri, 18 May 2018 11:51:52 +0530 Subject: [PATCH 0346/1001] f2fs: Fix deadlock in shutdown ioctl [ Upstream commit 60b2b4ee2bc01dd052f99fa9d65da2232102ef8e ] f2fs_ioc_shutdown() ioctl gets stuck in the below path when issued with F2FS_GOING_DOWN_FULLSYNC option. __switch_to+0x90/0xc4 percpu_down_write+0x8c/0xc0 freeze_super+0xec/0x1e4 freeze_bdev+0xc4/0xcc f2fs_ioctl+0xc0c/0x1ce0 f2fs_compat_ioctl+0x98/0x1f0 Signed-off-by: Sahitya Tummala Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/file.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 72c6a9e9a9b4..97537ce5127c 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1808,9 +1808,11 @@ 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; + if (in != F2FS_GOING_DOWN_FULLSYNC) { + ret = mnt_want_write_file(filp); + if (ret) + return ret; + } switch (in) { case F2FS_GOING_DOWN_FULLSYNC: @@ -1838,7 +1840,8 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg) } f2fs_update_time(sbi, REQ_TIME); out: - mnt_drop_write_file(filp); + if (in != F2FS_GOING_DOWN_FULLSYNC) + mnt_drop_write_file(filp); return ret; } -- GitLab From ad8d61efc9b7b158095fac6a7f764d6897ef7952 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Sat, 21 Apr 2018 17:53:52 +0800 Subject: [PATCH 0347/1001] f2fs: fix to detect failure of dquot_initialize [ Upstream commit c22aecd75919511abea872b201751e0be1add898 ] dquot_initialize() can fail due to any exception inside quota subsystem, f2fs needs to be aware of it, and return correct return value to caller. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/file.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 97537ce5127c..1b361afcbb67 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -2493,7 +2493,9 @@ static int f2fs_ioc_setproject(struct file *filp, __u32 projid) } f2fs_put_page(ipage, 1); - dquot_initialize(inode); + err = dquot_initialize(inode); + if (err) + goto out_unlock; transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid)); if (!IS_ERR(transfer_to[PRJQUOTA])) { -- GitLab From 67226fb52c23e0df7d1e9f50fd29f880eb08ae69 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 17 Apr 2018 17:51:28 +0800 Subject: [PATCH 0348/1001] f2fs: fix race in between GC and atomic open [ Upstream commit 27319ba4044c0c67d62ae39e53c0118c89f0a029 ] Thread GC thread - f2fs_ioc_start_atomic_write - get_dirty_pages - filemap_write_and_wait_range - f2fs_gc - do_garbage_collect - gc_data_segment - move_data_page - f2fs_is_atomic_file - set_page_dirty - set_inode_flag(, FI_ATOMIC_FILE) Dirty data page can still be generated by GC in race condition as above call stack. This patch adds fi->dio_rwsem[WRITE] in f2fs_ioc_start_atomic_write to avoid such race. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/file.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 1b361afcbb67..87e654c53c31 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1630,6 +1630,8 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) inode_lock(inode); + down_write(&F2FS_I(inode)->dio_rwsem[WRITE]); + if (f2fs_is_atomic_file(inode)) goto out; @@ -1659,6 +1661,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) stat_inc_atomic_write(inode); stat_update_max_atomic_write(inode); out: + up_write(&F2FS_I(inode)->dio_rwsem[WRITE]); inode_unlock(inode); mnt_drop_write_file(filp); return ret; -- GitLab From 63019044fb8923974ba735a6b580a8ba16219471 Mon Sep 17 00:00:00 2001 From: Filippo Muzzini Date: Thu, 31 May 2018 15:23:11 +0200 Subject: [PATCH 0349/1001] block, bfq: remove wrong lock in bfq_requests_merged [ Upstream commit a12bffebc0c9d6a5851f062aaea3aa7c4adc6042 ] In bfq_requests_merged(), there is a deadlock because the lock on bfqq->bfqd->lock is held by the calling function, but the code of this function tries to grab the lock again. This deadlock is currently hidden by another bug (fixed by next commit for this source file), which causes the body of bfq_requests_merged() to be never executed. This commit removes the deadlock by removing the lock/unlock pair. Signed-off-by: Filippo Muzzini Signed-off-by: Paolo Valente Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- block/bfq-iosched.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index 56c9cd01fd1d..4a4b7d3c909a 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c @@ -1678,7 +1678,6 @@ static void bfq_requests_merged(struct request_queue *q, struct request *rq, if (!RB_EMPTY_NODE(&rq->rb_node)) goto end; - spin_lock_irq(&bfqq->bfqd->lock); /* * If next and rq belong to the same bfq_queue and next is older @@ -1702,7 +1701,6 @@ static void bfq_requests_merged(struct request_queue *q, struct request *rq, bfq_remove_request(q, next); - spin_unlock_irq(&bfqq->bfqd->lock); end: bfqg_stats_update_io_merged(bfqq_group(bfqq), next->cmd_flags); } -- GitLab From bc30588b8e082f48882f713c19369bc9ae4c5509 Mon Sep 17 00:00:00 2001 From: "Shuah Khan (Samsung OSG)" Date: Tue, 29 May 2018 16:13:03 -0600 Subject: [PATCH 0350/1001] usbip: usbip_detach: Fix memory, udev context and udev leak [ Upstream commit d179f99a651685b19333360e6558110da2fe9bd7 ] detach_port() fails to call usbip_vhci_driver_close() from its error path after usbip_vhci_detach_device() returns failure, leaking memory allocated in usbip_vhci_driver_open() and holding udev_context and udev references. Fix it to call usbip_vhci_driver_close(). Signed-off-by: Shuah Khan (Samsung OSG) Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/usb/usbip/src/usbip_detach.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/usb/usbip/src/usbip_detach.c b/tools/usb/usbip/src/usbip_detach.c index 9db9d21bb2ec..6a8db858caa5 100644 --- a/tools/usb/usbip/src/usbip_detach.c +++ b/tools/usb/usbip/src/usbip_detach.c @@ -43,7 +43,7 @@ void usbip_detach_usage(void) static int detach_port(char *port) { - int ret; + int ret = 0; uint8_t portnum; char path[PATH_MAX+1]; @@ -73,9 +73,12 @@ static int detach_port(char *port) } ret = usbip_vhci_detach_device(portnum); - if (ret < 0) - return -1; + if (ret < 0) { + ret = -1; + goto call_driver_close; + } +call_driver_close: usbip_vhci_driver_close(); return ret; -- GitLab From 38c8c0a9709d2159fd989b0061b0b73364427b64 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Fri, 25 May 2018 16:23:46 +0200 Subject: [PATCH 0351/1001] usbip: dynamically allocate idev by nports found in sysfs [ Upstream commit de19ca6fd72c7dd45ad82403e7b3fe9c74ef6767 ] As the amount of available ports varies by the kernels build configuration. To remove the limitation of the fixed 128 ports we allocate the amount of idevs by using the number we get from the kernel. Signed-off-by: Michael Grzeschik Acked-by: Shuah Khan (Samsung OSG) Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/usb/usbip/libsrc/vhci_driver.c | 32 +++++++++++++++++----------- tools/usb/usbip/libsrc/vhci_driver.h | 3 +-- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c index d1fc0f9f00fb..ed8c9d360c0f 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.c +++ b/tools/usb/usbip/libsrc/vhci_driver.c @@ -135,11 +135,11 @@ static int refresh_imported_device_list(void) return 0; } -static int get_nports(void) +static int get_nports(struct udev_device *hc_device) { const char *attr_nports; - attr_nports = udev_device_get_sysattr_value(vhci_driver->hc_device, "nports"); + attr_nports = udev_device_get_sysattr_value(hc_device, "nports"); if (!attr_nports) { err("udev_device_get_sysattr_value nports failed"); return -1; @@ -242,35 +242,41 @@ static int read_record(int rhport, char *host, unsigned long host_len, int usbip_vhci_driver_open(void) { + int nports; + struct udev_device *hc_device; + udev_context = udev_new(); if (!udev_context) { err("udev_new failed"); return -1; } - vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver)); - /* will be freed in usbip_driver_close() */ - vhci_driver->hc_device = + hc_device = udev_device_new_from_subsystem_sysname(udev_context, USBIP_VHCI_BUS_TYPE, USBIP_VHCI_DEVICE_NAME); - if (!vhci_driver->hc_device) { + if (!hc_device) { err("udev_device_new_from_subsystem_sysname failed"); goto err; } - vhci_driver->nports = get_nports(); - dbg("available ports: %d", vhci_driver->nports); - - if (vhci_driver->nports <= 0) { + nports = get_nports(hc_device); + if (nports <= 0) { err("no available ports"); goto err; - } else if (vhci_driver->nports > MAXNPORT) { - err("port number exceeds %d", MAXNPORT); + } + dbg("available ports: %d", nports); + + vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver) + + nports * sizeof(struct usbip_imported_device)); + if (!vhci_driver) { + err("vhci_driver allocation failed"); goto err; } + vhci_driver->nports = nports; + vhci_driver->hc_device = hc_device; vhci_driver->ncontrollers = get_ncontrollers(); dbg("available controllers: %d", vhci_driver->ncontrollers); @@ -285,7 +291,7 @@ int usbip_vhci_driver_open(void) return 0; err: - udev_device_unref(vhci_driver->hc_device); + udev_device_unref(hc_device); if (vhci_driver) free(vhci_driver); diff --git a/tools/usb/usbip/libsrc/vhci_driver.h b/tools/usb/usbip/libsrc/vhci_driver.h index 418b404d5121..6c9aca216705 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.h +++ b/tools/usb/usbip/libsrc/vhci_driver.h @@ -13,7 +13,6 @@ #define USBIP_VHCI_BUS_TYPE "platform" #define USBIP_VHCI_DEVICE_NAME "vhci_hcd.0" -#define MAXNPORT 128 enum hub_speed { HUB_SPEED_HIGH = 0, @@ -41,7 +40,7 @@ struct usbip_vhci_driver { int ncontrollers; int nports; - struct usbip_imported_device idev[MAXNPORT]; + struct usbip_imported_device idev[]; }; -- GitLab From 71b1bf6e97534f11dc268d4c9b7e5a9b9235e662 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Thu, 3 May 2018 11:25:08 -0700 Subject: [PATCH 0352/1001] perf/x86/intel/uncore: Correct fixed counter index check in generic code [ Upstream commit 4749f8196452eeb73cf2086a6a9705bae479d33d ] There is no index which is bigger than UNCORE_PMC_IDX_FIXED. The only exception is client IMC uncore, which has been specially handled. For generic code, it is not correct to use >= to check fixed counter. The code quality issue will bring problem when a new counter index is introduced. Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Cc: acme@kernel.org Cc: eranian@google.com Link: http://lkml.kernel.org/r/1525371913-10597-3-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/events/intel/uncore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c index d45e06346f14..c56cb37b88e3 100644 --- a/arch/x86/events/intel/uncore.c +++ b/arch/x86/events/intel/uncore.c @@ -218,7 +218,7 @@ void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *e u64 prev_count, new_count, delta; int shift; - if (event->hw.idx >= UNCORE_PMC_IDX_FIXED) + if (event->hw.idx == UNCORE_PMC_IDX_FIXED) shift = 64 - uncore_fixed_ctr_bits(box); else shift = 64 - uncore_perf_ctr_bits(box); -- GitLab From 596a9bfe8190ccd8ea9d9b6fa16390a575b02d32 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Thu, 3 May 2018 11:25:07 -0700 Subject: [PATCH 0353/1001] perf/x86/intel/uncore: Correct fixed counter index check for NHM [ Upstream commit d71f11c076c420c4e2fceb4faefa144e055e0935 ] For Nehalem and Westmere, there is only one fixed counter for W-Box. There is no index which is bigger than UNCORE_PMC_IDX_FIXED. It is not correct to use >= to check fixed counter. The code quality issue will bring problem when new counter index is introduced. Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Cc: acme@kernel.org Cc: eranian@google.com Link: http://lkml.kernel.org/r/1525371913-10597-2-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/events/intel/uncore_nhmex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/events/intel/uncore_nhmex.c b/arch/x86/events/intel/uncore_nhmex.c index 93e7a8397cde..173e2674be6e 100644 --- a/arch/x86/events/intel/uncore_nhmex.c +++ b/arch/x86/events/intel/uncore_nhmex.c @@ -246,7 +246,7 @@ static void nhmex_uncore_msr_enable_event(struct intel_uncore_box *box, struct p { struct hw_perf_event *hwc = &event->hw; - if (hwc->idx >= UNCORE_PMC_IDX_FIXED) + if (hwc->idx == UNCORE_PMC_IDX_FIXED) wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0); else if (box->pmu->type->event_mask & NHMEX_PMON_CTL_EN_BIT0) wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22); -- GitLab From 9c8f3af662827d596ecde90c6c7ce069c0e404eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20D=C3=ADaz?= Date: Tue, 10 Apr 2018 17:11:15 -0500 Subject: [PATCH 0354/1001] selftests/intel_pstate: Improve test, minor fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit e9d33f149f52981fd856a0b16aa8ebda89b02e34 ] A few changes improve the overall usability of the test: * fix a hard-coded maximum frequency (3300), * don't adjust the CPU frequency if only evaluating results, * fix a comparison for multiple frequencies. A symptom of that last issue looked like this: ./run.sh: line 107: [: too many arguments ./run.sh: line 110: 3099 3099 3100-3100: syntax error in expression (error token is \"3099 3100-3100\") Because a check will count how many differente frequencies there are among the CPUs of the system, and after they are tallied another read is performed, which might produce different results. Signed-off-by: Daniel Díaz Signed-off-by: Shuah Khan (Samsung OSG) Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/intel_pstate/run.sh | 24 +++++++++------------ 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/tools/testing/selftests/intel_pstate/run.sh b/tools/testing/selftests/intel_pstate/run.sh index c670359becc6..bde31a0be5ca 100755 --- a/tools/testing/selftests/intel_pstate/run.sh +++ b/tools/testing/selftests/intel_pstate/run.sh @@ -48,11 +48,12 @@ function run_test () { echo "sleeping for 5 seconds" sleep 5 - num_freqs=$(cat /proc/cpuinfo | grep MHz | sort -u | wc -l) - if [ $num_freqs -le 2 ]; then - cat /proc/cpuinfo | grep MHz | sort -u | tail -1 > /tmp/result.$1 + grep MHz /proc/cpuinfo | sort -u > /tmp/result.freqs + num_freqs=$(wc -l /tmp/result.freqs | awk ' { print $1 } ') + if [ $num_freqs -ge 2 ]; then + tail -n 1 /tmp/result.freqs > /tmp/result.$1 else - cat /proc/cpuinfo | grep MHz | sort -u > /tmp/result.$1 + cp /tmp/result.freqs /tmp/result.$1 fi ./msr 0 >> /tmp/result.$1 @@ -82,21 +83,20 @@ _max_freq=$(cpupower frequency-info -l | tail -1 | awk ' { print $2 } ') max_freq=$(($_max_freq / 1000)) -for freq in `seq $max_freq -100 $min_freq` +[ $EVALUATE_ONLY -eq 0 ] && for freq in `seq $max_freq -100 $min_freq` do echo "Setting maximum frequency to $freq" cpupower frequency-set -g powersave --max=${freq}MHz >& /dev/null - [ $EVALUATE_ONLY -eq 0 ] && run_test $freq + run_test $freq done -echo "==============================================================================" +[ $EVALUATE_ONLY -eq 0 ] && cpupower frequency-set -g powersave --max=${max_freq}MHz >& /dev/null +echo "==============================================================================" echo "The marketing frequency of the cpu is $mkt_freq MHz" echo "The maximum frequency of the cpu is $max_freq MHz" echo "The minimum frequency of the cpu is $min_freq MHz" -cpupower frequency-set -g powersave --max=${max_freq}MHz >& /dev/null - # make a pretty table echo "Target Actual Difference MSR(0x199) max_perf_pct" for freq in `seq $max_freq -100 $min_freq` @@ -104,10 +104,6 @@ do result_freq=$(cat /tmp/result.${freq} | grep "cpu MHz" | awk ' { print $4 } ' | awk -F "." ' { print $1 } ') msr=$(cat /tmp/result.${freq} | grep "msr" | awk ' { print $3 } ') max_perf_pct=$(cat /tmp/result.${freq} | grep "max_perf_pct" | awk ' { print $2 } ' ) - if [ $result_freq -eq $freq ]; then - echo " $freq $result_freq 0 $msr $(($max_perf_pct*3300))" - else - echo " $freq $result_freq $(($result_freq-$freq)) $msr $(($max_perf_pct*$max_freq))" - fi + echo " $freq $result_freq $(($result_freq-$freq)) $msr $(($max_perf_pct*$max_freq))" done exit 0 -- GitLab From 4312c2df0b7b77e45a8727fba5cf9a36729e07bc Mon Sep 17 00:00:00 2001 From: "Shuah Khan (Samsung OSG)" Date: Fri, 4 May 2018 13:33:37 -0600 Subject: [PATCH 0355/1001] selftests: memfd: return Kselftest Skip code for skipped tests [ Upstream commit b27f0259e8cea74c627327c063742a83613dd460 ] When memfd test is skipped because of unmet dependencies and/or unsupported configuration, it returns non-zero value which is treated as a fail by the Kselftest framework. This leads to false negative result even when the test could not be run. Change it to return kselftest skip code when a test gets skipped to clearly report that the test could not be run. Added an explicit check for root user at the start of memfd hugetlbfs test and return skip code if a non-root user attempts to run it. In addition, return skip code when not enough huge pages are available to run the test. Kselftest framework SKIP code is 4 and the framework prints appropriate messages to indicate that the test is skipped. Signed-off-by: Shuah Khan (Samsung OSG) Reviewed-by: Mike Kravetz Signed-off-by: Shuah Khan (Samsung OSG) Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/memfd/run_tests.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/memfd/run_tests.sh b/tools/testing/selftests/memfd/run_tests.sh index daabb350697c..bf83db61013a 100755 --- a/tools/testing/selftests/memfd/run_tests.sh +++ b/tools/testing/selftests/memfd/run_tests.sh @@ -1,6 +1,9 @@ #!/bin/bash # please run as root +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + # # Normal tests requiring no special resources # @@ -29,12 +32,13 @@ if [ -n "$freepgs" ] && [ $freepgs -lt $hpages_test ]; then nr_hugepgs=`cat /proc/sys/vm/nr_hugepages` hpages_needed=`expr $hpages_test - $freepgs` + if [ $UID != 0 ]; then + echo "Please run memfd with hugetlbfs test as root" + exit $ksft_skip + fi + echo 3 > /proc/sys/vm/drop_caches echo $(( $hpages_needed + $nr_hugepgs )) > /proc/sys/vm/nr_hugepages - if [ $? -ne 0 ]; then - echo "Please run this test as root" - exit 1 - fi while read name size unit; do if [ "$name" = "HugePages_Free:" ]; then freepgs=$size @@ -53,7 +57,7 @@ if [ $freepgs -lt $hpages_test ]; then fi printf "Not enough huge pages available (%d < %d)\n" \ $freepgs $needpgs - exit 1 + exit $ksft_skip fi # -- GitLab From f559bb20c1aeedb0a9efe321b3e42d97556aa970 Mon Sep 17 00:00:00 2001 From: "Shuah Khan (Samsung OSG)" Date: Thu, 3 May 2018 17:09:40 -0600 Subject: [PATCH 0356/1001] selftests: intel_pstate: return Kselftest Skip code for skipped tests [ Upstream commit 5c30a038fb8ec8cdff011e6b5d5d51eb415381d4 ] When intel_pstate test is skipped because of unmet dependencies and/or unsupported configuration, it returns 0 which is treated as a pass by the Kselftest framework. This leads to false positive result even when the test could not be run. Change it to return kselftest skip code when a test gets skipped to clearly report that the test could not be run. Kselftest framework SKIP code is 4 and the framework prints appropriate messages to indicate that the test is skipped. Signed-off-by: Shuah Khan (Samsung OSG) Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/intel_pstate/run.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/intel_pstate/run.sh b/tools/testing/selftests/intel_pstate/run.sh index bde31a0be5ca..928978804342 100755 --- a/tools/testing/selftests/intel_pstate/run.sh +++ b/tools/testing/selftests/intel_pstate/run.sh @@ -30,9 +30,12 @@ EVALUATE_ONLY=0 +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + if ! uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ | grep -q x86; then echo "$0 # Skipped: Test can only run on x86 architectures." - exit 0 + exit $ksft_skip fi max_cpus=$(($(nproc)-1)) -- GitLab From 233cba023484e3f4ff68d01204eae85ad427ec0d Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 15 May 2018 11:07:01 +0200 Subject: [PATCH 0357/1001] PCI: Fix devm_pci_alloc_host_bridge() memory leak [ Upstream commit 3bbce531788719749520f28052cabdef16af6b16 ] Fix a memory leak by freeing the PCI resource list in devm_pci_release_host_bridge_dev(). Fixes: 5c3f18cce083 ("PCI: Add devm_pci_alloc_host_bridge() interface") Signed-off-by: Jan Kiszka Signed-off-by: Bjorn Helgaas Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/pci/probe.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f285cd74088e..4bccaf688aad 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -516,12 +516,14 @@ static void devm_pci_release_host_bridge_dev(struct device *dev) if (bridge->release_fn) bridge->release_fn(bridge); + + pci_free_resource_list(&bridge->windows); } static void pci_release_host_bridge_dev(struct device *dev) { devm_pci_release_host_bridge_dev(dev); - pci_free_host_bridge(to_pci_host_bridge(dev)); + kfree(to_pci_host_bridge(dev)); } struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) -- GitLab From 59b837d5927cfa03867931aed336ac0c9fa9700c Mon Sep 17 00:00:00 2001 From: Ethan Lien Date: Mon, 28 May 2018 13:48:20 +0800 Subject: [PATCH 0358/1001] btrfs: balance dirty metadata pages in btrfs_finish_ordered_io [ Upstream commit e73e81b6d0114d4a303205a952ab2e87c44bd279 ] [Problem description and how we fix it] We should balance dirty metadata pages at the end of btrfs_finish_ordered_io, since a small, unmergeable random write can potentially produce dirty metadata which is multiple times larger than the data itself. For example, a small, unmergeable 4KiB write may produce: 16KiB dirty leaf (and possibly 16KiB dirty node) in subvolume tree 16KiB dirty leaf (and possibly 16KiB dirty node) in checksum tree 16KiB dirty leaf (and possibly 16KiB dirty node) in extent tree Although we do call balance dirty pages in write side, but in the buffered write path, most metadata are dirtied only after we reach the dirty background limit (which by far only counts dirty data pages) and wakeup the flusher thread. If there are many small, unmergeable random writes spread in a large btree, we'll find a burst of dirty pages exceeds the dirty_bytes limit after we wakeup the flusher thread - which is not what we expect. In our machine, it caused out-of-memory problem since a page cannot be dropped if it is marked dirty. Someone may worry about we may sleep in btrfs_btree_balance_dirty_nodelay, but since we do btrfs_finish_ordered_io in a separate worker, it will not stop the flusher consuming dirty pages. Also, we use different worker for metadata writeback endio, sleep in btrfs_finish_ordered_io help us throttle the size of dirty metadata pages. [Reproduce steps] To reproduce the problem, we need to do 4KiB write randomly spread in a large btree. In our 2GiB RAM machine: 1) Create 4 subvolumes. 2) Run fio on each subvolume: [global] direct=0 rw=randwrite ioengine=libaio bs=4k iodepth=16 numjobs=1 group_reporting size=128G runtime=1800 norandommap time_based randrepeat=0 3) Take snapshot on each subvolume and repeat fio on existing files. 4) Repeat step (3) until we get large btrees. In our case, by observing btrfs_root_item->bytes_used, we have 2GiB of metadata in each subvolume tree and 12GiB of metadata in extent tree. 5) Stop all fio, take snapshot again, and wait until all delayed work is completed. 6) Start all fio. Few seconds later we hit OOM when the flusher starts to work. It can be reproduced even when using nocow write. Signed-off-by: Ethan Lien Reviewed-by: David Sterba [ add comment ] Signed-off-by: David Sterba Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/inode.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index f5b90dc137ec..3d339b41f5b3 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3162,6 +3162,9 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) /* once for the tree */ btrfs_put_ordered_extent(ordered_extent); + /* Try to release some metadata so we don't get an OOM but don't wait */ + btrfs_btree_balance_dirty_nodelay(fs_info); + return ret; } -- GitLab From 73425f6ad6ebaf08db227748c69dbd4bbfd09d0d Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Thu, 22 Mar 2018 14:14:45 +0200 Subject: [PATCH 0359/1001] iwlwifi: pcie: fix race in Rx buffer allocator [ Upstream commit 0f22e40053bd5378ad1e3250e65c574fd61c0cd6 ] Make sure the rx_allocator worker is canceled before running the rx_init routine. rx_init frees and re-allocates all rxb's pages. The rx_allocator worker also allocates pages for the used rxb's. Running rx_init and rx_allocator simultaniously causes a kernel panic. Fix that by canceling the work in rx_init. Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index a06b6612b658..ca99c3cf41c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -901,6 +901,8 @@ static int _iwl_pcie_rx_init(struct iwl_trans *trans) } def_rxq = trans_pcie->rxq; + cancel_work_sync(&rba->rx_alloc); + spin_lock(&rba->lock); atomic_set(&rba->req_pending, 0); atomic_set(&rba->req_ready, 0); -- GitLab From 678e64c63217eb7a88eb77613979ac9037357cf7 Mon Sep 17 00:00:00 2001 From: Thierry Escande Date: Tue, 29 May 2018 18:37:16 +0200 Subject: [PATCH 0360/1001] Bluetooth: hci_qca: Fix "Sleep inside atomic section" warning [ Upstream commit 9960521c44a5d828f29636ceac0600603ecbddbf ] This patch fixes the following warning during boot: do not call blocking ops when !TASK_RUNNING; state=1 set at [<(ptrval)>] qca_setup+0x194/0x750 [hci_uart] WARNING: CPU: 2 PID: 1878 at kernel/sched/core.c:6135 __might_sleep+0x7c/0x88 In qca_set_baudrate(), the current task state is set to TASK_UNINTERRUPTIBLE before going to sleep for 300ms. It was then restored to TASK_INTERRUPTIBLE. This patch sets the current task state back to TASK_RUNNING instead. Signed-off-by: Thierry Escande Signed-off-by: Marcel Holtmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/hci_qca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 6f4ebd5e54c8..a6173ddfb5a7 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -881,7 +881,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate) */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(msecs_to_jiffies(BAUDRATE_SETTLE_TIMEOUT_MS)); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_RUNNING); return 0; } -- GitLab From 5650a9be9635f574b8e5e8b38981324ffb283140 Mon Sep 17 00:00:00 2001 From: Jian-Hong Pan Date: Mon, 21 May 2018 18:09:20 +0800 Subject: [PATCH 0361/1001] Bluetooth: btusb: Add a new Realtek 8723DE ID 2ff8:b011 [ Upstream commit 66d9975c5a7c40aa7e4bb0ec0b0c37ba1f190923 ] Without this patch we cannot turn on the Bluethooth adapter on ASUS E406MA. T: Bus=01 Lev=01 Prnt=01 Port=00 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=2ff8 ProdID=b011 Rev= 2.00 S: Manufacturer=Realtek S: Product=802.11n WLAN Adapter S: SerialNumber=00e04c000001 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Jian-Hong Pan Signed-off-by: Marcel Holtmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btusb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 86d7975afaeb..d89a674604b8 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -373,6 +373,9 @@ static const struct usb_device_id blacklist_table[] = { /* Additional Realtek 8723BU Bluetooth devices */ { USB_DEVICE(0x7392, 0xa611), .driver_info = BTUSB_REALTEK }, + /* Additional Realtek 8723DE Bluetooth devices */ + { USB_DEVICE(0x2ff8, 0xb011), .driver_info = BTUSB_REALTEK }, + /* Additional Realtek 8821AE Bluetooth devices */ { USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x13d3, 0x3414), .driver_info = BTUSB_REALTEK }, -- GitLab From 3d4837733945a7d9505fd08db34b4188ca59e854 Mon Sep 17 00:00:00 2001 From: Kai Chieh Chuang Date: Mon, 28 May 2018 10:18:18 +0800 Subject: [PATCH 0362/1001] ASoC: dpcm: fix BE dai not hw_free and shutdown [ Upstream commit 9c0ac70ad24d76b873c1551e27790c7f6a815d5c ] In case, one BE is used by two FE1/FE2 FE1--->BE--> | FE2----] when FE1/FE2 call dpcm_be_dai_hw_free() together the BE users will be 2 (> 1), hence cannot be hw_free the be state will leave at, ex. SND_SOC_DPCM_STATE_STOP later FE1/FE2 call dpcm_be_dai_shutdown(), will be skip due to wrong state. leaving the BE not being hw_free and shutdown. The BE dai will be hw_free later when calling dpcm_be_dai_shutdown() if still in invalid state. Signed-off-by: KaiChieh Chuang Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/soc-pcm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 94b88b897c3b..3d0dab8282ad 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1779,8 +1779,10 @@ int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream) continue; if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && - (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) - continue; + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) { + soc_pcm_hw_free(be_substream); + be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; + } dev_dbg(be->dev, "ASoC: close BE %s\n", be->dai_link->name); -- GitLab From 6648fdc71138caf906bfa0a96b383a7d0dee270f Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Wed, 18 Apr 2018 12:23:58 +0200 Subject: [PATCH 0363/1001] mfd: cros_ec: Fail early if we cannot identify the EC [ Upstream commit 0dbbf25561b29ffab5ba6277429760abdf49ceff ] If we cannot communicate with the EC chip to detect the protocol version and its features, it's very likely useless to continue. Else we will commit all kind of uninformed mistakes (using the wrong protocol, the wrong buffer size, mixing the EC with other chips). Signed-off-by: Vincent Palatin Acked-by: Benson Leung Signed-off-by: Enric Balletbo i Serra Reviewed-by: Gwendal Grignou Reviewed-by: Andy Shevchenko Signed-off-by: Lee Jones Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/cros_ec.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index b0ca5a4c841e..c5528ae982f2 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -112,7 +112,11 @@ int cros_ec_register(struct cros_ec_device *ec_dev) mutex_init(&ec_dev->lock); - cros_ec_query_all(ec_dev); + err = cros_ec_query_all(ec_dev); + if (err) { + dev_err(dev, "Cannot identify the EC: error %d\n", err); + return err; + } if (ec_dev->irq) { err = request_threaded_irq(ec_dev->irq, NULL, ec_irq_thread, -- GitLab From 852feed35dcdec8521c2f3227545ad2a187a2b3b Mon Sep 17 00:00:00 2001 From: Ganapathi Bhat Date: Thu, 24 May 2018 19:18:27 +0530 Subject: [PATCH 0364/1001] mwifiex: handle race during mwifiex_usb_disconnect [ Upstream commit b817047ae70c0bd67b677b65d0d69d72cd6e9728 ] Race condition is observed during rmmod of mwifiex_usb: 1. The rmmod thread will call mwifiex_usb_disconnect(), download SHUTDOWN command and do wait_event_interruptible_timeout(), waiting for response. 2. The main thread will handle the response and will do a wake_up_interruptible(), unblocking rmmod thread. 3. On getting unblocked, rmmod thread will make rx_cmd.urb = NULL in mwifiex_usb_free(). 4. The main thread will try to resubmit rx_cmd.urb in mwifiex_usb_submit_rx_urb(), which is NULL. To fix, wait for main thread to complete before calling mwifiex_usb_free(). Signed-off-by: Ganapathi Bhat Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/marvell/mwifiex/usb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index f4f2b9b27e32..50890cab8807 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -644,6 +644,9 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf) MWIFIEX_FUNC_SHUTDOWN); } + if (adapter->workqueue) + flush_workqueue(adapter->workqueue); + mwifiex_usb_free(card); mwifiex_dbg(adapter, FATAL, -- GitLab From 6f8688bf299b35b5d585a96fa670ea257257fbd3 Mon Sep 17 00:00:00 2001 From: Eyal Reizer Date: Mon, 28 May 2018 11:36:42 +0300 Subject: [PATCH 0365/1001] wlcore: sdio: check for valid platform device data before suspend [ Upstream commit 6e91d48371e79862ea2c05867aaebe4afe55a865 ] the wl pointer can be null In case only wlcore_sdio is probed while no WiLink module is successfully probed, as in the case of mounting a wl12xx module while using a device tree file configured with wl18xx related settings. In this case the system was crashing in wl1271_suspend() as platform device data is not set. Make sure wl the pointer is valid before using it. Signed-off-by: Eyal Reizer Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ti/wlcore/sdio.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index f8a1fea64e25..219d1a86b92e 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -406,6 +406,11 @@ static int wl1271_suspend(struct device *dev) mmc_pm_flag_t sdio_flags; int ret = 0; + if (!wl) { + dev_err(dev, "no wilink module was probed\n"); + goto out; + } + dev_dbg(dev, "wl1271 suspend. wow_enabled: %d\n", wl->wow_enabled); -- GitLab From 1a95962bf210b6d763113d595e74223341492684 Mon Sep 17 00:00:00 2001 From: Fuyun Liang Date: Fri, 25 May 2018 19:43:02 +0100 Subject: [PATCH 0366/1001] net: hns3: Fixes the init of the VALID BD info in the descriptor [ Upstream commit 7d0b130cbbfa4651cc1ab9268a2956c1b9d82ff9 ] RX Buffer Descriptor contains a VALID bit which indicates if the BD is valid and has some data. This field is set by HNS3 hardware to intimate the driver of some valid data present in the BD. nd should be reset by the driver when BD is being used again. In the existing code this bit was not being (re-)initialized properly and hence was causing problems. Fixes: 76ad4f0ee747 ("net: hns3: Add support of HNS3 Ethernet Driver for hip08 SoC") Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c index d1e4dcec5db2..9f8c56f9e9c1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c @@ -1598,6 +1598,7 @@ static void hns3_replace_buffer(struct hns3_enet_ring *ring, int i, hns3_unmap_buffer(ring, &ring->desc_cb[i]); ring->desc_cb[i] = *res_cb; ring->desc[i].addr = cpu_to_le64(ring->desc_cb[i].dma); + ring->desc[i].rx.bd_base_info = 0; } static void hns3_reuse_buffer(struct hns3_enet_ring *ring, int i) @@ -1605,6 +1606,7 @@ static void hns3_reuse_buffer(struct hns3_enet_ring *ring, int i) ring->desc_cb[i].reuse_flag = 0; ring->desc[i].addr = cpu_to_le64(ring->desc_cb[i].dma + ring->desc_cb[i].page_offset); + ring->desc[i].rx.bd_base_info = 0; } static void hns3_nic_reclaim_one_desc(struct hns3_enet_ring *ring, int *bytes, -- GitLab From b7ffc03574f84c616d64e00b4ec3c4c46743b95f Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Fri, 18 May 2018 17:07:48 -0400 Subject: [PATCH 0367/1001] media: tw686x: Fix incorrect vb2_mem_ops GFP flags [ Upstream commit 636757ab6c93e19e2f58d3b3af1312e34eaffbab ] When the driver is configured in the "memcpy" dma-mode, it uses vb2_vmalloc_memops, which is backed by a SLAB allocator and so shouldn't be using GFP_DMA32. Fix it. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/pci/tw686x/tw686x-video.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c index c3fafa97b2d0..0ea8dd44026c 100644 --- a/drivers/media/pci/tw686x/tw686x-video.c +++ b/drivers/media/pci/tw686x/tw686x-video.c @@ -1228,7 +1228,8 @@ int tw686x_video_init(struct tw686x_dev *dev) vc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; vc->vidq.min_buffers_needed = 2; vc->vidq.lock = &vc->vb_mutex; - vc->vidq.gfp_flags = GFP_DMA32; + vc->vidq.gfp_flags = dev->dma_mode != TW686X_DMA_MODE_MEMCPY ? + GFP_DMA32 : 0; vc->vidq.dev = &dev->pci_dev->dev; err = vb2_queue_init(&vc->vidq); -- GitLab From 9aecdc961e6a863866dcbc389b4d5324937a73ad Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 21 May 2018 08:43:02 -0400 Subject: [PATCH 0368/1001] media: videobuf2-core: don't call memop 'finish' when queueing [ Upstream commit 90b2da89a083e1395cb322521a42397c49ae4500 ] When a buffer is queued or requeued in vb2_buffer_done, then don't call the finish memop. In this case the buffer is only returned to vb2, not to userspace. Calling 'finish' here will cause an unbalance when the queue is canceled, since the core will call the same memop again. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/videobuf2-core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index ffbb178c6918..2dbf632c10de 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -912,9 +912,12 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) dprintk(4, "done processing on buffer %d, state: %d\n", vb->index, state); - /* sync buffers */ - for (plane = 0; plane < vb->num_planes; ++plane) - call_void_memop(vb, finish, vb->planes[plane].mem_priv); + if (state != VB2_BUF_STATE_QUEUED && + state != VB2_BUF_STATE_REQUEUEING) { + /* sync buffers */ + for (plane = 0; plane < vb->num_planes; ++plane) + call_void_memop(vb, finish, vb->planes[plane].mem_priv); + } spin_lock_irqsave(&q->done_lock, flags); if (state == VB2_BUF_STATE_QUEUED || -- GitLab From ef61d940cd9684ebb910b12d4d0936c2ffc1f811 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Fri, 11 May 2018 13:13:35 -0700 Subject: [PATCH 0369/1001] Btrfs: don't return ino to ino cache if inode item removal fails [ Upstream commit c08db7d8d295a4f3a10faaca376de011afff7950 ] In btrfs_evict_inode(), if btrfs_truncate_inode_items() fails, the inode item will still be in the tree but we still return the ino to the ino cache. That will blow up later when someone tries to allocate that ino, so don't return it to the cache. Fixes: 581bb050941b ("Btrfs: Cache free inode numbers in memory") Reviewed-by: Josef Bacik Signed-off-by: Omar Sandoval Signed-off-by: David Sterba Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/inode.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 3d339b41f5b3..e61044d14cd7 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5499,13 +5499,18 @@ void btrfs_evict_inode(struct inode *inode) trans->block_rsv = rsv; ret = btrfs_truncate_inode_items(trans, root, inode, 0, 0); - if (ret != -ENOSPC && ret != -EAGAIN) + if (ret) { + trans->block_rsv = &fs_info->trans_block_rsv; + btrfs_end_transaction(trans); + btrfs_btree_balance_dirty(fs_info); + if (ret != -ENOSPC && ret != -EAGAIN) { + btrfs_orphan_del(NULL, BTRFS_I(inode)); + btrfs_free_block_rsv(fs_info, rsv); + goto no_delete; + } + } else { break; - - trans->block_rsv = &fs_info->trans_block_rsv; - btrfs_end_transaction(trans); - trans = NULL; - btrfs_btree_balance_dirty(fs_info); + } } btrfs_free_block_rsv(fs_info, rsv); @@ -5514,12 +5519,8 @@ void btrfs_evict_inode(struct inode *inode) * Errors here aren't a big deal, it just means we leave orphan items * in the tree. They will be cleaned up on the next mount. */ - if (ret == 0) { - trans->block_rsv = root->orphan_block_rsv; - btrfs_orphan_del(trans, BTRFS_I(inode)); - } else { - btrfs_orphan_del(NULL, BTRFS_I(inode)); - } + trans->block_rsv = root->orphan_block_rsv; + btrfs_orphan_del(trans, BTRFS_I(inode)); trans->block_rsv = &fs_info->trans_block_rsv; if (!(root == fs_info->tree_root || -- GitLab From 3bf165384e82f70571ba2f439391dab86eddb23d Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Fri, 11 May 2018 13:13:31 -0700 Subject: [PATCH 0370/1001] Btrfs: don't BUG_ON() in btrfs_truncate_inode_items() [ Upstream commit 0552210997badb6a60740a26ff9d976a416510f0 ] btrfs_free_extent() can fail because of ENOMEM. There's no reason to panic here, we can just abort the transaction. Fixes: f4b9aa8d3b87 ("btrfs_truncate") Reviewed-by: Nikolay Borisov Signed-off-by: Omar Sandoval Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/inode.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index e61044d14cd7..28a58f40f3a4 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4740,7 +4740,10 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, extent_num_bytes, 0, btrfs_header_owner(leaf), ino, extent_offset); - BUG_ON(ret); + if (ret) { + btrfs_abort_transaction(trans, ret); + break; + } if (btrfs_should_throttle_delayed_refs(trans, fs_info)) btrfs_async_run_delayed_refs(fs_info, trans->delayed_ref_updates * 2, -- GitLab From 31371d2dad493ce0bc7892cb6c1c3f5f397e12b9 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Tue, 24 Apr 2018 14:53:56 +0200 Subject: [PATCH 0371/1001] btrfs: add barriers to btrfs_sync_log before log_commit_wait wakeups [ Upstream commit 3d3a2e610ea5e7c6d4f9481ecce5d8e2d8317843 ] Currently the code assumes that there's an implied barrier by the sequence of code preceding the wakeup, namely the mutex unlock. As Nikolay pointed out: I think this is wrong (not your code) but the original assumption that the RELEASE semantics provided by mutex_unlock is sufficient. According to memory-barriers.txt: Section 'LOCK ACQUISITION FUNCTIONS' states: (2) RELEASE operation implication: Memory operations issued before the RELEASE will be completed before the RELEASE operation has completed. Memory operations issued after the RELEASE *may* be completed before the RELEASE operation has completed. (I've bolded the may portion) The example given there: As an example, consider the following: *A = a; *B = b; ACQUIRE *C = c; *D = d; RELEASE *E = e; *F = f; The following sequence of events is acceptable: ACQUIRE, {*F,*A}, *E, {*C,*D}, *B, RELEASE So if we assume that *C is modifying the flag which the waitqueue is checking, and *E is the actual wakeup, then those accesses can be re-ordered... IMHO this code should be considered broken... Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/tree-log.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index bf4e22df7c97..e1b4a59485df 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -3041,8 +3041,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, mutex_unlock(&log_root_tree->log_mutex); /* - * The barrier before waitqueue_active is implied by mutex_unlock + * The barrier before waitqueue_active is needed so all the updates + * above are seen by the woken threads. It might not be necessary, but + * proving that seems to be hard. */ + smp_mb(); if (waitqueue_active(&log_root_tree->log_commit_wait[index2])) wake_up(&log_root_tree->log_commit_wait[index2]); out: @@ -3053,8 +3056,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, mutex_unlock(&root->log_mutex); /* - * The barrier before waitqueue_active is implied by mutex_unlock + * The barrier before waitqueue_active is needed so all the updates + * above are seen by the woken threads. It might not be necessary, but + * proving that seems to be hard. */ + smp_mb(); if (waitqueue_active(&root->log_commit_wait[index1])) wake_up(&root->log_commit_wait[index1]); return ret; -- GitLab From 2737a4adec5a8903e7fa2ddd8368dff1ad658fe7 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Mon, 14 May 2018 09:38:13 +0800 Subject: [PATCH 0372/1001] btrfs: qgroup: Finish rescan when hit the last leaf of extent tree [ Upstream commit ff3d27a048d926b3920ccdb75d98788c567cae0d ] Under the following case, qgroup rescan can double account cowed tree blocks: In this case, extent tree only has one tree block. - | transid=5 last committed=4 | btrfs_qgroup_rescan_worker() | |- btrfs_start_transaction() | | transid = 5 | |- qgroup_rescan_leaf() | |- btrfs_search_slot_for_read() on extent tree | Get the only extent tree block from commit root (transid = 4). | Scan it, set qgroup_rescan_progress to the last | EXTENT/META_ITEM + 1 | now qgroup_rescan_progress = A + 1. | | fs tree get CoWed, new tree block is at A + 16K | transid 5 get committed - | transid=6 last committed=5 | btrfs_qgroup_rescan_worker() | btrfs_qgroup_rescan_worker() | |- btrfs_start_transaction() | | transid = 5 | |- qgroup_rescan_leaf() | |- btrfs_search_slot_for_read() on extent tree | Get the only extent tree block from commit root (transid = 5). | scan it using qgroup_rescan_progress (A + 1). | found new tree block beyong A, and it's fs tree block, | account it to increase qgroup numbers. - In above case, tree block A, and tree block A + 16K get accounted twice, while qgroup rescan should stop when it already reach the last leaf, other than continue using its qgroup_rescan_progress. Such case could happen by just looping btrfs/017 and with some possibility it can hit such double qgroup accounting problem. Fix it by checking the path to determine if we should finish qgroup rescan, other than relying on next loop to exit. Reported-by: Nikolay Borisov Signed-off-by: Qu Wenruo Signed-off-by: David Sterba Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/qgroup.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index e172d4843eae..473ad5985aa3 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -2499,6 +2499,21 @@ void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info, spin_unlock(&fs_info->qgroup_lock); } +/* + * Check if the leaf is the last leaf. Which means all node pointers + * are at their last position. + */ +static bool is_last_leaf(struct btrfs_path *path) +{ + int i; + + for (i = 1; i < BTRFS_MAX_LEVEL && path->nodes[i]; i++) { + if (path->slots[i] != btrfs_header_nritems(path->nodes[i]) - 1) + return false; + } + return true; +} + /* * returns < 0 on error, 0 when more leafs are to be scanned. * returns 1 when done. @@ -2512,6 +2527,7 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path, struct ulist *roots = NULL; struct seq_list tree_mod_seq_elem = SEQ_LIST_INIT(tree_mod_seq_elem); u64 num_bytes; + bool done; int slot; int ret; @@ -2540,6 +2556,7 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path, mutex_unlock(&fs_info->qgroup_rescan_lock); return ret; } + done = is_last_leaf(path); btrfs_item_key_to_cpu(path->nodes[0], &found, btrfs_header_nritems(path->nodes[0]) - 1); @@ -2586,6 +2603,8 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path, } btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem); + if (done && !ret) + ret = 1; return ret; } -- GitLab From 652b94b72696e6cbe7332a461b535657de23fcbe Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 24 May 2018 10:44:20 -0500 Subject: [PATCH 0373/1001] x86/microcode: Make the late update update_lock a raw lock for RT [ Upstream commit ff987fcf011d20c53b3a613edf6e2055ea48e26e ] __reload_late() is called from stop_machine context and thus cannot acquire a non-raw spinlock on PREEMPT_RT. Signed-off-by: Scott Wood Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Acked-by: Thomas Gleixner Cc: Ashok Raj Cc: Clark Williams Cc: Pei Zhang Cc: x86-ml Link: http://lkml.kernel.org/r/20180524154420.24455-1-swood@redhat.com Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/microcode/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index c8e0cda0f272..4fc0e08a30b9 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -70,7 +70,7 @@ static DEFINE_MUTEX(microcode_mutex); /* * Serialize late loading so that CPUs get updated one-by-one. */ -static DEFINE_SPINLOCK(update_lock); +static DEFINE_RAW_SPINLOCK(update_lock); struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; @@ -560,9 +560,9 @@ static int __reload_late(void *info) if (__wait_for_cpus(&late_cpus_in, NSEC_PER_SEC)) return -1; - spin_lock(&update_lock); + raw_spin_lock(&update_lock); apply_microcode_local(&err); - spin_unlock(&update_lock); + raw_spin_unlock(&update_lock); /* siblings return UCODE_OK because their engine got updated already */ if (err > UCODE_NFOUND) { -- GitLab From d93663a78783621895afd0999272c2ab8bad82cd Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 25 May 2018 11:46:48 +0200 Subject: [PATCH 0374/1001] PM / wakeup: Make s2idle_lock a RAW_SPINLOCK [ Upstream commit 62fc00a6611a0014c85763f9def1fc07c15d1302 ] The `s2idle_lock' is acquired during suspend while interrupts are disabled even on RT. The lock is acquired for short sections only. Make it a RAW lock which avoids "sleeping while atomic" warnings on RT. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/power/suspend.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 0685c4499431..c0bc2c89697a 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -60,7 +60,7 @@ static const struct platform_s2idle_ops *s2idle_ops; static DECLARE_WAIT_QUEUE_HEAD(s2idle_wait_head); enum s2idle_states __read_mostly s2idle_state; -static DEFINE_SPINLOCK(s2idle_lock); +static DEFINE_RAW_SPINLOCK(s2idle_lock); void s2idle_set_ops(const struct platform_s2idle_ops *ops) { @@ -78,12 +78,12 @@ static void s2idle_enter(void) { trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_TO_IDLE, true); - spin_lock_irq(&s2idle_lock); + raw_spin_lock_irq(&s2idle_lock); if (pm_wakeup_pending()) goto out; s2idle_state = S2IDLE_STATE_ENTER; - spin_unlock_irq(&s2idle_lock); + raw_spin_unlock_irq(&s2idle_lock); get_online_cpus(); cpuidle_resume(); @@ -97,11 +97,11 @@ static void s2idle_enter(void) cpuidle_pause(); put_online_cpus(); - spin_lock_irq(&s2idle_lock); + raw_spin_lock_irq(&s2idle_lock); out: s2idle_state = S2IDLE_STATE_NONE; - spin_unlock_irq(&s2idle_lock); + raw_spin_unlock_irq(&s2idle_lock); trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_TO_IDLE, false); } @@ -156,12 +156,12 @@ void s2idle_wake(void) { unsigned long flags; - spin_lock_irqsave(&s2idle_lock, flags); + raw_spin_lock_irqsave(&s2idle_lock, flags); if (s2idle_state > S2IDLE_STATE_NONE) { s2idle_state = S2IDLE_STATE_WAKE; wake_up(&s2idle_wait_head); } - spin_unlock_irqrestore(&s2idle_lock, flags); + raw_spin_unlock_irqrestore(&s2idle_lock, flags); } EXPORT_SYMBOL_GPL(s2idle_wake); -- GitLab From 2040b0d8c9c0aa2e50b733c0ecd12d8605d8a66d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 18 May 2018 18:56:24 +0200 Subject: [PATCH 0375/1001] PCI: Prevent sysfs disable of device while driver is attached [ Upstream commit 6f5cdfa802733dcb561bf664cc89d203f2fd958f ] Manipulating the enable_cnt behind the back of the driver will wreak complete havoc with the kernel state, so disallow it. Signed-off-by: Christoph Hellwig Signed-off-by: Bjorn Helgaas Reviewed-by: Johannes Thumshirn Acked-by: Keith Busch Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-sysfs.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 00fa4278c1f4..c3f0473d1afa 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -305,13 +305,16 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (!val) { - if (pci_is_enabled(pdev)) - pci_disable_device(pdev); - else - result = -EIO; - } else + device_lock(dev); + if (dev->driver) + result = -EBUSY; + else if (val) result = pci_enable_device(pdev); + else if (pci_is_enabled(pdev)) + pci_disable_device(pdev); + else + result = -EIO; + device_unlock(dev); return result < 0 ? result : count; } -- GitLab From 4bb1acf80c7fb05994955a26d7e40594ff6e9a9a Mon Sep 17 00:00:00 2001 From: Jianchao Wang Date: Thu, 24 May 2018 09:27:38 +0800 Subject: [PATCH 0376/1001] nvme-rdma: stop admin queue before freeing it [ Upstream commit 2e050f00a0f0e07467050cb4afae0234941e5bf3 ] For any failure after nvme_rdma_start_queue in nvme_rdma_configure_admin_queue, the admin queue will be freed with the NVME_RDMA_Q_LIVE flag still set. Once nvme_rdma_stop_queue is invoked, that will cause a use-after-free. BUG: KASAN: use-after-free in rdma_disconnect+0x1f/0xe0 [rdma_cm] To fix it, call nvme_rdma_stop_queue for all the failed cases after nvme_rdma_start_queue. Signed-off-by: Jianchao Wang Suggested-by: Sagi Grimberg Reviewed-by: Max Gurtovoy Signed-off-by: Christoph Hellwig Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/host/rdma.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 93a082e0bdd4..48a831d58e7a 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -796,7 +796,7 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl, if (error) { dev_err(ctrl->ctrl.device, "prop_get NVME_REG_CAP failed\n"); - goto out_cleanup_queue; + goto out_stop_queue; } ctrl->ctrl.sqsize = @@ -804,23 +804,25 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl, error = nvme_enable_ctrl(&ctrl->ctrl, ctrl->ctrl.cap); if (error) - goto out_cleanup_queue; + goto out_stop_queue; ctrl->ctrl.max_hw_sectors = (ctrl->max_fr_pages - 1) << (ilog2(SZ_4K) - 9); error = nvme_init_identify(&ctrl->ctrl); if (error) - goto out_cleanup_queue; + goto out_stop_queue; error = nvme_rdma_alloc_qe(ctrl->queues[0].device->dev, &ctrl->async_event_sqe, sizeof(struct nvme_command), DMA_TO_DEVICE); if (error) - goto out_cleanup_queue; + goto out_stop_queue; return 0; +out_stop_queue: + nvme_rdma_stop_queue(&ctrl->queues[0]); out_cleanup_queue: if (new) blk_cleanup_queue(ctrl->ctrl.admin_q); -- GitLab From 1afb8720b6943afe538b775fe3acbf367b772f4b Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 24 May 2018 16:16:04 -0600 Subject: [PATCH 0377/1001] nvme-pci: Fix AER reset handling [ Upstream commit 72cd4cc28e234ed7189ee508ed65ab60c80a97c8 ] The nvme timeout handling doesn't do anything if the pci channel is offline, which is the case when recovering from PCI error event, so it was a bad idea to sync the controller reset in this state. This patch flushes the reset work in the error_resume callback instead when the channel is back to online. This keeps AER handling serialized and can recover from timeouts. Link: https://bugzilla.kernel.org/show_bug.cgi?id=199757 Fixes: cc1d5e749a2e ("nvme/pci: Sync controller reset for AER slot_reset") Reported-by: Alex Gagniuc Tested-by: Alex Gagniuc Signed-off-by: Keith Busch Signed-off-by: Christoph Hellwig Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/host/pci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 4cac4755abef..6a76e3974240 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2519,6 +2519,9 @@ static pci_ers_result_t nvme_slot_reset(struct pci_dev *pdev) static void nvme_error_resume(struct pci_dev *pdev) { + struct nvme_dev *dev = pci_get_drvdata(pdev); + + flush_work(&dev->ctrl.reset_work); pci_cleanup_aer_uncorrect_error_status(pdev); } -- GitLab From be1c9763cbc749d1d646d0797ff07da24d4bdb46 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:11:30 +0300 Subject: [PATCH 0378/1001] ath: Add regulatory mapping for FCC3_ETSIC [ Upstream commit 01fb2994a98dc72c8818c274f7b5983d5dd885c7 ] The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this regdomain code are: * 2.4GHz: ETSI * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd_common.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index bdd2b4d61f2f..7d955fa8c24c 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -35,6 +35,7 @@ enum EnumRd { FRANCE_RES = 0x31, FCC3_FCCA = 0x3A, FCC3_WORLD = 0x3B, + FCC3_ETSIC = 0x3F, ETSI1_WORLD = 0x37, ETSI3_ETSIA = 0x32, @@ -168,6 +169,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {FCC2_ETSIC, CTL_FCC, CTL_ETSI}, {FCC3_FCCA, CTL_FCC, CTL_FCC}, {FCC3_WORLD, CTL_FCC, CTL_ETSI}, + {FCC3_ETSIC, CTL_FCC, CTL_ETSI}, {FCC4_FCCA, CTL_FCC, CTL_FCC}, {FCC5_FCCA, CTL_FCC, CTL_FCC}, {FCC6_FCCA, CTL_FCC, CTL_FCC}, -- GitLab From f198926d6a408d66d01ee59bf3db48361423becb Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:11:18 +0300 Subject: [PATCH 0379/1001] ath: Add regulatory mapping for ETSI8_WORLD [ Upstream commit 45faf6e096da8bb80e1ddf8c08a26a9601d9469e ] The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this regdomain code are: * 2.4GHz: ETSI * 5GHz: ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd_common.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 7d955fa8c24c..7c0fcbbf1900 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -45,6 +45,7 @@ enum EnumRd { ETSI4_ETSIC = 0x38, ETSI5_WORLD = 0x39, ETSI6_WORLD = 0x34, + ETSI8_WORLD = 0x3D, ETSI_RESERVED = 0x33, MKK1_MKKA = 0x40, @@ -181,6 +182,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {ETSI4_WORLD, CTL_ETSI, CTL_ETSI}, {ETSI5_WORLD, CTL_ETSI, CTL_ETSI}, {ETSI6_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI8_WORLD, CTL_ETSI, CTL_ETSI}, /* XXX: For ETSI3_ETSIA, Was NO_CTL meant for the 2 GHz band ? */ {ETSI3_ETSIA, CTL_ETSI, CTL_ETSI}, -- GitLab From cdd106451c6a8b7c56b2284ac51aac4d23e5854b Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:11:14 +0300 Subject: [PATCH 0380/1001] ath: Add regulatory mapping for APL13_WORLD [ Upstream commit 9ba8df0c52b3e6baa436374b429d3d73bd09a320 ] The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this regdomain code are: * 2.4GHz: ETSI * 5GHz: ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd_common.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 7c0fcbbf1900..2c873840a46a 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -69,6 +69,7 @@ enum EnumRd { APL1_ETSIC = 0x55, APL2_ETSIC = 0x56, APL5_WORLD = 0x58, + APL13_WORLD = 0x5A, APL6_WORLD = 0x5B, APL7_FCCA = 0x5C, APL8_WORLD = 0x5D, @@ -195,6 +196,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {APL3_WORLD, CTL_FCC, CTL_ETSI}, {APL4_WORLD, CTL_FCC, CTL_ETSI}, {APL5_WORLD, CTL_FCC, CTL_ETSI}, + {APL13_WORLD, CTL_ETSI, CTL_ETSI}, {APL6_WORLD, CTL_ETSI, CTL_ETSI}, {APL8_WORLD, CTL_ETSI, CTL_ETSI}, {APL9_WORLD, CTL_ETSI, CTL_ETSI}, -- GitLab From 3c51226005d940f901689ae76a01d73ae29f8e52 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:11:05 +0300 Subject: [PATCH 0381/1001] ath: Add regulatory mapping for APL2_FCCA [ Upstream commit 4f183687e3fad3ce0e06e38976cad81bc4541990 ] The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this regdomain code are: * 2.4GHz: FCC * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd_common.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 2c873840a46a..d8a7db4976f0 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -61,6 +61,7 @@ enum EnumRd { MKK1_MKKA1 = 0x4A, MKK1_MKKA2 = 0x4B, MKK1_MKKC = 0x4C, + APL2_FCCA = 0x4D, APL3_FCCA = 0x50, APL1_WORLD = 0x52, @@ -193,6 +194,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {FCC1_FCCA, CTL_FCC, CTL_FCC}, {APL1_WORLD, CTL_FCC, CTL_ETSI}, {APL2_WORLD, CTL_FCC, CTL_ETSI}, + {APL2_FCCA, CTL_FCC, CTL_FCC}, {APL3_WORLD, CTL_FCC, CTL_ETSI}, {APL4_WORLD, CTL_FCC, CTL_ETSI}, {APL5_WORLD, CTL_FCC, CTL_ETSI}, -- GitLab From 5e895c9cb8ca4c9b0c99cc48a3673e13a5020537 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:10:54 +0300 Subject: [PATCH 0382/1001] ath: Add regulatory mapping for Uganda [ Upstream commit 1ea3986ad2bc72081c69f3fbc1e5e0eeb3c44f17 ] The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: ETSI * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd.h | 1 + drivers/net/wireless/ath/regd_common.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 5d80be213fac..3555f5170cc6 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -175,6 +175,7 @@ enum CountryCode { CTRY_TUNISIA = 788, CTRY_TURKEY = 792, CTRY_UAE = 784, + CTRY_UGANDA = 800, CTRY_UKRAINE = 804, CTRY_UNITED_KINGDOM = 826, CTRY_UNITED_STATES = 840, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index d8a7db4976f0..cba1020bc854 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -467,6 +467,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT"}, {CTRY_TUNISIA, ETSI3_WORLD, "TN"}, {CTRY_TURKEY, ETSI3_WORLD, "TR"}, + {CTRY_UGANDA, FCC3_WORLD, "UG"}, {CTRY_UKRAINE, NULL1_WORLD, "UA"}, {CTRY_UAE, NULL1_WORLD, "AE"}, {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"}, -- GitLab From aafbcce424ecba10419a6303a67a184358f577e0 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:10:48 +0300 Subject: [PATCH 0383/1001] ath: Add regulatory mapping for Tanzania [ Upstream commit 667ddac5745fb9fddfe8f7fd2523070f50bd4442 ] The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: ETSI * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd.h | 1 + drivers/net/wireless/ath/regd_common.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 3555f5170cc6..74f745d9fab3 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -170,6 +170,7 @@ enum CountryCode { CTRY_SWITZERLAND = 756, CTRY_SYRIA = 760, CTRY_TAIWAN = 158, + CTRY_TANZANIA = 834, CTRY_THAILAND = 764, CTRY_TRINIDAD_Y_TOBAGO = 780, CTRY_TUNISIA = 788, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index cba1020bc854..b85dc86cc188 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -463,6 +463,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_SWITZERLAND, ETSI1_WORLD, "CH"}, {CTRY_SYRIA, NULL1_WORLD, "SY"}, {CTRY_TAIWAN, APL3_FCCA, "TW"}, + {CTRY_TANZANIA, APL1_WORLD, "TZ"}, {CTRY_THAILAND, FCC3_WORLD, "TH"}, {CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT"}, {CTRY_TUNISIA, ETSI3_WORLD, "TN"}, -- GitLab From c4b93c91bb63b5e3de43df9015bf3a1b0ddf7a47 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:10:43 +0300 Subject: [PATCH 0384/1001] ath: Add regulatory mapping for Serbia [ Upstream commit 2a3169a54bb53717928392a04fb84deb765b51f1 ] The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: ETSI * 5GHz: ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd.h | 1 + drivers/net/wireless/ath/regd_common.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 74f745d9fab3..b5764a38f90c 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -159,6 +159,7 @@ enum CountryCode { CTRY_ROMANIA = 642, CTRY_RUSSIA = 643, CTRY_SAUDI_ARABIA = 682, + CTRY_SERBIA = 688, CTRY_SERBIA_MONTENEGRO = 891, CTRY_SINGAPORE = 702, CTRY_SLOVAKIA = 703, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index b85dc86cc188..1ced5a323cf8 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -452,6 +452,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_ROMANIA, NULL1_WORLD, "RO"}, {CTRY_RUSSIA, NULL1_WORLD, "RU"}, {CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"}, + {CTRY_SERBIA, ETSI1_WORLD, "RS"}, {CTRY_SERBIA_MONTENEGRO, ETSI1_WORLD, "CS"}, {CTRY_SINGAPORE, APL6_WORLD, "SG"}, {CTRY_SLOVAKIA, ETSI1_WORLD, "SK"}, -- GitLab From 936058197fbb3ecf62bfa8a5eb493bd34d6eff72 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:09:59 +0300 Subject: [PATCH 0385/1001] ath: Add regulatory mapping for Bermuda [ Upstream commit 9c790f2d234f65697e3b0948adbfdf36dbe63dd7 ] The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: FCC * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd.h | 1 + drivers/net/wireless/ath/regd_common.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index b5764a38f90c..ab6b006d1534 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -74,6 +74,7 @@ enum CountryCode { CTRY_BELARUS = 112, CTRY_BELGIUM = 56, CTRY_BELIZE = 84, + CTRY_BERMUDA = 60, CTRY_BOLIVIA = 68, CTRY_BOSNIA_HERZ = 70, CTRY_BRAZIL = 76, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 1ced5a323cf8..e13b96e45d53 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -313,6 +313,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_BELGIUM, ETSI1_WORLD, "BE"}, {CTRY_BELGIUM2, ETSI4_WORLD, "BL"}, {CTRY_BELIZE, APL1_ETSIC, "BZ"}, + {CTRY_BERMUDA, FCC3_FCCA, "BM"}, {CTRY_BOLIVIA, APL1_ETSIC, "BO"}, {CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA"}, {CTRY_BRAZIL, FCC3_WORLD, "BR"}, -- GitLab From 935674605cf8db94d85a504cb3c4e4587052aeb8 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:09:53 +0300 Subject: [PATCH 0386/1001] ath: Add regulatory mapping for Bahamas [ Upstream commit 699e2302c286a14afe7b7394151ce6c4e1790cc1 ] The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: ETSI * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd.h | 1 + drivers/net/wireless/ath/regd_common.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index ab6b006d1534..869f276cc1d8 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -68,6 +68,7 @@ enum CountryCode { CTRY_AUSTRALIA = 36, CTRY_AUSTRIA = 40, CTRY_AZERBAIJAN = 31, + CTRY_BAHAMAS = 44, CTRY_BAHRAIN = 48, CTRY_BANGLADESH = 50, CTRY_BARBADOS = 52, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index e13b96e45d53..15bbd1e0d912 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -306,6 +306,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_AUSTRALIA2, FCC6_WORLD, "AU"}, {CTRY_AUSTRIA, ETSI1_WORLD, "AT"}, {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"}, + {CTRY_BAHAMAS, FCC3_WORLD, "BS"}, {CTRY_BAHRAIN, APL6_WORLD, "BH"}, {CTRY_BANGLADESH, NULL1_WORLD, "BD"}, {CTRY_BARBADOS, FCC2_WORLD, "BB"}, -- GitLab From c0ff32b7e85238baf1172304be65a256e6adca83 Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Thu, 22 Mar 2018 21:20:03 +0100 Subject: [PATCH 0387/1001] powerpc/32: Add a missing include header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit c89ca593220931c150cffda24b4d4ccf82f13fc8 ] The header file was missing from the includes. Fix the following warning, treated as error with W=1: arch/powerpc/kernel/pci_32.c:286:6: error: no previous prototype for ‘sys_pciconfig_iobase’ [-Werror=missing-prototypes] Signed-off-by: Mathieu Malaterre Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/pci_32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index 1d817f4d97d9..2094f2b249fd 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include -- GitLab From ee8c480702a62eb757effc81a6868407248363e3 Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Thu, 22 Mar 2018 21:19:56 +0100 Subject: [PATCH 0388/1001] powerpc/chrp/time: Make some functions static, add missing header include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit b87a358b4a1421abd544c0b554b1b7159b2b36c0 ] Add a missing include . These functions can all be static, make it so. Fix warnings treated as errors with W=1: arch/powerpc/platforms/chrp/time.c:41:13: error: no previous prototype for ‘chrp_time_init’ [-Werror=missing-prototypes] arch/powerpc/platforms/chrp/time.c:66:5: error: no previous prototype for ‘chrp_cmos_clock_read’ [-Werror=missing-prototypes] arch/powerpc/platforms/chrp/time.c:74:6: error: no previous prototype for ‘chrp_cmos_clock_write’ [-Werror=missing-prototypes] arch/powerpc/platforms/chrp/time.c:86:5: error: no previous prototype for ‘chrp_set_rtc_time’ [-Werror=missing-prototypes] arch/powerpc/platforms/chrp/time.c:130:6: error: no previous prototype for ‘chrp_get_rtc_time’ [-Werror=missing-prototypes] Signed-off-by: Mathieu Malaterre Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/chrp/time.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/chrp/time.c b/arch/powerpc/platforms/chrp/time.c index 03d115aaa191..acde7bbe0716 100644 --- a/arch/powerpc/platforms/chrp/time.c +++ b/arch/powerpc/platforms/chrp/time.c @@ -28,6 +28,8 @@ #include #include +#include + extern spinlock_t rtc_lock; #define NVRAM_AS0 0x74 @@ -63,7 +65,7 @@ long __init chrp_time_init(void) return 0; } -int chrp_cmos_clock_read(int addr) +static int chrp_cmos_clock_read(int addr) { if (nvram_as1 != 0) outb(addr>>8, nvram_as1); @@ -71,7 +73,7 @@ int chrp_cmos_clock_read(int addr) return (inb(nvram_data)); } -void chrp_cmos_clock_write(unsigned long val, int addr) +static void chrp_cmos_clock_write(unsigned long val, int addr) { if (nvram_as1 != 0) outb(addr>>8, nvram_as1); -- GitLab From d26f8af1a126c81b9b28ad7cf05fe946c845c428 Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Wed, 4 Apr 2018 22:13:05 +0200 Subject: [PATCH 0389/1001] powerpc/powermac: Add missing prototype for note_bootable_part() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit f72cf3f1d49f2c35d6cb682af2e8c93550f264e4 ] Add a missing prototype for function `note_bootable_part` to silence a warning treated as error with W=1: arch/powerpc/platforms/powermac/setup.c:361:12: error: no previous prototype for ‘note_bootable_part’ [-Werror=missing-prototypes] Suggested-by: Christophe Leroy Signed-off-by: Mathieu Malaterre Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powermac/setup.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index ab668cb72263..8b2eab1340f4 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -352,6 +352,7 @@ static int pmac_late_init(void) } machine_late_initcall(powermac, pmac_late_init); +void note_bootable_part(dev_t dev, int part, int goodness); /* * This is __ref because we check for "initializing" before * touching any of the __init sensitive things and "initializing" -- GitLab From 566be4969b839411244da8a80342e8da199d03d8 Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Wed, 4 Apr 2018 22:07:46 +0200 Subject: [PATCH 0390/1001] powerpc/powermac: Mark variable x as unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 5a4b475cf8511da721f20ba432c244061db7139f ] Since the value of x is never intended to be read, declare it with gcc attribute as unused. Fix warning treated as error with W=1: arch/powerpc/platforms/powermac/bootx_init.c:471:21: error: variable ‘x’ set but not used [-Werror=unused-but-set-variable] Suggested-by: Christophe Leroy Signed-off-by: Mathieu Malaterre Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powermac/bootx_init.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c index c3c9bbb3573a..ba0964c17620 100644 --- a/arch/powerpc/platforms/powermac/bootx_init.c +++ b/arch/powerpc/platforms/powermac/bootx_init.c @@ -468,7 +468,7 @@ void __init bootx_init(unsigned long r3, unsigned long r4) boot_infos_t *bi = (boot_infos_t *) r4; unsigned long hdr; unsigned long space; - unsigned long ptr, x; + unsigned long ptr; char *model; unsigned long offset = reloc_offset(); @@ -562,6 +562,8 @@ void __init bootx_init(unsigned long r3, unsigned long r4) * MMU switched OFF, so this should not be useful anymore. */ if (bi->version < 4) { + unsigned long x __maybe_unused; + bootx_printf("Touching pages...\n"); /* -- GitLab From 7eda318729800c9ef64483da1b9fea194edbb134 Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Fri, 6 Apr 2018 22:12:19 +0200 Subject: [PATCH 0391/1001] powerpc: Add __printf verification to prom_printf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit eae5f709a4d738c52b6ab636981755d76349ea9e ] __printf is useful to verify format and arguments. Fix arg mismatch reported by gcc, remove the following warnings (with W=1): arch/powerpc/kernel/prom_init.c:1467:31: error: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘long unsigned int’ arch/powerpc/kernel/prom_init.c:1471:31: error: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘long unsigned int’ arch/powerpc/kernel/prom_init.c:1504:33: error: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘long unsigned int’ arch/powerpc/kernel/prom_init.c:1505:33: error: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘long unsigned int’ arch/powerpc/kernel/prom_init.c:1506:33: error: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘long unsigned int’ arch/powerpc/kernel/prom_init.c:1507:33: error: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘long unsigned int’ arch/powerpc/kernel/prom_init.c:1508:33: error: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘long unsigned int’ arch/powerpc/kernel/prom_init.c:1509:33: error: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘long unsigned int’ arch/powerpc/kernel/prom_init.c:1975:39: error: format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 2 has type ‘unsigned int’ arch/powerpc/kernel/prom_init.c:1986:27: error: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘long unsigned int’ arch/powerpc/kernel/prom_init.c:2567:38: error: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘long unsigned int’ arch/powerpc/kernel/prom_init.c:2567:46: error: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘long unsigned int’ arch/powerpc/kernel/prom_init.c:2569:38: error: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘long unsigned int’ arch/powerpc/kernel/prom_init.c:2569:46: error: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘long unsigned int’ The patch also include arg mismatch fix for case with #define DEBUG_PROM (warning not listed here). This patch fix also the following warnings revealed by checkpatch: WARNING: Prefer using '"%s...", __func__' to using 'alloc_up', this function's name, in a string #101: FILE: arch/powerpc/kernel/prom_init.c:1235: + prom_debug("alloc_up(%lx, %lx)\n", size, align); and WARNING: Prefer using '"%s...", __func__' to using 'alloc_down', this function's name, in a string #138: FILE: arch/powerpc/kernel/prom_init.c:1278: + prom_debug("alloc_down(%lx, %lx, %s)\n", size, align, Signed-off-by: Mathieu Malaterre Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/prom_init.c | 114 ++++++++++++++++---------------- 1 file changed, 58 insertions(+), 56 deletions(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 02190e90c7ae..f8782c7ef50f 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -334,6 +334,7 @@ static void __init prom_print_dec(unsigned long val) call_prom("write", 3, 1, prom.stdout, buf+i, size); } +__printf(1, 2) static void __init prom_printf(const char *format, ...) { const char *p, *q, *s; @@ -1148,7 +1149,7 @@ static void __init prom_send_capabilities(void) */ cores = DIV_ROUND_UP(NR_CPUS, prom_count_smt_threads()); - prom_printf("Max number of cores passed to firmware: %lu (NR_CPUS = %lu)\n", + prom_printf("Max number of cores passed to firmware: %u (NR_CPUS = %d)\n", cores, NR_CPUS); ibm_architecture_vec.vec5.max_cpus = cpu_to_be32(cores); @@ -1230,7 +1231,7 @@ static unsigned long __init alloc_up(unsigned long size, unsigned long align) if (align) base = _ALIGN_UP(base, align); - prom_debug("alloc_up(%x, %x)\n", size, align); + prom_debug("%s(%lx, %lx)\n", __func__, size, align); if (ram_top == 0) prom_panic("alloc_up() called with mem not initialized\n"); @@ -1241,7 +1242,7 @@ static unsigned long __init alloc_up(unsigned long size, unsigned long align) for(; (base + size) <= alloc_top; base = _ALIGN_UP(base + 0x100000, align)) { - prom_debug(" trying: 0x%x\n\r", base); + prom_debug(" trying: 0x%lx\n\r", base); addr = (unsigned long)prom_claim(base, size, 0); if (addr != PROM_ERROR && addr != 0) break; @@ -1253,12 +1254,12 @@ static unsigned long __init alloc_up(unsigned long size, unsigned long align) return 0; alloc_bottom = addr + size; - prom_debug(" -> %x\n", addr); - prom_debug(" alloc_bottom : %x\n", alloc_bottom); - prom_debug(" alloc_top : %x\n", alloc_top); - prom_debug(" alloc_top_hi : %x\n", alloc_top_high); - prom_debug(" rmo_top : %x\n", rmo_top); - prom_debug(" ram_top : %x\n", ram_top); + prom_debug(" -> %lx\n", addr); + prom_debug(" alloc_bottom : %lx\n", alloc_bottom); + prom_debug(" alloc_top : %lx\n", alloc_top); + prom_debug(" alloc_top_hi : %lx\n", alloc_top_high); + prom_debug(" rmo_top : %lx\n", rmo_top); + prom_debug(" ram_top : %lx\n", ram_top); return addr; } @@ -1273,7 +1274,7 @@ static unsigned long __init alloc_down(unsigned long size, unsigned long align, { unsigned long base, addr = 0; - prom_debug("alloc_down(%x, %x, %s)\n", size, align, + prom_debug("%s(%lx, %lx, %s)\n", __func__, size, align, highmem ? "(high)" : "(low)"); if (ram_top == 0) prom_panic("alloc_down() called with mem not initialized\n"); @@ -1301,7 +1302,7 @@ static unsigned long __init alloc_down(unsigned long size, unsigned long align, base = _ALIGN_DOWN(alloc_top - size, align); for (; base > alloc_bottom; base = _ALIGN_DOWN(base - 0x100000, align)) { - prom_debug(" trying: 0x%x\n\r", base); + prom_debug(" trying: 0x%lx\n\r", base); addr = (unsigned long)prom_claim(base, size, 0); if (addr != PROM_ERROR && addr != 0) break; @@ -1312,12 +1313,12 @@ static unsigned long __init alloc_down(unsigned long size, unsigned long align, alloc_top = addr; bail: - prom_debug(" -> %x\n", addr); - prom_debug(" alloc_bottom : %x\n", alloc_bottom); - prom_debug(" alloc_top : %x\n", alloc_top); - prom_debug(" alloc_top_hi : %x\n", alloc_top_high); - prom_debug(" rmo_top : %x\n", rmo_top); - prom_debug(" ram_top : %x\n", ram_top); + prom_debug(" -> %lx\n", addr); + prom_debug(" alloc_bottom : %lx\n", alloc_bottom); + prom_debug(" alloc_top : %lx\n", alloc_top); + prom_debug(" alloc_top_hi : %lx\n", alloc_top_high); + prom_debug(" rmo_top : %lx\n", rmo_top); + prom_debug(" ram_top : %lx\n", ram_top); return addr; } @@ -1443,7 +1444,7 @@ static void __init prom_init_mem(void) if (size == 0) continue; - prom_debug(" %x %x\n", base, size); + prom_debug(" %lx %lx\n", base, size); if (base == 0 && (of_platform & PLATFORM_LPAR)) rmo_top = size; if ((base + size) > ram_top) @@ -1463,12 +1464,12 @@ static void __init prom_init_mem(void) if (prom_memory_limit) { if (prom_memory_limit <= alloc_bottom) { - prom_printf("Ignoring mem=%x <= alloc_bottom.\n", - prom_memory_limit); + prom_printf("Ignoring mem=%lx <= alloc_bottom.\n", + prom_memory_limit); prom_memory_limit = 0; } else if (prom_memory_limit >= ram_top) { - prom_printf("Ignoring mem=%x >= ram_top.\n", - prom_memory_limit); + prom_printf("Ignoring mem=%lx >= ram_top.\n", + prom_memory_limit); prom_memory_limit = 0; } else { ram_top = prom_memory_limit; @@ -1500,12 +1501,13 @@ static void __init prom_init_mem(void) alloc_bottom = PAGE_ALIGN(prom_initrd_end); prom_printf("memory layout at init:\n"); - prom_printf(" memory_limit : %x (16 MB aligned)\n", prom_memory_limit); - prom_printf(" alloc_bottom : %x\n", alloc_bottom); - prom_printf(" alloc_top : %x\n", alloc_top); - prom_printf(" alloc_top_hi : %x\n", alloc_top_high); - prom_printf(" rmo_top : %x\n", rmo_top); - prom_printf(" ram_top : %x\n", ram_top); + prom_printf(" memory_limit : %lx (16 MB aligned)\n", + prom_memory_limit); + prom_printf(" alloc_bottom : %lx\n", alloc_bottom); + prom_printf(" alloc_top : %lx\n", alloc_top); + prom_printf(" alloc_top_hi : %lx\n", alloc_top_high); + prom_printf(" rmo_top : %lx\n", rmo_top); + prom_printf(" ram_top : %lx\n", ram_top); } static void __init prom_close_stdin(void) @@ -1566,7 +1568,7 @@ static void __init prom_instantiate_opal(void) return; } - prom_printf("instantiating opal at 0x%x...", base); + prom_printf("instantiating opal at 0x%llx...", base); if (call_prom_ret("call-method", 4, 3, rets, ADDR("load-opal-runtime"), @@ -1582,10 +1584,10 @@ static void __init prom_instantiate_opal(void) reserve_mem(base, size); - prom_debug("opal base = 0x%x\n", base); - prom_debug("opal align = 0x%x\n", align); - prom_debug("opal entry = 0x%x\n", entry); - prom_debug("opal size = 0x%x\n", (long)size); + prom_debug("opal base = 0x%llx\n", base); + prom_debug("opal align = 0x%llx\n", align); + prom_debug("opal entry = 0x%llx\n", entry); + prom_debug("opal size = 0x%llx\n", size); prom_setprop(opal_node, "/ibm,opal", "opal-base-address", &base, sizeof(base)); @@ -1662,7 +1664,7 @@ static void __init prom_instantiate_rtas(void) prom_debug("rtas base = 0x%x\n", base); prom_debug("rtas entry = 0x%x\n", entry); - prom_debug("rtas size = 0x%x\n", (long)size); + prom_debug("rtas size = 0x%x\n", size); prom_debug("prom_instantiate_rtas: end...\n"); } @@ -1720,7 +1722,7 @@ static void __init prom_instantiate_sml(void) if (base == 0) prom_panic("Could not allocate memory for sml\n"); - prom_printf("instantiating sml at 0x%x...", base); + prom_printf("instantiating sml at 0x%llx...", base); memset((void *)base, 0, size); @@ -1739,8 +1741,8 @@ static void __init prom_instantiate_sml(void) prom_setprop(ibmvtpm_node, "/vdevice/vtpm", "linux,sml-size", &size, sizeof(size)); - prom_debug("sml base = 0x%x\n", base); - prom_debug("sml size = 0x%x\n", (long)size); + prom_debug("sml base = 0x%llx\n", base); + prom_debug("sml size = 0x%x\n", size); prom_debug("prom_instantiate_sml: end...\n"); } @@ -1841,7 +1843,7 @@ static void __init prom_initialize_tce_table(void) prom_debug("TCE table: %s\n", path); prom_debug("\tnode = 0x%x\n", node); - prom_debug("\tbase = 0x%x\n", base); + prom_debug("\tbase = 0x%llx\n", base); prom_debug("\tsize = 0x%x\n", minsize); /* Initialize the table to have a one-to-one mapping @@ -1928,12 +1930,12 @@ static void __init prom_hold_cpus(void) } prom_debug("prom_hold_cpus: start...\n"); - prom_debug(" 1) spinloop = 0x%x\n", (unsigned long)spinloop); - prom_debug(" 1) *spinloop = 0x%x\n", *spinloop); - prom_debug(" 1) acknowledge = 0x%x\n", + prom_debug(" 1) spinloop = 0x%lx\n", (unsigned long)spinloop); + prom_debug(" 1) *spinloop = 0x%lx\n", *spinloop); + prom_debug(" 1) acknowledge = 0x%lx\n", (unsigned long)acknowledge); - prom_debug(" 1) *acknowledge = 0x%x\n", *acknowledge); - prom_debug(" 1) secondary_hold = 0x%x\n", secondary_hold); + prom_debug(" 1) *acknowledge = 0x%lx\n", *acknowledge); + prom_debug(" 1) secondary_hold = 0x%lx\n", secondary_hold); /* Set the common spinloop variable, so all of the secondary cpus * will block when they are awakened from their OF spinloop. @@ -1961,7 +1963,7 @@ static void __init prom_hold_cpus(void) prom_getprop(node, "reg", ®, sizeof(reg)); cpu_no = be32_to_cpu(reg); - prom_debug("cpu hw idx = %lu\n", cpu_no); + prom_debug("cpu hw idx = %u\n", cpu_no); /* Init the acknowledge var which will be reset by * the secondary cpu when it awakens from its OF @@ -1971,7 +1973,7 @@ static void __init prom_hold_cpus(void) if (cpu_no != prom.cpu) { /* Primary Thread of non-boot cpu or any thread */ - prom_printf("starting cpu hw idx %lu... ", cpu_no); + prom_printf("starting cpu hw idx %u... ", cpu_no); call_prom("start-cpu", 3, 0, node, secondary_hold, cpu_no); @@ -1982,11 +1984,11 @@ static void __init prom_hold_cpus(void) if (*acknowledge == cpu_no) prom_printf("done\n"); else - prom_printf("failed: %x\n", *acknowledge); + prom_printf("failed: %lx\n", *acknowledge); } #ifdef CONFIG_SMP else - prom_printf("boot cpu hw idx %lu\n", cpu_no); + prom_printf("boot cpu hw idx %u\n", cpu_no); #endif /* CONFIG_SMP */ } @@ -2264,7 +2266,7 @@ static void __init *make_room(unsigned long *mem_start, unsigned long *mem_end, while ((*mem_start + needed) > *mem_end) { unsigned long room, chunk; - prom_debug("Chunk exhausted, claiming more at %x...\n", + prom_debug("Chunk exhausted, claiming more at %lx...\n", alloc_bottom); room = alloc_top - alloc_bottom; if (room > DEVTREE_CHUNK_SIZE) @@ -2490,7 +2492,7 @@ static void __init flatten_device_tree(void) room = alloc_top - alloc_bottom - 0x4000; if (room > DEVTREE_CHUNK_SIZE) room = DEVTREE_CHUNK_SIZE; - prom_debug("starting device tree allocs at %x\n", alloc_bottom); + prom_debug("starting device tree allocs at %lx\n", alloc_bottom); /* Now try to claim that */ mem_start = (unsigned long)alloc_up(room, PAGE_SIZE); @@ -2553,7 +2555,7 @@ static void __init flatten_device_tree(void) int i; prom_printf("reserved memory map:\n"); for (i = 0; i < mem_reserve_cnt; i++) - prom_printf(" %x - %x\n", + prom_printf(" %llx - %llx\n", be64_to_cpu(mem_reserve_map[i].base), be64_to_cpu(mem_reserve_map[i].size)); } @@ -2563,9 +2565,9 @@ static void __init flatten_device_tree(void) */ mem_reserve_cnt = MEM_RESERVE_MAP_SIZE; - prom_printf("Device tree strings 0x%x -> 0x%x\n", + prom_printf("Device tree strings 0x%lx -> 0x%lx\n", dt_string_start, dt_string_end); - prom_printf("Device tree struct 0x%x -> 0x%x\n", + prom_printf("Device tree struct 0x%lx -> 0x%lx\n", dt_struct_start, dt_struct_end); } @@ -2997,7 +2999,7 @@ static void __init prom_find_boot_cpu(void) prom_getprop(cpu_pkg, "reg", &rval, sizeof(rval)); prom.cpu = be32_to_cpu(rval); - prom_debug("Booting CPU hw index = %lu\n", prom.cpu); + prom_debug("Booting CPU hw index = %d\n", prom.cpu); } static void __init prom_check_initrd(unsigned long r3, unsigned long r4) @@ -3019,8 +3021,8 @@ static void __init prom_check_initrd(unsigned long r3, unsigned long r4) reserve_mem(prom_initrd_start, prom_initrd_end - prom_initrd_start); - prom_debug("initrd_start=0x%x\n", prom_initrd_start); - prom_debug("initrd_end=0x%x\n", prom_initrd_end); + prom_debug("initrd_start=0x%lx\n", prom_initrd_start); + prom_debug("initrd_end=0x%lx\n", prom_initrd_end); } #endif /* CONFIG_BLK_DEV_INITRD */ } @@ -3273,7 +3275,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, /* Don't print anything after quiesce under OPAL, it crashes OFW */ if (of_platform != PLATFORM_OPAL) { prom_printf("Booting Linux via __start() @ 0x%lx ...\n", kbase); - prom_debug("->dt_header_start=0x%x\n", hdr); + prom_debug("->dt_header_start=0x%lx\n", hdr); } #ifdef CONFIG_PPC32 -- GitLab From 56a58a5395aba19f0a4c3e18b46532511994841a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 23 May 2018 11:02:04 +0200 Subject: [PATCH 0392/1001] spi: sh-msiof: Fix setting SIRMDR1.SYNCAC to match SITMDR1.SYNCAC [ Upstream commit 0921e11e1e12802ae0a3c19cb02e33354ca51967 ] According to section 59.2.4 MSIOF Receive Mode Register 1 (SIRMDR1) in the R-Car Gen3 datasheet Rev.1.00, the value of the SIRMDR1.SYNCAC bit must match the value of the SITMDR1.SYNCAC bit. However, sh_msiof_spi_setup() changes only the latter. Fix this by updating the SIRMDR1 register like the SITMDR1 register, taking into account register bits that exist in SITMDR1 only. Reported-by: Renesas BSP team via Yoshihiro Shimoda Fixes: 7ff0b53c4051145d ("spi: sh-msiof: Avoid writing to registers from spi_master.setup()") Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-sh-msiof.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 52056535f54e..0fea18ab970e 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -555,14 +555,16 @@ static int sh_msiof_spi_setup(struct spi_device *spi) /* Configure native chip select mode/polarity early */ clr = MDR1_SYNCMD_MASK; - set = MDR1_TRMD | TMDR1_PCON | MDR1_SYNCMD_SPI; + set = MDR1_SYNCMD_SPI; if (spi->mode & SPI_CS_HIGH) clr |= BIT(MDR1_SYNCAC_SHIFT); else set |= BIT(MDR1_SYNCAC_SHIFT); pm_runtime_get_sync(&p->pdev->dev); tmp = sh_msiof_read(p, TMDR1) & ~clr; - sh_msiof_write(p, TMDR1, tmp | set); + sh_msiof_write(p, TMDR1, tmp | set | MDR1_TRMD | TMDR1_PCON); + tmp = sh_msiof_read(p, RMDR1) & ~clr; + sh_msiof_write(p, RMDR1, tmp | set); pm_runtime_put(&p->pdev->dev); p->native_cs_high = spi->mode & SPI_CS_HIGH; p->native_cs_inited = true; -- GitLab From 210807e92b4902fa672c3ab6cb7381d374a58b23 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 24 May 2018 11:02:06 +0000 Subject: [PATCH 0393/1001] powerpc/8xx: fix invalid register expression in head_8xx.S [ Upstream commit e4ccb1dae6bdef228d729c076c38161ef6e7ca34 ] New binutils generate the following warning AS arch/powerpc/kernel/head_8xx.o arch/powerpc/kernel/head_8xx.S: Assembler messages: arch/powerpc/kernel/head_8xx.S:916: Warning: invalid register expression This patch fixes it. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/head_8xx.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index 4fee00d414e8..2d0d89e2cb9a 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -958,7 +958,7 @@ start_here: tovirt(r6,r6) lis r5, abatron_pteptrs@h ori r5, r5, abatron_pteptrs@l - stw r5, 0xf0(r0) /* Must match your Abatron config file */ + stw r5, 0xf0(0) /* Must match your Abatron config file */ tophys(r5,r5) stw r6, 0(r5) -- GitLab From cf957ba7c6e8ab922ae45f46a31b5f8370bcf889 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 23 May 2018 21:07:12 +0200 Subject: [PATCH 0394/1001] pinctrl: at91-pio4: add missing of_node_put [ Upstream commit 21816364715f508c10da1e087e352bc1e326614f ] The device node iterators perform an of_node_get on each iteration, so a jump out of the loop requires an of_node_put. The semantic patch that fixes this problem is as follows (http://coccinelle.lip6.fr): // @@ expression root,e; local idexpression child; iterator name for_each_child_of_node; @@ for_each_child_of_node(root, child) { ... when != of_node_put(child) when != e = child + of_node_put(child); ? break; ... } ... when != child // Signed-off-by: Julia Lawall Acked-by: Ludovic Desroches Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/pinctrl/pinctrl-at91-pio4.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c index b1ca838dd80a..e61e2f8c91ce 100644 --- a/drivers/pinctrl/pinctrl-at91-pio4.c +++ b/drivers/pinctrl/pinctrl-at91-pio4.c @@ -576,8 +576,10 @@ static int atmel_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, for_each_child_of_node(np_config, np) { ret = atmel_pctl_dt_subnode_to_map(pctldev, np, map, &reserved_maps, num_maps); - if (ret < 0) + if (ret < 0) { + of_node_put(np); break; + } } } -- GitLab From 39da0cf774db1f1ac41caa4d01a8c63903e5f85d Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Thu, 24 May 2018 12:26:46 +0530 Subject: [PATCH 0395/1001] bpf: powerpc64: pad function address loads with NOPs [ Upstream commit 4ea69b2fd623dee2bbc77d3b6b7d8c0924e2026a ] For multi-function programs, loading the address of a callee function to a register requires emitting instructions whose count varies from one to five depending on the nature of the address. Since we come to know of the callee's address only before the extra pass, the number of instructions required to load this address may vary from what was previously generated. This can make the JITed image grow or shrink. To avoid this, we should generate a constant five-instruction when loading function addresses by padding the optimized load sequence with NOPs. Signed-off-by: Sandipan Das Signed-off-by: Daniel Borkmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/net/bpf_jit_comp64.c | 34 +++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c index bd0786c23109..254634fb3fc7 100644 --- a/arch/powerpc/net/bpf_jit_comp64.c +++ b/arch/powerpc/net/bpf_jit_comp64.c @@ -203,25 +203,37 @@ static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx) static void bpf_jit_emit_func_call(u32 *image, struct codegen_context *ctx, u64 func) { + unsigned int i, ctx_idx = ctx->idx; + + /* Load function address into r12 */ + PPC_LI64(12, func); + + /* For bpf-to-bpf function calls, the callee's address is unknown + * until the last extra pass. As seen above, we use PPC_LI64() to + * load the callee's address, but this may optimize the number of + * instructions required based on the nature of the address. + * + * Since we don't want the number of instructions emitted to change, + * we pad the optimized PPC_LI64() call with NOPs to guarantee that + * we always have a five-instruction sequence, which is the maximum + * that PPC_LI64() can emit. + */ + for (i = ctx->idx - ctx_idx; i < 5; i++) + PPC_NOP(); + #ifdef PPC64_ELF_ABI_v1 - /* func points to the function descriptor */ - PPC_LI64(b2p[TMP_REG_2], func); - /* Load actual entry point from function descriptor */ - PPC_BPF_LL(b2p[TMP_REG_1], b2p[TMP_REG_2], 0); - /* ... and move it to LR */ - PPC_MTLR(b2p[TMP_REG_1]); /* * Load TOC from function descriptor at offset 8. * We can clobber r2 since we get called through a * function pointer (so caller will save/restore r2) * and since we don't use a TOC ourself. */ - PPC_BPF_LL(2, b2p[TMP_REG_2], 8); -#else - /* We can clobber r12 */ - PPC_FUNC_ADDR(12, func); - PPC_MTLR(12); + PPC_BPF_LL(2, 12, 8); + /* Load actual entry point from function descriptor */ + PPC_BPF_LL(12, 12, 0); #endif + + PPC_MTLR(12); PPC_BLRL(); } -- GitLab From 082900a6d56766eeefd6f301c71f4d913d2cd0b9 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 23 May 2018 17:19:22 -0500 Subject: [PATCH 0396/1001] PCI: pciehp: Request control of native hotplug only if supported [ Upstream commit 408fec36a1ab3d14273c2116b449ef1e9be3cb8b ] Currently we request control of native PCIe hotplug unconditionally. Native PCIe hotplug events are handled by the pciehp driver, and if it is not enabled those events will be lost. Request control of native PCIe hotplug only if the pciehp driver is enabled, so we will actually handle native PCIe hotplug events. Suggested-by: Bjorn Helgaas Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/pci_root.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 6fc204a52493..eb857d6ea1fe 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -472,9 +472,11 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm) } control = OSC_PCI_EXPRESS_CAPABILITY_CONTROL - | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | OSC_PCI_EXPRESS_PME_CONTROL; + if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) + control |= OSC_PCI_EXPRESS_NATIVE_HP_CONTROL; + if (pci_aer_available()) { if (aer_acpi_firmware_first()) dev_info(&device->dev, -- GitLab From a30ff89c34b8b6b952a8ceb9bf68027f19e28be8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vok=C3=A1=C4=8D?= Date: Wed, 23 May 2018 08:20:19 +0200 Subject: [PATCH 0397/1001] net: dsa: qca8k: Add support for QCA8334 switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 64cf81675a1f64c1b311e4611dd3b6a961607612 ] Add support for the four-port variant of the Qualcomm QCA833x switch. Signed-off-by: Michal Vokáč Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/dsa/qca8k.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index 5ada7a41449c..2a2bbf5e9c8e 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -934,6 +934,7 @@ static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, qca8k_suspend, qca8k_resume); static const struct of_device_id qca8k_of_match[] = { + { .compatible = "qca,qca8334" }, { .compatible = "qca,qca8337" }, { /* sentinel */ }, }; -- GitLab From 945e6ce33d80cd637e6e9f24871c926581bac2c9 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Fri, 18 May 2018 15:38:54 +0800 Subject: [PATCH 0398/1001] mwifiex: correct histogram data with appropriate index [ Upstream commit 30bfce0b63fa68c14ae1613eb9d259fa18644074 ] Correct snr/nr/rssi data index to avoid possible buffer underflow. Signed-off-by: Xinming Hu Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/marvell/mwifiex/util.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c index 0cd68ffc2c74..51ccf10f4413 100644 --- a/drivers/net/wireless/marvell/mwifiex/util.c +++ b/drivers/net/wireless/marvell/mwifiex/util.c @@ -708,12 +708,14 @@ void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr, s8 nflr) { struct mwifiex_histogram_data *phist_data = priv->hist_data; + s8 nf = -nflr; + s8 rssi = snr - nflr; atomic_inc(&phist_data->num_samples); atomic_inc(&phist_data->rx_rate[rx_rate]); - atomic_inc(&phist_data->snr[snr]); - atomic_inc(&phist_data->noise_flr[128 + nflr]); - atomic_inc(&phist_data->sig_str[nflr - snr]); + atomic_inc(&phist_data->snr[snr + 128]); + atomic_inc(&phist_data->noise_flr[nf + 128]); + atomic_inc(&phist_data->sig_str[rssi + 128]); } /* function to reset histogram data during init/reset */ -- GitLab From cffbdb7702ba549f116c44fe3006a587c94f8885 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Fri, 27 Apr 2018 14:31:40 -0400 Subject: [PATCH 0399/1001] ima: based on policy verify firmware signatures (pre-allocated buffer) [ Upstream commit fd90bc559bfba743ae8de87ff23b92a5e4668062 ] Don't differentiate, for now, between kernel_read_file_id READING_FIRMWARE and READING_FIRMWARE_PREALLOC_BUFFER enumerations. Fixes: a098ecd firmware: support loading into a pre-allocated buffer (since 4.8) Signed-off-by: Mimi Zohar Cc: Luis R. Rodriguez Cc: David Howells Cc: Kees Cook Cc: Serge E. Hallyn Cc: Stephen Boyd Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- security/integrity/ima/ima_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 7e334fd31c15..f8553179bdd7 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -379,6 +379,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id) static int read_idmap[READING_MAX_ID] = { [READING_FIRMWARE] = FIRMWARE_CHECK, + [READING_FIRMWARE_PREALLOC_BUFFER] = FIRMWARE_CHECK, [READING_MODULE] = MODULE_CHECK, [READING_KEXEC_IMAGE] = KEXEC_KERNEL_CHECK, [READING_KEXEC_INITRAMFS] = KEXEC_INITRAMFS_CHECK, -- GitLab From d0a963cf845c6ed34e911774b0de6bca7daa5e6f Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 21 May 2018 18:19:49 +0100 Subject: [PATCH 0400/1001] drivers/perf: arm-ccn: don't log to dmesg in event_init [ Upstream commit 1898eb61fbc9703efee886d3abec27a388cf28c3 ] The ARM CCN PMU driver uses dev_warn() to complain about parameters in the user-provided perf_event_attr. This means that under normal operation (e.g. a single invocation of the perf tool), a number of messages warnings may be logged to dmesg. Tools may issue multiple syscalls to probe for feature support, and multiple applications (from multiple users) can attempt to open events simultaneously, so this is not very helpful, even if a user happens to have access to dmesg. Worse, this can push important information out of the dmesg ring buffer, and can significantly slow down syscall fuzzers, vastly increasing the time it takes to find critical bugs. Demote the dev_warn() instances to dev_dbg(), as is the case for all other PMU drivers under drivers/perf/. Users who wish to debug PMU event initialisation can enable dynamic debug to receive these messages. Signed-off-by: Mark Rutland Cc: Pawel Moll Cc: Will Deacon Signed-off-by: Will Deacon Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/bus/arm-ccn.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/bus/arm-ccn.c b/drivers/bus/arm-ccn.c index 72fd1750134d..942d076cbb0a 100644 --- a/drivers/bus/arm-ccn.c +++ b/drivers/bus/arm-ccn.c @@ -736,7 +736,7 @@ static int arm_ccn_pmu_event_init(struct perf_event *event) ccn = pmu_to_arm_ccn(event->pmu); if (hw->sample_period) { - dev_warn(ccn->dev, "Sampling not supported!\n"); + dev_dbg(ccn->dev, "Sampling not supported!\n"); return -EOPNOTSUPP; } @@ -744,12 +744,12 @@ static int arm_ccn_pmu_event_init(struct perf_event *event) event->attr.exclude_kernel || event->attr.exclude_hv || event->attr.exclude_idle || event->attr.exclude_host || event->attr.exclude_guest) { - dev_warn(ccn->dev, "Can't exclude execution levels!\n"); + dev_dbg(ccn->dev, "Can't exclude execution levels!\n"); return -EINVAL; } if (event->cpu < 0) { - dev_warn(ccn->dev, "Can't provide per-task data!\n"); + dev_dbg(ccn->dev, "Can't provide per-task data!\n"); return -EOPNOTSUPP; } /* @@ -771,13 +771,13 @@ static int arm_ccn_pmu_event_init(struct perf_event *event) switch (type) { case CCN_TYPE_MN: if (node_xp != ccn->mn_id) { - dev_warn(ccn->dev, "Invalid MN ID %d!\n", node_xp); + dev_dbg(ccn->dev, "Invalid MN ID %d!\n", node_xp); return -EINVAL; } break; case CCN_TYPE_XP: if (node_xp >= ccn->num_xps) { - dev_warn(ccn->dev, "Invalid XP ID %d!\n", node_xp); + dev_dbg(ccn->dev, "Invalid XP ID %d!\n", node_xp); return -EINVAL; } break; @@ -785,11 +785,11 @@ static int arm_ccn_pmu_event_init(struct perf_event *event) break; default: if (node_xp >= ccn->num_nodes) { - dev_warn(ccn->dev, "Invalid node ID %d!\n", node_xp); + dev_dbg(ccn->dev, "Invalid node ID %d!\n", node_xp); return -EINVAL; } if (!arm_ccn_pmu_type_eq(type, ccn->node[node_xp].type)) { - dev_warn(ccn->dev, "Invalid type 0x%x for node %d!\n", + dev_dbg(ccn->dev, "Invalid type 0x%x for node %d!\n", type, node_xp); return -EINVAL; } @@ -808,19 +808,19 @@ static int arm_ccn_pmu_event_init(struct perf_event *event) if (event_id != e->event) continue; if (e->num_ports && port >= e->num_ports) { - dev_warn(ccn->dev, "Invalid port %d for node/XP %d!\n", + dev_dbg(ccn->dev, "Invalid port %d for node/XP %d!\n", port, node_xp); return -EINVAL; } if (e->num_vcs && vc >= e->num_vcs) { - dev_warn(ccn->dev, "Invalid vc %d for node/XP %d!\n", + dev_dbg(ccn->dev, "Invalid vc %d for node/XP %d!\n", vc, node_xp); return -EINVAL; } valid = 1; } if (!valid) { - dev_warn(ccn->dev, "Invalid event 0x%x for node/XP %d!\n", + dev_dbg(ccn->dev, "Invalid event 0x%x for node/XP %d!\n", event_id, node_xp); return -EINVAL; } -- GitLab From 625d1e783375202c099b67aecb9b227d5b6f568f Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 18 May 2018 10:30:07 -0700 Subject: [PATCH 0401/1001] spi: Add missing pm_runtime_put_noidle() after failed get [ Upstream commit 7e48e23a1f4a50f93ac1073f1326e0a73829b631 ] If pm_runtime_get_sync() fails we should call pm_runtime_put_noidle(). This is probably not a critical fix as we should only hit this when things are broken elsewhere. Signed-off-by: Tony Lindgren Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 84dfef4bd6ae..f85d30dc9187 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1222,6 +1222,7 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) if (!was_busy && ctlr->auto_runtime_pm) { ret = pm_runtime_get_sync(ctlr->dev.parent); if (ret < 0) { + pm_runtime_put_noidle(ctlr->dev.parent); dev_err(&ctlr->dev, "Failed to power device: %d\n", ret); mutex_unlock(&ctlr->io_mutex); -- GitLab From 1d6908ce90b5506cdd5f163afeecffa0039a62e6 Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Sat, 19 May 2018 16:53:18 +0100 Subject: [PATCH 0402/1001] net: hns3: Fix the missing client list node initialization [ Upstream commit 13562d1f5e2fbe2cf33b23a00abca3f71264c4ac ] This patch fixes the missing initialization of the client list node in the hnae3_register_client() function. Fixes: 76ad4f0ee747 ("net: hns3: Add support of HNS3 Ethernet Driver for hip08 SoC") Signed-off-by: Xi Wang Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c index 9f8c56f9e9c1..69726908e72c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c @@ -2883,6 +2883,8 @@ static int __init hns3_init_module(void) client.ops = &client_ops; + INIT_LIST_HEAD(&client.node); + ret = hnae3_register_client(&client); if (ret) return ret; -- GitLab From 63c7e58dab1e6ba58e6c3c31097c58c8a1eaf0f5 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 20 Apr 2018 16:30:02 -0700 Subject: [PATCH 0403/1001] fscrypt: use unbound workqueue for decryption [ Upstream commit 36dd26e0c8d42699eeba87431246c07c28075bae ] Improve fscrypt read performance by switching the decryption workqueue from bound to unbound. With the bound workqueue, when multiple bios completed on the same CPU, they were decrypted on that same CPU. But with the unbound queue, they are now decrypted in parallel on any CPU. Although fscrypt read performance can be tough to measure due to the many sources of variation, this change is most beneficial when decryption is slow, e.g. on CPUs without AES instructions. For example, I timed tarring up encrypted directories on f2fs. On x86 with AES-NI instructions disabled, the unbound workqueue improved performance by about 25-35%, using 1 to NUM_CPUs jobs with 4 or 8 CPUs available. But with AES-NI enabled, performance was unchanged to within ~2%. I also did the same test on a quad-core ARM CPU using xts-speck128-neon encryption. There performance was usually about 10% better with the unbound workqueue, bringing it closer to the unencrypted speed. The unbound workqueue may be worse in some cases due to worse locality, but I think it's still the better default. dm-crypt uses an unbound workqueue by default too, so this change makes fscrypt match. Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/crypto/crypto.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index d262a93d9b31..daf2683f0655 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -446,8 +446,17 @@ int fscrypt_initialize(unsigned int cop_flags) */ static int __init fscrypt_init(void) { + /* + * Use an unbound workqueue to allow bios to be decrypted in parallel + * even when they happen to complete on the same CPU. This sacrifices + * locality, but it's worthwhile since decryption is CPU-intensive. + * + * Also use a high-priority workqueue to prioritize decryption work, + * which blocks reads from completing, over regular application tasks. + */ fscrypt_read_workqueue = alloc_workqueue("fscrypt_read_queue", - WQ_HIGHPRI, 0); + WQ_UNBOUND | WQ_HIGHPRI, + num_online_cpus()); if (!fscrypt_read_workqueue) goto fail; -- GitLab From c9f744135ad7004cb978ec59c745c5e852bf7476 Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Thu, 3 May 2018 16:37:17 +0530 Subject: [PATCH 0404/1001] scsi: ufs: ufshcd: fix possible unclocked register access [ Upstream commit b334456ec2021b1addc19806990115e69ec4ac32 ] Vendor specific setup_clocks ops may depend on clocks managed by ufshcd driver so if the vendor specific setup_clocks callback is called when the required clocks are turned off, it results into unclocked register access. This change make sure that required clocks are enabled before vendor specific setup_clocks callback is called. Signed-off-by: Subhash Jadavani Signed-off-by: Venkat Gopalakrishnan Signed-off-by: Can Guo Signed-off-by: Asutosh Das Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/ufs/ufshcd.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 3bb1f6cc297a..5efcfb528cb8 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -6761,9 +6761,16 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, if (list_empty(head)) goto out; - ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE); - if (ret) - return ret; + /* + * vendor specific setup_clocks ops may depend on clocks managed by + * this standard driver hence call the vendor specific setup_clocks + * before disabling the clocks managed here. + */ + if (!on) { + ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE); + if (ret) + return ret; + } list_for_each_entry(clki, head, list) { if (!IS_ERR_OR_NULL(clki->clk)) { @@ -6787,9 +6794,16 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, } } - ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE); - if (ret) - return ret; + /* + * vendor specific setup_clocks ops may depend on clocks managed by + * this standard driver hence call the vendor specific setup_clocks + * after enabling the clocks managed here. + */ + if (on) { + ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE); + if (ret) + return ret; + } out: if (ret) { -- GitLab From b095b5888eab89b8e92418b2ebd93f6d535711b9 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Thu, 3 May 2018 16:37:16 +0530 Subject: [PATCH 0405/1001] scsi: ufs: fix exception event handling [ Upstream commit 2e3611e9546c2ed4def152a51dfd34e8dddae7a5 ] The device can set the exception event bit in one of the response UPIU, for example to notify the need for urgent BKOPs operation. In such a case, the host driver calls ufshcd_exception_event_handler to handle this notification. When trying to check the exception event status (for finding the cause for the exception event), the device may be busy with additional SCSI commands handling and may not respond within the 100ms timeout. To prevent that, we need to block SCSI commands during handling of exception events and allow retransmissions of the query requests, in case of timeout. Signed-off-by: Subhash Jadavani Signed-off-by: Maya Erez Signed-off-by: Can Guo Signed-off-by: Asutosh Das Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/ufs/ufshcd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 5efcfb528cb8..21c81c1feac5 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4947,6 +4947,7 @@ static void ufshcd_exception_event_handler(struct work_struct *work) hba = container_of(work, struct ufs_hba, eeh_work); pm_runtime_get_sync(hba->dev); + scsi_block_requests(hba->host); err = ufshcd_get_ee_status(hba, &status); if (err) { dev_err(hba->dev, "%s: failed to get exception status %d\n", @@ -4960,6 +4961,7 @@ static void ufshcd_exception_event_handler(struct work_struct *work) ufshcd_bkops_exception_event_handler(hba); out: + scsi_unblock_requests(hba->host); pm_runtime_put_sync(hba->dev); return; } -- GitLab From fdb5207dc1f1e3844728df5bb9d125d0c0cee5e7 Mon Sep 17 00:00:00 2001 From: Jens Remus Date: Thu, 17 May 2018 19:15:05 +0200 Subject: [PATCH 0406/1001] scsi: zfcp: assert that the ERP lock is held when tracing a recovery trigger [ Upstream commit 9e156c54ace310ce7fb1cd960e62416947f3d47c ] Otherwise iterating with list_for_each() over the adapter->erp_ready_head and adapter->erp_running_head lists can lead to an infinite loop. See commit "zfcp: fix infinite iteration on erp_ready_head list". The run-time check is only performed for debug kernels which have the kernel lock validator enabled. Following is an example of the warning that is reported, if the ERP lock is not held when calling zfcp_dbf_rec_trig(): WARNING: CPU: 0 PID: 604 at drivers/s390/scsi/zfcp_dbf.c:288 zfcp_dbf_rec_trig+0x172/0x188 Modules linked in: ... CPU: 0 PID: 604 Comm: kworker/u128:3 Not tainted 4.16.0-... #1 Hardware name: IBM 2964 N96 702 (z/VM 6.4.0) Workqueue: zfcp_q_0.0.1906 zfcp_scsi_rport_work Krnl PSW : 00000000330fdbf9 00000000367e9728 (zfcp_dbf_rec_trig+0x172/0x188) R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:3 CC:3 PM:0 RI:0 EA:3 Krnl GPRS: 00000000c57a5d99 3288200000000000 0000000000000000 000000006cc82740 00000000009d09d6 0000000000000000 00000000000000ff 0000000000000000 0000000000000000 0000000000e1b5fe 000000006de01d38 0000000076130958 000000006cc82548 000000006de01a98 00000000009d09d6 000000006a6d3c80 Krnl Code: 00000000009d0ad2: eb7ff0b80004 lmg %r7,%r15,184(%r15) 00000000009d0ad8: c0f4000d7dd0 brcl 15,b80678 #00000000009d0ade: a7f40001 brc 15,9d0ae0 >00000000009d0ae2: a7f4ff7d brc 15,9d09dc 00000000009d0ae6: e340f0f00004 lg %r4,240(%r15) 00000000009d0aec: eb7ff0b80004 lmg %r7,%r15,184(%r15) 00000000009d0af2: 07f4 bcr 15,%r4 00000000009d0af4: 0707 bcr 0,%r7 Call Trace: ([<00000000009d09d6>] zfcp_dbf_rec_trig+0x66/0x188) [<00000000009dd740>] zfcp_scsi_rport_work+0x98/0x190 [<0000000000169b34>] process_one_work+0x3d4/0x6f8 [<000000000016a08a>] worker_thread+0x232/0x418 [<000000000017219e>] kthread+0x166/0x178 [<0000000000b815ea>] kernel_thread_starter+0x6/0xc [<0000000000b815e4>] kernel_thread_starter+0x0/0xc 2 locks held by kworker/u128:3/604: #0: ((wq_completion)name){+.+.}, at: [<0000000082af1024>] process_one_work+0x1dc/0x6f8 #1: ((work_completion)(&port->rport_work)){+.+.}, at: [<0000000082af1024>] process_one_work+0x1dc/0x6f8 Last Breaking-Event-Address: [<00000000009d0ade>] zfcp_dbf_rec_trig+0x16e/0x188 ---[ end trace b2f4020572e2c124 ]--- Suggested-by: Steffen Maier Signed-off-by: Jens Remus Reviewed-by: Benjamin Block Reviewed-by: Steffen Maier Signed-off-by: Steffen Maier Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/s390/scsi/zfcp_dbf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index b415ba42ca73..599447032e50 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -285,6 +285,8 @@ void zfcp_dbf_rec_trig(char *tag, struct zfcp_adapter *adapter, struct list_head *entry; unsigned long flags; + lockdep_assert_held(&adapter->erp_lock); + if (unlikely(!debug_level_enabled(dbf->rec, level))) return; -- GitLab From 33775b07426be6553003a15743bd24a8bf0d841e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 8 May 2018 20:39:46 +1000 Subject: [PATCH 0407/1001] drm/nouveau/fifo/gk104-: poll for runlist update completion [ Upstream commit 4f2fc25c0f8bcc8db1b8a7b21e88c3d7f35c5acb ] Newer HW doesn't appear to send this event, which will cause long delays in runlist updates if they don't complete immediately. RM doesn't use these events anywhere, and an NVGPU commit message notes that polling is the preferred method even on HW that supports the event. Signed-off-by: Ben Skeggs Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index a7e55c422501..0b632dc0cf7d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -155,10 +155,10 @@ gk104_fifo_runlist_commit(struct gk104_fifo *fifo, int runl) (target << 28)); nvkm_wr32(device, 0x002274, (runl << 20) | nr); - if (wait_event_timeout(fifo->runlist[runl].wait, - !(nvkm_rd32(device, 0x002284 + (runl * 0x08)) - & 0x00100000), - msecs_to_jiffies(2000)) == 0) + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x002284 + (runl * 0x08)) & 0x00100000)) + break; + ) < 0) nvkm_error(subdev, "runlist %d update timeout\n", runl); unlock: mutex_unlock(&subdev->mutex); -- GitLab From 192591ade6ecaf9147b7fde977cda0bc77cc5a67 Mon Sep 17 00:00:00 2001 From: Vic Wei Date: Mon, 23 Apr 2018 15:17:07 -0700 Subject: [PATCH 0408/1001] Bluetooth: btusb: add ID for LiteOn 04ca:301a [ Upstream commit d666fc5479ad76a1bcbe6476d4997cea714bab2d ] Contains a QCA6174A chipset, with USB BT. Let's support loading firmware on it. >From usb-devices: T: Bus=02 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 2.01 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=04ca ProdID=301a 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 I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb Signed-off-by: Vic Wei Signed-off-by: Matthias Kaehlcke Signed-off-by: Marcel Holtmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btusb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index d89a674604b8..819521d5895e 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -279,6 +279,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x04ca, 0x3011), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x04ca, 0x3015), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x04ca, 0x3016), .driver_info = BTUSB_QCA_ROME }, + { USB_DEVICE(0x04ca, 0x301a), .driver_info = BTUSB_QCA_ROME }, /* Broadcom BCM2035 */ { USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 }, -- GitLab From aca6728fa1ede62972c266b30e618240ef8e9e6e Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 17 May 2018 22:48:17 +0200 Subject: [PATCH 0409/1001] rtc: tps6586x: fix possible race condition [ Upstream commit 63d22063073b0ab46d1e06fe633fb5de8f5c58e1 ] The probe function is not allowed to fail after the RTC is registered because the following may happen: CPU0: CPU1: sys_load_module() do_init_module() do_one_initcall() cmos_do_probe() rtc_device_register() __register_chrdev() cdev->owner = struct module* open("/dev/rtc0") rtc_device_unregister() module_put() free_module() module_free(mod->module_core) /* struct module *module is now freed */ chrdev_open() spin_lock(cdev_lock) cdev_get() try_module_get() module_is_live() /* dereferences already freed struct module* */ Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-tps6586x.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c index a3418a8a3796..97fdc99bfeef 100644 --- a/drivers/rtc/rtc-tps6586x.c +++ b/drivers/rtc/rtc-tps6586x.c @@ -276,14 +276,15 @@ static int tps6586x_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); platform_set_drvdata(pdev, rtc); - rtc->rtc = devm_rtc_device_register(&pdev->dev, dev_name(&pdev->dev), - &tps6586x_rtc_ops, THIS_MODULE); + rtc->rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(rtc->rtc)) { ret = PTR_ERR(rtc->rtc); - dev_err(&pdev->dev, "RTC device register: ret %d\n", ret); + dev_err(&pdev->dev, "RTC allocate device: ret %d\n", ret); goto fail_rtc_register; } + rtc->rtc->ops = &tps6586x_rtc_ops; + ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, tps6586x_rtc_irq, IRQF_ONESHOT, @@ -294,6 +295,13 @@ static int tps6586x_rtc_probe(struct platform_device *pdev) goto fail_rtc_register; } disable_irq(rtc->irq); + + ret = rtc_register_device(rtc->rtc); + if (ret) { + dev_err(&pdev->dev, "RTC device register: ret %d\n", ret); + goto fail_rtc_register; + } + return 0; fail_rtc_register: -- GitLab From 8f5e7596fe3a41be914056bab79230b2c71d7e63 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 17 May 2018 22:47:05 +0200 Subject: [PATCH 0410/1001] rtc: vr41xx: fix possible race condition [ Upstream commit 9a99247c9c1d1c95c6e8153d013979aac6111c6e ] The probe function is not allowed to fail after the RTC is registered because the following may happen: CPU0: CPU1: sys_load_module() do_init_module() do_one_initcall() cmos_do_probe() rtc_device_register() __register_chrdev() cdev->owner = struct module* open("/dev/rtc0") rtc_device_unregister() module_put() free_module() module_free(mod->module_core) /* struct module *module is now freed */ chrdev_open() spin_lock(cdev_lock) cdev_get() try_module_get() module_is_live() /* dereferences already freed struct module* */ Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-vr41xx.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index 7ce22967fd16..7ed010714f29 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -292,13 +292,14 @@ static int rtc_probe(struct platform_device *pdev) goto err_rtc1_iounmap; } - rtc = devm_rtc_device_register(&pdev->dev, rtc_name, &vr41xx_rtc_ops, - THIS_MODULE); + rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(rtc)) { retval = PTR_ERR(rtc); goto err_iounmap_all; } + rtc->ops = &vr41xx_rtc_ops; + rtc->max_user_freq = MAX_PERIODIC_RATE; spin_lock_irq(&rtc_lock); @@ -340,6 +341,10 @@ static int rtc_probe(struct platform_device *pdev) dev_info(&pdev->dev, "Real Time Clock of NEC VR4100 series\n"); + retval = rtc_register_device(rtc); + if (retval) + goto err_iounmap_all; + return 0; err_iounmap_all: -- GitLab From 9f25b548732cfdcda2b0bd638497934b4a8eaaf6 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 17 May 2018 22:26:21 +0200 Subject: [PATCH 0411/1001] rtc: tps65910: fix possible race condition [ Upstream commit e6000a438e534ee0afd9e83b67f4e23a26dd1067 ] The IRQ is requested before the struct rtc is allocated and registered, but this struct is used in the IRQ handler. This may lead to a NULL pointer dereference. Switch to devm_rtc_allocate_device/rtc_register_device to allocate the rtc before requesting the IRQ. Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-tps65910.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index d0244d7979fc..a56b526db89a 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -380,6 +380,10 @@ static int tps65910_rtc_probe(struct platform_device *pdev) if (!tps_rtc) return -ENOMEM; + tps_rtc->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(tps_rtc->rtc)) + return PTR_ERR(tps_rtc->rtc); + /* Clear pending interrupts */ ret = regmap_read(tps65910->regmap, TPS65910_RTC_STATUS, &rtc_reg); if (ret < 0) @@ -421,10 +425,10 @@ static int tps65910_rtc_probe(struct platform_device *pdev) tps_rtc->irq = irq; device_set_wakeup_capable(&pdev->dev, 1); - tps_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &tps65910_rtc_ops, THIS_MODULE); - if (IS_ERR(tps_rtc->rtc)) { - ret = PTR_ERR(tps_rtc->rtc); + tps_rtc->rtc->ops = &tps65910_rtc_ops; + + ret = rtc_register_device(tps_rtc->rtc); + if (ret) { dev_err(&pdev->dev, "RTC device register: err %d\n", ret); return ret; } -- GitLab From 9b56c4151ac250f8ee4f320c0ac63ffdce275304 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 17 May 2018 20:02:23 +0200 Subject: [PATCH 0412/1001] ALSA: emu10k1: Rate-limit error messages about page errors [ Upstream commit 11d42c81036324697d367600bfc16f6dd37636fd ] The error messages at sanity checks of memory pages tend to repeat too many times once when it hits, and without the rate limit, it may flood and become unreadable. Replace such messages with the *_ratelimited() variant. Bugzilla: http://bugzilla.opensuse.org/show_bug.cgi?id=1093027 Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/pci/emu10k1/memory.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 4f1f69be1865..8c778fa33031 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -237,13 +237,13 @@ search_empty(struct snd_emu10k1 *emu, int size) static int is_valid_page(struct snd_emu10k1 *emu, dma_addr_t addr) { if (addr & ~emu->dma_mask) { - dev_err(emu->card->dev, + dev_err_ratelimited(emu->card->dev, "max memory size is 0x%lx (addr = 0x%lx)!!\n", emu->dma_mask, (unsigned long)addr); return 0; } if (addr & (EMUPAGESIZE-1)) { - dev_err(emu->card->dev, "page is not aligned\n"); + dev_err_ratelimited(emu->card->dev, "page is not aligned\n"); return 0; } return 1; @@ -334,7 +334,7 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst else addr = snd_pcm_sgbuf_get_addr(substream, ofs); if (! is_valid_page(emu, addr)) { - dev_err(emu->card->dev, + dev_err_ratelimited(emu->card->dev, "emu: failure page = %d\n", idx); mutex_unlock(&hdr->block_mutex); return NULL; -- GitLab From 6192b115c58b725789cb333b4e043a6491c8d313 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 17 May 2018 15:27:22 +0800 Subject: [PATCH 0413/1001] regulator: pfuze100: add .is_enable() for pfuze100_swb_regulator_ops [ Upstream commit 0b01fd3d40fe6402e5fa3b491ef23109feb1aaa5 ] If is_enabled() is not defined, regulator core will assume this regulator is already enabled, then it can NOT be really enabled after disabled. Based on Li Jun's patch from the NXP kernel tree. Signed-off-by: Anson Huang Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/regulator/pfuze100-regulator.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 63922a2167e5..659e516455be 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -158,6 +158,7 @@ static const struct regulator_ops pfuze100_sw_regulator_ops = { static const struct regulator_ops pfuze100_swb_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = regulator_set_voltage_sel_regmap, -- GitLab From 1b3433cfa222b65342a4f945b96bec991ed6fe05 Mon Sep 17 00:00:00 2001 From: Gioh Kim Date: Wed, 2 May 2018 13:08:11 +0200 Subject: [PATCH 0414/1001] md/raid1: add error handling of read error from FailFast device [ Upstream commit b33d10624fdc15cdf1495f3f00481afccec76783 ] Current handle_read_error() function calls fix_read_error() only if md device is RW and rdev does not include FailFast flag. It does not handle a read error from a RW device including FailFast flag. I am not sure it is intended. But I found that write IO error sets rdev faulty. The md module should handle the read IO error and write IO error equally. So I think read IO error should set rdev faulty. Signed-off-by: Gioh Kim Reviewed-by: Jack Wang Signed-off-by: Shaohua Li Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid1.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 029ecba60727..78d830763704 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -2462,6 +2462,8 @@ static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio) fix_read_error(conf, r1_bio->read_disk, r1_bio->sector, r1_bio->sectors); unfreeze_array(conf); + } else if (mddev->ro == 0 && test_bit(FailFast, &rdev->flags)) { + md_error(mddev, rdev); } else { r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED; } -- GitLab From 7627ecfc4902a724b8a9aac971e19bd05655ad85 Mon Sep 17 00:00:00 2001 From: Yufen Yu Date: Fri, 4 May 2018 18:08:10 +0800 Subject: [PATCH 0415/1001] md: fix NULL dereference of mddev->pers in remove_and_add_spares() [ Upstream commit c42a0e2675721e1444f56e6132a07b7b1ec169ac ] We met NULL pointer BUG as follow: [ 151.760358] BUG: unable to handle kernel NULL pointer dereference at 0000000000000060 [ 151.761340] PGD 80000001011eb067 P4D 80000001011eb067 PUD 1011ea067 PMD 0 [ 151.762039] Oops: 0000 [#1] SMP PTI [ 151.762406] Modules linked in: [ 151.762723] CPU: 2 PID: 3561 Comm: mdadm-test Kdump: loaded Not tainted 4.17.0-rc1+ #238 [ 151.763542] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1.fc26 04/01/2014 [ 151.764432] RIP: 0010:remove_and_add_spares.part.56+0x13c/0x3a0 [ 151.765061] RSP: 0018:ffffc90001d7fcd8 EFLAGS: 00010246 [ 151.765590] RAX: 0000000000000000 RBX: ffff88013601d600 RCX: 0000000000000000 [ 151.766306] RDX: 0000000000000000 RSI: ffff88013601d600 RDI: ffff880136187000 [ 151.767014] RBP: ffff880136187018 R08: 0000000000000003 R09: 0000000000000051 [ 151.767728] R10: ffffc90001d7fed8 R11: 0000000000000000 R12: ffff88013601d600 [ 151.768447] R13: ffff8801298b1300 R14: ffff880136187000 R15: 0000000000000000 [ 151.769160] FS: 00007f2624276700(0000) GS:ffff88013ae80000(0000) knlGS:0000000000000000 [ 151.769971] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 151.770554] CR2: 0000000000000060 CR3: 0000000111aac000 CR4: 00000000000006e0 [ 151.771272] Call Trace: [ 151.771542] md_ioctl+0x1df2/0x1e10 [ 151.771906] ? __switch_to+0x129/0x440 [ 151.772295] ? __schedule+0x244/0x850 [ 151.772672] blkdev_ioctl+0x4bd/0x970 [ 151.773048] block_ioctl+0x39/0x40 [ 151.773402] do_vfs_ioctl+0xa4/0x610 [ 151.773770] ? dput.part.23+0x87/0x100 [ 151.774151] ksys_ioctl+0x70/0x80 [ 151.774493] __x64_sys_ioctl+0x16/0x20 [ 151.774877] do_syscall_64+0x5b/0x180 [ 151.775258] entry_SYSCALL_64_after_hwframe+0x44/0xa9 For raid6, when two disk of the array are offline, two spare disks can be added into the array. Before spare disks recovery completing, system reboot and mdadm thinks it is ok to restart the degraded array by md_ioctl(). Since disks in raid6 is not only_parity(), raid5_run() will abort, when there is no PPL feature or not setting 'start_dirty_degraded' parameter. Therefore, mddev->pers is NULL. But, mddev->raid_disks has been set and it will not be cleared when raid5_run abort. md_ioctl() can execute cmd 'HOT_REMOVE_DISK' to remove a disk by mdadm, which will cause NULL pointer dereference in remove_and_add_spares() finally. Signed-off-by: Yufen Yu Signed-off-by: Shaohua Li Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/md.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/md/md.c b/drivers/md/md.c index 11a67eac55b1..5599712d478e 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -6498,6 +6498,9 @@ static int hot_remove_disk(struct mddev *mddev, dev_t dev) char b[BDEVNAME_SIZE]; struct md_rdev *rdev; + if (!mddev->pers) + return -ENODEV; + rdev = find_rdev(mddev, dev); if (!rdev) return -ENXIO; -- GitLab From 41b16e6ec6a8c269a4d7b75bf36523662c402db4 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Mon, 14 May 2018 11:16:16 -0700 Subject: [PATCH 0416/1001] ixgbevf: fix MAC address changes through ixgbevf_set_mac() [ Upstream commit 6e7d0ba1e59b1a306761a731e67634c0f2efea2a ] Set hw->mac.perm_addr in ixgbevf_set_mac() in order to avoid losing the custom MAC on reset. This can happen in the following case: >ip link set $vf address $mac >ethtool -r $vf Signed-off-by: Emil Tantilov Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 90ecc4b06462..90be4385bf36 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -3737,6 +3737,7 @@ static int ixgbevf_set_mac(struct net_device *netdev, void *p) return -EPERM; ether_addr_copy(hw->mac.addr, addr->sa_data); + ether_addr_copy(hw->mac.perm_addr, addr->sa_data); ether_addr_copy(netdev->dev_addr, addr->sa_data); return 0; -- GitLab From 0bd08027bd197103aa1c42843a894dca7414b5d0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 25 Apr 2018 11:04:21 -0400 Subject: [PATCH 0417/1001] media: smiapp: fix timeout checking in smiapp_read_nvm [ Upstream commit 7a2148dfda8001c983f0effd9afd8a7fa58e99c4 ] The current code decrements the timeout counter i and the end of each loop i is incremented, so the check for timeout will always be false and hence the timeout mechanism is just a dead code path. Potentially, if the RD_READY bit is not set, we could end up in an infinite loop. Fix this so the timeout starts from 1000 and decrements to zero, if at the end of the loop i is zero we have a timeout condition. Detected by CoverityScan, CID#1324008 ("Logically dead code") Fixes: ccfc97bdb5ae ("[media] smiapp: Add driver") Signed-off-by: Colin Ian King Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/i2c/smiapp/smiapp-core.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 700f433261d0..e4d7f2febf00 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -1001,7 +1001,7 @@ static int smiapp_read_nvm(struct smiapp_sensor *sensor, if (rval) goto out; - for (i = 0; i < 1000; i++) { + for (i = 1000; i > 0; i--) { rval = smiapp_read( sensor, SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, &s); @@ -1012,11 +1012,10 @@ static int smiapp_read_nvm(struct smiapp_sensor *sensor, if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY) break; - if (--i == 0) { - rval = -ETIMEDOUT; - goto out; - } - + } + if (!i) { + rval = -ETIMEDOUT; + goto out; } for (i = 0; i < SMIAPP_NVM_PAGE_SIZE; i++) { -- GitLab From d239ee35ddb2a967d1b6003eef180cb544c95249 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Tue, 15 May 2018 18:37:25 -0500 Subject: [PATCH 0418/1001] net: ethernet: ti: cpsw-phy-sel: check bus_find_device() ret value [ Upstream commit c6213eb1aee308e67377fd1890d84f7284caf531 ] This fixes klockworks warnings: Pointer 'dev' returned from call to function 'bus_find_device' at line 179 may be NULL and will be dereferenced at line 181. cpsw-phy-sel.c:179: 'dev' is assigned the return value from function 'bus_find_device'. bus.c:342: 'bus_find_device' explicitly returns a NULL value. cpsw-phy-sel.c:181: 'dev' is dereferenced by passing argument 1 to function 'dev_get_drvdata'. device.h:1024: 'dev' is passed to function 'dev_get_drvdata'. device.h:1026: 'dev' is explicitly dereferenced. Signed-off-by: Grygorii Strashko [nsekhar@ti.com: add an error message, fix return path] Signed-off-by: Sekhar Nori Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/ti/cpsw-phy-sel.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ti/cpsw-phy-sel.c b/drivers/net/ethernet/ti/cpsw-phy-sel.c index 18013645e76c..0c1adad7415d 100644 --- a/drivers/net/ethernet/ti/cpsw-phy-sel.c +++ b/drivers/net/ethernet/ti/cpsw-phy-sel.c @@ -177,12 +177,18 @@ void cpsw_phy_sel(struct device *dev, phy_interface_t phy_mode, int slave) } dev = bus_find_device(&platform_bus_type, NULL, node, match); - of_node_put(node); + if (!dev) { + dev_err(dev, "unable to find platform device for %pOF\n", node); + goto out; + } + priv = dev_get_drvdata(dev); priv->cpsw_phy_sel(priv, phy_mode, slave); put_device(dev); +out: + of_node_put(node); } EXPORT_SYMBOL_GPL(cpsw_phy_sel); -- GitLab From 25436aa5c184b93e364c9c97d754f71725be1179 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 16 May 2018 20:07:18 +0200 Subject: [PATCH 0419/1001] ALSA: usb-audio: Apply rate limit to warning messages in URB complete callback [ Upstream commit 377a879d9832f4ba69bd6a1fc996bb4181b1e504 ] retire_capture_urb() may print warning messages when the given URB doesn't align, and this may flood the system log easily. Put the rate limit to the message for avoiding it. Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1093485 Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/usb/pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 3cbfae6604f9..d8a46d46bcd2 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1311,7 +1311,7 @@ static void retire_capture_urb(struct snd_usb_substream *subs, if (bytes % (runtime->sample_bits >> 3) != 0) { int oldbytes = bytes; bytes = frames * stride; - dev_warn(&subs->dev->dev, + dev_warn_ratelimited(&subs->dev->dev, "Corrected urb data len. %d->%d\n", oldbytes, bytes); } -- GitLab From 62a87c8759f272e65f7f60f4f7d2d7b3671e1edc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 16 Apr 2018 12:37:09 -0400 Subject: [PATCH 0420/1001] media: atomisp: ov2680: don't declare unused vars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit e5c0680fd2c44252868fe4062558925b5506b179 ] drivers/staging/media/atomisp/i2c/atomisp-ov2680.c: In function ‘__ov2680_set_exposure’: drivers/staging/media/atomisp/i2c/atomisp-ov2680.c:400:10: warning: variable ‘hts’ set but not used [-Wunused-but-set-variable] u16 vts,hts; ^~~ drivers/staging/media/atomisp/i2c/atomisp-ov2680.c: In function ‘ov2680_detect’: drivers/staging/media/atomisp/i2c/atomisp-ov2680.c:1164:5: warning: variable ‘revision’ set but not used [-Wunused-but-set-variable] u8 revision; ^~~~~~~~ Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/media/atomisp/i2c/ov2680.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/ov2680.c b/drivers/staging/media/atomisp/i2c/ov2680.c index 51b7d61df0f5..179576224319 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.c +++ b/drivers/staging/media/atomisp/i2c/ov2680.c @@ -396,12 +396,11 @@ static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, { struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov2680_device *dev = to_ov2680_sensor(sd); - u16 vts,hts; + u16 vts; int ret,exp_val; dev_dbg(&client->dev, "+++++++__ov2680_set_exposure coarse_itg %d, gain %d, digitgain %d++\n",coarse_itg, gain, digitgain); - hts = ov2680_res[dev->fmt_idx].pixels_per_line; vts = ov2680_res[dev->fmt_idx].lines_per_frame; /* group hold */ @@ -1190,7 +1189,8 @@ static int ov2680_detect(struct i2c_client *client) OV2680_SC_CMMN_SUB_ID, &high); revision = (u8) high & 0x0f; - dev_info(&client->dev, "sensor_revision id = 0x%x\n", id); + dev_info(&client->dev, "sensor_revision id = 0x%x, rev= %d\n", + id, revision); return 0; } -- GitLab From 6a43d5a3ca6c03103e614ac7d075615ef6609731 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 30 Apr 2018 13:56:32 +0100 Subject: [PATCH 0421/1001] arm64: cmpwait: Clear event register before arming exclusive monitor [ Upstream commit 1cfc63b5ae60fe7e01773f38132f98d8b13a99a0 ] When waiting for a cacheline to change state in cmpwait, we may immediately wake-up the first time around the outer loop if the event register was already set (for example, because of the event stream). Avoid these spurious wakeups by explicitly clearing the event register before loading the cacheline and setting the exclusive monitor. Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/cmpxchg.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h index ae852add053d..0f2e1ab5e166 100644 --- a/arch/arm64/include/asm/cmpxchg.h +++ b/arch/arm64/include/asm/cmpxchg.h @@ -229,7 +229,9 @@ static inline void __cmpwait_case_##name(volatile void *ptr, \ unsigned long tmp; \ \ asm volatile( \ - " ldxr" #sz "\t%" #w "[tmp], %[v]\n" \ + " sevl\n" \ + " wfe\n" \ + " ldxr" #sz "\t%" #w "[tmp], %[v]\n" \ " eor %" #w "[tmp], %" #w "[tmp], %" #w "[val]\n" \ " cbnz %" #w "[tmp], 1f\n" \ " wfe\n" \ -- GitLab From d85073283aa7f838b3add199cbccfaed0a943bb5 Mon Sep 17 00:00:00 2001 From: Terry Junge Date: Mon, 30 Apr 2018 13:32:46 -0700 Subject: [PATCH 0422/1001] HID: hid-plantronics: Re-resend Update to map button for PTT products [ Upstream commit 37e376df5f4993677c33968a0c19b0c5acbf1108 ] Add a mapping for Push-To-Talk joystick trigger button. Tested on ChromeBox/ChromeBook with various Plantronics devices. Signed-off-by: Terry Junge Signed-off-by: Jiri Kosina Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-plantronics.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-plantronics.c b/drivers/hid/hid-plantronics.c index febb21ee190e..584b10d3fc3d 100644 --- a/drivers/hid/hid-plantronics.c +++ b/drivers/hid/hid-plantronics.c @@ -2,7 +2,7 @@ * Plantronics USB HID Driver * * Copyright (c) 2014 JD Cole - * Copyright (c) 2015 Terry Junge + * Copyright (c) 2015-2018 Terry Junge */ /* @@ -48,6 +48,10 @@ static int plantronics_input_mapping(struct hid_device *hdev, unsigned short mapped_key; unsigned long plt_type = (unsigned long)hid_get_drvdata(hdev); + /* special case for PTT products */ + if (field->application == HID_GD_JOYSTICK) + goto defaulted; + /* handle volume up/down mapping */ /* non-standard types or multi-HID interfaces - plt_type is PID */ if (!(plt_type & HID_USAGE_PAGE)) { -- GitLab From 3ee32f73fc7258b5470286d8d05585b3b4d10486 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 23 Apr 2018 01:40:16 +0000 Subject: [PATCH 0423/1001] arm64: dts: renesas: salvator-common: use audio-graph-card for Sound [ Upstream commit 06a574c7ef69bd0bd26ed08e35967acb76622ab3 ] Current Sound is using simple-audio-card which can't support HDMI. To use HDMI sound, we need to use audio-graph-card. But, one note is that r8a7795 has 2 HDMI ports, but r8a7796 has 1. Because of this mismatch, supporting HDMI on salvator-common is impossible. Thus, this patch exchange sound card to audio-graph-card and keep supporting ak4613 as 1st sound node. r8a7795/r8a7796 salvator-x{s} need to add HDMI sound individually. Signed-off-by: Kuninori Morimoto Tested-by: Nguyen Viet Dung Signed-off-by: Simon Horman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../boot/dts/renesas/salvator-common.dtsi | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/arch/arm64/boot/dts/renesas/salvator-common.dtsi b/arch/arm64/boot/dts/renesas/salvator-common.dtsi index 9eb11a8d9eda..26a978616071 100644 --- a/arch/arm64/boot/dts/renesas/salvator-common.dtsi +++ b/arch/arm64/boot/dts/renesas/salvator-common.dtsi @@ -93,20 +93,12 @@ regulator-always-on; }; - rsnd_ak4613: sound { - compatible = "simple-audio-card"; + sound_card: sound { + compatible = "audio-graph-card"; - simple-audio-card,format = "left_j"; - simple-audio-card,bitclock-master = <&sndcpu>; - simple-audio-card,frame-master = <&sndcpu>; + label = "rcar-sound"; - sndcpu: simple-audio-card,cpu { - sound-dai = <&rcar_sound>; - }; - - sndcodec: simple-audio-card,codec { - sound-dai = <&ak4613>; - }; + dais = <&rsnd_port0>; }; vbus0_usb2: regulator-vbus0-usb2 { @@ -320,6 +312,12 @@ asahi-kasei,out4-single-end; asahi-kasei,out5-single-end; asahi-kasei,out6-single-end; + + port { + ak4613_endpoint: endpoint { + remote-endpoint = <&rsnd_endpoint0>; + }; + }; }; cs2000: clk_multiplier@4f { @@ -538,10 +536,18 @@ <&audio_clk_c>, <&cpg CPG_CORE CPG_AUDIO_CLK_I>; - rcar_sound,dai { - dai0 { - playback = <&ssi0 &src0 &dvc0>; - capture = <&ssi1 &src1 &dvc1>; + ports { + rsnd_port0: port@0 { + rsnd_endpoint0: endpoint { + remote-endpoint = <&ak4613_endpoint>; + + dai-format = "left_j"; + bitclock-master = <&rsnd_endpoint0>; + frame-master = <&rsnd_endpoint0>; + + playback = <&ssi0 &src0 &dvc0>; + capture = <&ssi1 &src1 &dvc1>; + }; }; }; }; -- GitLab From 14bedc05ab2d18bd17014615f0897545337eabf1 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Tue, 24 Apr 2018 15:15:13 +0200 Subject: [PATCH 0424/1001] drm/radeon: fix mode_valid's return type [ Upstream commit 7a47f20eb1fb8fa8d7a8fe3a4fd8c721f04c2174 ] The method struct drm_connector_helper_funcs::mode_valid is defined as returning an 'enum drm_mode_status' but the driver implementation for this method uses an 'int' for it. Fix this by using 'enum drm_mode_status' in the driver too. Signed-off-by: Luc Van Oostenryck Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_connectors.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 424cd1b66575..337d3a1c2a40 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -853,7 +853,7 @@ static int radeon_lvds_get_modes(struct drm_connector *connector) return ret; } -static int radeon_lvds_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_encoder *encoder = radeon_best_single_encoder(connector); @@ -1013,7 +1013,7 @@ static int radeon_vga_get_modes(struct drm_connector *connector) return ret; } -static int radeon_vga_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_vga_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; @@ -1157,7 +1157,7 @@ static int radeon_tv_get_modes(struct drm_connector *connector) return 1; } -static int radeon_tv_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { if ((mode->hdisplay > 1024) || (mode->vdisplay > 768)) @@ -1499,7 +1499,7 @@ static void radeon_dvi_force(struct drm_connector *connector) radeon_connector->use_digital = true; } -static int radeon_dvi_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_dvi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; @@ -1801,7 +1801,7 @@ radeon_dp_detect(struct drm_connector *connector, bool force) return ret; } -static int radeon_dp_mode_valid(struct drm_connector *connector, +static enum drm_mode_status radeon_dp_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; -- GitLab From b42848b2a819ae2fd310080bfb32221fde9e084d Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Wed, 18 Apr 2018 16:26:18 -0400 Subject: [PATCH 0425/1001] drm/amdgpu: Remove VRAM from shared bo domains. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 9b3f217faf48603c91d4ca44a18e6ff74c3c1c0c ] This fixes an issue introduced by change "allow framebuffer in GART memory as well" which could lead to a shared buffer ending up pinned in vram. Use GTT if it is included in the domain, otherwise return an error. Signed-off-by: Samuel Li Reviewed-by: Alex Deucher Reviewed-by: Christian König Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 1360a24d2ede..f08624f2f209 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -683,8 +683,12 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, return -EINVAL; /* A shared bo cannot be migrated to VRAM */ - if (bo->prime_shared_count && (domain == AMDGPU_GEM_DOMAIN_VRAM)) - return -EINVAL; + if (bo->prime_shared_count) { + if (domain & AMDGPU_GEM_DOMAIN_GTT) + domain = AMDGPU_GEM_DOMAIN_GTT; + else + return -EINVAL; + } if (bo->pin_count) { uint32_t mem_type = bo->tbo.mem.mem_type; -- GitLab From 83eef34c65f179af463924e34fc687426ac2f705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Thu, 10 May 2018 23:59:19 +0200 Subject: [PATCH 0426/1001] powerpc/embedded6xx/hlwd-pic: Prevent interrupts from being handled by Starlet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 9dcb3df4281876731e4e8bff7940514d72375154 ] The interrupt controller inside the Wii's Hollywood chip is connected to two masters, the "Broadway" PowerPC and the "Starlet" ARM926, each with their own interrupt status and mask registers. When booting the Wii with mini[1], interrupts from the SD card controller (IRQ 7) are handled by the ARM, because mini provides SD access over IPC. Linux however can't currently use or disable this IPC service, so both sides try to handle IRQ 7 without coordination. Let's instead make sure that all interrupts that are unmasked on the PPC side are masked on the ARM side; this will also make sure that Linux can properly talk to the SD card controller (and potentially other devices). If access to a device through IPC is desired in the future, interrupts from that device should not be handled by Linux directly. [1]: https://github.com/lewurm/mini Signed-off-by: Jonathan Neuschäfer Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/embedded6xx/hlwd-pic.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index 89c54de88b7a..bf4a125faec6 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -35,6 +35,8 @@ */ #define HW_BROADWAY_ICR 0x00 #define HW_BROADWAY_IMR 0x04 +#define HW_STARLET_ICR 0x08 +#define HW_STARLET_IMR 0x0c /* @@ -74,6 +76,9 @@ static void hlwd_pic_unmask(struct irq_data *d) void __iomem *io_base = irq_data_get_irq_chip_data(d); setbits32(io_base + HW_BROADWAY_IMR, 1 << irq); + + /* Make sure the ARM (aka. Starlet) doesn't handle this interrupt. */ + clrbits32(io_base + HW_STARLET_IMR, 1 << irq); } -- GitLab From d0eca5d32b11ef4d7c176a362c55e4ed53f13a73 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 9 May 2018 12:12:15 -0700 Subject: [PATCH 0427/1001] HID: i2c-hid: check if device is there before really probing [ Upstream commit b3a81b6c4fc6730ac49e20d789a93c0faabafc98 ] On many Chromebooks touch devices are multi-sourced; the components are electrically compatible and one can be freely swapped for another without changing the OS image or firmware. To avoid bunch of scary messages when device is not actually present in the system let's try testing basic communication with it and if there is no response terminate probe early with -ENXIO. Signed-off-by: Dmitry Torokhov Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/hid/i2c-hid/i2c-hid.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index d92827556389..136a34dc31b8 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -1036,6 +1036,14 @@ static int i2c_hid_probe(struct i2c_client *client, pm_runtime_enable(&client->dev); device_enable_async_suspend(&client->dev); + /* Make sure there is something at this address */ + ret = i2c_smbus_read_byte(client); + if (ret < 0) { + dev_dbg(&client->dev, "nothing at this address: %d\n", ret); + ret = -ENXIO; + goto err_pm; + } + ret = i2c_hid_fetch_hid_descriptor(ihid); if (ret < 0) goto err_pm; -- GitLab From d7ed9da96a8a4cb47601e56f5632167b46679fbb Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Mon, 14 May 2018 12:04:01 -0500 Subject: [PATCH 0428/1001] EDAC, altera: Fix ARM64 build warning [ Upstream commit 9ef20753e044f7468c4113e5aecd785419b0b3cc ] The kbuild test robot reported the following warning: drivers/edac/altera_edac.c: In function 'ocram_free_mem': drivers/edac/altera_edac.c:1410:42: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] gen_pool_free((struct gen_pool *)other, (u32)p, size); ^ After adding support for ARM64 architectures, the unsigned long parameter is 64 bits and causes a build warning on 64-bit configs. Fix by casting to the correct size (unsigned long) instead of u32. Reported-by: kbuild test robot Signed-off-by: Thor Thayer Cc: linux-arm-kernel@lists.infradead.org Cc: linux-edac Fixes: c3eea1942a16 ("EDAC, altera: Add Altera L2 cache and OCRAM support") Link: http://lkml.kernel.org/r/1526317441-4996-1-git-send-email-thor.thayer@linux.intel.com Signed-off-by: Borislav Petkov Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/edac/altera_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 346c4987b284..38983f56ad0d 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -1106,7 +1106,7 @@ static void *ocram_alloc_mem(size_t size, void **other) static void ocram_free_mem(void *p, size_t size, void *other) { - gen_pool_free((struct gen_pool *)other, (u32)p, size); + gen_pool_free((struct gen_pool *)other, (unsigned long)p, size); } static const struct edac_device_prv_data ocramecc_data = { -- GitLab From b565e4e9dd09e55bfb0340e58d67c395dcee30c2 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 20 Apr 2018 17:41:31 +0200 Subject: [PATCH 0429/1001] ARM: dts: stih407-pinctrl: Fix complain about IRQ_TYPE_NONE usage [ Upstream commit e95b8e718f9bd2386a29639dd21c633b4951dc21 ] Since commit 83a86fbb5b56 ("irqchip/gic: Loudly complain about the use of IRQ_TYPE_NONE") kernel is complaining about the IRQ_TYPE_NONE usage which shouldn't be used. Use IRQ_TYPE_LEVEL_HIGH instead. Signed-off-by: Patrice Chotard Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/stih407-pinctrl.dtsi | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/stih407-pinctrl.dtsi b/arch/arm/boot/dts/stih407-pinctrl.dtsi index bd1a82e8fffe..fe501d32d059 100644 --- a/arch/arm/boot/dts/stih407-pinctrl.dtsi +++ b/arch/arm/boot/dts/stih407-pinctrl.dtsi @@ -52,7 +52,7 @@ st,syscfg = <&syscfg_sbc>; reg = <0x0961f080 0x4>; reg-names = "irqmux"; - interrupts = ; + interrupts = ; interrupt-names = "irqmux"; ranges = <0 0x09610000 0x6000>; @@ -376,7 +376,7 @@ st,syscfg = <&syscfg_front>; reg = <0x0920f080 0x4>; reg-names = "irqmux"; - interrupts = ; + interrupts = ; interrupt-names = "irqmux"; ranges = <0 0x09200000 0x10000>; @@ -936,7 +936,7 @@ st,syscfg = <&syscfg_front>; reg = <0x0921f080 0x4>; reg-names = "irqmux"; - interrupts = ; + interrupts = ; interrupt-names = "irqmux"; ranges = <0 0x09210000 0x10000>; @@ -969,7 +969,7 @@ st,syscfg = <&syscfg_rear>; reg = <0x0922f080 0x4>; reg-names = "irqmux"; - interrupts = ; + interrupts = ; interrupt-names = "irqmux"; ranges = <0 0x09220000 0x6000>; @@ -1164,7 +1164,7 @@ st,syscfg = <&syscfg_flash>; reg = <0x0923f080 0x4>; reg-names = "irqmux"; - interrupts = ; + interrupts = ; interrupt-names = "irqmux"; ranges = <0 0x09230000 0x3000>; -- GitLab From 9c552c4e262fb4a640ada039b395b954960a066e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 7 May 2018 15:40:05 +0200 Subject: [PATCH 0430/1001] ARM: dts: emev2: Add missing interrupt-affinity to PMU node [ Upstream commit 7207b94754b6f503b278b5b200faaf662ffa1da8 ] The PMU node references two interrupts, but lacks the interrupt-affinity property, which is required in that case: hw perfevents: no interrupt-affinity property for /pmu, guessing. Add the missing property to fix this. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/emev2.dtsi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/emev2.dtsi b/arch/arm/boot/dts/emev2.dtsi index 42ea246e71cb..fec1241b858f 100644 --- a/arch/arm/boot/dts/emev2.dtsi +++ b/arch/arm/boot/dts/emev2.dtsi @@ -31,13 +31,13 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <0>; clock-frequency = <533000000>; }; - cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <1>; @@ -57,6 +57,7 @@ compatible = "arm,cortex-a9-pmu"; interrupts = , ; + interrupt-affinity = <&cpu0>, <&cpu1>; }; clocks@e0110000 { -- GitLab From 901366594729fdd10d1288487dd86011d6f135d0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 7 May 2018 15:40:04 +0200 Subject: [PATCH 0431/1001] ARM: dts: sh73a0: Add missing interrupt-affinity to PMU node [ Upstream commit 57a66497e1b7486609250a482f05935eae5035e9 ] The PMU node references two interrupts, but lacks the interrupt-affinity property, which is required in that case: hw perfevents: no interrupt-affinity property for /pmu, guessing. Add the missing property to fix this. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/sh73a0.dtsi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/sh73a0.dtsi b/arch/arm/boot/dts/sh73a0.dtsi index 4ea5c5a16c57..5fc24d4c2d5d 100644 --- a/arch/arm/boot/dts/sh73a0.dtsi +++ b/arch/arm/boot/dts/sh73a0.dtsi @@ -22,7 +22,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <0>; @@ -30,7 +30,7 @@ power-domains = <&pd_a2sl>; next-level-cache = <&L2>; }; - cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <1>; @@ -89,6 +89,7 @@ compatible = "arm,cortex-a9-pmu"; interrupts = , ; + interrupt-affinity = <&cpu0>, <&cpu1>; }; cmt1: timer@e6138000 { -- GitLab From 6fdc5235693b333f28a6581d049799156ba2807a Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Fri, 11 May 2018 12:07:03 +0100 Subject: [PATCH 0432/1001] nvmem: properly handle returned value nvmem_reg_read [ Upstream commit 50808bfcc14b854775a9f1d0abe3dac2babcf5c3 ] Function nvmem_reg_read can return a non zero value indicating an error. This returned value must be read and error propagated to nvmem_cell_prepare_write_buffer. Silence the following gcc warning (W=1): drivers/nvmem/core.c:1093:9: warning: variable 'rc' set but not used [-Wunused-but-set-variable] Signed-off-by: Mathieu Malaterre Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index d12e5de78e70..2afafd5d8915 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -1049,6 +1049,8 @@ static inline void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, /* setup the first byte with lsb bits from nvmem */ rc = nvmem_reg_read(nvmem, cell->offset, &v, 1); + if (rc) + goto err; *b++ |= GENMASK(bit_offset - 1, 0) & v; /* setup rest of the byte if any */ @@ -1067,11 +1069,16 @@ static inline void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, /* setup the last byte with msb bits from nvmem */ rc = nvmem_reg_read(nvmem, cell->offset + cell->bytes - 1, &v, 1); + if (rc) + goto err; *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; } return buf; +err: + kfree(buf); + return ERR_PTR(rc); } /** -- GitLab From 731b918a624c48dba4a48767668fac57f8a7a42e Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Thu, 10 May 2018 05:59:48 -0700 Subject: [PATCH 0433/1001] i40e: free the skb after clearing the bitlock [ Upstream commit c79756cb5f084736b138da9319a02f7c72644548 ] In commit bbc4e7d273b5 ("i40e: fix race condition with PTP_TX_IN_PROGRESS bits") we modified the code which handles Tx timestamps so that we would clear the progress bit as soon as possible. A later commit 0bc0706b46cd ("i40e: check for Tx timestamp timeouts during watchdog") introduced similar code for detecting and handling cleanup of a blocked Tx timestamp. This code did not use the same pattern for cleaning up the skb. Update this code to wait to free the skb until after the bit lock is free, by first setting the ptp_tx_skb to NULL and clearing the lock. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index d8456c381c99..ef242dbae116 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -337,6 +337,8 @@ void i40e_ptp_rx_hang(struct i40e_pf *pf) **/ void i40e_ptp_tx_hang(struct i40e_pf *pf) { + struct sk_buff *skb; + if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_tx) return; @@ -349,9 +351,12 @@ void i40e_ptp_tx_hang(struct i40e_pf *pf) * within a second it is reasonable to assume that we never will. */ if (time_is_before_jiffies(pf->ptp_tx_start + HZ)) { - dev_kfree_skb_any(pf->ptp_tx_skb); + skb = pf->ptp_tx_skb; pf->ptp_tx_skb = NULL; clear_bit_unlock(__I40E_PTP_TX_IN_PROGRESS, pf->state); + + /* Free the skb after we clear the bitlock */ + dev_kfree_skb_any(skb); pf->tx_hwtstamp_timeouts++; } } -- GitLab From deb1feaad03a78b545c949e54582ae57b3c56982 Mon Sep 17 00:00:00 2001 From: DaeRyong Jeong Date: Tue, 1 May 2018 00:27:04 +0900 Subject: [PATCH 0434/1001] tty: Fix data race in tty_insert_flip_string_fixed_flag [ Upstream commit b6da31b2c07c46f2dcad1d86caa835227a16d9ff ] Unlike normal serials, in pty layer, there is no guarantee that multiple threads don't insert input characters at the same time. If it is happened, tty_insert_flip_string_fixed_flag can be executed concurrently. This can lead slab out-of-bounds write in tty_insert_flip_string_fixed_flag. Call sequences are as follows. CPU0 CPU1 n_tty_ioctl_helper n_tty_ioctl_helper __start_tty tty_send_xchar tty_wakeup pty_write n_hdlc_tty_wakeup tty_insert_flip_string n_hdlc_send_frames tty_insert_flip_string_fixed_flag pty_write tty_insert_flip_string tty_insert_flip_string_fixed_flag To fix the race, acquire port->lock in pty_write() before it inserts input characters to tty buffer. It prevents multiple threads from inserting input characters concurrently. The crash log is as follows: BUG: KASAN: slab-out-of-bounds in tty_insert_flip_string_fixed_flag+0xb5/ 0x130 drivers/tty/tty_buffer.c:316 at addr ffff880114fcc121 Write of size 1792 by task syz-executor0/30017 CPU: 1 PID: 30017 Comm: syz-executor0 Not tainted 4.8.0 #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.8.2-0-g33fbe13 by qemu-project.org 04/01/2014 0000000000000000 ffff88011638f888 ffffffff81694cc3 ffff88007d802140 ffff880114fcb300 ffff880114fcc300 ffff880114fcb300 ffff88011638f8b0 ffffffff8130075c ffff88011638f940 ffff88007d802140 ffff880194fcc121 Call Trace: __dump_stack lib/dump_stack.c:15 [inline] dump_stack+0xb3/0x110 lib/dump_stack.c:51 kasan_object_err+0x1c/0x70 mm/kasan/report.c:156 print_address_description mm/kasan/report.c:194 [inline] kasan_report_error+0x1f7/0x4e0 mm/kasan/report.c:283 kasan_report+0x36/0x40 mm/kasan/report.c:303 check_memory_region_inline mm/kasan/kasan.c:292 [inline] check_memory_region+0x13e/0x1a0 mm/kasan/kasan.c:299 memcpy+0x37/0x50 mm/kasan/kasan.c:335 tty_insert_flip_string_fixed_flag+0xb5/0x130 drivers/tty/tty_buffer.c:316 tty_insert_flip_string include/linux/tty_flip.h:35 [inline] pty_write+0x7f/0xc0 drivers/tty/pty.c:115 n_hdlc_send_frames+0x1d4/0x3b0 drivers/tty/n_hdlc.c:419 n_hdlc_tty_wakeup+0x73/0xa0 drivers/tty/n_hdlc.c:496 tty_wakeup+0x92/0xb0 drivers/tty/tty_io.c:601 __start_tty.part.26+0x66/0x70 drivers/tty/tty_io.c:1018 __start_tty+0x34/0x40 drivers/tty/tty_io.c:1013 n_tty_ioctl_helper+0x146/0x1e0 drivers/tty/tty_ioctl.c:1138 n_hdlc_tty_ioctl+0xb3/0x2b0 drivers/tty/n_hdlc.c:794 tty_ioctl+0xa85/0x16d0 drivers/tty/tty_io.c:2992 vfs_ioctl fs/ioctl.c:43 [inline] do_vfs_ioctl+0x13e/0xba0 fs/ioctl.c:679 SYSC_ioctl fs/ioctl.c:694 [inline] SyS_ioctl+0x8f/0xc0 fs/ioctl.c:685 entry_SYSCALL_64_fastpath+0x1f/0xbd Signed-off-by: DaeRyong Jeong Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/pty.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 64338442050e..899e8fe5e00f 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -110,16 +110,19 @@ static void pty_unthrottle(struct tty_struct *tty) static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c) { struct tty_struct *to = tty->link; + unsigned long flags; if (tty->stopped) return 0; if (c > 0) { + spin_lock_irqsave(&to->port->lock, flags); /* Stuff the data into the input queue of the other end */ c = tty_insert_flip_string(to->port, buf, c); /* And shovel */ if (c) tty_flip_buffer_push(to->port); + spin_unlock_irqrestore(&to->port->lock, flags); } return c; } -- GitLab From fa57e8d54494f1a9b636dbd18d566217ef29423b Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 8 May 2018 13:14:33 +0100 Subject: [PATCH 0435/1001] dma-iommu: Fix compilation when !CONFIG_IOMMU_DMA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 8a22a3e1e768c309b718f99bd86f9f25a453e0dc ] Inclusion of include/dma-iommu.h when CONFIG_IOMMU_DMA is not selected results in the following splat: In file included from drivers/irqchip/irq-gic-v3-mbi.c:20:0: ./include/linux/dma-iommu.h:95:69: error: unknown type name ‘dma_addr_t’ static inline int iommu_get_msi_cookie(struct iommu_domain *domain, dma_addr_t base) ^~~~~~~~~~ ./include/linux/dma-iommu.h:108:74: warning: ‘struct list_head’ declared inside parameter list will not be visible outside of this definition or declaration static inline void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list) ^~~~~~~~~ scripts/Makefile.build:312: recipe for target 'drivers/irqchip/irq-gic-v3-mbi.o' failed Fix it by including linux/types.h. Signed-off-by: Marc Zyngier Signed-off-by: Thomas Gleixner Cc: Rob Herring Cc: Jason Cooper Cc: Ard Biesheuvel Cc: Srinivas Kandagatla Cc: Thomas Petazzoni Cc: Miquel Raynal Link: https://lkml.kernel.org/r/20180508121438.11301-5-marc.zyngier@arm.com Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/linux/dma-iommu.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/dma-iommu.h b/include/linux/dma-iommu.h index 92f20832fd28..e8ca5e654277 100644 --- a/include/linux/dma-iommu.h +++ b/include/linux/dma-iommu.h @@ -17,6 +17,7 @@ #define __DMA_IOMMU_H #ifdef __KERNEL__ +#include #include #ifdef CONFIG_IOMMU_DMA -- GitLab From 240bc678f72629b9bf420d7dd75462fdcb70b2a8 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 10 May 2018 13:17:30 -0700 Subject: [PATCH 0436/1001] net: phy: phylink: Release link GPIO [ Upstream commit daab3349ad1a69663ccad278ed71d55974d104b4 ] We are not releasing the link GPIO descriptor with gpiod_put() which results in subsequent probing to get -EBUSY when calling fwnode_get_named_gpiod(). Fix this by doing the release in phylink_destroy(). Fixes: 9525ae83959b ("phylink: add phylink infrastructure") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/phylink.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 1b2fe74a44ea..e4a6ed88b9cf 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -561,6 +561,8 @@ void phylink_destroy(struct phylink *pl) { if (pl->sfp_bus) sfp_unregister_upstream(pl->sfp_bus); + if (!IS_ERR(pl->link_gpio)) + gpiod_put(pl->link_gpio); cancel_work_sync(&pl->resolve); kfree(pl); -- GitLab From adf9ceabfc168c26c83e7160103aa752c136cc1b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 12 Jul 2016 07:21:46 -0400 Subject: [PATCH 0437/1001] media: rcar_jpu: Add missing clk_disable_unprepare() on error in jpu_open() [ Upstream commit 43d0d3c52787df0221d1c52494daabd824fe84f1 ] Add the missing clk_disable_unprepare() before return from jpu_open() in the software reset error handling case. Signed-off-by: Wei Yongjun Acked-by: Mikhail Ulyanov Reviewed-by: Kieran Bingham Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/rcar_jpu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/rcar_jpu.c b/drivers/media/platform/rcar_jpu.c index 070bac36d766..2e2b8c409150 100644 --- a/drivers/media/platform/rcar_jpu.c +++ b/drivers/media/platform/rcar_jpu.c @@ -1280,7 +1280,7 @@ static int jpu_open(struct file *file) /* ...issue software reset */ ret = jpu_reset(jpu); if (ret) - goto device_prepare_rollback; + goto jpu_reset_rollback; } jpu->ref_count++; @@ -1288,6 +1288,8 @@ static int jpu_open(struct file *file) mutex_unlock(&jpu->mutex); return 0; +jpu_reset_rollback: + clk_disable_unprepare(jpu->clk); device_prepare_rollback: mutex_unlock(&jpu->mutex); v4l_prepare_rollback: -- GitLab From 885d2128ab7f7bf469c9441d2178081585003a74 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Wed, 9 May 2018 09:28:12 +0900 Subject: [PATCH 0438/1001] libata: Fix command retry decision [ Upstream commit 804689ad2d9b66d0d3920b48cf05881049d44589 ] For failed commands with valid sense data (e.g. NCQ commands), scsi_check_sense() is used in ata_analyze_tf() to determine if the command can be retried. In such case, rely on this decision and ignore the command error mask based decision done in ata_worth_retry(). This fixes useless retries of commands such as unaligned writes on zoned disks (TYPE_ZAC). Signed-off-by: Damien Le Moal Reviewed-by: Hannes Reinecke Signed-off-by: Tejun Heo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-eh.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 711dd91b5e2c..2651c81d1edf 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2217,12 +2217,16 @@ static void ata_eh_link_autopsy(struct ata_link *link) if (qc->err_mask & ~AC_ERR_OTHER) qc->err_mask &= ~AC_ERR_OTHER; - /* SENSE_VALID trumps dev/unknown error and revalidation */ + /* + * SENSE_VALID trumps dev/unknown error and revalidation. Upper + * layers will determine whether the command is worth retrying + * based on the sense data and device class/type. Otherwise, + * determine directly if the command is worth retrying using its + * error mask and flags. + */ if (qc->flags & ATA_QCFLAG_SENSE_VALID) qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER); - - /* determine whether the command is worth retrying */ - if (ata_eh_worth_retry(qc)) + else if (ata_eh_worth_retry(qc)) qc->flags |= ATA_QCFLAG_RETRY; /* accumulate error info */ -- GitLab From ce222fb1256b4c8c712bc894e395cd7640fc54ad Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 13 Apr 2018 14:54:17 +0200 Subject: [PATCH 0439/1001] ACPI / LPSS: Only call pwm_add_table() for Bay Trail PWM if PMIC HRV is 2 [ Upstream commit c975e472ec12392a0c34de1350e634310f8a1dea ] The Point of View mobii wintab p800w Bay Trail tablet comes with a Crystal Cove PMIC, yet uses the LPSS PWM for backlight control, rather then the Crystal Cove's PWM, so we need to call pwm_add_table() to add a pwm_backlight mapping for the LPSS pwm despite there being an INT33FD ACPI device present. On all Bay Trail devices the _HRV object of the INT33FD ACPI device will normally return 2, to indicate the Bay Trail variant of the CRC PMIC is present, except on this tablet where _HRV is 0xffff. I guess this is a hack to make the windows Crystal Cove PWM driver not bind. Out of the 44 DSTDs with an INT33FD device in there which I have (from different model devices) only the pov mobii wintab p800w uses 0xffff for the HRV. The byt_pwm_setup code calls acpi_dev_present to check for the presence of a INT33FD ACPI device which indicates that a CRC PMIC is present and if the INT33FD ACPI device is present then byt_pwm_setup will not add a pwm_backlight mapping for the LPSS pwm, so that the CRC PWM will get used instead. acpi_dev_present has a hrv parameter, this commit make us pass 2 instead of -1, so that things still match on normal tablets, but on this special case with its _HRV of 0xffff, the check will now fail so that the pwm_backlight mapping for the LPSS pwm gets added fixing backlight brightness control on this device. Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/acpi_lpss.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 602ae58ee2d8..75c3cb377b98 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -69,6 +69,10 @@ ACPI_MODULE_NAME("acpi_lpss"); #define LPSS_SAVE_CTX BIT(4) #define LPSS_NO_D3_DELAY BIT(5) +/* Crystal Cove PMIC shares same ACPI ID between different platforms */ +#define BYT_CRC_HRV 2 +#define CHT_CRC_HRV 3 + struct lpss_private_data; struct lpss_device_desc { @@ -162,7 +166,7 @@ static void byt_pwm_setup(struct lpss_private_data *pdata) if (!adev->pnp.unique_id || strcmp(adev->pnp.unique_id, "1")) return; - if (!acpi_dev_present("INT33FD", NULL, -1)) + if (!acpi_dev_present("INT33FD", NULL, BYT_CRC_HRV)) pwm_add_table(byt_pwm_lookup, ARRAY_SIZE(byt_pwm_lookup)); } -- GitLab From f3766ad7d325be5dae629f16f6027e2acf0a01bc Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Mon, 7 May 2018 14:09:46 -0400 Subject: [PATCH 0440/1001] media: media-device: fix ioctl function types [ Upstream commit daa36370b62428cca6d48d1b2530a8419f631c8c ] This change fixes function types for media device ioctls to avoid indirect call mismatches with Control-Flow Integrity checking. Signed-off-by: Sami Tolvanen Acked-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/media-device.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index e79f72b8b858..62b2c5d9bdfb 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -54,9 +54,10 @@ static int media_device_close(struct file *filp) return 0; } -static int media_device_get_info(struct media_device *dev, - struct media_device_info *info) +static long media_device_get_info(struct media_device *dev, void *arg) { + struct media_device_info *info = arg; + memset(info, 0, sizeof(*info)); if (dev->driver_name[0]) @@ -93,9 +94,9 @@ static struct media_entity *find_entity(struct media_device *mdev, u32 id) return NULL; } -static long media_device_enum_entities(struct media_device *mdev, - struct media_entity_desc *entd) +static long media_device_enum_entities(struct media_device *mdev, void *arg) { + struct media_entity_desc *entd = arg; struct media_entity *ent; ent = find_entity(mdev, entd->id); @@ -146,9 +147,9 @@ static void media_device_kpad_to_upad(const struct media_pad *kpad, upad->flags = kpad->flags; } -static long media_device_enum_links(struct media_device *mdev, - struct media_links_enum *links) +static long media_device_enum_links(struct media_device *mdev, void *arg) { + struct media_links_enum *links = arg; struct media_entity *entity; entity = find_entity(mdev, links->entity); @@ -194,9 +195,9 @@ static long media_device_enum_links(struct media_device *mdev, return 0; } -static long media_device_setup_link(struct media_device *mdev, - struct media_link_desc *linkd) +static long media_device_setup_link(struct media_device *mdev, void *arg) { + struct media_link_desc *linkd = arg; struct media_link *link = NULL; struct media_entity *source; struct media_entity *sink; @@ -222,9 +223,9 @@ static long media_device_setup_link(struct media_device *mdev, return __media_entity_setup_link(link, linkd->flags); } -static long media_device_get_topology(struct media_device *mdev, - struct media_v2_topology *topo) +static long media_device_get_topology(struct media_device *mdev, void *arg) { + struct media_v2_topology *topo = arg; struct media_entity *entity; struct media_interface *intf; struct media_pad *pad; -- GitLab From d49f8498042a5b7f99fff05a7c2adbf3135906d1 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Fri, 4 May 2018 17:53:35 -0400 Subject: [PATCH 0441/1001] media: saa7164: Fix driver name in debug output [ Upstream commit 0cc4655cb57af0b7e105d075c4f83f8046efafe7 ] This issue was reported by a user who downloaded a corrupt saa7164 firmware, then went looking for a valid xc5000 firmware to fix the error displayed...but the device in question has no xc5000, thus after much effort, the wild goose chase eventually led to a support call. The xc5000 has nothing to do with saa7164 (as far as I can tell), so replace the string with saa7164 as well as give a meaningful hint on the firmware mismatch. Signed-off-by: Brad Love Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/pci/saa7164/saa7164-fw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/pci/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c index ef4906406ebf..a50461861133 100644 --- a/drivers/media/pci/saa7164/saa7164-fw.c +++ b/drivers/media/pci/saa7164/saa7164-fw.c @@ -426,7 +426,8 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev) __func__, fw->size); if (fw->size != fwlength) { - printk(KERN_ERR "xc5000: firmware incorrect size\n"); + printk(KERN_ERR "saa7164: firmware incorrect size %zu != %u\n", + fw->size, fwlength); ret = -ENOMEM; goto out; } -- GitLab From 59d9b120600d981c2cf4b31a34334f75480cb7a3 Mon Sep 17 00:00:00 2001 From: Jane Wan Date: Tue, 8 May 2018 14:19:53 -0700 Subject: [PATCH 0442/1001] mtd: rawnand: fsl_ifc: fix FSL NAND driver to read all ONFI parameter pages [ Upstream commit a75bbe71a27875fdc61cde1af6d799037cef6bed ] Per ONFI specification (Rev. 4.0), if the CRC of the first parameter page read is not valid, the host should read redundant parameter page copies. Fix FSL NAND driver to read the two redundant copies which are mandatory in the specification. Signed-off-by: Jane Wan Signed-off-by: Boris Brezillon Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/fsl_ifc_nand.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 4005b427023c..16deba1a2385 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -342,9 +342,16 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, case NAND_CMD_READID: case NAND_CMD_PARAM: { + /* + * For READID, read 8 bytes that are currently used. + * For PARAM, read all 3 copies of 256-bytes pages. + */ + int len = 8; int timing = IFC_FIR_OP_RB; - if (command == NAND_CMD_PARAM) + if (command == NAND_CMD_PARAM) { timing = IFC_FIR_OP_RBCD; + len = 256 * 3; + } ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | @@ -354,12 +361,8 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, &ifc->ifc_nand.nand_fcr0); ifc_out32(column, &ifc->ifc_nand.row3); - /* - * although currently it's 8 bytes for READID, we always read - * the maximum 256 bytes(for PARAM) - */ - ifc_out32(256, &ifc->ifc_nand.nand_fbcr); - ifc_nand_ctrl->read_bytes = 256; + ifc_out32(len, &ifc->ifc_nand.nand_fbcr); + ifc_nand_ctrl->read_bytes = len; set_addr(mtd, 0, 0, 0); fsl_ifc_run_command(mtd); -- GitLab From af5e8846a5e9a34f61b672954db0810b74b79268 Mon Sep 17 00:00:00 2001 From: Sean Lanigan Date: Fri, 4 May 2018 16:48:23 +1000 Subject: [PATCH 0443/1001] brcmfmac: Add support for bcm43364 wireless chipset [ Upstream commit 9c4a121e82634aa000a702c98cd6f05b27d6e186 ] Add support for the BCM43364 chipset via an SDIO interface, as used in e.g. the Murata 1FX module. The BCM43364 uses the same firmware as the BCM43430 (which is already included), the only difference is the omission of Bluetooth. However, the SDIO_ID for the BCM43364 is 02D0:A9A4, giving it a MODALIAS of sdio:c00v02D0dA9A4, which doesn't get recognised and hence doesn't load the brcmfmac module. Adding the 'A9A4' ID in the appropriate place triggers the brcmfmac driver to load, and then correctly use the firmware file 'brcmfmac43430-sdio.bin'. Signed-off-by: Sean Lanigan Acked-by: Ulf Hansson Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 1 + include/linux/mmc/sdio_ids.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index cd587325e286..dd6e27513cc1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -1098,6 +1098,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43340), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43364), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4339), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430), diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index cdd66a5fbd5e..0a7abe8a407f 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -35,6 +35,7 @@ #define SDIO_DEVICE_ID_BROADCOM_4335_4339 0x4335 #define SDIO_DEVICE_ID_BROADCOM_4339 0x4339 #define SDIO_DEVICE_ID_BROADCOM_43362 0xa962 +#define SDIO_DEVICE_ID_BROADCOM_43364 0xa9a4 #define SDIO_DEVICE_ID_BROADCOM_43430 0xa9a6 #define SDIO_DEVICE_ID_BROADCOM_4345 0x4345 #define SDIO_DEVICE_ID_BROADCOM_43455 0xa9bf -- GitLab From d5d8223d7c67fb005407e0e569ea8cd5b9f4b4fa Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Tue, 8 May 2018 10:18:39 +0200 Subject: [PATCH 0444/1001] s390/cpum_sf: Add data entry sizes to sampling trailer entry [ Upstream commit 77715b7ddb446bd39a06f3376e85f4bb95b29bb8 ] The CPU Measurement sampling facility creates a trailer entry for each Sample-Data-Block of stored samples. The trailer entry contains the sizes (in bytes) of the stored sampling types: - basic-sampling data entry size - diagnostic-sampling data entry size Both sizes are 2 bytes long. This patch changes the trailer entry definition to reflect this. Fixes: fcc77f507333 ("s390/cpum_sf: Atomically reset trailer entry fields of sample-data-blocks") Signed-off-by: Thomas Richter Reviewed-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/cpu_mf.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h index 05480e4cc5ca..073837f204ee 100644 --- a/arch/s390/include/asm/cpu_mf.h +++ b/arch/s390/include/asm/cpu_mf.h @@ -132,7 +132,9 @@ struct hws_trailer_entry { unsigned int f:1; /* 0 - Block Full Indicator */ unsigned int a:1; /* 1 - Alert request control */ unsigned int t:1; /* 2 - Timestamp format */ - unsigned long long:61; /* 3 - 63: Reserved */ + unsigned int :29; /* 3 - 31: Reserved */ + unsigned int bsdes:16; /* 32-47: size of basic SDE */ + unsigned int dsdes:16; /* 48-63: size of diagnostic SDE */ }; unsigned long long flags; /* 0 - 63: All indicators */ }; -- GitLab From c9b5d1519c2400281b2c7dd121100725a8d6c11f Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Tue, 8 May 2018 07:53:39 +0200 Subject: [PATCH 0445/1001] perf: fix invalid bit in diagnostic entry [ Upstream commit 3c0a83b14ea71fef5ccc93a3bd2de5f892be3194 ] The s390 CPU measurement facility sampling mode supports basic entries and diagnostic entries. Each entry has a valid bit to indicate the status of the entry as valid or invalid. This bit is bit 31 in the diagnostic entry, but the bit mask definition refers to bit 30. Fix this by making the reserved field one bit larger. Fixes: 7e75fc3ff4cf ("s390/cpum_sf: Add raw data sampling to support the diagnostic-sampling function") Signed-off-by: Thomas Richter Reviewed-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/cpu_mf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h index 073837f204ee..bc764a674594 100644 --- a/arch/s390/include/asm/cpu_mf.h +++ b/arch/s390/include/asm/cpu_mf.h @@ -116,7 +116,7 @@ struct hws_basic_entry { struct hws_diag_entry { unsigned int def:16; /* 0-15 Data Entry Format */ - unsigned int R:14; /* 16-19 and 20-30 reserved */ + unsigned int R:15; /* 16-19 and 20-30 reserved */ unsigned int I:1; /* 31 entry valid or invalid */ u8 data[]; /* Machine-dependent sample data */ } __packed; -- GitLab From 112f47373e364dd508cd9515f626b3fc83fddb10 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 8 May 2018 03:18:39 -0400 Subject: [PATCH 0446/1001] bnxt_en: Check unsupported speeds in bnxt_update_link() on PF only. [ Upstream commit dac0490718bd17df5e3995ffca14255e5f9ed22d ] Only non-NPAR PFs need to actively check and manage unsupported link speeds. NPAR functions and VFs do not control the link speed and should skip the unsupported speed detection logic, to avoid warning messages from firmware rejecting the unsupported firmware calls. Signed-off-by: Michael Chan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index bfd2d0382f4c..94931318587c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5927,6 +5927,9 @@ static int bnxt_update_link(struct bnxt *bp, bool chng_link_state) } mutex_unlock(&bp->hwrm_cmd_lock); + if (!BNXT_SINGLE_PF(bp)) + return 0; + diff = link_info->support_auto_speeds ^ link_info->advertising; if ((link_info->support_auto_speeds | diff) != link_info->support_auto_speeds) { -- GitLab From a0e86c016bb4e8c59e57a99bf53762ad313593c5 Mon Sep 17 00:00:00 2001 From: Wenwen Wang Date: Mon, 7 May 2018 19:46:43 -0500 Subject: [PATCH 0447/1001] scsi: 3w-9xxx: fix a missing-check bug [ Upstream commit c9318a3e0218bc9dacc25be46b9eec363259536f ] In twa_chrdev_ioctl(), the ioctl driver command is firstly copied from the userspace pointer 'argp' and saved to the kernel object 'driver_command'. Then a security check is performed on the data buffer size indicated by 'driver_command', which is 'driver_command.buffer_length'. If the security check is passed, the entire ioctl command is copied again from the 'argp' pointer and saved to the kernel object 'tw_ioctl'. Then, various operations are performed on 'tw_ioctl' according to the 'cmd'. Given that the 'argp' pointer resides in userspace, a malicious userspace process can race to change the buffer size between the two copies. This way, the user can bypass the security check and inject invalid data buffer size. This can cause potential security issues in the following execution. This patch checks for capable(CAP_SYS_ADMIN) in twa_chrdev_open()t o avoid the above issues. Signed-off-by: Wenwen Wang Acked-by: Adam Radford Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/3w-9xxx.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 00e7968a1d70..a1388842e17e 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -886,6 +886,11 @@ static int twa_chrdev_open(struct inode *inode, struct file *file) unsigned int minor_number; int retval = TW_IOCTL_ERROR_OS_ENODEV; + if (!capable(CAP_SYS_ADMIN)) { + retval = -EACCES; + goto out; + } + minor_number = iminor(inode); if (minor_number >= twa_device_extension_count) goto out; -- GitLab From ca588ff3e7d649690bb80a1cca4ed3dd591d9cd7 Mon Sep 17 00:00:00 2001 From: Wenwen Wang Date: Mon, 7 May 2018 19:54:01 -0500 Subject: [PATCH 0448/1001] scsi: 3w-xxxx: fix a missing-check bug [ Upstream commit 9899e4d3523faaef17c67141aa80ff2088f17871 ] In tw_chrdev_ioctl(), the length of the data buffer is firstly copied from the userspace pointer 'argp' and saved to the kernel object 'data_buffer_length'. Then a security check is performed on it to make sure that the length is not more than 'TW_MAX_IOCTL_SECTORS * 512'. Otherwise, an error code -EINVAL is returned. If the security check is passed, the entire ioctl command is copied again from the 'argp' pointer and saved to the kernel object 'tw_ioctl'. Then, various operations are performed on 'tw_ioctl' according to the 'cmd'. Given that the 'argp' pointer resides in userspace, a malicious userspace process can race to change the buffer length between the two copies. This way, the user can bypass the security check and inject invalid data buffer length. This can cause potential security issues in the following execution. This patch checks for capable(CAP_SYS_ADMIN) in tw_chrdev_open() to avoid the above issues. Signed-off-by: Wenwen Wang Acked-by: Adam Radford Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/3w-xxxx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 33261b690774..f6179e3d6953 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -1033,6 +1033,9 @@ static int tw_chrdev_open(struct inode *inode, struct file *file) dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_open()\n"); + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + minor_number = iminor(inode); if (minor_number >= tw_device_extension_count) return -ENODEV; -- GitLab From 13e4e358b94c2c07257a6b50170af93681ae10eb Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 3 May 2018 13:54:32 +0300 Subject: [PATCH 0449/1001] scsi: megaraid: silence a static checker bug [ Upstream commit 27e833dabab74ee665e487e291c9afc6d71effba ] If we had more than 32 megaraid cards then it would cause memory corruption. That's not likely, of course, but it's handy to enforce it and make the static checker happy. Signed-off-by: Dan Carpenter Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/megaraid.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 7195cff51d4c..9b6f5d024dba 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -4199,6 +4199,9 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) int irq, i, j; int error = -ENODEV; + if (hba_count >= MAX_CONTROLLERS) + goto out; + if (pci_enable_device(pdev)) goto out; pci_set_master(pdev); -- GitLab From ad1562ae81357df085117c3ee61513ec5836c98b Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Wed, 2 May 2018 23:56:31 +0800 Subject: [PATCH 0450/1001] scsi: hisi_sas: config ATA de-reset as an constrained command for v3 hw [ Upstream commit 9413532788df7470297dd0475995c5dc5b07f362 ] As a unconstrained command, a command can be sent to SATA disk even if SATA disk status is BUSY, ERR or DRQ. If an ATA reset assert is successful but ATA reset de-assert fails, then it will retry the reset de-assert. If reset de- assert retry is successful, we think it is okay to probe the device but actually it still has Err status. Apparently we need to retry the ATA reset assertion and de- assertion instead for this mentioned scenario. As such, we config ATA reset assert as a constrained command, if ATA reset de-assert fails, then ATA reset de-assert retry will also fail. Then we will retry the proper process of ATA reset assert and de-assert again. Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 2e5fa9717be8..871962b2e2f6 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -328,10 +328,11 @@ enum { #define DIR_TO_DEVICE 2 #define DIR_RESERVED 3 -#define CMD_IS_UNCONSTRAINT(cmd) \ - ((cmd == ATA_CMD_READ_LOG_EXT) || \ - (cmd == ATA_CMD_READ_LOG_DMA_EXT) || \ - (cmd == ATA_CMD_DEV_RESET)) +#define FIS_CMD_IS_UNCONSTRAINED(fis) \ + ((fis.command == ATA_CMD_READ_LOG_EXT) || \ + (fis.command == ATA_CMD_READ_LOG_DMA_EXT) || \ + ((fis.command == ATA_CMD_DEV_RESET) && \ + ((fis.control & ATA_SRST) != 0))) static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) { @@ -1044,7 +1045,7 @@ static int prep_ata_v3_hw(struct hisi_hba *hisi_hba, << CMD_HDR_FRAME_TYPE_OFF; dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF; - if (CMD_IS_UNCONSTRAINT(task->ata_task.fis.command)) + if (FIS_CMD_IS_UNCONSTRAINED(task->ata_task.fis)) dw1 |= 1 << CMD_HDR_UNCON_CMD_OFF; hdr->dw1 = cpu_to_le32(dw1); -- GitLab From de3da42dc775f991dd4aa94b4407c06d59be7395 Mon Sep 17 00:00:00 2001 From: Chad Dupuis Date: Wed, 25 Apr 2018 06:09:02 -0700 Subject: [PATCH 0451/1001] scsi: qedf: Set the UNLOADING flag when removing a vport [ Upstream commit 4f4616ceebaf045c59e8a6aa01f08826d18d5c63 ] Similar to what we do when we remove a PCI function, set the QEDF_UNLOADING flag to prevent any requests from being queued while a vport is being deleted. This prevents any requests from getting stuck in limbo when the vport is unloaded or deleted. Fixes the crash: PID: 106676 TASK: ffff9a436aa90000 CPU: 12 COMMAND: "multipathd" #0 [ffff9a43567d3550] machine_kexec+522 at ffffffffaca60b2a #1 [ffff9a43567d35b0] __crash_kexec+114 at ffffffffacb13512 #2 [ffff9a43567d3680] crash_kexec+48 at ffffffffacb13600 #3 [ffff9a43567d3698] oops_end+168 at ffffffffad117768 #4 [ffff9a43567d36c0] no_context+645 at ffffffffad106f52 #5 [ffff9a43567d3710] __bad_area_nosemaphore+116 at ffffffffad106fe9 #6 [ffff9a43567d3760] bad_area+70 at ffffffffad107379 #7 [ffff9a43567d3788] __do_page_fault+1247 at ffffffffad11a8cf #8 [ffff9a43567d37f0] do_page_fault+53 at ffffffffad11a915 #9 [ffff9a43567d3820] page_fault+40 at ffffffffad116768 [exception RIP: qedf_init_task+61] RIP: ffffffffc0e13c2d RSP: ffff9a43567d38d0 RFLAGS: 00010046 RAX: 0000000000000000 RBX: ffffbe920472c738 RCX: ffff9a434fa0e3e8 RDX: ffff9a434f695280 RSI: ffffbe920472c738 RDI: ffff9a43aa359c80 RBP: ffff9a43567d3950 R8: 0000000000000c15 R9: ffff9a3fb09b9880 R10: ffff9a434fa0e3e8 R11: ffff9a43567d35ce R12: 0000000000000000 R13: ffff9a434f695280 R14: ffff9a43aa359c80 R15: ffff9a3fb9e005c0 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 Signed-off-by: Chad Dupuis Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qedf/qedf_main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 7c0064500cc5..382edb79a0de 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -1649,6 +1649,15 @@ static int qedf_vport_destroy(struct fc_vport *vport) struct Scsi_Host *shost = vport_to_shost(vport); struct fc_lport *n_port = shost_priv(shost); struct fc_lport *vn_port = vport->dd_data; + struct qedf_ctx *qedf = lport_priv(vn_port); + + if (!qedf) { + QEDF_ERR(NULL, "qedf is NULL.\n"); + goto out; + } + + /* Set unloading bit on vport qedf_ctx to prevent more I/O */ + set_bit(QEDF_UNLOADING, &qedf->flags); mutex_lock(&n_port->lp_mutex); list_del(&vn_port->list); @@ -1675,6 +1684,7 @@ static int qedf_vport_destroy(struct fc_vport *vport) if (vn_port->host) scsi_host_put(vn_port->host); +out: return 0; } -- GitLab From 52a21fcafa717002402c0e28c9e466950710b96d Mon Sep 17 00:00:00 2001 From: Doug Oucahrek Date: Tue, 1 May 2018 22:22:19 -0700 Subject: [PATCH 0452/1001] staging: lustre: o2iblnd: fix race at kiblnd_connect_peer [ Upstream commit cf04968efe341b9b1c30a527e5dd61b2af9c43d2 ] cmid will be destroyed at OFED if kiblnd_cm_callback return error. if error happen before the end of kiblnd_connect_peer, it will touch destroyed cmid and fail as (o2iblnd_cb.c:1315:kiblnd_connect_peer()) ASSERTION( cmid->device != ((void *)0) ) failed: Signed-off-by: Alexander Boyko Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-10015 Reviewed-by: Alexey Lyashkov Reviewed-by: Doug Oucharek Reviewed-by: John L. Hammond Signed-off-by: Doug Oucharek Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c index 29e10021b906..4a9b73305e4e 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c @@ -1289,11 +1289,6 @@ kiblnd_connect_peer(struct kib_peer *peer) goto failed2; } - LASSERT(cmid->device); - CDEBUG(D_NET, "%s: connection bound to %s:%pI4h:%s\n", - libcfs_nid2str(peer->ibp_nid), dev->ibd_ifname, - &dev->ibd_ifip, cmid->device->name); - return; failed2: @@ -2995,8 +2990,19 @@ kiblnd_cm_callback(struct rdma_cm_id *cmid, struct rdma_cm_event *event) } else { rc = rdma_resolve_route( cmid, *kiblnd_tunables.kib_timeout * 1000); - if (!rc) + if (!rc) { + struct kib_net *net = peer->ibp_ni->ni_data; + struct kib_dev *dev = net->ibn_dev; + + CDEBUG(D_NET, "%s: connection bound to "\ + "%s:%pI4h:%s\n", + libcfs_nid2str(peer->ibp_nid), + dev->ibd_ifname, + &dev->ibd_ifip, cmid->device->name); + return 0; + } + /* Can't initiate route resolution */ CERROR("Can't resolve route for %s: %d\n", libcfs_nid2str(peer->ibp_nid), rc); -- GitLab From 66eb9942673a55eed1d7267c04da389d5cdb64f9 Mon Sep 17 00:00:00 2001 From: Doug Oucharek Date: Tue, 1 May 2018 23:49:18 -0400 Subject: [PATCH 0453/1001] staging: lustre: o2iblnd: Fix FastReg map/unmap for MLX5 [ Upstream commit 24d4b7c8de007cff9c7d83c06ae76099fdcce008 ] The FastReg support in ko2iblnd was not unmapping pool items causing the items to leak. In addition, the mapping code is not growing the pool like we do with FMR. This patch makes sure we are unmapping FastReg pool elements when we are done with them. It also makes sure the pool will grow when we depleat the pool. Signed-off-by: Doug Oucharek Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-9472 Reviewed-on: https://review.whamcloud.com/27015 Reviewed-by: Andrew Perepechko Reviewed-by: Dmitry Eremin Reviewed-by: James Simmons Reviewed-by: Oleg Drokin Signed-off-by: Doug Oucharek Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 2 +- .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index 284cdd44a2ee..8b92cf06d063 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -1710,7 +1710,7 @@ int kiblnd_fmr_pool_map(struct kib_fmr_poolset *fps, struct kib_tx *tx, return 0; } spin_unlock(&fps->fps_lock); - rc = -EBUSY; + rc = -EAGAIN; } spin_lock(&fps->fps_lock); diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c index 4a9b73305e4e..4b4a20149894 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c @@ -47,7 +47,7 @@ static int kiblnd_init_rdma(struct kib_conn *conn, struct kib_tx *tx, int type, __u64 dstcookie); static void kiblnd_queue_tx_locked(struct kib_tx *tx, struct kib_conn *conn); static void kiblnd_queue_tx(struct kib_tx *tx, struct kib_conn *conn); -static void kiblnd_unmap_tx(struct lnet_ni *ni, struct kib_tx *tx); +static void kiblnd_unmap_tx(struct kib_tx *tx); static void kiblnd_check_sends_locked(struct kib_conn *conn); static void @@ -65,7 +65,7 @@ kiblnd_tx_done(struct lnet_ni *ni, struct kib_tx *tx) LASSERT(!tx->tx_waiting); /* mustn't be awaiting peer response */ LASSERT(tx->tx_pool); - kiblnd_unmap_tx(ni, tx); + kiblnd_unmap_tx(tx); /* tx may have up to 2 lnet msgs to finalise */ lntmsg[0] = tx->tx_lntmsg[0]; tx->tx_lntmsg[0] = NULL; @@ -590,13 +590,9 @@ kiblnd_fmr_map_tx(struct kib_net *net, struct kib_tx *tx, struct kib_rdma_desc * return 0; } -static void kiblnd_unmap_tx(struct lnet_ni *ni, struct kib_tx *tx) +static void kiblnd_unmap_tx(struct kib_tx *tx) { - struct kib_net *net = ni->ni_data; - - LASSERT(net); - - if (net->ibn_fmr_ps) + if (tx->fmr.fmr_pfmr || tx->fmr.fmr_frd) kiblnd_fmr_pool_unmap(&tx->fmr, tx->tx_status); if (tx->tx_nfrags) { -- GitLab From b62ed0bbbd63bfec2a28c26d9c9a2d264b3c5ed8 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 26 Apr 2018 13:51:16 +0200 Subject: [PATCH 0454/1001] thermal: exynos: fix setting rising_threshold for Exynos5433 [ Upstream commit 8bfc218d0ebbabcba8ed2b8ec1831e0cf1f71629 ] Add missing clearing of the previous value when setting rising temperature threshold. Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Eduardo Valentin Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/thermal/samsung/exynos_tmu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index ac83f721db24..d60069b5dc98 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -598,6 +598,7 @@ static int exynos5433_tmu_initialize(struct platform_device *pdev) threshold_code = temp_to_code(data, temp); rising_threshold = readl(data->base + rising_reg_offset); + rising_threshold &= ~(0xff << j * 8); rising_threshold |= (threshold_code << j * 8); writel(rising_threshold, data->base + rising_reg_offset); -- GitLab From 15239633dc559c22aea80b1627176d6bc181b2f7 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 3 May 2018 18:37:17 -0700 Subject: [PATCH 0455/1001] bpf: fix references to free_bpf_prog_info() in comments [ Upstream commit ab7f5bf0928be2f148d000a6eaa6c0a36e74750e ] Comments in the verifier refer to free_bpf_prog_info() which seems to have never existed in tree. Replace it with free_used_maps(). Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Signed-off-by: Daniel Borkmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/bpf/verifier.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 3ceb269c0ebd..450e2cd31ed6 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -4110,7 +4110,7 @@ static int replace_map_fd_with_map_ptr(struct bpf_verifier_env *env) /* hold the map. If the program is rejected by verifier, * the map will be released by release_maps() or it * will be used by the valid program until it's unloaded - * and all maps are released in free_bpf_prog_info() + * and all maps are released in free_used_maps() */ map = bpf_map_inc(map, false); if (IS_ERR(map)) { @@ -4623,7 +4623,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) vfree(log_buf); if (!env->prog->aux->used_maps) /* if we didn't copy map pointers into bpf_prog_info, release - * them now. Otherwise free_bpf_prog_info() will release them. + * them now. Otherwise free_used_maps() will release them. */ release_maps(env); *prog = env->prog; -- GitLab From 4bbf1ce3a1e3efb6c746e0dbf5a5acb889b3b38b Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Thu, 3 May 2018 23:26:02 -0700 Subject: [PATCH 0456/1001] f2fs: avoid fsync() failure caused by EAGAIN in writepage() [ Upstream commit 5b19d284f5195a925dd015a6397bfce184097378 ] pageout() in MM traslates EAGAIN, so calls handle_write_error() -> mapping_set_error() -> set_bit(AS_EIO, ...). file_write_and_wait_range() will see EIO error, which is critical to return value of fsync() followed by atomic_write failure to user. Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/data.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 36b535207c88..85142e5df88b 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1601,7 +1601,13 @@ static int __write_data_page(struct page *page, bool *submitted, redirty_out: redirty_page_for_writepage(wbc, page); - if (!err) + /* + * pageout() in MM traslates EAGAIN, so calls handle_write_error() + * -> mapping_set_error() -> set_bit(AS_EIO, ...). + * file_write_and_wait_range() will see EIO error, which is critical + * to return value of fsync() followed by atomic_write failure to user. + */ + if (!err || wbc->for_reclaim) return AOP_WRITEPAGE_ACTIVATE; unlock_page(page); return err; -- GitLab From cf006139691098ddfcbf70be07bf2a6264df27e1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 20 Apr 2018 08:32:16 -0400 Subject: [PATCH 0457/1001] media: siano: get rid of __le32/__le16 cast warnings [ Upstream commit e1b7f11b37def5f3021c06e8c2b4953e099357aa ] Those are all false-positives that appear with smatch when building for arm: drivers/media/common/siano/smsendian.c:38:36: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:38:36: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:38:36: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:38:36: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:38:36: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:38:36: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:47:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:47:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:47:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:47:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:47:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:47:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:67:35: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:67:35: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:67:35: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:67:35: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:84:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:84:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:84:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:84:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:84:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:84:44: warning: cast to restricted __le32 drivers/media/common/siano/smsendian.c:98:26: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:98:26: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:98:26: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:98:26: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:99:28: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:99:28: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:99:28: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:99:28: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:100:27: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:100:27: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:100:27: warning: cast to restricted __le16 drivers/media/common/siano/smsendian.c:100:27: warning: cast to restricted __le16 Get rid of them by adding explicit forced casts. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/common/siano/smsendian.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/common/siano/smsendian.c b/drivers/media/common/siano/smsendian.c index bfe831c10b1c..b95a631f23f9 100644 --- a/drivers/media/common/siano/smsendian.c +++ b/drivers/media/common/siano/smsendian.c @@ -35,7 +35,7 @@ void smsendian_handle_tx_message(void *buffer) switch (msg->x_msg_header.msg_type) { case MSG_SMS_DATA_DOWNLOAD_REQ: { - msg->msg_data[0] = le32_to_cpu(msg->msg_data[0]); + msg->msg_data[0] = le32_to_cpu((__force __le32)(msg->msg_data[0])); break; } @@ -44,7 +44,7 @@ void smsendian_handle_tx_message(void *buffer) sizeof(struct sms_msg_hdr))/4; for (i = 0; i < msg_words; i++) - msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]); + msg->msg_data[i] = le32_to_cpu((__force __le32)msg->msg_data[i]); break; } @@ -64,7 +64,7 @@ void smsendian_handle_rx_message(void *buffer) { struct sms_version_res *ver = (struct sms_version_res *) msg; - ver->chip_model = le16_to_cpu(ver->chip_model); + ver->chip_model = le16_to_cpu((__force __le16)ver->chip_model); break; } @@ -81,7 +81,7 @@ void smsendian_handle_rx_message(void *buffer) sizeof(struct sms_msg_hdr))/4; for (i = 0; i < msg_words; i++) - msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]); + msg->msg_data[i] = le32_to_cpu((__force __le32)msg->msg_data[i]); break; } @@ -95,9 +95,9 @@ void smsendian_handle_message_header(void *msg) #ifdef __BIG_ENDIAN struct sms_msg_hdr *phdr = (struct sms_msg_hdr *)msg; - phdr->msg_type = le16_to_cpu(phdr->msg_type); - phdr->msg_length = le16_to_cpu(phdr->msg_length); - phdr->msg_flags = le16_to_cpu(phdr->msg_flags); + phdr->msg_type = le16_to_cpu((__force __le16)phdr->msg_type); + phdr->msg_length = le16_to_cpu((__force __le16)phdr->msg_length); + phdr->msg_flags = le16_to_cpu((__force __le16)phdr->msg_flags); #endif /* __BIG_ENDIAN */ } EXPORT_SYMBOL_GPL(smsendian_handle_message_header); -- GitLab From c6f9830cfb475d71b37f84657091012eee7bfb9d Mon Sep 17 00:00:00 2001 From: Satendra Singh Thakur Date: Thu, 3 May 2018 11:19:32 +0530 Subject: [PATCH 0458/1001] drm/atomic: Handling the case when setting old crtc for plane [ Upstream commit fc2a69f3903dfd97cd47f593e642b47918c949df ] In the func drm_atomic_set_crtc_for_plane, with the current code, if crtc of the plane_state and crtc passed as argument to the func are same, entire func will executed in vein. It will get state of crtc and clear and set the bits in plane_mask. All these steps are not required for same old crtc. Ideally, we should do nothing in this case, this patch handles the same, and causes the program to return without doing anything in such scenario. Signed-off-by: Satendra Singh Thakur Cc: Madhur Verma Cc: Hemanshu Srivastava Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/1525326572-25854-1-git-send-email-satendra.t@samsung.com Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_atomic.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 0d8a417e2cd6..bb5cc15fa0b9 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1355,7 +1355,9 @@ drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, { struct drm_plane *plane = plane_state->plane; struct drm_crtc_state *crtc_state; - + /* Nothing to do for same crtc*/ + if (plane_state->crtc == crtc) + return 0; if (plane_state->crtc) { crtc_state = drm_atomic_get_crtc_state(plane_state->state, plane_state->crtc); -- GitLab From ab76f866c8f0936b72813659f70a16cd827ac683 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 2 May 2018 22:48:16 +0900 Subject: [PATCH 0459/1001] ALSA: hda/ca0132: fix build failure when a local macro is defined [ Upstream commit 8e142e9e628975b0dddd05cf1b095331dff6e2de ] DECLARE_TLV_DB_SCALE (alias of SNDRV_CTL_TLVD_DECLARE_DB_SCALE) is used but tlv.h is not included. This causes build failure when local macro is defined by comment-out. This commit fixes the bug. At the same time, the alias macro is replaced with a destination macro added at a commit 46e860f76804 ("ALSA: rename TLV-related macros so that they're friendly to user applications") Reported-by: Connor McAdams Fixes: 44f0c9782cc6 ('ALSA: hda/ca0132: Add tuning controls') Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_ca0132.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 3e73d5c6ccfc..119f3b504765 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -38,6 +38,10 @@ /* Enable this to see controls for tuning purpose. */ /*#define ENABLE_TUNING_CONTROLS*/ +#ifdef ENABLE_TUNING_CONTROLS +#include +#endif + #define FLOAT_ZERO 0x00000000 #define FLOAT_ONE 0x3f800000 #define FLOAT_TWO 0x40000000 @@ -3067,8 +3071,8 @@ static int equalizer_ctl_put(struct snd_kcontrol *kcontrol, return 1; } -static const DECLARE_TLV_DB_SCALE(voice_focus_db_scale, 2000, 100, 0); -static const DECLARE_TLV_DB_SCALE(eq_db_scale, -2400, 100, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(voice_focus_db_scale, 2000, 100, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(eq_db_scale, -2400, 100, 0); static int add_tuning_control(struct hda_codec *codec, hda_nid_t pnid, hda_nid_t nid, -- GitLab From f0b0debbb49dc14b2deddfd226b22ad7c5496828 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Mon, 26 Mar 2018 17:26:25 +0800 Subject: [PATCH 0460/1001] mmc: dw_mmc: update actual clock for mmc debugfs [ Upstream commit ff178981bd5fd1667f373098740cb1c6d6efa1ba ] Respect the actual clock for mmc debugfs to help better debug the hardware. mmc_host mmc0: Bus speed (slot 0) = 135475200Hz (slot req 150000000Hz, actual 135475200HZ div = 0) cat /sys/kernel/debug/mmc0/ios clock: 150000000 Hz actual clock: 135475200 Hz vdd: 21 (3.3 ~ 3.4 V) bus mode: 2 (push-pull) chip select: 0 (don't care) power mode: 2 (on) bus width: 3 (8 bits) timing spec: 9 (mmc HS200) signal voltage: 0 (1.80 V) driver type: 0 (driver type B) Cc: Xiao Yao Cc: Ziyuan Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/dw_mmc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 6a2cbbba29aa..5252885e5cda 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1255,6 +1255,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) if (host->state == STATE_WAITING_CMD11_DONE) sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH; + slot->mmc->actual_clock = 0; + if (!clock) { mci_writel(host, CLKENA, 0); mci_send_cmd(slot, sdmmc_cmd_bits, 0); @@ -1313,6 +1315,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) /* keep the last clock value that was requested from core */ slot->__clk_old = clock; + slot->mmc->actual_clock = div ? ((host->bus_hz / div) >> 1) : + host->bus_hz; } host->current_speed = clock; -- GitLab From d6ce4f1bf79a007a8c391c93b58eef15b2fffb07 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Mon, 26 Mar 2018 17:33:14 +1100 Subject: [PATCH 0461/1001] mmc: pwrseq: Use kmalloc_array instead of stack VLA [ Upstream commit 486e6661367b40f927aadbed73237693396cbf94 ] The use of stack Variable Length Arrays needs to be avoided, as they can be a vector for stack exhaustion, which can be both a runtime bug (kernel Oops) or a security flaw (overwriting memory beyond the stack). Also, in general, as code evolves it is easy to lose track of how big a VLA can get. Thus, we can end up having runtime failures that are hard to debug. As part of the directive[1] to remove all VLAs from the kernel, and build with -Wvla. Currently driver is using a VLA declared using the number of descriptors. This array is used to store integer values and is later used as an argument to `gpiod_set_array_value_cansleep()` This can be avoided by using `kmalloc_array()` to allocate memory for the array of integer values. Memory is free'd before return from function. >From the code it appears that it is safe to sleep so we can use GFP_KERNEL (based _cansleep() suffix of function `gpiod_set_array_value_cansleep()`. It can be expected that this patch will result in a small increase in overhead due to the use of `kmalloc_array()` [1] https://lkml.org/lkml/2018/3/7/621 Signed-off-by: Tobin C. Harding Signed-off-by: Ulf Hansson Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/core/pwrseq_simple.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c index 13ef162cf066..a8b9fee4d62a 100644 --- a/drivers/mmc/core/pwrseq_simple.c +++ b/drivers/mmc/core/pwrseq_simple.c @@ -40,14 +40,18 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq, struct gpio_descs *reset_gpios = pwrseq->reset_gpios; if (!IS_ERR(reset_gpios)) { - int i; - int values[reset_gpios->ndescs]; + int i, *values; + int nvalues = reset_gpios->ndescs; - for (i = 0; i < reset_gpios->ndescs; i++) + values = kmalloc_array(nvalues, sizeof(int), GFP_KERNEL); + if (!values) + return; + + for (i = 0; i < nvalues; i++) values[i] = value; - gpiod_set_array_value_cansleep( - reset_gpios->ndescs, reset_gpios->desc, values); + gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, values); + kfree(values); } } -- GitLab From c9e5888ec8ae248d30b499a0add51047ef135b03 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sun, 22 Apr 2018 12:53:28 +0200 Subject: [PATCH 0462/1001] dt-bindings: pinctrl: meson: add support for the Meson8m2 SoC [ Upstream commit 03d9fbc39730b3e6b2e7047dc85f0f70de8fb97d ] The Meson8m2 SoC is a variant of Meson8 with some updates from Meson8b (such as the Gigabit capable DesignWare MAC). It is mostly pin compatible with Meson8, only 10 (existing) CBUS pins get an additional function (four of these are Ethernet RXD2, RXD3, TXD2 and TXD3 which are required when the board uses an RGMII PHY). The AOBUS pins seem to be identical on Meson8 and Meson8m2. Signed-off-by: Martin Blumenstingl Reviewed-by: Rob Herring Reviewed-by: Kevin Hilman Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt index 2392557ede27..df77d394edc0 100644 --- a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt @@ -3,8 +3,10 @@ Required properties for the root node: - compatible: one of "amlogic,meson8-cbus-pinctrl" "amlogic,meson8b-cbus-pinctrl" + "amlogic,meson8m2-cbus-pinctrl" "amlogic,meson8-aobus-pinctrl" "amlogic,meson8b-aobus-pinctrl" + "amlogic,meson8m2-aobus-pinctrl" "amlogic,meson-gxbb-periphs-pinctrl" "amlogic,meson-gxbb-aobus-pinctrl" "amlogic,meson-gxl-periphs-pinctrl" -- GitLab From 17b26041363f7d4589e23bcad21f62dbfcf50bf8 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sun, 29 Apr 2018 01:46:23 +0300 Subject: [PATCH 0463/1001] spi: meson-spicc: Fix error handling in meson_spicc_probe() [ Upstream commit ded5fa4e8bac25612caab8f0822691308a28a552 ] If devm_spi_register_master() fails in meson_spicc_probe(), spicc->core is left undisabled. The patch fixes that. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Reviewed-by: Neil Armstrong Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-meson-spicc.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index 7f8429635502..a5b0df7e6131 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -574,10 +574,15 @@ static int meson_spicc_probe(struct platform_device *pdev) master->max_speed_hz = rate >> 2; ret = devm_spi_register_master(&pdev->dev, master); - if (!ret) - return 0; + if (ret) { + dev_err(&pdev->dev, "spi master registration failed\n"); + goto out_clk; + } - dev_err(&pdev->dev, "spi master registration failed\n"); + return 0; + +out_clk: + clk_disable_unprepare(spicc->core); out_master: spi_master_put(master); -- GitLab From c3b540c06954615a58c74fd4658d715fdf8955a4 Mon Sep 17 00:00:00 2001 From: Huazhong Tan Date: Tue, 1 May 2018 19:55:59 +0100 Subject: [PATCH 0464/1001] net: hns3: Fixes the out of bounds access in hclge_map_tqp [ Upstream commit 38e62046d4c95272e2fb001d2d72baf48fa090e9 ] This patch fixes the handling of the check when number of vports are detected to be more than available TPQs. Current handling causes an out of bounds access in hclge_map_tqp(). Fixes: 7df7dad633e2 ("net: hns3: Refactor the mapping of tqp to vport") Signed-off-by: Huazhong Tan Signed-off-by: Peng Li Signed-off-by: Salil Mehta Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index ff7a70ffafc6..c133491ad9fa 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -1272,8 +1272,11 @@ static int hclge_alloc_vport(struct hclge_dev *hdev) /* We need to alloc a vport for main NIC of PF */ num_vport = hdev->num_vmdq_vport + hdev->num_req_vfs + 1; - if (hdev->num_tqps < num_vport) - num_vport = hdev->num_tqps; + if (hdev->num_tqps < num_vport) { + dev_err(&hdev->pdev->dev, "tqps(%d) is less than vports(%d)", + hdev->num_tqps, num_vport); + return -EINVAL; + } /* Alloc the same number of TQPs for every vport */ tqp_per_vport = hdev->num_tqps / num_vport; -- GitLab From 232703c9091f18b57f371fe6bbe0716ef5c09df5 Mon Sep 17 00:00:00 2001 From: Yixun Lan Date: Sat, 28 Apr 2018 10:21:10 +0000 Subject: [PATCH 0465/1001] dt-bindings: net: meson-dwmac: new compatible name for AXG SoC [ Upstream commit 7e5d05e18ba1ed491c6f836edee7f0b90f3167bc ] We need to introduce a new compatible name for the Meson-AXG SoC in order to support the RMII 100M ethernet PHY, since the PRG_ETH0 register of the dwmac glue layer is changed from previous old SoC. Signed-off-by: Yixun Lan Reviewed-by: Rob Herring Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/net/meson-dwmac.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/net/meson-dwmac.txt b/Documentation/devicetree/bindings/net/meson-dwmac.txt index 354dd9896bb5..910187ebf1ce 100644 --- a/Documentation/devicetree/bindings/net/meson-dwmac.txt +++ b/Documentation/devicetree/bindings/net/meson-dwmac.txt @@ -10,6 +10,7 @@ Required properties on all platforms: - "amlogic,meson6-dwmac" - "amlogic,meson8b-dwmac" - "amlogic,meson-gxbb-dwmac" + - "amlogic,meson-axg-dwmac" Additionally "snps,dwmac" and any applicable more detailed version number described in net/stmmac.txt should be used. -- GitLab From 4531135811a5bf90011c99fe850a45a16a584f8b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 14 Jan 2018 22:07:10 +0100 Subject: [PATCH 0466/1001] backlight: pwm_bl: Don't use GPIOF_* with gpiod_get_direction [ Upstream commit bb084c0f61d659f0e6d371b096e0e57998f191d6 ] The documentation was wrong, gpiod_get_direction() returns 0/1 instead of the GPIOF_* flags. The docs were fixed with commit 94fc73094abe47 ("gpio: correct docs about return value of gpiod_get_direction"). Now, fix this user (until a better, system-wide solution is in place). Signed-off-by: Wolfram Sang Acked-by: Daniel Thompson Reviewed-by: Simon Horman Signed-off-by: Lee Jones Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/video/backlight/pwm_bl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 1c2289ddd555..0fa7d2bd0e48 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -301,14 +301,14 @@ static int pwm_backlight_probe(struct platform_device *pdev) /* * If the GPIO is not known to be already configured as output, that - * is, if gpiod_get_direction returns either GPIOF_DIR_IN or -EINVAL, - * change the direction to output and set the GPIO as active. + * is, if gpiod_get_direction returns either 1 or -EINVAL, change the + * direction to output and set the GPIO as active. * Do not force the GPIO to active when it was already output as it * could cause backlight flickering or we would enable the backlight too * early. Leave the decision of the initial backlight state for later. */ if (pb->enable_gpio && - gpiod_get_direction(pb->enable_gpio) != GPIOF_DIR_OUT) + gpiod_get_direction(pb->enable_gpio) != 0) gpiod_direction_output(pb->enable_gpio, 1); pb->power_supply = devm_regulator_get(&pdev->dev, "power"); -- GitLab From da2b62c740def7d1e9d7ce4506e8b1b7a2514e89 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 23 Apr 2018 21:16:35 +0200 Subject: [PATCH 0467/1001] stop_machine: Use raw spinlocks [ Upstream commit de5b55c1d4e30740009864eb35ce4ed856aac01d ] Use raw-locks in stop_machine() to allow locking in irq-off and preempt-disabled regions on -RT. This also documents the possible locking context in general. [bigeasy: update patch description.] Signed-off-by: Thomas Gleixner Signed-off-by: Sebastian Andrzej Siewior Link: https://lkml.kernel.org/r/20180423191635.6014-1-bigeasy@linutronix.de Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/stop_machine.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index 2f6fa95de2d8..1ff523dae6e2 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c @@ -37,7 +37,7 @@ struct cpu_stop_done { struct cpu_stopper { struct task_struct *thread; - spinlock_t lock; + raw_spinlock_t lock; bool enabled; /* is this stopper enabled? */ struct list_head works; /* list of pending works */ @@ -81,13 +81,13 @@ static bool cpu_stop_queue_work(unsigned int cpu, struct cpu_stop_work *work) unsigned long flags; bool enabled; - spin_lock_irqsave(&stopper->lock, flags); + raw_spin_lock_irqsave(&stopper->lock, flags); enabled = stopper->enabled; if (enabled) __cpu_stop_queue_work(stopper, work, &wakeq); else if (work->done) cpu_stop_signal_done(work->done); - spin_unlock_irqrestore(&stopper->lock, flags); + raw_spin_unlock_irqrestore(&stopper->lock, flags); wake_up_q(&wakeq); @@ -237,8 +237,8 @@ static int cpu_stop_queue_two_works(int cpu1, struct cpu_stop_work *work1, DEFINE_WAKE_Q(wakeq); int err; retry: - spin_lock_irq(&stopper1->lock); - spin_lock_nested(&stopper2->lock, SINGLE_DEPTH_NESTING); + raw_spin_lock_irq(&stopper1->lock); + raw_spin_lock_nested(&stopper2->lock, SINGLE_DEPTH_NESTING); err = -ENOENT; if (!stopper1->enabled || !stopper2->enabled) @@ -261,8 +261,8 @@ static int cpu_stop_queue_two_works(int cpu1, struct cpu_stop_work *work1, __cpu_stop_queue_work(stopper1, work1, &wakeq); __cpu_stop_queue_work(stopper2, work2, &wakeq); unlock: - spin_unlock(&stopper2->lock); - spin_unlock_irq(&stopper1->lock); + raw_spin_unlock(&stopper2->lock); + raw_spin_unlock_irq(&stopper1->lock); if (unlikely(err == -EDEADLK)) { while (stop_cpus_in_progress) @@ -461,9 +461,9 @@ static int cpu_stop_should_run(unsigned int cpu) unsigned long flags; int run; - spin_lock_irqsave(&stopper->lock, flags); + raw_spin_lock_irqsave(&stopper->lock, flags); run = !list_empty(&stopper->works); - spin_unlock_irqrestore(&stopper->lock, flags); + raw_spin_unlock_irqrestore(&stopper->lock, flags); return run; } @@ -474,13 +474,13 @@ static void cpu_stopper_thread(unsigned int cpu) repeat: work = NULL; - spin_lock_irq(&stopper->lock); + raw_spin_lock_irq(&stopper->lock); if (!list_empty(&stopper->works)) { work = list_first_entry(&stopper->works, struct cpu_stop_work, list); list_del_init(&work->list); } - spin_unlock_irq(&stopper->lock); + raw_spin_unlock_irq(&stopper->lock); if (work) { cpu_stop_fn_t fn = work->fn; @@ -554,7 +554,7 @@ static int __init cpu_stop_init(void) for_each_possible_cpu(cpu) { struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu); - spin_lock_init(&stopper->lock); + raw_spin_lock_init(&stopper->lock); INIT_LIST_HEAD(&stopper->works); } -- GitLab From c06f5a018f710ff24ef7c1b922d2b6704c35dd8c Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 23 Apr 2018 18:10:23 +0200 Subject: [PATCH 0468/1001] delayacct: Use raw_spinlocks [ Upstream commit 02acc80d19edb0d5684c997b2004ad19f9f5236e ] try_to_wake_up() might invoke delayacct_blkio_end() while holding the pi_lock (which is a raw_spinlock_t). delayacct_blkio_end() acquires task_delay_info.lock which is a spinlock_t. This causes a might sleep splat on -RT where non raw spinlocks are converted to 'sleeping' spinlocks. task_delay_info.lock is only held for a short amount of time so it's not a problem latency wise to make convert it to a raw spinlock. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Thomas Gleixner Cc: Balbir Singh Link: https://lkml.kernel.org/r/20180423161024.6710-1-bigeasy@linutronix.de Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/linux/delayacct.h | 2 +- kernel/delayacct.c | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/include/linux/delayacct.h b/include/linux/delayacct.h index 41ee6dea7531..31c865d1842e 100644 --- a/include/linux/delayacct.h +++ b/include/linux/delayacct.h @@ -29,7 +29,7 @@ #ifdef CONFIG_TASK_DELAY_ACCT struct task_delay_info { - spinlock_t lock; + raw_spinlock_t lock; unsigned int flags; /* Private per-task flags */ /* For each stat XXX, add following, aligned appropriately diff --git a/kernel/delayacct.c b/kernel/delayacct.c index e2764d767f18..ca8ac2824f0b 100644 --- a/kernel/delayacct.c +++ b/kernel/delayacct.c @@ -44,23 +44,24 @@ void __delayacct_tsk_init(struct task_struct *tsk) { tsk->delays = kmem_cache_zalloc(delayacct_cache, GFP_KERNEL); if (tsk->delays) - spin_lock_init(&tsk->delays->lock); + raw_spin_lock_init(&tsk->delays->lock); } /* * Finish delay accounting for a statistic using its timestamps (@start), * accumalator (@total) and @count */ -static void delayacct_end(spinlock_t *lock, u64 *start, u64 *total, u32 *count) +static void delayacct_end(raw_spinlock_t *lock, u64 *start, u64 *total, + u32 *count) { s64 ns = ktime_get_ns() - *start; unsigned long flags; if (ns > 0) { - spin_lock_irqsave(lock, flags); + raw_spin_lock_irqsave(lock, flags); *total += ns; (*count)++; - spin_unlock_irqrestore(lock, flags); + raw_spin_unlock_irqrestore(lock, flags); } } @@ -127,7 +128,7 @@ int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) /* zero XXX_total, non-zero XXX_count implies XXX stat overflowed */ - spin_lock_irqsave(&tsk->delays->lock, flags); + raw_spin_lock_irqsave(&tsk->delays->lock, flags); tmp = d->blkio_delay_total + tsk->delays->blkio_delay; d->blkio_delay_total = (tmp < d->blkio_delay_total) ? 0 : tmp; tmp = d->swapin_delay_total + tsk->delays->swapin_delay; @@ -137,7 +138,7 @@ int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) d->blkio_count += tsk->delays->blkio_count; d->swapin_count += tsk->delays->swapin_count; d->freepages_count += tsk->delays->freepages_count; - spin_unlock_irqrestore(&tsk->delays->lock, flags); + raw_spin_unlock_irqrestore(&tsk->delays->lock, flags); return 0; } @@ -147,10 +148,10 @@ __u64 __delayacct_blkio_ticks(struct task_struct *tsk) __u64 ret; unsigned long flags; - spin_lock_irqsave(&tsk->delays->lock, flags); + raw_spin_lock_irqsave(&tsk->delays->lock, flags); ret = nsec_to_clock_t(tsk->delays->blkio_delay + tsk->delays->swapin_delay); - spin_unlock_irqrestore(&tsk->delays->lock, flags); + raw_spin_unlock_irqrestore(&tsk->delays->lock, flags); return ret; } -- GitLab From 9746d3696de90457a0e7880d4e8ed3d8fe52f8bc Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 9 Apr 2018 22:28:27 +0300 Subject: [PATCH 0469/1001] memory: tegra: Do not handle spurious interrupts [ Upstream commit bf3fbdfbec947cdd04b2f2c4bce11534c8786eee ] The ISR reads interrupts-enable mask, but doesn't utilize it. Apply the mask to the interrupt status and don't handle interrupts that MC driver haven't asked for. Kernel would disable spurious MC IRQ and report the error. This would happen only in a case of a very severe bug. Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/memory/tegra/mc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index a4803ac192bb..d2005b995821 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -252,8 +252,11 @@ static irqreturn_t tegra_mc_irq(int irq, void *data) unsigned int bit; /* mask all interrupts to avoid flooding */ - status = mc_readl(mc, MC_INTSTATUS); mask = mc_readl(mc, MC_INTMASK); + status = mc_readl(mc, MC_INTSTATUS) & mask; + + if (!status) + return IRQ_NONE; for_each_set_bit(bit, &status, 32) { const char *error = status_names[bit] ?: "unknown"; -- GitLab From 503f22cf7b2a5fcd4dfb0041eca03028a6284fab Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 9 Apr 2018 22:28:29 +0300 Subject: [PATCH 0470/1001] memory: tegra: Apply interrupts mask per SoC [ Upstream commit 1c74d5c0de0c2cc29fef97a19251da2ad6f579bd ] Currently we are enabling handling of interrupts specific to Tegra124+ which happen to overlap with previous generations. Let's specify interrupts mask per SoC generation for consistency and in a preparation of squashing of Tegra20 driver into the common one that will enable handling of GART faults which may be undesirable by newer generations. Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/memory/tegra/mc.c | 21 +++------------------ drivers/memory/tegra/mc.h | 9 +++++++++ drivers/memory/tegra/tegra114.c | 2 ++ drivers/memory/tegra/tegra124.c | 6 ++++++ drivers/memory/tegra/tegra210.c | 3 +++ drivers/memory/tegra/tegra30.c | 2 ++ include/soc/tegra/mc.h | 2 ++ 7 files changed, 27 insertions(+), 18 deletions(-) diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index d2005b995821..1d49a8dd4a37 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -20,14 +20,6 @@ #include "mc.h" #define MC_INTSTATUS 0x000 -#define MC_INT_DECERR_MTS (1 << 16) -#define MC_INT_SECERR_SEC (1 << 13) -#define MC_INT_DECERR_VPR (1 << 12) -#define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11) -#define MC_INT_INVALID_SMMU_PAGE (1 << 10) -#define MC_INT_ARBITRATION_EMEM (1 << 9) -#define MC_INT_SECURITY_VIOLATION (1 << 8) -#define MC_INT_DECERR_EMEM (1 << 6) #define MC_INTMASK 0x004 @@ -248,13 +240,11 @@ static const char *const error_names[8] = { static irqreturn_t tegra_mc_irq(int irq, void *data) { struct tegra_mc *mc = data; - unsigned long status, mask; + unsigned long status; unsigned int bit; /* mask all interrupts to avoid flooding */ - mask = mc_readl(mc, MC_INTMASK); - status = mc_readl(mc, MC_INTSTATUS) & mask; - + status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask; if (!status) return IRQ_NONE; @@ -349,7 +339,6 @@ static int tegra_mc_probe(struct platform_device *pdev) const struct of_device_id *match; struct resource *res; struct tegra_mc *mc; - u32 value; int err; match = of_match_node(tegra_mc_of_match, pdev->dev.of_node); @@ -417,11 +406,7 @@ static int tegra_mc_probe(struct platform_device *pdev) WARN(!mc->soc->client_id_mask, "Missing client ID mask for this SoC\n"); - value = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | - MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | - MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM; - - mc_writel(mc, value, MC_INTMASK); + mc_writel(mc, mc->soc->intmask, MC_INTMASK); return 0; } diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h index ddb16676c3af..24e020b4609b 100644 --- a/drivers/memory/tegra/mc.h +++ b/drivers/memory/tegra/mc.h @@ -14,6 +14,15 @@ #include +#define MC_INT_DECERR_MTS (1 << 16) +#define MC_INT_SECERR_SEC (1 << 13) +#define MC_INT_DECERR_VPR (1 << 12) +#define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11) +#define MC_INT_INVALID_SMMU_PAGE (1 << 10) +#define MC_INT_ARBITRATION_EMEM (1 << 9) +#define MC_INT_SECURITY_VIOLATION (1 << 8) +#define MC_INT_DECERR_EMEM (1 << 6) + static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset) { return readl(mc->regs + offset); diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c index ba8fff3d66a6..6d2a5a849d92 100644 --- a/drivers/memory/tegra/tegra114.c +++ b/drivers/memory/tegra/tegra114.c @@ -930,4 +930,6 @@ const struct tegra_mc_soc tegra114_mc_soc = { .atom_size = 32, .client_id_mask = 0x7f, .smmu = &tegra114_smmu_soc, + .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION | + MC_INT_DECERR_EMEM, }; diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c index 5a58e440f4a7..9f68a56f2727 100644 --- a/drivers/memory/tegra/tegra124.c +++ b/drivers/memory/tegra/tegra124.c @@ -1020,6 +1020,9 @@ const struct tegra_mc_soc tegra124_mc_soc = { .smmu = &tegra124_smmu_soc, .emem_regs = tegra124_mc_emem_regs, .num_emem_regs = ARRAY_SIZE(tegra124_mc_emem_regs), + .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | + MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | + MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, }; #endif /* CONFIG_ARCH_TEGRA_124_SOC */ @@ -1042,5 +1045,8 @@ const struct tegra_mc_soc tegra132_mc_soc = { .atom_size = 32, .client_id_mask = 0x7f, .smmu = &tegra132_smmu_soc, + .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | + MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | + MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, }; #endif /* CONFIG_ARCH_TEGRA_132_SOC */ diff --git a/drivers/memory/tegra/tegra210.c b/drivers/memory/tegra/tegra210.c index 5e144abe4c18..47c78a6d8f00 100644 --- a/drivers/memory/tegra/tegra210.c +++ b/drivers/memory/tegra/tegra210.c @@ -1077,4 +1077,7 @@ const struct tegra_mc_soc tegra210_mc_soc = { .atom_size = 64, .client_id_mask = 0xff, .smmu = &tegra210_smmu_soc, + .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | + MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | + MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, }; diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c index b44737840e70..d0689428ea1a 100644 --- a/drivers/memory/tegra/tegra30.c +++ b/drivers/memory/tegra/tegra30.c @@ -952,4 +952,6 @@ const struct tegra_mc_soc tegra30_mc_soc = { .atom_size = 16, .client_id_mask = 0x7f, .smmu = &tegra30_smmu_soc, + .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION | + MC_INT_DECERR_EMEM, }; diff --git a/include/soc/tegra/mc.h b/include/soc/tegra/mc.h index 44202ff897fd..f759e0918037 100644 --- a/include/soc/tegra/mc.h +++ b/include/soc/tegra/mc.h @@ -99,6 +99,8 @@ struct tegra_mc_soc { u8 client_id_mask; const struct tegra_smmu_soc *smmu; + + u32 intmask; }; struct tegra_mc { -- GitLab From 2ee4fbcd27f97006748656c791fcf59dec0ebf3f Mon Sep 17 00:00:00 2001 From: Wei Xu Date: Thu, 26 Apr 2018 14:59:19 -0600 Subject: [PATCH 0471/1001] nvme: lightnvm: add granby support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit ea48e877994f086af481427bac110aa63686c3ce ] Add a new lightnvm quirk to identify CNEX’s Granby controller. Signed-off-by: Wei Xu Reviewed-by: Javier González Reviewed-by: Matias Bjørling Signed-off-by: Keith Busch Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/host/pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 6a76e3974240..f5643d107cc6 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2565,6 +2565,8 @@ static const struct pci_device_id nvme_id_table[] = { .driver_data = NVME_QUIRK_LIGHTNVM, }, { PCI_DEVICE(0x1d1d, 0x2807), /* CNEX WL */ .driver_data = NVME_QUIRK_LIGHTNVM, }, + { PCI_DEVICE(0x1d1d, 0x2601), /* CNEX Granby */ + .driver_data = NVME_QUIRK_LIGHTNVM, }, { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) }, { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001) }, { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2003) }, -- GitLab From c7ab132d7e3de0a9020bf5b3e91fc6fe0736031d Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Mon, 16 Apr 2018 11:39:57 -0300 Subject: [PATCH 0472/1001] arm64: defconfig: Enable Rockchip io-domain driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 7c8b77f81552c2b0e5d9c560da70bc4149ce66a5 ] Heiko Stübner justified pretty well the change in commit e330eb86ba0b ("ARM: multi_v7_defconfig: enable Rockchip io-domain driver"). This change is also needed for arm64 rockchip boards, so, do the same for arm64. The io-domain driver is necessary to notify the soc about voltages changes happening on supplying regulators. Probably the most important user right now is the mmc tuning code, where the soc needs to get notified when the voltage is dropped to the 1.8V point. As this option is necessary to successfully tune UHS cards etc, it should get built in. Otherwise, tuning will fail with, dwmmc_rockchip fe320000.dwmmc: All phases bad! mmc0: tuning execution failed: -5 Signed-off-by: Enric Balletbo i Serra Acked-by: Robin Murphy Signed-off-by: Heiko Stuebner Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm64/configs/defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 34480e9af2e7..b05796578e7a 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -302,6 +302,8 @@ CONFIG_GPIO_XGENE_SB=y CONFIG_GPIO_PCA953X=y CONFIG_GPIO_PCA953X_IRQ=y CONFIG_GPIO_MAX77620=y +CONFIG_POWER_AVS=y +CONFIG_ROCKCHIP_IODOMAIN=y CONFIG_POWER_RESET_MSM=y CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y -- GitLab From 75d1087174d27e2ac835f04ba782e39b7e54096d Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Tue, 10 Apr 2018 10:49:51 -0700 Subject: [PATCH 0473/1001] igb: Fix queue selection on MAC filters on i210 [ Upstream commit 4dc93fcf0b95dc3fda4db917effae31fbb8ad2a8 ] On the RAH registers there are semantic differences on the meaning of the "queue" parameter for traffic steering depending on the controller model: there is the 82575 meaning, which "queue" means a RX Hardware Queue, and the i350 meaning, where it is a reception pool. The previous behaviour was having no effect for i210 based controllers because the QSEL bit of the RAH register wasn't being set. This patch separates the condition in discrete cases, so the different handling is clearer. Fixes: 83c21335c876 ("igb: improve MAC filter handling") Signed-off-by: Vinicius Costa Gomes Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/igb/igb_main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 6ca580cdfd84..1c027f9d9af5 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -8376,12 +8376,17 @@ static void igb_rar_set_index(struct igb_adapter *adapter, u32 index) if (is_valid_ether_addr(addr)) rar_high |= E1000_RAH_AV; - if (hw->mac.type == e1000_82575) + switch (hw->mac.type) { + case e1000_82575: + case e1000_i210: rar_high |= E1000_RAH_POOL_1 * adapter->mac_table[index].queue; - else + break; + default: rar_high |= E1000_RAH_POOL_1 << adapter->mac_table[index].queue; + break; + } } wr32(E1000_RAL(index), rar_low); -- GitLab From 18a48a7a4418381d03492de3dba8cfee5ca5d14f Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Tue, 24 Apr 2018 15:14:57 +0200 Subject: [PATCH 0474/1001] drm/gma500: fix psb_intel_lvds_mode_valid()'s return type [ Upstream commit 2ea009095c6e7396915a1d0dd480c41f02985f79 ] The method struct drm_connector_helper_funcs::mode_valid is defined as returning an 'enum drm_mode_status' but the driver implementation for this method, psb_intel_lvds_mode_valid(), uses an 'int' for it. Fix this by using 'enum drm_mode_status' for psb_intel_lvds_mode_valid(). Signed-off-by: Luc Van Oostenryck Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20180424131458.2060-1-luc.vanoostenryck@gmail.com Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/gma500/psb_intel_drv.h | 2 +- drivers/gpu/drm/gma500/psb_intel_lvds.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h index e8e4ea14b12b..e05e5399af2d 100644 --- a/drivers/gpu/drm/gma500/psb_intel_drv.h +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h @@ -255,7 +255,7 @@ extern int intelfb_remove(struct drm_device *dev, extern bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); -extern int psb_intel_lvds_mode_valid(struct drm_connector *connector, +extern enum drm_mode_status psb_intel_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode); extern int psb_intel_lvds_set_property(struct drm_connector *connector, struct drm_property *property, diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c index be3eefec5152..8baf6325c6e4 100644 --- a/drivers/gpu/drm/gma500/psb_intel_lvds.c +++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c @@ -343,7 +343,7 @@ static void psb_intel_lvds_restore(struct drm_connector *connector) } } -int psb_intel_lvds_mode_valid(struct drm_connector *connector, +enum drm_mode_status psb_intel_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_psb_private *dev_priv = connector->dev->dev_private; -- GitLab From e660508795d6cc8e509be68596164d6574111149 Mon Sep 17 00:00:00 2001 From: Chris Novakovic Date: Tue, 24 Apr 2018 03:56:37 +0100 Subject: [PATCH 0475/1001] ipconfig: Correctly initialise ic_nameservers [ Upstream commit 300eec7c0a2495f771709c7642aa15f7cc148b83 ] ic_nameservers, which stores the list of name servers discovered by ipconfig, is initialised (i.e. has all of its elements set to NONE, or 0xffffffff) by ic_nameservers_predef() in the following scenarios: - before the "ip=" and "nfsaddrs=" kernel command line parameters are parsed (in ip_auto_config_setup()); - before autoconfiguring via DHCP or BOOTP (in ic_bootp_init()), in order to clear any values that may have been set after parsing "ip=" or "nfsaddrs=" and are no longer needed. This means that ic_nameservers_predef() is not called when neither "ip=" nor "nfsaddrs=" is specified on the kernel command line. In this scenario, every element in ic_nameservers remains set to 0x00000000, which is indistinguishable from ANY and causes pnp_seq_show() to write the following (bogus) information to /proc/net/pnp: #MANUAL nameserver 0.0.0.0 nameserver 0.0.0.0 nameserver 0.0.0.0 This is potentially problematic for systems that blindly link /etc/resolv.conf to /proc/net/pnp. Ensure that ic_nameservers is also initialised when neither "ip=" nor "nfsaddrs=" are specified by calling ic_nameservers_predef() in ip_auto_config(), but only when ip_auto_config_setup() was not called earlier. This causes the following to be written to /proc/net/pnp, and is consistent with what gets written when ipconfig is configured manually but no name servers are specified on the kernel command line: #MANUAL Signed-off-by: Chris Novakovic Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ipconfig.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index abdebca848c9..f0782c91514c 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -781,6 +781,11 @@ static void __init ic_bootp_init_ext(u8 *e) */ static inline void __init ic_bootp_init(void) { + /* Re-initialise all name servers to NONE, in case any were set via the + * "ip=" or "nfsaddrs=" kernel command line parameters: any IP addresses + * specified there will already have been decoded but are no longer + * needed + */ ic_nameservers_predef(); dev_add_pack(&bootp_packet_type); @@ -1402,6 +1407,13 @@ static int __init ip_auto_config(void) int err; unsigned int i; + /* Initialise all name servers to NONE (but only if the "ip=" or + * "nfsaddrs=" kernel command line parameters weren't decoded, otherwise + * we'll overwrite the IP addresses specified there) + */ + if (ic_set_manually == 0) + ic_nameservers_predef(); + #ifdef CONFIG_PROC_FS proc_create("pnp", S_IRUGO, init_net.proc_net, &pnp_seq_fops); #endif /* CONFIG_PROC_FS */ @@ -1622,6 +1634,7 @@ static int __init ip_auto_config_setup(char *addrs) return 1; } + /* Initialise all name servers to NONE */ ic_nameservers_predef(); /* Parse string for static IP assignment. */ -- GitLab From 0be8aa812cef251b4208bb51fadf3510ded74f33 Mon Sep 17 00:00:00 2001 From: Siva Rebbagondla Date: Wed, 11 Apr 2018 12:13:32 +0530 Subject: [PATCH 0476/1001] rsi: Fix 'invalid vdd' warning in mmc [ Upstream commit 78e450719c702784e42af6da912d3692fd3da0cb ] While performing cleanup, driver is messing with card->ocr value by not masking rocr against ocr_avail. Below panic is observed with some of the SDIO host controllers due to this. Issue is resolved by reverting incorrect modifications to vdd. [ 927.423821] mmc1: Invalid vdd 0x1f [ 927.423925] Modules linked in: rsi_sdio(+) cmac bnep arc4 rsi_91x mac80211 cfg80211 btrsi rfcomm bluetooth ecdh_generic [ 927.424073] CPU: 0 PID: 1624 Comm: insmod Tainted: G W 4.15.0-1000-caracalla #1 [ 927.424075] Hardware name: Dell Inc. Edge Gateway 3003/ , BIOS 01.00.06 01/22/2018 [ 927.424082] RIP: 0010:sdhci_set_power_noreg+0xdd/0x190[sdhci] [ 927.424085] RSP: 0018:ffffac3fc064b930 EFLAGS: 00010282 [ 927.424107] Call Trace: [ 927.424118] sdhci_set_power+0x5a/0x60 [sdhci] [ 927.424125] sdhci_set_ios+0x360/0x3b0 [sdhci] [ 927.424133] mmc_set_initial_state+0x92/0x120 [ 927.424137] mmc_power_up.part.34+0x33/0x1d0 [ 927.424141] mmc_power_up+0x17/0x20 [ 927.424147] mmc_sdio_runtime_resume+0x2d/0x50 [ 927.424151] mmc_runtime_resume+0x17/0x20 [ 927.424156] __rpm_callback+0xc4/0x200 [ 927.424161] ? idr_alloc_cyclic+0x57/0xd0 [ 927.424165] ? mmc_runtime_suspend+0x20/0x20 [ 927.424169] rpm_callback+0x24/0x80 [ 927.424172] ? mmc_runtime_suspend+0x20/0x20 [ 927.424176] rpm_resume+0x4b3/0x6c0 [ 927.424181] __pm_runtime_resume+0x4e/0x80 [ 927.424188] driver_probe_device+0x41/0x490 [ 927.424192] __driver_attach+0xdf/0xf0 [ 927.424196] ? driver_probe_device+0x490/0x490 [ 927.424201] bus_for_each_dev+0x6c/0xc0 [ 927.424205] driver_attach+0x1e/0x20 [ 927.424209] bus_add_driver+0x1f4/0x270 [ 927.424217] ? rsi_sdio_ack_intr+0x50/0x50 [rsi_sdio] [ 927.424221] driver_register+0x60/0xe0 [ 927.424227] ? rsi_sdio_ack_intr+0x50/0x50 [rsi_sdio] [ 927.424231] sdio_register_driver+0x20/0x30 [ 927.424237] rsi_module_init+0x16/0x40 [rsi_sdio] Signed-off-by: Siva Rebbagondla Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rsi/rsi_91x_sdio.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 370161ca2a1c..2545f8f8f3fb 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -161,7 +161,6 @@ static void rsi_reset_card(struct sdio_func *pfunction) int err; struct mmc_card *card = pfunction->card; struct mmc_host *host = card->host; - s32 bit = (fls(host->ocr_avail) - 1); u8 cmd52_resp; u32 clock, resp, i; u16 rca; @@ -181,7 +180,6 @@ static void rsi_reset_card(struct sdio_func *pfunction) msleep(20); /* Initialize the SDIO card */ - host->ios.vdd = bit; host->ios.chip_select = MMC_CS_DONTCARE; host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; host->ios.power_mode = MMC_POWER_UP; -- GitLab From e7cb8f11f6e2341a167c1b23c58716171f3fcfb9 Mon Sep 17 00:00:00 2001 From: Siva Rebbagondla Date: Wed, 11 Apr 2018 12:13:31 +0530 Subject: [PATCH 0477/1001] rsi: fix nommu_map_sg overflow kernel panic [ Upstream commit f700546682a62a87a9615121a37ee7452dab4b76 ] Following overflow kernel panic is observed on some platforms while loading the driver. It is fixed if dynamically allocated memory is passed to SDIO instead of static one [ 927.513963] nommu_map_sg: overflow 17d54064ba7c+20 of device mask ffffffff [ 927.517712] Modules linked in: rsi_sdio(+) cmac bnep arc4 rsi_91x mac80211 cfg80211 btrsi rfcomm bluetooth ecdh_generic snd_soc_sst_bytcr_rt5660 [ 927.517861] CPU: 0 PID: 1624 Comm: insmod Tainted: G W 4.15.0-1000 #1 [ 927.517870] RIP: 0010:sdhci_send_command+0x5f0/0xa90 [sdhci] [ 927.517873] RSP: 0000:ffffac3fc064b6d8 EFLAGS: 00010086 [ 927.517895] Call Trace: [ 927.517908] ? __schedule+0x3cd/0x890 [ 927.517915] ? mod_timer+0x17b/0x3c0 [ 927.517922] sdhci_request+0x7c/0xf0 [sdhci] [ 927.517928] __mmc_start_request+0x5a/0x170 [ 927.517932] mmc_start_request+0x74/0x90 [ 927.517936] mmc_wait_for_req+0x87/0xe0 [ 927.517940] mmc_io_rw_extended+0x2fd/0x330 [ 927.517946] ? mmc_wait_data_done+0x30/0x30 [ 927.517951] sdio_io_rw_ext_helper+0x160/0x210 [ 927.517956] sdio_writesb+0x1d/0x20 [ 927.517966] rsi_sdio_write_register_multiple+0x68/0x110 [rsi_sdio] [ 927.517976] rsi_hal_device_init+0x357/0x910 [rsi_91x] [ 927.517983] ? rsi_hal_device_init+0x357/0x910 [rsi_91x] [ 927.517990] rsi_probe+0x2c6/0x450 [rsi_sdio] [ 927.517995] sdio_bus_probe+0xfc/0x110 [ 927.518000] driver_probe_device+0x2b3/0x490 [ 927.518005] __driver_attach+0xdf/0xf0 [ 927.518008] ? driver_probe_device+0x490/0x490 [ 927.518014] bus_for_each_dev+0x6c/0xc0 [ 927.518018] driver_attach+0x1e/0x20 [ 927.518021] bus_add_driver+0x1f4/0x270 [ 927.518028] ? rsi_sdio_ack_intr+0x50/0x50 [rsi_sdio] [ 927.518031] driver_register+0x60/0xe0 [ 927.518038] ? rsi_sdio_ack_intr+0x50/0x50 [rsi_sdio] [ 927.518041] sdio_register_driver+0x20/0x30 [ 927.518047] rsi_module_init+0x16/0x40 [rsi_sdio] Signed-off-by: Siva Rebbagondla Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rsi/rsi_91x_hal.c | 35 +++++++++++++++---------- drivers/net/wireless/rsi/rsi_91x_sdio.c | 21 ++++++++++----- drivers/net/wireless/rsi/rsi_sdio.h | 2 +- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 070dfd68bb83..120b0ff545c1 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -557,28 +557,32 @@ static int bl_write_header(struct rsi_hw *adapter, u8 *flash_content, u32 content_size) { struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; - struct bl_header bl_hdr; + struct bl_header *bl_hdr; u32 write_addr, write_len; int status; - bl_hdr.flags = 0; - bl_hdr.image_no = cpu_to_le32(adapter->priv->coex_mode); - bl_hdr.check_sum = cpu_to_le32( - *(u32 *)&flash_content[CHECK_SUM_OFFSET]); - bl_hdr.flash_start_address = cpu_to_le32( - *(u32 *)&flash_content[ADDR_OFFSET]); - bl_hdr.flash_len = cpu_to_le32(*(u32 *)&flash_content[LEN_OFFSET]); + bl_hdr = kzalloc(sizeof(*bl_hdr), GFP_KERNEL); + if (!bl_hdr) + return -ENOMEM; + + bl_hdr->flags = 0; + bl_hdr->image_no = cpu_to_le32(adapter->priv->coex_mode); + bl_hdr->check_sum = + cpu_to_le32(*(u32 *)&flash_content[CHECK_SUM_OFFSET]); + bl_hdr->flash_start_address = + cpu_to_le32(*(u32 *)&flash_content[ADDR_OFFSET]); + bl_hdr->flash_len = cpu_to_le32(*(u32 *)&flash_content[LEN_OFFSET]); write_len = sizeof(struct bl_header); if (adapter->rsi_host_intf == RSI_HOST_INTF_USB) { write_addr = PING_BUFFER_ADDRESS; status = hif_ops->write_reg_multiple(adapter, write_addr, - (u8 *)&bl_hdr, write_len); + (u8 *)bl_hdr, write_len); if (status < 0) { rsi_dbg(ERR_ZONE, "%s: Failed to load Version/CRC structure\n", __func__); - return status; + goto fail; } } else { write_addr = PING_BUFFER_ADDRESS >> 16; @@ -587,20 +591,23 @@ static int bl_write_header(struct rsi_hw *adapter, u8 *flash_content, rsi_dbg(ERR_ZONE, "%s: Unable to set ms word to common reg\n", __func__); - return status; + goto fail; } write_addr = RSI_SD_REQUEST_MASTER | (PING_BUFFER_ADDRESS & 0xFFFF); status = hif_ops->write_reg_multiple(adapter, write_addr, - (u8 *)&bl_hdr, write_len); + (u8 *)bl_hdr, write_len); if (status < 0) { rsi_dbg(ERR_ZONE, "%s: Failed to load Version/CRC structure\n", __func__); - return status; + goto fail; } } - return 0; + status = 0; +fail: + kfree(bl_hdr); + return status; } static u32 read_flash_capacity(struct rsi_hw *adapter) diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 2545f8f8f3fb..0362967874aa 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -968,17 +968,21 @@ static void ulp_read_write(struct rsi_hw *adapter, u16 addr, u32 data, /*This function resets and re-initializes the chip.*/ static void rsi_reset_chip(struct rsi_hw *adapter) { - __le32 data; + u8 *data; u8 sdio_interrupt_status = 0; u8 request = 1; int ret; + data = kzalloc(sizeof(u32), GFP_KERNEL); + if (!data) + return; + rsi_dbg(INFO_ZONE, "Writing disable to wakeup register\n"); ret = rsi_sdio_write_register(adapter, 0, SDIO_WAKEUP_REG, &request); if (ret < 0) { rsi_dbg(ERR_ZONE, "%s: Failed to write SDIO wakeup register\n", __func__); - return; + goto err; } msleep(20); ret = rsi_sdio_read_register(adapter, RSI_FN1_INT_REGISTER, @@ -986,7 +990,7 @@ static void rsi_reset_chip(struct rsi_hw *adapter) if (ret < 0) { rsi_dbg(ERR_ZONE, "%s: Failed to Read Intr Status Register\n", __func__); - return; + goto err; } rsi_dbg(INFO_ZONE, "%s: Intr Status Register value = %d\n", __func__, sdio_interrupt_status); @@ -996,17 +1000,17 @@ static void rsi_reset_chip(struct rsi_hw *adapter) rsi_dbg(ERR_ZONE, "%s: Unable to set ms word to common reg\n", __func__); - return; + goto err; } - data = TA_HOLD_THREAD_VALUE; + put_unaligned_le32(TA_HOLD_THREAD_VALUE, data); if (rsi_sdio_write_register_multiple(adapter, TA_HOLD_THREAD_REG | RSI_SD_REQUEST_MASTER, - (u8 *)&data, 4)) { + data, 4)) { rsi_dbg(ERR_ZONE, "%s: Unable to hold Thread-Arch processor threads\n", __func__); - return; + goto err; } /* This msleep will ensure Thread-Arch processor to go to hold @@ -1027,6 +1031,9 @@ static void rsi_reset_chip(struct rsi_hw *adapter) * read write operations to complete for chip reset. */ msleep(500); +err: + kfree(data); + return; } /** diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h index 903392039200..6788fbbdd166 100644 --- a/drivers/net/wireless/rsi/rsi_sdio.h +++ b/drivers/net/wireless/rsi/rsi_sdio.h @@ -85,7 +85,7 @@ enum sdio_interrupt_type { #define TA_SOFT_RST_CLR 0 #define TA_SOFT_RST_SET BIT(0) #define TA_PC_ZERO 0 -#define TA_HOLD_THREAD_VALUE cpu_to_le32(0xF) +#define TA_HOLD_THREAD_VALUE 0xF #define TA_RELEASE_THREAD_VALUE cpu_to_le32(0xF) #define TA_BASE_ADDR 0x2200 #define MISC_CFG_BASE_ADDR 0x4105 -- GitLab From 06d6d1ad241d9df531e1d8af4be6c468cb830d8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ondrej=20Mosn=C3=A1=C4=8Dek?= Date: Mon, 9 Apr 2018 10:00:06 +0200 Subject: [PATCH 0478/1001] audit: allow not equal op for audit by executable [ Upstream commit 23bcc480dac204c7dbdf49d96b2c918ed98223c2 ] Current implementation of auditing by executable name only implements the 'equal' operator. This patch extends it to also support the 'not equal' operator. See: https://github.com/linux-audit/audit-kernel/issues/53 Signed-off-by: Ondrej Mosnacek Reviewed-by: Richard Guy Briggs Signed-off-by: Paul Moore Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/auditfilter.c | 2 +- kernel/auditsc.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 0b0aa5854dac..8dd4063647c2 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -407,7 +407,7 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f) return -EINVAL; break; case AUDIT_EXE: - if (f->op != Audit_equal) + if (f->op != Audit_not_equal && f->op != Audit_equal) return -EINVAL; if (entry->rule.listnr != AUDIT_FILTER_EXIT) return -EINVAL; diff --git a/kernel/auditsc.c b/kernel/auditsc.c index ecc23e25c9eb..677053a2fb57 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -471,6 +471,8 @@ static int audit_filter_rules(struct task_struct *tsk, break; case AUDIT_EXE: result = audit_exe_compare(tsk, rule->exe); + if (f->op == Audit_not_equal) + result = !result; break; case AUDIT_UID: result = audit_uid_comparator(cred->uid, f->op, f->uid); -- GitLab From fea5a0d8781644daaee936a84f14dae5e7fc0795 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 31 Mar 2018 22:09:37 +0200 Subject: [PATCH 0479/1001] staging: vchiq_core: Fix missing semaphore release in error case [ Upstream commit 8113b89fc615cfb531df0334fb3a091cf6a45ce0 ] The bail out branch in case of a invalid tx_pos missed a semaphore release. Dan Carpenter found this with a static checker. Fixes: d1eab9dec610 ("staging: vchiq_core: Bail out in case of invalid tx_pos") Reported-by: Dan Carpenter Signed-off-by: Stefan Wahren Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index 486be990d7fc..a457034818c3 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -601,6 +601,7 @@ reserve_space(VCHIQ_STATE_T *state, size_t space, int is_blocking) } if (tx_pos == (state->slot_queue_available * VCHIQ_SLOT_SIZE)) { + up(&state->slot_available_event); pr_warn("%s: invalid tx_pos: %d\n", __func__, tx_pos); return NULL; } -- GitLab From e906355a7f9665c8ec07739f8561d0c783ee5dad Mon Sep 17 00:00:00 2001 From: James Simmons Date: Mon, 16 Apr 2018 00:15:10 -0400 Subject: [PATCH 0480/1001] staging: lustre: llite: correct removexattr detection [ Upstream commit 1b60f6dfa38403ff7c4d0b4b7ecdb810f9789a2a ] In ll_xattr_set_common() detect the removexattr() case correctly by testing for a NULL value as well as XATTR_REPLACE. Signed-off-by: John L. Hammond Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-10787 Reviewed-on: https://review.whamcloud.com/ Reviewed-by: Dmitry Eremin Reviewed-by: James Simmons Signed-off-by: James Simmons Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/llite/xattr.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/staging/lustre/lustre/llite/xattr.c b/drivers/staging/lustre/lustre/llite/xattr.c index 0be55623bac4..364d697b2690 100644 --- a/drivers/staging/lustre/lustre/llite/xattr.c +++ b/drivers/staging/lustre/lustre/llite/xattr.c @@ -93,7 +93,11 @@ ll_xattr_set_common(const struct xattr_handler *handler, __u64 valid; int rc; - if (flags == XATTR_REPLACE) { + /* When setxattr() is called with a size of 0 the value is + * unconditionally replaced by "". When removexattr() is + * called we get a NULL value and XATTR_REPLACE for flags. + */ + if (!value && flags == XATTR_REPLACE) { ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_REMOVEXATTR, 1); valid = OBD_MD_FLXATTRRM; } else { -- GitLab From 41e1f1feee0634c0acb3727980607c7784c7d494 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 29 Mar 2018 15:26:48 +1100 Subject: [PATCH 0481/1001] staging: lustre: ldlm: free resource when ldlm_lock_create() fails. [ Upstream commit d8caf662b4aeeb2ac83ac0b22e40db88e9360c77 ] ldlm_lock_create() gets a resource, but don't put it on all failure paths. It should. Signed-off-by: NeilBrown Reviewed-by: James Simmons Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/ldlm/ldlm_lock.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c index b5d84f3f6071..11e01c48f51a 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c @@ -1571,8 +1571,10 @@ struct ldlm_lock *ldlm_lock_create(struct ldlm_namespace *ns, return ERR_CAST(res); lock = ldlm_lock_new(res); - if (!lock) + if (!lock) { + ldlm_resource_putref(res); return ERR_PTR(-ENOMEM); + } lock->l_req_mode = mode; lock->l_ast_data = data; @@ -1615,6 +1617,8 @@ struct ldlm_lock *ldlm_lock_create(struct ldlm_namespace *ns, return ERR_PTR(rc); } + + /** * Enqueue (request) a lock. * On the client this is called from ldlm_cli_enqueue_fini -- GitLab From 62079c8371aaa08f072a3e41628e753f9696d6df Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 23 Mar 2018 10:58:31 -0700 Subject: [PATCH 0482/1001] serial: core: Make sure compiler barfs for 16-byte earlycon names [ Upstream commit c1c734cb1f54b062f7e67ffc9656d82f5b412b9c ] As part of bringup I ended up wanting to call an earlycon driver by a name that was exactly 16-bytes big, specifically "qcom_geni_serial". Unfortunately, when I tried this I found that things compiled just fine. They just didn't work. Specifically the compiler felt perfectly justified in initting the ".name" field of "struct earlycon_id" with the full 16-bytes and just skipping the '\0'. Needless to say, that behavior didn't seem ideal, but I guess someone must have allowed it for a reason. One way to fix this is to shorten the name field to 15 bytes and then add an extra byte after that nobody touches. This should always be initted to 0 and we're golden. There are, of course, other ways to fix this too. We could audit all the users of the "name" field and make them stop at both null termination or at 16 bytes. We could also just make the name field much bigger so that we're not likely to run into this. ...but both seem like we'll just hit the bug again. Signed-off-by: Douglas Anderson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/linux/serial_core.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 74fc82d22310..868b60a79c0b 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -348,7 +348,8 @@ struct earlycon_device { }; struct earlycon_id { - char name[16]; + char name[15]; + char name_term; /* In case compiler didn't '\0' term name */ char compatible[128]; int (*setup)(struct earlycon_device *, const char *options); }; -- GitLab From 6cfd0d3c627f845ca6bcc560a57c0bb2632e4ebf Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Tue, 10 Apr 2018 11:32:09 -0700 Subject: [PATCH 0483/1001] soc: imx: gpcv2: Do not pass static memory as platform data [ Upstream commit 050f810e238f268670f14a8f8b793ba2dbf2e92f ] Platform device core assumes the ownership of dev.platform_data as well as that it is dynamically allocated and it will try to kfree it as a part of platform_device_release(). Change the code to use platform_device_add_data() n instead of a pointer to a static memory to avoid causing a BUG() when calling platform_device_put(). The problem can be reproduced by artificially enabling the error path of platform_device_add() call (around line 357). Note that this change also allows us to constify imx7_pgc_domains, since we no longer need to be able to modify it. Cc: Stefan Agner Cc: Lucas Stach Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Andrey Smirnov Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/soc/imx/gpcv2.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index afc7ecc3c187..f4e3bd40c72e 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -155,7 +155,7 @@ static int imx7_gpc_pu_pgc_sw_pdn_req(struct generic_pm_domain *genpd) return imx7_gpc_pu_pgc_sw_pxx_req(genpd, false); } -static struct imx7_pgc_domain imx7_pgc_domains[] = { +static const struct imx7_pgc_domain imx7_pgc_domains[] = { [IMX7_POWER_DOMAIN_MIPI_PHY] = { .genpd = { .name = "mipi-phy", @@ -321,11 +321,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev) continue; } - domain = &imx7_pgc_domains[domain_index]; - domain->regmap = regmap; - domain->genpd.power_on = imx7_gpc_pu_pgc_sw_pup_req; - domain->genpd.power_off = imx7_gpc_pu_pgc_sw_pdn_req; - pd_pdev = platform_device_alloc("imx7-pgc-domain", domain_index); if (!pd_pdev) { @@ -334,7 +329,20 @@ static int imx_gpcv2_probe(struct platform_device *pdev) return -ENOMEM; } - pd_pdev->dev.platform_data = domain; + ret = platform_device_add_data(pd_pdev, + &imx7_pgc_domains[domain_index], + sizeof(imx7_pgc_domains[domain_index])); + if (ret) { + platform_device_put(pd_pdev); + of_node_put(np); + return ret; + } + + domain = pd_pdev->dev.platform_data; + domain->regmap = regmap; + domain->genpd.power_on = imx7_gpc_pu_pgc_sw_pup_req; + domain->genpd.power_off = imx7_gpc_pu_pgc_sw_pdn_req; + pd_pdev->dev.parent = dev; pd_pdev->dev.of_node = np; -- GitLab From d136b7ab24b8df3136f96babe0b4e369c1e6c120 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 10 Apr 2018 15:05:42 +0200 Subject: [PATCH 0484/1001] microblaze: Fix simpleImage format generation [ Upstream commit ece97f3a5fb50cf5f98886fbc63c9665f2bb199d ] simpleImage generation was broken for some time. This patch is fixing steps how simpleImage.*.ub file is generated. Steps are objdump of vmlinux and create .ub. Also make sure that there is striped elf version with .strip suffix. Signed-off-by: Michal Simek Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/microblaze/boot/Makefile | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/microblaze/boot/Makefile b/arch/microblaze/boot/Makefile index 47f94cc383b6..7c2f52d4a0e4 100644 --- a/arch/microblaze/boot/Makefile +++ b/arch/microblaze/boot/Makefile @@ -22,17 +22,19 @@ $(obj)/linux.bin.gz: $(obj)/linux.bin FORCE quiet_cmd_cp = CP $< $@$2 cmd_cp = cat $< >$@$2 || (rm -f $@ && echo false) -quiet_cmd_strip = STRIP $@ +quiet_cmd_strip = STRIP $< $@$2 cmd_strip = $(STRIP) -K microblaze_start -K _end -K __log_buf \ - -K _fdt_start vmlinux -o $@ + -K _fdt_start $< -o $@$2 UIMAGE_LOADADDR = $(CONFIG_KERNEL_BASE_ADDR) +UIMAGE_IN = $@ +UIMAGE_OUT = $@.ub $(obj)/simpleImage.%: vmlinux FORCE $(call if_changed,cp,.unstrip) $(call if_changed,objcopy) $(call if_changed,uimage) - $(call if_changed,strip) - @echo 'Kernel: $@ is ready' ' (#'`cat .version`')' + $(call if_changed,strip,.strip) + @echo 'Kernel: $(UIMAGE_OUT) is ready' ' (#'`cat .version`')' clean-files += simpleImage.*.unstrip linux.bin.ub dts/*.dtb -- GitLab From f17d397bfed4371bbefcb1a9d497ea9cd057df3e Mon Sep 17 00:00:00 2001 From: Dominik Bozek Date: Fri, 13 Apr 2018 10:42:31 -0700 Subject: [PATCH 0485/1001] usb: hub: Don't wait for connect state at resume for powered-off ports [ Upstream commit 5d111f5190848d6fb1c414dc57797efea3526a2f ] wait_for_connected() wait till a port change status to USB_PORT_STAT_CONNECTION, but this is not possible if the port is unpowered. The loop will only exit at timeout. Such case take place if an over-current incident happen while system is in S3. Then during resume wait_for_connected() will wait 2s, which may be noticeable by the user. Signed-off-by: Dominik Bozek Signed-off-by: Kuppuswamy Sathyanarayanan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index a8bc48b26c23..a9db0887edca 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3361,6 +3361,10 @@ static int wait_for_connected(struct usb_device *udev, while (delay_ms < 2000) { if (status || *portstatus & USB_PORT_STAT_CONNECTION) break; + if (!port_is_power_on(hub, *portstatus)) { + status = -ENODEV; + break; + } msleep(20); delay_ms += 20; status = hub_port_status(hub, *port1, portstatus, portchange); -- GitLab From a07fc8dd2bd4f790940c9a5ac3b7fae1e6738800 Mon Sep 17 00:00:00 2001 From: Tudor-Dan Ambarus Date: Tue, 3 Apr 2018 09:39:01 +0300 Subject: [PATCH 0486/1001] crypto: authencesn - don't leak pointers to authenc keys [ Upstream commit 31545df391d58a3bb60e29b1192644a6f2b5a8dd ] In crypto_authenc_esn_setkey we save pointers to the authenc keys in a local variable of type struct crypto_authenc_keys and we don't zeroize it after use. Fix this and don't leak pointers to the authenc keys. Signed-off-by: Tudor Ambarus Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- crypto/authencesn.c | 1 + 1 file changed, 1 insertion(+) diff --git a/crypto/authencesn.c b/crypto/authencesn.c index 0cf5fefdb859..6de852ce4cf8 100644 --- a/crypto/authencesn.c +++ b/crypto/authencesn.c @@ -90,6 +90,7 @@ static int crypto_authenc_esn_setkey(struct crypto_aead *authenc_esn, const u8 * CRYPTO_TFM_RES_MASK); out: + memzero_explicit(&keys, sizeof(keys)); return err; badkey: -- GitLab From 09740f513e3fab823bce5daecc6caf00f1d0b82c Mon Sep 17 00:00:00 2001 From: Tudor-Dan Ambarus Date: Tue, 3 Apr 2018 09:39:00 +0300 Subject: [PATCH 0487/1001] crypto: authenc - don't leak pointers to authenc keys [ Upstream commit ad2fdcdf75d169e7a5aec6c7cb421c0bec8ec711 ] In crypto_authenc_setkey we save pointers to the authenc keys in a local variable of type struct crypto_authenc_keys and we don't zeroize it after use. Fix this and don't leak pointers to the authenc keys. Signed-off-by: Tudor Ambarus Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- crypto/authenc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/crypto/authenc.c b/crypto/authenc.c index 875470b0e026..0db344d5a01a 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -108,6 +108,7 @@ static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key, CRYPTO_TFM_RES_MASK); out: + memzero_explicit(&keys, sizeof(keys)); return err; badkey: -- GitLab From 4886bf00337f4c70a2bffc0e2e5cdbf813342a95 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 14 Mar 2018 11:41:36 -0400 Subject: [PATCH 0488/1001] media: omap3isp: fix unbalanced dma_iommu_mapping [ Upstream commit b7e1e6859fbf60519fd82d7120cee106a6019512 ] The OMAP3 ISP driver manages its MMU mappings through the IOMMU-aware ARM DMA backend. The current code creates a dma_iommu_mapping and attaches this to the ISP device, but never detaches the mapping in either the probe failure paths or the driver remove path resulting in an unbalanced mapping refcount and a memory leak. Fix this properly. Reported-by: Pavel Machek Signed-off-by: Suman Anna Tested-by: Pavel Machek Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/omap3isp/isp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 1a428fe9f070..9f023bc6e1b7 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -1945,6 +1945,7 @@ static int isp_initialize_modules(struct isp_device *isp) static void isp_detach_iommu(struct isp_device *isp) { + arm_iommu_detach_device(isp->dev); arm_iommu_release_mapping(isp->mapping); isp->mapping = NULL; } @@ -1961,8 +1962,7 @@ static int isp_attach_iommu(struct isp_device *isp) mapping = arm_iommu_create_mapping(&platform_bus_type, SZ_1G, SZ_2G); if (IS_ERR(mapping)) { dev_err(isp->dev, "failed to create ARM IOMMU mapping\n"); - ret = PTR_ERR(mapping); - goto error; + return PTR_ERR(mapping); } isp->mapping = mapping; @@ -1977,7 +1977,8 @@ static int isp_attach_iommu(struct isp_device *isp) return 0; error: - isp_detach_iommu(isp); + arm_iommu_release_mapping(isp->mapping); + isp->mapping = NULL; return ret; } -- GitLab From fb2b60e27a16c4bd5054bc518ec3d786036b7dce Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Wed, 18 Apr 2018 08:54:18 -0700 Subject: [PATCH 0489/1001] regulator: Don't return or expect -errno from of_map_mode() [ Upstream commit 02f3703934a42417021405ef336fe45add13c3d1 ] In of_get_regulation_constraints() we were taking the result of of_map_mode() (an unsigned int) and assigning it to an int. We were then checking whether this value was -EINVAL. Some implementers of of_map_mode() were returning -EINVAL (even though the return type of their function needed to be unsigned int) because they needed to signal an error back to of_get_regulation_constraints(). In general in the regulator framework the mode is always referred to as an unsigned int. While we could fix this to be a signed int (the highest value we store in there right now is 0x8), it's actually pretty clean to just define the regulator mode 0x0 (the lack of any bits set) as an invalid mode. Let's do that. Fixes: 5e5e3a42c653 ("regulator: of: Add support for parsing initial and suspend modes") Suggested-by: Javier Martinez Canillas Signed-off-by: Douglas Anderson Reviewed-by: Javier Martinez Canillas Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/regulator/cpcap-regulator.c | 2 +- drivers/regulator/of_regulator.c | 13 +++++++------ drivers/regulator/twl-regulator.c | 2 +- include/linux/regulator/consumer.h | 1 + 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/regulator/cpcap-regulator.c b/drivers/regulator/cpcap-regulator.c index f541b80f1b54..bd910fe123d9 100644 --- a/drivers/regulator/cpcap-regulator.c +++ b/drivers/regulator/cpcap-regulator.c @@ -222,7 +222,7 @@ static unsigned int cpcap_map_mode(unsigned int mode) case CPCAP_BIT_AUDIO_LOW_PWR: return REGULATOR_MODE_STANDBY; default: - return -EINVAL; + return REGULATOR_MODE_INVALID; } } diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index c9875355905d..a3bf7c993723 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -31,6 +31,7 @@ static void of_get_regulation_constraints(struct device_node *np, struct regulation_constraints *constraints = &(*init_data)->constraints; struct regulator_state *suspend_state; struct device_node *suspend_np; + unsigned int mode; int ret, i; u32 pval; @@ -124,11 +125,11 @@ static void of_get_regulation_constraints(struct device_node *np, if (!of_property_read_u32(np, "regulator-initial-mode", &pval)) { if (desc && desc->of_map_mode) { - ret = desc->of_map_mode(pval); - if (ret == -EINVAL) + mode = desc->of_map_mode(pval); + if (mode == REGULATOR_MODE_INVALID) pr_err("%s: invalid mode %u\n", np->name, pval); else - constraints->initial_mode = ret; + constraints->initial_mode = mode; } else { pr_warn("%s: mapping for mode %d not defined\n", np->name, pval); @@ -163,12 +164,12 @@ static void of_get_regulation_constraints(struct device_node *np, if (!of_property_read_u32(suspend_np, "regulator-mode", &pval)) { if (desc && desc->of_map_mode) { - ret = desc->of_map_mode(pval); - if (ret == -EINVAL) + mode = desc->of_map_mode(pval); + if (mode == REGULATOR_MODE_INVALID) pr_err("%s: invalid mode %u\n", np->name, pval); else - suspend_state->mode = ret; + suspend_state->mode = mode; } else { pr_warn("%s: mapping for mode %d not defined\n", np->name, pval); diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index a4456db5849d..884c7505ed91 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -274,7 +274,7 @@ static inline unsigned int twl4030reg_map_mode(unsigned int mode) case RES_STATE_SLEEP: return REGULATOR_MODE_STANDBY; default: - return -EINVAL; + return REGULATOR_MODE_INVALID; } } diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index df176d7c2b87..25602afd4844 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -80,6 +80,7 @@ struct regmap; * These modes can be OR'ed together to make up a mask of valid register modes. */ +#define REGULATOR_MODE_INVALID 0x0 #define REGULATOR_MODE_FAST 0x1 #define REGULATOR_MODE_NORMAL 0x2 #define REGULATOR_MODE_IDLE 0x4 -- GitLab From 0b45eb5a340d100856721c8ba9a49e29e655d7f7 Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Sat, 7 Apr 2018 00:47:23 +0200 Subject: [PATCH 0490/1001] scsi: scsi_dh: replace too broad "TP9" string with the exact models [ Upstream commit 37b37d2609cb0ac267280ef27350b962d16d272e ] SGI/TP9100 is not an RDAC array: ^^^ https://git.opensvc.com/gitweb.cgi?p=multipath-tools/.git;a=blob;f=libmultipath/hwtable.c;h=88b4700beb1d8940008020fbe4c3cd97d62f4a56;hb=HEAD#l235 This partially reverts commit 35204772ea03 ("[SCSI] scsi_dh_rdac : Consolidate rdac strings together") [mkp: fixed up the new entries to align with rest of struct] Cc: NetApp RDAC team Cc: Hannes Reinecke Cc: James E.J. Bottomley Cc: Martin K. Petersen Cc: SCSI ML Cc: DM ML Signed-off-by: Xose Vazquez Perez Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_dh.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index a5e30e9449ef..375cede0c534 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -58,7 +58,10 @@ static const struct scsi_dh_blist scsi_dh_blist[] = { {"IBM", "3526", "rdac", }, {"IBM", "3542", "rdac", }, {"IBM", "3552", "rdac", }, - {"SGI", "TP9", "rdac", }, + {"SGI", "TP9300", "rdac", }, + {"SGI", "TP9400", "rdac", }, + {"SGI", "TP9500", "rdac", }, + {"SGI", "TP9700", "rdac", }, {"SGI", "IS", "rdac", }, {"STK", "OPENstorage", "rdac", }, {"STK", "FLEXLINE 380", "rdac", }, -- GitLab From 07b2a0d0018381c7b9760e6d3ceb72f683ad46ba Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Fri, 6 Apr 2018 02:02:11 -0700 Subject: [PATCH 0491/1001] scsi: megaraid_sas: Increase timeout by 1 sec for non-RAID fastpath IOs [ Upstream commit 3239b8cd28fd849a2023483257d35d68c5876c74 ] Hardware could time out Fastpath IOs one second earlier than the timeout provided by the host. For non-RAID devices, driver provides timeout value based on OS provided timeout value. Under certain scenarios, if the OS provides a timeout value of 1 second, due to above behavior hardware will timeout immediately. Increase timeout value for non-RAID fastpath IOs by 1 second. Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/megaraid/megaraid_sas_fusion.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index d8f626567f59..06a2e3d9fc5b 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -2677,6 +2677,9 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, pRAID_Context->timeout_value = cpu_to_le16(os_timeout_value); pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id); } else { + if (os_timeout_value) + os_timeout_value++; + /* system pd Fast Path */ io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; timeout_limit = (scmd->device->type == TYPE_DISK) ? -- GitLab From bb7cccb01c84e0b7c0a4d43fa7b25510e56e92df Mon Sep 17 00:00:00 2001 From: Uma Krishnan Date: Mon, 26 Mar 2018 11:35:27 -0500 Subject: [PATCH 0492/1001] scsi: cxlflash: Synchronize reset and remove ops [ Upstream commit a3feb6ef50def7c91244d7bd15a3625b7b49b81f ] The following Oops can be encountered if a device removal or system shutdown is initiated while an EEH recovery is in process: [c000000ff2f479c0] c008000015256f18 cxlflash_pci_slot_reset+0xa0/0x100 [cxlflash] [c000000ff2f47a30] c00800000dae22e0 cxl_pci_slot_reset+0x168/0x290 [cxl] [c000000ff2f47ae0] c00000000003ef1c eeh_report_reset+0xec/0x170 [c000000ff2f47b20] c00000000003d0b8 eeh_pe_dev_traverse+0x98/0x170 [c000000ff2f47bb0] c00000000003f80c eeh_handle_normal_event+0x56c/0x580 [c000000ff2f47c60] c00000000003fba4 eeh_handle_event+0x2a4/0x338 [c000000ff2f47d10] c0000000000400b8 eeh_event_handler+0x1f8/0x200 [c000000ff2f47dc0] c00000000013da48 kthread+0x1a8/0x1b0 [c000000ff2f47e30] c00000000000b528 ret_from_kernel_thread+0x5c/0xb4 The remove handler frees AFU memory while the EEH recovery is in progress, leading to a race condition. This can result in a crash if the recovery thread tries to access this memory. To resolve this issue, the cxlflash remove handler will evaluate the device state and yield to any active reset or probing threads. Signed-off-by: Uma Krishnan Acked-by: Matthew R. Ochs Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/cxlflash/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 0b6467206f8e..12faf7f6c8ac 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -946,9 +946,9 @@ static void cxlflash_remove(struct pci_dev *pdev) return; } - /* If a Task Management Function is active, wait for it to complete - * before continuing with remove. - */ + /* Yield to running recovery threads before continuing with remove */ + wait_event(cfg->reset_waitq, cfg->state != STATE_RESET && + cfg->state != STATE_PROBING); spin_lock_irqsave(&cfg->tmf_slock, lock_flags); if (cfg->tmf_active) wait_event_interruptible_lock_irq(cfg->tmf_waitq, -- GitLab From a5ed99bc6f59803e58b59bc1c84444f77b6b7712 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Mon, 26 Mar 2018 11:30:22 -0500 Subject: [PATCH 0493/1001] scsi: cxlflash: Avoid clobbering context control register value [ Upstream commit 465891fe9237b02f8d0fd26448f733fae7236f4a ] The SISLite specification originally defined the context control register with a single field of bits to represent the LISN and also stipulated that the register reset value be 0. The cxlflash driver took advantage of this when programming the LISN for the master contexts via an unconditional write - no other bits were preserved. When unmap support was added, SISLite was updated to define bit 0 of the context control register as a way for the AFU to notify the context owner that unmap operations were supported. Thus the assumptions under which the register is setup changed and the existing unconditional write is clobbering the unmap state for master contexts. This is presently not an issue due to the order in which the context control register is programmed in relation to the unmap bit being queried but should be addressed to avoid a future regression in the event this code is moved elsewhere. To remedy this issue, preserve the bits when programming the LISN field in the context control register. Since the LISN will now be programmed using a read value, assert that the initial state of the LISN field is as described in SISLite (0). Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/cxlflash/main.c | 5 ++++- drivers/scsi/cxlflash/sislite.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 12faf7f6c8ac..737314cac8d8 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1303,7 +1303,10 @@ static void afu_err_intr_init(struct afu *afu) for (i = 0; i < afu->num_hwqs; i++) { hwq = get_hwq(afu, i); - writeq_be(SISL_MSI_SYNC_ERROR, &hwq->host_map->ctx_ctrl); + reg = readq_be(&hwq->host_map->ctx_ctrl); + WARN_ON((reg & SISL_CTX_CTRL_LISN_MASK) != 0); + reg |= SISL_MSI_SYNC_ERROR; + writeq_be(reg, &hwq->host_map->ctx_ctrl); writeq_be(SISL_ISTATUS_MASK, &hwq->host_map->intr_mask); } } diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index 09daa86670fc..0892fb1f0a1e 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -284,6 +284,7 @@ struct sisl_host_map { __be64 cmd_room; __be64 ctx_ctrl; /* least significant byte or b56:63 is LISN# */ #define SISL_CTX_CTRL_UNMAP_SECTOR 0x8000000000000000ULL /* b0 */ +#define SISL_CTX_CTRL_LISN_MASK (0xFFULL) __be64 mbox_w; /* restricted use */ __be64 sq_start; /* Submission Queue (R/W): write sequence and */ __be64 sq_end; /* inclusion semantics are the same as RRQ */ -- GitLab From 98121d665d93f306d832ac635fd77acdfeb41302 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 12 Apr 2018 05:31:59 -0400 Subject: [PATCH 0494/1001] media: atomisp: compat32: fix __user annotations [ Upstream commit ad4222a0e29664666a71685a6e732923ca7c7e45 ] The __user annotations at the compat32 code is not right: drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:81:18: warning: incorrect type in assignment (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:81:18: expected void *base drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:81:18: got void [noderef] * drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:232:23: warning: incorrect type in assignment (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:232:23: expected unsigned int [usertype] *xcoords_y drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:232:23: got void [noderef] * drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:233:23: warning: incorrect type in assignment (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:233:23: expected unsigned int [usertype] *ycoords_y drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:233:23: got void [noderef] * drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:234:24: warning: incorrect type in assignment (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:234:24: expected unsigned int [usertype] *xcoords_uv drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:234:24: got void [noderef] * drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:235:24: warning: incorrect type in assignment (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:235:24: expected unsigned int [usertype] *ycoords_uv drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:235:24: got void [noderef] * drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:296:29: warning: incorrect type in assignment (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:296:29: expected unsigned int [usertype] *effective_width drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:296:29: got void [noderef] * drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:360:29: warning: incorrect type in assignment (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:360:29: expected unsigned int [usertype] *effective_width drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:360:29: got void [noderef] * drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:437:19: warning: incorrect type in assignment (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:437:19: expected struct v4l2_framebuffer *frame drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:437:19: got void [noderef] * drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:481:29: warning: incorrect type in assignment (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:481:29: expected unsigned short *calb_grp_values drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:481:29: got void [noderef] * drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:701:39: warning: cast removes address space of expression drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:704:21: warning: incorrect type in argument 1 (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:704:21: expected void const volatile [noderef] * drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:704:21: got unsigned int [usertype] *src drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:737:43: warning: incorrect type in assignment (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:737:43: expected struct atomisp_shading_table *shading_table drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:737:43: got void [noderef] * drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:742:44: warning: incorrect type in argument 1 (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:742:44: expected void [noderef] *to drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:742:44: got struct atomisp_shading_table *shading_table drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:755:41: warning: incorrect type in assignment (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:755:41: expected struct atomisp_morph_table *morph_table drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:755:41: got void [noderef] * drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:760:44: warning: incorrect type in argument 1 (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:760:44: expected void [noderef] *to drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:760:44: got struct atomisp_morph_table *morph_table drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:772:40: warning: incorrect type in assignment (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:772:40: expected struct atomisp_dvs2_coefficients *dvs2_coefs drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:772:40: got void [noderef] * drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:777:44: warning: incorrect type in argument 1 (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:777:44: expected void [noderef] *to drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:777:44: got struct atomisp_dvs2_coefficients *dvs2_coefs drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:788:46: warning: incorrect type in assignment (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:788:46: expected struct atomisp_dvs_6axis_config *dvs_6axis_config drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:788:46: got void [noderef] * drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:793:44: warning: incorrect type in argument 1 (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:793:44: expected void [noderef] *to drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:793:44: got struct atomisp_dvs_6axis_config *dvs_6axis_config drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:853:17: warning: incorrect type in assignment (different address spaces) drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:853:17: expected struct atomisp_sensor_ae_bracketing_lut_entry *lut drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c:853:17: got void [noderef] * Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../pci/atomisp2/atomisp_compat_ioctl32.c | 49 ++++++++++--------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c index 0592ac1f2832..cfe6bb610014 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c @@ -81,7 +81,7 @@ static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, get_user(kp->flags, &up->flags)) return -EFAULT; - kp->base = compat_ptr(tmp); + kp->base = (void __force *)compat_ptr(tmp); get_v4l2_pix_format((struct v4l2_pix_format *)&kp->fmt, &up->fmt); return 0; } @@ -232,10 +232,10 @@ static int get_atomisp_dvs_6axis_config32(struct atomisp_dvs_6axis_config *kp, get_user(ycoords_uv, &up->ycoords_uv)) return -EFAULT; - kp->xcoords_y = compat_ptr(xcoords_y); - kp->ycoords_y = compat_ptr(ycoords_y); - kp->xcoords_uv = compat_ptr(xcoords_uv); - kp->ycoords_uv = compat_ptr(ycoords_uv); + kp->xcoords_y = (void __force *)compat_ptr(xcoords_y); + kp->ycoords_y = (void __force *)compat_ptr(ycoords_y); + kp->xcoords_uv = (void __force *)compat_ptr(xcoords_uv); + kp->ycoords_uv = (void __force *)compat_ptr(ycoords_uv); return 0; } @@ -296,7 +296,7 @@ static int get_atomisp_metadata_stat32(struct atomisp_metadata *kp, return -EFAULT; kp->data = compat_ptr(data); - kp->effective_width = compat_ptr(effective_width); + kp->effective_width = (void __force *)compat_ptr(effective_width); return 0; } @@ -360,7 +360,7 @@ static int get_atomisp_metadata_by_type_stat32( return -EFAULT; kp->data = compat_ptr(data); - kp->effective_width = compat_ptr(effective_width); + kp->effective_width = (void __force *)compat_ptr(effective_width); return 0; } @@ -437,7 +437,7 @@ static int get_atomisp_overlay32(struct atomisp_overlay *kp, get_user(kp->overlay_start_x, &up->overlay_start_y)) return -EFAULT; - kp->frame = compat_ptr(frame); + kp->frame = (void __force *)compat_ptr(frame); return 0; } @@ -481,7 +481,7 @@ static int get_atomisp_calibration_group32( get_user(calb_grp_values, &up->calb_grp_values)) return -EFAULT; - kp->calb_grp_values = compat_ptr(calb_grp_values); + kp->calb_grp_values = (void __force *)compat_ptr(calb_grp_values); return 0; } @@ -703,8 +703,8 @@ static int get_atomisp_parameters32(struct atomisp_parameters *kp, return -EFAULT; while (n >= 0) { - compat_uptr_t *src = (compat_uptr_t *)up + n; - uintptr_t *dst = (uintptr_t *)kp + n; + compat_uptr_t __user *src = ((compat_uptr_t __user *)up) + n; + uintptr_t *dst = ((uintptr_t *)kp) + n; if (get_user((*dst), src)) return -EFAULT; @@ -751,12 +751,12 @@ static int get_atomisp_parameters32(struct atomisp_parameters *kp, #endif return -EFAULT; - kp->shading_table = user_ptr + offset; + kp->shading_table = (void __force *)user_ptr + offset; offset = sizeof(struct atomisp_shading_table); if (!kp->shading_table) return -EFAULT; - if (copy_to_user(kp->shading_table, + if (copy_to_user((void __user *)kp->shading_table, &karg.shading_table, sizeof(struct atomisp_shading_table))) return -EFAULT; @@ -777,13 +777,14 @@ static int get_atomisp_parameters32(struct atomisp_parameters *kp, #endif return -EFAULT; - kp->morph_table = user_ptr + offset; + kp->morph_table = (void __force *)user_ptr + offset; offset += sizeof(struct atomisp_morph_table); if (!kp->morph_table) return -EFAULT; - if (copy_to_user(kp->morph_table, &karg.morph_table, - sizeof(struct atomisp_morph_table))) + if (copy_to_user((void __user *)kp->morph_table, + &karg.morph_table, + sizeof(struct atomisp_morph_table))) return -EFAULT; } @@ -802,13 +803,14 @@ static int get_atomisp_parameters32(struct atomisp_parameters *kp, #endif return -EFAULT; - kp->dvs2_coefs = user_ptr + offset; + kp->dvs2_coefs = (void __force *)user_ptr + offset; offset += sizeof(struct atomisp_dis_coefficients); if (!kp->dvs2_coefs) return -EFAULT; - if (copy_to_user(kp->dvs2_coefs, &karg.dvs2_coefs, - sizeof(struct atomisp_dis_coefficients))) + if (copy_to_user((void __user *)kp->dvs2_coefs, + &karg.dvs2_coefs, + sizeof(struct atomisp_dis_coefficients))) return -EFAULT; } /* handle dvs 6axis configuration */ @@ -826,13 +828,14 @@ static int get_atomisp_parameters32(struct atomisp_parameters *kp, #endif return -EFAULT; - kp->dvs_6axis_config = user_ptr + offset; + kp->dvs_6axis_config = (void __force *)user_ptr + offset; offset += sizeof(struct atomisp_dvs_6axis_config); if (!kp->dvs_6axis_config) return -EFAULT; - if (copy_to_user(kp->dvs_6axis_config, &karg.dvs_6axis_config, - sizeof(struct atomisp_dvs_6axis_config))) + if (copy_to_user((void __user *)kp->dvs_6axis_config, + &karg.dvs_6axis_config, + sizeof(struct atomisp_dvs_6axis_config))) return -EFAULT; } } @@ -891,7 +894,7 @@ static int get_atomisp_sensor_ae_bracketing_lut( get_user(lut, &up->lut)) return -EFAULT; - kp->lut = compat_ptr(lut); + kp->lut = (void __force *)compat_ptr(lut); return 0; } -- GitLab From e1d4f1e2856ee76e0d12141da2737a87875037fa Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 6 Apr 2018 07:54:51 -0400 Subject: [PATCH 0495/1001] media: si470x: fix __be16 annotations [ Upstream commit 90db5c829692a0a7845e977e45719b4699216bd4 ] The annotations there are wrong as warned: drivers/media/radio/si470x/radio-si470x-i2c.c:107:35: warning: cast to restricted __be16 drivers/media/radio/si470x/radio-si470x-i2c.c:107:35: warning: cast to restricted __be16 drivers/media/radio/si470x/radio-si470x-i2c.c:107:35: warning: cast to restricted __be16 drivers/media/radio/si470x/radio-si470x-i2c.c:107:35: warning: cast to restricted __be16 drivers/media/radio/si470x/radio-si470x-i2c.c:129:24: warning: incorrect type in assignment (different base types) drivers/media/radio/si470x/radio-si470x-i2c.c:129:24: expected unsigned short [unsigned] [short] drivers/media/radio/si470x/radio-si470x-i2c.c:129:24: got restricted __be16 [usertype] drivers/media/radio/si470x/radio-si470x-i2c.c:163:39: warning: cast to restricted __be16 drivers/media/radio/si470x/radio-si470x-i2c.c:163:39: warning: cast to restricted __be16 drivers/media/radio/si470x/radio-si470x-i2c.c:163:39: warning: cast to restricted __be16 drivers/media/radio/si470x/radio-si470x-i2c.c:163:39: warning: cast to restricted __be16 Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/radio/si470x/radio-si470x-i2c.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index b3034f80163f..8ce6f9cff746 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -92,7 +92,7 @@ MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); */ int si470x_get_register(struct si470x_device *radio, int regnr) { - u16 buf[READ_REG_NUM]; + __be16 buf[READ_REG_NUM]; struct i2c_msg msgs[1] = { { .addr = radio->client->addr, @@ -117,7 +117,7 @@ int si470x_get_register(struct si470x_device *radio, int regnr) int si470x_set_register(struct si470x_device *radio, int regnr) { int i; - u16 buf[WRITE_REG_NUM]; + __be16 buf[WRITE_REG_NUM]; struct i2c_msg msgs[1] = { { .addr = radio->client->addr, @@ -147,7 +147,7 @@ int si470x_set_register(struct si470x_device *radio, int regnr) static int si470x_get_all_registers(struct si470x_device *radio) { int i; - u16 buf[READ_REG_NUM]; + __be16 buf[READ_REG_NUM]; struct i2c_msg msgs[1] = { { .addr = radio->client->addr, -- GitLab From b754906cd9c9e7dce29e38a744a61b28dc161e5f Mon Sep 17 00:00:00 2001 From: Kirill Marinushkin Date: Wed, 4 Apr 2018 06:19:37 +0200 Subject: [PATCH 0496/1001] ASoC: topology: Fix bclk and fsync inversion in set_link_hw_format() [ Upstream commit a941e2fab3207cb0d57dc4ec47b1b12c8ea78b84 ] The values of bclk and fsync are inverted WRT the codec. But the existing solution already works for Broadwell, see the alsa-lib config: `alsa-lib/src/conf/topology/broadwell/broadwell.conf` This commit provides the backwards-compatible solution to fix this misuse. Signed-off-by: Kirill Marinushkin Reviewed-by: Pierre-Louis Bossart Tested-by: Pan Xiuli Tested-by: Pierre-Louis Bossart Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: Mark Brown Cc: Liam Girdwood Cc: linux-kernel@vger.kernel.org Cc: alsa-devel@alsa-project.org Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/uapi/sound/asoc.h | 16 ++++++++++++++-- sound/soc/soc-topology.c | 12 +++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h index 69c37ecbff7e..f0e5e21efa54 100644 --- a/include/uapi/sound/asoc.h +++ b/include/uapi/sound/asoc.h @@ -160,6 +160,18 @@ #define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS (1 << 2) #define SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP (1 << 3) +/* DAI topology BCLK parameter + * For the backwards capability, by default codec is bclk master + */ +#define SND_SOC_TPLG_BCLK_CM 0 /* codec is bclk master */ +#define SND_SOC_TPLG_BCLK_CS 1 /* codec is bclk slave */ + +/* DAI topology FSYNC parameter + * For the backwards capability, by default codec is fsync master + */ +#define SND_SOC_TPLG_FSYNC_CM 0 /* codec is fsync master */ +#define SND_SOC_TPLG_FSYNC_CS 1 /* codec is fsync slave */ + /* * Block Header. * This header precedes all object and object arrays below. @@ -315,8 +327,8 @@ struct snd_soc_tplg_hw_config { __u8 clock_gated; /* 1 if clock can be gated to save power */ __u8 invert_bclk; /* 1 for inverted BCLK, 0 for normal */ __u8 invert_fsync; /* 1 for inverted frame clock, 0 for normal */ - __u8 bclk_master; /* 1 for master of BCLK, 0 for slave */ - __u8 fsync_master; /* 1 for master of FSYNC, 0 for slave */ + __u8 bclk_master; /* SND_SOC_TPLG_BCLK_ value */ + __u8 fsync_master; /* SND_SOC_TPLG_FSYNC_ value */ __u8 mclk_direction; /* 0 for input, 1 for output */ __le16 reserved; /* for 32bit alignment */ __le32 mclk_rate; /* MCLK or SYSCLK freqency in Hz */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 30cdad2eab7f..5e74844b0eb7 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -2010,13 +2010,15 @@ static void set_link_hw_format(struct snd_soc_dai_link *link, link->dai_fmt |= SND_SOC_DAIFMT_IB_IF; /* clock masters */ - bclk_master = hw_config->bclk_master; - fsync_master = hw_config->fsync_master; - if (!bclk_master && !fsync_master) + bclk_master = (hw_config->bclk_master == + SND_SOC_TPLG_BCLK_CM); + fsync_master = (hw_config->fsync_master == + SND_SOC_TPLG_FSYNC_CM); + if (bclk_master && fsync_master) link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; - else if (bclk_master && !fsync_master) - link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFM; else if (!bclk_master && fsync_master) + link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFM; + else if (bclk_master && !fsync_master) link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFS; else link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; -- GitLab From a2fdb85a15eb060dbe64201d6932e6c72379bcef Mon Sep 17 00:00:00 2001 From: Kirill Marinushkin Date: Wed, 4 Apr 2018 06:19:38 +0200 Subject: [PATCH 0497/1001] ASoC: topology: Add missing clock gating parameter when parsing hw_configs [ Upstream commit 933e1c4a667103c4d10ebdc9505a0a6abd8c3fbd ] Clock gating parameter is a part of `dai_fmt`. It is supported by `alsa-lib` when creating a topology binary file, but ignored by kernel when loading this topology file. After applying this commit, the clock gating parameter is not ignored any more. This solution is backwards compatible. The existing behaviour is not broken, because by default the parameter value is 0 and is ignored. snd_soc_tplg_hw_config.clock_gated = 0 => no effect snd_soc_tplg_hw_config.clock_gated = 1 => SND_SOC_DAIFMT_GATED snd_soc_tplg_hw_config.clock_gated = 2 => SND_SOC_DAIFMT_CONT For example, the following config, based on alsa-lib/src/conf/topology/broadwell/broadwell.conf, is now supported: ~~~~ SectionHWConfig."CodecHWConfig" { id "1" format "I2S" # physical audio format. pm_gate_clocks "true" # clock can be gated } SectionLink."Codec" { # used for binding to the physical link id "0" hw_configs [ "CodecHWConfig" ] default_hw_conf_id "1" } ~~~~ Signed-off-by: Kirill Marinushkin Reviewed-by: Pierre-Louis Bossart Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: Mark Brown Cc: Pan Xiuli Cc: Liam Girdwood Cc: linux-kernel@vger.kernel.org Cc: alsa-devel@alsa-project.org Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/uapi/sound/asoc.h | 7 ++++++- sound/soc/soc-topology.c | 7 +++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h index f0e5e21efa54..f3c4b46e39d8 100644 --- a/include/uapi/sound/asoc.h +++ b/include/uapi/sound/asoc.h @@ -139,6 +139,11 @@ #define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS (1 << 1) #define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS (1 << 2) +/* DAI clock gating */ +#define SND_SOC_TPLG_DAI_CLK_GATE_UNDEFINED 0 +#define SND_SOC_TPLG_DAI_CLK_GATE_GATED 1 +#define SND_SOC_TPLG_DAI_CLK_GATE_CONT 2 + /* DAI physical PCM data formats. * Add new formats to the end of the list. */ @@ -324,7 +329,7 @@ struct snd_soc_tplg_hw_config { __le32 size; /* in bytes of this structure */ __le32 id; /* unique ID - - used to match */ __le32 fmt; /* SND_SOC_DAI_FORMAT_ format value */ - __u8 clock_gated; /* 1 if clock can be gated to save power */ + __u8 clock_gated; /* SND_SOC_TPLG_DAI_CLK_GATE_ value */ __u8 invert_bclk; /* 1 for inverted BCLK, 0 for normal */ __u8 invert_fsync; /* 1 for inverted frame clock, 0 for normal */ __u8 bclk_master; /* SND_SOC_TPLG_BCLK_ value */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 5e74844b0eb7..c1619860a5de 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1997,6 +1997,13 @@ static void set_link_hw_format(struct snd_soc_dai_link *link, link->dai_fmt = hw_config->fmt & SND_SOC_DAIFMT_FORMAT_MASK; + /* clock gating */ + if (hw_config->clock_gated == SND_SOC_TPLG_DAI_CLK_GATE_GATED) + link->dai_fmt |= SND_SOC_DAIFMT_GATED; + else if (hw_config->clock_gated == + SND_SOC_TPLG_DAI_CLK_GATE_CONT) + link->dai_fmt |= SND_SOC_DAIFMT_CONT; + /* clock signal polarity */ invert_bclk = hw_config->invert_bclk; invert_fsync = hw_config->invert_fsync; -- GitLab From 20f01a1b7b6d00b8b440c57b124a10606e209271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Wed, 28 Mar 2018 15:30:37 -0700 Subject: [PATCH 0498/1001] drm: Add DP PSR2 sink enable bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 4f212e40468650e220c1770876c7f25b8e0c1ff5 ] To comply with eDP1.4a this bit should be set when enabling PSR2. Signed-off-by: José Roberto de Souza Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180328223046.16125-1-jose.souza@intel.com Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/drm/drm_dp_helper.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index b17476a6909c..8fd7cb5297ab 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -453,6 +453,7 @@ # define DP_PSR_FRAME_CAPTURE (1 << 3) # define DP_PSR_SELECTIVE_UPDATE (1 << 4) # define DP_PSR_IRQ_HPD_WITH_CRC_ERRORS (1 << 5) +# define DP_PSR_ENABLE_PSR2 (1 << 6) /* eDP 1.4a */ #define DP_ADAPTER_CTRL 0x1a0 # define DP_ADAPTER_CTRL_FORCE_LOAD_SENSE (1 << 0) -- GitLab From 2aa0e652bce105ca0d5544e887ed7224e0339a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 22 Mar 2018 17:22:51 +0200 Subject: [PATCH 0499/1001] drm/atomic-helper: Drop plane->fb references only for drm_atomic_helper_shutdown() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 5e9cfeba6abb7e1a3f240bd24eb29178f0b83716 ] drm_atomic_helper_shutdown() needs to release the reference held by plane->fb. Since commit 49d70aeaeca8 ("drm/atomic-helper: Fix leak in disable_all") we're doing that by calling drm_atomic_clean_old_fb() in drm_atomic_helper_disable_all(). This also leaves plane->fb == NULL afterwards. However, since drm_atomic_helper_disable_all() is also used by the i915 gpu reset code drm_atomic_helper_commit_duplicated_state() then has to undo the damage and put the correct plane->fb pointers back in (and also adjust the ref counts to match again as well). That approach doesn't work so well for load detection as nothing sets up the plane->old_fb pointers for us. This causes us to leak an extra reference for each plane->fb when drm_atomic_helper_commit_duplicated_state() calls drm_atomic_clean_old_fb() after load detection. To fix this let's call drm_atomic_clean_old_fb() only for drm_atomic_helper_shutdown() as that's the only time we need to actually drop the plane->fb references. In all the other cases (load detection, gpu reset) we want to leave plane->fb alone. v2: Don't inflict the clean_old_fbs bool to drivers (Daniel) v3: Squash in the revert and rewrite the commit msg (Daniel) Cc: martin.peres@free.fr Cc: chris@chris-wilson.co.uk Cc: Dave Airlie Cc: Maarten Lankhorst Cc: Daniel Vetter Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180322152313.6561-3-ville.syrjala@linux.intel.com Reviewed-by: Maarten Lankhorst #pre-squash Reviewed-by: Daniel Vetter Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_atomic_helper.c | 78 ++++++++++++++--------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 0028591f3f95..1f08d597b87a 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2683,31 +2683,9 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set, return 0; } -/** - * drm_atomic_helper_disable_all - disable all currently active outputs - * @dev: DRM device - * @ctx: lock acquisition context - * - * Loops through all connectors, finding those that aren't turned off and then - * turns them off by setting their DPMS mode to OFF and deactivating the CRTC - * that they are connected to. - * - * This is used for example in suspend/resume to disable all currently active - * functions when suspending. If you just want to shut down everything at e.g. - * driver unload, look at drm_atomic_helper_shutdown(). - * - * Note that if callers haven't already acquired all modeset locks this might - * return -EDEADLK, which must be handled by calling drm_modeset_backoff(). - * - * Returns: - * 0 on success or a negative error code on failure. - * - * See also: - * drm_atomic_helper_suspend(), drm_atomic_helper_resume() and - * drm_atomic_helper_shutdown(). - */ -int drm_atomic_helper_disable_all(struct drm_device *dev, - struct drm_modeset_acquire_ctx *ctx) +static int __drm_atomic_helper_disable_all(struct drm_device *dev, + struct drm_modeset_acquire_ctx *ctx, + bool clean_old_fbs) { struct drm_atomic_state *state; struct drm_connector_state *conn_state; @@ -2759,8 +2737,11 @@ int drm_atomic_helper_disable_all(struct drm_device *dev, goto free; drm_atomic_set_fb_for_plane(plane_state, NULL); - plane_mask |= BIT(drm_plane_index(plane)); - plane->old_fb = plane->fb; + + if (clean_old_fbs) { + plane->old_fb = plane->fb; + plane_mask |= BIT(drm_plane_index(plane)); + } } ret = drm_atomic_commit(state); @@ -2771,6 +2752,34 @@ int drm_atomic_helper_disable_all(struct drm_device *dev, return ret; } +/** + * drm_atomic_helper_disable_all - disable all currently active outputs + * @dev: DRM device + * @ctx: lock acquisition context + * + * Loops through all connectors, finding those that aren't turned off and then + * turns them off by setting their DPMS mode to OFF and deactivating the CRTC + * that they are connected to. + * + * This is used for example in suspend/resume to disable all currently active + * functions when suspending. If you just want to shut down everything at e.g. + * driver unload, look at drm_atomic_helper_shutdown(). + * + * Note that if callers haven't already acquired all modeset locks this might + * return -EDEADLK, which must be handled by calling drm_modeset_backoff(). + * + * Returns: + * 0 on success or a negative error code on failure. + * + * See also: + * drm_atomic_helper_suspend(), drm_atomic_helper_resume() and + * drm_atomic_helper_shutdown(). + */ +int drm_atomic_helper_disable_all(struct drm_device *dev, + struct drm_modeset_acquire_ctx *ctx) +{ + return __drm_atomic_helper_disable_all(dev, ctx, false); +} EXPORT_SYMBOL(drm_atomic_helper_disable_all); /** @@ -2793,7 +2802,7 @@ void drm_atomic_helper_shutdown(struct drm_device *dev) while (1) { ret = drm_modeset_lock_all_ctx(dev, &ctx); if (!ret) - ret = drm_atomic_helper_disable_all(dev, &ctx); + ret = __drm_atomic_helper_disable_all(dev, &ctx, true); if (ret != -EDEADLK) break; @@ -2897,16 +2906,11 @@ int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state, struct drm_connector_state *new_conn_state; struct drm_crtc *crtc; struct drm_crtc_state *new_crtc_state; - unsigned plane_mask = 0; - struct drm_device *dev = state->dev; - int ret; state->acquire_ctx = ctx; - for_each_new_plane_in_state(state, plane, new_plane_state, i) { - plane_mask |= BIT(drm_plane_index(plane)); + for_each_new_plane_in_state(state, plane, new_plane_state, i) state->planes[i].old_state = plane->state; - } for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) state->crtcs[i].old_state = crtc->state; @@ -2914,11 +2918,7 @@ int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state, for_each_new_connector_in_state(state, connector, new_conn_state, i) state->connectors[i].old_state = connector->state; - ret = drm_atomic_commit(state); - if (plane_mask) - drm_atomic_clean_old_fb(dev, plane_mask, ret); - - return ret; + return drm_atomic_commit(state); } EXPORT_SYMBOL(drm_atomic_helper_commit_duplicated_state); -- GitLab From 2488689fe4684756269a961117bf348ef458d58c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Mar 2018 16:19:32 +0200 Subject: [PATCH 0500/1001] drm/dp/mst: Fix off-by-one typo when dump payload table [ Upstream commit 7056a2bccc3b5afc51f9b35b30a46f0d9219968d ] It seems there is a classical off-by-one typo from the beginning when commit ad7f8a1f9ced ("drm/helper: add Displayport multi-stream helper (v0.6)") introduced a new helper. Fix a typo by introducing a macro constant. Cc: Dave Airlie Signed-off-by: Andy Shevchenko Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20180319141932.37290-1-andriy.shevchenko@linux.intel.com Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_dp_mst_topology.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 41b492f99955..c022ab6e84bd 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -2862,12 +2862,14 @@ static void drm_dp_mst_dump_mstb(struct seq_file *m, } } +#define DP_PAYLOAD_TABLE_SIZE 64 + static bool dump_dp_payload_table(struct drm_dp_mst_topology_mgr *mgr, char *buf) { int i; - for (i = 0; i < 64; i += 16) { + for (i = 0; i < DP_PAYLOAD_TABLE_SIZE; i += 16) { if (drm_dp_dpcd_read(mgr->aux, DP_PAYLOAD_TABLE_UPDATE_STATUS + i, &buf[i], 16) != 16) @@ -2936,7 +2938,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m, mutex_lock(&mgr->lock); if (mgr->mst_primary) { - u8 buf[64]; + u8 buf[DP_PAYLOAD_TABLE_SIZE]; int ret; ret = drm_dp_dpcd_read(mgr->aux, DP_DPCD_REV, buf, DP_RECEIVER_CAP_SIZE); @@ -2954,8 +2956,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m, seq_printf(m, " revision: hw: %x.%x sw: %x.%x\n", buf[0x9] >> 4, buf[0x9] & 0xf, buf[0xa], buf[0xb]); if (dump_dp_payload_table(mgr, buf)) - seq_printf(m, "payload table: %*ph\n", 63, buf); - + seq_printf(m, "payload table: %*ph\n", DP_PAYLOAD_TABLE_SIZE, buf); } mutex_unlock(&mgr->lock); -- GitLab From 2258351cf0865b6367a5b2b3843ec39a146bb0f8 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Wed, 25 Jul 2018 23:15:07 +0200 Subject: [PATCH 0501/1001] block: bio_iov_iter_get_pages: fix size of last iovec commit b403ea2404889e1227812fa9657667a1deb9c694 upstream. If the last page of the bio is not "full", the length of the last vector slot needs to be corrected. This slot has the index (bio->bi_vcnt - 1), but only in bio->bi_io_vec. In the "bv" helper array, which is shifted by the value of bio->bi_vcnt at function invocation, the correct index is (nr_pages - 1). v2: improved readability following suggestions from Ming Lei. v3: followed a formatting suggestion from Christoph Hellwig. Fixes: 2cefe4dbaadf ("block: add bio_iov_iter_get_pages()") Reviewed-by: Hannes Reinecke Reviewed-by: Ming Lei Reviewed-by: Jan Kara Reviewed-by: Christoph Hellwig Signed-off-by: Martin Wilck Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/bio.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/block/bio.c b/block/bio.c index 90f19d7df66c..e5df69918d1a 100644 --- a/block/bio.c +++ b/block/bio.c @@ -881,16 +881,16 @@ EXPORT_SYMBOL(bio_add_page); */ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter) { - unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt; + unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt, idx; struct bio_vec *bv = bio->bi_io_vec + bio->bi_vcnt; struct page **pages = (struct page **)bv; - size_t offset, diff; + size_t offset; ssize_t size; size = iov_iter_get_pages(iter, pages, LONG_MAX, nr_pages, &offset); if (unlikely(size <= 0)) return size ? size : -EFAULT; - nr_pages = (size + offset + PAGE_SIZE - 1) / PAGE_SIZE; + idx = nr_pages = (size + offset + PAGE_SIZE - 1) / PAGE_SIZE; /* * Deep magic below: We need to walk the pinned pages backwards @@ -903,17 +903,15 @@ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter) bio->bi_iter.bi_size += size; bio->bi_vcnt += nr_pages; - diff = (nr_pages * PAGE_SIZE - offset) - size; - while (nr_pages--) { - bv[nr_pages].bv_page = pages[nr_pages]; - bv[nr_pages].bv_len = PAGE_SIZE; - bv[nr_pages].bv_offset = 0; + while (idx--) { + bv[idx].bv_page = pages[idx]; + bv[idx].bv_len = PAGE_SIZE; + bv[idx].bv_offset = 0; } bv[0].bv_offset += offset; bv[0].bv_len -= offset; - if (diff) - bv[bio->bi_vcnt - 1].bv_len -= diff; + bv[nr_pages - 1].bv_len -= nr_pages * PAGE_SIZE - offset - size; iov_iter_advance(iter, size); return 0; -- GitLab From cc5d7097ba8f46a9b5382edba733e5a8705145ba Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Wed, 25 Jul 2018 23:15:08 +0200 Subject: [PATCH 0502/1001] blkdev: __blkdev_direct_IO_simple: fix leak in error case commit 9362dd1109f87a9d0a798fbc890cb339c171ed35 upstream. Fixes: 72ecad22d9f1 ("block: support a full bio worth of IO for simplified bdev direct-io") Reviewed-by: Ming Lei Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Signed-off-by: Martin Wilck Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- fs/block_dev.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/block_dev.c b/fs/block_dev.c index 789f55e851ae..3323eec5c164 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -231,7 +231,7 @@ __blkdev_direct_IO_simple(struct kiocb *iocb, struct iov_iter *iter, ret = bio_iov_iter_get_pages(&bio, iter); if (unlikely(ret)) - return ret; + goto out; ret = bio.bi_iter.bi_size; if (iov_iter_rw(iter) == READ) { @@ -260,12 +260,13 @@ __blkdev_direct_IO_simple(struct kiocb *iocb, struct iov_iter *iter, put_page(bvec->bv_page); } - if (vecs != inline_vecs) - kfree(vecs); - if (unlikely(bio.bi_status)) ret = blk_status_to_errno(bio.bi_status); +out: + if (vecs != inline_vecs) + kfree(vecs); + bio_uninit(&bio); return ret; -- GitLab From b8088c524ae21dc97c86e09f0e41bb419804b5ad Mon Sep 17 00:00:00 2001 From: Greg Edwards Date: Thu, 26 Jul 2018 14:39:37 -0400 Subject: [PATCH 0503/1001] block: reset bi_iter.bi_done after splitting bio commit 5151842b9d8732d4cbfa8400b40bff894f501b2f upstream. After the bio has been updated to represent the remaining sectors, reset bi_done so bio_rewind_iter() does not rewind further than it should. This resolves a bio_integrity_process() failure on reads where the original request was split. Fixes: 63573e359d05 ("bio-integrity: Restore original iterator on verify stage") Signed-off-by: Greg Edwards Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/bio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/block/bio.c b/block/bio.c index e5df69918d1a..194d28cdc642 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1889,6 +1889,7 @@ struct bio *bio_split(struct bio *bio, int sectors, bio_integrity_trim(split); bio_advance(bio, split->bi_iter.bi_size); + bio->bi_iter.bi_done = 0; if (bio_flagged(bio, BIO_TRACE_COMPLETION)) bio_set_flag(split, BIO_TRACE_COMPLETION); -- GitLab From af41fd042fc10e65e93ed009c4933fd65c67ef2c Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 14 Jul 2018 23:55:57 -0400 Subject: [PATCH 0504/1001] random: mix rdrand with entropy sent in from userspace commit 81e69df38e2911b642ec121dec319fad2a4782f3 upstream. Fedora has integrated the jitter entropy daemon to work around slow boot problems, especially on VM's that don't support virtio-rng: https://bugzilla.redhat.com/show_bug.cgi?id=1572944 It's understandable why they did this, but the Jitter entropy daemon works fundamentally on the principle: "the CPU microarchitecture is **so** complicated and we can't figure it out, so it *must* be random". Yes, it uses statistical tests to "prove" it is secure, but AES_ENCRYPT(NSA_KEY, COUNTER++) will also pass statistical tests with flying colors. So if RDRAND is available, mix it into entropy submitted from userspace. It can't hurt, and if you believe the NSA has backdoored RDRAND, then they probably have enough details about the Intel microarchitecture that they can reverse engineer how the Jitter entropy daemon affects the microarchitecture, and attack its output stream. And if RDRAND is in fact an honest DRNG, it will immeasurably improve on what the Jitter entropy daemon might produce. This also provides some protection against someone who is able to read or set the entropy seed file. Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Cc: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index ddc493d976fd..ea4dbfa30657 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1897,14 +1897,22 @@ static int write_pool(struct entropy_store *r, const char __user *buffer, size_t count) { size_t bytes; - __u32 buf[16]; + __u32 t, buf[16]; const char __user *p = buffer; while (count > 0) { + int b, i = 0; + bytes = min(count, sizeof(buf)); if (copy_from_user(&buf, p, bytes)) return -EFAULT; + for (b = bytes ; b > 0 ; b -= sizeof(__u32), i++) { + if (!arch_get_random_int(&t)) + break; + buf[i] ^= t; + } + count -= bytes; p += bytes; -- GitLab From 961f9feb4332f448e5d2fa4851ba86598fc112de Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 29 Jul 2018 12:44:46 -0700 Subject: [PATCH 0505/1001] squashfs: be more careful about metadata corruption commit 01cfb7937a9af2abb1136c7e89fbf3fd92952956 upstream. Anatoly Trosinenko reports that a corrupted squashfs image can cause a kernel oops. It turns out that squashfs can end up being confused about negative fragment lengths. The regular squashfs_read_data() does check for negative lengths, but squashfs_read_metadata() did not, and the fragment size code just blindly trusted the on-disk value. Fix both the fragment parsing and the metadata reading code. Reported-by: Anatoly Trosinenko Cc: Al Viro Cc: Phillip Lougher Cc: stable@kernel.org Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/squashfs/cache.c | 3 +++ fs/squashfs/file.c | 8 ++++++-- fs/squashfs/fragment.c | 4 +--- fs/squashfs/squashfs_fs.h | 6 ++++++ 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c index 23813c078cc9..0839efa720b3 100644 --- a/fs/squashfs/cache.c +++ b/fs/squashfs/cache.c @@ -350,6 +350,9 @@ int squashfs_read_metadata(struct super_block *sb, void *buffer, TRACE("Entered squashfs_read_metadata [%llx:%x]\n", *block, *offset); + if (unlikely(length < 0)) + return -EIO; + while (length) { entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0); if (entry->error) { diff --git a/fs/squashfs/file.c b/fs/squashfs/file.c index 13d80947bf9e..fcff2e0487fe 100644 --- a/fs/squashfs/file.c +++ b/fs/squashfs/file.c @@ -194,7 +194,11 @@ static long long read_indexes(struct super_block *sb, int n, } for (i = 0; i < blocks; i++) { - int size = le32_to_cpu(blist[i]); + int size = squashfs_block_size(blist[i]); + if (size < 0) { + err = size; + goto failure; + } block += SQUASHFS_COMPRESSED_SIZE_BLOCK(size); } n -= blocks; @@ -367,7 +371,7 @@ static int read_blocklist(struct inode *inode, int index, u64 *block) sizeof(size)); if (res < 0) return res; - return le32_to_cpu(size); + return squashfs_block_size(size); } /* Copy data into page cache */ diff --git a/fs/squashfs/fragment.c b/fs/squashfs/fragment.c index 0ed6edbc5c71..86ad9a4b8c36 100644 --- a/fs/squashfs/fragment.c +++ b/fs/squashfs/fragment.c @@ -61,9 +61,7 @@ int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment, return size; *fragment_block = le64_to_cpu(fragment_entry.start_block); - size = le32_to_cpu(fragment_entry.size); - - return size; + return squashfs_block_size(fragment_entry.size); } diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h index 24d12fd14177..4e6853f084d0 100644 --- a/fs/squashfs/squashfs_fs.h +++ b/fs/squashfs/squashfs_fs.h @@ -129,6 +129,12 @@ #define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) +static inline int squashfs_block_size(__le32 raw) +{ + u32 size = le32_to_cpu(raw); + return (size >> 25) ? -EIO : size; +} + /* * Inode number ops. Inodes consist of a compressed block number, and an * uncompressed offset within that block -- GitLab From cdcbe750acd6cd1e083189c2a50810eeb59f057a Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Tue, 10 Jul 2018 01:07:43 -0400 Subject: [PATCH 0506/1001] ext4: fix inline data updates with checksums enabled commit 362eca70b53389bddf3143fe20f53dcce2cfdf61 upstream. The inline data code was updating the raw inode directly; this is problematic since if metadata checksums are enabled, ext4_mark_inode_dirty() must be called to update the inode's checksum. In addition, the jbd2 layer requires that get_write_access() be called before the metadata buffer is modified. Fix both of these problems. https://bugzilla.kernel.org/show_bug.cgi?id=200443 Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inline.c | 19 +++++++++++-------- fs/ext4/inode.c | 16 +++++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 7d498f4a3f90..b549cfd2d7d3 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -688,6 +688,10 @@ int ext4_try_to_write_inline_data(struct address_space *mapping, goto convert; } + ret = ext4_journal_get_write_access(handle, iloc.bh); + if (ret) + goto out; + flags |= AOP_FLAG_NOFS; page = grab_cache_page_write_begin(mapping, 0, flags); @@ -716,7 +720,7 @@ int ext4_try_to_write_inline_data(struct address_space *mapping, out_up_read: up_read(&EXT4_I(inode)->xattr_sem); out: - if (handle) + if (handle && (ret != 1)) ext4_journal_stop(handle); brelse(iloc.bh); return ret; @@ -758,6 +762,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, ext4_write_unlock_xattr(inode, &no_expand); brelse(iloc.bh); + mark_inode_dirty(inode); out: return copied; } @@ -904,7 +909,6 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping, goto out; } - page = grab_cache_page_write_begin(mapping, 0, flags); if (!page) { ret = -ENOMEM; @@ -922,6 +926,9 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping, if (ret < 0) goto out_release_page; } + ret = ext4_journal_get_write_access(handle, iloc.bh); + if (ret) + goto out_release_page; up_read(&EXT4_I(inode)->xattr_sem); *pagep = page; @@ -942,7 +949,6 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, unsigned copied, struct page *page) { - int i_size_changed = 0; int ret; ret = ext4_write_inline_data_end(inode, pos, len, copied, page); @@ -960,10 +966,8 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, * But it's important to update i_size while still holding page lock: * page writeout could otherwise come in and zero beyond i_size. */ - if (pos+copied > inode->i_size) { + if (pos+copied > inode->i_size) i_size_write(inode, pos+copied); - i_size_changed = 1; - } unlock_page(page); put_page(page); @@ -973,8 +977,7 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, * ordering of page lock and transaction start for journaling * filesystems. */ - if (i_size_changed) - mark_inode_dirty(inode); + mark_inode_dirty(inode); return copied; } diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index c2efe4d2ad87..f9baa59de0e2 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1388,9 +1388,10 @@ static int ext4_write_end(struct file *file, loff_t old_size = inode->i_size; int ret = 0, ret2; int i_size_changed = 0; + int inline_data = ext4_has_inline_data(inode); trace_ext4_write_end(inode, pos, len, copied); - if (ext4_has_inline_data(inode)) { + if (inline_data) { ret = ext4_write_inline_data_end(inode, pos, len, copied, page); if (ret < 0) { @@ -1418,7 +1419,7 @@ static int ext4_write_end(struct file *file, * ordering of page lock and transaction start for journaling * filesystems. */ - if (i_size_changed) + if (i_size_changed || inline_data) ext4_mark_inode_dirty(handle, inode); if (pos + len > inode->i_size && ext4_can_truncate(inode)) @@ -1492,6 +1493,7 @@ static int ext4_journalled_write_end(struct file *file, int partial = 0; unsigned from, to; int size_changed = 0; + int inline_data = ext4_has_inline_data(inode); trace_ext4_journalled_write_end(inode, pos, len, copied); from = pos & (PAGE_SIZE - 1); @@ -1499,7 +1501,7 @@ static int ext4_journalled_write_end(struct file *file, BUG_ON(!ext4_handle_valid(handle)); - if (ext4_has_inline_data(inode)) { + if (inline_data) { ret = ext4_write_inline_data_end(inode, pos, len, copied, page); if (ret < 0) { @@ -1530,7 +1532,7 @@ static int ext4_journalled_write_end(struct file *file, if (old_size < pos) pagecache_isize_extended(inode, old_size, pos); - if (size_changed) { + if (size_changed || inline_data) { ret2 = ext4_mark_inode_dirty(handle, inode); if (!ret) ret = ret2; @@ -2027,11 +2029,7 @@ static int __ext4_journalled_writepage(struct page *page, } if (inline_data) { - BUFFER_TRACE(inode_bh, "get write access"); - ret = ext4_journal_get_write_access(handle, inode_bh); - - err = ext4_handle_dirty_metadata(handle, inode, inode_bh); - + ret = ext4_mark_inode_dirty(handle, inode); } else { ret = ext4_walk_page_buffers(handle, page_bufs, 0, len, NULL, do_journal_get_write_access); -- GitLab From dc1b4b710fbef5f8f5a41efe35368e9dd07e71cb Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 12 Jul 2018 19:08:05 -0400 Subject: [PATCH 0507/1001] ext4: check for allocation block validity with block group locked commit 8d5a803c6a6ce4ec258e31f76059ea5153ba46ef upstream. With commit 044e6e3d74a3: "ext4: don't update checksum of new initialized bitmaps" the buffer valid bit will get set without actually setting up the checksum for the allocation bitmap, since the checksum will get calculated once we actually allocate an inode or block. If we are doing this, then we need to (re-)check the verified bit after we take the block group lock. Otherwise, we could race with another process reading and verifying the bitmap, which would then complain about the checksum being invalid. https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1780137 Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/balloc.c | 3 +++ fs/ext4/ialloc.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 9c9eafd6bd76..70266a3355dc 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -379,6 +379,8 @@ static int ext4_validate_block_bitmap(struct super_block *sb, return -EFSCORRUPTED; ext4_lock_group(sb, block_group); + if (buffer_verified(bh)) + goto verified; if (unlikely(!ext4_block_bitmap_csum_verify(sb, block_group, desc, bh))) { ext4_unlock_group(sb, block_group); @@ -401,6 +403,7 @@ static int ext4_validate_block_bitmap(struct super_block *sb, return -EFSCORRUPTED; } set_buffer_verified(bh); +verified: ext4_unlock_group(sb, block_group); return 0; } diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 95341bc2b3b7..e38340b218a0 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -91,6 +91,8 @@ static int ext4_validate_inode_bitmap(struct super_block *sb, return -EFSCORRUPTED; ext4_lock_group(sb, block_group); + if (buffer_verified(bh)) + goto verified; blk = ext4_inode_bitmap(sb, desc); if (!ext4_inode_bitmap_csum_verify(sb, block_group, desc, bh, EXT4_INODES_PER_GROUP(sb) / 8)) { @@ -108,6 +110,7 @@ static int ext4_validate_inode_bitmap(struct super_block *sb, return -EFSBADCRC; } set_buffer_verified(bh); +verified: ext4_unlock_group(sb, block_group); return 0; } -- GitLab From f547aa20b4f61662ad3e1a2040bb3cc5778f19b0 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 28 Jul 2018 08:12:04 -0400 Subject: [PATCH 0508/1001] ext4: fix check to prevent initializing reserved inodes commit 5012284700775a4e6e3fbe7eac4c543c4874b559 upstream. Commit 8844618d8aa7: "ext4: only look at the bg_flags field if it is valid" will complain if block group zero does not have the EXT4_BG_INODE_ZEROED flag set. Unfortunately, this is not correct, since a freshly created file system has this flag cleared. It gets almost immediately after the file system is mounted read-write --- but the following somewhat unlikely sequence will end up triggering a false positive report of a corrupted file system: mkfs.ext4 /dev/vdc mount -o ro /dev/vdc /vdc mount -o remount,rw /dev/vdc Instead, when initializing the inode table for block group zero, test to make sure that itable_unused count is not too large, since that is the case that will result in some or all of the reserved inodes getting cleared. This fixes the failures reported by Eric Whiteney when running generic/230 and generic/231 in the the nojournal test case. Fixes: 8844618d8aa7 ("ext4: only look at the bg_flags field if it is valid") Reported-by: Eric Whitney Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ialloc.c | 5 ++++- fs/ext4/super.c | 8 +------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index e38340b218a0..2f46564d3fca 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -1397,7 +1397,10 @@ int ext4_init_inode_table(struct super_block *sb, ext4_group_t group, ext4_itable_unused_count(sb, gdp)), sbi->s_inodes_per_block); - if ((used_blks < 0) || (used_blks > sbi->s_itb_per_group)) { + if ((used_blks < 0) || (used_blks > sbi->s_itb_per_group) || + ((group == 0) && ((EXT4_INODES_PER_GROUP(sb) - + ext4_itable_unused_count(sb, gdp)) < + EXT4_FIRST_INO(sb)))) { ext4_error(sb, "Something is wrong with group %u: " "used itable blocks: %d; " "itable unused count: %u", diff --git a/fs/ext4/super.c b/fs/ext4/super.c index fc32a67a7a19..6b0c1ea95196 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3103,14 +3103,8 @@ static ext4_group_t ext4_has_uninit_itable(struct super_block *sb) if (!gdp) continue; - if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED)) - continue; - if (group != 0) + if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))) break; - ext4_error(sb, "Inode table for bg 0 marked as " - "needing zeroing"); - if (sb_rdonly(sb)) - return ngroups; } return group; -- GitLab From 011626d61a43224dcebefca44279f981d504e8d2 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 17 Jan 2018 16:48:39 +0100 Subject: [PATCH 0509/1001] PCI: pciehp: Assume NoCompl+ for Thunderbolt ports commit 493fb50e958c1c6deef7feff0b8c3855def78d75 upstream. Certain Thunderbolt 1 controllers claim to support Command Completed events (value of 0b in the No Command Completed Support field of the Slot Capabilities register) but in reality they neither set the Command Completed bit in the Slot Status register nor signal a Command Completed interrupt: 8086:1513 CV82524 [Light Ridge 4C 2010] 8086:151a DSL2310 [Eagle Ridge 2C 2011] 8086:151b CVL2510 [Light Peak 2C 2010] 8086:1547 DSL3510 [Cactus Ridge 4C 2012] 8086:1548 DSL3310 [Cactus Ridge 2C 2012] 8086:1549 DSL2210 [Port Ridge 1C 2011] All known newer chips (Redwood Ridge and onwards) set No Command Completed Support, indicating that they do not support Command Completed events. The user-visible impact is that after unplugging such a device, 2 seconds elapse until pciehp is unbound. That's because on ->remove, pcie_write_cmd() is called via pcie_disable_notification() and every call to pcie_write_cmd() takes 2 seconds (1 second for each invocation of pcie_wait_cmd()): [ 337.942727] pciehp 0000:0a:00.0:pcie204: Timeout on hotplug command 0x1038 (issued 21176 msec ago) [ 340.014735] pciehp 0000:0a:00.0:pcie204: Timeout on hotplug command 0x0000 (issued 2072 msec ago) That by itself has always been unpleasant, but the situation has become worse with commit cc27b735ad3a ("PCI/portdrv: Turn off PCIe services during shutdown"): Now pciehp is unbound on ->shutdown. Because Thunderbolt controllers typically have 4 hotplug ports, every reboot and shutdown is now delayed by 8 seconds, plus another 2 seconds for every attached Thunderbolt 1 device. Thunderbolt hotplug slots are not physical slots that one inserts cards into, but rather logical hotplug slots implemented in silicon. Devices appear beyond those logical slots once a PCI tunnel is established on top of the Thunderbolt Converged I/O switch. One would expect commands written to the Slot Control register to be executed immediately by the silicon, so for simplicity we always assume NoCompl+ for Thunderbolt ports. Fixes: cc27b735ad3a ("PCI/portdrv: Turn off PCIe services during shutdown") Tested-by: Mika Westerberg Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Mika Westerberg Cc: stable@vger.kernel.org # v4.12+ Cc: Sinan Kaya Cc: Yehezkel Bernat Cc: Michael Jamet Cc: Andreas Noever Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_hpc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 05832b597e53..46c2ee2caf28 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -863,6 +863,13 @@ struct controller *pcie_init(struct pcie_device *dev) if (pdev->hotplug_user_indicators) slot_cap &= ~(PCI_EXP_SLTCAP_AIP | PCI_EXP_SLTCAP_PIP); + /* + * We assume no Thunderbolt controllers support Command Complete events, + * but some controllers falsely claim they do. + */ + if (pdev->is_thunderbolt) + slot_cap |= PCI_EXP_SLTCAP_NCCS; + ctrl->slot_cap = slot_cap; mutex_init(&ctrl->ctrl_lock); init_waitqueue_head(&ctrl->queue); -- GitLab From 21b5b5e80bcf3f873bf89e9d957a129ea1fdcf36 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Tue, 21 Nov 2017 15:49:31 +0000 Subject: [PATCH 0510/1001] PCI: xgene: Remove leftover pci_scan_child_bus() call commit 94b9d290b753cbbc87971ee134511245f5872a83 upstream. The changes in commit 9af275be15f7 ("PCI: xgene: Convert PCI scan API to pci_scan_root_bus_bridge()") converted the xgene PCI host driver to the new pci_scan_root_bus_bridge() bus scanning API but erroneously left the existing pci_scan_child_bus() call in place which resulted in duplicate PCI bus enumerations. Remove the leftover pci_scan_child_bus() call to properly complete the API conversion. Fixes: 9af275be15f7 ("PCI: xgene: Convert PCI scan API to pci_scan_root_bus_bridge()") Tested-by: Khuong Dinh Signed-off-by: Lorenzo Pieralisi Cc: # 4.13+ Cc: Bjorn Helgaas Cc: Tanmay Inamdar Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/pci/host/pci-xgene.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c index 087645116ecb..c78fd9c2cf8c 100644 --- a/drivers/pci/host/pci-xgene.c +++ b/drivers/pci/host/pci-xgene.c @@ -686,7 +686,6 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev) bus = bridge->bus; - pci_scan_child_bus(bus); pci_assign_unassigned_bus_resources(bus); list_for_each_entry(child, &bus->children, node) pcie_bus_configure_settings(child); -- GitLab From 6aaaca7b81e4929a43ac8c0a2a734b762467c60f Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Wed, 29 Nov 2017 10:01:32 +0800 Subject: [PATCH 0511/1001] ovl: Sync upper dirty data when syncing overlayfs commit e8d4bfe3a71537284a90561f77c85dea6c154369 upstream. When executing filesystem sync or umount on overlayfs, dirty data does not get synced as expected on upper filesystem. This patch fixes sync filesystem method to keep data consistency for overlayfs. Signed-off-by: Chengguang Xu Fixes: e593b2bf513d ("ovl: properly implement sync_filesystem()") Cc: #4.11 Signed-off-by: Miklos Szeredi Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- fs/overlayfs/super.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index b8f8d666e8d4..ba20393d60ef 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -232,6 +232,7 @@ static void ovl_put_super(struct super_block *sb) kfree(ufs); } +/* Sync real dirty inodes in upper filesystem (if it exists) */ static int ovl_sync_fs(struct super_block *sb, int wait) { struct ovl_fs *ufs = sb->s_fs_info; @@ -240,14 +241,24 @@ static int ovl_sync_fs(struct super_block *sb, int wait) if (!ufs->upper_mnt) return 0; - upper_sb = ufs->upper_mnt->mnt_sb; - if (!upper_sb->s_op->sync_fs) + + /* + * If this is a sync(2) call or an emergency sync, all the super blocks + * will be iterated, including upper_sb, so no need to do anything. + * + * If this is a syncfs(2) call, then we do need to call + * sync_filesystem() on upper_sb, but enough if we do it when being + * called with wait == 1. + */ + if (!wait) return 0; - /* real inodes have already been synced by sync_filesystem(ovl_sb) */ + upper_sb = ufs->upper_mnt->mnt_sb; + down_read(&upper_sb->s_umount); - ret = upper_sb->s_op->sync_fs(upper_sb, wait); + ret = sync_filesystem(upper_sb); up_read(&upper_sb->s_umount); + return ret; } -- GitLab From b8e9dd160ca358f1f2aadccfb64eb1a85d6a77da Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 10 Apr 2018 14:38:50 +0900 Subject: [PATCH 0512/1001] usb: gadget: udc: renesas_usb3: should remove debugfs commit 1990cf7c21ea185cec98c6d45a82c04481261e35 upstream. This patch fixes an issue that this driver doesn't remove its debugfs. Fixes: 43ba968b00ea ("usb: gadget: udc: renesas_usb3: add debugfs to set the b-device mode") Cc: # v4.14+ Signed-off-by: Yoshihiro Shimoda Reviewed-by: Simon Horman Signed-off-by: Felipe Balbi Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/renesas_usb3.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 4cfa72cb0a91..c12a1a6554ba 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -334,6 +334,7 @@ struct renesas_usb3 { struct usb_gadget_driver *driver; struct extcon_dev *extcon; struct work_struct extcon_work; + struct dentry *dentry; struct renesas_usb3_ep *usb3_ep; int num_usb3_eps; @@ -2397,8 +2398,12 @@ static void renesas_usb3_debugfs_init(struct renesas_usb3 *usb3, file = debugfs_create_file("b_device", 0644, root, usb3, &renesas_usb3_b_device_fops); - if (!file) + if (!file) { dev_info(dev, "%s: Can't create debugfs mode\n", __func__); + debugfs_remove_recursive(root); + } else { + usb3->dentry = root; + } } /*------- platform_driver ------------------------------------------------*/ @@ -2406,6 +2411,7 @@ static int renesas_usb3_remove(struct platform_device *pdev) { struct renesas_usb3 *usb3 = platform_get_drvdata(pdev); + debugfs_remove_recursive(usb3->dentry); device_remove_file(&pdev->dev, &dev_attr_role); usb_del_gadget_udc(&usb3->gadget); -- GitLab From a61b3378b8473694ebd87e59c8a5dd35839c50fc Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Sun, 24 Jun 2018 11:23:42 +0300 Subject: [PATCH 0513/1001] RDMA/uverbs: Protect from attempts to create flows on unsupported QP commit 940efcc8889f0d15567eb07fc9fd69b06e366aa5 upstream. Flows can be created on UD and RAW_PACKET QP types. Attempts to provide other QP types as an input causes to various unpredictable failures. The reason is that in order to support all various types (e.g. XRC), we are supposed to use real_qp handle and not qp handle and expect to driver/FW to fail such (XRC) flows. The simpler and safer variant is to ban all QP types except UD and RAW_PACKET, instead of relying on driver/FW. Cc: # 3.11 Fixes: 436f2ad05a0b ("IB/core: Export ib_create/destroy_flow through uverbs") Cc: syzkaller Reported-by: Noa Osherovich Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/uverbs_cmd.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 186dce6bba8f..b8229d7b0ff5 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -3376,6 +3376,11 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file, goto err_uobj; } + if (qp->qp_type != IB_QPT_UD && qp->qp_type != IB_QPT_RAW_PACKET) { + err = -EINVAL; + goto err_put; + } + flow_attr = kzalloc(sizeof(*flow_attr) + cmd.flow_attr.num_of_specs * sizeof(union ib_flow_spec), GFP_KERNEL); if (!flow_attr) { -- GitLab From 62310e69f1ae5923646adedfd916fa2b090bada7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vok=C3=A1=C4=8D?= Date: Wed, 23 May 2018 08:20:21 +0200 Subject: [PATCH 0514/1001] net: dsa: qca8k: Force CPU port to its highest bandwidth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 79a4ed4f0f93fc65e48a0fc5247ffa5645f7b0cc upstream. By default autonegotiation is enabled to configure MAC on all ports. For the CPU port autonegotiation can not be used so we need to set some sensible defaults manually. This patch forces the default setting of the CPU port to 1000Mbps/full duplex which is the chip maximum capability. Also correct size of the bit field used to configure link speed. Fixes: 6b93fb46480a ("net-next: dsa: add new driver for qca8xxx family") Signed-off-by: Michal Vokáč Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/dsa/qca8k.c | 6 +++++- drivers/net/dsa/qca8k.h | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index 2a2bbf5e9c8e..d2bcf2b3c19c 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -490,6 +490,7 @@ qca8k_setup(struct dsa_switch *ds) { struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; int ret, i, phy_mode = -1; + u32 mask; /* Make sure that port 0 is the cpu port */ if (!dsa_is_cpu_port(ds, 0)) { @@ -515,7 +516,10 @@ qca8k_setup(struct dsa_switch *ds) if (ret < 0) return ret; - /* Enable CPU Port */ + /* Enable CPU Port, force it to maximum bandwidth and full-duplex */ + mask = QCA8K_PORT_STATUS_SPEED_1000 | QCA8K_PORT_STATUS_TXFLOW | + QCA8K_PORT_STATUS_RXFLOW | QCA8K_PORT_STATUS_DUPLEX; + qca8k_write(priv, QCA8K_REG_PORT_STATUS(QCA8K_CPU_PORT), mask); qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0, QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); qca8k_port_set_status(priv, QCA8K_CPU_PORT, 1); diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h index 1cf8a920d4ff..5bda16555478 100644 --- a/drivers/net/dsa/qca8k.h +++ b/drivers/net/dsa/qca8k.h @@ -51,8 +51,10 @@ #define QCA8K_GOL_MAC_ADDR0 0x60 #define QCA8K_GOL_MAC_ADDR1 0x64 #define QCA8K_REG_PORT_STATUS(_i) (0x07c + (_i) * 4) -#define QCA8K_PORT_STATUS_SPEED GENMASK(2, 0) -#define QCA8K_PORT_STATUS_SPEED_S 0 +#define QCA8K_PORT_STATUS_SPEED GENMASK(1, 0) +#define QCA8K_PORT_STATUS_SPEED_10 0 +#define QCA8K_PORT_STATUS_SPEED_100 0x1 +#define QCA8K_PORT_STATUS_SPEED_1000 0x2 #define QCA8K_PORT_STATUS_TXMAC BIT(2) #define QCA8K_PORT_STATUS_RXMAC BIT(3) #define QCA8K_PORT_STATUS_TXFLOW BIT(4) -- GitLab From 1fbc97b32b7e3756e2b84f652108281791e9d377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vok=C3=A1=C4=8D?= Date: Wed, 23 May 2018 08:20:20 +0200 Subject: [PATCH 0515/1001] net: dsa: qca8k: Enable RXMAC when bringing up a port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit eee1fe64765c562d8bcaf95e5631a8ea2f760f34 upstream. When a port is brought up/down do not enable/disable only the TXMAC but the RXMAC as well. This is essential for the CPU port to work. Fixes: 6b93fb46480a ("net-next: dsa: add new driver for qca8xxx family") Signed-off-by: Michal Vokáč Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/dsa/qca8k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index d2bcf2b3c19c..533aa5325819 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -473,7 +473,7 @@ qca8k_set_pad_ctrl(struct qca8k_priv *priv, int port, int mode) static void qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) { - u32 mask = QCA8K_PORT_STATUS_TXMAC; + u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; /* Port 0 and 6 have no internal PHY */ if ((port > 0) && (port < 6)) -- GitLab From 2eda475b0849ba898abf99a61e8926b1335f6988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vok=C3=A1=C4=8D?= Date: Wed, 23 May 2018 08:20:18 +0200 Subject: [PATCH 0516/1001] net: dsa: qca8k: Add QCA8334 binding documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 218bbea11a777c156eb7bcbdc72867b32ae10985 upstream. Add support for the four-port variant of the Qualcomm QCA833x switch. The CPU port default link settings can be reconfigured using a fixed-link sub-node. Signed-off-by: Michal Vokáč Reviewed-by: Rob Herring Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/net/dsa/qca8k.txt | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/dsa/qca8k.txt b/Documentation/devicetree/bindings/net/dsa/qca8k.txt index 9c67ee4890d7..bbcb255c3150 100644 --- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt +++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt @@ -2,7 +2,10 @@ Required properties: -- compatible: should be "qca,qca8337" +- compatible: should be one of: + "qca,qca8334" + "qca,qca8337" + - #size-cells: must be 0 - #address-cells: must be 1 @@ -14,6 +17,20 @@ port and PHY id, each subnode describing a port needs to have a valid phandle referencing the internal PHY connected to it. The CPU port of this switch is always port 0. +A CPU port node has the following optional node: + +- fixed-link : Fixed-link subnode describing a link to a non-MDIO + managed entity. See + Documentation/devicetree/bindings/net/fixed-link.txt + for details. + +For QCA8K the 'fixed-link' sub-node supports only the following properties: + +- 'speed' (integer, mandatory), to indicate the link speed. Accepted + values are 10, 100 and 1000 +- 'full-duplex' (boolean, optional), to indicate that full duplex is + used. When absent, half duplex is assumed. + Example: @@ -53,6 +70,10 @@ Example: label = "cpu"; ethernet = <&gmac1>; phy-mode = "rgmii"; + fixed-link { + speed = 1000; + full-duplex; + }; }; port@1 { -- GitLab From 20556dc7f239f8ad724f8ff5fec289961439cd6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vok=C3=A1=C4=8D?= Date: Wed, 23 May 2018 08:20:22 +0200 Subject: [PATCH 0517/1001] net: dsa: qca8k: Allow overwriting CPU port setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 9bb2289f90e671bdb78e306974187424ac19ff8e upstream. Implement adjust_link function that allows to overwrite default CPU port setting using fixed-link device tree subnode. Signed-off-by: Michal Vokáč Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/dsa/qca8k.c | 43 +++++++++++++++++++++++++++++++++++++++++ drivers/net/dsa/qca8k.h | 1 + 2 files changed, 44 insertions(+) diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index 533aa5325819..9645c8f05c7f 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -588,6 +588,47 @@ qca8k_setup(struct dsa_switch *ds) return 0; } +static void +qca8k_adjust_link(struct dsa_switch *ds, int port, struct phy_device *phy) +{ + struct qca8k_priv *priv = ds->priv; + u32 reg; + + /* Force fixed-link setting for CPU port, skip others. */ + if (!phy_is_pseudo_fixed_link(phy)) + return; + + /* Set port speed */ + switch (phy->speed) { + case 10: + reg = QCA8K_PORT_STATUS_SPEED_10; + break; + case 100: + reg = QCA8K_PORT_STATUS_SPEED_100; + break; + case 1000: + reg = QCA8K_PORT_STATUS_SPEED_1000; + break; + default: + dev_dbg(priv->dev, "port%d link speed %dMbps not supported.\n", + port, phy->speed); + return; + } + + /* Set duplex mode */ + if (phy->duplex == DUPLEX_FULL) + reg |= QCA8K_PORT_STATUS_DUPLEX; + + /* Force flow control */ + if (dsa_is_cpu_port(ds, port)) + reg |= QCA8K_PORT_STATUS_RXFLOW | QCA8K_PORT_STATUS_TXFLOW; + + /* Force link down before changing MAC options */ + qca8k_port_set_status(priv, port, 0); + qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg); + qca8k_port_set_status(priv, port, 1); +} + static int qca8k_phy_read(struct dsa_switch *ds, int phy, int regnum) { @@ -836,6 +877,7 @@ qca8k_get_tag_protocol(struct dsa_switch *ds) static const struct dsa_switch_ops qca8k_switch_ops = { .get_tag_protocol = qca8k_get_tag_protocol, .setup = qca8k_setup, + .adjust_link = qca8k_adjust_link, .get_strings = qca8k_get_strings, .phy_read = qca8k_phy_read, .phy_write = qca8k_phy_write, @@ -867,6 +909,7 @@ qca8k_sw_probe(struct mdio_device *mdiodev) return -ENOMEM; priv->bus = mdiodev->bus; + priv->dev = &mdiodev->dev; /* read the switches ID register */ id = qca8k_read(priv, QCA8K_REG_MASK_CTRL); diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h index 5bda16555478..613fe5c50236 100644 --- a/drivers/net/dsa/qca8k.h +++ b/drivers/net/dsa/qca8k.h @@ -167,6 +167,7 @@ struct qca8k_priv { struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS]; struct dsa_switch *ds; struct mutex reg_mutex; + struct device *dev; }; struct qca8k_mib_desc { -- GitLab From 1494a3a70ce0feb8b9fe47f3cb30e804d2d4c2d5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 27 Jul 2018 18:15:46 +0200 Subject: [PATCH 0518/1001] ipv4: remove BUG_ON() from fib_compute_spec_dst [ Upstream commit 9fc12023d6f51551d6ca9ed7e02ecc19d79caf17 ] Remove BUG_ON() from fib_compute_spec_dst routine and check in_dev pointer during flowi4 data structure initialization. fib_compute_spec_dst routine can be run concurrently with device removal where ip_ptr net_device pointer is set to NULL. This can happen if userspace enables pkt info on UDP rx socket and the device is removed while traffic is flowing Fixes: 35ebf65e851c ("ipv4: Create and use fib_compute_spec_dst() helper") Signed-off-by: Lorenzo Bianconi Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/fib_frontend.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 67eebcb113f3..5bbdd05d0cd3 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -282,19 +282,19 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb) return ip_hdr(skb)->daddr; in_dev = __in_dev_get_rcu(dev); - BUG_ON(!in_dev); net = dev_net(dev); scope = RT_SCOPE_UNIVERSE; if (!ipv4_is_zeronet(ip_hdr(skb)->saddr)) { + bool vmark = in_dev && IN_DEV_SRC_VMARK(in_dev); struct flowi4 fl4 = { .flowi4_iif = LOOPBACK_IFINDEX, .flowi4_oif = l3mdev_master_ifindex_rcu(dev), .daddr = ip_hdr(skb)->saddr, .flowi4_tos = RT_TOS(ip_hdr(skb)->tos), .flowi4_scope = scope, - .flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0, + .flowi4_mark = vmark ? skb->mark : 0, }; if (!fib_lookup(net, &fl4, &res, 0)) return FIB_RES_PREFSRC(net, res); -- GitLab From 11b694387ab493fbc10e203109ed2faed5d592b1 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Thu, 26 Jul 2018 23:40:33 +0300 Subject: [PATCH 0519/1001] net: ena: Fix use of uninitialized DMA address bits field [ Upstream commit 101f0cd4f2216d32f1b8a75a2154cf3997484ee2 ] UBSAN triggers the following undefined behaviour warnings: [...] [ 13.236124] UBSAN: Undefined behaviour in drivers/net/ethernet/amazon/ena/ena_eth_com.c:468:22 [ 13.240043] shift exponent 64 is too large for 64-bit type 'long long unsigned int' [...] [ 13.744769] UBSAN: Undefined behaviour in drivers/net/ethernet/amazon/ena/ena_eth_com.c:373:4 [ 13.748694] shift exponent 64 is too large for 64-bit type 'long long unsigned int' [...] When splitting the address to high and low, GENMASK_ULL is used to generate a bitmask with dma_addr_bits field from io_sq (in ena_com_prepare_tx and ena_com_add_single_rx_desc). The problem is that dma_addr_bits is not initialized with a proper value (besides being cleared in ena_com_create_io_queue). Assign dma_addr_bits the correct value that is stored in ena_dev when initializing the SQ. Fixes: 1738cd3ed342 ("net: ena: Add a driver for Amazon Elastic Network Adapters (ENA)") Signed-off-by: Gal Pressman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/amazon/ena/ena_com.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 52beba8c7a39..e3b7a71fcad9 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -331,6 +331,7 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev, memset(&io_sq->desc_addr, 0x0, sizeof(io_sq->desc_addr)); + io_sq->dma_addr_bits = ena_dev->dma_addr_bits; io_sq->desc_entry_size = (io_sq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) ? sizeof(struct ena_eth_io_tx_desc) : -- GitLab From 112e80ac82851912fd8dae1e4c0bf1a0fb3bffeb Mon Sep 17 00:00:00 2001 From: tangpengpeng Date: Thu, 26 Jul 2018 14:45:16 +0800 Subject: [PATCH 0520/1001] net: fix amd-xgbe flow-control issue [ Upstream commit 7f3fc7ddf719cd6faaf787722c511f6918ac6aab ] If we enable or disable xgbe flow-control by ethtool , it does't work.Because the parameter is not properly assigned,so we need to adjust the assignment order of the parameters. Fixes: c1ce2f77366b ("amd-xgbe: Fix flow control setting logic") Signed-off-by: tangpengpeng Acked-by: Tom Lendacky Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index 1b45cd73a258..119777986ea4 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -1128,14 +1128,14 @@ static void xgbe_phy_adjust_link(struct xgbe_prv_data *pdata) if (pdata->tx_pause != pdata->phy.tx_pause) { new_state = 1; - pdata->hw_if.config_tx_flow_control(pdata); pdata->tx_pause = pdata->phy.tx_pause; + pdata->hw_if.config_tx_flow_control(pdata); } if (pdata->rx_pause != pdata->phy.rx_pause) { new_state = 1; - pdata->hw_if.config_rx_flow_control(pdata); pdata->rx_pause = pdata->phy.rx_pause; + pdata->hw_if.config_rx_flow_control(pdata); } /* Speed support */ -- GitLab From ccdbe7e2374a0be4ab81d70b53d23dd12b043648 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 28 Jul 2018 09:52:10 +0200 Subject: [PATCH 0521/1001] net: lan78xx: fix rx handling before first packet is send [ Upstream commit 136f55f660192ce04af091642efc75d85e017364 ] As long the bh tasklet isn't scheduled once, no packet from the rx path will be handled. Since the tx path also schedule the same tasklet this situation only persits until the first packet transmission. So fix this issue by scheduling the tasklet after link reset. Link: https://github.com/raspberrypi/linux/issues/2617 Fixes: 55d7de9de6c3 ("Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet") Suggested-by: Floris Bos Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/lan78xx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 0aa91ab9a0fb..9e3f632e22f1 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -1216,6 +1216,8 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) mod_timer(&dev->stat_monitor, jiffies + STAT_UPDATE_TIMER); } + + tasklet_schedule(&dev->bh); } return ret; -- GitLab From e071e2fdf45e1505436ad61e42b0d44904db1997 Mon Sep 17 00:00:00 2001 From: Anton Vasilyev Date: Fri, 27 Jul 2018 18:57:47 +0300 Subject: [PATCH 0522/1001] net: mdio-mux: bcm-iproc: fix wrong getter and setter pair [ Upstream commit b0753408aadf32c7ece9e6b765017881e54af833 ] mdio_mux_iproc_probe() uses platform_set_drvdata() to store md pointer in device, whereas mdio_mux_iproc_remove() restores md pointer by dev_get_platdata(&pdev->dev). This leads to wrong resources release. The patch replaces getter to platform_get_drvdata. Fixes: 98bc865a1ec8 ("net: mdio-mux: Add MDIO mux driver for iProc SoCs") Signed-off-by: Anton Vasilyev Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/mdio-mux-bcm-iproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/mdio-mux-bcm-iproc.c b/drivers/net/phy/mdio-mux-bcm-iproc.c index 0831b7142df7..0c5b68e7da51 100644 --- a/drivers/net/phy/mdio-mux-bcm-iproc.c +++ b/drivers/net/phy/mdio-mux-bcm-iproc.c @@ -218,7 +218,7 @@ static int mdio_mux_iproc_probe(struct platform_device *pdev) static int mdio_mux_iproc_remove(struct platform_device *pdev) { - struct iproc_mdiomux_desc *md = dev_get_platdata(&pdev->dev); + struct iproc_mdiomux_desc *md = platform_get_drvdata(pdev); mdio_mux_uninit(md->mux_handle); mdiobus_unregister(md->mii_bus); -- GitLab From 7f36a065963aebecc94d2be1e37f30162e5fe229 Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Thu, 26 Jul 2018 15:05:37 +0300 Subject: [PATCH 0523/1001] NET: stmmac: align DMA stuff to largest cache line length [ Upstream commit 9939a46d90c6c76f4533d534dbadfa7b39dc6acc ] As for today STMMAC_ALIGN macro (which is used to align DMA stuff) relies on L1 line length (L1_CACHE_BYTES). This isn't correct in case of system with several cache levels which might have L1 cache line length smaller than L2 line. This can lead to sharing one cache line between DMA buffer and other data, so we can lose this data while invalidate DMA buffer before DMA transaction. Fix that by using SMP_CACHE_BYTES instead of L1_CACHE_BYTES for aligning. Signed-off-by: Eugeniy Paltsev Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 27f2e650e27b..1a9a382bf1c4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -51,7 +51,7 @@ #include #include "dwmac1000.h" -#define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x) +#define STMMAC_ALIGN(x) __ALIGN_KERNEL(x, SMP_CACHE_BYTES) #define TSO_MAX_BUFF_SIZE (SZ_16K - 1) /* Module parameters */ -- GitLab From 7309441887f64f6ed942408a569bd629386cec71 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Fri, 27 Jul 2018 17:19:12 -0400 Subject: [PATCH 0524/1001] tcp_bbr: fix bw probing to raise in-flight data for very small BDPs [ Upstream commit 383d470936c05554219094a4d364d964cb324827 ] For some very small BDPs (with just a few packets) there was a quantization effect where the target number of packets in flight during the super-unity-gain (1.25x) phase of gain cycling was implicitly truncated to a number of packets no larger than the normal unity-gain (1.0x) phase of gain cycling. This meant that in multi-flow scenarios some flows could get stuck with a lower bandwidth, because they did not push enough packets inflight to discover that there was more bandwidth available. This was really only an issue in multi-flow LAN scenarios, where RTTs and BDPs are low enough for this to be an issue. This fix ensures that gain cycling can raise inflight for small BDPs by ensuring that in PROBE_BW mode target inflight values with a super-unity gain are always greater than inflight values with a gain <= 1. Importantly, this applies whether the inflight value is calculated for use as a cwnd value, or as a target inflight value for the end of the super-unity phase in bbr_is_next_cycle_phase() (both need to be bigger to ensure we can probe with more packets in flight reliably). This is a candidate fix for stable releases. Fixes: 0f8782ea1497 ("tcp_bbr: add BBR congestion control") Signed-off-by: Neal Cardwell Acked-by: Yuchung Cheng Acked-by: Soheil Hassas Yeganeh Acked-by: Priyaranjan Jha Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_bbr.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c index 9a0b952dd09b..06f247ca9197 100644 --- a/net/ipv4/tcp_bbr.c +++ b/net/ipv4/tcp_bbr.c @@ -353,6 +353,10 @@ static u32 bbr_target_cwnd(struct sock *sk, u32 bw, int gain) /* Reduce delayed ACKs by rounding up cwnd to the next even number. */ cwnd = (cwnd + 1) & ~1U; + /* Ensure gain cycling gets inflight above BDP even for small BDPs. */ + if (bbr->mode == BBR_PROBE_BW && gain > BBR_UNIT) + cwnd += 2; + return cwnd; } -- GitLab From da970765b24cad557bde1b0372166e46c1276230 Mon Sep 17 00:00:00 2001 From: Xiao Liang Date: Fri, 27 Jul 2018 17:56:08 +0800 Subject: [PATCH 0525/1001] xen-netfront: wait xenbus state change when load module manually [ Upstream commit 822fb18a82abaf4ee7058793d95d340f5dab7bfc ] When loading module manually, after call xenbus_switch_state to initializes the state of the netfront device, the driver state did not change so fast that may lead no dev created in latest kernel. This patch adds wait to make sure xenbus knows the driver is not in closed/unknown state. Current state: [vm]# ethtool eth0 Settings for eth0: Link detected: yes [vm]# modprobe -r xen_netfront [vm]# modprobe xen_netfront [vm]# ethtool eth0 Settings for eth0: Cannot get device settings: No such device Cannot get wake-on-lan settings: No such device Cannot get message level: No such device Cannot get link status: No such device No data available With the patch installed. [vm]# ethtool eth0 Settings for eth0: Link detected: yes [vm]# modprobe -r xen_netfront [vm]# modprobe xen_netfront [vm]# ethtool eth0 Settings for eth0: Link detected: yes Signed-off-by: Xiao Liang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/xen-netfront.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 04e0765be5e7..dfc076f9ee4b 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -87,6 +87,7 @@ struct netfront_cb { /* IRQ name is queue name with "-tx" or "-rx" appended */ #define IRQ_NAME_SIZE (QUEUE_NAME_SIZE + 3) +static DECLARE_WAIT_QUEUE_HEAD(module_load_q); static DECLARE_WAIT_QUEUE_HEAD(module_unload_q); struct netfront_stats { @@ -1330,6 +1331,11 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev) netif_carrier_off(netdev); xenbus_switch_state(dev, XenbusStateInitialising); + wait_event(module_load_q, + xenbus_read_driver_state(dev->otherend) != + XenbusStateClosed && + xenbus_read_driver_state(dev->otherend) != + XenbusStateUnknown); return netdev; exit: -- GitLab From e208cda5f10e131f149e59d7de4ceb943382f4c6 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Fri, 27 Jul 2018 16:54:44 +0100 Subject: [PATCH 0526/1001] netlink: Do not subscribe to non-existent groups [ Upstream commit 7acf9d4237c46894e0fa0492dd96314a41742e84 ] Make ABI more strict about subscribing to group > ngroups. Code doesn't check for that and it looks bogus. (one can subscribe to non-existing group) Still, it's possible to bind() to all possible groups with (-1) Cc: "David S. Miller" Cc: Herbert Xu Cc: Steffen Klassert Cc: netdev@vger.kernel.org Signed-off-by: Dmitry Safonov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/netlink/af_netlink.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index b3932846f6c4..143d9001e87d 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -976,6 +976,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, if (err) return err; } + groups &= (1UL << nlk->ngroups) - 1; bound = nlk->bound; if (bound) { -- GitLab From fffd3058eaf438e71cd301c14a0c67161a5864df Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 30 Jul 2018 18:32:36 +0100 Subject: [PATCH 0527/1001] netlink: Don't shift with UB on nlk->ngroups [ Upstream commit 61f4b23769f0cc72ae62c9a81cf08f0397d40da8 ] On i386 nlk->ngroups might be 32 or 0. Which leads to UB, resulting in hang during boot. Check for 0 ngroups and use (unsigned long long) as a type to shift. Fixes: 7acf9d4237c4 ("netlink: Do not subscribe to non-existent groups"). Reported-by: kernel test robot Signed-off-by: Dmitry Safonov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/netlink/af_netlink.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 143d9001e87d..b2fcbf012056 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -976,7 +976,11 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, if (err) return err; } - groups &= (1UL << nlk->ngroups) - 1; + + if (nlk->ngroups == 0) + groups = 0; + else + groups &= (1ULL << nlk->ngroups) - 1; bound = nlk->bound; if (bound) { -- GitLab From 5a1baf194475849ff31a34c30d540bc1795a2a7c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 17 May 2018 14:47:25 -0700 Subject: [PATCH 0528/1001] tcp: do not force quickack when receiving out-of-order packets [ Upstream commit a3893637e1eb0ef5eb1bbc52b3a8d2dfa317a35d ] As explained in commit 9f9843a751d0 ("tcp: properly handle stretch acks in slow start"), TCP stacks have to consider how many packets are acknowledged in one single ACK, because of GRO, but also because of ACK compression or losses. We plan to add SACK compression in the following patch, we must therefore not call tcp_enter_quickack_mode() Signed-off-by: Eric Dumazet Acked-by: Neal Cardwell Acked-by: Soheil Hassas Yeganeh Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index b86e7b8beb1d..e12bf35beb1c 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4721,8 +4721,6 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt + tcp_receive_window(tp))) goto out_of_window; - tcp_enter_quickack_mode(sk); - if (before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { /* Partial packet, seq < rcv_next < end_seq */ SOCK_DEBUG(sk, "partial packet: rcv_next %X seq %X - %X\n", -- GitLab From 1c005489fa9876713d8f1f626947017dd45a9bfc Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 21 May 2018 15:08:56 -0700 Subject: [PATCH 0529/1001] tcp: add max_quickacks param to tcp_incr_quickack and tcp_enter_quickack_mode [ Upstream commit 9a9c9b51e54618861420093ae6e9b50a961914c5 ] We want to add finer control of the number of ACK packets sent after ECN events. This patch is not changing current behavior, it only enables following change. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Acked-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/tcp.h | 2 +- net/ipv4/tcp_dctcp.c | 4 ++-- net/ipv4/tcp_input.c | 24 +++++++++++++----------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 3173dd12b8cc..686e33ea76e7 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -372,7 +372,7 @@ ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); -void tcp_enter_quickack_mode(struct sock *sk); +void tcp_enter_quickack_mode(struct sock *sk, unsigned int max_quickacks); static inline void tcp_dec_quickack_mode(struct sock *sk, const unsigned int pkts) { diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c index c78fb53988a1..1a9b88c8cf72 100644 --- a/net/ipv4/tcp_dctcp.c +++ b/net/ipv4/tcp_dctcp.c @@ -138,7 +138,7 @@ static void dctcp_ce_state_0_to_1(struct sock *sk) */ if (inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) __tcp_send_ack(sk, ca->prior_rcv_nxt); - tcp_enter_quickack_mode(sk); + tcp_enter_quickack_mode(sk, 1); } ca->prior_rcv_nxt = tp->rcv_nxt; @@ -159,7 +159,7 @@ static void dctcp_ce_state_1_to_0(struct sock *sk) */ if (inet_csk(sk)->icsk_ack.pending & ICSK_ACK_TIMER) __tcp_send_ack(sk, ca->prior_rcv_nxt); - tcp_enter_quickack_mode(sk); + tcp_enter_quickack_mode(sk, 1); } ca->prior_rcv_nxt = tp->rcv_nxt; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e12bf35beb1c..bc9c48d01980 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -198,21 +198,23 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb) } } -static void tcp_incr_quickack(struct sock *sk) +static void tcp_incr_quickack(struct sock *sk, unsigned int max_quickacks) { struct inet_connection_sock *icsk = inet_csk(sk); unsigned int quickacks = tcp_sk(sk)->rcv_wnd / (2 * icsk->icsk_ack.rcv_mss); if (quickacks == 0) quickacks = 2; + quickacks = min(quickacks, max_quickacks); if (quickacks > icsk->icsk_ack.quick) - icsk->icsk_ack.quick = min(quickacks, TCP_MAX_QUICKACKS); + icsk->icsk_ack.quick = quickacks; } -void tcp_enter_quickack_mode(struct sock *sk) +void tcp_enter_quickack_mode(struct sock *sk, unsigned int max_quickacks) { struct inet_connection_sock *icsk = inet_csk(sk); - tcp_incr_quickack(sk); + + tcp_incr_quickack(sk, max_quickacks); icsk->icsk_ack.pingpong = 0; icsk->icsk_ack.ato = TCP_ATO_MIN; } @@ -257,7 +259,7 @@ static void __tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) * it is probably a retransmit. */ if (tp->ecn_flags & TCP_ECN_SEEN) - tcp_enter_quickack_mode((struct sock *)tp); + tcp_enter_quickack_mode((struct sock *)tp, TCP_MAX_QUICKACKS); break; case INET_ECN_CE: if (tcp_ca_needs_ecn((struct sock *)tp)) @@ -265,7 +267,7 @@ static void __tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) if (!(tp->ecn_flags & TCP_ECN_DEMAND_CWR)) { /* Better not delay acks, sender can have a very low cwnd */ - tcp_enter_quickack_mode((struct sock *)tp); + tcp_enter_quickack_mode((struct sock *)tp, TCP_MAX_QUICKACKS); tp->ecn_flags |= TCP_ECN_DEMAND_CWR; } tp->ecn_flags |= TCP_ECN_SEEN; @@ -686,7 +688,7 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb) /* The _first_ data packet received, initialize * delayed ACK engine. */ - tcp_incr_quickack(sk); + tcp_incr_quickack(sk, TCP_MAX_QUICKACKS); icsk->icsk_ack.ato = TCP_ATO_MIN; } else { int m = now - icsk->icsk_ack.lrcvtime; @@ -702,7 +704,7 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb) /* Too long gap. Apparently sender failed to * restart window, so that we send ACKs quickly. */ - tcp_incr_quickack(sk); + tcp_incr_quickack(sk, TCP_MAX_QUICKACKS); sk_mem_reclaim(sk); } } @@ -4160,7 +4162,7 @@ static void tcp_send_dupack(struct sock *sk, const struct sk_buff *skb) if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOST); - tcp_enter_quickack_mode(sk); + tcp_enter_quickack_mode(sk, TCP_MAX_QUICKACKS); if (tcp_is_sack(tp) && sysctl_tcp_dsack) { u32 end_seq = TCP_SKB_CB(skb)->end_seq; @@ -4710,7 +4712,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); out_of_window: - tcp_enter_quickack_mode(sk); + tcp_enter_quickack_mode(sk, TCP_MAX_QUICKACKS); inet_csk_schedule_ack(sk); drop: tcp_drop(sk, skb); @@ -5791,7 +5793,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, * to stand against the temptation 8) --ANK */ inet_csk_schedule_ack(sk); - tcp_enter_quickack_mode(sk); + tcp_enter_quickack_mode(sk, TCP_MAX_QUICKACKS); inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, TCP_DELACK_MAX, TCP_RTO_MAX); -- GitLab From fd31083cbe050d10b1cb4f681929154cffe18fb6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 21 May 2018 15:08:57 -0700 Subject: [PATCH 0530/1001] tcp: do not aggressively quick ack after ECN events [ Upstream commit 522040ea5fdd1c33bbf75e1d7c7c0422b96a94ef ] ECN signals currently forces TCP to enter quickack mode for up to 16 (TCP_MAX_QUICKACKS) following incoming packets. We believe this is not needed, and only sending one immediate ack for the current packet should be enough. This should reduce the extra load noticed in DCTCP environments, after congestion events. This is part 2 of our effort to reduce pure ACK packets. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Acked-by: Yuchung Cheng Acked-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index bc9c48d01980..a7bb96054852 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -259,7 +259,7 @@ static void __tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) * it is probably a retransmit. */ if (tp->ecn_flags & TCP_ECN_SEEN) - tcp_enter_quickack_mode((struct sock *)tp, TCP_MAX_QUICKACKS); + tcp_enter_quickack_mode((struct sock *)tp, 1); break; case INET_ECN_CE: if (tcp_ca_needs_ecn((struct sock *)tp)) @@ -267,7 +267,7 @@ static void __tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) if (!(tp->ecn_flags & TCP_ECN_DEMAND_CWR)) { /* Better not delay acks, sender can have a very low cwnd */ - tcp_enter_quickack_mode((struct sock *)tp, TCP_MAX_QUICKACKS); + tcp_enter_quickack_mode((struct sock *)tp, 1); tp->ecn_flags |= TCP_ECN_DEMAND_CWR; } tp->ecn_flags |= TCP_ECN_SEEN; -- GitLab From 1f04d750f6688c0fe0cc13fd05d5744d1e7b50c3 Mon Sep 17 00:00:00 2001 From: Yousuk Seung Date: Mon, 4 Jun 2018 15:29:51 -0700 Subject: [PATCH 0531/1001] tcp: refactor tcp_ecn_check_ce to remove sk type cast [ Upstream commit f4c9f85f3b2cb7669830cd04d0be61192a4d2436 ] Refactor tcp_ecn_check_ce and __tcp_ecn_check_ce to accept struct sock* instead of tcp_sock* to clean up type casts. This is a pure refactor patch. Signed-off-by: Yousuk Seung Signed-off-by: Neal Cardwell Signed-off-by: Yuchung Cheng Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index a7bb96054852..124be1636efe 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -250,8 +250,10 @@ static void tcp_ecn_withdraw_cwr(struct tcp_sock *tp) tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; } -static void __tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) +static void __tcp_ecn_check_ce(struct sock *sk, const struct sk_buff *skb) { + struct tcp_sock *tp = tcp_sk(sk); + switch (TCP_SKB_CB(skb)->ip_dsfield & INET_ECN_MASK) { case INET_ECN_NOT_ECT: /* Funny extension: if ECT is not set on a segment, @@ -259,31 +261,31 @@ static void __tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) * it is probably a retransmit. */ if (tp->ecn_flags & TCP_ECN_SEEN) - tcp_enter_quickack_mode((struct sock *)tp, 1); + tcp_enter_quickack_mode(sk, 1); break; case INET_ECN_CE: - if (tcp_ca_needs_ecn((struct sock *)tp)) - tcp_ca_event((struct sock *)tp, CA_EVENT_ECN_IS_CE); + if (tcp_ca_needs_ecn(sk)) + tcp_ca_event(sk, CA_EVENT_ECN_IS_CE); if (!(tp->ecn_flags & TCP_ECN_DEMAND_CWR)) { /* Better not delay acks, sender can have a very low cwnd */ - tcp_enter_quickack_mode((struct sock *)tp, 1); + tcp_enter_quickack_mode(sk, 1); tp->ecn_flags |= TCP_ECN_DEMAND_CWR; } tp->ecn_flags |= TCP_ECN_SEEN; break; default: - if (tcp_ca_needs_ecn((struct sock *)tp)) - tcp_ca_event((struct sock *)tp, CA_EVENT_ECN_NO_CE); + if (tcp_ca_needs_ecn(sk)) + tcp_ca_event(sk, CA_EVENT_ECN_NO_CE); tp->ecn_flags |= TCP_ECN_SEEN; break; } } -static void tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) +static void tcp_ecn_check_ce(struct sock *sk, const struct sk_buff *skb) { - if (tp->ecn_flags & TCP_ECN_OK) - __tcp_ecn_check_ce(tp, skb); + if (tcp_sk(sk)->ecn_flags & TCP_ECN_OK) + __tcp_ecn_check_ce(sk, skb); } static void tcp_ecn_rcv_synack(struct tcp_sock *tp, const struct tcphdr *th) @@ -710,7 +712,7 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb) } icsk->icsk_ack.lrcvtime = now; - tcp_ecn_check_ce(tp, skb); + tcp_ecn_check_ce(sk, skb); if (skb->len >= 128) tcp_grow_window(sk, skb); @@ -4443,7 +4445,7 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) u32 seq, end_seq; bool fragstolen; - tcp_ecn_check_ce(tp, skb); + tcp_ecn_check_ce(sk, skb); if (unlikely(tcp_try_rmem_schedule(sk, skb, skb->truesize))) { NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPOFODROP); -- GitLab From 0a2f6725115dc17b97294403a5afca830c64e48a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 27 Jun 2018 08:47:21 -0700 Subject: [PATCH 0532/1001] tcp: add one more quick ack after after ECN events [ Upstream commit 15ecbe94a45ef88491ca459b26efdd02f91edb6d ] Larry Brakmo proposal ( https://patchwork.ozlabs.org/patch/935233/ tcp: force cwnd at least 2 in tcp_cwnd_reduction) made us rethink about our recent patch removing ~16 quick acks after ECN events. tcp_enter_quickack_mode(sk, 1) makes sure one immediate ack is sent, but in the case the sender cwnd was lowered to 1, we do not want to have a delayed ack for the next packet we will receive. Fixes: 522040ea5fdd ("tcp: do not aggressively quick ack after ECN events") Signed-off-by: Eric Dumazet Reported-by: Neal Cardwell Cc: Lawrence Brakmo Acked-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 124be1636efe..bdabd748f4bc 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -261,7 +261,7 @@ static void __tcp_ecn_check_ce(struct sock *sk, const struct sk_buff *skb) * it is probably a retransmit. */ if (tp->ecn_flags & TCP_ECN_SEEN) - tcp_enter_quickack_mode(sk, 1); + tcp_enter_quickack_mode(sk, 2); break; case INET_ECN_CE: if (tcp_ca_needs_ecn(sk)) @@ -269,7 +269,7 @@ static void __tcp_ecn_check_ce(struct sock *sk, const struct sk_buff *skb) if (!(tp->ecn_flags & TCP_ECN_DEMAND_CWR)) { /* Better not delay acks, sender can have a very low cwnd */ - tcp_enter_quickack_mode(sk, 1); + tcp_enter_quickack_mode(sk, 2); tp->ecn_flags |= TCP_ECN_DEMAND_CWR; } tp->ecn_flags |= TCP_ECN_SEEN; -- GitLab From deaacd62c2175c624a41c1b3c721e23c660031e1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 3 Aug 2018 07:50:45 +0200 Subject: [PATCH 0533/1001] Linux 4.14.60 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 81b0e99dce80..5b48ec630990 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 59 +SUBLEVEL = 60 EXTRAVERSION = NAME = Petit Gorille -- GitLab From ca0ef17590f9d805ad6df45cae583cc72b01f13a Mon Sep 17 00:00:00 2001 From: David Collins Date: Fri, 20 Jul 2018 17:01:06 -0700 Subject: [PATCH 0534/1001] clk: qcom: gdsc-regulator: add support for skipping GDSC disable Some GDSCs have side effects when enabled without first performing a special reset sequence. It is only feasible for this sequence to be performed by the always-on processor (AOP) when it is resuming from system sleep. Add support for a device tree flag which can be specified in order to skip physically disabling a GDSC when regulator_disable() is called. The AOP will then ensure that the GDSC is disabled upon entering system sleep and appropriately reset upon resuming from system sleep. Also change the is_enabled() callback so that it returns the GDSC logical enable state instead of the physical enable state whenever the disable skipping flag is specified. This ensures that all dependent regulator and bus requests are made in the case of disabling and re-enabling a GDSC without entering system sleep (i.e. when the GDSC shows up as still physically enabled.) Change-Id: I0eaa3041daa855e458bf97fc58876bc62a236df2 Signed-off-by: David Collins --- .../bindings/regulator/gdsc-regulator.txt | 6 ++++++ drivers/clk/qcom/gdsc-regulator.c | 17 ++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt index 5c93e5666634..c661c71aee3b 100644 --- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt @@ -43,6 +43,12 @@ Optional properties: Ex. "base", "domain-addr", "sw-reset", "hw-ctrl-addr". - qcom,no-status-check-on-disable: Do not poll the status bit when GDSC is disabled. + - qcom,skip-disable: Boolean flag indicating that the GDSC must not be + physically disabled upon a software disable request. + Instead, the GDSC will be disabled by the always-on + processor (AOP) upon entering system sleep. The AOP + will also perform a special reset sequence for the GDSC + upon resuming from system sleep. - qcom,disallow-clear: Presence denotes the periph & core memory will not be cleared, unless the required subsystem does not invoke the api which will allow clearing the bits. diff --git a/drivers/clk/qcom/gdsc-regulator.c b/drivers/clk/qcom/gdsc-regulator.c index 048d1ff302a6..a579a5d1f028 100644 --- a/drivers/clk/qcom/gdsc-regulator.c +++ b/drivers/clk/qcom/gdsc-regulator.c @@ -72,6 +72,7 @@ struct gdsc { bool root_en; bool force_root_en; bool no_status_check_on_disable; + bool skip_disable; bool is_gdsc_enabled; bool allow_clear; bool reset_aon; @@ -150,6 +151,13 @@ static int gdsc_is_enabled(struct regulator_dev *rdev) int ret; bool is_enabled = false; + /* + * Return the logical GDSC enable state given that it will only be + * physically disabled by AOP during system sleep. + */ + if (sc->skip_disable) + return sc->is_gdsc_enabled; + if (!sc->toggle_logic) return !sc->resets_asserted; @@ -418,7 +426,12 @@ static int gdsc_disable(struct regulator_dev *rdev) /* Delay to account for staggered memory powerdown. */ udelay(1); - if (sc->toggle_logic) { + if (sc->skip_disable) { + /* + * Don't change the GDSCR register state on disable. AOP will + * handle this during system sleep. + */ + } else if (sc->toggle_logic) { regmap_read(sc->regmap, REG_OFFSET, ®val); regval |= SW_COLLAPSE_MASK; regmap_write(sc->regmap, REG_OFFSET, regval); @@ -831,6 +844,8 @@ static int gdsc_probe(struct platform_device *pdev) sc->no_status_check_on_disable = of_property_read_bool(pdev->dev.of_node, "qcom,no-status-check-on-disable"); + sc->skip_disable = of_property_read_bool(pdev->dev.of_node, + "qcom,skip-disable"); retain_mem = of_property_read_bool(pdev->dev.of_node, "qcom,retain-mem"); sc->toggle_mem = !retain_mem; -- GitLab From 33ac7ac9c560a25c2fb7ba43ad48979589615433 Mon Sep 17 00:00:00 2001 From: David Collins Date: Tue, 31 Jul 2018 12:02:44 -0700 Subject: [PATCH 0535/1001] ARM: dts: msm: do not disable gpu_cx_gdsc for SM8150 Modify the configurations for gpu_cx_gdsc so that application processor software does not attempt to disable it. This GDSC will instead be disabled by the always-on processor when entering system sleep. The AOP also performs a special reset sequence for the GDSC upon resuming from system sleep. These steps ensure that software does not encounter a NOC error when enabling the GDSC. Change-Id: I4477ce6016734ea5be66f66e220a5519b4f013b1 Signed-off-by: David Collins --- arch/arm64/boot/dts/qcom/sm8150-gdsc.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-gdsc.dtsi b/arch/arm64/boot/dts/qcom/sm8150-gdsc.dtsi index f83eb2a10064..6baac00ed014 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-gdsc.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-gdsc.dtsi @@ -208,7 +208,7 @@ regulator-name = "gpu_cx_gdsc"; reg = <0x2c9106c 0x4>; hw-ctrl-addr = <&gpu_cx_hw_ctrl>; - qcom,no-status-check-on-disable; + qcom,skip-disable; qcom,gds-timeout = <500>; qcom,clk-dis-wait-val = <8>; status = "disabled"; -- GitLab From a270848739f06f8d199229c6d070e5e06472c72a Mon Sep 17 00:00:00 2001 From: Suraj Dongre Date: Fri, 3 Aug 2018 15:16:49 -0700 Subject: [PATCH 0536/1001] msm: camera: Fix context refcount underflow Fixed context refcount underflow caused by putref even though device handle had been already released. Also fixed check for dev handle value. Change-Id: I50b9d77571381dd308f30059104be416caea6885 Signed-off-by: Suraj Dongre --- drivers/media/platform/msm/camera/cam_core/cam_context.c | 2 +- .../media/platform/msm/camera/cam_core/cam_context_utils.c | 1 + drivers/media/platform/msm/camera/cam_core/cam_node.c | 7 +++++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.c b/drivers/media/platform/msm/camera/cam_core/cam_context.c index 24685b985bcd..06151bbd3440 100644 --- a/drivers/media/platform/msm/camera/cam_core/cam_context.c +++ b/drivers/media/platform/msm/camera/cam_core/cam_context.c @@ -58,7 +58,7 @@ int cam_context_shutdown(struct cam_context *ctx) } if (!rc) - cam_destroy_device_hdl(ctx_hdl); + rc = cam_destroy_device_hdl(ctx_hdl); return rc; } diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c index fce7fc6cc6b8..d28dd5c8bff1 100644 --- a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c +++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c @@ -490,6 +490,7 @@ int32_t cam_context_acquire_dev_to_hw(struct cam_context *ctx, release.ctxt_to_hw_map = ctx->ctxt_to_hw_map; ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, &release); ctx->ctxt_to_hw_map = NULL; + ctx->dev_hdl = -1; end: return rc; } diff --git a/drivers/media/platform/msm/camera/cam_core/cam_node.c b/drivers/media/platform/msm/camera/cam_core/cam_node.c index 6e46c4ca950f..235c754c30f4 100644 --- a/drivers/media/platform/msm/camera/cam_core/cam_node.c +++ b/drivers/media/platform/msm/camera/cam_core/cam_node.c @@ -413,13 +413,16 @@ int cam_node_deinit(struct cam_node *node) int cam_node_shutdown(struct cam_node *node) { int i = 0; + int rc = 0; if (!node) return -EINVAL; for (i = 0; i < node->ctx_size; i++) { - if (node->ctx_list[i].dev_hdl >= 0) { - cam_context_shutdown(&(node->ctx_list[i])); + if (node->ctx_list[i].dev_hdl > 0) { + rc = cam_context_shutdown(&(node->ctx_list[i])); + if (rc) + continue; cam_context_putref(&(node->ctx_list[i])); } } -- GitLab From deeaa94eeae7f3128c8d7d85c6edc47184f67279 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Fri, 3 Aug 2018 16:54:27 -0700 Subject: [PATCH 0537/1001] msm: camera: Memset the data structure This change memsets the flush arguments struct before populating the necessary fields. Also as part of icp flush removing log that accesses pending req even when the pending req count might be 0. Change-Id: I16f9b1c1bfa6f863a32d305e163b10883e78b212 Signed-off-by: Karthik Anantha Ram --- .../media/platform/msm/camera/cam_core/cam_context_utils.c | 2 ++ .../msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c index fce7fc6cc6b8..79d0e79d5860 100644 --- a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c +++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c @@ -504,6 +504,7 @@ int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx) bool free_req; CAM_DBG(CAM_CTXT, "[%s] E: NRT flush ctx", ctx->dev_name); + memset(&flush_args, 0, sizeof(flush_args)); /* * flush pending requests, take the sync lock to synchronize with the @@ -670,6 +671,7 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, CAM_DBG(CAM_CTXT, "[%s] E: NRT flush req", ctx->dev_name); + memset(&flush_args, 0, sizeof(flush_args)); flush_args.num_req_pending = 0; flush_args.num_req_active = 0; mutex_lock(&ctx->sync_mutex); diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index 4cfc3b5e1456..072129a57082 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -3842,10 +3842,8 @@ static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) return -EINVAL; } - CAM_DBG(CAM_REQ, "ctx_id %d req %lld Flush type %d", - ctx_data->ctx_id, - *(int64_t *)flush_args->flush_req_pending[0], - flush_args->flush_type); + CAM_DBG(CAM_REQ, "ctx_id %d Flush type %d", + ctx_data->ctx_id, flush_args->flush_type); switch (flush_args->flush_type) { case CAM_FLUSH_TYPE_ALL: -- GitLab From dc8edd08cd894a87b0136c7f077b48290eef14f6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 31 Jul 2018 06:30:54 -0700 Subject: [PATCH 0538/1001] bonding: avoid lockdep confusion in bond_get_stats() [ Upstream commit 7e2556e40026a1b0c16f37446ab398d5a5a892e4 ] syzbot found that the following sequence produces a LOCKDEP splat [1] ip link add bond10 type bond ip link add bond11 type bond ip link set bond11 master bond10 To fix this, we can use the already provided nest_level. This patch also provides correct nesting for dev->addr_list_lock [1] WARNING: possible recursive locking detected 4.18.0-rc6+ #167 Not tainted -------------------------------------------- syz-executor751/4439 is trying to acquire lock: (____ptrval____) (&(&bond->stats_lock)->rlock){+.+.}, at: spin_lock include/linux/spinlock.h:310 [inline] (____ptrval____) (&(&bond->stats_lock)->rlock){+.+.}, at: bond_get_stats+0xb4/0x560 drivers/net/bonding/bond_main.c:3426 but task is already holding lock: (____ptrval____) (&(&bond->stats_lock)->rlock){+.+.}, at: spin_lock include/linux/spinlock.h:310 [inline] (____ptrval____) (&(&bond->stats_lock)->rlock){+.+.}, at: bond_get_stats+0xb4/0x560 drivers/net/bonding/bond_main.c:3426 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&(&bond->stats_lock)->rlock); lock(&(&bond->stats_lock)->rlock); *** DEADLOCK *** May be due to missing lock nesting notation 3 locks held by syz-executor751/4439: #0: (____ptrval____) (rtnl_mutex){+.+.}, at: rtnl_lock+0x17/0x20 net/core/rtnetlink.c:77 #1: (____ptrval____) (&(&bond->stats_lock)->rlock){+.+.}, at: spin_lock include/linux/spinlock.h:310 [inline] #1: (____ptrval____) (&(&bond->stats_lock)->rlock){+.+.}, at: bond_get_stats+0xb4/0x560 drivers/net/bonding/bond_main.c:3426 #2: (____ptrval____) (rcu_read_lock){....}, at: bond_get_stats+0x0/0x560 include/linux/compiler.h:215 stack backtrace: CPU: 0 PID: 4439 Comm: syz-executor751 Not tainted 4.18.0-rc6+ #167 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x1c9/0x2b4 lib/dump_stack.c:113 print_deadlock_bug kernel/locking/lockdep.c:1765 [inline] check_deadlock kernel/locking/lockdep.c:1809 [inline] validate_chain kernel/locking/lockdep.c:2405 [inline] __lock_acquire.cold.64+0x1fb/0x486 kernel/locking/lockdep.c:3435 lock_acquire+0x1e4/0x540 kernel/locking/lockdep.c:3924 __raw_spin_lock include/linux/spinlock_api_smp.h:142 [inline] _raw_spin_lock+0x2a/0x40 kernel/locking/spinlock.c:144 spin_lock include/linux/spinlock.h:310 [inline] bond_get_stats+0xb4/0x560 drivers/net/bonding/bond_main.c:3426 dev_get_stats+0x10f/0x470 net/core/dev.c:8316 bond_get_stats+0x232/0x560 drivers/net/bonding/bond_main.c:3432 dev_get_stats+0x10f/0x470 net/core/dev.c:8316 rtnl_fill_stats+0x4d/0xac0 net/core/rtnetlink.c:1169 rtnl_fill_ifinfo+0x1aa6/0x3fb0 net/core/rtnetlink.c:1611 rtmsg_ifinfo_build_skb+0xc8/0x190 net/core/rtnetlink.c:3268 rtmsg_ifinfo_event.part.30+0x45/0xe0 net/core/rtnetlink.c:3300 rtmsg_ifinfo_event net/core/rtnetlink.c:3297 [inline] rtnetlink_event+0x144/0x170 net/core/rtnetlink.c:4716 notifier_call_chain+0x180/0x390 kernel/notifier.c:93 __raw_notifier_call_chain kernel/notifier.c:394 [inline] raw_notifier_call_chain+0x2d/0x40 kernel/notifier.c:401 call_netdevice_notifiers_info+0x3f/0x90 net/core/dev.c:1735 call_netdevice_notifiers net/core/dev.c:1753 [inline] netdev_features_change net/core/dev.c:1321 [inline] netdev_change_features+0xb3/0x110 net/core/dev.c:7759 bond_compute_features.isra.47+0x585/0xa50 drivers/net/bonding/bond_main.c:1120 bond_enslave+0x1b25/0x5da0 drivers/net/bonding/bond_main.c:1755 bond_do_ioctl+0x7cb/0xae0 drivers/net/bonding/bond_main.c:3528 dev_ifsioc+0x43c/0xb30 net/core/dev_ioctl.c:327 dev_ioctl+0x1b5/0xcc0 net/core/dev_ioctl.c:493 sock_do_ioctl+0x1d3/0x3e0 net/socket.c:992 sock_ioctl+0x30d/0x680 net/socket.c:1093 vfs_ioctl fs/ioctl.c:46 [inline] file_ioctl fs/ioctl.c:500 [inline] do_vfs_ioctl+0x1de/0x1720 fs/ioctl.c:684 ksys_ioctl+0xa9/0xd0 fs/ioctl.c:701 __do_sys_ioctl fs/ioctl.c:708 [inline] __se_sys_ioctl fs/ioctl.c:706 [inline] __x64_sys_ioctl+0x73/0xb0 fs/ioctl.c:706 do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x440859 Code: e8 2c af 02 00 48 83 c4 18 c3 0f 1f 80 00 00 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 3b 10 fc ff c3 66 2e 0f 1f 84 00 00 00 00 RSP: 002b:00007ffc51a92878 EFLAGS: 00000213 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 0000000000440859 RDX: 0000000020000040 RSI: 0000000000008990 RDI: 0000000000000003 RBP: 0000000000000000 R08: 00000000004002c8 R09: 00000000004002c8 R10: 00000000022d5880 R11: 0000000000000213 R12: 0000000000007390 R13: 0000000000401db0 R14: 0000000000000000 R15: 0000000000000000 Signed-off-by: Eric Dumazet Cc: Jay Vosburgh Cc: Veaceslav Falico Cc: Andy Gospodarek Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 00245b73c224..15aedb64a02b 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1687,6 +1687,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) goto err_upper_unlink; } + bond->nest_level = dev_get_nest_level(bond_dev) + 1; + /* If the mode uses primary, then the following is handled by * bond_change_active_slave(). */ @@ -1734,7 +1736,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (bond_mode_uses_xmit_hash(bond)) bond_update_slave_arr(bond, NULL); - bond->nest_level = dev_get_nest_level(bond_dev); netdev_info(bond_dev, "Enslaving %s as %s interface with %s link\n", slave_dev->name, @@ -3379,6 +3380,13 @@ static void bond_fold_stats(struct rtnl_link_stats64 *_res, } } +static int bond_get_nest_level(struct net_device *bond_dev) +{ + struct bonding *bond = netdev_priv(bond_dev); + + return bond->nest_level; +} + static void bond_get_stats(struct net_device *bond_dev, struct rtnl_link_stats64 *stats) { @@ -3387,7 +3395,7 @@ static void bond_get_stats(struct net_device *bond_dev, struct list_head *iter; struct slave *slave; - spin_lock(&bond->stats_lock); + spin_lock_nested(&bond->stats_lock, bond_get_nest_level(bond_dev)); memcpy(stats, &bond->bond_stats, sizeof(*stats)); rcu_read_lock(); @@ -4182,6 +4190,7 @@ static const struct net_device_ops bond_netdev_ops = { .ndo_neigh_setup = bond_neigh_setup, .ndo_vlan_rx_add_vid = bond_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = bond_vlan_rx_kill_vid, + .ndo_get_lock_subclass = bond_get_nest_level, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_netpoll_setup = bond_netpoll_setup, .ndo_netpoll_cleanup = bond_netpoll_cleanup, @@ -4680,6 +4689,7 @@ static int bond_init(struct net_device *bond_dev) if (!bond->wq) return -ENOMEM; + bond->nest_level = SINGLE_DEPTH_NESTING; netdev_lockdep_set_classes(bond_dev); list_add_tail(&bond->bond_list, &bn->dev_list); -- GitLab From fc63057d5fdad14ccf94dffe746187388aad2e55 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 30 Jul 2018 20:09:11 -0700 Subject: [PATCH 0539/1001] inet: frag: enforce memory limits earlier [ Upstream commit 56e2c94f055d328f5f6b0a5c1721cca2f2d4e0a1 ] We currently check current frags memory usage only when a new frag queue is created. This allows attackers to first consume the memory budget (default : 4 MB) creating thousands of frag queues, then sending tiny skbs to exceed high_thresh limit by 2 to 3 order of magnitude. Note that before commit 648700f76b03 ("inet: frags: use rhashtables for reassembly units"), work queue could be starved under DOS, getting no cpu cycles. After commit 648700f76b03, only the per frag queue timer can eventually remove an incomplete frag queue and its skbs. Fixes: b13d3cbfb8e8 ("inet: frag: move eviction of queues to work queue") Signed-off-by: Eric Dumazet Reported-by: Jann Horn Cc: Florian Westphal Cc: Peter Oskolkov Cc: Paolo Abeni Acked-by: Florian Westphal Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/inet_fragment.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index e691705f0a85..ba4454ecdf0f 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -356,11 +356,6 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf, { struct inet_frag_queue *q; - if (!nf->high_thresh || frag_mem_limit(nf) > nf->high_thresh) { - inet_frag_schedule_worker(f); - return NULL; - } - q = kmem_cache_zalloc(f->frags_cachep, GFP_ATOMIC); if (!q) return NULL; @@ -397,6 +392,11 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, struct inet_frag_queue *q; int depth = 0; + if (!nf->high_thresh || frag_mem_limit(nf) > nf->high_thresh) { + inet_frag_schedule_worker(f); + return NULL; + } + if (frag_mem_limit(nf) > nf->low_thresh) inet_frag_schedule_worker(f); -- GitLab From 8721f360894576908a32f5c2979dbe640731a97b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 30 Jul 2018 21:50:29 -0700 Subject: [PATCH 0540/1001] ipv4: frags: handle possible skb truesize change [ Upstream commit 4672694bd4f1aebdab0ad763ae4716e89cb15221 ] ip_frag_queue() might call pskb_pull() on one skb that is already in the fragment queue. We need to take care of possible truesize change, or we might have an imbalance of the netns frags memory usage. IPv6 is immune to this bug, because RFC5722, Section 4, amended by Errata ID 3089 states : When reassembling an IPv6 datagram, if one or more its constituent fragments is determined to be an overlapping fragment, the entire datagram (and any constituent fragments) MUST be silently discarded. Fixes: 158f323b9868 ("net: adjust skb->truesize in pskb_expand_head()") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ip_fragment.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index df8fe0503de0..4cb1befc3949 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -447,11 +447,16 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) int i = end - FRAG_CB(next)->offset; /* overlap is 'i' bytes */ if (i < next->len) { + int delta = -next->truesize; + /* Eat head of the next overlapped fragment * and leave the loop. The next ones cannot overlap. */ if (!pskb_pull(next, i)) goto err; + delta += next->truesize; + if (delta) + add_frag_mem_limit(qp->q.net, delta); FRAG_CB(next)->offset += i; qp->q.meat -= i; if (next->ip_summed != CHECKSUM_UNNECESSARY) -- GitLab From bcbdea1371599dab43a16dcb3649f811cf602d03 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 31 Jul 2018 17:12:52 -0700 Subject: [PATCH 0541/1001] net: dsa: Do not suspend/resume closed slave_dev [ Upstream commit a94c689e6c9e72e722f28339e12dff191ee5a265 ] If a DSA slave network device was previously disabled, there is no need to suspend or resume it. Fixes: 2446254915a7 ("net: dsa: allow switch drivers to implement suspend/resume hooks") Signed-off-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/dsa/slave.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 865e29e62bad..242e74b9d454 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -1219,6 +1219,9 @@ int dsa_slave_suspend(struct net_device *slave_dev) { struct dsa_slave_priv *p = netdev_priv(slave_dev); + if (!netif_running(slave_dev)) + return 0; + netif_device_detach(slave_dev); if (p->phy) { @@ -1236,6 +1239,9 @@ int dsa_slave_resume(struct net_device *slave_dev) { struct dsa_slave_priv *p = netdev_priv(slave_dev); + if (!netif_running(slave_dev)) + return 0; + netif_device_attach(slave_dev); if (p->phy) { -- GitLab From 1828cb3d10d9fee017fdd13dc655f708a1f39d68 Mon Sep 17 00:00:00 2001 From: Jeremy Cline Date: Tue, 31 Jul 2018 21:13:16 +0000 Subject: [PATCH 0542/1001] netlink: Fix spectre v1 gadget in netlink_create() [ Upstream commit bc5b6c0b62b932626a135f516a41838c510c6eba ] 'protocol' is a user-controlled value, so sanitize it after the bounds check to avoid using it for speculative out-of-bounds access to arrays indexed by it. This addresses the following accesses detected with the help of smatch: * net/netlink/af_netlink.c:654 __netlink_create() warn: potential spectre issue 'nlk_cb_mutex_keys' [w] * net/netlink/af_netlink.c:654 __netlink_create() warn: potential spectre issue 'nlk_cb_mutex_key_strings' [w] * net/netlink/af_netlink.c:685 netlink_create() warn: potential spectre issue 'nl_table' [w] (local cap) Cc: Josh Poimboeuf Signed-off-by: Jeremy Cline Reviewed-by: Josh Poimboeuf Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/netlink/af_netlink.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index b2fcbf012056..68c9d1833b95 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -63,6 +63,7 @@ #include #include #include +#include #include #include @@ -647,6 +648,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol, if (protocol < 0 || protocol >= MAX_LINKS) return -EPROTONOSUPPORT; + protocol = array_index_nospec(protocol, MAX_LINKS); netlink_lock_table(); #ifdef CONFIG_MODULES -- GitLab From 83a46456c983258eb0ba6cfc1ad650df9f59c9c1 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Tue, 31 Jul 2018 15:08:20 +0100 Subject: [PATCH 0543/1001] net: stmmac: Fix WoL for PCI-based setups [ Upstream commit b7d0f08e9129c45ed41bc0cfa8e77067881e45fd ] WoL won't work in PCI-based setups because we are not saving the PCI EP state before entering suspend state and not allowing D3 wake. Fix this by using a wrapper around stmmac_{suspend/resume} which correctly sets the PCI EP state. Signed-off-by: Jose Abreu Cc: David S. Miller Cc: Joao Pinto Cc: Giuseppe Cavallaro Cc: Alexandre Torgue Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- .../net/ethernet/stmicro/stmmac/stmmac_pci.c | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index 8d375e51a526..6a393b16a1fc 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -257,7 +257,7 @@ static int stmmac_pci_probe(struct pci_dev *pdev, return -ENOMEM; /* Enable pci device */ - ret = pcim_enable_device(pdev); + ret = pci_enable_device(pdev); if (ret) { dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n", __func__); @@ -300,9 +300,45 @@ static int stmmac_pci_probe(struct pci_dev *pdev, static void stmmac_pci_remove(struct pci_dev *pdev) { stmmac_dvr_remove(&pdev->dev); + pci_disable_device(pdev); } -static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_suspend, stmmac_resume); +static int stmmac_pci_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int ret; + + ret = stmmac_suspend(dev); + if (ret) + return ret; + + ret = pci_save_state(pdev); + if (ret) + return ret; + + pci_disable_device(pdev); + pci_wake_from_d3(pdev, true); + return 0; +} + +static int stmmac_pci_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int ret; + + pci_restore_state(pdev); + pci_set_power_state(pdev, PCI_D0); + + ret = pci_enable_device(pdev); + if (ret) + return ret; + + pci_set_master(pdev); + + return stmmac_resume(dev); +} + +static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_pci_suspend, stmmac_pci_resume); /* synthetic ID, no official vendor */ #define PCI_VENDOR_ID_STMMAC 0x700 -- GitLab From e0638b6a054cef5ad820f7380ff59463c6519b57 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 1 Aug 2018 13:27:23 +0100 Subject: [PATCH 0544/1001] rxrpc: Fix user call ID check in rxrpc_service_prealloc_one [ Upstream commit c01f6c9b3207e52fc9973a066a856ddf7a0538d8 ] There just check the user call ID isn't already in use, hence should compare user_call_ID with xcall->user_call_ID, which is current node's user_call_ID. Fixes: 540b1c48c37a ("rxrpc: Fix deadlock between call creation and sendmsg/recvmsg") Suggested-by: David Howells Signed-off-by: YueHaibing Signed-off-by: David Howells Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/rxrpc/call_accept.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/rxrpc/call_accept.c b/net/rxrpc/call_accept.c index 3028298ca561..62b1581d44a5 100644 --- a/net/rxrpc/call_accept.c +++ b/net/rxrpc/call_accept.c @@ -115,9 +115,9 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx, while (*pp) { parent = *pp; xcall = rb_entry(parent, struct rxrpc_call, sock_node); - if (user_call_ID < call->user_call_ID) + if (user_call_ID < xcall->user_call_ID) pp = &(*pp)->rb_left; - else if (user_call_ID > call->user_call_ID) + else if (user_call_ID > xcall->user_call_ID) pp = &(*pp)->rb_right; else goto id_in_use; -- GitLab From a766ccbf1d29db4f3a793131c2e986287757107c Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Mon, 16 Jul 2018 11:49:27 +0300 Subject: [PATCH 0545/1001] net/mlx5e: E-Switch, Initialize eswitch only if eswitch manager [ Upstream commit 5f5991f36dce1e69dd8bd7495763eec2e28f08e7 ] Execute mlx5_eswitch_init() only if we have MLX5_ESWITCH_MANAGER capabilities. Do the same for mlx5_eswitch_cleanup(). Fixes: a9f7705ffd66 ("net/mlx5: Unify vport manager capability check") Signed-off-by: Eli Cohen Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 667415301066..f697084937c3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1616,7 +1616,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev) int vport_num; int err; - if (!MLX5_VPORT_MANAGER(dev)) + if (!MLX5_ESWITCH_MANAGER(dev)) return 0; esw_info(dev, @@ -1689,7 +1689,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev) void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) { - if (!esw || !MLX5_VPORT_MANAGER(esw->dev)) + if (!esw || !MLX5_ESWITCH_MANAGER(esw->dev)) return; esw_info(esw->dev, "cleanup\n"); -- GitLab From 953f918d548b569d37467fadb7266d0cd93a9ff6 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 30 Jul 2018 14:27:15 -0700 Subject: [PATCH 0546/1001] squashfs: more metadata hardening commit d512584780d3e6a7cacb2f482834849453d444a1 upstream. Anatoly reports another squashfs fuzzing issue, where the decompression parameters themselves are in a compressed block. This causes squashfs_read_data() to be called in order to read the decompression options before the decompression stream having been set up, making squashfs go sideways. Reported-by: Anatoly Trosinenko Acked-by: Phillip Lougher Cc: stable@kernel.org Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/squashfs/block.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c index 2751476e6b6e..f098b9f1c396 100644 --- a/fs/squashfs/block.c +++ b/fs/squashfs/block.c @@ -167,6 +167,8 @@ int squashfs_read_data(struct super_block *sb, u64 index, int length, } if (compressed) { + if (!msblk->stream) + goto read_failure; length = squashfs_decompress(msblk, bh, b, offset, length, output); if (length < 0) -- GitLab From e7de67165efe052f1a05f4afae5b7cd4dc242b34 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 2 Aug 2018 08:43:35 -0700 Subject: [PATCH 0547/1001] squashfs: more metadata hardenings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 71755ee5350b63fb1f283de8561cdb61b47f4d1d upstream. The squashfs fragment reading code doesn't actually verify that the fragment is inside the fragment table. The end result _is_ verified to be inside the image when actually reading the fragment data, but before that is done, we may end up taking a page fault because the fragment table itself might not even exist. Another report from Anatoly and his endless squashfs image fuzzing. Reported-by: Анатолий Тросиненко Acked-by:: Phillip Lougher , Cc: Willy Tarreau Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/squashfs/fragment.c | 13 +++++++++---- fs/squashfs/squashfs_fs_sb.h | 1 + fs/squashfs/super.c | 5 +++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/fs/squashfs/fragment.c b/fs/squashfs/fragment.c index 86ad9a4b8c36..0681feab4a84 100644 --- a/fs/squashfs/fragment.c +++ b/fs/squashfs/fragment.c @@ -49,11 +49,16 @@ int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment, u64 *fragment_block) { struct squashfs_sb_info *msblk = sb->s_fs_info; - int block = SQUASHFS_FRAGMENT_INDEX(fragment); - int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); - u64 start_block = le64_to_cpu(msblk->fragment_index[block]); + int block, offset, size; struct squashfs_fragment_entry fragment_entry; - int size; + u64 start_block; + + if (fragment >= msblk->fragments) + return -EIO; + block = SQUASHFS_FRAGMENT_INDEX(fragment); + offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); + + start_block = le64_to_cpu(msblk->fragment_index[block]); size = squashfs_read_metadata(sb, &fragment_entry, &start_block, &offset, sizeof(fragment_entry)); diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h index 1da565cb50c3..ef69c31947bf 100644 --- a/fs/squashfs/squashfs_fs_sb.h +++ b/fs/squashfs/squashfs_fs_sb.h @@ -75,6 +75,7 @@ struct squashfs_sb_info { unsigned short block_log; long long bytes_used; unsigned int inodes; + unsigned int fragments; int xattr_ids; }; #endif diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index cf01e15a7b16..1516bb779b8d 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -175,6 +175,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) msblk->inode_table = le64_to_cpu(sblk->inode_table_start); msblk->directory_table = le64_to_cpu(sblk->directory_table_start); msblk->inodes = le32_to_cpu(sblk->inodes); + msblk->fragments = le32_to_cpu(sblk->fragments); flags = le16_to_cpu(sblk->flags); TRACE("Found valid superblock on %pg\n", sb->s_bdev); @@ -185,7 +186,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) TRACE("Filesystem size %lld bytes\n", msblk->bytes_used); TRACE("Block size %d\n", msblk->block_size); TRACE("Number of inodes %d\n", msblk->inodes); - TRACE("Number of fragments %d\n", le32_to_cpu(sblk->fragments)); + TRACE("Number of fragments %d\n", msblk->fragments); TRACE("Number of ids %d\n", le16_to_cpu(sblk->no_ids)); TRACE("sblk->inode_table_start %llx\n", msblk->inode_table); TRACE("sblk->directory_table_start %llx\n", msblk->directory_table); @@ -272,7 +273,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_export_op = &squashfs_export_ops; handle_fragments: - fragments = le32_to_cpu(sblk->fragments); + fragments = msblk->fragments; if (fragments == 0) goto check_directory_table; -- GitLab From c8159f9a1ae9c9ea76b389666a37bd9263a761cd Mon Sep 17 00:00:00 2001 From: Anton Vasilyev Date: Fri, 27 Jul 2018 18:50:42 +0300 Subject: [PATCH 0548/1001] can: ems_usb: Fix memory leak on ems_usb_disconnect() commit 72c05f32f4a5055c9c8fe889bb6903ec959c0aad upstream. ems_usb_probe() allocates memory for dev->tx_msg_buffer, but there is no its deallocation in ems_usb_disconnect(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Anton Vasilyev Cc: Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/usb/ems_usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index b00358297424..d0846ae9e0e4 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -1071,6 +1071,7 @@ static void ems_usb_disconnect(struct usb_interface *intf) usb_free_urb(dev->intr_urb); kfree(dev->intr_in_buffer); + kfree(dev->tx_msg_buffer); } } -- GitLab From 45c8178cf69ea21b6d0356b3e541c8e111ba6458 Mon Sep 17 00:00:00 2001 From: Jeremy Cline Date: Fri, 27 Jul 2018 22:43:01 +0000 Subject: [PATCH 0549/1001] net: socket: fix potential spectre v1 gadget in socketcall commit c8e8cd579bb4265651df8223730105341e61a2d1 upstream. 'call' is a user-controlled value, so sanitize the array index after the bounds check to avoid speculating past the bounds of the 'nargs' array. Found with the help of Smatch: net/socket.c:2508 __do_sys_socketcall() warn: potential spectre issue 'nargs' [r] (local cap) Cc: Josh Poimboeuf Cc: stable@vger.kernel.org Signed-off-by: Jeremy Cline Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/socket.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/socket.c b/net/socket.c index 8b2bef6cfe42..d27922639a20 100644 --- a/net/socket.c +++ b/net/socket.c @@ -89,6 +89,7 @@ #include #include #include +#include #include #include @@ -2443,6 +2444,7 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args) if (call < 1 || call > SYS_SENDMMSG) return -EINVAL; + call = array_index_nospec(call, SYS_SENDMMSG + 1); len = nargs[call]; if (len > sizeof(a)) -- GitLab From 34a938cd3ad45b5c6d67d83329ce1dcf239863a8 Mon Sep 17 00:00:00 2001 From: Jiang Biao Date: Wed, 18 Jul 2018 10:29:28 +0800 Subject: [PATCH 0550/1001] virtio_balloon: fix another race between migration and ballooning commit 89da619bc18d79bca5304724c11d4ba3b67ce2c6 upstream. Kernel panic when with high memory pressure, calltrace looks like, PID: 21439 TASK: ffff881be3afedd0 CPU: 16 COMMAND: "java" #0 [ffff881ec7ed7630] machine_kexec at ffffffff81059beb #1 [ffff881ec7ed7690] __crash_kexec at ffffffff81105942 #2 [ffff881ec7ed7760] crash_kexec at ffffffff81105a30 #3 [ffff881ec7ed7778] oops_end at ffffffff816902c8 #4 [ffff881ec7ed77a0] no_context at ffffffff8167ff46 #5 [ffff881ec7ed77f0] __bad_area_nosemaphore at ffffffff8167ffdc #6 [ffff881ec7ed7838] __node_set at ffffffff81680300 #7 [ffff881ec7ed7860] __do_page_fault at ffffffff8169320f #8 [ffff881ec7ed78c0] do_page_fault at ffffffff816932b5 #9 [ffff881ec7ed78f0] page_fault at ffffffff8168f4c8 [exception RIP: _raw_spin_lock_irqsave+47] RIP: ffffffff8168edef RSP: ffff881ec7ed79a8 RFLAGS: 00010046 RAX: 0000000000000246 RBX: ffffea0019740d00 RCX: ffff881ec7ed7fd8 RDX: 0000000000020000 RSI: 0000000000000016 RDI: 0000000000000008 RBP: ffff881ec7ed79a8 R8: 0000000000000246 R9: 000000000001a098 R10: ffff88107ffda000 R11: 0000000000000000 R12: 0000000000000000 R13: 0000000000000008 R14: ffff881ec7ed7a80 R15: ffff881be3afedd0 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 It happens in the pagefault and results in double pagefault during compacting pages when memory allocation fails. Analysed the vmcore, the page leads to second pagefault is corrupted with _mapcount=-256, but private=0. It's caused by the race between migration and ballooning, and lock missing in virtballoon_migratepage() of virtio_balloon driver. This patch fix the bug. Fixes: e22504296d4f64f ("virtio_balloon: introduce migration primitives to balloon pages") Cc: stable@vger.kernel.org Signed-off-by: Jiang Biao Signed-off-by: Huang Chong Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/virtio/virtio_balloon.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index f0b3a0b9d42f..36c9fbf70d44 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -490,7 +490,9 @@ static int virtballoon_migratepage(struct balloon_dev_info *vb_dev_info, tell_host(vb, vb->inflate_vq); /* balloon's page migration 2nd step -- deflate "page" */ + spin_lock_irqsave(&vb_dev_info->pages_lock, flags); balloon_page_delete(page); + spin_unlock_irqrestore(&vb_dev_info->pages_lock, flags); vb->num_pfns = VIRTIO_BALLOON_PAGES_PER_PAGE; set_page_pfns(vb, vb->pfns, page); tell_host(vb, vb->deflate_vq); -- GitLab From 7cf6b325f5545ba41953e2a49267632ea3a78af8 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sat, 21 Jul 2018 17:19:19 -0400 Subject: [PATCH 0551/1001] x86/apic: Future-proof the TSC_DEADLINE quirk for SKX commit d9e6dbcf28f383bf08e6a3180972f5722e514a54 upstream. All SKX with stepping higher than 4 support the TSC_DEADLINE, no matter the microcode version. Without this patch, upcoming SKX steppings will not be able to use their TSC_DEADLINE timer. Signed-off-by: Len Brown Cc: # v4.14+ Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: 616dd5872e ("x86/apic: Update TSC_DEADLINE quirk with additional SKX stepping") Link: http://lkml.kernel.org/r/d0c7129e509660be9ec6b233284b8d42d90659e8.1532207856.git.len.brown@intel.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/apic/apic.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index ebdcc368a2d3..f48a51335538 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -580,6 +580,9 @@ static u32 skx_deadline_rev(void) case 0x04: return 0x02000014; } + if (boot_cpu_data.x86_stepping > 4) + return 0; + return ~0U; } -- GitLab From c1a29c2d00c656fcc4abfeec5f4f92762e3c7437 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Sun, 22 Jul 2018 11:05:09 -0700 Subject: [PATCH 0552/1001] x86/entry/64: Remove %ebx handling from error_entry/exit commit b3681dd548d06deb2e1573890829dff4b15abf46 upstream. error_entry and error_exit communicate the user vs. kernel status of the frame using %ebx. This is unnecessary -- the information is in regs->cs. Just use regs->cs. This makes error_entry simpler and makes error_exit more robust. It also fixes a nasty bug. Before all the Spectre nonsense, the xen_failsafe_callback entry point returned like this: ALLOC_PT_GPREGS_ON_STACK SAVE_C_REGS SAVE_EXTRA_REGS ENCODE_FRAME_POINTER jmp error_exit And it did not go through error_entry. This was bogus: RBX contained garbage, and error_exit expected a flag in RBX. Fortunately, it generally contained *nonzero* garbage, so the correct code path was used. As part of the Spectre fixes, code was added to clear RBX to mitigate certain speculation attacks. Now, depending on kernel configuration, RBX got zeroed and, when running some Wine workloads, the kernel crashes. This was introduced by: commit 3ac6d8c787b8 ("x86/entry/64: Clear registers for exceptions/interrupts, to reduce speculation attack surface") With this patch applied, RBX is no longer needed as a flag, and the problem goes away. I suspect that malicious userspace could use this bug to crash the kernel even without the offending patch applied, though. [ Historical note: I wrote this patch as a cleanup before I was aware of the bug it fixed. ] [ Note to stable maintainers: this should probably get applied to all kernels. If you're nervous about that, a more conservative fix to add xorl %ebx,%ebx; incl %ebx before the jump to error_exit should also fix the problem. ] Reported-and-tested-by: M. Vefa Bicakci Signed-off-by: Andy Lutomirski Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: Dominik Brodowski Cc: Greg KH Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Juergen Gross Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: stable@vger.kernel.org Cc: xen-devel@lists.xenproject.org Fixes: 3ac6d8c787b8 ("x86/entry/64: Clear registers for exceptions/interrupts, to reduce speculation attack surface") Link: http://lkml.kernel.org/r/b5010a090d3586b2d6e06c7ad3ec5542d1241c45.1532282627.git.luto@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/entry/entry_64.S | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index f7bfa701219b..0fae7096ae23 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -933,7 +933,7 @@ ENTRY(\sym) call \do_sym - jmp error_exit /* %ebx: no swapgs flag */ + jmp error_exit .endif END(\sym) .endm @@ -1166,7 +1166,6 @@ END(paranoid_exit) /* * Save all registers in pt_regs, and switch GS if needed. - * Return: EBX=0: came from user mode; EBX=1: otherwise */ ENTRY(error_entry) UNWIND_HINT_FUNC @@ -1213,7 +1212,6 @@ ENTRY(error_entry) * for these here too. */ .Lerror_kernelspace: - incl %ebx leaq native_irq_return_iret(%rip), %rcx cmpq %rcx, RIP+8(%rsp) je .Lerror_bad_iret @@ -1247,28 +1245,20 @@ ENTRY(error_entry) /* * Pretend that the exception came from user mode: set up pt_regs - * as if we faulted immediately after IRET and clear EBX so that - * error_exit knows that we will be returning to user mode. + * as if we faulted immediately after IRET. */ mov %rsp, %rdi call fixup_bad_iret mov %rax, %rsp - decl %ebx jmp .Lerror_entry_from_usermode_after_swapgs END(error_entry) - -/* - * On entry, EBX is a "return to kernel mode" flag: - * 1: already in kernel mode, don't need SWAPGS - * 0: user gsbase is loaded, we need SWAPGS and standard preparation for return to usermode - */ ENTRY(error_exit) UNWIND_HINT_REGS DISABLE_INTERRUPTS(CLBR_ANY) TRACE_IRQS_OFF - testl %ebx, %ebx - jnz retint_kernel + testb $3, CS(%rsp) + jz retint_kernel jmp retint_user END(error_exit) -- GitLab From e5a16c6a6707f7ec905dc595cd3a7e37402735a2 Mon Sep 17 00:00:00 2001 From: Roman Kagan Date: Thu, 19 Jul 2018 21:59:07 +0300 Subject: [PATCH 0553/1001] kvm: x86: vmx: fix vpid leak commit 63aff65573d73eb8dda4732ad4ef222dd35e4862 upstream. VPID for the nested vcpu is allocated at vmx_create_vcpu whenever nested vmx is turned on with the module parameter. However, it's only freed if the L1 guest has executed VMXON which is not a given. As a result, on a system with nested==on every creation+deletion of an L1 vcpu without running an L2 guest results in leaking one vpid. Since the total number of vpids is limited to 64k, they can eventually get exhausted, preventing L2 from starting. Delay allocation of the L2 vpid until VMXON emulation, thus matching its freeing. Fixes: 5c614b3583e7b6dab0c86356fa36c2bcbb8322a0 Cc: stable@vger.kernel.org Signed-off-by: Roman Kagan Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/vmx.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 90747865205d..8d000fde1414 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -7354,6 +7354,8 @@ static int enter_vmx_operation(struct kvm_vcpu *vcpu) HRTIMER_MODE_REL_PINNED); vmx->nested.preemption_timer.function = vmx_preemption_timer_fn; + vmx->nested.vpid02 = allocate_vpid(); + vmx->nested.vmxon = true; return 0; @@ -9802,10 +9804,8 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) goto free_vmcs; } - if (nested) { + if (nested) nested_vmx_setup_ctls_msrs(vmx); - vmx->nested.vpid02 = allocate_vpid(); - } vmx->nested.posted_intr_nv = -1; vmx->nested.current_vmptr = -1ull; @@ -9822,7 +9822,6 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) return &vmx->vcpu; free_vmcs: - free_vpid(vmx->nested.vpid02); free_loaded_vmcs(vmx->loaded_vmcs); free_msrs: kfree(vmx->guest_msrs); -- GitLab From a1b5bcffe4a4e6740545fe8ab4a3381da148ce89 Mon Sep 17 00:00:00 2001 From: Yi Wang Date: Wed, 25 Jul 2018 10:26:19 +0800 Subject: [PATCH 0554/1001] audit: fix potential null dereference 'context->module.name' commit b305f7ed0f4f494ad6f3ef5667501535d5a8fa31 upstream. The variable 'context->module.name' may be null pointer when kmalloc return null, so it's better to check it before using to avoid null dereference. Another one more thing this patch does is using kstrdup instead of (kmalloc + strcpy), and signal a lost record via audit_log_lost. Cc: stable@vger.kernel.org # 4.11 Signed-off-by: Yi Wang Reviewed-by: Jiang Biao Reviewed-by: Richard Guy Briggs Signed-off-by: Paul Moore Signed-off-by: Greg Kroah-Hartman --- kernel/auditsc.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 677053a2fb57..76d789d6cea0 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1274,8 +1274,12 @@ static void show_special(struct audit_context *context, int *call_panic) break; case AUDIT_KERN_MODULE: audit_log_format(ab, "name="); - audit_log_untrustedstring(ab, context->module.name); - kfree(context->module.name); + if (context->module.name) { + audit_log_untrustedstring(ab, context->module.name); + kfree(context->module.name); + } else + audit_log_format(ab, "(null)"); + break; } audit_log_end(ab); @@ -2387,8 +2391,9 @@ void __audit_log_kern_module(char *name) { struct audit_context *context = current->audit_context; - context->module.name = kmalloc(strlen(name) + 1, GFP_KERNEL); - strcpy(context->module.name, name); + context->module.name = kstrdup(name, GFP_KERNEL); + if (!context->module.name) + audit_log_lost("out of memory in __audit_log_kern_module"); context->type = AUDIT_KERN_MODULE; } -- GitLab From 0eba9f5d3d4829fe5cc53abe90a73c33f47405af Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Thu, 2 Aug 2018 15:36:09 -0700 Subject: [PATCH 0555/1001] userfaultfd: remove uffd flags from vma->vm_flags if UFFD_EVENT_FORK fails commit 31e810aa1033a7db50a2746cd34a2432237f6420 upstream. The fix in commit 0cbb4b4f4c44 ("userfaultfd: clear the vma->vm_userfaultfd_ctx if UFFD_EVENT_FORK fails") cleared the vma->vm_userfaultfd_ctx but kept userfaultfd flags in vma->vm_flags that were copied from the parent process VMA. As the result, there is an inconsistency between the values of vma->vm_userfaultfd_ctx.ctx and vma->vm_flags which triggers BUG_ON in userfaultfd_release(). Clearing the uffd flags from vma->vm_flags in case of UFFD_EVENT_FORK failure resolves the issue. Link: http://lkml.kernel.org/r/1532931975-25473-1-git-send-email-rppt@linux.vnet.ibm.com Fixes: 0cbb4b4f4c44 ("userfaultfd: clear the vma->vm_userfaultfd_ctx if UFFD_EVENT_FORK fails") Signed-off-by: Mike Rapoport Reported-by: syzbot+121be635a7a35ddb7dcb@syzkaller.appspotmail.com Cc: Andrea Arcangeli Cc: Eric Biggers Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/userfaultfd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index f6ed92524a03..3eda623e4cb4 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -628,8 +628,10 @@ static void userfaultfd_event_wait_completion(struct userfaultfd_ctx *ctx, /* the various vma->vm_userfaultfd_ctx still points to it */ down_write(&mm->mmap_sem); for (vma = mm->mmap; vma; vma = vma->vm_next) - if (vma->vm_userfaultfd_ctx.ctx == release_new_ctx) + if (vma->vm_userfaultfd_ctx.ctx == release_new_ctx) { vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX; + vma->vm_flags &= ~(VM_UFFD_WP | VM_UFFD_MISSING); + } up_write(&mm->mmap_sem); userfaultfd_ctx_put(release_new_ctx); -- GitLab From 4aa0acf290643c8161a0b6af4b5083a000124ff1 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 17 Jul 2018 13:43:56 +0300 Subject: [PATCH 0556/1001] iwlwifi: add more card IDs for 9000 series commit 0a5257bc6d89c2ae69b9bf955679cb4f89261874 upstream. Add new device IDs for the 9000 series. Cc: stable@vger.kernel.org # 4.14 Signed-off-by: Emmanuel Grumbach Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/intel/iwlwifi/cfg/9000.c | 69 +++++++++++++++++++ .../net/wireless/intel/iwlwifi/iwl-config.h | 5 ++ drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 22 ++++++ 3 files changed, 96 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index 73da5e63a609..2c80c722feca 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -177,6 +177,17 @@ const struct iwl_cfg iwl9260_2ac_cfg = { .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, }; +const struct iwl_cfg iwl9260_killer_2ac_cfg = { + .name = "Killer (R) Wireless-AC 1550 Wireless Network Adapter (9260NGW)", + .fw_name_pre = IWL9260A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9260B_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + const struct iwl_cfg iwl9270_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9270", .fw_name_pre = IWL9260A_FW_PRE, @@ -266,6 +277,34 @@ const struct iwl_cfg iwl9560_2ac_cfg_soc = { .soc_latency = 5000, }; +const struct iwl_cfg iwl9560_killer_2ac_cfg_soc = { + .name = "Killer (R) Wireless-AC 1550i Wireless Network Adapter (9560NGW)", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, +}; + +const struct iwl_cfg iwl9560_killer_s_2ac_cfg_soc = { + .name = "Killer (R) Wireless-AC 1550s Wireless Network Adapter (9560NGW)", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, +}; + const struct iwl_cfg iwl9460_2ac_cfg_shared_clk = { .name = "Intel(R) Dual Band Wireless AC 9460", .fw_name_pre = IWL9000A_FW_PRE, @@ -326,6 +365,36 @@ const struct iwl_cfg iwl9560_2ac_cfg_shared_clk = { .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK }; +const struct iwl_cfg iwl9560_killer_2ac_cfg_shared_clk = { + .name = "Killer (R) Wireless-AC 1550i Wireless Network Adapter (9560NGW)", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, + .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK +}; + +const struct iwl_cfg iwl9560_killer_s_2ac_cfg_shared_clk = { + .name = "Killer (R) Wireless-AC 1550s Wireless Network Adapter (9560NGW)", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, + .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK +}; + MODULE_FIRMWARE(IWL9000A_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL9000B_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL9000RFB_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 85fe1a928adc..70f3c327eb4a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -470,6 +470,7 @@ extern const struct iwl_cfg iwl8265_2ac_sdio_cfg; extern const struct iwl_cfg iwl4165_2ac_sdio_cfg; extern const struct iwl_cfg iwl9160_2ac_cfg; extern const struct iwl_cfg iwl9260_2ac_cfg; +extern const struct iwl_cfg iwl9260_killer_2ac_cfg; extern const struct iwl_cfg iwl9270_2ac_cfg; extern const struct iwl_cfg iwl9460_2ac_cfg; extern const struct iwl_cfg iwl9560_2ac_cfg; @@ -477,10 +478,14 @@ extern const struct iwl_cfg iwl9460_2ac_cfg_soc; extern const struct iwl_cfg iwl9461_2ac_cfg_soc; extern const struct iwl_cfg iwl9462_2ac_cfg_soc; extern const struct iwl_cfg iwl9560_2ac_cfg_soc; +extern const struct iwl_cfg iwl9560_killer_2ac_cfg_soc; +extern const struct iwl_cfg iwl9560_killer_s_2ac_cfg_soc; extern const struct iwl_cfg iwl9460_2ac_cfg_shared_clk; extern const struct iwl_cfg iwl9461_2ac_cfg_shared_clk; extern const struct iwl_cfg iwl9462_2ac_cfg_shared_clk; extern const struct iwl_cfg iwl9560_2ac_cfg_shared_clk; +extern const struct iwl_cfg iwl9560_killer_2ac_cfg_shared_clk; +extern const struct iwl_cfg iwl9560_killer_s_2ac_cfg_shared_clk; extern const struct iwl_cfg iwla000_2ac_cfg_hr; extern const struct iwl_cfg iwla000_2ac_cfg_hr_cdb; extern const struct iwl_cfg iwla000_2ac_cfg_jf; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 9a8605abb00a..4cbc6cb8bf89 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -543,6 +543,9 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x2526, 0x1210, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x1410, iwl9270_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x1420, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2526, 0x1550, iwl9260_killer_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2526, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x1610, iwl9270_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x2030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x2034, iwl9560_2ac_cfg_soc)}, @@ -552,6 +555,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x2526, 0x40A4, iwl9460_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x4234, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2526, 0x8014, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0xA014, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x271B, 0x0010, iwl9160_2ac_cfg)}, {IWL_PCI_DEVICE(0x271B, 0x0014, iwl9160_2ac_cfg)}, @@ -576,6 +580,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x2720, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2720, 0x1030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x2030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x4030, iwl9560_2ac_cfg)}, @@ -602,6 +608,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x30DC, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x30DC, 0x1030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x30DC, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x2030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x4030, iwl9560_2ac_cfg_soc)}, @@ -628,6 +636,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x31DC, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x31DC, 0x1030, iwl9560_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x31DC, 0x1551, iwl9560_killer_s_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x1552, iwl9560_killer_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x2030, iwl9560_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x2034, iwl9560_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x4030, iwl9560_2ac_cfg_shared_clk)}, @@ -654,6 +664,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x34F0, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x34F0, 0x1030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x34F0, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x34F0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x34F0, 0x2030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x34F0, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x34F0, 0x4030, iwl9560_2ac_cfg_soc)}, @@ -680,6 +692,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x3DF0, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x3DF0, 0x1030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x3DF0, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3DF0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x3DF0, 0x2030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x3DF0, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x3DF0, 0x4030, iwl9560_2ac_cfg_soc)}, @@ -706,6 +720,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x43F0, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x43F0, 0x1030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x43F0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x2030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x4030, iwl9560_2ac_cfg_soc)}, @@ -741,6 +757,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x9DF0, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x9DF0, 0x1030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x9DF0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x2010, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x2030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x2034, iwl9560_2ac_cfg_soc)}, @@ -769,6 +787,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0xA0F0, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0xA0F0, 0x1030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0xA0F0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x2030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x4030, iwl9560_2ac_cfg_soc)}, @@ -795,6 +815,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0xA370, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0xA370, 0x1030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0xA370, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x2030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x4030, iwl9560_2ac_cfg_soc)}, -- GitLab From 65be9cbe1224f1fe51591b44e3d35603b81b595c Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Wed, 11 Jul 2018 11:23:52 +0300 Subject: [PATCH 0557/1001] RDMA/uverbs: Expand primary and alt AV port checks commit addb8a6559f0f8b5a37582b7ca698358445a55bf upstream. The commit cited below checked that the port numbers provided in the primary and alt AVs are legal. That is sufficient to prevent a kernel panic. However, it is not sufficient for correct operation. In Linux, AVs (both primary and alt) must be completely self-described. We do not accept an AV from userspace without an embedded port number. (This has been the case since kernel 3.14 commit dbf727de7440 ("IB/core: Use GID table in AH creation and dmac resolution")). For the primary AV, this embedded port number must match the port number specified with IB_QP_PORT. We also expect the port number embedded in the alt AV to match the alt_port_num value passed by the userspace driver in the modify_qp command base structure. Add these checks to modify_qp. Cc: # 4.16 Fixes: 5d4c05c3ee36 ("RDMA/uverbs: Sanitize user entered port numbers prior to access it") Signed-off-by: Jack Morgenstein Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/uverbs_cmd.c | 59 +++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index b8229d7b0ff5..f836ed1dd300 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -1981,15 +1981,64 @@ static int modify_qp(struct ib_uverbs_file *file, goto release_qp; } - if ((cmd->base.attr_mask & IB_QP_AV) && - !rdma_is_port_valid(qp->device, cmd->base.dest.port_num)) { - ret = -EINVAL; - goto release_qp; + if ((cmd->base.attr_mask & IB_QP_AV)) { + if (!rdma_is_port_valid(qp->device, cmd->base.dest.port_num)) { + ret = -EINVAL; + goto release_qp; + } + + if (cmd->base.attr_mask & IB_QP_STATE && + cmd->base.qp_state == IB_QPS_RTR) { + /* We are in INIT->RTR TRANSITION (if we are not, + * this transition will be rejected in subsequent checks). + * In the INIT->RTR transition, we cannot have IB_QP_PORT set, + * but the IB_QP_STATE flag is required. + * + * Since kernel 3.14 (commit dbf727de7440), the uverbs driver, + * when IB_QP_AV is set, has required inclusion of a valid + * port number in the primary AV. (AVs are created and handled + * differently for infiniband and ethernet (RoCE) ports). + * + * Check the port number included in the primary AV against + * the port number in the qp struct, which was set (and saved) + * in the RST->INIT transition. + */ + if (cmd->base.dest.port_num != qp->real_qp->port) { + ret = -EINVAL; + goto release_qp; + } + } else { + /* We are in SQD->SQD. (If we are not, this transition will + * be rejected later in the verbs layer checks). + * Check for both IB_QP_PORT and IB_QP_AV, these can be set + * together in the SQD->SQD transition. + * + * If only IP_QP_AV was set, add in IB_QP_PORT as well (the + * verbs layer driver does not track primary port changes + * resulting from path migration. Thus, in SQD, if the primary + * AV is modified, the primary port should also be modified). + * + * Note that in this transition, the IB_QP_STATE flag + * is not allowed. + */ + if (((cmd->base.attr_mask & (IB_QP_AV | IB_QP_PORT)) + == (IB_QP_AV | IB_QP_PORT)) && + cmd->base.port_num != cmd->base.dest.port_num) { + ret = -EINVAL; + goto release_qp; + } + if ((cmd->base.attr_mask & (IB_QP_AV | IB_QP_PORT)) + == IB_QP_AV) { + cmd->base.attr_mask |= IB_QP_PORT; + cmd->base.port_num = cmd->base.dest.port_num; + } + } } if ((cmd->base.attr_mask & IB_QP_ALT_PATH) && (!rdma_is_port_valid(qp->device, cmd->base.alt_port_num) || - !rdma_is_port_valid(qp->device, cmd->base.alt_dest.port_num))) { + !rdma_is_port_valid(qp->device, cmd->base.alt_dest.port_num) || + cmd->base.alt_port_num != cmd->base.alt_dest.port_num)) { ret = -EINVAL; goto release_qp; } -- GitLab From 51ef850c78bb311e7bc5e6aada5756fbf71d6b08 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 13 Jul 2018 16:12:32 +0800 Subject: [PATCH 0558/1001] crypto: padlock-aes - Fix Nano workaround data corruption commit 46d8c4b28652d35dc6cfb5adf7f54e102fc04384 upstream. This was detected by the self-test thanks to Ard's chunking patch. I finally got around to testing this out on my ancient Via box. It turns out that the workaround got the assembly wrong and we end up doing count + initial cycles of the loop instead of just count. This obviously causes corruption, either by overwriting the source that is yet to be processed, or writing over the end of the buffer. On CPUs that don't require the workaround only ECB is affected. On Nano CPUs both ECB and CBC are affected. This patch fixes it by doing the subtraction prior to the assembly. Fixes: a76c1c23d0c3 ("crypto: padlock-aes - work around Nano CPU...") Cc: Reported-by: Jamie Heilman Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/padlock-aes.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index c939f18f70cc..7685f557dcc0 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -266,6 +266,8 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, return; } + count -= initial; + if (initial) asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ : "+S"(input), "+D"(output) @@ -273,7 +275,7 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ : "+S"(input), "+D"(output) - : "d"(control_word), "b"(key), "c"(count - initial)); + : "d"(control_word), "b"(key), "c"(count)); } static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, @@ -284,6 +286,8 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, if (count < cbc_fetch_blocks) return cbc_crypt(input, output, key, iv, control_word, count); + count -= initial; + if (initial) asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ : "+S" (input), "+D" (output), "+a" (iv) @@ -291,7 +295,7 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" /* rep xcryptcbc */ : "+S" (input), "+D" (output), "+a" (iv) - : "d" (control_word), "b" (key), "c" (count-initial)); + : "d" (control_word), "b" (key), "c" (count)); return iv; } -- GitLab From 1a08888316d2d69d772391597fadde90d1cf1483 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 24 Jul 2018 15:36:01 +0200 Subject: [PATCH 0559/1001] drm/vc4: Reset ->{x, y}_scaling[1] when dealing with uniplanar formats commit a6a00918d4ad8718c3ccde38c02cec17f116b2fd upstream. This is needed to ensure ->is_unity is correct when the plane was previously configured to output a multi-planar format with scaling enabled, and is then being reconfigured to output a uniplanar format. Fixes: fc04023fafec ("drm/vc4: Add support for YUV planes.") Cc: Signed-off-by: Boris Brezillon Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20180724133601.32114-1-boris.brezillon@bootlin.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/vc4/vc4_plane.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 77c56264c05b..17590cb2b80d 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -352,6 +352,9 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) vc4_state->x_scaling[0] = VC4_SCALING_TPZ; if (vc4_state->y_scaling[0] == VC4_SCALING_NONE) vc4_state->y_scaling[0] = VC4_SCALING_TPZ; + } else { + vc4_state->x_scaling[1] = VC4_SCALING_NONE; + vc4_state->y_scaling[1] = VC4_SCALING_NONE; } vc4_state->is_unity = (vc4_state->x_scaling[0] == VC4_SCALING_NONE && -- GitLab From b4653a3ea3d7e68d4118f0476c72f70288c6c7f4 Mon Sep 17 00:00:00 2001 From: Tony Battersby Date: Thu, 12 Jul 2018 16:30:45 -0400 Subject: [PATCH 0560/1001] scsi: sg: fix minor memory leak in error path commit c170e5a8d222537e98aa8d4fddb667ff7a2ee114 upstream. Fix a minor memory leak when there is an error opening a /dev/sg device. Fixes: cc833acbee9d ("sg: O_EXCL and other lock handling") Cc: Reviewed-by: Ewan D. Milne Signed-off-by: Tony Battersby Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 4d49fb8f2bbc..3a406b40f150 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -2186,6 +2186,7 @@ sg_add_sfp(Sg_device * sdp) write_lock_irqsave(&sdp->sfd_lock, iflags); if (atomic_read(&sdp->detaching)) { write_unlock_irqrestore(&sdp->sfd_lock, iflags); + kfree(sfp); return ERR_PTR(-ENODEV); } list_add_tail(&sfp->sfd_siblings, &sdp->sfds); -- GitLab From 2ae6c0413b4768f9d8fc6f718a732f9dae014b67 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 6 Aug 2018 16:20:52 +0200 Subject: [PATCH 0561/1001] Linux 4.14.61 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5b48ec630990..4bd65eabd298 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 60 +SUBLEVEL = 61 EXTRAVERSION = NAME = Petit Gorille -- GitLab From 218a1100c41882b9affd50b0a25a6b2ce804b16e Mon Sep 17 00:00:00 2001 From: Anna-Maria Gleixner Date: Tue, 31 Jul 2018 18:13:58 +0200 Subject: [PATCH 0562/1001] nohz: Fix local_timer_softirq_pending() local_timer_softirq_pending() checks whether the timer softirq is pending with: local_softirq_pending() & TIMER_SOFTIRQ. This is wrong because TIMER_SOFTIRQ is the softirq number and not a bitmask. So the test checks for the wrong bit. Use BIT(TIMER_SOFTIRQ) instead. Change-Id: I48cb96a585d1f60d5ad8aaceef077eac08ff37d0 Fixes: 5d62c183f9e9 ("nohz: Prevent a timer interrupt storm in tick_nohz_stop_sched_tick()") Signed-off-by: Anna-Maria Gleixner Signed-off-by: Thomas Gleixner Reviewed-by: Paul E. McKenney Reviewed-by: Daniel Bristot de Oliveira Acked-by: Frederic Weisbecker Cc: bigeasy@linutronix.de Cc: peterz@infradead.org Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/20180731161358.29472-1-anna-maria@linutronix.de Git-commit: 80d20d35af1edd632a5e7a3b9c0ab7ceff92769e Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Isaac J. Manjarres --- kernel/time/tick-sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 0ae8aa5a8911..c2e975ad25cc 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -682,7 +682,7 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) static inline bool local_timer_softirq_pending(void) { - return local_softirq_pending() & TIMER_SOFTIRQ; + return local_softirq_pending() & BIT(TIMER_SOFTIRQ); } static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, -- GitLab From b20e9b05e7ec56ec52507002fb0ab693f86dc812 Mon Sep 17 00:00:00 2001 From: Carter Cooper Date: Tue, 29 May 2018 15:15:22 -0600 Subject: [PATCH 0563/1001] msm: kgsl: Store GMU firmware image in the GMU device structure Use the struct firmware structure for storing the GMU firmware image. Parse the firmware until out of data rather than reading the number of blocks present in the firmware. Change-Id: I6d8aef7a088f26be7fd6f092eedbbe021bf76f77 Signed-off-by: Carter Cooper --- drivers/gpu/msm/adreno_a6xx_gmu.c | 84 +++++++++++++------------------ drivers/gpu/msm/kgsl_gmu.c | 26 ++-------- drivers/gpu/msm/kgsl_gmu.h | 14 ++++-- 3 files changed, 50 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index bbfab64bddf9..2a4e3c5b4a26 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -472,12 +472,6 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) return 0; } -/* - * Gmu FW header format: - * <32-bit start addr> <32-bit size> <32-bit pad0> <32-bit pad1> - */ -#define GMU_FW_HEADER_SIZE 4 - #define GMU_ITCM_VA_START 0x0 #define GMU_ITCM_VA_END (GMU_ITCM_VA_START + 0x4000) /* 16 KB */ @@ -490,50 +484,52 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) static int load_gmu_fw(struct kgsl_device *device) { struct gmu_device *gmu = KGSL_GMU_DEVICE(device); - uint32_t *fwptr = gmu->fw_image->hostptr; - int i, j; - int start_addr, size_in_bytes, num_dwords, tcm_slot, num_records; + uint8_t *fw = (uint8_t *)gmu->fw_image->data; + struct gmu_block_header *blk; + uint32_t *fwptr; + int j; + int tcm_slot; + + while (fw < (uint8_t *)gmu->fw_image->data + gmu->fw_image->size) { + blk = (struct gmu_block_header *)fw; + fw += sizeof(*blk); + + /* Don't deal with zero size blocks */ + if (blk->size == 0) + continue; + + if ((blk->addr >= GMU_ITCM_VA_START) && + (blk->addr < GMU_ITCM_VA_END)) { + fwptr = (uint32_t *)fw; + tcm_slot = (blk->addr - GMU_ITCM_VA_START) + / sizeof(uint32_t); - /* - * Read first record. pad0 field of first record contains - * number of records in the image. - */ - num_records = fwptr[2]; - for (i = 0; i < num_records; i++) { - start_addr = fwptr[0]; - size_in_bytes = fwptr[1]; - num_dwords = size_in_bytes / sizeof(uint32_t); - fwptr += GMU_FW_HEADER_SIZE; - - if ((start_addr >= GMU_ITCM_VA_START) && - (start_addr < GMU_ITCM_VA_END)) { - tcm_slot = start_addr / sizeof(uint32_t); - - for (j = 0; j < num_dwords; j++) + for (j = 0; j < blk->size / sizeof(uint32_t); j++) gmu_core_regwrite(device, A6XX_GMU_CM3_ITCM_START + tcm_slot + j, fwptr[j]); - } else if ((start_addr >= GMU_DTCM_VA_START) && - (start_addr < GMU_DTCM_VA_END)) { - tcm_slot = (start_addr - GMU_DTCM_VA_START) + } else if ((blk->addr >= GMU_DTCM_VA_START) && + (blk->addr < GMU_DTCM_VA_END)) { + fwptr = (uint32_t *)fw; + tcm_slot = (blk->addr - GMU_DTCM_VA_START) / sizeof(uint32_t); - for (j = 0; j < num_dwords; j++) + for (j = 0; j < blk->size / sizeof(uint32_t); j++) gmu_core_regwrite(device, A6XX_GMU_CM3_DTCM_START + tcm_slot + j, fwptr[j]); - } else if ((start_addr >= GMU_ICACHE_VA_START) && - (start_addr < GMU_ICACHE_VA_END)) { - if (!is_cached_fw_size_valid(size_in_bytes)) { + } else if ((blk->addr >= GMU_ICACHE_VA_START) && + (blk->addr < GMU_ICACHE_VA_END)) { + if (!is_cached_fw_size_valid(blk->size)) { dev_err(&gmu->pdev->dev, "GMU firmware size too big\n"); return -EINVAL; } - memcpy(gmu->icache_mem->hostptr, fwptr, size_in_bytes); + memcpy(gmu->icache_mem->hostptr, fw, blk->size); } - fwptr += num_dwords; + fw += blk->size; } /* Proceed only after the FW is written */ @@ -1044,11 +1040,10 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, */ static int a6xx_gmu_load_firmware(struct kgsl_device *device) { - const struct firmware *fw = NULL; const struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct gmu_device *gmu = KGSL_GMU_DEVICE(device); const struct adreno_gpu_core *gpucore = adreno_dev->gpucore; - int image_size, ret = -EINVAL; + int ret = -EINVAL; /* there is no GMU */ if (!gmu_core_isenabled(device)) @@ -1061,22 +1056,11 @@ static int a6xx_gmu_load_firmware(struct kgsl_device *device) if (gpucore->gpmufw_name == NULL) return -EINVAL; - ret = request_firmware(&fw, gpucore->gpmufw_name, device->dev); - if (ret || fw == NULL) { + ret = request_firmware(&gmu->fw_image, gpucore->gpmufw_name, + device->dev); + if (ret || gmu->fw_image == NULL) KGSL_CORE_ERR("request_firmware (%s) failed: %d\n", gpucore->gpmufw_name, ret); - return ret; - } - - image_size = PAGE_ALIGN(fw->size); - - ret = allocate_gmu_image(gmu, image_size); - - /* load into shared memory with GMU */ - if (!ret) - memcpy(gmu->fw_image->hostptr, fw->data, fw->size); - - release_firmware(fw); return ret; } diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index b47246533d42..f88e074dfe31 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -235,26 +235,6 @@ static struct gmu_memdesc *allocate_gmu_kmem(struct gmu_device *gmu, return md; } -/* - * allocate_gmu_image() - allocates & maps memory for FW image, the size - * shall come from the loaded f/w file. - * @gmu: Pointer to GMU device - * @size: Requested allocation size - */ -int allocate_gmu_image(struct gmu_device *gmu, unsigned int size) -{ - /* Allocates & maps memory for GMU FW */ - gmu->fw_image = allocate_gmu_kmem(gmu, GMU_NONCACHED_KERNEL, size, - (IOMMU_READ | IOMMU_PRIV)); - if (IS_ERR(gmu->fw_image)) { - dev_err(&gmu->pdev->dev, - "GMU firmware image allocation failed\n"); - return -EINVAL; - } - - return 0; -} - /* Checks if cached fw code size falls within the cached code segment range */ bool is_cached_fw_size_valid(uint32_t size_in_bytes) { @@ -360,7 +340,6 @@ static void gmu_kmem_close(struct gmu_device *gmu) gmu->hfi_mem = NULL; gmu->bw_mem = NULL; gmu->dump_mem = NULL; - gmu->fw_image = NULL; gmu->gmu_log = NULL; /* Unmap all memories in GMU kernel memory pool */ @@ -1629,6 +1608,11 @@ static void gmu_remove(struct kgsl_device *device) gmu->pcl = 0; } + if (gmu->fw_image) { + release_firmware(gmu->fw_image); + gmu->fw_image = NULL; + } + gmu_memory_close(gmu); for (i = 0; i < MAX_GMU_CLKS; i++) { diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h index 4b003a8a659e..8f3adf9332ce 100644 --- a/drivers/gpu/msm/kgsl_gmu.h +++ b/drivers/gpu/msm/kgsl_gmu.h @@ -14,6 +14,7 @@ #define __KGSL_GMU_H #include "kgsl_gmu_core.h" +#include #include "kgsl_hfi.h" #define MAX_GMUFW_SIZE 0x2000 /* in bytes */ @@ -55,6 +56,14 @@ #define OOB_BOOT_OPTION 0 #define OOB_SLUMBER_OPTION 1 +/* Gmu FW block header format */ +struct gmu_block_header { + uint32_t addr; + uint32_t size; + uint32_t type; + uint32_t value; +}; + /* For GMU Logs*/ #define LOGMEM_SIZE SZ_4K @@ -112,7 +121,7 @@ enum gmu_load_mode { * @reg_phys: GMU CSR physical address * @reg_len: GMU CSR range * @gmu_interrupt_num: GMU interrupt number - * @fw_image: descriptor of GMU memory that has GMU image in it + * @fw_image: GMU FW image * @hfi_mem: pointer to HFI shared memory * @bw_mem: pointer to BW data indirect buffer memory * @dump_mem: pointer to GMU debug dump memory @@ -148,7 +157,7 @@ struct gmu_device { unsigned long reg_phys; unsigned int reg_len; unsigned int gmu_interrupt_num; - struct gmu_memdesc *fw_image; + const struct firmware *fw_image; struct gmu_memdesc *hfi_mem; struct gmu_memdesc *bw_mem; struct gmu_memdesc *dump_mem; @@ -177,6 +186,5 @@ struct gmu_device { }; bool is_cached_fw_size_valid(uint32_t size_in_bytes); -int allocate_gmu_image(struct gmu_device *gmu, unsigned int size); #endif /* __KGSL_GMU_H */ -- GitLab From d29bd29a58cfb800aa864a4011164ec24bad4084 Mon Sep 17 00:00:00 2001 From: Heesub Shin Date: Mon, 7 Jan 2013 11:10:13 +0900 Subject: [PATCH 0564/1001] cma: redirect page allocation to CMA CMA pages are designed to be used as fallback for movable allocations and cannot be used for non-movable allocations. If CMA pages are utilized poorly, non-movable allocations may end up getting starved if all regular movable pages are allocated and the only pages left are CMA. Always using CMA pages first creates unacceptable performance problems. As a midway alternative, use CMA pages for certain userspace allocations. The userspace pages can be migrated or dropped quickly which giving decent utilization. Change-Id: I6165dda01b705309eebabc6dfa67146b7a95c174 Signed-off-by: Kyungmin Park Signed-off-by: Heesub Shin [lmark@codeaurora.org: resolve conflicts relating to MIGRATE_HIGHATOMIC and some other trivial merge conflicts.] Signed-off-by: Liam Mark Signed-off-by: Vinayak Menon Signed-off-by: Charan Teja Reddy --- include/linux/gfp.h | 3 ++- include/linux/highmem.h | 5 ++++ include/linux/mmzone.h | 4 +++ mm/page_alloc.c | 56 +++++++++++++++++++++++++++++++---------- 4 files changed, 54 insertions(+), 14 deletions(-) diff --git a/include/linux/gfp.h b/include/linux/gfp.h index b041f94678de..fb62fbd33194 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -40,6 +40,7 @@ struct vm_area_struct; #define ___GFP_DIRECT_RECLAIM 0x400000u #define ___GFP_WRITE 0x800000u #define ___GFP_KSWAPD_RECLAIM 0x1000000u +#define ___GFP_CMA 0x4000000u #ifdef CONFIG_LOCKDEP #define ___GFP_NOLOCKDEP 0x2000000u #else @@ -58,8 +59,8 @@ struct vm_area_struct; #define __GFP_HIGHMEM ((__force gfp_t)___GFP_HIGHMEM) #define __GFP_DMA32 ((__force gfp_t)___GFP_DMA32) #define __GFP_MOVABLE ((__force gfp_t)___GFP_MOVABLE) /* ZONE_MOVABLE allowed */ +#define __GFP_CMA ((__force gfp_t)___GFP_CMA) #define GFP_ZONEMASK (__GFP_DMA|__GFP_HIGHMEM|__GFP_DMA32|__GFP_MOVABLE) - /* * Page mobility and placement hints * diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 4db2f34c4fe5..b471a881f326 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -193,7 +193,12 @@ static inline struct page * alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma, unsigned long vaddr) { +#ifndef CONFIG_CMA return __alloc_zeroed_user_highpage(__GFP_MOVABLE, vma, vaddr); +#else + return __alloc_zeroed_user_highpage(__GFP_MOVABLE|__GFP_CMA, vma, + vaddr); +#endif } static inline void clear_highpage(struct page *page) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index da6bb5bb3658..198ad34fc91a 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -388,6 +388,10 @@ struct zone { struct pglist_data *zone_pgdat; struct per_cpu_pageset __percpu *pageset; +#ifdef CONFIG_CMA + bool cma_alloc; +#endif + #ifndef CONFIG_SPARSEMEM /* * Flags for a pageblock_nr_pages block. See pageblock-flags.h. diff --git a/mm/page_alloc.c b/mm/page_alloc.c index d1c2ffd7960b..5077bb37dbfd 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2321,13 +2321,29 @@ static struct page *__rmqueue(struct zone *zone, unsigned int order, retry: page = __rmqueue_smallest(zone, order, migratetype); - if (unlikely(!page)) { - if (migratetype == MIGRATE_MOVABLE) - page = __rmqueue_cma_fallback(zone, order); - if (!page && __rmqueue_fallback(zone, order, migratetype)) - goto retry; - } + if (unlikely(!page) && __rmqueue_fallback(zone, order, migratetype)) + goto retry; + + trace_mm_page_alloc_zone_locked(page, order, migratetype); + return page; +} + +static struct page *__rmqueue_cma(struct zone *zone, unsigned int order, + int migratetype) +{ + struct page *page = 0; + +retry: +#ifdef CONFIG_CMA + if (migratetype == MIGRATE_MOVABLE && !zone->cma_alloc) + page = __rmqueue_cma_fallback(zone, order); + else +#endif + page = __rmqueue_smallest(zone, order, migratetype); + + if (unlikely(!page) && __rmqueue_fallback(zone, order, migratetype)) + goto retry; trace_mm_page_alloc_zone_locked(page, order, migratetype); return page; @@ -2340,13 +2356,19 @@ static struct page *__rmqueue(struct zone *zone, unsigned int order, */ static int rmqueue_bulk(struct zone *zone, unsigned int order, unsigned long count, struct list_head *list, - int migratetype, bool cold) + int migratetype, bool cold, int cma) { int i, alloced = 0; spin_lock(&zone->lock); for (i = 0; i < count; ++i) { - struct page *page = __rmqueue(zone, order, migratetype); + struct page *page; + + if (cma) + page = __rmqueue_cma(zone, order, migratetype); + else + page = __rmqueue(zone, order, migratetype); + if (unlikely(page == NULL)) break; @@ -2771,7 +2793,7 @@ static inline void zone_statistics(struct zone *preferred_zone, struct zone *z) /* Remove page from the per-cpu list, caller must protect the list */ static struct page *__rmqueue_pcplist(struct zone *zone, int migratetype, bool cold, struct per_cpu_pages *pcp, - struct list_head *list) + struct list_head *list, gfp_t gfp_flags) { struct page *page; @@ -2779,7 +2801,8 @@ static struct page *__rmqueue_pcplist(struct zone *zone, int migratetype, if (list_empty(list)) { pcp->count += rmqueue_bulk(zone, 0, pcp->batch, list, - migratetype, cold); + migratetype, cold, + gfp_flags & __GFP_CMA); if (unlikely(list_empty(list))) return NULL; } @@ -2810,7 +2833,8 @@ static struct page *rmqueue_pcplist(struct zone *preferred_zone, local_irq_save(flags); pcp = &this_cpu_ptr(zone->pageset)->pcp; list = &pcp->lists[migratetype]; - page = __rmqueue_pcplist(zone, migratetype, cold, pcp, list); + page = __rmqueue_pcplist(zone, migratetype, cold, pcp, list, + gfp_flags); if (page) { __count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order); zone_statistics(preferred_zone, zone); @@ -2851,8 +2875,12 @@ struct page *rmqueue(struct zone *preferred_zone, if (page) trace_mm_page_alloc_zone_locked(page, order, migratetype); } - if (!page) - page = __rmqueue(zone, order, migratetype); + if (!page) { + if (gfp_flags & __GFP_CMA) + page = __rmqueue_cma(zone, order, migratetype); + else + page = __rmqueue(zone, order, migratetype); + } } while (page && check_new_pages(page, order)); spin_unlock(&zone->lock); if (!page) @@ -7638,6 +7666,7 @@ int alloc_contig_range(unsigned long start, unsigned long end, if (ret) return ret; + cc.zone->cma_alloc = 1; /* * In case of -EBUSY, we'd like to know which page causes problem. * So, just fall through. test_pages_isolated() has a tracepoint @@ -7720,6 +7749,7 @@ int alloc_contig_range(unsigned long start, unsigned long end, done: undo_isolate_page_range(pfn_max_align_down(start), pfn_max_align_up(end), migratetype); + cc.zone->cma_alloc = 0; return ret; } -- GitLab From 79360d60fe4ecd424c8a39ae98cbbd48fe0f9f23 Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Mon, 23 Jun 2014 14:13:47 -0700 Subject: [PATCH 0565/1001] mm: add cma pcp list Add a cma pcp list in order to increase cma memory utilization. Increased cma memory utilization will improve overall memory utilization because free cma pages are ignored when memory reclaim is done with gfp mask GFP_KERNEL. Since most memory reclaim is done by kswapd, which uses a gfp mask of GFP_KERNEL, by increasing cma memory utilization we are therefore ensuring that less aggressive memory reclaim takes place. Increased cma memory utilization will improve performance, for example it will increase app concurrency. Change-Id: I809589a25c6abca51f1c963f118adfc78e955cf9 Signed-off-by: Liam Mark [vinmenon@codeaurora.org: fix !CONFIG_CMA compile time issues] Signed-off-by: Vinayak Menon Signed-off-by: Charan Teja Reddy --- include/linux/mmzone.h | 6 ++- mm/page_alloc.c | 108 ++++++++++++++++++++++++++++------------- 2 files changed, 77 insertions(+), 37 deletions(-) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 198ad34fc91a..132b24533e16 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -40,8 +40,6 @@ enum migratetype { MIGRATE_UNMOVABLE, MIGRATE_MOVABLE, MIGRATE_RECLAIMABLE, - MIGRATE_PCPTYPES, /* the number of types on the pcp lists */ - MIGRATE_HIGHATOMIC = MIGRATE_PCPTYPES, #ifdef CONFIG_CMA /* * MIGRATE_CMA migration type is designed to mimic the way @@ -58,6 +56,8 @@ enum migratetype { */ MIGRATE_CMA, #endif + MIGRATE_PCPTYPES, /* the number of types on the pcp lists */ + MIGRATE_HIGHATOMIC = MIGRATE_PCPTYPES, #ifdef CONFIG_MEMORY_ISOLATION MIGRATE_ISOLATE, /* can't allocate from here */ #endif @@ -77,9 +77,11 @@ extern int *get_migratetype_fallbacks(int mtype); #ifdef CONFIG_CMA # define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA) # define is_migrate_cma_page(_page) (get_pageblock_migratetype(_page) == MIGRATE_CMA) +# define get_cma_migrate_type() MIGRATE_CMA #else # define is_migrate_cma(migratetype) false # define is_migrate_cma_page(_page) false +# define get_cma_migrate_type() MIGRATE_MOVABLE #endif static inline bool is_migrate_movable(int mt) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 5077bb37dbfd..25b21de7786e 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -239,10 +239,10 @@ char * const migratetype_names[MIGRATE_TYPES] = { "Unmovable", "Movable", "Reclaimable", - "HighAtomic", #ifdef CONFIG_CMA "CMA", #endif + "HighAtomic", #ifdef CONFIG_MEMORY_ISOLATION "Isolate", #endif @@ -2329,25 +2329,23 @@ static struct page *__rmqueue(struct zone *zone, unsigned int order, return page; } -static struct page *__rmqueue_cma(struct zone *zone, unsigned int order, - int migratetype) +#ifdef CONFIG_CMA +static struct page *__rmqueue_cma(struct zone *zone, unsigned int order) { struct page *page = 0; -retry: -#ifdef CONFIG_CMA - if (migratetype == MIGRATE_MOVABLE && !zone->cma_alloc) - page = __rmqueue_cma_fallback(zone, order); - else -#endif - page = __rmqueue_smallest(zone, order, migratetype); - - if (unlikely(!page) && __rmqueue_fallback(zone, order, migratetype)) - goto retry; - - trace_mm_page_alloc_zone_locked(page, order, migratetype); + if (IS_ENABLED(CONFIG_CMA)) + if (!zone->cma_alloc) + page = __rmqueue_cma_fallback(zone, order); + trace_mm_page_alloc_zone_locked(page, order, MIGRATE_CMA); return page; } +#else +static inline struct page *__rmqueue_cma(struct zone *zone, unsigned int order) +{ + return NULL; +} +#endif /* * Obtain a specified number of elements from the buddy allocator, all under @@ -2356,7 +2354,7 @@ static struct page *__rmqueue_cma(struct zone *zone, unsigned int order, */ static int rmqueue_bulk(struct zone *zone, unsigned int order, unsigned long count, struct list_head *list, - int migratetype, bool cold, int cma) + int migratetype, bool cold) { int i, alloced = 0; @@ -2364,8 +2362,13 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order, for (i = 0; i < count; ++i) { struct page *page; - if (cma) - page = __rmqueue_cma(zone, order, migratetype); + /* + * If migrate type CMA is being requested only try to + * satisfy the request with CMA pages to try and increase + * CMA utlization. + */ + if (is_migrate_cma(migratetype)) + page = __rmqueue_cma(zone, order); else page = __rmqueue(zone, order, migratetype); @@ -2406,6 +2409,28 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order, return alloced; } +/* + * Return the pcp list that corresponds to the migrate type if that list isn't + * empty. + * If the list is empty return NULL. + */ +static struct list_head *get_populated_pcp_list(struct zone *zone, + unsigned int order, struct per_cpu_pages *pcp, + int migratetype, int cold) +{ + struct list_head *list = &pcp->lists[migratetype]; + + if (list_empty(list)) { + pcp->count += rmqueue_bulk(zone, order, + pcp->batch, list, + migratetype, cold); + + if (list_empty(list)) + list = NULL; + } + return list; +} + #ifdef CONFIG_NUMA /* * Called from the vmstat counter updater to drain pagesets of this @@ -2793,18 +2818,30 @@ static inline void zone_statistics(struct zone *preferred_zone, struct zone *z) /* Remove page from the per-cpu list, caller must protect the list */ static struct page *__rmqueue_pcplist(struct zone *zone, int migratetype, bool cold, struct per_cpu_pages *pcp, - struct list_head *list, gfp_t gfp_flags) + gfp_t gfp_flags) { - struct page *page; + struct page *page = NULL; + struct list_head *list = NULL; do { - if (list_empty(list)) { - pcp->count += rmqueue_bulk(zone, 0, - pcp->batch, list, - migratetype, cold, - gfp_flags & __GFP_CMA); - if (unlikely(list_empty(list))) + /* First try to get CMA pages */ + if (migratetype == MIGRATE_MOVABLE && + gfp_flags & __GFP_CMA) { + list = get_populated_pcp_list(zone, 0, pcp, + get_cma_migrate_type(), cold); + } + + if (list == NULL) { + /* + * Either CMA is not suitable or there are no + * free CMA pages. + */ + list = get_populated_pcp_list(zone, 0, pcp, + migratetype, cold); + if (unlikely(list == NULL) || + unlikely(list_empty(list))) return NULL; + } if (cold) @@ -2825,15 +2862,13 @@ static struct page *rmqueue_pcplist(struct zone *preferred_zone, gfp_t gfp_flags, int migratetype) { struct per_cpu_pages *pcp; - struct list_head *list; bool cold = ((gfp_flags & __GFP_COLD) != 0); struct page *page; unsigned long flags; local_irq_save(flags); pcp = &this_cpu_ptr(zone->pageset)->pcp; - list = &pcp->lists[migratetype]; - page = __rmqueue_pcplist(zone, migratetype, cold, pcp, list, + page = __rmqueue_pcplist(zone, migratetype, cold, pcp, gfp_flags); if (page) { __count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order); @@ -2870,18 +2905,21 @@ struct page *rmqueue(struct zone *preferred_zone, do { page = NULL; + if (alloc_flags & ALLOC_HARDER) { page = __rmqueue_smallest(zone, order, MIGRATE_HIGHATOMIC); if (page) trace_mm_page_alloc_zone_locked(page, order, migratetype); } - if (!page) { - if (gfp_flags & __GFP_CMA) - page = __rmqueue_cma(zone, order, migratetype); - else - page = __rmqueue(zone, order, migratetype); - } + + if (!page && migratetype == MIGRATE_MOVABLE && + gfp_flags & __GFP_CMA) + page = __rmqueue_cma(zone, order); + + if (!page) + page = __rmqueue(zone, order, migratetype); } while (page && check_new_pages(page, order)); + spin_unlock(&zone->lock); if (!page) goto failed; -- GitLab From e1f0edb1aff7bb34f88795beec0115d61c321aa0 Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Mon, 23 Jul 2018 11:17:04 -0700 Subject: [PATCH 0566/1001] mm: Increase number of GFP masks The __GFP_CMA mask is now placed after all available GFP masks. With this we need to increase the total number of GFP flags. Do so accordingly. CRs-Fixed: 648978 Change-Id: I53f5f064ac16a50ee10c84ff2bb50fdb7e085bd0 Signed-off-by: Laura Abbott [lmark@codeaurora.org: resolve trivial merge conflicts] Signed-off-by: Liam Mark --- include/linux/gfp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/gfp.h b/include/linux/gfp.h index fb62fbd33194..3d6265fd3209 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -40,12 +40,12 @@ struct vm_area_struct; #define ___GFP_DIRECT_RECLAIM 0x400000u #define ___GFP_WRITE 0x800000u #define ___GFP_KSWAPD_RECLAIM 0x1000000u -#define ___GFP_CMA 0x4000000u #ifdef CONFIG_LOCKDEP #define ___GFP_NOLOCKDEP 0x2000000u #else #define ___GFP_NOLOCKDEP 0 #endif +#define ___GFP_CMA 0x4000000u /* If the above are modified, __GFP_BITS_SHIFT may need updating */ /* @@ -211,7 +211,7 @@ struct vm_area_struct; #define __GFP_NOLOCKDEP ((__force gfp_t)___GFP_NOLOCKDEP) /* Room for N __GFP_FOO bits */ -#define __GFP_BITS_SHIFT (25 + IS_ENABLED(CONFIG_LOCKDEP)) +#define __GFP_BITS_SHIFT 27 #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) /* -- GitLab From c31f443349aea6bb76d597c10c01a66c45702155 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Fri, 3 Aug 2018 17:46:00 -0700 Subject: [PATCH 0567/1001] msm: camera: icp: Change log type for hfi queue dump In certain cases we enounter multiple consecutive FW timeouts leading to dumping the hfi queues everytime. This might lead to WD bite hence changing the log level to debug. Change-Id: Iceac91eaa9374f0d128987d9235b91eba032d5c9 Signed-off-by: Karthik Anantha Ram --- drivers/media/platform/msm/camera/cam_icp/hfi.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c index 14a3e656e76d..f91e29a8f2d9 100644 --- a/drivers/media/platform/msm/camera/cam_icp/hfi.c +++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c @@ -64,30 +64,30 @@ void cam_hfi_queue_dump(void) qtbl = (struct hfi_qtbl *)hfi_mem->qtbl.kva; qtbl_hdr = &qtbl->q_tbl_hdr; - CAM_INFO(CAM_HFI, + CAM_DBG(CAM_HFI, "qtbl: version = %x size = %u num q = %u qhdr_size = %u", qtbl_hdr->qtbl_version, qtbl_hdr->qtbl_size, qtbl_hdr->qtbl_num_q, qtbl_hdr->qtbl_qhdr_size); cmd_q_hdr = &qtbl->q_hdr[Q_CMD]; - CAM_INFO(CAM_HFI, "cmd: size = %u r_idx = %u w_idx = %u addr = %x", + CAM_DBG(CAM_HFI, "cmd: size = %u r_idx = %u w_idx = %u addr = %x", cmd_q_hdr->qhdr_q_size, cmd_q_hdr->qhdr_read_idx, cmd_q_hdr->qhdr_write_idx, hfi_mem->cmd_q.iova); read_q = (uint32_t *)g_hfi->map.cmd_q.kva; read_ptr = (uint32_t *)(read_q + 0); - CAM_INFO(CAM_HFI, "CMD Q START"); + CAM_DBG(CAM_HFI, "CMD Q START"); for (i = 0; i < ICP_CMD_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; i++) - CAM_INFO(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]); + CAM_DBG(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]); msg_q_hdr = &qtbl->q_hdr[Q_MSG]; - CAM_INFO(CAM_HFI, "msg: size = %u r_idx = %u w_idx = %u addr = %x", + CAM_DBG(CAM_HFI, "msg: size = %u r_idx = %u w_idx = %u addr = %x", msg_q_hdr->qhdr_q_size, msg_q_hdr->qhdr_read_idx, msg_q_hdr->qhdr_write_idx, hfi_mem->msg_q.iova); read_q = (uint32_t *)g_hfi->map.msg_q.kva; read_ptr = (uint32_t *)(read_q + 0); - CAM_INFO(CAM_HFI, "MSG Q START"); + CAM_DBG(CAM_HFI, "MSG Q START"); for (i = 0; i < ICP_MSG_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; i++) - CAM_INFO(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]); + CAM_DBG(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]); } int hfi_write_cmd(void *cmd_ptr) -- GitLab From 282815bfe3565369f9a5ecc220136a69f0e55bcc Mon Sep 17 00:00:00 2001 From: Kyle Piefer Date: Mon, 7 May 2018 16:44:58 -0700 Subject: [PATCH 0568/1001] msm: kgsl: Add support for Adaptive Clock Distribution Adaptive Clock Distribution (ACD) is a power feature that mitigates voltage droops. ACD involves interactions between the host, the GMU, and the AOP. Change-Id: Ibffa62a0858ca9dabac4d5b382ad2b8a3167789e Signed-off-by: Kyle Piefer --- .../bindings/gpu/adreno-pwrlevels.txt | 7 +- drivers/gpu/msm/adreno.c | 4 + drivers/gpu/msm/adreno.h | 6 + drivers/gpu/msm/adreno_a6xx_gmu.c | 6 - drivers/gpu/msm/adreno_sysfs.c | 18 ++- drivers/gpu/msm/kgsl_gmu.c | 127 ++++++++++++++++++ drivers/gpu/msm/kgsl_gmu.h | 10 ++ drivers/gpu/msm/kgsl_gmu_core.c | 10 ++ drivers/gpu/msm/kgsl_gmu_core.h | 2 + drivers/gpu/msm/kgsl_hfi.c | 11 +- drivers/gpu/msm/kgsl_pwrctrl.h | 2 + 11 files changed, 190 insertions(+), 13 deletions(-) diff --git a/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt b/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt index 747e0b601da2..645052c048d2 100644 --- a/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt +++ b/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt @@ -2,7 +2,7 @@ Qualcomm Technologies, Inc. GPU powerlevels Powerlevels are defined in sets by qcom,gpu-pwrlevels. Multiple sets (bins) can be defined within qcom,gpu-pwrelvel-bins. Each powerlevel defines a -voltage, bus, and bandwitdh level. +voltage, bus, bandwidth level, and a DVM value. - qcom,gpu-pwrlevel-bins: Contains one or more qcom,gpu-pwrlevels sets @@ -28,3 +28,8 @@ Properties: settings) - qcom,bus-min Minimum bus level to set for the power level - qcom,bus-max maximum bus level to set for the power level +- qcom,dvm-val: Value that is used as a register setting for + the ACD power feature. It helps determine the + threshold for when ACD activates. 0xFFFFFFFF + is the default value, and the setting where + ACD will never activate. diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index df69aa95dc49..dda9872c7ca2 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -965,6 +965,10 @@ static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev, if (of_property_read_u32(child, "qcom,bus-max", &level->bus_max)) level->bus_max = level->bus_freq; + + if (of_property_read_u32(child, "qcom,dvm-val", + &level->acd_dvm_val)) + level->acd_dvm_val = 0xFFFFFFFF; } return 0; diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 0ffcc9eed235..daf61170707f 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -123,6 +123,11 @@ #define ADRENO_MIN_VOLT BIT(15) /* The core supports IO-coherent memory */ #define ADRENO_IOCOHERENT BIT(16) +/* + * The GMU supports Adaptive Clock Distribution (ACD) + * for droop mitigation + */ +#define ADRENO_ACD BIT(17) /* * Adreno GPU quirks - control bits for various workarounds @@ -233,6 +238,7 @@ enum adreno_gpurev { #define ADRENO_LM_CTRL 2 #define ADRENO_HWCG_CTRL 3 #define ADRENO_THROTTLING_CTRL 4 +#define ADRENO_ACD_CTRL 5 /* VBIF, GBIF halt request and ack mask */ #define GBIF_HALT_REQUEST 0x1E0 diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index bbfab64bddf9..6c8d86d38f44 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -301,12 +301,6 @@ static void a6xx_gmu_power_config(struct kgsl_device *device) break; } - /* ACD feature enablement */ - if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) && - test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) - gmu_core_regrmw(device, A6XX_GMU_BOOT_KMD_LM_HANDSHAKE, 0, - BIT(10)); - /* Enable RPMh GPU client */ if (ADRENO_FEATURE(adreno_dev, ADRENO_RPMH)) gmu_core_regrmw(device, A6XX_GMU_RPMH_CTRL, 0, diff --git a/drivers/gpu/msm/adreno_sysfs.c b/drivers/gpu/msm/adreno_sysfs.c index a414e553cd7b..55b0b73468ed 100644 --- a/drivers/gpu/msm/adreno_sysfs.c +++ b/drivers/gpu/msm/adreno_sysfs.c @@ -312,6 +312,21 @@ static unsigned int _preempt_count_show(struct adreno_device *adreno_dev) return preempt->count; } +static unsigned int _acd_show(struct adreno_device *adreno_dev) +{ + return test_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag); +} + +static int _acd_store(struct adreno_device *adreno_dev, unsigned int val) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + if (test_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag) == val) + return 0; + + return gmu_core_acd_set(device, val); +} + static ssize_t _sysfs_store_u32(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -416,7 +431,7 @@ static ADRENO_SYSFS_BOOL(hwcg); static ADRENO_SYSFS_BOOL(throttling); static ADRENO_SYSFS_BOOL(ifpc); static ADRENO_SYSFS_RO_U32(ifpc_count); - +static ADRENO_SYSFS_BOOL(acd); static const struct device_attribute *_attr_list[] = { @@ -439,6 +454,7 @@ static const struct device_attribute *_attr_list[] = { &adreno_attr_ifpc.attr, &adreno_attr_ifpc_count.attr, &adreno_attr_preempt_count.attr, + &adreno_attr_acd.attr, NULL, }; diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index b47246533d42..ef9c21552f7e 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -10,6 +10,7 @@ * GNU General Public License for more details. * */ +#include #include #include #include @@ -26,6 +27,13 @@ #include "kgsl_hfi.h" #include "adreno.h" +#undef MODULE_PARAM_PREFIX +#define MODULE_PARAM_PREFIX "kgsl." + +static bool noacd; +module_param(noacd, bool, 0444); +MODULE_PARM_DESC(noacd, "Disable GPU ACD"); + #define GMU_CONTEXT_USER 0 #define GMU_CONTEXT_KERNEL 1 #define GMU_KERNEL_ENTRIES 16 @@ -1166,6 +1174,103 @@ static int gmu_irq_probe(struct kgsl_device *device, struct gmu_device *gmu) return ret; } +struct mbox_message { + uint32_t len; + void *msg; +}; + +static void gmu_aop_send_acd_state(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct mbox_message msg; + char msg_buf[33]; + bool state = test_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag); + int ret; + + if (!gmu->mailbox.client) + return; + + msg.len = scnprintf(msg_buf, sizeof(msg_buf), + "{class: gpu, res: acd, value: %d}", state); + msg.msg = msg_buf; + + ret = mbox_send_message(gmu->mailbox.channel, &msg); + if (ret < 0) + dev_err(&gmu->pdev->dev, + "AOP mbox send message failed: %d\n", ret); +} + +static void gmu_aop_mailbox_destroy(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct kgsl_mailbox *mailbox = &gmu->mailbox; + + if (!mailbox->client) + return; + + mbox_free_channel(mailbox->channel); + mailbox->channel = NULL; + + kfree(mailbox->client); + mailbox->client = NULL; + + clear_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag); +} + +static int gmu_aop_mailbox_init(struct kgsl_device *device, + struct gmu_device *gmu) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_mailbox *mailbox = &gmu->mailbox; + + mailbox->client = kzalloc(sizeof(*mailbox->client), GFP_KERNEL); + if (!mailbox->client) + return -ENOMEM; + + mailbox->client->dev = &gmu->pdev->dev; + mailbox->client->tx_block = true; + mailbox->client->tx_tout = 1000; + mailbox->client->knows_txdone = false; + + mailbox->channel = mbox_request_channel(mailbox->client, 0); + if (IS_ERR(mailbox->channel)) { + kfree(mailbox->client); + mailbox->client = NULL; + return PTR_ERR(mailbox->channel); + } + + set_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag); + return 0; +} + +static int gmu_acd_set(struct kgsl_device *device, unsigned int val) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + + if (!gmu->mailbox.client) + return -EINVAL; + + /* Don't do any unneeded work if ACD is already in the correct state */ + if (val == test_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag)) + return 0; + + mutex_lock(&device->mutex); + + /* Power down the GPU before enabling or disabling ACD */ + kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); + if (val) + set_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag); + else + clear_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag); + kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); + + mutex_unlock(&device->mutex); + return 0; +} + /* Do not access any GMU registers in GMU probe function */ static int gmu_probe(struct kgsl_device *device, struct device_node *node) { @@ -1240,6 +1345,7 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node) int j = gmu->num_gpupwrlevels - 1 - i; gmu->gpu_freqs[i] = pwr->pwrlevels[j].gpu_freq; + gmu->acd_dvm_vals[i] = pwr->pwrlevels[j].acd_dvm_val; } /* Initializes GPU b/w levels configuration */ @@ -1271,6 +1377,13 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node) else gmu->idle_level = GPU_HW_ACTIVE; + if (ADRENO_FEATURE(adreno_dev, ADRENO_ACD) && !noacd) { + ret = gmu_aop_mailbox_init(device, gmu); + if (ret) + dev_err(&gmu->pdev->dev, + "AOP mailbox init failed: %d\n", ret); + } + /* disable LM during boot time */ clear_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag); set_bit(GMU_ENABLED, &device->gmu_core.flags); @@ -1450,6 +1563,9 @@ static int gmu_start(struct kgsl_device *device) case KGSL_STATE_INIT: case KGSL_STATE_SUSPEND: WARN_ON(test_bit(GMU_CLK_ON, &device->gmu_core.flags)); + + gmu_aop_send_acd_state(device); + gmu_enable_gdsc(gmu); gmu_enable_clks(device); gmu_dev_ops->irq_enable(device); @@ -1477,6 +1593,9 @@ static int gmu_start(struct kgsl_device *device) case KGSL_STATE_SLUMBER: WARN_ON(test_bit(GMU_CLK_ON, &device->gmu_core.flags)); + + gmu_aop_send_acd_state(device); + gmu_enable_gdsc(gmu); gmu_enable_clks(device); gmu_dev_ops->irq_enable(device); @@ -1497,6 +1616,9 @@ static int gmu_start(struct kgsl_device *device) if (test_bit(ADRENO_DEVICE_HARD_RESET, &adreno_dev->priv) || test_bit(GMU_FAULT, &device->gmu_core.flags)) { gmu_suspend(device); + + gmu_aop_send_acd_state(device); + gmu_enable_gdsc(gmu); gmu_enable_clks(device); gmu_dev_ops->irq_enable(device); @@ -1517,6 +1639,8 @@ static int gmu_start(struct kgsl_device *device) /* GMU fast boot */ hfi_stop(gmu); + gmu_aop_send_acd_state(device); + ret = gmu_dev_ops->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START, GMU_COLD_BOOT, 0); if (ret) @@ -1602,6 +1726,8 @@ static void gmu_remove(struct kgsl_device *device) gmu_stop(device); + gmu_aop_mailbox_destroy(device); + while ((i < MAX_GMU_CLKS) && gmu->clks[i]) { gmu->clks[i] = NULL; i++; @@ -1670,4 +1796,5 @@ struct gmu_core_ops gmu_ops = { .snapshot = gmu_snapshot, .regulator_isenabled = gmu_regulator_isenabled, .suspend = gmu_suspend, + .acd_set = gmu_acd_set, }; diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h index 4b003a8a659e..02b26b4b0436 100644 --- a/drivers/gpu/msm/kgsl_gmu.h +++ b/drivers/gpu/msm/kgsl_gmu.h @@ -13,6 +13,7 @@ #ifndef __KGSL_GMU_H #define __KGSL_GMU_H +#include #include "kgsl_gmu_core.h" #include "kgsl_hfi.h" @@ -106,6 +107,11 @@ enum gmu_load_mode { INVALID_LOAD }; +struct kgsl_mailbox { + struct mbox_client *client; + struct mbox_chan *channel; +}; + /** * struct gmu_device - GMU device structure * @ver: GMU FW version, read from GMU @@ -141,6 +147,8 @@ enum gmu_load_mode { * @ccl: CNOC BW scaling client * @idle_level: Minimal GPU idle power level * @fault_count: GMU fault count + * @acd_dvm_vals: Table of DVM values that correspond to frequency levels + * @mailbox: Messages to AOP for ACD enable/disable go through this */ struct gmu_device { unsigned int ver; @@ -174,6 +182,8 @@ struct gmu_device { unsigned int ccl; unsigned int idle_level; unsigned int fault_count; + unsigned int acd_dvm_vals[MAX_GX_LEVELS]; + struct kgsl_mailbox mailbox; }; bool is_cached_fw_size_valid(uint32_t size_in_bytes); diff --git a/drivers/gpu/msm/kgsl_gmu_core.c b/drivers/gpu/msm/kgsl_gmu_core.c index e752c3231204..9421de861cb7 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.c +++ b/drivers/gpu/msm/kgsl_gmu_core.c @@ -132,6 +132,16 @@ int gmu_core_dcvs_set(struct kgsl_device *device, unsigned int gpu_pwrlevel, return -EINVAL; } +int gmu_core_acd_set(struct kgsl_device *device, unsigned int val) +{ + struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); + + if (gmu_core_ops && gmu_core_ops->acd_set) + return gmu_core_ops->acd_set(device, val); + + return -EINVAL; +} + bool gmu_core_regulator_isenabled(struct kgsl_device *device) { struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); diff --git a/drivers/gpu/msm/kgsl_gmu_core.h b/drivers/gpu/msm/kgsl_gmu_core.h index b6a559d46fc4..b2ecf2b1632d 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.h +++ b/drivers/gpu/msm/kgsl_gmu_core.h @@ -127,6 +127,7 @@ struct gmu_core_ops { void (*snapshot)(struct kgsl_device *device); bool (*regulator_isenabled)(struct kgsl_device *device); int (*suspend)(struct kgsl_device *device); + int (*acd_set)(struct kgsl_device *device, unsigned int val); }; struct gmu_dev_ops { @@ -187,6 +188,7 @@ bool gmu_core_gpmu_isenabled(struct kgsl_device *device); bool gmu_core_isenabled(struct kgsl_device *device); int gmu_core_dcvs_set(struct kgsl_device *device, unsigned int gpu_pwrlevel, unsigned int bus_level); +int gmu_core_acd_set(struct kgsl_device *device, unsigned int val); bool gmu_core_regulator_isenabled(struct kgsl_device *device); bool gmu_core_is_register_offset(struct kgsl_device *device, unsigned int offsetwords); diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/kgsl_hfi.c index 6b2f77acc67e..b1516aefdf0c 100644 --- a/drivers/gpu/msm/kgsl_hfi.c +++ b/drivers/gpu/msm/kgsl_hfi.c @@ -388,6 +388,7 @@ static int hfi_send_core_fw_start(struct gmu_device *gmu) static const char * const hfi_features[] = { [HFI_FEATURE_ECP] = "ECP", + [HFI_FEATURE_ACD] = "ACD", }; static const char *feature_to_string(uint32_t feature) @@ -474,11 +475,7 @@ static int hfi_send_dcvstbl(struct gmu_device *gmu) for (i = 0; i < gmu->num_gpupwrlevels; i++) { cmd.gx_votes[i].vote = gmu->rpmh_votes.gx_votes[i]; - /* - * Set ACD threshold to the maximum value as a default. - * At this level, ACD will never activate. - */ - cmd.gx_votes[i].acd = 0xFFFFFFFF; + cmd.gx_votes[i].acd = gmu->acd_dvm_vals[i]; /* Divide by 1000 to convert to kHz */ cmd.gx_votes[i].freq = gmu->gpu_freqs[i] / 1000; } @@ -729,6 +726,10 @@ int hfi_start(struct kgsl_device *device, */ if (HFI_VER_MAJOR(&gmu->hfi) >= 2) { result = hfi_send_feature_ctrl(gmu, HFI_FEATURE_ECP, 0, 0); + if (test_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag)) + result |= hfi_send_feature_ctrl(gmu, + HFI_FEATURE_ACD, 1, 0); + if (result) return result; diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index 1800d14c389d..8f700028351a 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -106,12 +106,14 @@ struct kgsl_pwr_constraint { * @bus_freq: Bus bandwidth vote index * @bus_min: Min bus index @gpu_freq * @bus_max: Max bus index @gpu_freq + * @acd_dvm_val: Register setting for ACD */ struct kgsl_pwrlevel { unsigned int gpu_freq; unsigned int bus_freq; unsigned int bus_min; unsigned int bus_max; + unsigned int acd_dvm_val; }; struct kgsl_regulator { -- GitLab From 350b8790b853523ebd0475199a2335ec5de07817 Mon Sep 17 00:00:00 2001 From: Kyle Piefer Date: Wed, 9 May 2018 11:43:45 -0700 Subject: [PATCH 0569/1001] ARM: dts: msm: Add AOP mailbox and DVM for SM8150 The AOP mailbox will be used to send enable and disable messages for Adaptive Clock Distribution (ACD) to the AOP on SM8150. Additionally, the DVM values for each power level will be used as setting for ACD that determine when the feature activates. Change-Id: Ie2d1a6499c1124e41449ea325e002cfc5f82647d Signed-off-by: Kyle Piefer --- arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi b/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi index 753d0627b091..284c821e77fd 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi @@ -215,6 +215,7 @@ qcom,bus-freq = <12>; qcom,bus-min = <10>; qcom,bus-max = <12>; + qcom,dvm-val = <0xffffffff>; }; qcom,gpu-pwrlevel@1 { @@ -223,6 +224,7 @@ qcom,bus-freq = <10>; qcom,bus-min = <9>; qcom,bus-max = <11>; + qcom,dvm-val = <0xffffffff>; }; @@ -232,6 +234,7 @@ qcom,bus-freq = <9>; qcom,bus-min = <8>; qcom,bus-max = <10>; + qcom,dvm-val = <0xffffffff>; }; qcom,gpu-pwrlevel@3 { @@ -240,6 +243,7 @@ qcom,bus-freq = <8>; qcom,bus-min = <7>; qcom,bus-max = <9>; + qcom,dvm-val = <0xffffffff>; }; @@ -249,6 +253,7 @@ qcom,bus-freq = <5>; qcom,bus-min = <5>; qcom,bus-max = <7>; + qcom,dvm-val = <0xffffffff>; }; qcom,gpu-pwrlevel@5 { @@ -257,6 +262,7 @@ qcom,bus-freq = <4>; qcom,bus-min = <3>; qcom,bus-max = <5>; + qcom,dvm-val = <0xffffffff>; }; qcom,gpu-pwrlevel@6 { @@ -265,6 +271,7 @@ qcom,bus-freq = <0>; qcom,bus-min = <0>; qcom,bus-max = <0>; + qcom,dvm-val = <0xffffffff>; }; }; }; @@ -330,6 +337,10 @@ clock-names = "gmu_clk", "cxo_clk", "axi_clk", "memnoc_clk", "gpu_cc_ahb"; + /* AOP mailbox for sending ACD enable and disable messages */ + mboxes = <&qmp_aop 0>; + mbox-names = "aop"; + qcom,gmu-pwrlevels { #address-cells = <1>; #size-cells = <0>; -- GitLab From cd16e4b35a3a6cca4d4cdc199238eda650ec30e5 Mon Sep 17 00:00:00 2001 From: Kyle Piefer Date: Wed, 9 May 2018 11:54:32 -0700 Subject: [PATCH 0570/1001] msm: kgsl: Enable Adaptive Clock Distribution on A640 Adaptive Clock Distribution (ACD) is now supported on the A640 GPU, so enable it. Change-Id: Id5fdacbf9b16a016ee64ad1c6e412423cd2fa3f9 Signed-off-by: Kyle Piefer --- drivers/gpu/msm/adreno-gpulist.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h index 28783d2fa91a..034584656a7f 100644 --- a/drivers/gpu/msm/adreno-gpulist.h +++ b/drivers/gpu/msm/adreno-gpulist.h @@ -387,7 +387,7 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .patchid = 0, .features = ADRENO_64BIT | ADRENO_RPMH | ADRENO_GPMU | ADRENO_CONTENT_PROTECTION | ADRENO_IOCOHERENT | - ADRENO_IFPC, + ADRENO_IFPC | ADRENO_ACD, .sqefw_name = "a630_sqe.fw", .zap_name = "a640_zap", .gpudev = &adreno_a6xx_gpudev, -- GitLab From b188a2d9e4482d0fc128ab28183419af5be8c6bf Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Thu, 2 Aug 2018 16:33:39 +0530 Subject: [PATCH 0571/1001] msm: ipa3: Software workaround to fix GSI2.2 HW bug in SM6150 Any allocate GSI channel operation issued from SW may cause any channel context access on any channel, any EE it will return wrong address for a very short duration until the allocate channel operation completes. Make a changes to allocate all EE GSI channel during device bootup to fix HW bug. Change-Id: Ic5e9a20ec0eec653a4b9a1346aef826153bfb4b8 Acked-by: Ashok Vuyyuru Signed-off-by: Mohammed Javid --- drivers/platform/msm/gsi/gsi.c | 168 +++++++++++++++----- drivers/platform/msm/gsi/gsi.h | 2 + drivers/platform/msm/ipa/ipa_v3/ipa.c | 44 +++++ drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 1 + drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 2 +- include/linux/msm_gsi.h | 19 +++ 6 files changed, 191 insertions(+), 45 deletions(-) diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 75788e858d9b..e5c04c0945fc 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -2096,31 +2096,36 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl, atomic_set(&ctx->poll_mode, GSI_CHAN_MODE_CALLBACK); ctx->props = *props; - mutex_lock(&gsi_ctx->mlock); - ee = gsi_ctx->per.ee; - gsi_ctx->ch_dbg[props->ch_id].ch_allocate++; - val = (((props->ch_id << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & - GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | - ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & - GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK)); - gsi_writel(val, gsi_ctx->base + - GSI_EE_n_GSI_CH_CMD_OFFS(ee)); - res = wait_for_completion_timeout(&ctx->compl, GSI_CMD_TIMEOUT); - if (res == 0) { - GSIERR("chan_hdl=%u timed out\n", props->ch_id); + if (gsi_ctx->per.ver != GSI_VER_2_2) { + mutex_lock(&gsi_ctx->mlock); + ee = gsi_ctx->per.ee; + gsi_ctx->ch_dbg[props->ch_id].ch_allocate++; + val = (((props->ch_id << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & + GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | + ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & + GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK)); + gsi_writel(val, gsi_ctx->base + + GSI_EE_n_GSI_CH_CMD_OFFS(ee)); + res = wait_for_completion_timeout(&ctx->compl, GSI_CMD_TIMEOUT); + if (res == 0) { + GSIERR("chan_hdl=%u timed out\n", props->ch_id); + mutex_unlock(&gsi_ctx->mlock); + devm_kfree(gsi_ctx->dev, user_data); + return -GSI_STATUS_TIMED_OUT; + } + if (ctx->state != GSI_CHAN_STATE_ALLOCATED) { + GSIERR("chan_hdl=%u allocation failed state=%d\n", + props->ch_id, ctx->state); + mutex_unlock(&gsi_ctx->mlock); + devm_kfree(gsi_ctx->dev, user_data); + return -GSI_STATUS_RES_ALLOC_FAILURE; + } mutex_unlock(&gsi_ctx->mlock); - devm_kfree(gsi_ctx->dev, user_data); - return -GSI_STATUS_TIMED_OUT; - } - if (ctx->state != GSI_CHAN_STATE_ALLOCATED) { - GSIERR("chan_hdl=%u allocation failed state=%d\n", - props->ch_id, ctx->state); + } else { + mutex_lock(&gsi_ctx->mlock); + ctx->state = GSI_CHAN_STATE_ALLOCATED; mutex_unlock(&gsi_ctx->mlock); - devm_kfree(gsi_ctx->dev, user_data); - return -GSI_STATUS_RES_ALLOC_FAILURE; } - mutex_unlock(&gsi_ctx->mlock); - erindex = props->evt_ring_hdl != ~0 ? props->evt_ring_hdl : GSI_NO_EVT_ERINDEX; if (erindex != GSI_NO_EVT_ERINDEX) { @@ -2693,31 +2698,40 @@ int gsi_dealloc_channel(unsigned long chan_hdl) return -GSI_STATUS_UNSUPPORTED_OP; } - mutex_lock(&gsi_ctx->mlock); - reinit_completion(&ctx->compl); + /*In GSI_VER_2_2 version deallocation channel not supported*/ + if (gsi_ctx->per.ver != GSI_VER_2_2) { + mutex_lock(&gsi_ctx->mlock); + reinit_completion(&ctx->compl); + + gsi_ctx->ch_dbg[chan_hdl].ch_de_alloc++; + val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & + GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | + ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & + GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK)); + gsi_writel(val, gsi_ctx->base + + GSI_EE_n_GSI_CH_CMD_OFFS(gsi_ctx->per.ee)); + res = wait_for_completion_timeout(&ctx->compl, GSI_CMD_TIMEOUT); + if (res == 0) { + GSIERR("chan_hdl=%lu timed out\n", chan_hdl); + mutex_unlock(&gsi_ctx->mlock); + return -GSI_STATUS_TIMED_OUT; + } + if (ctx->state != GSI_CHAN_STATE_NOT_ALLOCATED) { + GSIERR("chan_hdl=%lu unexpected state=%u\n", chan_hdl, + ctx->state); + /* Hardware returned incorrect value */ + BUG(); + } - gsi_ctx->ch_dbg[chan_hdl].ch_de_alloc++; - val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & - GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | - ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & - GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK)); - gsi_writel(val, gsi_ctx->base + - GSI_EE_n_GSI_CH_CMD_OFFS(gsi_ctx->per.ee)); - res = wait_for_completion_timeout(&ctx->compl, GSI_CMD_TIMEOUT); - if (res == 0) { - GSIERR("chan_hdl=%lu timed out\n", chan_hdl); mutex_unlock(&gsi_ctx->mlock); - return -GSI_STATUS_TIMED_OUT; - } - if (ctx->state != GSI_CHAN_STATE_NOT_ALLOCATED) { - GSIERR("chan_hdl=%lu unexpected state=%u\n", chan_hdl, - ctx->state); - /* Hardware returned incorrect value */ - BUG(); + } else { + mutex_lock(&gsi_ctx->mlock); + GSIDBG("In GSI_VER_2_2 channel deallocation not supported\n"); + ctx->state = GSI_CHAN_STATE_NOT_ALLOCATED; + GSIDBG("chan_hdl=%lu Channel state = %u\n", chan_hdl, + ctx->state); + mutex_unlock(&gsi_ctx->mlock); } - - mutex_unlock(&gsi_ctx->mlock); - devm_kfree(gsi_ctx->dev, ctx->user_data); ctx->allocated = false; if (ctx->evtr) @@ -3527,6 +3541,72 @@ int gsi_halt_channel_ee(unsigned int chan_idx, unsigned int ee, int *code) } EXPORT_SYMBOL(gsi_halt_channel_ee); +int gsi_alloc_channel_ee(unsigned int chan_idx, unsigned int ee, int *code) +{ + enum gsi_generic_ee_cmd_opcode op = GSI_GEN_EE_CMD_ALLOC_CHANNEL; + struct gsi_chan_ctx *ctx; + uint32_t val; + int res; + + if (chan_idx >= gsi_ctx->max_ch || !code) { + GSIERR("bad params chan_idx=%d\n", chan_idx); + return -GSI_STATUS_INVALID_PARAMS; + } + + mutex_lock(&gsi_ctx->mlock); + reinit_completion(&gsi_ctx->gen_ee_cmd_compl); + + /* invalidate the response */ + gsi_ctx->scratch.word0.val = gsi_readl(gsi_ctx->base + + GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee)); + gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code = 0; + gsi_writel(gsi_ctx->scratch.word0.val, gsi_ctx->base + + GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee)); + + val = (((op << GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_SHFT) & + GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_BMSK) | + ((chan_idx << GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_SHFT) & + GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_BMSK) | + ((ee << GSI_EE_n_GSI_EE_GENERIC_CMD_EE_SHFT) & + GSI_EE_n_GSI_EE_GENERIC_CMD_EE_BMSK)); + gsi_writel(val, gsi_ctx->base + + GSI_EE_n_GSI_EE_GENERIC_CMD_OFFS(gsi_ctx->per.ee)); + + res = wait_for_completion_timeout(&gsi_ctx->gen_ee_cmd_compl, + msecs_to_jiffies(GSI_CMD_TIMEOUT)); + if (res == 0) { + GSIERR("chan_idx=%u ee=%u timed out\n", chan_idx, ee); + res = -GSI_STATUS_TIMED_OUT; + goto free_lock; + } + + gsi_ctx->scratch.word0.val = gsi_readl(gsi_ctx->base + + GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee)); + if (gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code == + GSI_GEN_EE_CMD_RETURN_CODE_OUT_OF_RESOURCES) { + GSIDBG("chan_idx=%u ee=%u out of resources\n", chan_idx, ee); + *code = GSI_GEN_EE_CMD_RETURN_CODE_OUT_OF_RESOURCES; + res = -GSI_STATUS_RES_ALLOC_FAILURE; + goto free_lock; + } + if (gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code == 0) { + GSIERR("No response received\n"); + res = -GSI_STATUS_ERROR; + goto free_lock; + } + if (ee == 0) { + ctx = &gsi_ctx->chan[chan_idx]; + gsi_ctx->ch_dbg[chan_idx].ch_allocate++; + } + res = GSI_STATUS_SUCCESS; + *code = gsi_ctx->scratch.word0.s.generic_ee_cmd_return_code; +free_lock: + mutex_unlock(&gsi_ctx->mlock); + + return res; +} +EXPORT_SYMBOL(gsi_alloc_channel_ee); + int gsi_map_virtual_ch_to_per_ep(u32 ee, u32 chan_num, u32 per_ep_index) { if (!gsi_ctx) { diff --git a/drivers/platform/msm/gsi/gsi.h b/drivers/platform/msm/gsi/gsi.h index 870d8d615ba3..dbf89418e2fc 100644 --- a/drivers/platform/msm/gsi/gsi.h +++ b/drivers/platform/msm/gsi/gsi.h @@ -295,6 +295,7 @@ enum gsi_evt_ch_cmd_opcode { enum gsi_generic_ee_cmd_opcode { GSI_GEN_EE_CMD_HALT_CHANNEL = 0x1, + GSI_GEN_EE_CMD_ALLOC_CHANNEL = 0x2, }; enum gsi_generic_ee_cmd_return_code { @@ -304,6 +305,7 @@ enum gsi_generic_ee_cmd_return_code { GSI_GEN_EE_CMD_RETURN_CODE_INCORRECT_CHANNEL_TYPE = 0x4, GSI_GEN_EE_CMD_RETURN_CODE_INCORRECT_CHANNEL_INDEX = 0x5, GSI_GEN_EE_CMD_RETURN_CODE_RETRY = 0x6, + GSI_GEN_EE_CMD_RETURN_CODE_OUT_OF_RESOURCES = 0x7, }; extern struct gsi_ctx *gsi_ctx; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 7d77d7c1aee2..b2c90ff1cfff 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -4438,6 +4438,38 @@ static int ipa3_gsi_pre_fw_load_init(void) return 0; } +static int ipa3_alloc_gsi_channel(void) +{ + const struct ipa_gsi_ep_config *gsi_ep_cfg; + enum ipa_client_type type; + int code = 0; + int ret = 0; + int i; + + for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) { + type = ipa3_get_client_by_pipe(i); + gsi_ep_cfg = ipa3_get_gsi_ep_info(type); + IPADBG("for ep %d client is %d\n", i, type); + if (!gsi_ep_cfg) + continue; + + ret = gsi_alloc_channel_ee(gsi_ep_cfg->ipa_gsi_chan_num, + gsi_ep_cfg->ee, &code); + if (ret == GSI_STATUS_SUCCESS) { + IPADBG("alloc gsi ch %d ee %d with code %d\n", + gsi_ep_cfg->ipa_gsi_chan_num, + gsi_ep_cfg->ee, + code); + } else { + IPAERR("failed to alloc ch %d ee %d code %d\n", + gsi_ep_cfg->ipa_gsi_chan_num, + gsi_ep_cfg->ee, + code); + return ret; + } + } + return ret; +} /** * ipa3_post_init() - Initialize the IPA Driver (Part II). * This part contains all initialization which requires interaction with @@ -4665,6 +4697,17 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, goto fail_register_device; } IPADBG("IPA gsi is registered\n"); + /* GSI 2.2 requires to allocate all EE GSI channel + * during device bootup. + */ + if (ipa3_get_gsi_ver(resource_p->ipa_hw_type) == GSI_VER_2_2) { + result = ipa3_alloc_gsi_channel(); + if (result) { + IPAERR("Failed to alloc the GSI channels\n"); + result = -ENODEV; + goto fail_alloc_gsi_channel; + } + } /* setup the AP-IPA pipes */ if (ipa3_setup_apps_pipes()) { @@ -4728,6 +4771,7 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, fail_teth_bridge_driver_init: ipa3_teardown_apps_pipes(); +fail_alloc_gsi_channel: fail_setup_apps_pipes: gsi_deregister_device(ipa3_ctx->gsi_dev_hdl, false); fail_register_device: diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index f80e7dece358..332ca67a2f47 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -2298,6 +2298,7 @@ void ipa3_proxy_clk_unvote(void); bool ipa3_is_client_handle_valid(u32 clnt_hdl); enum ipa_client_type ipa3_get_client_mapping(int pipe_idx); +enum ipa_client_type ipa3_get_client_by_pipe(int pipe_idx); void ipa_init_ep_flt_bitmap(void); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index f62a320f105a..de5a0b725744 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -3510,7 +3510,7 @@ enum ipa_client_type ipa3_get_client_mapping(int pipe_idx) * * Return value: client type */ -static enum ipa_client_type ipa3_get_client_by_pipe(int pipe_idx) +enum ipa_client_type ipa3_get_client_by_pipe(int pipe_idx) { int j = 0; diff --git a/include/linux/msm_gsi.h b/include/linux/msm_gsi.h index 70cd1fbe9109..2dae9a187f40 100644 --- a/include/linux/msm_gsi.h +++ b/include/linux/msm_gsi.h @@ -1209,6 +1209,19 @@ int gsi_unmap_base(void); */ int gsi_map_virtual_ch_to_per_ep(u32 ee, u32 chan_num, u32 per_ep_index); +/** + * gsi_alloc_channel_ee - Peripheral should call this function + * to alloc other EE's channel. This is usually done in bootup to allocate all + * chnnels. + * + * @chan_idx: Virtual channel index + * @ee: EE + * @code: [out] response code for operation + + * @Return gsi_status + */ +int gsi_alloc_channel_ee(unsigned int chan_idx, unsigned int ee, int *code); + /* * Here is a typical sequence of calls * @@ -1456,5 +1469,11 @@ static inline int gsi_map_virtual_ch_to_per_ep( return -GSI_STATUS_UNSUPPORTED_OP; } +static inline int gsi_alloc_channel_ee(unsigned int chan_idx, unsigned int ee, + int *code) +{ + return -GSI_STATUS_UNSUPPORTED_OP; +} + #endif #endif -- GitLab From aa4d4815912e1e45df08bfe9ac86bd5a07913858 Mon Sep 17 00:00:00 2001 From: Sudarshan Rajagopalan Date: Mon, 6 Aug 2018 14:45:40 -0700 Subject: [PATCH 0572/1001] soc: qcom: mem-offline: Fix klocwork errors Fix the NULL dereference Klocwork error report. Change-Id: I7f092cb3817b19a041fbf090d2a8e53bb503c462 Signed-off-by: Sudarshan Rajagopalan --- drivers/soc/qcom/mem-offline.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/mem-offline.c b/drivers/soc/qcom/mem-offline.c index 8a4eaeae684c..dbd160781342 100644 --- a/drivers/soc/qcom/mem-offline.c +++ b/drivers/soc/qcom/mem-offline.c @@ -324,10 +324,14 @@ static int mem_parse_dt(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; val = of_get_property(node, "granule", NULL); - if (!val && !*val) { + if (!val) { pr_err("mem-offine: granule property not found in DT\n"); return -EINVAL; } + if (!*val) { + pr_err("mem-offine: invalid granule property\n"); + return -EINVAL; + } offline_granule = be32_to_cpup(val); if (!offline_granule && !(offline_granule & (offline_granule - 1)) && offline_granule * SZ_1M < MIN_MEMORY_BLOCK_SIZE) { -- GitLab From a27f7d327b67f2660cd680008d68db81aaac403e Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Thu, 2 Aug 2018 16:40:10 -0700 Subject: [PATCH 0573/1001] msm: camera: crm: Perform the notification in workq on sof freeze In case of SOF freeze perform the task of notifying the devices in a workq instead of timer callback context to avoid watchdog bite from mutex lock. Change-Id: Ie787900e4a7f28209d9aa1d7e580186982f918db Signed-off-by: Vishalsingh Hajeri --- .../msm/camera/cam_req_mgr/cam_req_mgr_core.c | 61 +++++++++++++++---- .../msm/camera/cam_req_mgr/cam_req_mgr_core.h | 1 + 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c index 3c9d44fccaa8..edeecdbb6712 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c @@ -1140,24 +1140,26 @@ static void __cam_req_mgr_notify_sof_freeze( } /** - * __cam_req_mgr_sof_freeze() + * __cam_req_mgr_process_sof_freeze() * * @brief : Apoptosis - Handles case when connected devices are not responding - * @data : timer pointer + * @priv : link information + * @data : task data * */ -static void __cam_req_mgr_sof_freeze(unsigned long data) +static int __cam_req_mgr_process_sof_freeze(void *priv, void *data) { - struct cam_req_mgr_timer *timer = (struct cam_req_mgr_timer *)data; struct cam_req_mgr_core_link *link = NULL; struct cam_req_mgr_core_session *session = NULL; struct cam_req_mgr_message msg; + int rc = 0; - if (!timer) { - CAM_ERR(CAM_CRM, "NULL timer"); - return; + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + return -EINVAL; } - link = (struct cam_req_mgr_core_link *)timer->parent; + + link = (struct cam_req_mgr_core_link *)priv; session = (struct cam_req_mgr_core_session *)link->parent; CAM_ERR(CAM_CRM, "SOF freeze for session %d link 0x%x", @@ -1171,12 +1173,47 @@ static void __cam_req_mgr_sof_freeze(unsigned long data) msg.u.err_msg.request_id = 0; msg.u.err_msg.link_hdl = link->link_hdl; + rc = cam_req_mgr_notify_message(&msg, + V4L_EVENT_CAM_REQ_MGR_ERROR, V4L_EVENT_CAM_REQ_MGR_EVENT); - if (cam_req_mgr_notify_message(&msg, - V4L_EVENT_CAM_REQ_MGR_ERROR, V4L_EVENT_CAM_REQ_MGR_EVENT)) + if (rc) CAM_ERR(CAM_CRM, - "Error notifying SOF freeze for session %d link 0x%x", - session->session_hdl, link->link_hdl); + "Error notifying SOF freeze for session %d link 0x%x rc %d", + session->session_hdl, link->link_hdl, rc); + + return rc; +} + +/** + * __cam_req_mgr_sof_freeze() + * + * @brief : Callback function for timer timeout indicating SOF freeze + * @data : timer pointer + * + */ +static void __cam_req_mgr_sof_freeze(unsigned long data) +{ + struct cam_req_mgr_timer *timer = (struct cam_req_mgr_timer *)data; + struct crm_workq_task *task = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct crm_task_payload *task_data; + + if (!timer) { + CAM_ERR(CAM_CRM, "NULL timer"); + return; + } + + link = (struct cam_req_mgr_core_link *)timer->parent; + task = cam_req_mgr_workq_get_task(link->workq); + if (!task) { + CAM_ERR(CAM_CRM, "No empty task"); + return; + } + + task_data = (struct crm_task_payload *)task->payload; + task_data->type = CRM_WORKQ_TASK_NOTIFY_FREEZE; + task->process_cb = &__cam_req_mgr_process_sof_freeze; + cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); } /** diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h index 025c16aacfdf..68ec09b1e89e 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h @@ -45,6 +45,7 @@ enum crm_workq_task_type { CRM_WORKQ_TASK_APPLY_REQ, CRM_WORKQ_TASK_NOTIFY_SOF, CRM_WORKQ_TASK_NOTIFY_ERR, + CRM_WORKQ_TASK_NOTIFY_FREEZE, CRM_WORKQ_TASK_SCHED_REQ, CRM_WORKQ_TASK_FLUSH_REQ, CRM_WORKQ_TASK_INVALID, -- GitLab From 8276c8caf24b87c8e2a69766280ddf5e30f2cec5 Mon Sep 17 00:00:00 2001 From: Harsh Shah Date: Mon, 6 Aug 2018 15:25:23 -0700 Subject: [PATCH 0574/1001] Revert "ARM: dts: msm: Add camera dts for sm6150" This reverts commit d97e66506d08661394bd3fbfa4486eaebd029ffa. The original commit is causing conflicts with upstream changes because of common files modified. Reverting it and will reupload after pulling in the upstream changes and rebasing this change on top of it. This way there will be no conflict when we try to upstream the changes. Change-Id: I6c126e6a773dfeb06edad69314663a2a1ba020be Signed-off-by: Harsh Shah --- .../bindings/media/video/msm-cam-csiphy.txt | 2 +- .../dts/qcom/sm6150-camera-sensor-idp.dtsi | 378 ------ arch/arm64/boot/dts/qcom/sm6150-camera.dtsi | 1055 ----------------- .../boot/dts/qcom/sm6150-idp-overlay.dts | 1 - arch/arm64/boot/dts/qcom/sm6150-idp.dtsi | 1 - arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi | 278 ----- arch/arm64/boot/dts/qcom/sm6150.dtsi | 1 - 7 files changed, 1 insertion(+), 1715 deletions(-) delete mode 100644 arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi delete mode 100644 arch/arm64/boot/dts/qcom/sm6150-camera.dtsi diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt b/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt index 249dd04cc6e2..33865b225231 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt @@ -14,7 +14,7 @@ First Level Node - CSIPHY device Usage: required Value type: Definition: Should be "qcom,csiphy-v1.0", - "qcom,csiphy-v1.1", "qcom,csiphy-v2.0", "qcom,csiphy". + "qcom,csiphy-v1.1", "qcom,csiphy". - cell-index: csiphy hardware core index Usage: required diff --git a/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi deleted file mode 100644 index eaf3c8a9ab61..000000000000 --- a/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -&soc { - - led_flash_rear: qcom,camera-flash@0 { - cell-index = <0>; - reg = <0x00 0x00>; - compatible = "qcom,camera-flash"; - flash-source = <&pm6150l_flash0>; - torch-source = <&pm6150l_torch1>; - switch-source = <&pm6150l_switch0>; - status = "ok"; - }; - - led_flash_rear_aux: qcom,camera-flash@1 { - cell-index = <1>; - reg = <0x01 0x00>; - compatible = "qcom,camera-flash"; - flash-source = <&pm6150l_flash1>; - torch-source = <&pm6150l_torch1>; - switch-source = <&pm6150l_switch1>; - status = "ok"; - }; - - led_flash_front: qcom,camera-flash@2 { - cell-index = <2>; - reg = <0x02 0x00>; - compatible = "qcom,camera-flash"; - flash-source = <&pm6150l_flash2>; - torch-source = <&pm6150l_torch2>; - switch-source = <&pm6150l_switch2>; - status = "ok"; - enable-active-high; - gpio = <&tlmm 38 0>; - pinctrl-names = "default"; - pinctrl-0 = <&flash_led3_front_en>; - }; - - camera_ldo: gpio-regulator@0 { - compatible = "regulator-fixed"; - reg = <0x00 0x00>; - regulator-name = "camera_ldo"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - regulator-enable-ramp-delay = <135>; - enable-active-high; - gpio = <&pm6150l_gpios 3 0>; - pinctrl-names = "default"; - pinctrl-0 = <&cam_sensor_dvdd_en>; - vin-supply = <&pm6150l_s8>; - }; - - camera_vana0_ldo: gpio-regulator@1 { - compatible = "regulator-fixed"; - reg = <0x01 0x00>; - regulator-name = "camera_vana0_ldo"; - regulator-min-microvolt = <2850000>; - regulator-max-microvolt = <2850000>; - regulator-enable-ramp-delay = <233>; - enable-active-high; - gpio = <&pm6150l_gpios 9 0>; - pinctrl-names = "default"; - pinctrl-0 = <&cam_sensor_0_vana>; - vin-supply = <&pm6150l_bob>; - }; - - camera_vana1_2_ldo: gpio-regulator@2 { - compatible = "regulator-fixed"; - reg = <0x02 0x00>; - regulator-name = "camera_vana1_2_ldo"; - regulator-min-microvolt = <2850000>; - regulator-max-microvolt = <2850000>; - regulator-enable-ramp-delay = <233>; - enable-active-high; - gpio = <&pm6150l_gpios 4 0>; - pinctrl-names = "default"; - pinctrl-0 = <&cam_sensor_1_2_vana>; - vin-supply = <&pm6150l_bob>; - }; -}; - -&cam_cci { - qcom,cam-res-mgr { - compatible = "qcom,cam-res-mgr"; - status = "ok"; - }; - - actuator_rear: qcom,actuator@0 { - cell-index = <0>; - reg = <0x0>; - compatible = "qcom,actuator"; - cci-master = <0>; - cam_vaf-supply = <&pm6150_l19>; - regulator-names = "cam_vaf"; - rgltr-cntrl-support; - rgltr-min-voltage = <2800000>; - rgltr-max-voltage = <2800000>; - rgltr-load-current = <0>; - }; - - actuator_front: qcom,actuator@1 { - cell-index = <1>; - reg = <0x1>; - compatible = "qcom,actuator"; - cci-master = <1>; - cam_vaf-supply = <&pm6150_l19>; - regulator-names = "cam_vaf"; - rgltr-cntrl-support; - rgltr-min-voltage = <2800000>; - rgltr-max-voltage = <2800000>; - rgltr-load-current = <0>; - }; - - ois_rear: qcom,ois@0 { - cell-index = <0>; - reg = <0x0>; - compatible = "qcom,ois"; - cci-master = <0>; - cam_vaf-supply = <&pm6150_l19>; - regulator-names = "cam_vaf"; - rgltr-cntrl-support; - rgltr-min-voltage = <2800000>; - rgltr-max-voltage = <2800000>; - rgltr-load-current = <0>; - status = "disabled"; - }; - - eeprom_rear: qcom,eeprom@0 { - cell-index = <0>; - reg = <0>; - compatible = "qcom,eeprom"; - cam_vio-supply = <&pm6150_l13>; - cam_vana-supply = <&camera_vana0_ldo>; - cam_vdig-supply = <&camera_ldo>; - cam_clk-supply = <&titan_top_gdsc>; - cam_vaf-supply = <&pm6150_l19>; - regulator-names = "cam_vio", "cam_vana", "cam_vdig", - "cam_clk", "cam_vaf"; - rgltr-cntrl-support; - rgltr-min-voltage = <1800000 2850000 1200000 0 2800000>; - rgltr-max-voltage = <1800000 2850000 1200000 0 2800000>; - rgltr-load-current = <0 80000 105000 0 0>; - gpio-no-mux = <0>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk0_active - &cam_sensor_rear_active>; - pinctrl-1 = <&cam_sensor_mclk0_suspend - &cam_sensor_rear_suspend>; - gpios = <&tlmm 28 0>, - <&tlmm 47 0>; - gpio-reset = <1>; - gpio-req-tbl-num = <0 1>; - gpio-req-tbl-flags = <1 0>; - gpio-req-tbl-label = "CAMIF_MCLK0", - "CAM_RESET0"; - sensor-mode = <0>; - cci-master = <0>; - status = "ok"; - clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; - clock-names = "cam_clk"; - clock-cntl-level = "turbo"; - clock-rates = <24000000>; - }; - - eeprom_rear_aux: qcom,eeprom@1 { - cell-index = <1>; - reg = <0x1>; - compatible = "qcom,eeprom"; - cam_vio-supply = <&pm6150_l13>; - cam_vana-supply = <&camera_vana1_2_ldo>; - cam_vdig-supply = <&camera_ldo>; - cam_clk-supply = <&titan_top_gdsc>; - cam_vaf-supply = <&pm6150_l19>; - regulator-names = "cam_vio", "cam_vana", "cam_vdig", - "cam_clk", "cam_vaf"; - rgltr-cntrl-support; - rgltr-min-voltage = <1800000 2850000 1200000 0 2800000>; - rgltr-max-voltage = <1800000 2850000 1200000 0 2800000>; - rgltr-load-current = <105000 0 80000 0 0>; - gpio-no-mux = <0>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk1_active - &cam_sensor_rear2_active>; - pinctrl-1 = <&cam_sensor_mclk1_suspend - &cam_sensor_rear2_suspend>; - gpios = <&tlmm 29 0>, - <&tlmm 45 0>; - gpio-reset = <1>; - gpio-req-tbl-num = <0 1>; - gpio-req-tbl-flags = <1 0>; - gpio-req-tbl-label = "CAMIF_MCLK1", - "CAM_RESET1"; - sensor-position = <0>; - sensor-mode = <0>; - cci-master = <1>; - status = "ok"; - clock-names = "cam_clk"; - clock-cntl-level = "turbo"; - clock-rates = <24000000>; - }; - - eeprom_front: qcom,eeprom@2 { - cell-index = <2>; - reg = <0x2>; - compatible = "qcom,eeprom"; - cam_vio-supply = <&pm6150_l13>; - cam_vana-supply = <&camera_vana1_2_ldo>; - cam_vdig-supply = <&camera_ldo>; - cam_clk-supply = <&titan_top_gdsc>; - cam_vaf-supply = <&pm6150_l19>; - regulator-names = "cam_vio", "cam_vana", "cam_vdig", - "cam_clk", "cam_vaf"; - rgltr-cntrl-support; - rgltr-min-voltage = <1800000 2850000 1200000 0 2800000>; - rgltr-max-voltage = <1800000 2850000 1200000 0 2800000>; - rgltr-load-current = <0 80000 105000 0 0>; - gpio-no-mux = <0>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk2_active - &cam_sensor_front_active>; - pinctrl-1 = <&cam_sensor_mclk2_suspend - &cam_sensor_front_suspend>; - gpios = <&tlmm 30 0>, - <&tlmm 37 0>; - gpio-reset = <1>; - gpio-req-tbl-num = <0 1>; - gpio-req-tbl-flags = <1 0>; - gpio-req-tbl-label = "CAMIF_MCLK2", - "CAM_RESET2"; - sensor-mode = <0>; - cci-master = <1>; - status = "ok"; - clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; - clock-names = "cam_clk"; - clock-cntl-level = "turbo"; - clock-rates = <24000000>; - }; - - qcom,cam-sensor@0 { - cell-index = <0>; - compatible = "qcom,cam-sensor"; - reg = <0x0>; - csiphy-sd-index = <0>; - sensor-position-roll = <90>; - sensor-position-pitch = <0>; - sensor-position-yaw = <180>; - led-flash-src = <&led_flash_rear>; - actuator-src = <&actuator_rear>; - ois-src = <&ois_rear>; - eeprom-src = <&eeprom_rear>; - cam_vio-supply = <&pm6150_l13>; - cam_vana-supply = <&camera_vana0_ldo>; - cam_vdig-supply = <&camera_ldo>; - cam_clk-supply = <&titan_top_gdsc>; - regulator-names = "cam_vio", "cam_vana", "cam_vdig", - "cam_clk"; - rgltr-cntrl-support; - rgltr-min-voltage = <1800000 2850000 1200000 0>; - rgltr-max-voltage = <1800000 2850000 1200000 0>; - rgltr-load-current = <0 80000 105000 0>; - gpio-no-mux = <0>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk0_active - &cam_sensor_rear_active>; - pinctrl-1 = <&cam_sensor_mclk0_suspend - &cam_sensor_rear_suspend>; - gpios = <&tlmm 28 0>, - <&tlmm 47 0>; - gpio-reset = <1>; - gpio-req-tbl-num = <0 1>; - gpio-req-tbl-flags = <1 0>; - gpio-req-tbl-label = "CAMIF_MCLK0", - "CAM_RESET0"; - sensor-mode = <0>; - cci-master = <0>; - status = "ok"; - clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; - clock-names = "cam_clk"; - clock-cntl-level = "turbo"; - clock-rates = <24000000>; - }; - - qcom,cam-sensor@1 { - cell-index = <1>; - compatible = "qcom,cam-sensor"; - reg = <0x1>; - csiphy-sd-index = <1>; - sensor-position-roll = <90>; - sensor-position-pitch = <0>; - sensor-position-yaw = <180>; - led-flash-src = <&led_flash_rear_aux>; - eeprom-src = <&eeprom_rear_aux>; - cam_vio-supply = <&pm6150_l13>; - cam_vana-supply = <&camera_vana1_2_ldo>; - cam_vdig-supply = <&camera_ldo>; - cam_clk-supply = <&titan_top_gdsc>; - regulator-names = "cam_vio", "cam_vana", "cam_vdig", - "cam_clk"; - rgltr-cntrl-support; - rgltr-min-voltage = <1800000 2850000 1200000 0>; - rgltr-max-voltage = <1800000 2850000 1200000 0>; - rgltr-load-current = <105000 0 80000 0>; - gpio-no-mux = <0>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk1_active - &cam_sensor_rear2_active>; - pinctrl-1 = <&cam_sensor_mclk1_suspend - &cam_sensor_rear2_suspend>; - gpios = <&tlmm 29 0>, - <&tlmm 45 0>; - gpio-reset = <1>; - gpio-req-tbl-num = <0 1>; - gpio-req-tbl-flags = <1 0>; - gpio-req-tbl-label = "CAMIF_MCLK1", - "CAM_RESET1"; - sensor-mode = <0>; - cci-master = <1>; - status = "ok"; - clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; - clock-names = "cam_clk"; - clock-cntl-level = "turbo"; - clock-rates = <24000000>; - }; - - qcom,cam-sensor@2 { - cell-index = <2>; - compatible = "qcom,cam-sensor"; - reg = <0x02>; - csiphy-sd-index = <2>; - sensor-position-roll = <270>; - sensor-position-pitch = <0>; - sensor-position-yaw = <0>; - eeprom-src = <&eeprom_front>; - actuator-src = <&actuator_front>; - led-flash-src = <&led_flash_front>; - cam_vio-supply = <&pm6150_l13>; - cam_vana-supply = <&camera_vana1_2_ldo>; - cam_vdig-supply = <&camera_ldo>; - cam_clk-supply = <&titan_top_gdsc>; - regulator-names = "cam_vio", "cam_vana", "cam_vdig", - "cam_clk"; - rgltr-cntrl-support; - rgltr-min-voltage = <1800000 2850000 1200000 0>; - rgltr-max-voltage = <1800000 2850000 1200000 0>; - rgltr-load-current = <0 80000 105000 0>; - gpio-no-mux = <0>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk2_active - &cam_sensor_front_active>; - pinctrl-1 = <&cam_sensor_mclk2_suspend - &cam_sensor_front_suspend>; - gpios = <&tlmm 30 0>, - <&tlmm 37 0>; - gpio-reset = <1>; - gpio-req-tbl-num = <0 1>; - gpio-req-tbl-flags = <1 0>; - gpio-req-tbl-label = "CAMIF_MCLK2", - "CAM_RESET2"; - sensor-mode = <0>; - cci-master = <1>; - status = "ok"; - clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; - clock-names = "cam_clk"; - clock-cntl-level = "turbo"; - clock-rates = <24000000>; - }; -}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi b/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi deleted file mode 100644 index 5076b603c074..000000000000 --- a/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi +++ /dev/null @@ -1,1055 +0,0 @@ -/* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -&soc { - qcom,cam-req-mgr { - compatible = "qcom,cam-req-mgr"; - status = "ok"; - }; - - cam_csiphy0: qcom,csiphy@ac65000 { - cell-index = <0>; - compatible = "qcom,csiphy-v2.0", "qcom,csiphy"; - reg = <0x0ac65000 0x1000>; - reg-names = "csiphy"; - reg-cam-base = <0x65000>; - interrupts = <0 477 0>; - interrupt-names = "csiphy"; - regulator-names = "gdscr"; - gdscr-supply = <&titan_top_gdsc>; - csi-vdd-voltage = <1200000>; - mipi-csi-vdd-supply = <&pm6150l_l3>; - clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, - <&clock_camcc CAM_CC_SOC_AHB_CLK>, - <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, - <&clock_camcc CAM_CC_CPAS_AHB_CLK>, - <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, - <&clock_camcc CAM_CC_CSIPHY0_CLK>, - <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>, - <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>; - clock-names = "camnoc_axi_clk", - "soc_ahb_clk", - "slow_ahb_src_clk", - "cpas_ahb_clk", - "cphy_rx_clk_src", - "csiphy0_clk", - "csi0phytimer_clk_src", - "csi0phytimer_clk"; - clock-cntl-level = "turbo"; - clock-rates = - <0 0 0 0 384000000 0 269333333 0>; - status = "ok"; - }; - - cam_csiphy1: qcom,csiphy@ac66000{ - cell-index = <1>; - compatible = "qcom,csiphy-v2.0", "qcom,csiphy"; - reg = <0xac66000 0x1000>; - reg-names = "csiphy"; - reg-cam-base = <0x66000>; - interrupts = <0 478 0>; - interrupt-names = "csiphy"; - regulator-names = "gdscr"; - gdscr-supply = <&titan_top_gdsc>; - csi-vdd-voltage = <1200000>; - mipi-csi-vdd-supply = <&pm6150l_l3>; - clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, - <&clock_camcc CAM_CC_SOC_AHB_CLK>, - <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, - <&clock_camcc CAM_CC_CPAS_AHB_CLK>, - <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, - <&clock_camcc CAM_CC_CSIPHY1_CLK>, - <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>, - <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK>; - clock-names = "camnoc_axi_clk", - "soc_ahb_clk", - "slow_ahb_src_clk", - "cpas_ahb_clk", - "cphy_rx_clk_src", - "csiphy1_clk", - "csi1phytimer_clk_src", - "csi1phytimer_clk"; - clock-cntl-level = "turbo"; - clock-rates = - <0 0 0 0 384000000 0 269333333 0>; - - status = "ok"; - }; - - cam_csiphy2: qcom,csiphy@ac67000 { - cell-index = <2>; - compatible = "qcom,csiphy-v2.0", "qcom,csiphy"; - reg = <0xac67000 0x1000>; - reg-names = "csiphy"; - reg-cam-base = <0x67000>; - interrupts = <0 479 0>; - interrupt-names = "csiphy"; - regulator-names = "gdscr"; - gdscr-supply = <&titan_top_gdsc>; - csi-vdd-voltage = <1200000>; - mipi-csi-vdd-supply = <&pm6150l_l3>; - clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, - <&clock_camcc CAM_CC_SOC_AHB_CLK>, - <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, - <&clock_camcc CAM_CC_CPAS_AHB_CLK>, - <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, - <&clock_camcc CAM_CC_CSIPHY2_CLK>, - <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>, - <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK>; - clock-names = "camnoc_axi_clk", - "soc_ahb_clk", - "slow_ahb_src_clk", - "cpas_ahb_clk", - "cphy_rx_clk_src", - "csiphy2_clk", - "csi2phytimer_clk_src", - "csi2phytimer_clk"; - clock-cntl-level = "turbo"; - clock-rates = - <0 0 0 0 384000000 0 269333333 0>; - status = "ok"; - }; - - cam_cci: qcom,cci@ac4a000 { - cell-index = <0>; - compatible = "qcom,cci"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0xac4a000 0x4000>; - reg-names = "cci"; - reg-cam-base = <0x4a000>; - interrupt-names = "cci"; - interrupts = <0 460 0>; - status = "ok"; - gdscr-supply = <&titan_top_gdsc>; - regulator-names = "gdscr"; - clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, - <&clock_camcc CAM_CC_SOC_AHB_CLK>, - <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, - <&clock_camcc CAM_CC_CPAS_AHB_CLK>, - <&clock_camcc CAM_CC_CCI_CLK>, - <&clock_camcc CAM_CC_CCI_CLK_SRC>; - clock-names = "camnoc_axi_clk", - "soc_ahb_clk", - "slow_ahb_src_clk", - "cpas_ahb_clk", - "cci_clk", - "cci_clk_src"; - src-clock-name = "cci_clk_src"; - clock-cntl-level = "lowsvs"; - clock-rates = <0 0 0 0 0 37500000>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cci0_active &cci1_active>; - pinctrl-1 = <&cci0_suspend &cci1_suspend>; - gpios = <&tlmm 17 0>, - <&tlmm 18 0>, - <&tlmm 19 0>, - <&tlmm 20 0>; - gpio-req-tbl-num = <0 1 2 3>; - gpio-req-tbl-flags = <1 1 1 1>; - gpio-req-tbl-label = "CCI_I2C_DATA0", - "CCI_I2C_CLK0", - "CCI_I2C_DATA1", - "CCI_I2C_CLK1"; - - i2c_freq_100Khz: qcom,i2c_standard_mode { - hw-thigh = <201>; - hw-tlow = <174>; - hw-tsu-sto = <204>; - hw-tsu-sta = <231>; - hw-thd-dat = <22>; - hw-thd-sta = <162>; - hw-tbuf = <227>; - hw-scl-stretch-en = <0>; - hw-trdhld = <6>; - hw-tsp = <3>; - cci-clk-src = <37500000>; - status = "ok"; - }; - - i2c_freq_400Khz: qcom,i2c_fast_mode { - hw-thigh = <38>; - hw-tlow = <56>; - hw-tsu-sto = <40>; - hw-tsu-sta = <40>; - hw-thd-dat = <22>; - hw-thd-sta = <35>; - hw-tbuf = <62>; - hw-scl-stretch-en = <0>; - hw-trdhld = <6>; - hw-tsp = <3>; - cci-clk-src = <37500000>; - status = "ok"; - }; - - i2c_freq_custom: qcom,i2c_custom_mode { - hw-thigh = <38>; - hw-tlow = <56>; - hw-tsu-sto = <40>; - hw-tsu-sta = <40>; - hw-thd-dat = <22>; - hw-thd-sta = <35>; - hw-tbuf = <62>; - hw-scl-stretch-en = <1>; - hw-trdhld = <6>; - hw-tsp = <3>; - cci-clk-src = <37500000>; - status = "ok"; - }; - - i2c_freq_1Mhz: qcom,i2c_fast_plus_mode { - hw-thigh = <16>; - hw-tlow = <22>; - hw-tsu-sto = <17>; - hw-tsu-sta = <18>; - hw-thd-dat = <16>; - hw-thd-sta = <15>; - hw-tbuf = <24>; - hw-scl-stretch-en = <0>; - hw-trdhld = <3>; - hw-tsp = <3>; - cci-clk-src = <37500000>; - status = "ok"; - }; - }; - - qcom,cam_smmu { - compatible = "qcom,msm-cam-smmu"; - status = "ok"; - - msm_cam_smmu_ife { - compatible = "qcom,msm-cam-smmu-cb"; - iommus = <&apps_smmu 0x820 0x0>, - <&apps_smmu 0x840 0x0>, - <&apps_smmu 0x860 0x0>; - label = "ife"; - ife_iova_mem_map: iova-mem-map { - /* IO region is approximately 3.4 GB */ - iova-mem-region-io { - iova-region-name = "io"; - iova-region-start = <0x7400000>; - iova-region-len = <0xd8c00000>; - iova-region-id = <0x3>; - status = "ok"; - }; - }; - }; - - msm_cam_smmu_lrme { - compatible = "qcom,msm-cam-smmu-cb"; - iommus = <&apps_smmu 0x0cc0 0x0>, - <&apps_smmu 0x0d40 0x0>; - label = "lrme"; - lrme_iova_mem_map: iova-mem-map { - iova-mem-region-shared { - /* Shared region is 100MB long */ - iova-region-name = "shared"; - iova-region-start = <0x7400000>; - iova-region-len = <0x6400000>; - iova-region-id = <0x1>; - status = "ok"; - }; - /* IO region is approximately 3.3 GB */ - iova-mem-region-io { - iova-region-name = "io"; - iova-region-start = <0xd800000>; - iova-region-len = <0xd2800000>; - iova-region-id = <0x3>; - status = "ok"; - }; - }; - }; - - msm_cam_smmu_jpeg { - compatible = "qcom,msm-cam-smmu-cb"; - iommus = <&apps_smmu 0x1060 0x8>; - label = "jpeg"; - jpeg_iova_mem_map: iova-mem-map { - /* IO region is approximately 3.4 GB */ - iova-mem-region-io { - iova-region-name = "io"; - iova-region-start = <0x7400000>; - iova-region-len = <0xd8c00000>; - iova-region-id = <0x3>; - status = "ok"; - }; - }; - }; - - msm_cam_icp_fw { - compatible = "qcom,msm-cam-smmu-fw-dev"; - label="icp"; - memory-region = <&pil_camera_mem>; - }; - - msm_cam_smmu_icp { - compatible = "qcom,msm-cam-smmu-cb"; - iommus = <&apps_smmu 0x0de2 0x0>, - <&apps_smmu 0x0c80 0x0>, - <&apps_smmu 0x0ca0 0x0>, - <&apps_smmu 0x0d00 0x0>, - <&apps_smmu 0x0d20 0x0>; - label = "icp"; - icp_iova_mem_map: iova-mem-map { - iova-mem-region-firmware { - /* Firmware region is 5MB */ - iova-region-name = "firmware"; - iova-region-start = <0x0>; - iova-region-len = <0x500000>; - iova-region-id = <0x0>; - status = "ok"; - }; - - iova-mem-region-shared { - /* Shared region is 100MB long */ - iova-region-name = "shared"; - iova-region-start = <0x7400000>; - iova-region-len = <0x6400000>; - iova-region-id = <0x1>; - iova-granularity = <0x15>; - status = "ok"; - }; - - iova-mem-region-secondary-heap { - /* Secondary heap region is 1MB long */ - iova-region-name = "secheap"; - iova-region-start = <0xd800000>; - iova-region-len = <0x100000>; - iova-region-id = <0x4>; - status = "ok"; - }; - - iova-mem-region-io { - /* IO region is approximately 3 GB */ - iova-region-name = "io"; - iova-region-start = <0xd911000>; - iova-region-len = <0xd26ef000>; - iova-region-id = <0x3>; - status = "ok"; - }; - - iova-mem-qdss-region { - /* qdss region is approximately 64K */ - iova-region-name = "qdss"; - iova-region-start = <0xd900000>; - iova-region-len = <0x10000>; - iova-region-id = <0x5>; - qdss-phy-addr = <0x16790000>; - status = "ok"; - }; - }; - }; - - msm_cam_smmu_cpas_cdm { - compatible = "qcom,msm-cam-smmu-cb"; - iommus = <&apps_smmu 0x0c00 0x0>, - <&apps_smmu 0x0c01 0x0>; - label = "cpas-cdm0"; - cpas_cdm_iova_mem_map: iova-mem-map { - iova-mem-region-io { - /* IO region is approximately 3.4 GB */ - iova-region-name = "io"; - iova-region-start = <0x7400000>; - iova-region-len = <0xd8c00000>; - iova-region-id = <0x3>; - status = "ok"; - }; - }; - }; - - msm_cam_smmu_secure { - compatible = "qcom,msm-cam-smmu-cb"; - label = "cam-secure"; - qcom,secure-cb; - }; - }; - - qcom,cam-cpas@ac40000 { - cell-index = <0>; - compatible = "qcom,cam-cpas"; - label = "cpas"; - arch-compat = "cpas_top"; - status = "ok"; - reg-names = "cam_cpas_top", "cam_camnoc"; - reg = <0xac40000 0x1000>, - <0xac42000 0x5000>; - reg-cam-base = <0x40000 0x42000>; - interrupt-names = "cpas_camnoc"; - interrupts = <0 459 0>; - qcom,cpas-hw-ver = <0x150100>; /* Titan v150 v1.0.0 */ - camnoc-axi-min-ib-bw = <3000000000>; - regulator-names = "camss-vdd"; - camss-vdd-supply = <&titan_top_gdsc>; - clock-names = "gcc_ahb_clk", - "gcc_axi_clk", - "soc_ahb_clk", - "slow_ahb_clk_src", - "cpas_ahb_clk", - "camnoc_axi_clk"; - clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, - <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, - <&clock_camcc CAM_CC_SOC_AHB_CLK>, - <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, - <&clock_camcc CAM_CC_CPAS_AHB_CLK>, - <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; - src-clock-name = "slow_ahb_clk_src"; - clock-rates = <0 0 0 0 0 0>, - <0 0 0 80000000 0 0>, - <0 0 0 80000000 0 0>, - <0 0 0 80000000 0 0>, - <0 0 0 80000000 0 0>, - <0 0 0 80000000 0 0>, - <0 0 0 80000000 0 0>; - clock-cntl-level = "suspend", "minsvs", "lowsvs", "svs", - "svs_l1", "nominal", "turbo"; - qcom,msm-bus,name = "cam_ahb"; - qcom,msm-bus,num-cases = <7>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - , - , - , - , - , - , - ; - vdd-corners = ; - vdd-corner-ahb-mapping = "suspend", "suspend", - "minsvs", "lowsvs", "svs", "svs_l1", - "nominal", "nominal", "nominal", - "turbo", "turbo"; - client-id-based; - client-names = - "csiphy0", "csiphy1", "csiphy2", "cci0", - "csid0", "csid1", "csid2", - "ife0", "ife1", "ife2", "ipe0", - "ipe1", "cam-cdm-intf0", "cpas-cdm0", "bps0", - "icp0", "jpeg-dma0", "jpeg-enc0", "lrmecpas"; - client-axi-port-names = - "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", - "cam_hf_1", "cam_hf_2", "cam_hf_2", - "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", - "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1", - "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1"; - client-bus-camnoc-based; - qcom,axi-port-list { - qcom,axi-port1 { - qcom,axi-port-name = "cam_hf_1"; - qcom,axi-port-mnoc { - qcom,msm-bus,name = "cam_hf_1_mnoc"; - qcom,msm-bus-vector-dyn-vote; - qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - , - ; - }; - qcom,axi-port-camnoc { - qcom,msm-bus,name = "cam_hf_1_camnoc"; - qcom,msm-bus-vector-dyn-vote; - qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - , - ; - }; - }; - qcom,axi-port2 { - qcom,axi-port-name = "cam_hf_2"; - qcom,axi-port-mnoc { - qcom,msm-bus,name = "cam_hf_2_mnoc"; - qcom,msm-bus-vector-dyn-vote; - qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - , - ; - }; - qcom,axi-port-camnoc { - qcom,msm-bus,name = "cam_hf_2_camnoc"; - qcom,msm-bus-vector-dyn-vote; - qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - , - ; - }; - }; - qcom,axi-port3 { - qcom,axi-port-name = "cam_sf_1"; - qcom,axi-port-mnoc { - qcom,msm-bus,name = "cam_sf_1_mnoc"; - qcom,msm-bus-vector-dyn-vote; - qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - , - ; - }; - qcom,axi-port-camnoc { - qcom,msm-bus,name = "cam_sf_1_camnoc"; - qcom,msm-bus-vector-dyn-vote; - qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - , - ; - }; - }; - }; - }; - - qcom,cam-cdm-intf { - compatible = "qcom,cam-cdm-intf"; - cell-index = <0>; - label = "cam-cdm-intf"; - num-hw-cdm = <1>; - cdm-client-names = "vfe", - "jpegdma", - "jpegenc", - "lrmecdm"; - status = "ok"; - }; - - qcom,cpas-cdm0@ac48000 { - cell-index = <0>; - compatible = "qcom,cam170-cpas-cdm0"; - label = "cpas-cdm"; - reg = <0xac48000 0x1000>; - reg-names = "cpas-cdm"; - reg-cam-base = <0x48000>; - interrupts = <0 461 0>; - interrupt-names = "cpas-cdm"; - regulator-names = "camss"; - camss-supply = <&titan_top_gdsc>; - clock-names = "gcc_camera_ahb", - "gcc_camera_axi", - "cam_cc_soc_ahb_clk", - "cam_cc_cpas_ahb_clk", - "cam_cc_camnoc_axi_clk"; - clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, - <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, - <&clock_camcc CAM_CC_SOC_AHB_CLK>, - <&clock_camcc CAM_CC_CPAS_AHB_CLK>, - <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; - clock-rates = <0 0 0 0 0>; - clock-cntl-level = "svs"; - cdm-client-names = "ife"; - status = "ok"; - }; - - qcom,cam-isp { - compatible = "qcom,cam-isp"; - arch-compat = "ife"; - status = "ok"; - }; - - cam_csid0: qcom,csid0@acb3000 { - cell-index = <0>; - compatible = "qcom,csid170"; - reg-names = "csid"; - reg = <0xacb3000 0x1000>; - reg-cam-base = <0xb3000>; - interrupt-names = "csid"; - interrupts = <0 464 0>; - regulator-names = "camss", "ife0"; - camss-supply = <&titan_top_gdsc>; - ife0-supply = <&ife_0_gdsc>; - clock-names = "camera_ahb", - "camera_axi", - "soc_ahb_clk", - "cpas_ahb_clk", - "slow_ahb_clk_src", - "ife_csid_clk", - "ife_csid_clk_src", - "ife_cphy_rx_clk", - "cphy_rx_clk_src", - "ife_clk", - "ife_clk_src", - "camnoc_axi_clk", - "ife_axi_clk"; - clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, - <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, - <&clock_camcc CAM_CC_SOC_AHB_CLK>, - <&clock_camcc CAM_CC_CPAS_AHB_CLK>, - <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, - <&clock_camcc CAM_CC_IFE_0_CSID_CLK>, - <&clock_camcc CAM_CC_IFE_0_CSID_CLK_SRC>, - <&clock_camcc CAM_CC_IFE_0_CPHY_RX_CLK>, - <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, - <&clock_camcc CAM_CC_IFE_0_CLK>, - <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, - <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, - <&clock_camcc CAM_CC_IFE_0_AXI_CLK>; - clock-rates = - <0 0 0 0 0 0 200000000 0 0 0 360000000 0 0>, - <0 0 0 0 0 0 540000000 0 0 0 600000000 0 0>; - clock-cntl-level = "svs", "turbo"; - src-clock-name = "ife_csid_clk_src"; - status = "ok"; - }; - - cam_vfe0: qcom,vfe0@acaf000 { - cell-index = <0>; - compatible = "qcom,vfe170"; - reg-names = "ife"; - reg = <0xacaf000 0x4000>; - reg-cam-base = <0xaf000>; - interrupt-names = "ife"; - interrupts = <0 465 0>; - regulator-names = "camss", "ife0"; - camss-supply = <&titan_top_gdsc>; - ife0-supply = <&ife_0_gdsc>; - clock-names = "camera_ahb", - "camera_axi", - "soc_ahb_clk", - "cpas_ahb_clk", - "slow_ahb_clk_src", - "ife_clk", - "ife_clk_src", - "camnoc_axi_clk", - "ife_axi_clk"; - clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, - <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, - <&clock_camcc CAM_CC_SOC_AHB_CLK>, - <&clock_camcc CAM_CC_CPAS_AHB_CLK>, - <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, - <&clock_camcc CAM_CC_IFE_0_CLK>, - <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, - <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, - <&clock_camcc CAM_CC_IFE_0_AXI_CLK>; - clock-rates = - <0 0 0 0 0 0 360000000 0 0>, - <0 0 0 0 0 0 432000000 0 0>, - <0 0 0 0 0 0 540000000 0 0>, - <0 0 0 0 0 0 600000000 0 0>; - clock-cntl-level = "svs", "svs_l1", "nominal", "turbo"; - src-clock-name = "ife_clk_src"; - clock-names-option = "ife_dsp_clk"; - clocks-option = <&clock_camcc CAM_CC_IFE_0_DSP_CLK>; - clock-rates-option = <600000000>; - status = "ok"; - }; - - cam_csid1: qcom,csid1@acba000 { - cell-index = <1>; - compatible = "qcom,csid170"; - reg-names = "csid"; - reg = <0xacba000 0x1000>; - reg-cam-base = <0xba000>; - interrupt-names = "csid"; - interrupts = <0 466 0>; - regulator-names = "camss", "ife1"; - camss-supply = <&titan_top_gdsc>; - ife1-supply = <&ife_1_gdsc>; - clock-names = "camera_ahb", - "camera_axi", - "soc_ahb_clk", - "cpas_ahb_clk", - "slow_ahb_clk_src", - "ife_csid_clk", - "ife_csid_clk_src", - "ife_cphy_rx_clk", - "cphy_rx_clk_src", - "ife_clk", - "ife_clk_src", - "camnoc_axi_clk", - "ife_axi_clk"; - clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, - <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, - <&clock_camcc CAM_CC_SOC_AHB_CLK>, - <&clock_camcc CAM_CC_CPAS_AHB_CLK>, - <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, - <&clock_camcc CAM_CC_IFE_1_CSID_CLK>, - <&clock_camcc CAM_CC_IFE_1_CSID_CLK_SRC>, - <&clock_camcc CAM_CC_IFE_1_CPHY_RX_CLK>, - <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, - <&clock_camcc CAM_CC_IFE_1_CLK>, - <&clock_camcc CAM_CC_IFE_1_CLK_SRC>, - <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, - <&clock_camcc CAM_CC_IFE_1_AXI_CLK>; - clock-rates = - <0 0 0 0 0 0 200000000 0 0 0 360000000 0 0>, - <0 0 0 0 0 0 540000000 0 0 0 600000000 0 0>; - clock-cntl-level = "svs", "turbo"; - src-clock-name = "ife_csid_clk_src"; - status = "ok"; - }; - - cam_vfe1: qcom,vfe1@acb6000 { - cell-index = <1>; - compatible = "qcom,vfe170"; - reg-names = "ife"; - reg = <0xacb6000 0x4000>; - reg-cam-base = <0xb6000>; - interrupt-names = "ife"; - interrupts = <0 467 0>; - regulator-names = "camss", "ife1"; - camss-supply = <&titan_top_gdsc>; - ife1-supply = <&ife_1_gdsc>; - clock-names = "camera_ahb", - "camera_axi", - "soc_ahb_clk", - "cpas_ahb_clk", - "slow_ahb_clk_src", - "ife_clk", - "ife_clk_src", - "camnoc_axi_clk", - "ife_axi_clk"; - clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, - <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, - <&clock_camcc CAM_CC_SOC_AHB_CLK>, - <&clock_camcc CAM_CC_CPAS_AHB_CLK>, - <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, - <&clock_camcc CAM_CC_IFE_1_CLK>, - <&clock_camcc CAM_CC_IFE_1_CLK_SRC>, - <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, - <&clock_camcc CAM_CC_IFE_1_AXI_CLK>; - clock-rates = - <0 0 0 0 0 0 360000000 0 0>, - <0 0 0 0 0 0 432000000 0 0>, - <0 0 0 0 0 0 540000000 0 0>, - <0 0 0 0 0 0 600000000 0 0>; - clock-cntl-level = "svs", "svs_l1", "nominal", "turbo"; - src-clock-name = "ife_clk_src"; - clock-names-option = "ife_dsp_clk"; - clocks-option = <&clock_camcc CAM_CC_IFE_1_DSP_CLK>; - clock-rates-option = <600000000>; - status = "ok"; - }; - - cam_csid_lite: qcom,csid-lite@acc8000 { - cell-index = <2>; - compatible = "qcom,csid-lite170"; - reg-names = "csid-lite"; - reg = <0xacc8000 0x1000>; - reg-cam-base = <0xc8000>; - interrupt-names = "csid-lite"; - interrupts = <0 468 0>; - regulator-names = "camss"; - camss-supply = <&titan_top_gdsc>; - clock-names = "camera_ahb", - "camera_axi", - "soc_ahb_clk", - "cpas_ahb_clk", - "slow_ahb_clk_src", - "ife_csid_clk", - "ife_csid_clk_src", - "ife_cphy_rx_clk", - "cphy_rx_clk_src", - "ife_clk", - "ife_clk_src", - "camnoc_axi_clk"; - clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, - <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, - <&clock_camcc CAM_CC_SOC_AHB_CLK>, - <&clock_camcc CAM_CC_CPAS_AHB_CLK>, - <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, - <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK>, - <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, - <&clock_camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, - <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, - <&clock_camcc CAM_CC_IFE_LITE_CLK>, - <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>, - <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; - clock-rates = - <0 0 0 0 0 0 200000000 0 0 0 360000000 0>, - <0 0 0 0 0 0 540000000 0 0 0 600000000 0>; - clock-cntl-level = "svs", "turbo"; - src-clock-name = "ife_csid_clk_src"; - status = "ok"; - }; - - cam_vfe_lite: qcom,vfe-lite@acc4000 { - cell-index = <2>; - compatible = "qcom,vfe-lite170"; - reg-names = "ife-lite"; - reg = <0xacc4000 0x4000>; - reg-cam-base = <0xc4000>; - interrupt-names = "ife-lite"; - interrupts = <0 469 0>; - regulator-names = "camss"; - camss-supply = <&titan_top_gdsc>; - clock-names = "camera_ahb", - "camera_axi", - "soc_ahb_clk", - "cpas_ahb_clk", - "slow_ahb_clk_src", - "ife_clk", - "ife_clk_src", - "camnoc_axi_clk"; - clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, - <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, - <&clock_camcc CAM_CC_SOC_AHB_CLK>, - <&clock_camcc CAM_CC_CPAS_AHB_CLK>, - <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, - <&clock_camcc CAM_CC_IFE_LITE_CLK>, - <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>, - <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; - clock-rates = - <0 0 0 0 0 0 360000000 0>, - <0 0 0 0 0 0 432000000 0>, - <0 0 0 0 0 0 540000000 0>, - <0 0 0 0 0 0 600000000 0>; - clock-cntl-level = "svs", "svs_l1", "nominal", "turbo"; - src-clock-name = "ife_clk_src"; - status = "ok"; - }; - - qcom,cam-icp { - compatible = "qcom,cam-icp"; - compat-hw-name = "qcom,a5", - "qcom,ipe0", - "qcom,bps"; - num-a5 = <1>; - num-ipe = <1>; - num-bps = <1>; - status = "ok"; - }; - - cam_a5: qcom,a5@ac00000 { - cell-index = <0>; - compatible = "qcom,cam-a5"; - reg = <0xac00000 0x6000>, - <0xac10000 0x8000>, - <0xac18000 0x3000>; - reg-names = "a5_qgic", "a5_sierra", "a5_csr"; - reg-cam-base = <0x00000 0x10000 0x18000>; - interrupts = <0 463 0>; - interrupt-names = "a5"; - regulator-names = "camss-vdd"; - camss-vdd-supply = <&titan_top_gdsc>; - clock-names = "gcc_cam_ahb_clk", - "gcc_cam_axi_clk", - "soc_fast_ahb", - "soc_ahb_clk", - "cpas_ahb_clk", - "camnoc_axi_clk", - "icp_clk", - "icp_clk_src"; - clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, - <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, - <&clock_camcc CAM_CC_FAST_AHB_CLK_SRC>, - <&clock_camcc CAM_CC_SOC_AHB_CLK>, - <&clock_camcc CAM_CC_CPAS_AHB_CLK>, - <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, - <&clock_camcc CAM_CC_ICP_CLK>, - <&clock_camcc CAM_CC_ICP_CLK_SRC>; - - clock-rates = - <0 0 200000000 0 0 0 0 360000000>, - <0 0 200000000 0 0 0 0 600000000>; - clock-cntl-level = "svs", "turbo"; - fw_name = "CAMERA_ICP.elf"; - ubwc-cfg = <0x73 0x1CF>; - status = "ok"; - }; - - cam_ipe0: qcom,ipe0 { - cell-index = <0>; - compatible = "qcom,cam-ipe"; - regulator-names = "ipe0-vdd"; - ipe0-vdd-supply = <&ipe_0_gdsc>; - clock-names = "ipe_0_ahb_clk", - "ipe_0_areg_clk", - "ipe_0_axi_clk", - "ipe_0_clk", - "ipe_0_clk_src"; - src-clock-name = "ipe_0_clk_src"; - clocks = <&clock_camcc CAM_CC_IPE_0_AHB_CLK>, - <&clock_camcc CAM_CC_IPE_0_AREG_CLK>, - <&clock_camcc CAM_CC_IPE_0_AXI_CLK>, - <&clock_camcc CAM_CC_IPE_0_CLK>, - <&clock_camcc CAM_CC_IPE_0_CLK_SRC>; - - clock-rates = - <0 0 0 0 360000000>, - <0 0 0 0 432000000>, - <0 0 0 0 480000000>, - <0 0 0 0 540000000>, - <0 0 0 0 600000000>; - clock-cntl-level = "svs", - "svs_l1", "nominal", "nominal_l1", "turbo"; - status = "ok"; - }; - - cam_bps: qcom,bps { - cell-index = <0>; - compatible = "qcom,cam-bps"; - regulator-names = "bps-vdd"; - bps-vdd-supply = <&bps_gdsc>; - clock-names = "bps_ahb_clk", - "bps_areg_clk", - "bps_axi_clk", - "bps_clk", - "bps_clk_src"; - src-clock-name = "bps_clk_src"; - clocks = <&clock_camcc CAM_CC_BPS_AHB_CLK>, - <&clock_camcc CAM_CC_BPS_AREG_CLK>, - <&clock_camcc CAM_CC_BPS_AXI_CLK>, - <&clock_camcc CAM_CC_BPS_CLK>, - <&clock_camcc CAM_CC_BPS_CLK_SRC>; - - clock-rates = - <0 0 0 0 360000000>, - <0 0 0 0 432000000>, - <0 0 0 0 480000000>, - <0 0 0 0 540000000>, - <0 0 0 0 600000000>; - clock-cntl-level = "svs", - "svs_l1", "nominal", "nominal_l1", "turbo"; - status = "ok"; - }; - - qcom,cam-jpeg { - compatible = "qcom,cam-jpeg"; - compat-hw-name = "qcom,jpegenc", - "qcom,jpegdma"; - num-jpeg-enc = <1>; - num-jpeg-dma = <1>; - status = "ok"; - }; - - cam_jpeg_enc: qcom,jpegenc@ac4e000 { - cell-index = <0>; - compatible = "qcom,cam_jpeg_enc"; - reg-names = "jpege_hw"; - reg = <0xac4e000 0x4000>; - reg-cam-base = <0x4e000>; - interrupt-names = "jpeg"; - interrupts = <0 474 0>; - regulator-names = "camss-vdd"; - camss-vdd-supply = <&titan_top_gdsc>; - clock-names = "camera_ahb", - "camera_axi", - "soc_ahb_clk", - "cpas_ahb_clk", - "camnoc_axi_clk", - "jpegenc_clk_src", - "jpegenc_clk"; - clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, - <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, - <&clock_camcc CAM_CC_SOC_AHB_CLK>, - <&clock_camcc CAM_CC_CPAS_AHB_CLK>, - <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, - <&clock_camcc CAM_CC_JPEG_CLK_SRC>, - <&clock_camcc CAM_CC_JPEG_CLK>; - - clock-rates = <0 0 0 0 0 320000000 0>; - src-clock-name = "jpegenc_clk_src"; - clock-cntl-level = "nominal"; - status = "ok"; - }; - - cam_jpeg_dma: qcom,jpegdma@0xac52000{ - cell-index = <0>; - compatible = "qcom,cam_jpeg_dma"; - reg-names = "jpegdma_hw"; - reg = <0xac52000 0x4000>; - reg-cam-base = <0x52000>; - interrupt-names = "jpegdma"; - interrupts = <0 475 0>; - regulator-names = "camss-vdd"; - camss-vdd-supply = <&titan_top_gdsc>; - clock-names = "camera_ahb", - "camera_axi", - "soc_ahb_clk", - "cpas_ahb_clk", - "camnoc_axi_clk", - "jpegdma_clk_src", - "jpegdma_clk"; - clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, - <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, - <&clock_camcc CAM_CC_SOC_AHB_CLK>, - <&clock_camcc CAM_CC_CPAS_AHB_CLK>, - <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, - <&clock_camcc CAM_CC_JPEG_CLK_SRC>, - <&clock_camcc CAM_CC_JPEG_CLK>; - - clock-rates = <0 0 0 0 0 320000000 0>; - src-clock-name = "jpegdma_clk_src"; - clock-cntl-level = "nominal"; - status = "ok"; - }; - - qcom,cam-lrme { - compatible = "qcom,cam-lrme"; - arch-compat = "lrme"; - status = "ok"; - }; - - cam_lrme: qcom,lrme@ac6b000 { - cell-index = <0>; - compatible = "qcom,lrme"; - reg-names = "lrme"; - reg = <0xac6b000 0xa00>; - reg-cam-base = <0x6b000>; - interrupt-names = "lrme"; - interrupts = <0 476 0>; - regulator-names = "camss"; - camss-supply = <&titan_top_gdsc>; - clock-names = "camera_ahb", - "camera_axi", - "soc_ahb_clk", - "cpas_ahb_clk", - "camnoc_axi_clk", - "lrme_clk_src", - "lrme_clk"; - clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, - <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, - <&clock_camcc CAM_CC_SOC_AHB_CLK>, - <&clock_camcc CAM_CC_CPAS_AHB_CLK>, - <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, - <&clock_camcc CAM_CC_LRME_CLK_SRC>, - <&clock_camcc CAM_CC_LRME_CLK>; - clock-rates = <0 0 0 0 0 200000000 200000000>, - <0 0 0 0 0 216000000 216000000>, - <0 0 0 0 0 300000000 300000000>, - <0 0 0 0 0 404000000 404000000>, - <0 0 0 0 0 404000000 404000000>, - <0 0 0 0 0 404000000 404000000>; - clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal", - "nominal_l1", "turbo"; - src-clock-name = "lrme_clk_src"; - status = "ok"; - }; -}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts index de09032f4db1..ae891836ed6b 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts @@ -14,7 +14,6 @@ /plugin/; #include -#include #include "sm6150-idp.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi index 698609b4fcbf..f9f7bc31ec86 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi @@ -10,7 +10,6 @@ * GNU General Public License for more details. */ -#include "sm6150-camera-sensor-idp.dtsi" &soc { }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi index a22754aefc93..5e62775e0761 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi @@ -580,283 +580,5 @@ drive-strength = <2>; /* 2 MA */ }; }; - - cci0_active: cci0_active { - mux { - /* CLK, DATA */ - pins = "gpio32", "gpio33"; - function = "cci_i2c"; - }; - - config { - pins = "gpio32", "gpio33"; - bias-pull-up; /* PULL UP*/ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cci0_suspend: cci0_suspend { - mux { - /* CLK, DATA */ - pins = "gpio32", "gpio33"; - function = "cci_i2c"; - }; - - config { - pins = "gpio32", "gpio33"; - bias-pull-down; /* PULL DOWN */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cci1_active: cci1_active { - mux { - /* CLK, DATA */ - pins = "gpio34", "gpio35"; - function = "cci_i2c"; - }; - - config { - pins = "gpio34", "gpio35"; - bias-pull-up; /* PULL UP*/ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cci1_suspend: cci1_suspend { - mux { - /* CLK, DATA */ - pins = "gpio34", "gpio35"; - function = "cci_i2c"; - }; - - config { - pins = "gpio34", "gpio35"; - bias-pull-down; /* PULL DOWN */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cam_sensor_mclk0_active: cam_sensor_mclk0_active { - /* MCLK0 */ - mux { - pins = "gpio28"; - function = "cam_mclk"; - }; - - config { - pins = "gpio28"; - bias-disable; /* No PULL */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cam_sensor_mclk0_suspend: cam_sensor_mclk0_suspend { - /* MCLK0 */ - mux { - pins = "gpio28"; - function = "cam_mclk"; - }; - - config { - pins = "gpio28"; - bias-pull-down; /* PULL DOWN */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cam_sensor_rear_active: cam_sensor_rear_active { - /* RESET */ - mux { - pins = "gpio47"; - function = "gpio"; - }; - - config { - pins = "gpio47"; - bias-disable; /* No PULL */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cam_sensor_rear_suspend: cam_sensor_rear_suspend { - /* RESET */ - mux { - pins = "gpio47"; - function = "gpio"; - }; - - config { - pins = "gpio47"; - bias-pull-down; /* PULL DOWN */ - drive-strength = <2>; /* 2 MA */ - output-low; - }; - }; - - cam_sensor_front_active: cam_sensor_front_active { - /* RESET */ - mux { - pins = "gpio37"; - function = "gpio"; - }; - - config { - pins = "gpio37"; - bias-disable; /* No PULL */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cam_sensor_front_suspend: cam_sensor_front_suspend { - /* RESET */ - mux { - pins = "gpio37"; - function = "gpio"; - }; - - config { - pins = "gpio37"; - bias-pull-down; /* PULL DOWN */ - drive-strength = <2>; /* 2 MA */ - output-low; - }; - }; - - cam_sensor_rear2_active: cam_sensor_rear2_active { - /* RESET */ - mux { - pins = "gpio45"; - function = "gpio"; - }; - - config { - pins = "gpio45"; - bias-disable; /* No PULL */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cam_sensor_rear2_suspend: cam_sensor_rear2_suspend { - /* RESET */ - mux { - pins = "gpio45"; - function = "gpio"; - }; - - config { - pins = "gpio45"; - bias-pull-down; /* PULL DOWN */ - drive-strength = <2>; /* 2 MA */ - output-low; - }; - }; - - cam_sensor_mclk1_active: cam_sensor_mclk1_active { - /* MCLK1 */ - mux { - pins = "gpio29"; - function = "cam_mclk"; - }; - - config { - pins = "gpio29"; - bias-disable; /* No PULL */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cam_sensor_mclk1_suspend: cam_sensor_mclk1_suspend { - /* MCLK1 */ - mux { - pins = "gpio29"; - function = "cam_mclk"; - }; - - config { - pins = "gpio29"; - bias-pull-down; /* PULL DOWN */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cam_sensor_mclk2_active: cam_sensor_mclk2_active { - /* MCLK2 */ - mux { - pins = "gpio30"; - function = "cam_mclk"; - }; - - config { - pins = "gpio30"; - bias-disable; /* No PULL */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cam_sensor_mclk2_suspend: cam_sensor_mclk2_suspend { - /* MCLK2 */ - mux { - pins = "gpio30"; - function = "cam_mclk"; - }; - - config { - pins = "gpio30"; - bias-pull-down; /* PULL DOWN */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - flash_led3_front { - flash_led3_front_en: flash_led3_front_en { - mux { - pins = "gpio38"; - function = "gpio"; - }; - - config { - pins = "gpio38"; - drive_strength = <2>; - output-high; - bias-disable; - }; - }; - - flash_led3_front_dis: flash_led3_front_dis { - mux { - pins = "gpio38"; - function = "gpio"; - }; - - config { - pins = "gpio38"; - drive_strength = <2>; - output-low; - bias-disable; - }; - }; - }; - }; -}; - -&pm6150l_gpios { - cam_sensor_dvdd_en: cam_sensor_dvdd_en { - pins = "gpio3"; - function = "normal"; - power-source = <0>; - output-low; - }; - cam_sensor_0_vana: cam_sensor_0_vana { - pins = "gpio9"; - function = "normal"; - power-source = <0>; - output-low; - }; - cam_sensor_1_2_vana: cam_sensor_1_2_vana { - pins = "gpio4"; - function = "normal"; - power-source = <0>; - output-low; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index ff8bf79dd766..7a4fd67bf018 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -1935,7 +1935,6 @@ status = "ok"; }; -#include "sm6150-camera.dtsi" #include "sm6150-ion.dtsi" #include "msm-arm-smmu-sm6150.dtsi" #include "sm6150-coresight.dtsi" -- GitLab From 76b35fa8d95780d92d9241226fcfe6308ccdb29d Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Fri, 25 May 2018 15:50:14 +0530 Subject: [PATCH 0575/1001] usb: f_gsi: Report Function Remote Wake capabilities Add support for sending Function Wake capabilities in response to GET_STATUS from the host. GET_STATUS addressed to an Interface allows the device to report if it is capable of doing a Function Remote Wake. Windows8/10 MBIM hosts request this information before enabling Suspend in SS mode. Change-Id: Ic0a6db57b2b46804a82847de511feb433a3dfca6 Signed-off-by: Devdutt Patnaik Signed-off-by: Chandana Kishori Chiluveru --- drivers/usb/dwc3/ep0.c | 10 +++++++++- drivers/usb/gadget/function/f_gsi.c | 9 +++++++++ include/linux/usb/composite.h | 3 +++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 3518ab3908e9..772c5b4e75fa 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -43,6 +43,8 @@ MODULE_PARM_DESC(enable_dwc3_u1u2, "Enable support for U1U2 low power modes"); static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep); static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_request *req); +static int dwc3_ep0_delegate_req(struct dwc3 *dwc, + struct usb_ctrlrequest *ctrl); static void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep, dma_addr_t buf_dma, u32 len, u32 type, bool chain) @@ -332,12 +334,14 @@ static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le) static void dwc3_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req) { } + /* * ch 9.4.5 */ static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { + int ret; struct dwc3_ep *dep; u32 recip; u32 value; @@ -377,7 +381,8 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, * Function Remote Wake Capable D0 * Function Remote Wakeup D1 */ - break; + ret = dwc3_ep0_delegate_req(dwc, ctrl); + return ret; case USB_RECIP_ENDPOINT: dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); @@ -538,6 +543,9 @@ static int dwc3_ep0_handle_intf(struct dwc3 *dwc, * For now, we're not doing anything, just making sure we return * 0 so USB Command Verifier tests pass without any errors. */ + ret = dwc3_ep0_delegate_req(dwc, ctrl); + if (ret) + return ret; break; default: ret = -EINVAL; diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 88bc5a574f53..d40fb9a2fa75 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -2342,6 +2342,14 @@ static void gsi_resume(struct usb_function *f) log_event_dbg("%s: completed", __func__); } +static int gsi_get_status(struct usb_function *f) +{ + unsigned int remote_wakeup_en_status = f->func_wakeup_allowed ? 1 : 0; + + return (remote_wakeup_en_status << FUNC_WAKEUP_ENABLE_SHIFT) | + (1 << FUNC_WAKEUP_CAPABLE_SHIFT); +} + static int gsi_func_suspend(struct usb_function *f, u8 options) { bool func_wakeup_allowed; @@ -3002,6 +3010,7 @@ static int gsi_bind_config(struct f_gsi *gsi) gsi->function.disable = gsi_disable; gsi->function.free_func = gsi_free_func; gsi->function.suspend = gsi_suspend; + gsi->function.get_status = gsi_get_status; gsi->function.func_suspend = gsi_func_suspend; gsi->function.resume = gsi_resume; diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 9a1fabc6ff03..46b467d68b8d 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -45,6 +45,9 @@ #define FUNC_SUSPEND_OPT_SUSP_MASK BIT(0) #define FUNC_SUSPEND_OPT_RW_EN_MASK BIT(1) +#define FUNC_WAKEUP_CAPABLE_SHIFT 0 +#define FUNC_WAKEUP_ENABLE_SHIFT 1 + /* * USB function drivers should return USB_GADGET_DELAYED_STATUS if they * wish to delay the data/status stages of the control transfer till they -- GitLab From 2f23e8e6cb0c7e01195f660bd64afafd1962deee Mon Sep 17 00:00:00 2001 From: Mangesh Kunchamwar Date: Tue, 7 Aug 2018 15:03:18 +0530 Subject: [PATCH 0576/1001] ARM: dts: msm: updating audio route for qcs405 Updating audio routing to get MCLK event for csra targets. Change-Id: I2a1ffc9503e8d416db632c9e56d05de9b6dca093 Signed-off-by: Surendar Karka Signed-off-by: Mangesh Kunchamwar --- arch/arm64/boot/dts/qcom/qcs405-csra1-audio-overlay.dtsi | 1 + arch/arm64/boot/dts/qcom/qcs405-csra6-audio-overlay.dtsi | 1 + arch/arm64/boot/dts/qcom/qcs405-wsa-audio-overlay.dtsi | 1 + 3 files changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs405-csra1-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/qcs405-csra1-audio-overlay.dtsi index e32a117768da..1ad579c963cb 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-csra1-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-csra1-audio-overlay.dtsi @@ -30,6 +30,7 @@ qcom,cdc-dmic45-gpios = <&cdc_dmic45_gpios>; qcom,cdc-dmic67-gpios = <&cdc_dmic67_gpios>; qcom,audio-routing = + "RX_BIAS", "MCLK", "AMIC3", "MIC BIAS3", "AMIC4", "MIC BIAS4", "MIC BIAS3", "Analog Mic3", diff --git a/arch/arm64/boot/dts/qcom/qcs405-csra6-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/qcs405-csra6-audio-overlay.dtsi index 9138ebf733e7..76b39a57b791 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-csra6-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-csra6-audio-overlay.dtsi @@ -33,6 +33,7 @@ qcom,cdc-dmic45-gpios = <&cdc_dmic45_gpios>; qcom,cdc-dmic67-gpios = <&cdc_dmic67_gpios>; qcom,audio-routing = + "RX_BIAS", "MCLK", "AMIC3", "MIC BIAS3", "AMIC4", "MIC BIAS4", "MIC BIAS3", "Analog Mic3", diff --git a/arch/arm64/boot/dts/qcom/qcs405-wsa-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/qcs405-wsa-audio-overlay.dtsi index b1d41ae2355b..1a6ca3013bd6 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-wsa-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-wsa-audio-overlay.dtsi @@ -33,6 +33,7 @@ qcom,cdc-dmic45-gpios = <&cdc_dmic45_gpios>; qcom,cdc-dmic67-gpios = <&cdc_dmic67_gpios>; qcom,audio-routing = + "RX_BIAS", "MCLK", "AMIC3", "MIC BIAS3", "AMIC4", "MIC BIAS4", "MIC BIAS3", "Analog Mic3", -- GitLab From 55852060050102713127ef916c90f8c0e6c87397 Mon Sep 17 00:00:00 2001 From: Aditya Bavanari Date: Tue, 26 Jun 2018 18:34:32 +0530 Subject: [PATCH 0577/1001] ARM: dts: msm: add mdf memory region on qcs405 Add MDF memory region node that is used to allocate buffers to support MDF feature in qcs405. Change-Id: I1d034cd0323ca793158e8a4e3583d08ede2b91f0 Signed-off-by: Aditya Bavanari --- arch/arm64/boot/dts/qcom/qcs405.dtsi | 39 ++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index c79446345c93..0e2360075e71 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -88,6 +88,14 @@ size = <0 0x7000000>; }; + mdf_mem: mdf_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x800000>; + }; + qseecom_mem: qseecom_region { compatible = "shared-dma-pool"; reusable; @@ -732,6 +740,37 @@ }; }; + qcom,msm-mdf-mem { + compatible = "qcom,msm-mdf-mem-region"; + qcom,msm-mdf-mem-data-size = <0x200000>; + memory-region = <&mdf_mem>; + }; + + qcom,msm-mdf { + compatible = "qcom,msm-mdf"; + + qcom,msm_mdf_cb1 { + compatible = "qcom,msm-mdf-cb"; + label = "adsp"; + qcom,smmu-enabled; + }; + + qcom,msm_mdf_cb2 { + compatible = "qcom,msm-mdf-cb"; + label = "dsps"; + }; + + qcom,msm_mdf_cb3 { + compatible = "qcom,msm-mdf-cb"; + label = "modem"; + }; + + qcom,msm_mdf_cb4 { + compatible = "qcom,msm-mdf-cb"; + label = "cdsp"; + }; + }; + rpm-glink { compatible = "qcom,glink-rpm"; interrupts = ; -- GitLab From 71f643385e56c1dff3e5c9fcfb358a166440b19c Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Mon, 14 Dec 2015 15:42:47 -0800 Subject: [PATCH 0578/1001] regulator: fan53555: change fan53555_parse_dt() to read only DT parameters Currently, fan53555_parse_dt() does a platform data allocation in addition to reading device tree parameters. Move the memory allocation out of fan53555_parse_dt() and change it only to parse device tree parameters to match its name. This helps to expand the function to read other device tree parameters. CRs-Fixed: 968575 Change-Id: Id876d54bede15c73a298a6bfa68af7097115e36b Signed-off-by: Subbaraman Narayanamurthy --- drivers/regulator/fan53555.c | 38 +++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index a3bc8037153e..0fb5abf8fca8 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -344,26 +344,27 @@ static const struct regmap_config fan53555_regmap_config = { .val_bits = 8, }; -static struct fan53555_platform_data *fan53555_parse_dt(struct device *dev, - struct device_node *np, - const struct regulator_desc *desc) +static int fan53555_parse_dt(struct fan53555_device_info *di, + struct fan53555_platform_data *pdata, + const struct regulator_desc *desc) { - struct fan53555_platform_data *pdata; + struct device *dev = di->dev; + struct device_node *np = dev->of_node; int ret; u32 tmp; - pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return NULL; - pdata->regulator = of_get_regulator_init_data(dev, np, desc); + if (!pdata->regulator) { + dev_err(dev, "regulator init data is missing\n"); + return -ENODEV; + } ret = of_property_read_u32(np, "fcs,suspend-voltage-selector", &tmp); if (!ret) pdata->sleep_vsel_id = tmp; - return pdata; + return ret; } static const struct of_device_id fan53555_dt_ids[] = { @@ -384,7 +385,6 @@ MODULE_DEVICE_TABLE(of, fan53555_dt_ids); static int fan53555_regulator_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct device_node *np = client->dev.of_node; struct fan53555_device_info *di; struct fan53555_platform_data *pdata; struct regulator_config config = { }; @@ -397,14 +397,17 @@ static int fan53555_regulator_probe(struct i2c_client *client, return -ENOMEM; pdata = dev_get_platdata(&client->dev); - if (!pdata) - pdata = fan53555_parse_dt(&client->dev, np, &di->desc); - - if (!pdata || !pdata->regulator) { - dev_err(&client->dev, "Platform data not found!\n"); - return -ENODEV; + if (!pdata) { + pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; } + di->dev = &client->dev; + ret = fan53555_parse_dt(di, pdata, &di->desc); + if (ret) + return ret; + di->regulator = pdata->regulator; if (client->dev.of_node) { di->vendor = @@ -427,7 +430,6 @@ static int fan53555_regulator_probe(struct i2c_client *client, dev_err(&client->dev, "Failed to allocate regmap!\n"); return PTR_ERR(di->regmap); } - di->dev = &client->dev; i2c_set_clientdata(client, di); /* Get chip ID */ ret = regmap_read(di->regmap, FAN53555_ID1, &val); @@ -456,7 +458,7 @@ static int fan53555_regulator_probe(struct i2c_client *client, config.init_data = di->regulator; config.regmap = di->regmap; config.driver_data = di; - config.of_node = np; + config.of_node = client->dev.of_node; ret = fan53555_regulator_register(di, &config); if (ret < 0) -- GitLab From 985417160a24cb57746832200d896045b8251c0a Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Mon, 7 Dec 2015 16:42:03 -0800 Subject: [PATCH 0579/1001] regulator: fan53555: add support for Halo HL7509 buck converter Halo HL7509 is a digitally programmable buck converter that outputs a voltage from 600 to 1230 mV from an input voltage of 2.5 to 5.5 V. Since the register mappings are compatible with FAN53555, add a new vendor ID to support it. CRs-Fixed: 968575 Change-Id: I0083a7ada311d624731e43755cfd371b2364fb39 Signed-off-by: Subbaraman Narayanamurthy --- .../devicetree/bindings/regulator/fan53555.txt | 11 ++++++++++- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + drivers/regulator/fan53555.c | 10 ++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/regulator/fan53555.txt b/Documentation/devicetree/bindings/regulator/fan53555.txt index 54a3f2c80e3a..cc875e211f5d 100644 --- a/Documentation/devicetree/bindings/regulator/fan53555.txt +++ b/Documentation/devicetree/bindings/regulator/fan53555.txt @@ -1,7 +1,8 @@ Binding for Fairchild FAN53555 regulators Required properties: - - compatible: one of "fcs,fan53555", "silergy,syr827", "silergy,syr828" + - compatible: one of "fcs,fan53555", "silergy,syr827", "silergy,syr828" or + "halo,hl7509" - reg: I2C address Optional properties: @@ -21,3 +22,11 @@ Example: vin-supply = <&parent_reg>; fcs,suspend-voltage-selector = <1>; }; + + regulator@60 { + compatible = "halo,hl7509"; + regulator-name = "hl7509"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1230000>; + fcs,suspend-voltage-selector = <1>; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index ea764a49c6bc..23224632812c 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -136,6 +136,7 @@ grinn Grinn grmn Garmin Limited gumstix Gumstix, Inc. gw Gateworks Corporation +halo Halo Microelectronics Co., Ltd. hannstar HannStar Display Corporation haoyu Haoyu Microelectronic Co. Ltd. hardkernel Hardkernel Co., Ltd diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 0fb5abf8fca8..60b8d45ac791 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -55,6 +55,7 @@ enum fan53555_vendor { FAN53555_VENDOR_FAIRCHILD = 0, FAN53555_VENDOR_SILERGY, + HALO_HL7509, }; /* IC Type */ @@ -309,6 +310,9 @@ static int fan53555_device_setup(struct fan53555_device_info *di, case FAN53555_VENDOR_SILERGY: ret = fan53555_voltages_setup_silergy(di); break; + case HALO_HL7509: + ret = fan53555_voltages_setup_fairchild(di); + break; default: dev_err(di->dev, "vendor %d not supported!\n", di->vendor); return -EINVAL; @@ -377,6 +381,9 @@ static const struct of_device_id fan53555_dt_ids[] = { }, { .compatible = "silergy,syr828", .data = (void *)FAN53555_VENDOR_SILERGY, + }, { + .compatible = "halo,hl7509", + .data = (void *)HALO_HL7509, }, { } }; @@ -477,6 +484,9 @@ static const struct i2c_device_id fan53555_id[] = { }, { .name = "syr828", .driver_data = FAN53555_VENDOR_SILERGY + }, { + .name = "hl7509", + .driver_data = HALO_HL7509 }, { }, }; -- GitLab From c73d4af1eda8e4cffbc6a61b916077360df91368 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Mon, 14 Dec 2015 16:49:05 -0800 Subject: [PATCH 0580/1001] regulator: fan53555: add support to disable suspend voltage configuration Currently, fan53555 regulator driver always registers for set_suspend_voltage. This force configures the regulator to set suspend voltage switching to a different voltage selector. However, this might not be preferred for certain applications. Add a device tree parameter "fcs,disable-suspend" for the regulator which when specified will disable suspend voltage configuration. CRs-Fixed: 968575 Change-Id: Ib9f450126482e606f3e057857b7a58800583519a Signed-off-by: Subbaraman Narayanamurthy --- Documentation/devicetree/bindings/regulator/fan53555.txt | 5 +++++ drivers/regulator/fan53555.c | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/fan53555.txt b/Documentation/devicetree/bindings/regulator/fan53555.txt index cc875e211f5d..90ca0b70d555 100644 --- a/Documentation/devicetree/bindings/regulator/fan53555.txt +++ b/Documentation/devicetree/bindings/regulator/fan53555.txt @@ -11,6 +11,10 @@ Optional properties: voltage. The other one is used for the runtime voltage setting Possible values are either <0> or <1> - vin-supply: regulator supplying the vin pin + - fcs,disable-suspend: Boolean flag which specifies if suspend voltage + configuration should be avoided. If this property is present, + then the voltage selector register defined by + fcs,suspend-voltage-selector should not be modified at runtime. Example: @@ -29,4 +33,5 @@ Example: regulator-min-microvolt = <600000>; regulator-max-microvolt = <1230000>; fcs,suspend-voltage-selector = <1>; + fcs,disable-suspend; }; diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 60b8d45ac791..bb768cc44285 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -99,6 +99,8 @@ struct fan53555_device_info { unsigned int slew_rate; /* Sleep voltage cache */ unsigned int sleep_vol_cache; + /* Disable suspend */ + bool disable_suspend; }; static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV) @@ -106,6 +108,8 @@ static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV) struct fan53555_device_info *di = rdev_get_drvdata(rdev); int ret; + if (di->disable_suspend) + return 0; if (di->sleep_vol_cache == uV) return 0; ret = regulator_map_voltage_linear(rdev, uV, uV); @@ -368,6 +372,8 @@ static int fan53555_parse_dt(struct fan53555_device_info *di, if (!ret) pdata->sleep_vsel_id = tmp; + di->disable_suspend = of_property_read_bool(np, "fcs,disable-suspend"); + return ret; } -- GitLab From 80d9915fe06b7039699276798403d32a27a62cf2 Mon Sep 17 00:00:00 2001 From: Abhinay Reddy Vanipally Date: Fri, 3 Aug 2018 11:12:11 -0700 Subject: [PATCH 0581/1001] ARM: dts: msm: Disable NFC and camera on sm8150-sdx50m QRD platform Disable NFC and camera for initial sm8150-sdx50m QRD platforms. CRs-Fixed: 2290865 Change-Id: If3758e5ac50578f54a6ca6d0f1f0552ee2e92d69 Signed-off-by: Abhinay Reddy Vanipally --- arch/arm64/boot/dts/qcom/sm8150-sdx50m-qrd-overlay.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdx50m-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sm8150-sdx50m-qrd-overlay.dts index 0822195eddc9..8d384978ba3a 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sdx50m-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm8150-sdx50m-qrd-overlay.dts @@ -29,3 +29,11 @@ compatible = "qcom,sm8150-qrd", "qcom,sm8150", "qcom,qrd"; qcom,board-id = <11 1>; }; + +&cam_cci0 { + status = "disabled"; +}; + +&qupv3_se9_i2c { + status = "disabled"; +}; -- GitLab From 865f974fc804b22fb5fa7be09579cb9215ba9309 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Mon, 23 Jul 2018 14:54:20 +0530 Subject: [PATCH 0582/1001] power: smb5: add support to export "POWER_SUPPLY_PROP_CHARGE_FULL" Add support to expose "POWER_SUPPLY_PROP_CHARGE_FULL" from battery power supply class. While at it, create a common function to read properties from "bms" power_supply_class. Change-Id: I5980006c4429a835c0f5bf674f5de2657d990517 Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/qpnp-smb5.c | 19 ++++-- drivers/power/supply/qcom/smb5-lib.c | 92 ++++++--------------------- drivers/power/supply/qcom/smb5-lib.h | 13 +--- 3 files changed, 38 insertions(+), 86 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index e27dc6a9b79c..da5d33b8b21b 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -1128,6 +1128,7 @@ static enum power_supply_property smb5_batt_props[] = { POWER_SUPPLY_PROP_CHARGE_COUNTER, POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_RECHARGE_SOC, + POWER_SUPPLY_PROP_CHARGE_FULL, }; static int smb5_batt_get_prop(struct power_supply *psy, @@ -1178,14 +1179,16 @@ static int smb5_batt_get_prop(struct power_supply *psy, val->intval = chg->sw_jeita_enabled; break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: - rc = smblib_get_prop_batt_voltage_now(chg, val); + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_VOLTAGE_NOW, val); break; case POWER_SUPPLY_PROP_VOLTAGE_MAX: val->intval = get_client_vote(chg->fv_votable, BATT_PROFILE_VOTER); break; case POWER_SUPPLY_PROP_CURRENT_NOW: - rc = smblib_get_prop_batt_current_now(chg, val); + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_CURRENT_NOW, val); break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: val->intval = get_client_vote(chg->fcc_votable, @@ -1195,7 +1198,7 @@ static int smb5_batt_get_prop(struct power_supply *psy, rc = smblib_get_prop_batt_iterm(chg, val); break; case POWER_SUPPLY_PROP_TEMP: - rc = smblib_get_prop_batt_temp(chg, val); + rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_TEMP, val); break; case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = POWER_SUPPLY_TECHNOLOGY_LION; @@ -1224,10 +1227,12 @@ static int smb5_batt_get_prop(struct power_supply *psy, val->intval = 0; break; case POWER_SUPPLY_PROP_CHARGE_COUNTER: - rc = smblib_get_prop_batt_charge_counter(chg, val); + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_CHARGE_COUNTER, val); break; case POWER_SUPPLY_PROP_CYCLE_COUNT: - rc = smblib_get_prop_batt_cycle_count(chg, val); + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_CYCLE_COUNT, val); break; case POWER_SUPPLY_PROP_RECHARGE_SOC: val->intval = chg->auto_recharge_soc; @@ -1235,6 +1240,10 @@ static int smb5_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE: val->intval = 0; break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_CHARGE_FULL, val); + break; default: pr_err("batt power supply prop %d not supported\n", psp); return -EINVAL; diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index b6b6691a404b..6e38d7f45c4f 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -629,6 +629,21 @@ static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg, /******************** * HELPER FUNCTIONS * ********************/ + +int smblib_get_prop_from_bms(struct smb_charger *chg, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int rc; + + if (!chg->bms_psy) + return -EINVAL; + + rc = power_supply_get_property(chg->bms_psy, psp, val); + + return rc; +} + int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable) { int rc; @@ -859,7 +874,7 @@ void smblib_suspend_on_debug_battery(struct smb_charger *chg) int rc; union power_supply_propval val; - rc = power_supply_get_property(chg->bms_psy, + rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_DEBUG_BATTERY, &val); if (rc < 0) { smblib_err(chg, "Couldn't get debug battery prop rc=%d\n", rc); @@ -1328,9 +1343,8 @@ int smblib_get_prop_batt_capacity(struct smb_charger *chg, return 0; } - if (chg->bms_psy) - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_CAPACITY, val); + rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_CAPACITY, val); + return rc; } @@ -1473,7 +1487,8 @@ int smblib_get_prop_batt_health(struct smb_charger *chg, stat); if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) { - rc = smblib_get_prop_batt_voltage_now(chg, &pval); + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval); if (!rc) { /* * If Vbatt is within 40mV above Vfloat, then don't @@ -1544,32 +1559,6 @@ int smblib_get_prop_input_current_limited(struct smb_charger *chg, return 0; } -int smblib_get_prop_batt_voltage_now(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - - if (!chg->bms_psy) - return -EINVAL; - - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_VOLTAGE_NOW, val); - return rc; -} - -int smblib_get_prop_batt_current_now(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - - if (!chg->bms_psy) - return -EINVAL; - - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_CURRENT_NOW, val); - return rc; -} - int smblib_get_prop_batt_iterm(struct smb_charger *chg, union power_supply_propval *val) { @@ -1609,19 +1598,6 @@ int smblib_get_prop_batt_iterm(struct smb_charger *chg, return rc; } -int smblib_get_prop_batt_temp(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - - if (!chg->bms_psy) - return -EINVAL; - - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_TEMP, val); - return rc; -} - int smblib_get_prop_batt_charge_done(struct smb_charger *chg, union power_supply_propval *val) { @@ -1640,32 +1616,6 @@ int smblib_get_prop_batt_charge_done(struct smb_charger *chg, return 0; } -int smblib_get_prop_batt_charge_counter(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - - if (!chg->bms_psy) - return -EINVAL; - - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_CHARGE_COUNTER, val); - return rc; -} - -int smblib_get_prop_batt_cycle_count(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - - if (!chg->bms_psy) - return -EINVAL; - - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_CYCLE_COUNT, val); - return rc; -} - /*********************** * BATTERY PSY SETTERS * ***********************/ @@ -4183,7 +4133,7 @@ static void jeita_update_work(struct work_struct *work) if (!chg->bms_psy) return; - rc = power_supply_get_property(chg->bms_psy, + rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_RESISTANCE_ID, &val); if (rc < 0) { smblib_err(chg, "Failed to get batt-id rc=%d\n", rc); diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 188d15fa3ffe..2e6f96fe2681 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -461,18 +461,8 @@ int smblib_get_prop_system_temp_level_max(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_input_current_limited(struct smb_charger *chg, union power_supply_propval *val); -int smblib_get_prop_batt_voltage_now(struct smb_charger *chg, - union power_supply_propval *val); -int smblib_get_prop_batt_current_now(struct smb_charger *chg, - union power_supply_propval *val); int smblib_get_prop_batt_iterm(struct smb_charger *chg, union power_supply_propval *val); -int smblib_get_prop_batt_temp(struct smb_charger *chg, - union power_supply_propval *val); -int smblib_get_prop_batt_charge_counter(struct smb_charger *chg, - union power_supply_propval *val); -int smblib_get_prop_batt_cycle_count(struct smb_charger *chg, - union power_supply_propval *val); int smblib_set_prop_input_suspend(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_batt_capacity(struct smb_charger *chg, @@ -558,6 +548,9 @@ int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg, union power_supply_propval *val); int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, const union power_supply_propval *val); +int smblib_get_prop_from_bms(struct smb_charger *chg, + enum power_supply_property psp, + union power_supply_propval *val); int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable); int smblib_icl_override(struct smb_charger *chg, bool override); -- GitLab From eb4812fc464986db1144e10992d216b8e4f762e3 Mon Sep 17 00:00:00 2001 From: Harsh Shah Date: Mon, 6 Aug 2018 22:55:47 -0700 Subject: [PATCH 0583/1001] ARM: dts: msm: Add camera dts node for sm6150 Add camera dts node for SM6150 target used by camera driver. Change-Id: Ie551e06661b782f4332745d70d767121d2139287 Signed-off-by: Ravikishore Pampana Signed-off-by: Alok Pandey Signed-off-by: Om Parkash Signed-off-by: Harsh Shah --- .../bindings/media/video/msm-cam-csiphy.txt | 2 +- .../dts/qcom/sm6150-camera-sensor-idp.dtsi | 378 ++++++ arch/arm64/boot/dts/qcom/sm6150-camera.dtsi | 1055 +++++++++++++++++ .../boot/dts/qcom/sm6150-idp-overlay.dts | 1 + arch/arm64/boot/dts/qcom/sm6150-idp.dtsi | 2 + arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi | 278 +++++ arch/arm64/boot/dts/qcom/sm6150.dtsi | 1 + 7 files changed, 1716 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sm6150-camera.dtsi diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt b/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt index 33865b225231..249dd04cc6e2 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt @@ -14,7 +14,7 @@ First Level Node - CSIPHY device Usage: required Value type: Definition: Should be "qcom,csiphy-v1.0", - "qcom,csiphy-v1.1", "qcom,csiphy". + "qcom,csiphy-v1.1", "qcom,csiphy-v2.0", "qcom,csiphy". - cell-index: csiphy hardware core index Usage: required diff --git a/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi new file mode 100644 index 000000000000..eaf3c8a9ab61 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-idp.dtsi @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + + led_flash_rear: qcom,camera-flash@0 { + cell-index = <0>; + reg = <0x00 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash0>; + torch-source = <&pm6150l_torch1>; + switch-source = <&pm6150l_switch0>; + status = "ok"; + }; + + led_flash_rear_aux: qcom,camera-flash@1 { + cell-index = <1>; + reg = <0x01 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash1>; + torch-source = <&pm6150l_torch1>; + switch-source = <&pm6150l_switch1>; + status = "ok"; + }; + + led_flash_front: qcom,camera-flash@2 { + cell-index = <2>; + reg = <0x02 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash2>; + torch-source = <&pm6150l_torch2>; + switch-source = <&pm6150l_switch2>; + status = "ok"; + enable-active-high; + gpio = <&tlmm 38 0>; + pinctrl-names = "default"; + pinctrl-0 = <&flash_led3_front_en>; + }; + + camera_ldo: gpio-regulator@0 { + compatible = "regulator-fixed"; + reg = <0x00 0x00>; + regulator-name = "camera_ldo"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-enable-ramp-delay = <135>; + enable-active-high; + gpio = <&pm6150l_gpios 3 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_dvdd_en>; + vin-supply = <&pm6150l_s8>; + }; + + camera_vana0_ldo: gpio-regulator@1 { + compatible = "regulator-fixed"; + reg = <0x01 0x00>; + regulator-name = "camera_vana0_ldo"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&pm6150l_gpios 9 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_0_vana>; + vin-supply = <&pm6150l_bob>; + }; + + camera_vana1_2_ldo: gpio-regulator@2 { + compatible = "regulator-fixed"; + reg = <0x02 0x00>; + regulator-name = "camera_vana1_2_ldo"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&pm6150l_gpios 4 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_1_2_vana>; + vin-supply = <&pm6150l_bob>; + }; +}; + +&cam_cci { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; + + actuator_rear: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm6150_l19>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_front: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&pm6150_l19>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + ois_rear: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + cci-master = <0>; + cam_vaf-supply = <&pm6150_l19>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + status = "disabled"; + }; + + eeprom_rear: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm6150_l13>; + cam_vana-supply = <&camera_vana0_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm6150_l19>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-max-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend>; + gpios = <&tlmm 28 0>, + <&tlmm 47 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_rear_aux: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm6150_l13>; + cam_vana-supply = <&camera_vana1_2_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm6150_l19>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-max-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-load-current = <105000 0 80000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 29 0>, + <&tlmm 45 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_front: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm6150_l13>; + cam_vana-supply = <&camera_vana1_2_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm6150_l19>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-max-voltage = <1800000 2850000 1200000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_front_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 30 0>, + <&tlmm 37 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear>; + ois-src = <&ois_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&pm6150_l13>; + cam_vana-supply = <&camera_vana0_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0>; + rgltr-max-voltage = <1800000 2850000 1200000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend>; + gpios = <&tlmm 28 0>, + <&tlmm 47 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear_aux>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&pm6150_l13>; + cam_vana-supply = <&camera_vana1_2_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0>; + rgltr-max-voltage = <1800000 2850000 1200000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 29 0>, + <&tlmm 45 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + actuator-src = <&actuator_front>; + led-flash-src = <&led_flash_front>; + cam_vio-supply = <&pm6150_l13>; + cam_vana-supply = <&camera_vana1_2_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2850000 1200000 0>; + rgltr-max-voltage = <1800000 2850000 1200000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_front_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 30 0>, + <&tlmm 37 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi b/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi new file mode 100644 index 000000000000..b26b1ed6d4db --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi @@ -0,0 +1,1055 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + qcom,cam-req-mgr { + compatible = "qcom,cam-req-mgr"; + status = "ok"; + }; + + cam_csiphy0: qcom,csiphy@ac65000 { + cell-index = <0>; + compatible = "qcom,csiphy-v2.0", "qcom,csiphy"; + reg = <0x0ac65000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x65000>; + interrupts = <0 477 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr"; + gdscr-supply = <&titan_top_gdsc>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm6150l_l3>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY0_CLK>, + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy0_clk", + "csi0phytimer_clk_src", + "csi0phytimer_clk"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + status = "ok"; + }; + + cam_csiphy1: qcom,csiphy@ac66000{ + cell-index = <1>; + compatible = "qcom,csiphy-v2.0", "qcom,csiphy"; + reg = <0xac66000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x66000>; + interrupts = <0 478 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr"; + gdscr-supply = <&titan_top_gdsc>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm6150l_l3>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY1_CLK>, + <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy1_clk", + "csi1phytimer_clk_src", + "csi1phytimer_clk"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + + status = "ok"; + }; + + cam_csiphy2: qcom,csiphy@ac67000 { + cell-index = <2>; + compatible = "qcom,csiphy-v2.0", "qcom,csiphy"; + reg = <0xac67000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x67000>; + interrupts = <0 479 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr"; + gdscr-supply = <&titan_top_gdsc>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm6150l_l3>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY2_CLK>, + <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy2_clk", + "csi2phytimer_clk_src", + "csi2phytimer_clk"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + status = "ok"; + }; + + cam_cci: qcom,cci@ac4a000 { + cell-index = <0>; + compatible = "qcom,cci"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xac4a000 0x4000>; + reg-names = "cci"; + reg-cam-base = <0x4a000>; + interrupt-names = "cci"; + interrupts = <0 460 0>; + status = "ok"; + gdscr-supply = <&titan_top_gdsc>; + regulator-names = "gdscr"; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CCI_CLK>, + <&clock_camcc CAM_CC_CCI_CLK_SRC>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cci_clk", + "cci_clk_src"; + src-clock-name = "cci_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <0 0 0 0 0 37500000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cci0_active &cci1_active>; + pinctrl-1 = <&cci0_suspend &cci1_suspend>; + gpios = <&tlmm 17 0>, + <&tlmm 18 0>, + <&tlmm 19 0>, + <&tlmm 20 0>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 1 1 1>; + gpio-req-tbl-label = "CCI_I2C_DATA0", + "CCI_I2C_CLK0", + "CCI_I2C_DATA1", + "CCI_I2C_CLK1"; + + i2c_freq_100Khz: qcom,i2c_standard_mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz: qcom,i2c_fast_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_custom: qcom,i2c_custom_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz: qcom,i2c_fast_plus_mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <0>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + qcom,cam_smmu { + compatible = "qcom,msm-cam-smmu"; + status = "ok"; + + msm_cam_smmu_ife { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x820 0x0>, + <&apps_smmu 0x840 0x0>, + <&apps_smmu 0x860 0x0>; + label = "ife"; + ife_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_lrme { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x0cc0 0x0>, + <&apps_smmu 0x0d40 0x0>; + label = "lrme"; + lrme_iova_mem_map: iova-mem-map { + iova-mem-region-shared { + /* Shared region is 100MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x6400000>; + iova-region-id = <0x1>; + status = "ok"; + }; + /* IO region is approximately 3.3 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0xd800000>; + iova-region-len = <0xd2800000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_jpeg { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1060 0x8>; + label = "jpeg"; + jpeg_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_icp_fw { + compatible = "qcom,msm-cam-smmu-fw-dev"; + label="icp"; + memory-region = <&pil_camera_mem>; + }; + + msm_cam_smmu_icp { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x0de2 0x0>, + <&apps_smmu 0x0c80 0x0>, + <&apps_smmu 0x0ca0 0x0>, + <&apps_smmu 0x0d00 0x0>, + <&apps_smmu 0x0d20 0x0>; + label = "icp"; + icp_iova_mem_map: iova-mem-map { + iova-mem-region-firmware { + /* Firmware region is 5MB */ + iova-region-name = "firmware"; + iova-region-start = <0x0>; + iova-region-len = <0x500000>; + iova-region-id = <0x0>; + status = "ok"; + }; + + iova-mem-region-shared { + /* Shared region is 100MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x6400000>; + iova-region-id = <0x1>; + iova-granularity = <0x15>; + status = "ok"; + }; + + iova-mem-region-secondary-heap { + /* Secondary heap region is 1MB long */ + iova-region-name = "secheap"; + iova-region-start = <0xd800000>; + iova-region-len = <0x100000>; + iova-region-id = <0x4>; + status = "ok"; + }; + + iova-mem-region-io { + /* IO region is approximately 3 GB */ + iova-region-name = "io"; + iova-region-start = <0xd911000>; + iova-region-len = <0xd26ef000>; + iova-region-id = <0x3>; + status = "ok"; + }; + + iova-mem-qdss-region { + /* qdss region is approximately 64K */ + iova-region-name = "qdss"; + iova-region-start = <0xd900000>; + iova-region-len = <0x10000>; + iova-region-id = <0x5>; + qdss-phy-addr = <0x16790000>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_cpas_cdm { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x0c00 0x0>, + <&apps_smmu 0x0c01 0x0>; + label = "cpas-cdm0"; + cpas_cdm_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 3.4 GB */ + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_secure { + compatible = "qcom,msm-cam-smmu-cb"; + label = "cam-secure"; + qcom,secure-cb; + }; + }; + + qcom,cam-cpas@ac40000 { + cell-index = <0>; + compatible = "qcom,cam-cpas"; + label = "cpas"; + arch-compat = "cpas_top"; + status = "ok"; + reg-names = "cam_cpas_top", "cam_camnoc"; + reg = <0xac40000 0x1000>, + <0xac42000 0x5000>; + reg-cam-base = <0x40000 0x42000>; + interrupt-names = "cpas_camnoc"; + interrupts = <0 459 0>; + qcom,cpas-hw-ver = <0x150100>; /* Titan v150 v1.0.0 */ + camnoc-axi-min-ib-bw = <3000000000>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_ahb_clk", + "gcc_axi_clk", + "soc_ahb_clk", + "slow_ahb_clk_src", + "cpas_ahb_clk", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + src-clock-name = "slow_ahb_clk_src"; + clock-rates = <0 0 0 0 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>; + clock-cntl-level = "suspend", "minsvs", "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + qcom,msm-bus,name = "cam_ahb"; + qcom,msm-bus,num-cases = <7>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + , + , + , + , + ; + vdd-corners = ; + vdd-corner-ahb-mapping = "suspend", "suspend", + "minsvs", "lowsvs", "svs", "svs_l1", + "nominal", "nominal", "nominal", + "turbo", "turbo"; + client-id-based; + client-names = + "csiphy0", "csiphy1", "csiphy2", "cci0", + "csid0", "csid1", "csid2", + "ife0", "ife1", "ife2", "ipe0", + "ipe1", "cam-cdm-intf0", "cpas-cdm0", "bps0", + "icp0", "jpeg-dma0", "jpeg-enc0", "lrmecpas"; + client-axi-port-names = + "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", + "cam_hf_1", "cam_hf_2", "cam_hf_2", + "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", + "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1", + "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1"; + client-bus-camnoc-based; + qcom,axi-port-list { + qcom,axi-port1 { + qcom,axi-port-name = "cam_hf_1"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_hf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_hf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + qcom,axi-port2 { + qcom,axi-port-name = "cam_hf_2"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_hf_2_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_hf_2_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + qcom,axi-port3 { + qcom,axi-port-name = "cam_sf_1"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_sf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_sf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + }; + }; + + qcom,cam-cdm-intf { + compatible = "qcom,cam-cdm-intf"; + cell-index = <0>; + label = "cam-cdm-intf"; + num-hw-cdm = <1>; + cdm-client-names = "vfe", + "jpegdma", + "jpegenc", + "lrmecdm"; + status = "ok"; + }; + + qcom,cpas-cdm0@ac48000 { + cell-index = <0>; + compatible = "qcom,cam170-cpas-cdm0"; + label = "cpas-cdm"; + reg = <0xac48000 0x1000>; + reg-names = "cpas-cdm"; + reg-cam-base = <0x48000>; + interrupts = <0 461 0>; + interrupt-names = "cpas-cdm"; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "gcc_camera_ahb", + "gcc_camera_axi", + "cam_cc_soc_ahb_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-rates = <0 0 0 0 0>; + clock-cntl-level = "svs"; + cdm-client-names = "ife"; + status = "ok"; + }; + + qcom,cam-isp { + compatible = "qcom,cam-isp"; + arch-compat = "ife"; + status = "ok"; + }; + + cam_csid0: qcom,csid0@acb3000 { + cell-index = <0>; + compatible = "qcom,csid170"; + reg-names = "csid"; + reg = <0xacb3000 0x1000>; + reg-cam-base = <0xb3000>; + interrupt-names = "csid"; + interrupts = <0 464 0>; + regulator-names = "camss", "ife0"; + camss-supply = <&titan_top_gdsc>; + ife0-supply = <&ife_0_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_0_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 200000000 0 0 0 360000000 0 0>, + <0 0 0 0 0 0 540000000 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe0: qcom,vfe0@acaf000 { + cell-index = <0>; + compatible = "qcom,vfe170"; + reg-names = "ife"; + reg = <0xacaf000 0x4000>; + reg-cam-base = <0xaf000>; + interrupt-names = "ife"; + interrupts = <0 465 0>; + regulator-names = "camss", "ife0"; + camss-supply = <&titan_top_gdsc>; + ife0-supply = <&ife_0_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_0_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 360000000 0 0>, + <0 0 0 0 0 0 432000000 0 0>, + <0 0 0 0 0 0 540000000 0 0>, + <0 0 0 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "svs_l1", "nominal", "turbo"; + src-clock-name = "ife_clk_src"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&clock_camcc CAM_CC_IFE_0_DSP_CLK>; + clock-rates-option = <600000000>; + status = "ok"; + }; + + cam_csid1: qcom,csid1@acba000 { + cell-index = <1>; + compatible = "qcom,csid170"; + reg-names = "csid"; + reg = <0xacba000 0x1000>; + reg-cam-base = <0xba000>; + interrupt-names = "csid"; + interrupts = <0 466 0>; + regulator-names = "camss", "ife1"; + camss-supply = <&titan_top_gdsc>; + ife1-supply = <&ife_1_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_1_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CLK>, + <&clock_camcc CAM_CC_IFE_1_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_1_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 200000000 0 0 0 360000000 0 0>, + <0 0 0 0 0 0 540000000 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe1: qcom,vfe1@acb6000 { + cell-index = <1>; + compatible = "qcom,vfe170"; + reg-names = "ife"; + reg = <0xacb6000 0x4000>; + reg-cam-base = <0xb6000>; + interrupt-names = "ife"; + interrupts = <0 467 0>; + regulator-names = "camss", "ife1"; + camss-supply = <&titan_top_gdsc>; + ife1-supply = <&ife_1_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CLK>, + <&clock_camcc CAM_CC_IFE_1_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_1_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 360000000 0 0>, + <0 0 0 0 0 0 432000000 0 0>, + <0 0 0 0 0 0 540000000 0 0>, + <0 0 0 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "svs_l1", "nominal", "turbo"; + src-clock-name = "ife_clk_src"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&clock_camcc CAM_CC_IFE_1_DSP_CLK>; + clock-rates-option = <600000000>; + status = "ok"; + }; + + cam_csid_lite: qcom,csid-lite@acc8000 { + cell-index = <2>; + compatible = "qcom,csid-lite170"; + reg-names = "csid-lite"; + reg = <0xacc8000 0x1000>; + reg-cam-base = <0xc8000>; + interrupt-names = "csid-lite"; + interrupts = <0 468 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 200000000 0 0 0 360000000 0>, + <0 0 0 0 0 0 540000000 0 0 0 600000000 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe_lite: qcom,vfe-lite@acc4000 { + cell-index = <2>; + compatible = "qcom,vfe-lite170"; + reg-names = "ife-lite"; + reg = <0xacc4000 0x4000>; + reg-cam-base = <0xc4000>; + interrupt-names = "ife-lite"; + interrupts = <0 469 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 360000000 0>, + <0 0 0 0 0 0 432000000 0>, + <0 0 0 0 0 0 540000000 0>, + <0 0 0 0 0 0 600000000 0>; + clock-cntl-level = "svs", "svs_l1", "nominal", "turbo"; + src-clock-name = "ife_clk_src"; + status = "ok"; + }; + + qcom,cam-icp { + compatible = "qcom,cam-icp"; + compat-hw-name = "qcom,a5", + "qcom,ipe0", + "qcom,bps"; + num-a5 = <1>; + num-ipe = <1>; + num-bps = <1>; + status = "ok"; + }; + + cam_a5: qcom,a5@ac00000 { + cell-index = <0>; + compatible = "qcom,cam-a5"; + reg = <0xac00000 0x6000>, + <0xac10000 0x8000>, + <0xac18000 0x3000>; + reg-names = "a5_qgic", "a5_sierra", "a5_csr"; + reg-cam-base = <0x00000 0x10000 0x18000>; + interrupts = <0 463 0>; + interrupt-names = "a5"; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_cam_ahb_clk", + "gcc_cam_axi_clk", + "soc_fast_ahb", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "icp_clk", + "icp_clk_src"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_ICP_CLK>, + <&clock_camcc CAM_CC_ICP_CLK_SRC>; + + clock-rates = + <0 0 200000000 0 0 0 0 360000000>, + <0 0 200000000 0 0 0 0 600000000>; + clock-cntl-level = "svs", "turbo"; + fw_name = "CAMERA_ICP.elf"; + ubwc-cfg = <0x73 0x1CF>; + status = "ok"; + }; + + cam_ipe0: qcom,ipe0 { + cell-index = <0>; + compatible = "qcom,cam-ipe"; + regulator-names = "ipe0-vdd"; + ipe0-vdd-supply = <&ipe_0_gdsc>; + clock-names = "ipe_0_ahb_clk", + "ipe_0_areg_clk", + "ipe_0_axi_clk", + "ipe_0_clk", + "ipe_0_clk_src"; + src-clock-name = "ipe_0_clk_src"; + clocks = <&clock_camcc CAM_CC_IPE_0_AHB_CLK>, + <&clock_camcc CAM_CC_IPE_0_AREG_CLK>, + <&clock_camcc CAM_CC_IPE_0_AXI_CLK>, + <&clock_camcc CAM_CC_IPE_0_CLK>, + <&clock_camcc CAM_CC_IPE_0_CLK_SRC>; + + clock-rates = + <0 0 0 0 360000000>, + <0 0 0 0 432000000>, + <0 0 0 0 480000000>, + <0 0 0 0 540000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "svs", + "svs_l1", "nominal", "nominal_l1", "turbo"; + status = "ok"; + }; + + cam_bps: qcom,bps { + cell-index = <0>; + compatible = "qcom,cam-bps"; + regulator-names = "bps-vdd"; + bps-vdd-supply = <&bps_gdsc>; + clock-names = "bps_ahb_clk", + "bps_areg_clk", + "bps_axi_clk", + "bps_clk", + "bps_clk_src"; + src-clock-name = "bps_clk_src"; + clocks = <&clock_camcc CAM_CC_BPS_AHB_CLK>, + <&clock_camcc CAM_CC_BPS_AREG_CLK>, + <&clock_camcc CAM_CC_BPS_AXI_CLK>, + <&clock_camcc CAM_CC_BPS_CLK>, + <&clock_camcc CAM_CC_BPS_CLK_SRC>; + + clock-rates = + <0 0 0 0 360000000>, + <0 0 0 0 432000000>, + <0 0 0 0 480000000>, + <0 0 0 0 540000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "svs", + "svs_l1", "nominal", "nominal_l1", "turbo"; + status = "ok"; + }; + + qcom,cam-jpeg { + compatible = "qcom,cam-jpeg"; + compat-hw-name = "qcom,jpegenc", + "qcom,jpegdma"; + num-jpeg-enc = <1>; + num-jpeg-dma = <1>; + status = "ok"; + }; + + cam_jpeg_enc: qcom,jpegenc@ac4e000 { + cell-index = <0>; + compatible = "qcom,cam_jpeg_enc"; + reg-names = "jpege_hw"; + reg = <0xac4e000 0x4000>; + reg-cam-base = <0x4e000>; + interrupt-names = "jpeg"; + interrupts = <0 474 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "jpegenc_clk_src", + "jpegenc_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_JPEG_CLK_SRC>, + <&clock_camcc CAM_CC_JPEG_CLK>; + + clock-rates = <0 0 0 0 0 320000000 0>; + src-clock-name = "jpegenc_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + cam_jpeg_dma: qcom,jpegdma@ac52000{ + cell-index = <0>; + compatible = "qcom,cam_jpeg_dma"; + reg-names = "jpegdma_hw"; + reg = <0xac52000 0x4000>; + reg-cam-base = <0x52000>; + interrupt-names = "jpegdma"; + interrupts = <0 475 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "jpegdma_clk_src", + "jpegdma_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_JPEG_CLK_SRC>, + <&clock_camcc CAM_CC_JPEG_CLK>; + + clock-rates = <0 0 0 0 0 320000000 0>; + src-clock-name = "jpegdma_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + qcom,cam-lrme { + compatible = "qcom,cam-lrme"; + arch-compat = "lrme"; + status = "ok"; + }; + + cam_lrme: qcom,lrme@ac6b000 { + cell-index = <0>; + compatible = "qcom,lrme"; + reg-names = "lrme"; + reg = <0xac6b000 0xa00>; + reg-cam-base = <0x6b000>; + interrupt-names = "lrme"; + interrupts = <0 476 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "lrme_clk_src", + "lrme_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_LRME_CLK_SRC>, + <&clock_camcc CAM_CC_LRME_CLK>; + clock-rates = <0 0 0 0 0 200000000 200000000>, + <0 0 0 0 0 216000000 216000000>, + <0 0 0 0 0 300000000 300000000>, + <0 0 0 0 0 404000000 404000000>, + <0 0 0 0 0 404000000 404000000>, + <0 0 0 0 0 404000000 404000000>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal", + "nominal_l1", "turbo"; + src-clock-name = "lrme_clk_src"; + status = "ok"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts index ae891836ed6b..de09032f4db1 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts @@ -14,6 +14,7 @@ /plugin/; #include +#include #include "sm6150-idp.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi index fc441b419c7e..dc69946a8f87 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi @@ -10,6 +10,8 @@ * GNU General Public License for more details. */ +#include "sm6150-camera-sensor-idp.dtsi" + &soc { }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi index 27c89c5de174..a406d5f7f5f6 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi @@ -606,5 +606,283 @@ bias-disable; }; }; + + cci0_active: cci0_active { + mux { + /* CLK, DATA */ + pins = "gpio32", "gpio33"; + function = "cci_i2c"; + }; + + config { + pins = "gpio32", "gpio33"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci0_suspend: cci0_suspend { + mux { + /* CLK, DATA */ + pins = "gpio32", "gpio33"; + function = "cci_i2c"; + }; + + config { + pins = "gpio32", "gpio33"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_active: cci1_active { + mux { + /* CLK, DATA */ + pins = "gpio34", "gpio35"; + function = "cci_i2c"; + }; + + config { + pins = "gpio34", "gpio35"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_suspend: cci1_suspend { + mux { + /* CLK, DATA */ + pins = "gpio34", "gpio35"; + function = "cci_i2c"; + }; + + config { + pins = "gpio34", "gpio35"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_active: cam_sensor_mclk0_active { + /* MCLK0 */ + mux { + pins = "gpio28"; + function = "cam_mclk"; + }; + + config { + pins = "gpio28"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_suspend: cam_sensor_mclk0_suspend { + /* MCLK0 */ + mux { + pins = "gpio28"; + function = "cam_mclk"; + }; + + config { + pins = "gpio28"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_active: cam_sensor_rear_active { + /* RESET */ + mux { + pins = "gpio47"; + function = "gpio"; + }; + + config { + pins = "gpio47"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_suspend: cam_sensor_rear_suspend { + /* RESET */ + mux { + pins = "gpio47"; + function = "gpio"; + }; + + config { + pins = "gpio47"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_front_active: cam_sensor_front_active { + /* RESET */ + mux { + pins = "gpio37"; + function = "gpio"; + }; + + config { + pins = "gpio37"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_suspend: cam_sensor_front_suspend { + /* RESET */ + mux { + pins = "gpio37"; + function = "gpio"; + }; + + config { + pins = "gpio37"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_rear2_active: cam_sensor_rear2_active { + /* RESET */ + mux { + pins = "gpio45"; + function = "gpio"; + }; + + config { + pins = "gpio45"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear2_suspend: cam_sensor_rear2_suspend { + /* RESET */ + mux { + pins = "gpio45"; + function = "gpio"; + }; + + config { + pins = "gpio45"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_mclk1_active: cam_sensor_mclk1_active { + /* MCLK1 */ + mux { + pins = "gpio29"; + function = "cam_mclk"; + }; + + config { + pins = "gpio29"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_suspend: cam_sensor_mclk1_suspend { + /* MCLK1 */ + mux { + pins = "gpio29"; + function = "cam_mclk"; + }; + + config { + pins = "gpio29"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_active: cam_sensor_mclk2_active { + /* MCLK2 */ + mux { + pins = "gpio30"; + function = "cam_mclk"; + }; + + config { + pins = "gpio30"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_suspend: cam_sensor_mclk2_suspend { + /* MCLK2 */ + mux { + pins = "gpio30"; + function = "cam_mclk"; + }; + + config { + pins = "gpio30"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + flash_led3_front { + flash_led3_front_en: flash_led3_front_en { + mux { + pins = "gpio38"; + function = "gpio"; + }; + + config { + pins = "gpio38"; + drive_strength = <2>; + output-high; + bias-disable; + }; + }; + + flash_led3_front_dis: flash_led3_front_dis { + mux { + pins = "gpio38"; + function = "gpio"; + }; + + config { + pins = "gpio38"; + drive_strength = <2>; + output-low; + bias-disable; + }; + }; + }; + }; +}; + +&pm6150l_gpios { + cam_sensor_dvdd_en: cam_sensor_dvdd_en { + pins = "gpio3"; + function = "normal"; + power-source = <0>; + output-low; + }; + cam_sensor_0_vana: cam_sensor_0_vana { + pins = "gpio9"; + function = "normal"; + power-source = <0>; + output-low; + }; + cam_sensor_1_2_vana: cam_sensor_1_2_vana { + pins = "gpio4"; + function = "normal"; + power-source = <0>; + output-low; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index b930cc1df929..ce394ac7fe8e 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -2092,6 +2092,7 @@ status = "ok"; }; +#include "sm6150-camera.dtsi" #include "sm6150-ion.dtsi" #include "msm-arm-smmu-sm6150.dtsi" #include "sm6150-coresight.dtsi" -- GitLab From e737e6b08e482db8b998a54312d9b1c5e053472e Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Tue, 11 Feb 2014 12:37:49 -0800 Subject: [PATCH 0584/1001] arm64: Export caching APIs External modules may need to use caching APIs. Export the symbols to allow their use. Change-Id: I72a862608d37dedf0980ee2790ffb93a9de82221 Signed-off-by: Laura Abbott Signed-off-by: Patrick Daly Signed-off-by: Akhil P Oommen Signed-off-by: Charan Teja Reddy --- arch/arm64/kernel/arm64ksyms.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c index 66be504edb6c..ca1cf2d2b493 100644 --- a/arch/arm64/kernel/arm64ksyms.c +++ b/arch/arm64/kernel/arm64ksyms.c @@ -29,6 +29,7 @@ #include #include +#include #include EXPORT_SYMBOL(copy_page); @@ -75,3 +76,8 @@ NOKPROBE_SYMBOL(_mcount); /* arm-smccc */ EXPORT_SYMBOL(__arm_smccc_smc); EXPORT_SYMBOL(__arm_smccc_hvc); + + /* caching functions */ +EXPORT_SYMBOL(__dma_inv_area); +EXPORT_SYMBOL(__dma_clean_area); +EXPORT_SYMBOL(__dma_flush_area); -- GitLab From e0dd9783c2f4c2e768def6fb8af8bcb4a2e395bd Mon Sep 17 00:00:00 2001 From: shubham Date: Wed, 8 Aug 2018 18:25:41 +0530 Subject: [PATCH 0585/1001] Revert "msm: vidc: Remove QCOM keyword from buffer flag" This reverts commit b1b6c65dac178ce212a7a9d034b21af3eb95ee44. The commit b1b6c65dac178ce212a7a9d034b21af3eb95ee44 had non-complaint keywords, hence reverting the same. Change-Id: Ibcaaa4b5e696fd518a171d70dedc361e5672c756 Signed-off-by: Shubham Gupta --- include/uapi/linux/videodev2.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 68133f9f250a..f7de29626600 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1054,7 +1054,6 @@ struct v4l2_buffer { /* Vendor extensions */ #define V4L2_QCOM_BUF_FLAG_CODECCONFIG 0x00020000 #define V4L2_QCOM_BUF_DATA_CORRUPT 0x00400000 -#define V4L2_BUF_DATA_CORRUPT 0x00400000 #define V4L2_QCOM_BUF_INPUT_UNSUPPORTED 0x01000000 #define V4L2_QCOM_BUF_FLAG_EOS 0x02000000 #define V4L2_QCOM_BUF_FLAG_READONLY 0x04000000 -- GitLab From 7175ad509cdfeb6424adcec23be007b41e22be11 Mon Sep 17 00:00:00 2001 From: Vamsi Krishna Samavedam Date: Wed, 1 Aug 2018 10:33:26 -0700 Subject: [PATCH 0586/1001] usb: gadget: gsi: Increase Rmnet UL buffer size from 16K to 31K IPA Rmnet interface supports packet aggregation/de-aggregation up to 31K. Hence, increase buffer size given to IPA from 16K to 31K. Change-Id: Ib136bee28b324f5b665a6309228b823e37079862 Signed-off-by: Vamsi Krishna Samavedam --- drivers/usb/gadget/function/f_gsi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index e9ff9341fdbd..06b1bb484531 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -49,7 +49,7 @@ #define GSI_ECM_AGGR_SIZE 2048 #define GSI_OUT_MBIM_BUF_LEN 16384 -#define GSI_OUT_RMNET_BUF_LEN 16384 +#define GSI_OUT_RMNET_BUF_LEN 31744 #define GSI_OUT_ECM_BUF_LEN 2048 #define GSI_IPA_READY_TIMEOUT 5000 -- GitLab From 5a08ef7aa14699852b5784294b89af007bbfe3db Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Wed, 8 Aug 2018 13:01:36 -0600 Subject: [PATCH 0587/1001] checkpatch: Treat duplicate signatures as a different error class If code is merged upstream first it is possible that the same author may end up attempting to merge the same code into a downstream kernel. Since code coming from upstream is always a backport and may involve modifications it is appropriate for the author to add another Signed-off-by line to the bottom of the commit log but this will cause checkpatch to complain about duplicate signatures. By making the duplicate signature warning a different error class (DUPLICATE_SIGN_OFF instead of BAD_SIGN_OFF) this will let us ignore this error with --ignore DUPLICATE_SIGN_OFF without losing the benefits of the other signature checks. Change-Id: Ic0dedbadcc1b319061db324f88740e5320bfff09 Signed-off-by: Jordan Crouse --- scripts/checkpatch.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index a7ecdb123731..2e879e714be2 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2663,7 +2663,7 @@ sub process { $sig_nospace =~ s/\s//g; $sig_nospace = lc($sig_nospace); if (defined $signatures{$sig_nospace}) { - WARN("BAD_SIGN_OFF", + WARN("DUPLICATE_SIGN_OFF", "Duplicate signature\n" . $herecurr); } else { $signatures{$sig_nospace} = 1; -- GitLab From 397ea8cfed36a57e7a0a0d13469fc5efbe8b0676 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Thu, 26 Jul 2018 12:21:21 -0700 Subject: [PATCH 0588/1001] msm: camera: sync: Add callback mechanism for signaled objects Previously all objects that need to be signaled were added to a list by dynamically allocating memory. This change dispatches the necessary callbacks as and when it finds that an object is signaled and ready to be dispatched. Change-Id: I99759143c70dc7dd59ca72927c7e8b83521145ce Signed-off-by: Karthik Anantha Ram --- .../platform/msm/camera/cam_sync/cam_sync.c | 119 +++--------------- .../msm/camera/cam_sync/cam_sync_util.c | 78 +++++++++--- .../msm/camera/cam_sync/cam_sync_util.h | 24 ++-- 3 files changed, 83 insertions(+), 138 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c index efd3728d207c..c5438c917bc0 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c @@ -175,19 +175,11 @@ int cam_sync_deregister_callback(sync_callback cb_func, int cam_sync_signal(int32_t sync_obj, uint32_t status) { - int rc; struct sync_table_row *row = NULL; struct sync_table_row *parent_row = NULL; - struct sync_callback_info *sync_cb; - struct sync_user_payload *payload_info; - struct sync_parent_info *parent_info; - struct list_head sync_list; - struct cam_signalable_info *list_info = NULL; - struct cam_signalable_info *temp_list_info = NULL; + struct sync_parent_info *parent_info, *temp_parent_info; struct list_head parents_list; - - /* Objects to be signaled will be added into this list */ - INIT_LIST_HEAD(&sync_list); + int rc = 0; if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) { CAM_ERR(CAM_SYNC, "Error: Out of range sync obj (0 <= %d < %d)", @@ -230,14 +222,7 @@ int cam_sync_signal(int32_t sync_obj, uint32_t status) } row->state = status; - rc = cam_sync_util_add_to_signalable_list(sync_obj, status, &sync_list); - if (rc < 0) { - spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); - CAM_ERR(CAM_SYNC, - "Error: Unable to add sync object :%d to signalable list", - sync_obj); - return rc; - } + cam_sync_util_dispatch_signaled_cb(sync_obj, status); /* copy parent list to local and release child lock */ INIT_LIST_HEAD(&parents_list); @@ -245,13 +230,14 @@ int cam_sync_signal(int32_t sync_obj, uint32_t status) spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); if (list_empty(&parents_list)) - goto dispatch_cb; + return 0; /* * Now iterate over all parents of this object and if they too need to - * be signaled add them to the list + * be signaled dispatch cb's */ - list_for_each_entry(parent_info, + list_for_each_entry_safe(parent_info, + temp_parent_info, &parents_list, list) { parent_row = sync_dev->sync_table + parent_info->sync_id; @@ -270,93 +256,16 @@ int cam_sync_signal(int32_t sync_obj, uint32_t status) continue; } - if (!parent_row->remaining) { - rc = cam_sync_util_add_to_signalable_list - (parent_info->sync_id, - parent_row->state, - &sync_list); - if (rc < 0) { - spin_unlock_bh( - &sync_dev->row_spinlocks[ - parent_info->sync_id]); - continue; - } - } - spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); - } - -dispatch_cb: + if (!parent_row->remaining) + cam_sync_util_dispatch_signaled_cb( + parent_info->sync_id, parent_row->state); - /* - * Now dispatch the various sync objects collected so far, in our - * list - */ - list_for_each_entry_safe(list_info, - temp_list_info, - &sync_list, - list) { - struct sync_table_row *signalable_row = NULL; - struct sync_callback_info *temp_sync_cb; - struct sync_user_payload *temp_payload_info; - - signalable_row = sync_dev->sync_table + list_info->sync_obj; - - spin_lock_bh(&sync_dev->row_spinlocks[list_info->sync_obj]); - if (signalable_row->state == CAM_SYNC_STATE_INVALID) { - spin_unlock_bh( - &sync_dev->row_spinlocks[list_info->sync_obj]); - continue; - } - - /* Dispatch kernel callbacks if any were registered earlier */ - - list_for_each_entry_safe(sync_cb, - temp_sync_cb, &signalable_row->callback_list, list) { - sync_cb->status = list_info->status; - list_del_init(&sync_cb->list); - queue_work(sync_dev->work_queue, - &sync_cb->cb_dispatch_work); - } - - /* Dispatch user payloads if any were registered earlier */ - list_for_each_entry_safe(payload_info, temp_payload_info, - &signalable_row->user_payload_list, list) { - spin_lock_bh(&sync_dev->cam_sync_eventq_lock); - if (!sync_dev->cam_sync_eventq) { - spin_unlock_bh( - &sync_dev->cam_sync_eventq_lock); - break; - } - spin_unlock_bh(&sync_dev->cam_sync_eventq_lock); - cam_sync_util_send_v4l2_event( - CAM_SYNC_V4L_EVENT_ID_CB_TRIG, - list_info->sync_obj, - list_info->status, - payload_info->payload_data, - CAM_SYNC_PAYLOAD_WORDS * sizeof(__u64)); - - list_del_init(&payload_info->list); - /* - * We can free the list node here because - * sending V4L event will make a deep copy - * anyway - */ - kfree(payload_info); - } - - /* - * This needs to be done because we want to unblock anyone - * who might be blocked and waiting on this sync object - */ - complete_all(&signalable_row->signaled); - - spin_unlock_bh(&sync_dev->row_spinlocks[list_info->sync_obj]); - - list_del_init(&list_info->list); - kfree(list_info); + spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); + list_del_init(&parent_info->list); + kfree(parent_info); } - return rc; + return 0; } int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c index f391c8c8d51d..49a9d2f39974 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c @@ -287,6 +287,64 @@ void cam_sync_util_cb_dispatch(struct work_struct *cb_dispatch_work) kfree(cb_info); } +void cam_sync_util_dispatch_signaled_cb(int32_t sync_obj, + uint32_t status) +{ + struct sync_callback_info *sync_cb; + struct sync_user_payload *payload_info; + struct sync_callback_info *temp_sync_cb; + struct sync_table_row *signalable_row; + struct sync_user_payload *temp_payload_info; + + signalable_row = sync_dev->sync_table + sync_obj; + if (signalable_row->state == CAM_SYNC_STATE_INVALID) { + CAM_DBG(CAM_SYNC, + "Accessing invalid sync object:%i", sync_obj); + return; + } + + /* Dispatch kernel callbacks if any were registered earlier */ + list_for_each_entry_safe(sync_cb, + temp_sync_cb, &signalable_row->callback_list, list) { + sync_cb->status = status; + list_del_init(&sync_cb->list); + queue_work(sync_dev->work_queue, + &sync_cb->cb_dispatch_work); + } + + /* Dispatch user payloads if any were registered earlier */ + list_for_each_entry_safe(payload_info, temp_payload_info, + &signalable_row->user_payload_list, list) { + spin_lock_bh(&sync_dev->cam_sync_eventq_lock); + if (!sync_dev->cam_sync_eventq) { + spin_unlock_bh( + &sync_dev->cam_sync_eventq_lock); + break; + } + spin_unlock_bh(&sync_dev->cam_sync_eventq_lock); + cam_sync_util_send_v4l2_event( + CAM_SYNC_V4L_EVENT_ID_CB_TRIG, + sync_obj, + status, + payload_info->payload_data, + CAM_SYNC_PAYLOAD_WORDS * sizeof(__u64)); + + list_del_init(&payload_info->list); + /* + * We can free the list node here because + * sending V4L event will make a deep copy + * anyway + */ + kfree(payload_info); + } + + /* + * This needs to be done because we want to unblock anyone + * who might be blocked and waiting on this sync object + */ + complete_all(&signalable_row->signaled); +} + void cam_sync_util_send_v4l2_event(uint32_t id, uint32_t sync_obj, int status, @@ -312,26 +370,6 @@ void cam_sync_util_send_v4l2_event(uint32_t id, sync_obj); } -int cam_sync_util_add_to_signalable_list(int32_t sync_obj, - uint32_t status, - struct list_head *sync_list) -{ - struct cam_signalable_info *signalable_info = NULL; - - signalable_info = kzalloc(sizeof(*signalable_info), GFP_ATOMIC); - if (!signalable_info) - return -ENOMEM; - - signalable_info->sync_obj = sync_obj; - signalable_info->status = status; - - list_add_tail(&signalable_info->list, sync_list); - CAM_DBG(CAM_SYNC, "Add sync_obj :%d with status :%d to signalable list", - sync_obj, status); - - return 0; -} - int cam_sync_util_update_parent_state(struct sync_table_row *parent_row, int new_state) { diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h index a9d6f86c1709..cfa450c0e744 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h @@ -86,6 +86,17 @@ int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx); */ void cam_sync_util_cb_dispatch(struct work_struct *cb_dispatch_work); +/** + * @brief: Function to dispatch callbacks for a signaled sync object + * + * @sync_obj : Sync object that is signaled + * @status : Status of the signaled object + * + * @return None + */ +void cam_sync_util_dispatch_signaled_cb(int32_t sync_obj, + uint32_t status); + /** * @brief: Function to send V4L event to user space * @param id : V4L event id to send @@ -102,19 +113,6 @@ void cam_sync_util_send_v4l2_event(uint32_t id, void *payload, int len); -/** - * @brief: Function which adds sync object information to the signalable list - * - * @param sync_obj : Sync object to add - * @param status : Status of above sync object - * @param list : Linked list where the information should be added to - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ -int cam_sync_util_add_to_signalable_list(int32_t sync_obj, - uint32_t status, - struct list_head *sync_list); - /** * @brief: Function which gets the next state of the sync object based on the * current state and the new state -- GitLab From 03e12dde82991b7b050c3cd224e6966aaf50feb4 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 6 Aug 2018 18:16:11 -0700 Subject: [PATCH 0589/1001] msm: camera: cci: Modify condition check to read CCI data If the buffer level is zero, we continue to wait for the next irq and not proceed to read the data registers as part of cci read sequence. Change-Id: I60a9a2388789a17e5ff01742b7e8928a71cbe421 Signed-off-by: Karthik Anantha Ram --- .../camera/cam_sensor_module/cam_cci/cam_cci_core.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c index dbda92109f34..b203948ae39e 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c @@ -1013,7 +1013,7 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, read_words = cam_io_r_mb(base + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); total_read_words += read_words; - do { + while (read_words > 0) { val = cam_io_r_mb(base + CCI_I2C_M0_READ_DATA_ADDR + master * 0x100); for (i = 0; (i < 4) && @@ -1031,7 +1031,8 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, index++; } } - } while (--read_words > 0); + read_words--; + } } rel_mutex: @@ -1199,7 +1200,7 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, index = 0; CAM_DBG(CAM_CCI, "index %d num_type %d", index, read_cfg->num_byte); first_byte = 0; - do { + while (read_words > 0) { val = cam_io_r_mb(base + CCI_I2C_M0_READ_DATA_ADDR + master * 0x100); CAM_DBG(CAM_CCI, "read val 0x%x", val); @@ -1216,7 +1217,8 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, index++; } } - } while (--read_words > 0); + read_words--; + } rel_mutex: mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]); -- GitLab From 6abae13f6b0d1ba6ff926c905ef1be1ec1e321fd Mon Sep 17 00:00:00 2001 From: Junzhe Zou Date: Fri, 13 Jul 2018 17:08:04 -0700 Subject: [PATCH 0590/1001] msm: camera: ife: config rdi HFR Since RDI path doesn't have address increment register, config address manually to support rdi HFR mode. Change-Id: Ida7dd4d6840f48d08d6adaacff56cde25b0bd48c Signed-off-by: Junzhe Zou --- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 0377f71125ec..09e092bf726d 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -2692,8 +2692,9 @@ static int cam_vfe_bus_update_wm(void *priv, void *cmd_args, struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL; struct cam_vfe_bus_ver2_reg_offset_ubwc_client *ubwc_client = NULL; uint32_t *reg_val_pair; - uint32_t i, j, size = 0; + uint32_t i, j, k, size = 0; uint32_t frame_inc = 0, val; + uint32_t loop_size = 0; bus_priv = (struct cam_vfe_bus_ver2_priv *) priv; update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; @@ -2776,20 +2777,6 @@ static int cam_vfe_bus_update_wm(void *priv, void *cmd_args, update_buf->wm_update->image_buf[i]); } - /* WM Image address */ - if (wm_data->en_ubwc) - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->image_addr, - (update_buf->wm_update->image_buf[i] + - io_cfg->planes[i].meta_size)); - else - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->image_addr, - update_buf->wm_update->image_buf[i] + - wm_data->offset); - CAM_DBG(CAM_ISP, "WM %d image address 0x%x", - wm_data->index, reg_val_pair[j-1]); - if (wm_data->en_ubwc) { frame_inc = ALIGNUP(io_cfg->planes[i].plane_stride * io_cfg->planes[i].slice_height, 4096); @@ -2805,6 +2792,28 @@ static int cam_vfe_bus_update_wm(void *priv, void *cmd_args, io_cfg->planes[i].slice_height; } + if (wm_data->index < 3) + loop_size = wm_data->irq_subsample_period + 1; + else + loop_size = 1; + + /* WM Image address */ + for (k = 0; k < loop_size; k++) { + if (wm_data->en_ubwc) + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + update_buf->wm_update->image_buf[i] + + io_cfg->planes[i].meta_size + + k * frame_inc); + else + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + update_buf->wm_update->image_buf[i] + + wm_data->offset + k * frame_inc); + CAM_DBG(CAM_ISP, "WM %d image address 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, wm_data->hw_regs->frame_inc, frame_inc); CAM_DBG(CAM_ISP, "WM %d frame_inc %d", @@ -2875,6 +2884,13 @@ static int cam_vfe_bus_update_hfr(void *priv, void *cmd_args, wm_data = vfe_out_data->wm_res[i]->res_priv; + if (wm_data->index <= 2 && hfr_cfg->subsample_period > 3) { + CAM_ERR(CAM_ISP, + "RDI doesn't support irq subsample period %d", + hfr_cfg->subsample_period); + return -EINVAL; + } + if ((wm_data->framedrop_pattern != hfr_cfg->framedrop_pattern) || !wm_data->hfr_cfg_done) { -- GitLab From bd2d45570435a7adab03cfac16e12c4c98930eca Mon Sep 17 00:00:00 2001 From: Jilai Wang Date: Tue, 17 Jul 2018 11:42:07 -0400 Subject: [PATCH 0591/1001] msm: npu: Add asynchronous ioctl support In order to improve the NPU performance, ioctl commands like execute_network need to be executed in asynchronous mode to allow user applications to run multiple operations parallelly. Change-Id: I8cf4f20569539667a0eda6a0b8e3ec610ddde210 Signed-off-by: Jilai Wang --- drivers/media/platform/msm/npu/npu_common.h | 13 ++ drivers/media/platform/msm/npu/npu_dev.c | 181 ++++++++++++++++---- drivers/media/platform/msm/npu/npu_mgr.c | 166 ++++++++++++------ drivers/media/platform/msm/npu/npu_mgr.h | 14 +- include/uapi/linux/msm_npu.h | 36 ++++ 5 files changed, 324 insertions(+), 86 deletions(-) diff --git a/drivers/media/platform/msm/npu/npu_common.h b/drivers/media/platform/msm/npu/npu_common.h index 8639e7cd7e03..4dabbf34a877 100644 --- a/drivers/media/platform/msm/npu/npu_common.h +++ b/drivers/media/platform/msm/npu/npu_common.h @@ -208,6 +208,19 @@ struct npu_device { uint32_t execute_v2_flag; }; +struct npu_kevent { + struct list_head list; + struct msm_npu_event evt; + uint64_t reserved[4]; +}; + +struct npu_client { + struct npu_device *npu_dev; + wait_queue_head_t wait; + + struct mutex list_lock; + struct list_head evt_list; +}; /* ------------------------------------------------------------------------- * Function Prototypes diff --git a/drivers/media/platform/msm/npu/npu_dev.c b/drivers/media/platform/msm/npu/npu_dev.c index 1539e848fb87..bba09763778c 100644 --- a/drivers/media/platform/msm/npu/npu_dev.c +++ b/drivers/media/platform/msm/npu/npu_dev.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -75,16 +76,25 @@ static int npu_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state); static int npu_open(struct inode *inode, struct file *file); static int npu_close(struct inode *inode, struct file *file); -static int npu_get_info(struct npu_device *npu_dev, unsigned long arg); -static int npu_map_buf(struct npu_device *npu_dev, unsigned long arg); -static int npu_unmap_buf(struct npu_device *npu_dev, unsigned long arg); -static int npu_load_network(struct npu_device *npu_dev, unsigned long arg); -static int npu_load_network_v2(struct npu_device *npu_dev, unsigned long arg); -static int npu_unload_network(struct npu_device *npu_dev, unsigned long arg); -static int npu_exec_network(struct npu_device *npu_dev, unsigned long arg); -static int npu_exec_network_v2(struct npu_device *npu_dev, unsigned long arg); +static int npu_get_info(struct npu_client *client, unsigned long arg); +static int npu_map_buf(struct npu_client *client, unsigned long arg); +static int npu_unmap_buf(struct npu_client *client, + unsigned long arg); +static int npu_load_network(struct npu_client *client, + unsigned long arg); +static int npu_load_network_v2(struct npu_client *client, + unsigned long arg); +static int npu_unload_network(struct npu_client *client, + unsigned long arg); +static int npu_exec_network(struct npu_client *client, + unsigned long arg); +static int npu_exec_network_v2(struct npu_client *client, + unsigned long arg); +static int npu_receive_event(struct npu_client *client, + unsigned long arg); static long npu_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +static unsigned int npu_poll(struct file *filp, struct poll_table_struct *p); static int npu_parse_dt_clock(struct npu_device *npu_dev); static int npu_parse_dt_regulator(struct npu_device *npu_dev); static int npu_of_parse_pwrlevels(struct npu_device *npu_dev, @@ -207,6 +217,7 @@ static const struct file_operations npu_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = npu_ioctl, #endif + .poll = npu_poll, }; static const struct thermal_cooling_device_ops npu_cooling_ops = { @@ -793,14 +804,35 @@ static int npu_open(struct inode *inode, struct file *file) { struct npu_device *npu_dev = container_of(inode->i_cdev, struct npu_device, cdev); + struct npu_client *client; - file->private_data = npu_dev; + client = kmalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return -ENOMEM; + + client->npu_dev = npu_dev; + init_waitqueue_head(&client->wait); + mutex_init(&client->list_lock); + INIT_LIST_HEAD(&client->evt_list); + file->private_data = client; return 0; } static int npu_close(struct inode *inode, struct file *file) { + struct npu_client *client = file->private_data; + struct npu_kevent *kevent; + + while (!list_empty(&client->evt_list)) { + kevent = list_first_entry(&client->evt_list, + struct npu_kevent, list); + list_del(&kevent->list); + kfree(kevent); + } + + mutex_destroy(&client->list_lock); + kfree(client); return 0; } @@ -808,8 +840,9 @@ static int npu_close(struct inode *inode, struct file *file) * IOCTL Implementations * ------------------------------------------------------------------------- */ -static int npu_get_info(struct npu_device *npu_dev, unsigned long arg) +static int npu_get_info(struct npu_client *client, unsigned long arg) { + struct npu_device *npu_dev = client->npu_dev; struct msm_npu_get_info_ioctl req; void __user *argp = (void __user *)arg; int ret = 0; @@ -837,8 +870,9 @@ static int npu_get_info(struct npu_device *npu_dev, unsigned long arg) return 0; } -static int npu_map_buf(struct npu_device *npu_dev, unsigned long arg) +static int npu_map_buf(struct npu_client *client, unsigned long arg) { + struct npu_device *npu_dev = client->npu_dev; struct msm_npu_map_buf_ioctl req; void __user *argp = (void __user *)arg; int ret = 0; @@ -866,8 +900,9 @@ static int npu_map_buf(struct npu_device *npu_dev, unsigned long arg) return 0; } -static int npu_unmap_buf(struct npu_device *npu_dev, unsigned long arg) +static int npu_unmap_buf(struct npu_client *client, unsigned long arg) { + struct npu_device *npu_dev = client->npu_dev; struct msm_npu_unmap_buf_ioctl req; void __user *argp = (void __user *)arg; int ret = 0; @@ -895,7 +930,8 @@ static int npu_unmap_buf(struct npu_device *npu_dev, unsigned long arg) return 0; } -static int npu_load_network(struct npu_device *npu_dev, unsigned long arg) +static int npu_load_network(struct npu_client *client, + unsigned long arg) { struct msm_npu_load_network_ioctl req; void __user *argp = (void __user *)arg; @@ -910,7 +946,7 @@ static int npu_load_network(struct npu_device *npu_dev, unsigned long arg) pr_debug("network load with perf request %d\n", req.perf_mode); - ret = npu_host_load_network(npu_dev, &req); + ret = npu_host_load_network(client, &req); if (ret) { pr_err("network load failed: %d\n", ret); return -EFAULT; @@ -924,7 +960,8 @@ static int npu_load_network(struct npu_device *npu_dev, unsigned long arg) return 0; } -static int npu_load_network_v2(struct npu_device *npu_dev, unsigned long arg) +static int npu_load_network_v2(struct npu_client *client, + unsigned long arg) { struct msm_npu_load_network_ioctl_v2 req; void __user *argp = (void __user *)arg; @@ -956,7 +993,7 @@ static int npu_load_network_v2(struct npu_device *npu_dev, unsigned long arg) pr_debug("network load with perf request %d\n", req.perf_mode); - ret = npu_host_load_network_v2(npu_dev, &req, patch_info); + ret = npu_host_load_network_v2(client, &req, patch_info); if (ret) { pr_err("network load failed: %d\n", ret); } else { @@ -969,7 +1006,8 @@ static int npu_load_network_v2(struct npu_device *npu_dev, unsigned long arg) return ret; } -static int npu_unload_network(struct npu_device *npu_dev, unsigned long arg) +static int npu_unload_network(struct npu_client *client, + unsigned long arg) { struct msm_npu_unload_network_ioctl req; void __user *argp = (void __user *)arg; @@ -982,7 +1020,7 @@ static int npu_unload_network(struct npu_device *npu_dev, unsigned long arg) return -EFAULT; } - ret = npu_host_unload_network(npu_dev, &req); + ret = npu_host_unload_network(client, &req); if (ret) { pr_err("npu_host_unload_network failed\n"); @@ -998,7 +1036,8 @@ static int npu_unload_network(struct npu_device *npu_dev, unsigned long arg) return 0; } -static int npu_exec_network(struct npu_device *npu_dev, unsigned long arg) +static int npu_exec_network(struct npu_client *client, + unsigned long arg) { struct msm_npu_exec_network_ioctl req; void __user *argp = (void __user *)arg; @@ -1011,7 +1050,15 @@ static int npu_exec_network(struct npu_device *npu_dev, unsigned long arg) return -EFAULT; } - ret = npu_host_exec_network(npu_dev, &req); + if ((req.input_layer_num > MSM_NPU_MAX_INPUT_LAYER_NUM) || + (req.output_layer_num > MSM_NPU_MAX_OUTPUT_LAYER_NUM)) { + pr_err("Invalid input/out layer num %d[max:%d] %d[max:%d]\n", + req.input_layer_num, MSM_NPU_MAX_INPUT_LAYER_NUM, + req.output_layer_num, MSM_NPU_MAX_OUTPUT_LAYER_NUM); + return -EINVAL; + } + + ret = npu_host_exec_network(client, &req); if (ret) { pr_err("npu_host_exec_network failed\n"); @@ -1027,7 +1074,8 @@ static int npu_exec_network(struct npu_device *npu_dev, unsigned long arg) return 0; } -static int npu_exec_network_v2(struct npu_device *npu_dev, unsigned long arg) +static int npu_exec_network_v2(struct npu_client *client, + unsigned long arg) { struct msm_npu_exec_network_ioctl_v2 req; void __user *argp = (void __user *)arg; @@ -1063,7 +1111,7 @@ static int npu_exec_network_v2(struct npu_device *npu_dev, unsigned long arg) req.patch_buf_info_num * sizeof(*patch_buf_info)); } - ret = npu_host_exec_network_v2(npu_dev, &req, patch_buf_info); + ret = npu_host_exec_network_v2(client, &req, patch_buf_info); if (ret) { pr_err("npu_host_exec_network failed\n"); } else { @@ -1076,36 +1124,90 @@ static int npu_exec_network_v2(struct npu_device *npu_dev, unsigned long arg) return ret; } +static int npu_process_kevent(struct npu_kevent *kevt) +{ + int ret = 0; + + switch (kevt->evt.type) { + case MSM_NPU_EVENT_TYPE_EXEC_V2_DONE: + ret = copy_to_user((void __user *)kevt->reserved[1], + (void *)&kevt->reserved[0], + kevt->evt.u.exec_v2_done.stats_buf_size); + if (ret) { + pr_err("fail to copy to user\n"); + kevt->evt.u.exec_v2_done.stats_buf_size = 0; + ret = -EFAULT; + } + break; + default: + break; + } + + return ret; +} + +static int npu_receive_event(struct npu_client *client, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + struct npu_kevent *kevt; + int ret = 0; + + mutex_lock(&client->list_lock); + if (list_empty(&client->evt_list)) { + pr_err("event list is empty\n"); + ret = -EINVAL; + } else { + kevt = list_first_entry(&client->evt_list, + struct npu_kevent, list); + list_del(&kevt->list); + npu_process_kevent(kevt); + ret = copy_to_user(argp, &kevt->evt, + sizeof(struct msm_npu_event)); + if (ret) { + pr_err("fail to copy to user\n"); + ret = -EFAULT; + } + kfree(kevt); + } + mutex_unlock(&client->list_lock); + + return ret; +} + static long npu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = -ENOIOCTLCMD; - struct npu_device *npu_dev = file->private_data; + struct npu_client *client = file->private_data; switch (cmd) { case MSM_NPU_GET_INFO: - ret = npu_get_info(npu_dev, arg); + ret = npu_get_info(client, arg); break; case MSM_NPU_MAP_BUF: - ret = npu_map_buf(npu_dev, arg); + ret = npu_map_buf(client, arg); break; case MSM_NPU_UNMAP_BUF: - ret = npu_unmap_buf(npu_dev, arg); + ret = npu_unmap_buf(client, arg); break; case MSM_NPU_LOAD_NETWORK: - ret = npu_load_network(npu_dev, arg); + ret = npu_load_network(client, arg); break; case MSM_NPU_LOAD_NETWORK_V2: - ret = npu_load_network_v2(npu_dev, arg); + ret = npu_load_network_v2(client, arg); break; case MSM_NPU_UNLOAD_NETWORK: - ret = npu_unload_network(npu_dev, arg); + ret = npu_unload_network(client, arg); break; case MSM_NPU_EXEC_NETWORK: - ret = npu_exec_network(npu_dev, arg); + ret = npu_exec_network(client, arg); break; case MSM_NPU_EXEC_NETWORK_V2: - ret = npu_exec_network_v2(npu_dev, arg); + ret = npu_exec_network_v2(client, arg); + break; + case MSM_NPU_RECEIVE_EVENT: + ret = npu_receive_event(client, arg); break; default: pr_err("unexpected IOCTL %x\n", cmd); @@ -1114,6 +1216,23 @@ static long npu_ioctl(struct file *file, unsigned int cmd, return ret; } +static unsigned int npu_poll(struct file *filp, struct poll_table_struct *p) +{ + struct npu_client *client = filp->private_data; + int rc = 0; + + poll_wait(filp, &client->wait, p); + + mutex_lock(&client->list_lock); + if (!list_empty(&client->evt_list)) { + pr_debug("poll cmd done\n"); + rc = POLLIN | POLLRDNORM; + } + mutex_unlock(&client->list_lock); + + return rc; +} + /* ------------------------------------------------------------------------- * Device Tree Parsing * ------------------------------------------------------------------------- diff --git a/drivers/media/platform/msm/npu/npu_mgr.c b/drivers/media/platform/msm/npu/npu_mgr.c index c5f84644a199..5664435e004e 100644 --- a/drivers/media/platform/msm/npu/npu_mgr.c +++ b/drivers/media/platform/msm/npu/npu_mgr.c @@ -42,7 +42,8 @@ static void host_irq_wq(struct work_struct *work); static void turn_off_fw_logging(struct npu_device *npu_dev); static int wait_for_fw_ready(struct npu_device *npu_dev, uint32_t status_bits); -static struct npu_network *alloc_network(struct npu_host_ctx *ctx); +static struct npu_network *alloc_network(struct npu_host_ctx *ctx, + struct npu_client *client); static struct npu_network *get_network_by_hdl(struct npu_host_ctx *ctx, uint32_t hdl); static struct npu_network *get_network_by_id(struct npu_host_ctx *ctx, @@ -54,9 +55,10 @@ static void host_session_msg_hdlr(struct npu_device *npu_dev); static void host_session_log_hdlr(struct npu_device *npu_dev); static int host_error_hdlr(struct npu_device *npu_dev); static int npu_send_network_cmd(struct npu_device *npu_dev, - struct npu_network *network, void *cmd_ptr); + struct npu_network *network, void *cmd_ptr, bool async); static int npu_send_misc_cmd(struct npu_device *npu_dev, uint32_t q_idx, void *cmd_ptr); +static int npu_queue_event(struct npu_client *client, struct npu_kevent *evt); /* ------------------------------------------------------------------------- * Function Definitions - Init / Deinit @@ -298,6 +300,7 @@ static int host_error_hdlr(struct npu_device *npu_dev) struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; struct npu_network *network = NULL; bool fw_alive = true; + struct npu_kevent kevt; int i; if ((host_ctx->wdg_irq_sts == 0) && (host_ctx->err_irq_sts == 0)) @@ -317,8 +320,17 @@ static int host_error_hdlr(struct npu_device *npu_dev) network = &host_ctx->networks[i]; if (network->is_valid && network->cmd_pending && network->fw_error) { - pr_debug("complete network %x\n", network->id); - complete(&network->cmd_done); + if (network->cmd_async) { + pr_debug("async cmd, queue ssr event\n"); + kevt.evt.type = MSM_NPU_EVENT_TYPE_SSR; + kevt.evt.u.ssr.network_hdl = + network->network_hdl; + if (npu_queue_event(network->client, &kevt)) + pr_err("queue npu event failed\n"); + } else { + pr_debug("complete network %x\n", network->id); + complete(&network->cmd_done); + } } } complete_all(&host_ctx->loopback_done); @@ -391,7 +403,8 @@ static int wait_for_fw_ready(struct npu_device *npu_dev, uint32_t status_bits) * Function Definitions - Network Management * ------------------------------------------------------------------------- */ -static struct npu_network *alloc_network(struct npu_host_ctx *ctx) +static struct npu_network *alloc_network(struct npu_host_ctx *ctx, + struct npu_client *client) { int32_t i; struct npu_network *network = ctx->networks; @@ -416,6 +429,13 @@ static struct npu_network *alloc_network(struct npu_host_ctx *ctx) network->is_valid = true; network->fw_error = false; network->cmd_pending = false; + network->client = client; + network->stats_buf = kzalloc(MSM_NPU_MAX_STATS_BUF_SIZE, + GFP_KERNEL); + if (!network->stats_buf) { + free_network(ctx, network->id); + network = NULL; + } } return network; @@ -458,6 +478,7 @@ static void free_network(struct npu_host_ctx *ctx, int64_t id) struct npu_network *network = get_network_by_id(ctx, id); if (network) { + kfree(network->stats_buf); mutex_lock(&ctx->lock); memset(network, 0, sizeof(struct npu_network)); ctx->network_num--; @@ -469,10 +490,28 @@ static void free_network(struct npu_host_ctx *ctx, int64_t id) * Function Definitions - IPC * ------------------------------------------------------------------------- */ +static int npu_queue_event(struct npu_client *client, struct npu_kevent *evt) +{ + struct npu_kevent *kevt = kmalloc(sizeof(*kevt), GFP_KERNEL); + + if (!kevt) + return -ENOMEM; + + *kevt = *evt; + INIT_LIST_HEAD(&kevt->list); + mutex_lock(&client->list_lock); + list_add_tail(&kevt->list, &client->evt_list); + mutex_unlock(&client->list_lock); + wake_up_interruptible(&client->wait); + + return 0; +} + static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) { uint32_t msg_id; struct npu_network *network = NULL; + struct npu_kevent kevt; msg_id = msg[1]; switch (msg_id) { @@ -501,7 +540,20 @@ static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) break; } network->cmd_pending = false; - complete(&network->cmd_done); + + if (!network->cmd_async) { + complete(&network->cmd_done); + } else { + pr_debug("async cmd, queue event\n"); + kevt.evt.type = MSM_NPU_EVENT_TYPE_EXEC_DONE; + kevt.evt.u.exec_done.network_hdl = + exe_rsp_pkt->network_hdl; + kevt.evt.u.exec_done.exec_result = + exe_rsp_pkt->header.status; + if (npu_queue_event(network->client, &kevt)) + pr_err("queue npu event failed\n"); + } + break; } case NPU_IPC_MSG_EXECUTE_V2_DONE: @@ -527,13 +579,27 @@ static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) stats_size); stats_size = stats_size < network->stats_buf_size ? stats_size : network->stats_buf_size; - network->stats_buf_size = stats_size; if (stats_size) memcpy(network->stats_buf, exe_rsp_pkt->stats_data, stats_size); + network->stats_buf_size = stats_size; network->cmd_pending = false; - complete(&network->cmd_done); + if (network->cmd_async) { + pr_debug("async cmd, queue event\n"); + kevt.evt.type = MSM_NPU_EVENT_TYPE_EXEC_V2_DONE; + kevt.evt.u.exec_v2_done.network_hdl = + exe_rsp_pkt->network_hdl; + kevt.evt.u.exec_v2_done.exec_result = + exe_rsp_pkt->header.status; + kevt.evt.u.exec_v2_done.stats_buf_size = stats_size; + kevt.reserved[0] = (uint64_t)network->stats_buf; + kevt.reserved[1] = (uint64_t)network->stats_buf_u; + if (npu_queue_event(network->client, &kevt)) + pr_err("queue npu event failed\n"); + } else { + complete(&network->cmd_done); + } break; } case NPU_IPC_MSG_LOAD_DONE: @@ -679,7 +745,7 @@ int32_t npu_host_unmap_buf(struct npu_device *npu_dev, } static int npu_send_network_cmd(struct npu_device *npu_dev, - struct npu_network *network, void *cmd_ptr) + struct npu_network *network, void *cmd_ptr, bool async) { struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; int ret = 0; @@ -689,9 +755,13 @@ static int npu_send_network_cmd(struct npu_device *npu_dev, (host_ctx->fw_state == FW_DISABLED)) { pr_err("fw is in error state or disabled, can't send network cmd\n"); ret = -EIO; + } else if (network->cmd_pending) { + pr_err("Another cmd is pending\n"); + ret = -EBUSY; } else { pr_debug("Send cmd %d\n", ((struct ipc_cmd_header_pkt *)cmd_ptr)->cmd_type); + network->cmd_async = async; ret = npu_host_ipc_send_cmd(npu_dev, IPC_QUEUE_APPS_EXEC, cmd_ptr); if (!ret) @@ -783,10 +853,11 @@ static uint32_t find_networks_perf_mode(struct npu_host_ctx *host_ctx) return max_perf_mode; } -int32_t npu_host_load_network(struct npu_device *npu_dev, +int32_t npu_host_load_network(struct npu_client *client, struct msm_npu_load_network_ioctl *load_ioctl) { int ret = 0; + struct npu_device *npu_dev = client->npu_dev; struct npu_network *network; struct ipc_cmd_load_pkt load_packet; struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; @@ -796,7 +867,7 @@ int32_t npu_host_load_network(struct npu_device *npu_dev, if (ret) return ret; - network = alloc_network(host_ctx); + network = alloc_network(host_ctx, client); if (!network) { ret = -ENOMEM; goto err_deinit_fw; @@ -830,7 +901,7 @@ int32_t npu_host_load_network(struct npu_device *npu_dev, /* NPU_IPC_CMD_LOAD will go onto IPC_QUEUE_APPS_EXEC */ reinit_completion(&network->cmd_done); - ret = npu_send_network_cmd(npu_dev, network, &load_packet); + ret = npu_send_network_cmd(npu_dev, network, &load_packet, false); if (ret) { pr_err("NPU_IPC_CMD_LOAD sent failed: %d\n", ret); goto error_free_network; @@ -860,11 +931,12 @@ int32_t npu_host_load_network(struct npu_device *npu_dev, return ret; } -int32_t npu_host_load_network_v2(struct npu_device *npu_dev, +int32_t npu_host_load_network_v2(struct npu_client *client, struct msm_npu_load_network_ioctl_v2 *load_ioctl, struct msm_npu_patch_info_v2 *patch_info) { int ret = 0, i; + struct npu_device *npu_dev = client->npu_dev; struct npu_network *network; struct ipc_cmd_load_pkt_v2 *load_packet = NULL; struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; @@ -875,7 +947,7 @@ int32_t npu_host_load_network_v2(struct npu_device *npu_dev, if (ret) return ret; - network = alloc_network(host_ctx); + network = alloc_network(host_ctx, client); if (!network) { ret = -ENOMEM; goto err_deinit_fw; @@ -926,7 +998,7 @@ int32_t npu_host_load_network_v2(struct npu_device *npu_dev, /* NPU_IPC_CMD_LOAD_V2 will go onto IPC_QUEUE_APPS_EXEC */ reinit_completion(&network->cmd_done); - ret = npu_send_network_cmd(npu_dev, network, load_packet); + ret = npu_send_network_cmd(npu_dev, network, load_packet, false); if (ret) { pr_debug("NPU_IPC_CMD_LOAD_V2 sent failed: %d\n", ret); goto error_free_network; @@ -957,10 +1029,11 @@ int32_t npu_host_load_network_v2(struct npu_device *npu_dev, return ret; } -int32_t npu_host_unload_network(struct npu_device *npu_dev, +int32_t npu_host_unload_network(struct npu_client *client, struct msm_npu_unload_network_ioctl *unload) { int ret = 0; + struct npu_device *npu_dev = client->npu_dev; struct ipc_cmd_unload_pkt unload_packet; struct npu_network *network; struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; @@ -985,7 +1058,7 @@ int32_t npu_host_unload_network(struct npu_device *npu_dev, /* NPU_IPC_CMD_UNLOAD will go onto IPC_QUEUE_APPS_EXEC */ reinit_completion(&network->cmd_done); - ret = npu_send_network_cmd(npu_dev, network, &unload_packet); + ret = npu_send_network_cmd(npu_dev, network, &unload_packet, false); if (ret) { pr_err("NPU_IPC_CMD_UNLOAD sent failed: %d\n", ret); @@ -1010,17 +1083,17 @@ int32_t npu_host_unload_network(struct npu_device *npu_dev, return ret; } -int32_t npu_host_exec_network(struct npu_device *npu_dev, +int32_t npu_host_exec_network(struct npu_client *client, struct msm_npu_exec_network_ioctl *exec_ioctl) { + struct npu_device *npu_dev = client->npu_dev; struct ipc_cmd_execute_pkt exec_packet; /* npu mapped addr */ - uint64_t input_addr = 0, output_addr = 0; uint64_t input_off, output_off; int32_t ret; struct npu_network *network; struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; - int i = 0; + bool async_ioctl = !!exec_ioctl->async; network = get_network_by_hdl(host_ctx, exec_ioctl->network_hdl); @@ -1032,14 +1105,15 @@ int32_t npu_host_exec_network(struct npu_device *npu_dev, memset(&exec_packet, 0, sizeof(exec_packet)); if (exec_ioctl->patching_required) { - if (exec_ioctl->input_layer_num == 1) - input_addr = exec_ioctl->input_layers[0].buf_phys_addr; - if (exec_ioctl->output_layer_num == 1) - output_addr = - exec_ioctl->output_layers[0].buf_phys_addr; + if ((exec_ioctl->input_layer_num != 1) || + (exec_ioctl->output_layer_num != 1)) { + pr_err("Invalid input/output layer num\n"); + return -EINVAL; + } + + input_off = exec_ioctl->input_layers[0].buf_phys_addr; + output_off = exec_ioctl->output_layers[0].buf_phys_addr; exec_packet.patch_params.num_params = 2; - input_off = (uint64_t)input_addr; - output_off = (uint64_t)output_addr; host_copy_patch_data(&exec_packet.patch_params.param[0], (uint32_t)input_off, &exec_ioctl->input_layers[0]); host_copy_patch_data(&exec_packet.patch_params.param[1], @@ -1057,10 +1131,12 @@ int32_t npu_host_exec_network(struct npu_device *npu_dev, /* Send it on the high priority queue */ reinit_completion(&network->cmd_done); - ret = npu_send_network_cmd(npu_dev, network, &exec_packet); + ret = npu_send_network_cmd(npu_dev, network, &exec_packet, async_ioctl); if (ret) { pr_err("NPU_IPC_CMD_EXECUTE sent failed: %d\n", ret); + } else if (async_ioctl) { + pr_debug("Async ioctl, return now\n"); } else if (!wait_for_completion_interruptible_timeout( &network->cmd_done, (host_ctx->fw_dbg_mode & FW_DBG_MODE_INC_TIMEOUT) ? @@ -1072,28 +1148,22 @@ int32_t npu_host_exec_network(struct npu_device *npu_dev, } else if (network->fw_error) { ret = -EIO; pr_err("execute cmd returns with error\n"); - } else { - /* Invalidate output buffers */ - for (i = 0; i < exec_ioctl->output_layer_num; i++) { - if (exec_ioctl->output_layer_num == 1) { - npu_mem_invalidate(npu_dev, - exec_ioctl->output_layers[i].buf_hdl); - } - } } return ret; } -int32_t npu_host_exec_network_v2(struct npu_device *npu_dev, +int32_t npu_host_exec_network_v2(struct npu_client *client, struct msm_npu_exec_network_ioctl_v2 *exec_ioctl, struct msm_npu_patch_buf_info *patch_buf_info) { + struct npu_device *npu_dev = client->npu_dev; struct ipc_cmd_execute_pkt_v2 *exec_packet; int32_t ret; struct npu_network *network; struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; uint32_t num_patch_params, pkt_size; + bool async_ioctl = !!exec_ioctl->async; int i; network = get_network_by_hdl(host_ctx, exec_ioctl->network_hdl); @@ -1131,22 +1201,20 @@ int32_t npu_host_exec_network_v2(struct npu_device *npu_dev, exec_packet->network_hdl = network->network_hdl; exec_packet->num_patch_params = num_patch_params; - /* allocate stats_buf to be filled after execution */ - network->stats_buf = kzalloc(exec_ioctl->stats_buf_size, GFP_KERNEL); - if (!network->stats_buf) - network->stats_buf_size = 0; - else - network->stats_buf_size = exec_ioctl->stats_buf_size; + network->stats_buf_u = (void __user *)exec_ioctl->stats_buf_addr; + network->stats_buf_size = exec_ioctl->stats_buf_size; pr_debug("Execute_v2 flags %x stats_buf_size %d\n", exec_packet->header.flags, exec_ioctl->stats_buf_size); /* Send it on the high priority queue */ reinit_completion(&network->cmd_done); - ret = npu_send_network_cmd(npu_dev, network, exec_packet); + ret = npu_send_network_cmd(npu_dev, network, exec_packet, async_ioctl); if (ret) { pr_err("NPU_IPC_CMD_EXECUTE_V2 sent failed: %d\n", ret); + } else if (async_ioctl) { + pr_debug("Async ioctl, return now\n"); } else if (!wait_for_completion_interruptible_timeout( &network->cmd_done, (host_ctx->fw_dbg_mode & FW_DBG_MODE_INC_TIMEOUT) ? @@ -1160,15 +1228,13 @@ int32_t npu_host_exec_network_v2(struct npu_device *npu_dev, pr_err("execute cmd returns with error\n"); } else { exec_ioctl->stats_buf_size = network->stats_buf_size; - if (exec_ioctl->stats_buf_size) { - if (copy_to_user( - (void __user *)exec_ioctl->stats_buf_addr, - network->stats_buf, exec_ioctl->stats_buf_size)) - pr_err("copy stats to user failed\n"); + if (copy_to_user((void __user *)exec_ioctl->stats_buf_addr, + network->stats_buf, exec_ioctl->stats_buf_size)) { + pr_err("copy stats to user failed\n"); + exec_ioctl->stats_buf_size = 0; } } - kfree(network->stats_buf); kfree(exec_packet); return ret; } diff --git a/drivers/media/platform/msm/npu/npu_mgr.h b/drivers/media/platform/msm/npu/npu_mgr.h index 5d04dca131cd..d136b4761717 100644 --- a/drivers/media/platform/msm/npu/npu_mgr.h +++ b/drivers/media/platform/msm/npu/npu_mgr.h @@ -19,6 +19,7 @@ */ #include #include "npu_hw_access.h" +#include "npu_common.h" /* ------------------------------------------------------------------------- * Defines @@ -50,11 +51,14 @@ struct npu_network { uint32_t perf_mode; uint32_t num_layers; void *stats_buf; + void __user *stats_buf_u; uint32_t stats_buf_size; bool is_valid; bool fw_error; bool cmd_pending; + bool cmd_async; struct completion cmd_done; + struct npu_client *client; }; enum fw_state { @@ -107,16 +111,16 @@ int32_t npu_host_map_buf(struct npu_device *npu_dev, struct msm_npu_map_buf_ioctl *map_ioctl); int32_t npu_host_unmap_buf(struct npu_device *npu_dev, struct msm_npu_unmap_buf_ioctl *unmap_ioctl); -int32_t npu_host_load_network(struct npu_device *npu_dev, +int32_t npu_host_load_network(struct npu_client *client, struct msm_npu_load_network_ioctl *load_ioctl); -int32_t npu_host_load_network_v2(struct npu_device *npu_dev, +int32_t npu_host_load_network_v2(struct npu_client *client, struct msm_npu_load_network_ioctl_v2 *load_ioctl, struct msm_npu_patch_info_v2 *patch_info); -int32_t npu_host_unload_network(struct npu_device *npu_dev, +int32_t npu_host_unload_network(struct npu_client *client, struct msm_npu_unload_network_ioctl *unload); -int32_t npu_host_exec_network(struct npu_device *npu_dev, +int32_t npu_host_exec_network(struct npu_client *client, struct msm_npu_exec_network_ioctl *exec_ioctl); -int32_t npu_host_exec_network_v2(struct npu_device *npu_dev, +int32_t npu_host_exec_network_v2(struct npu_client *client, struct msm_npu_exec_network_ioctl_v2 *exec_ioctl, struct msm_npu_patch_buf_info *patch_buf_info); int32_t npu_host_loopback_test(struct npu_device *npu_dev); diff --git a/include/uapi/linux/msm_npu.h b/include/uapi/linux/msm_npu.h index 77102ff8a2b2..d1c61b7839c9 100644 --- a/include/uapi/linux/msm_npu.h +++ b/include/uapi/linux/msm_npu.h @@ -45,6 +45,15 @@ #define MSM_NPU_EXEC_NETWORK_V2 \ _IOWR(MSM_NPU_IOCTL_MAGIC, 8, struct msm_npu_exec_network_ioctl_v2) +/* receive event */ +#define MSM_NPU_RECEIVE_EVENT \ + _IOR(MSM_NPU_IOCTL_MAGIC, 9, struct msm_npu_event) + +#define MSM_NPU_EVENT_TYPE_START 0x10000000 +#define MSM_NPU_EVENT_TYPE_EXEC_DONE (MSM_NPU_EVENT_TYPE_START + 1) +#define MSM_NPU_EVENT_TYPE_EXEC_V2_DONE (MSM_NPU_EVENT_TYPE_START + 2) +#define MSM_NPU_EVENT_TYPE_SSR (MSM_NPU_EVENT_TYPE_START + 3) + #define MSM_NPU_MAX_INPUT_LAYER_NUM 8 #define MSM_NPU_MAX_OUTPUT_LAYER_NUM 4 #define MSM_NPU_MAX_PATCH_LAYER_NUM (MSM_NPU_MAX_INPUT_LAYER_NUM +\ @@ -219,4 +228,31 @@ struct msm_npu_exec_network_ioctl_v2 { uint32_t reserved; }; +struct msm_npu_event_execute_done { + uint32_t network_hdl; + int32_t exec_result; +}; + +struct msm_npu_event_execute_v2_done { + uint32_t network_hdl; + int32_t exec_result; + /* stats buf size filled */ + uint32_t stats_buf_size; +}; + +struct msm_npu_event_ssr { + uint32_t network_hdl; +}; + +struct msm_npu_event { + uint32_t type; + union { + struct msm_npu_event_execute_done exec_done; + struct msm_npu_event_execute_v2_done exec_v2_done; + struct msm_npu_event_ssr ssr; + uint8_t data[128]; + } u; + uint32_t reserved[4]; +}; + #endif /*_UAPI_MSM_NPU_H_*/ -- GitLab From 80f053b88956b88ee54e5ece6c231538bda47b49 Mon Sep 17 00:00:00 2001 From: Jilai Wang Date: Thu, 2 Aug 2018 08:56:44 -0400 Subject: [PATCH 0592/1001] msm: npu: refactor npu_map_buf/npu_unmap_buf functions Mapped ion buffer list is changed to be managed by each npu client and protected by a mutex to support concurrent use cases. Change-Id: Ia81876689c2e943c28cd5ee35e56fb9196b99002 Signed-off-by: Jilai Wang --- drivers/media/platform/msm/npu/npu_common.h | 5 +- drivers/media/platform/msm/npu/npu_dbg.c | 1 - drivers/media/platform/msm/npu/npu_dev.c | 9 +- .../media/platform/msm/npu/npu_hw_access.c | 137 ++++++++++++------ .../media/platform/msm/npu/npu_hw_access.h | 8 +- drivers/media/platform/msm/npu/npu_mgr.c | 42 +++++- drivers/media/platform/msm/npu/npu_mgr.h | 4 +- 7 files changed, 140 insertions(+), 66 deletions(-) diff --git a/drivers/media/platform/msm/npu/npu_common.h b/drivers/media/platform/msm/npu/npu_common.h index 4dabbf34a877..63c4fc1c1493 100644 --- a/drivers/media/platform/msm/npu/npu_common.h +++ b/drivers/media/platform/msm/npu/npu_common.h @@ -169,7 +169,7 @@ struct npu_irq { }; struct npu_device { - struct mutex ctx_lock; + struct mutex dev_lock; struct platform_device *pdev; @@ -190,8 +190,6 @@ struct npu_device { struct npu_irq irq[NPU_MAX_IRQ]; - struct npu_ion_buf mapped_buffers; - struct device *cb_device; struct npu_host_ctx host_ctx; @@ -220,6 +218,7 @@ struct npu_client { struct mutex list_lock; struct list_head evt_list; + struct list_head mapped_buffer_list; }; /* ------------------------------------------------------------------------- diff --git a/drivers/media/platform/msm/npu/npu_dbg.c b/drivers/media/platform/msm/npu/npu_dbg.c index 386433911530..67ded1ecd5e1 100644 --- a/drivers/media/platform/msm/npu/npu_dbg.c +++ b/drivers/media/platform/msm/npu/npu_dbg.c @@ -305,7 +305,6 @@ void npu_dump_debug_timeout_stats(struct npu_device *npu_dev) pr_info("fw jobs execute finished count = %d\n", reg_val); reg_val = REGR(npu_dev, REG_NPU_FW_DEBUG_DATA); pr_info("fw jobs aco parser debug = %d\n", reg_val); - npu_dump_cal_state(npu_dev); } void npu_dump_cal_state(struct npu_device *npu_dev) diff --git a/drivers/media/platform/msm/npu/npu_dev.c b/drivers/media/platform/msm/npu/npu_dev.c index bba09763778c..9e68687fe628 100644 --- a/drivers/media/platform/msm/npu/npu_dev.c +++ b/drivers/media/platform/msm/npu/npu_dev.c @@ -814,6 +814,7 @@ static int npu_open(struct inode *inode, struct file *file) init_waitqueue_head(&client->wait); mutex_init(&client->list_lock); INIT_LIST_HEAD(&client->evt_list); + INIT_LIST_HEAD(&(client->mapped_buffer_list)); file->private_data = client; return 0; @@ -872,7 +873,6 @@ static int npu_get_info(struct npu_client *client, unsigned long arg) static int npu_map_buf(struct npu_client *client, unsigned long arg) { - struct npu_device *npu_dev = client->npu_dev; struct msm_npu_map_buf_ioctl req; void __user *argp = (void __user *)arg; int ret = 0; @@ -884,7 +884,7 @@ static int npu_map_buf(struct npu_client *client, unsigned long arg) return -EFAULT; } - ret = npu_host_map_buf(npu_dev, &req); + ret = npu_host_map_buf(client, &req); if (ret) { pr_err("npu_host_map_buf failed\n"); @@ -902,7 +902,6 @@ static int npu_map_buf(struct npu_client *client, unsigned long arg) static int npu_unmap_buf(struct npu_client *client, unsigned long arg) { - struct npu_device *npu_dev = client->npu_dev; struct msm_npu_unmap_buf_ioctl req; void __user *argp = (void __user *)arg; int ret = 0; @@ -914,7 +913,7 @@ static int npu_unmap_buf(struct npu_client *client, unsigned long arg) return -EFAULT; } - ret = npu_host_unmap_buf(npu_dev, &req); + ret = npu_host_unmap_buf(client, &req); if (ret) { pr_err("npu_host_unmap_buf failed\n"); @@ -1633,7 +1632,7 @@ static int npu_probe(struct platform_device *pdev) goto error_driver_init; } - INIT_LIST_HEAD(&(npu_dev->mapped_buffers.list)); + mutex_init(&npu_dev->dev_lock); rc = npu_host_init(npu_dev); if (rc) { diff --git a/drivers/media/platform/msm/npu/npu_hw_access.c b/drivers/media/platform/msm/npu/npu_hw_access.c index a4c24fa5fd11..c233bd964161 100644 --- a/drivers/media/platform/msm/npu/npu_hw_access.c +++ b/drivers/media/platform/msm/npu/npu_hw_access.c @@ -151,69 +151,94 @@ int32_t npu_interrupt_raise_m0(struct npu_device *npu_dev) * Functions - ION Memory * ------------------------------------------------------------------------- */ -static struct npu_ion_buf *npu_get_npu_ion_buffer(struct npu_device - *npu_dev) +static struct npu_ion_buf *npu_alloc_npu_ion_buffer(struct npu_client + *client, int buf_hdl, uint32_t size) { - struct npu_ion_buf *ret_val = 0; + struct npu_ion_buf *ret_val = NULL, *tmp; + struct list_head *pos = NULL; + + mutex_lock(&client->list_lock); + list_for_each(pos, &(client->mapped_buffer_list)) { + tmp = list_entry(pos, struct npu_ion_buf, list); + if (tmp->fd == buf_hdl) { + ret_val = tmp; + break; + } + } - ret_val = kmalloc(sizeof(struct npu_ion_buf), GFP_KERNEL); - if (ret_val) - list_add(&(ret_val->list), &(npu_dev->mapped_buffers.list)); + if (ret_val) { + /* mapped already, treat as invalid request */ + pr_err("ion buf %x has been mapped\n"); + ret_val = NULL; + } else { + ret_val = kmalloc(sizeof(struct npu_ion_buf), GFP_KERNEL); + if (ret_val) { + ret_val->fd = buf_hdl; + ret_val->size = size; + ret_val->iova = 0; + list_add(&(ret_val->list), + &(client->mapped_buffer_list)); + } + } + mutex_unlock(&client->list_lock); return ret_val; } -static struct npu_ion_buf *npu_get_existing_ion_buffer(struct npu_device - *npu_dev, int buf_hdl) +static struct npu_ion_buf *npu_get_npu_ion_buffer(struct npu_client + *client, int buf_hdl) { - struct list_head *pos = 0; - struct npu_ion_buf *npu_ion_buf = 0; - - list_for_each(pos, &(npu_dev->mapped_buffers.list)) { - npu_ion_buf = list_entry(pos, struct npu_ion_buf, list); - if (npu_ion_buf->fd == buf_hdl) - return npu_ion_buf; + struct list_head *pos = NULL; + struct npu_ion_buf *ret_val = NULL, *tmp; + + mutex_lock(&client->list_lock); + list_for_each(pos, &(client->mapped_buffer_list)) { + tmp = list_entry(pos, struct npu_ion_buf, list); + if (tmp->fd == buf_hdl) { + ret_val = tmp; + break; + } } + mutex_unlock(&client->list_lock); - return NULL; + return ret_val; } -static struct npu_ion_buf *npu_clear_npu_ion_buffer(struct npu_device - *npu_dev, int buf_hdl, uint64_t addr) +static void npu_free_npu_ion_buffer(struct npu_client + *client, int buf_hdl) { - struct list_head *pos = 0; - struct npu_ion_buf *npu_ion_buf = 0; + struct list_head *pos = NULL; + struct npu_ion_buf *npu_ion_buf = NULL; - list_for_each(pos, &(npu_dev->mapped_buffers.list)) { + mutex_lock(&client->list_lock); + list_for_each(pos, &(client->mapped_buffer_list)) { npu_ion_buf = list_entry(pos, struct npu_ion_buf, list); - if (npu_ion_buf->fd == buf_hdl && - npu_ion_buf->iova == addr) { + if (npu_ion_buf->fd == buf_hdl) { list_del(&npu_ion_buf->list); - return npu_ion_buf; + kfree(npu_ion_buf); + break; } } - - return NULL; + mutex_unlock(&client->list_lock); } -int npu_mem_map(struct npu_device *npu_dev, int buf_hdl, uint32_t size, +int npu_mem_map(struct npu_client *client, int buf_hdl, uint32_t size, uint64_t *addr) { int ret = 0; - - struct npu_ion_buf *ion_buf = npu_get_npu_ion_buffer(npu_dev); + struct npu_device *npu_dev = client->npu_dev; + struct npu_ion_buf *ion_buf = NULL; struct npu_smmu_ctx *smmu_ctx = &npu_dev->smmu_ctx; + if (buf_hdl == 0) + return -EINVAL; + + ion_buf = npu_alloc_npu_ion_buffer(client, buf_hdl, size); if (!ion_buf) { - pr_err("%s no more table space\n", __func__); + pr_err("%s fail to alloc npu_ion_buffer\n", __func__); ret = -ENOMEM; return ret; } - ion_buf->fd = buf_hdl; - ion_buf->size = size; - - if (ion_buf->fd == 0) - return -EINVAL; smmu_ctx->attach_cnt++; @@ -250,15 +275,16 @@ int npu_mem_map(struct npu_device *npu_dev, int buf_hdl, uint32_t size, ion_buf->size = ion_buf->table->sgl->dma_length; map_end: if (ret) - npu_mem_unmap(npu_dev, buf_hdl, 0); + npu_mem_unmap(client, buf_hdl, 0); *addr = ion_buf->iova; return ret; } -void npu_mem_invalidate(struct npu_device *npu_dev, int buf_hdl) +void npu_mem_invalidate(struct npu_client *client, int buf_hdl) { - struct npu_ion_buf *ion_buf = npu_get_existing_ion_buffer(npu_dev, + struct npu_device *npu_dev = client->npu_dev; + struct npu_ion_buf *ion_buf = npu_get_npu_ion_buffer(client, buf_hdl); if (!ion_buf) @@ -268,29 +294,50 @@ void npu_mem_invalidate(struct npu_device *npu_dev, int buf_hdl) ion_buf->table->nents, DMA_BIDIRECTIONAL); } -void npu_mem_unmap(struct npu_device *npu_dev, int buf_hdl, uint64_t addr) +bool npu_mem_verify_addr(struct npu_client *client, uint64_t addr) { struct npu_ion_buf *ion_buf = 0; + struct list_head *pos = NULL; + bool valid = false; + + mutex_lock(&client->list_lock); + list_for_each(pos, &(client->mapped_buffer_list)) { + ion_buf = list_entry(pos, struct npu_ion_buf, list); + if (ion_buf->iova == addr) { + valid = true; + break; + } + } + mutex_unlock(&client->list_lock); - /* clear entry and retrieve the corresponding buffer */ - ion_buf = npu_clear_npu_ion_buffer(npu_dev, buf_hdl, addr); + return valid; +} +void npu_mem_unmap(struct npu_client *client, int buf_hdl, uint64_t addr) +{ + struct npu_device *npu_dev = client->npu_dev; + struct npu_ion_buf *ion_buf = 0; + + /* clear entry and retrieve the corresponding buffer */ + ion_buf = npu_get_npu_ion_buffer(client, buf_hdl); if (!ion_buf) { pr_err("%s could not find buffer\n", __func__); return; } + + if (ion_buf->iova != addr) + pr_warn("unmap address %lu doesn't match %lu\n", addr, + ion_buf->iova); + if (ion_buf->table) dma_buf_unmap_attachment(ion_buf->attachment, ion_buf->table, DMA_BIDIRECTIONAL); - ion_buf->table = 0; if (ion_buf->dma_buf && ion_buf->attachment) dma_buf_detach(ion_buf->dma_buf, ion_buf->attachment); - ion_buf->attachment = 0; if (ion_buf->dma_buf) dma_buf_put(ion_buf->dma_buf); - ion_buf->dma_buf = 0; npu_dev->smmu_ctx.attach_cnt--; - kfree(ion_buf); + npu_free_npu_ion_buffer(client, buf_hdl); } /* ------------------------------------------------------------------------- diff --git a/drivers/media/platform/msm/npu/npu_hw_access.h b/drivers/media/platform/msm/npu/npu_hw_access.h index 8f3eb332139a..96dc48af3e48 100644 --- a/drivers/media/platform/msm/npu/npu_hw_access.h +++ b/drivers/media/platform/msm/npu/npu_hw_access.h @@ -43,6 +43,7 @@ struct npu_device; struct npu_ion_buf_t; struct npu_host_ctx; +struct npu_client; typedef irqreturn_t (*intr_hdlr_fn)(int32_t irq, void *ptr); typedef void (*wq_hdlr_fn) (struct work_struct *work); @@ -57,10 +58,11 @@ void npu_mem_write(struct npu_device *npu_dev, void *dst, void *src, int32_t npu_mem_read(struct npu_device *npu_dev, void *src, void *dst, uint32_t size); -int npu_mem_map(struct npu_device *npu_dev, int buf_hdl, uint32_t size, +int npu_mem_map(struct npu_client *client, int buf_hdl, uint32_t size, uint64_t *addr); -void npu_mem_unmap(struct npu_device *npu_dev, int buf_hdl, uint64_t addr); -void npu_mem_invalidate(struct npu_device *npu_dev, int buf_hdl); +void npu_mem_unmap(struct npu_client *client, int buf_hdl, uint64_t addr); +void npu_mem_invalidate(struct npu_client *client, int buf_hdl); +bool npu_mem_verify_addr(struct npu_client *client, uint64_t addr); void *npu_ipc_addr(void); void npu_interrupt_ack(struct npu_device *npu_dev, uint32_t intr_num); diff --git a/drivers/media/platform/msm/npu/npu_mgr.c b/drivers/media/platform/msm/npu/npu_mgr.c index 5664435e004e..6315156a4b2b 100644 --- a/drivers/media/platform/msm/npu/npu_mgr.c +++ b/drivers/media/platform/msm/npu/npu_mgr.c @@ -574,6 +574,7 @@ static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) break; } + pr_debug("network id : %d", network->id); stats_size = exe_rsp_pkt->header.size - sizeof(*exe_rsp_pkt); pr_debug("stats_size %d:%d\n", exe_rsp_pkt->header.size, stats_size); @@ -728,18 +729,17 @@ int32_t npu_host_get_info(struct npu_device *npu_dev, return 0; } -int32_t npu_host_map_buf(struct npu_device *npu_dev, +int32_t npu_host_map_buf(struct npu_client *client, struct msm_npu_map_buf_ioctl *map_ioctl) { - npu_mem_map(npu_dev, map_ioctl->buf_ion_hdl, map_ioctl->size, + return npu_mem_map(client, map_ioctl->buf_ion_hdl, map_ioctl->size, &map_ioctl->npu_phys_addr); - return 0; } -int32_t npu_host_unmap_buf(struct npu_device *npu_dev, +int32_t npu_host_unmap_buf(struct npu_client *client, struct msm_npu_unmap_buf_ioctl *unmap_ioctl) { - npu_mem_unmap(npu_dev, unmap_ioctl->buf_ion_hdl, + npu_mem_unmap(client, unmap_ioctl->buf_ion_hdl, unmap_ioctl->npu_phys_addr); return 0; } @@ -759,8 +759,9 @@ static int npu_send_network_cmd(struct npu_device *npu_dev, pr_err("Another cmd is pending\n"); ret = -EBUSY; } else { - pr_debug("Send cmd %d\n", - ((struct ipc_cmd_header_pkt *)cmd_ptr)->cmd_type); + pr_debug("Send cmd %d network id %d\n", + ((struct ipc_cmd_header_pkt *)cmd_ptr)->cmd_type, + network->id); network->cmd_async = async; ret = npu_host_ipc_send_cmd(npu_dev, IPC_QUEUE_APPS_EXEC, cmd_ptr); @@ -880,6 +881,12 @@ int32_t npu_host_load_network(struct npu_client *client, network->priority = load_ioctl->priority; network->perf_mode = load_ioctl->perf_mode; + /* verify mapped physical address */ + if (!npu_mem_verify_addr(client, network->phy_add)) { + ret = -EINVAL; + goto error_free_network; + } + networks_perf_mode = find_networks_perf_mode(host_ctx); ret = npu_set_uc_power_level(npu_dev, networks_perf_mode); @@ -975,6 +982,12 @@ int32_t npu_host_load_network_v2(struct npu_client *client, network->perf_mode = load_ioctl->perf_mode; network->num_layers = load_ioctl->num_layers; + /* verify mapped physical address */ + if (!npu_mem_verify_addr(client, network->phy_add)) { + ret = -EINVAL; + goto error_free_network; + } + networks_perf_mode = find_networks_perf_mode(host_ctx); ret = npu_set_uc_power_level(npu_dev, networks_perf_mode); @@ -1113,6 +1126,13 @@ int32_t npu_host_exec_network(struct npu_client *client, input_off = exec_ioctl->input_layers[0].buf_phys_addr; output_off = exec_ioctl->output_layers[0].buf_phys_addr; + /* verify mapped physical address */ + if (!npu_mem_verify_addr(client, input_off) || + !npu_mem_verify_addr(client, output_off)) { + pr_err("Invalid patch buf address\n"); + return -EINVAL; + } + exec_packet.patch_params.num_params = 2; host_copy_patch_data(&exec_packet.patch_params.param[0], (uint32_t)input_off, &exec_ioctl->input_layers[0]); @@ -1190,6 +1210,14 @@ int32_t npu_host_exec_network_v2(struct npu_client *client, patch_buf_info[i].buf_phys_addr; pr_debug("%d: patch value: %x\n", i, exec_packet->patch_params[i].value); + + /* verify mapped physical address */ + if (!npu_mem_verify_addr(client, + patch_buf_info[i].buf_phys_addr)) { + pr_err("Invalid patch value\n"); + kfree(exec_packet); + return -EINVAL; + } } exec_packet->header.cmd_type = NPU_IPC_CMD_EXECUTE_V2; diff --git a/drivers/media/platform/msm/npu/npu_mgr.h b/drivers/media/platform/msm/npu/npu_mgr.h index d136b4761717..0a49893d69dc 100644 --- a/drivers/media/platform/msm/npu/npu_mgr.h +++ b/drivers/media/platform/msm/npu/npu_mgr.h @@ -107,9 +107,9 @@ int npu_host_ipc_read_msg(struct npu_device *npu_dev, uint32_t queueIndex, int32_t npu_host_get_info(struct npu_device *npu_dev, struct msm_npu_get_info_ioctl *get_info_ioctl); -int32_t npu_host_map_buf(struct npu_device *npu_dev, +int32_t npu_host_map_buf(struct npu_client *client, struct msm_npu_map_buf_ioctl *map_ioctl); -int32_t npu_host_unmap_buf(struct npu_device *npu_dev, +int32_t npu_host_unmap_buf(struct npu_client *client, struct msm_npu_unmap_buf_ioctl *unmap_ioctl); int32_t npu_host_load_network(struct npu_client *client, struct msm_npu_load_network_ioctl *load_ioctl); -- GitLab From 1a36e27471be2be50ad17397e11de266b50f37d2 Mon Sep 17 00:00:00 2001 From: Tony Truong Date: Fri, 3 Aug 2018 12:00:42 -0700 Subject: [PATCH 0593/1001] Revert "ARM: dts: msm: disable L1/L1ss for PCIe1 on sm8150-sdx50 platform" sm8150-sdx50 PCIe is now stable with L1 and L1ss enabled. Therefore enable L1 and L1ss for PCIe1 on sm8150-sdx50 by reverting the disable commit. This reverts commit 0dee6e755cda8dbd38d0724f38fefa00d2919385. Change-Id: I645c202639aaa2557315e6003ce7f1a40f913547 Signed-off-by: Tony Truong --- arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi index ba8679baa3e8..0f66048824b6 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi @@ -159,10 +159,6 @@ iommu-map = <0x0 &apps_smmu 0x1e00 0x1>, <0x100 &apps_smmu 0x1e7f 0x1>; - - qcom,no-l1-supported; - qcom,no-l1ss-supported; - qcom,no-aux-clk-sync; }; &soc { -- GitLab From b6dcd0fabd577b21a15af628253b7954cfd6c635 Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Mon, 30 Jul 2018 15:51:02 -0700 Subject: [PATCH 0594/1001] ARM: dts: msm: Add device tree property to collect full ramdumps Add device tree property to collect full ramdumps, without any holes between segments, for subsystems that are loaded by PIL, and whose ramdumps are collected, on SM8150. Change-Id: Iccf24aca2ed4697c70bd209e9a5f379a26d61d2f Signed-off-by: Isaac J. Manjarres --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index c7d9fd9765c9..acebb7e3c8dd 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -1656,6 +1656,7 @@ qcom,firmware-name = "adsp"; memory-region = <&pil_adsp_mem>; qcom,signal-aop; + qcom,complete-ramdump; /* Inputs from lpass */ interrupts-extended = <&pdc 0 162 1>, @@ -1703,6 +1704,7 @@ status = "ok"; memory-region = <&pil_slpi_mem>; qcom,signal-aop; + qcom,complete-ramdump; /* Inputs from ssc */ interrupts-extended = <&pdc 0 494 1>, @@ -1748,6 +1750,7 @@ qcom,pil-generic-irq-handler; status = "ok"; qcom,signal-aop; + qcom,complete-ramdump; qcom,pas-id = <14>; qcom,proxy-timeout-ms = <10000>; @@ -1803,6 +1806,7 @@ qcom,firmware-name = "cdsp"; memory-region = <&pil_cdsp_mem>; qcom,signal-aop; + qcom,complete-ramdump; qcom,msm-bus,name = "pil-cdsp"; qcom,msm-bus,num-cases = <2>; @@ -1838,6 +1842,7 @@ vdd-supply = <&mvsc_gdsc>; qcom,proxy-reg-names = "vdd"; + qcom,complete-ramdump; clocks = <&clock_videocc VIDEO_CC_XO_CLK>, <&clock_videocc VIDEO_CC_MVSC_CORE_CLK>, -- GitLab From 64278fd55cb9097df0491e2fa22cbd0f46e091e6 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Fri, 3 Aug 2018 19:15:35 -0700 Subject: [PATCH 0595/1001] power: qpnp-fg-gen4: Disable ESR pulsing when fast calibration is disabled Disable ESR discharging timer and ESR pulsing during discharging when ESR fast calibration is disabled. This helps in power savings. Change-Id: I1cce44ce6e741402ddd51ed23ff6c22b35acfc73 Signed-off-by: Harry Yang --- drivers/power/supply/qcom/qpnp-fg-gen4.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index 76f4897fe7c6..fd260825570e 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -3535,6 +3535,19 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) return rc; } } + + /* + * Disable ESR discharging timer and ESR pulsing during + * discharging when ESR fast calibration is disabled. + */ + val = 0; + mask = BIT(6) | BIT(7); + rc = fg_sram_masked_write(fg, SYS_CONFIG_WORD, + SYS_CONFIG_OFFSET, mask, val, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in writing SYS_CONFIG_WORD, rc=%d\n", rc); + return rc; + } } /* -- GitLab From bf4ec895e1d5698eea62e993917063612e2b3069 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Wed, 20 Jun 2018 11:11:49 -0700 Subject: [PATCH 0596/1001] power: smb5-lib: Add wireless support in DC psy Parallel wireless charging requires adjustable voltage output from Wireless receiver, implemented via input_voltage_regulation property in wireless psy. In addition, DC psy also supplies other current/voltage access. Change-Id: I56e2846f18e9827486569d9c2fa988bc77993e8e Signed-off-by: Harry Yang --- drivers/power/supply/qcom/qpnp-smb5.c | 18 ++++++-- drivers/power/supply/qcom/smb5-lib.c | 66 +++++++++++++++++++++++++++ drivers/power/supply/qcom/smb5-lib.h | 11 +++++ 3 files changed, 91 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 39e4ec07f1bd..d4f72a380e4f 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -1024,7 +1024,10 @@ static enum power_supply_property smb5_dc_props[] = { POWER_SUPPLY_PROP_INPUT_SUSPEND, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_MAX, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, POWER_SUPPLY_PROP_REAL_TYPE, }; @@ -1046,9 +1049,14 @@ static int smb5_dc_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_ONLINE: rc = smblib_get_prop_dc_online(chg, val); break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + rc = smblib_get_prop_dc_voltage_now(chg, val); + break; case POWER_SUPPLY_PROP_CURRENT_MAX: - rc = smblib_get_charge_param(chg, &chg->param.dc_icl, - &val->intval); + rc = smblib_get_prop_dc_current_max(chg, val); + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + rc = smblib_get_prop_dc_voltage_max(chg, val); break; case POWER_SUPPLY_PROP_REAL_TYPE: val->intval = POWER_SUPPLY_TYPE_WIPOWER; @@ -1077,8 +1085,10 @@ static int smb5_dc_set_prop(struct power_supply *psy, (bool)val->intval, 0); break; case POWER_SUPPLY_PROP_CURRENT_MAX: - rc = smblib_set_charge_param(chg, &chg->param.dc_icl, - val->intval); + rc = smblib_set_prop_dc_current_max(chg, val); + break; + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION: + rc = smblib_set_prop_voltage_wls_output(chg, val); break; default: return -EINVAL; diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index a03d0c9f07a1..5b358d55c9bd 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -1978,6 +1978,72 @@ int smblib_get_prop_dc_online(struct smb_charger *chg, return rc; } +int smblib_get_prop_dc_current_max(struct smb_charger *chg, + union power_supply_propval *val) +{ + return smblib_get_charge_param(chg, &chg->param.dc_icl, &val->intval); +} + +int smblib_get_prop_dc_voltage_max(struct smb_charger *chg, + union power_supply_propval *val) +{ + val->intval = MICRO_12V; + return 0; +} + +int smblib_get_prop_dc_voltage_now(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + if (!chg->wls_psy) { + chg->wls_psy = power_supply_get_by_name("wireless"); + if (!chg->wls_psy) + return -ENODEV; + } + + rc = power_supply_get_property(chg->wls_psy, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + val); + if (rc < 0) + dev_err(chg->dev, "Couldn't get POWER_SUPPLY_PROP_VOLTAGE_MAX, rc=%d\n", + rc); + return rc; +} + +/******************* + * DC PSY SETTERS * + *******************/ + +int smblib_set_prop_dc_current_max(struct smb_charger *chg, + const union power_supply_propval *val) +{ + return smblib_set_charge_param(chg, &chg->param.dc_icl, val->intval); +} + +int smblib_set_prop_voltage_wls_output(struct smb_charger *chg, + const union power_supply_propval *val) +{ + int rc; + + if (!chg->wls_psy) { + chg->wls_psy = power_supply_get_by_name("wireless"); + if (!chg->wls_psy) + return -ENODEV; + } + + rc = power_supply_set_property(chg->wls_psy, + POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, + val); + if (rc < 0) + dev_err(chg->dev, "Couldn't set POWER_SUPPLY_PROP_VOLTAGE_REGULATION, rc=%d\n", + rc); + + smblib_dbg(chg, PR_WLS, "Set WLS output voltage %d\n", val->intval); + + return rc; +} + /******************* * USB PSY GETTERS * *******************/ diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 26a0fa1f9508..447c269df1f2 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -26,6 +26,7 @@ enum print_reason { PR_MISC = BIT(2), PR_PARALLEL = BIT(3), PR_OTG = BIT(4), + PR_WLS = BIT(5), }; #define DEFAULT_VOTER "DEFAULT_VOTER" @@ -282,6 +283,7 @@ struct smb_charger { struct power_supply *bms_psy; struct power_supply *usb_main_psy; struct power_supply *usb_port_psy; + struct power_supply *wls_psy; enum power_supply_type real_charger_type; /* notifiers */ @@ -392,6 +394,9 @@ struct smb_charger { u32 headroom_mode; bool flash_init_done; bool flash_active; + + /* wireless */ + int wireless_vout; }; int smblib_read(struct smb_charger *chg, u16 addr, u8 *val); @@ -495,6 +500,12 @@ int smblib_get_prop_dc_current_max(struct smb_charger *chg, union power_supply_propval *val); int smblib_set_prop_dc_current_max(struct smb_charger *chg, const union power_supply_propval *val); +int smblib_get_prop_dc_voltage_now(struct smb_charger *chg, + union power_supply_propval *val); +int smblib_get_prop_dc_voltage_max(struct smb_charger *chg, + union power_supply_propval *val); +int smblib_set_prop_voltage_wls_output(struct smb_charger *chg, + const union power_supply_propval *val); int smblib_get_prop_usb_present(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_usb_online(struct smb_charger *chg, -- GitLab From 2bf2ab5a8d3afd8af2cf96e21b1fd4d6d03539c7 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Wed, 1 Aug 2018 21:08:34 -0700 Subject: [PATCH 0597/1001] power: smb5: enable smb1390 Wireless charging Enable SMB1390 wireless charging when DC is the only input power source. Raise wireless output voltage to twice that of vph_power on start. Change-Id: Iece540bdfcdd8f9309c9dcd1160fe976bdd804d6 Signed-off-by: Harry Yang --- drivers/power/supply/qcom/smb5-lib.c | 57 ++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 5b358d55c9bd..2f3717e79039 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -3898,8 +3898,65 @@ irqreturn_t dc_plugin_irq_handler(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; + union power_supply_propval pval; + bool dcin_present, vbus_present; + int rc, wireless_vout = 0; + + rc = iio_read_channel_processed(chg->iio.vph_v_chan, + &wireless_vout); + if (rc < 0) + return IRQ_HANDLED; + + wireless_vout *= 2; + wireless_vout /= 100000; + wireless_vout *= 100000; + + rc = smblib_get_prop_dc_present(chg, &pval); + if (rc < 0) + return IRQ_HANDLED; + + dcin_present = pval.intval; + + rc = smblib_get_prop_usb_present(chg, &pval); + if (rc < 0) { + smblib_err(chg, "Couldn't get usb present rc = %d\n", + rc); + return IRQ_HANDLED; + } + + vbus_present = pval.intval; + + if (dcin_present) { + if (!vbus_present && chg->sec_cp_present) { + pval.intval = wireless_vout; + rc = smblib_set_prop_voltage_wls_output(chg, &pval); + if (rc < 0) + dev_err(chg->dev, "Couldn't set dc voltage to 2*vph rc=%d\n", + rc); + + chg->cp_reason = POWER_SUPPLY_CP_WIRELESS; + rc = smblib_select_sec_charger(chg, + POWER_SUPPLY_CHARGER_SEC_CP); + if (rc < 0) + dev_err(chg->dev, "Couldn't enable secondary chargers rc=%d\n", + rc); + } + } else if (chg->cp_reason == POWER_SUPPLY_CP_WIRELESS) { + chg->cp_reason = POWER_SUPPLY_CP_NONE; + rc = smblib_select_sec_charger(chg, + chg->sec_pl_present ? POWER_SUPPLY_CHARGER_SEC_PL : + POWER_SUPPLY_CHARGER_SEC_NONE); + if (rc < 0) + dev_err(chg->dev, + "Couldn't disable secondary charger rc=%d\n", + rc); + } power_supply_changed(chg->dc_psy); + + smblib_dbg(chg, PR_WLS, "dcin_present= %d, usbin_present= %d, cp_reason = %d\n", + dcin_present, vbus_present, chg->cp_reason); + return IRQ_HANDLED; } -- GitLab From 01806dea74511287f49b47f5c77c95606b441128 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Tue, 19 Jun 2018 23:54:41 -0700 Subject: [PATCH 0598/1001] power: smb1390: add wireless charging support Add parallel wireless charging support in SMB1390 driver, maintaining ILIM = MIN(TOTAL_FCC/2, TOTAL_ICL), where TOTAL_ICL is DC Input current limit. Change-Id: I73444ee72ad10f9bf3aeb93d5859e58eba20080f Signed-off-by: Harry Yang --- drivers/power/supply/qcom/smb1390-charger.c | 46 +++++++++++++++++---- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/drivers/power/supply/qcom/smb1390-charger.c b/drivers/power/supply/qcom/smb1390-charger.c index 1d5771cd72db..92e7fa6ec350 100644 --- a/drivers/power/supply/qcom/smb1390-charger.c +++ b/drivers/power/supply/qcom/smb1390-charger.c @@ -86,7 +86,8 @@ #define ILIM_VOTER "ILIM_VOTER" #define FCC_VOTER "FCC_VOTER" #define ICL_VOTER "ICL_VOTER" -#define USB_VOTER "USB_VOTER" +#define WIRELESS_VOTER "WIRELESS_VOTER" +#define SRC_VOTER "SRC_VOTER" enum { SWITCHER_OFF_WINDOW_IRQ = 0, @@ -126,6 +127,7 @@ struct smb1390 { /* power supplies */ struct power_supply *usb_psy; struct power_supply *batt_psy; + struct power_supply *dc_psy; int irqs[NUM_IRQS]; bool status_change_running; @@ -184,6 +186,14 @@ static bool is_psy_voter_available(struct smb1390 *chip) } } + if (!chip->dc_psy) { + chip->dc_psy = power_supply_get_by_name("dc"); + if (!chip->dc_psy) { + pr_debug("Couldn't find dc psy\n"); + return false; + } + } + if (!chip->fcc_votable) { chip->fcc_votable = find_votable("FCC"); if (!chip->fcc_votable) { @@ -479,19 +489,39 @@ static void smb1390_status_change_work(struct work_struct *work) } if (pval.intval == POWER_SUPPLY_CHARGER_SEC_CP) { - vote(chip->disable_votable, USB_VOTER, false, 0); + rc = power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_SMB_EN_REASON, &pval); + if (rc < 0) { + pr_err("Couldn't get cp reason rc=%d\n", rc); + goto out; + } + + vote(chip->disable_votable, SRC_VOTER, false, 0); /* * ILIM is set based on the primary chargers AICL result. This * ensures VBUS does not collapse due to the current drawn via * MID. */ - rc = power_supply_get_property(chip->usb_psy, + if (pval.intval == POWER_SUPPLY_CP_WIRELESS) { + vote(chip->ilim_votable, ICL_VOTER, false, 0); + rc = power_supply_get_property(chip->dc_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, &pval); + if (rc < 0) + pr_err("Couldn't get dc icl rc=%d\n", rc); + else + vote(chip->ilim_votable, WIRELESS_VOTER, true, + pval.intval); + } else { /* QC3 or PPS */ + vote(chip->ilim_votable, WIRELESS_VOTER, false, 0); + rc = power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval); - if (rc < 0) - pr_err("Couldn't get usb icl rc=%d\n", rc); - else - vote(chip->ilim_votable, ICL_VOTER, true, pval.intval); + if (rc < 0) + pr_err("Couldn't get usb icl rc=%d\n", rc); + else + vote(chip->ilim_votable, ICL_VOTER, true, + pval.intval); + } /* input current is always half the charge current */ vote(chip->ilim_votable, FCC_VOTER, true, @@ -522,7 +552,7 @@ static void smb1390_status_change_work(struct work_struct *work) } } } else { - vote(chip->disable_votable, USB_VOTER, true, 0); + vote(chip->disable_votable, SRC_VOTER, true, 0); vote(chip->fcc_votable, CP_VOTER, false, 0); } -- GitLab From d8258e6fa4aab695ed9c0f3c326ef26e637dd95e Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Mon, 2 Jul 2018 12:51:32 -0600 Subject: [PATCH 0599/1001] net: qualcomm: rmnet: Add support to reset ethtool private stats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add ethtool private stats handler to reset the statistics of handling of packets with downlink header and trailer. “ethtool -r rmnet_data0” will reset the stats. CRs-Fixed: 2285862 Change-Id: Ib3da8c2b7b23d72de2795f93a90e8c0e3b2ce869 Signed-off-by: Subash Abhinov Kasiviswanathan --- drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c index 798984e060b5..e965dbea2e7a 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c @@ -231,10 +231,27 @@ static void rmnet_get_ethtool_stats(struct net_device *dev, ARRAY_SIZE(rmnet_port_gstrings_stats) * sizeof(u64)); } +static int rmnet_stats_reset(struct net_device *dev) +{ + struct rmnet_priv *priv = netdev_priv(dev); + struct rmnet_port_priv_stats *stp; + struct rmnet_port *port; + + port = rmnet_get_port(priv->real_dev); + if (!port) + return -EINVAL; + + stp = &port->stats; + + memset(stp, 0, sizeof(*stp)); + return 0; +} + static const struct ethtool_ops rmnet_ethtool_ops = { .get_ethtool_stats = rmnet_get_ethtool_stats, .get_strings = rmnet_get_strings, .get_sset_count = rmnet_get_sset_count, + .nway_reset = rmnet_stats_reset, }; /* Called by kernel whenever a new rmnet device is created. Sets MTU, -- GitLab From 42d6e15861469579b4948ce3351ef086cb1d5628 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Sun, 24 Jun 2018 16:49:56 +0530 Subject: [PATCH 0600/1001] clk: qcom: Add support for Video clock controller for SDMMAGPIE Add support for the video clock controller found on SDMMAGPIE based devices. This would allow video device drivers to probe and control their clocks and put across clock requests. Change-Id: Ie00d952e621fa62a8150259c40ea08ad4cb87290 Signed-off-by: Taniya Das --- .../bindings/clock/qcom,videocc.txt | 4 +- drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/videocc-sdmmagpie.c | 398 ++++++++++++++++++ .../clock/qcom,videocc-sdmmagpie.h | 32 +- 5 files changed, 422 insertions(+), 22 deletions(-) create mode 100644 drivers/clk/qcom/videocc-sdmmagpie.c diff --git a/Documentation/devicetree/bindings/clock/qcom,videocc.txt b/Documentation/devicetree/bindings/clock/qcom,videocc.txt index 1c7dfcd90270..38dd889acdef 100644 --- a/Documentation/devicetree/bindings/clock/qcom,videocc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,videocc.txt @@ -2,10 +2,10 @@ Qualcomm Technologies, Inc. Video Clock & Reset Controller Bindings Required properties: - compatible: shall contain "qcom,videocc-sm8150" or "qcom,videocc-sm8150-v2" or - "qcom,videocc-sm6150". + "qcom,videocc-sm6150", "qcom,videocc-sdmmagpie". - reg: shall contain base register location and length. - reg-names: names of registers listed in the same order as in the reg property. -- vdd_mm-supply: the logic rail supply. +- vdd_-supply: the logic rail supply which could be either MM or CX. - clock-names: Shall contain "cfg_ahb_clk" - clocks: phandle + clock reference to the GCC AHB clock. - #clock-cells: shall contain 1. diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index c9b13710c6c3..5932ad41af19 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -405,3 +405,12 @@ config MSM_GCC_SDMMAGPIE SDMMAGPIE devices. Say Y if you want to use peripheral devices such as UART, SPI, I2C, USB, UFS, SD/eMMC, PCIe, etc. + +config MSM_VIDEOCC_SDMMAGPIE + tristate "SDMMAGPIE Video Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the video clock controller on Qualcomm Technologies, Inc. + SDMMAGPIE devices. + Say Y if you want to support video devices and functionality such as + video encode/decode. diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 236935ff66d9..df36e77f22a2 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o obj-$(CONFIG_MSM_NPUCC_SM8150) += npucc-sm8150.o +obj-$(CONFIG_MSM_VIDEOCC_SDMMAGPIE) += videocc-sdmmagpie.o obj-$(CONFIG_MSM_VIDEOCC_SM6150) += videocc-sm6150.o obj-$(CONFIG_MSM_VIDEOCC_SM8150) += videocc-sm8150.o obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o diff --git a/drivers/clk/qcom/videocc-sdmmagpie.c b/drivers/clk/qcom/videocc-sdmmagpie.c new file mode 100644 index 000000000000..d38c6e4335c8 --- /dev/null +++ b/drivers/clk/qcom/videocc-sdmmagpie.c @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-branch.h" +#include "clk-alpha-pll.h" +#include "vdd-level.h" + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + +static DEFINE_VDD_REGULATORS(vdd_cx, VDD_NUM, 1, vdd_corner); + +enum { + P_BI_TCXO, + P_CORE_BI_PLL_TEST_SE, + P_VIDEO_PLL0_OUT_EVEN, + P_VIDEO_PLL0_OUT_MAIN, + P_VIDEO_PLL0_OUT_ODD, +}; + +static const struct parent_map video_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_VIDEO_PLL0_OUT_MAIN, 1 }, + { P_VIDEO_PLL0_OUT_EVEN, 2 }, + { P_VIDEO_PLL0_OUT_ODD, 3 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const video_cc_parent_names_0[] = { + "bi_tcxo", + "video_pll0", + "video_pll0_out_even", + "video_pll0_out_odd", + "core_bi_pll_test_se", +}; + +static const struct parent_map video_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const video_cc_parent_names_2[] = { + "bi_tcxo", + "core_bi_pll_test_se", +}; + +static struct pll_vco fabia_vco[] = { + { 249600000, 2000000000, 0 }, + { 125000000, 1000000000, 1 }, +}; + +static const struct alpha_pll_config video_pll0_config = { + .l = 0x19, + .frac = 0x0, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002067, + .user_ctl_val = 0x00000001, + .user_ctl_hi_val = 0x00004805, + .test_ctl_hi_val = 0x40000000, +}; + +static struct clk_alpha_pll video_pll0 = { + .offset = 0x42c, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "video_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_pll_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 615000000, + [VDD_LOW] = 1066000000, + [VDD_LOW_L1] = 1600000000, + [VDD_NOMINAL] = 2000000000}, + }, + }, +}; + +static const struct freq_tbl ftbl_video_cc_iris_clk_src[] = { + F(240000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + F(338000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + F(365000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + F(444000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + F(533000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 video_cc_iris_clk_src = { + .cmd_rcgr = 0x7f0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = video_cc_parent_map_0, + .freq_tbl = ftbl_video_cc_iris_clk_src, + .enable_safe_config = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "video_cc_iris_clk_src", + .parent_names = video_cc_parent_names_0, + .num_parents = 5, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 240000000, + [VDD_LOW] = 338000000, + [VDD_LOW_L1] = 365000000, + [VDD_NOMINAL] = 444000000, + [VDD_HIGH] = 533000000}, + }, +}; + +static const struct freq_tbl ftbl_video_cc_xo_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 video_cc_xo_clk_src = { + .cmd_rcgr = 0xa98, + .mnd_width = 0, + .hid_width = 5, + .parent_map = video_cc_parent_map_2, + .freq_tbl = ftbl_video_cc_xo_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "video_cc_xo_clk_src", + .parent_names = video_cc_parent_names_2, + .num_parents = 2, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 19200000}, + }, +}; + +static struct clk_branch video_cc_iris_ahb_clk = { + .halt_reg = 0x8f4, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x8f4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "video_cc_iris_ahb_clk", + .parent_names = (const char *[]){ + "video_cc_iris_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_mvs0_axi_clk = { + .halt_reg = 0x9ec, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9ec, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "video_cc_mvs0_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_mvs0_core_clk = { + .halt_reg = 0x890, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x890, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "video_cc_mvs0_core_clk", + .parent_names = (const char *[]){ + "video_cc_iris_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_mvs1_axi_clk = { + .halt_reg = 0xa0c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa0c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "video_cc_mvs1_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_mvs1_core_clk = { + .halt_reg = 0x8d0, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x8d0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "video_cc_mvs1_core_clk", + .parent_names = (const char *[]){ + "video_cc_iris_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_mvsc_core_clk = { + .halt_reg = 0x850, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x850, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "video_cc_mvsc_core_clk", + .parent_names = (const char *[]){ + "video_cc_iris_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_mvsc_ctl_axi_clk = { + .halt_reg = 0x9cc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9cc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "video_cc_mvsc_ctl_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_venus_ahb_clk = { + .halt_reg = 0xa6c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa6c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "video_cc_venus_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_xo_clk = { + .halt_reg = 0x984, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x984, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "video_cc_xo_clk", + .parent_names = (const char *[]){ + "video_cc_xo_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *video_cc_sdmmagpie_clocks[] = { + [VIDEO_PLL0] = &video_pll0.clkr, + [VIDEO_CC_IRIS_AHB_CLK] = &video_cc_iris_ahb_clk.clkr, + [VIDEO_CC_IRIS_CLK_SRC] = &video_cc_iris_clk_src.clkr, + [VIDEO_CC_MVS0_AXI_CLK] = &video_cc_mvs0_axi_clk.clkr, + [VIDEO_CC_MVS0_CORE_CLK] = &video_cc_mvs0_core_clk.clkr, + [VIDEO_CC_MVS1_AXI_CLK] = &video_cc_mvs1_axi_clk.clkr, + [VIDEO_CC_MVS1_CORE_CLK] = &video_cc_mvs1_core_clk.clkr, + [VIDEO_CC_MVSC_CORE_CLK] = &video_cc_mvsc_core_clk.clkr, + [VIDEO_CC_MVSC_CTL_AXI_CLK] = &video_cc_mvsc_ctl_axi_clk.clkr, + [VIDEO_CC_VENUS_AHB_CLK] = &video_cc_venus_ahb_clk.clkr, + [VIDEO_CC_XO_CLK] = &video_cc_xo_clk.clkr, + [VIDEO_CC_XO_CLK_SRC] = &video_cc_xo_clk_src.clkr, +}; + +static const struct regmap_config video_cc_sdmmagpie_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xb94, + .fast_io = true, +}; + +static const struct qcom_cc_desc video_cc_sdmmagpie_desc = { + .config = &video_cc_sdmmagpie_regmap_config, + .clks = video_cc_sdmmagpie_clocks, + .num_clks = ARRAY_SIZE(video_cc_sdmmagpie_clocks), +}; + +static const struct of_device_id video_cc_sdmmagpie_match_table[] = { + { .compatible = "qcom,videocc-sdmmagpie" }, + { } +}; +MODULE_DEVICE_TABLE(of, video_cc_sdmmagpie_match_table); + +static int video_cc_sdmmagpie_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx"); + if (IS_ERR(vdd_cx.regulator[0])) { + if (PTR_ERR(vdd_cx.regulator[0]) != -EPROBE_DEFER) + dev_err(&pdev->dev, + "Unable to get vdd_cx regulator\n"); + return PTR_ERR(vdd_cx.regulator[0]); + } + + regmap = qcom_cc_map(pdev, &video_cc_sdmmagpie_desc); + if (IS_ERR(regmap)) { + pr_err("Failed to map the video_cc registers\n"); + return PTR_ERR(regmap); + } + + clk_fabia_pll_configure(&video_pll0, regmap, &video_pll0_config); + + ret = qcom_cc_really_probe(pdev, &video_cc_sdmmagpie_desc, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to register Video CC clocks\n"); + return ret; + } + + dev_info(&pdev->dev, "Registered Video CC clocks\n"); + return ret; +} + +static struct platform_driver video_cc_sdmmagpie_driver = { + .probe = video_cc_sdmmagpie_probe, + .driver = { + .name = "video_cc-sdmmagpie", + .of_match_table = video_cc_sdmmagpie_match_table, + }, +}; + +static int __init video_cc_sdmmagpie_init(void) +{ + return platform_driver_register(&video_cc_sdmmagpie_driver); +} +subsys_initcall(video_cc_sdmmagpie_init); + +static void __exit video_cc_sdmmagpie_exit(void) +{ + platform_driver_unregister(&video_cc_sdmmagpie_driver); +} +module_exit(video_cc_sdmmagpie_exit); + +MODULE_DESCRIPTION("QTI VIDEO_CC SDMMAGPIE Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:video_cc-sdmmagpie"); diff --git a/include/dt-bindings/clock/qcom,videocc-sdmmagpie.h b/include/dt-bindings/clock/qcom,videocc-sdmmagpie.h index de287ee7e8ee..2ecc097c6e65 100644 --- a/include/dt-bindings/clock/qcom,videocc-sdmmagpie.h +++ b/include/dt-bindings/clock/qcom,videocc-sdmmagpie.h @@ -14,25 +14,17 @@ #ifndef _DT_BINDINGS_CLK_QCOM_VIDEO_CC_SDMMAGPIE_H #define _DT_BINDINGS_CLK_QCOM_VIDEO_CC_SDMMAGPIE_H -#define VIDEO_CC_APB_CLK 0 -#define VIDEO_CC_AT_CLK 1 -#define VIDEO_CC_IRIS_AHB_CLK 3 -#define VIDEO_CC_IRIS_CLK_SRC 4 -#define VIDEO_CC_MVS0_AXI_CLK 5 -#define VIDEO_CC_MVS0_CORE_CLK 6 -#define VIDEO_CC_MVS1_AXI_CLK 7 -#define VIDEO_CC_MVS1_CORE_CLK 8 -#define VIDEO_CC_MVSC_CORE_CLK 9 -#define VIDEO_CC_MVSC_CTL_AXI_CLK 10 -#define VIDEO_CC_SLEEP_CLK 13 -#define VIDEO_CC_SLEEP_CLK_SRC 14 -#define VIDEO_CC_VENUS_AHB_CLK 15 -#define VIDEO_CC_XO_CLK 16 -#define VIDEO_CC_XO_CLK_SRC 17 -#define VIDEO_PLL0 18 - -#define MVS0_GDSC 0 -#define MVS1_GDSC 1 -#define MVSC_GDSC 2 +#define VIDEO_PLL0 0 +#define VIDEO_CC_IRIS_AHB_CLK 1 +#define VIDEO_CC_IRIS_CLK_SRC 2 +#define VIDEO_CC_MVS0_AXI_CLK 3 +#define VIDEO_CC_MVS0_CORE_CLK 4 +#define VIDEO_CC_MVS1_AXI_CLK 5 +#define VIDEO_CC_MVS1_CORE_CLK 6 +#define VIDEO_CC_MVSC_CORE_CLK 7 +#define VIDEO_CC_MVSC_CTL_AXI_CLK 8 +#define VIDEO_CC_VENUS_AHB_CLK 9 +#define VIDEO_CC_XO_CLK 10 +#define VIDEO_CC_XO_CLK_SRC 11 #endif -- GitLab From 7ac86e334947efa4d0da028c5f672fdeb35351dc Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Wed, 1 Aug 2018 17:05:57 -0700 Subject: [PATCH 0601/1001] power: smb5-lib: Add liquid presence detection function Add liquid presence detection function based on SBUx resistance. Read resistance from ADC channel ADC_SBUx for both SBU1 and SBU2 by selecting current source. Liquid is present if either reading is below a given threshold. Change-Id: I21682c68c9a68cad6880c391f75c1cec7dbe69c8 Signed-off-by: Harry Yang --- drivers/power/supply/qcom/smb5-lib.c | 67 ++++++++++++++++++++++++++++ drivers/power/supply/qcom/smb5-reg.h | 8 ++++ 2 files changed, 75 insertions(+) diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index a03d0c9f07a1..81ffc81bccee 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -2083,6 +2083,73 @@ int smblib_get_prop_usb_voltage_now(struct smb_charger *chg, return ret; } +bool smblib_rsbux_low(struct smb_charger *chg, int r_thr) +{ + int r_sbu1, r_sbu2; + bool ret = false; + int rc; + + if (!chg->iio.sbux_chan) + return false; + + /* disable crude sensors */ + rc = smblib_masked_write(chg, TYPE_C_CRUDE_SENSOR_CFG_REG, + EN_SRC_CRUDE_SENSOR_BIT | EN_SNK_CRUDE_SENSOR_BIT, + 0); + if (rc < 0) { + smblib_err(chg, "Couldn't disable crude sensor rc=%d\n", rc); + return false; + } + + /* select SBU1 as current source */ + rc = smblib_write(chg, TYPE_C_SBU_CFG_REG, SEL_SBU1_ISRC_VAL); + if (rc < 0) { + smblib_err(chg, "Couldn't select SBU1 rc=%d\n", rc); + goto cleanup; + } + + rc = iio_read_channel_processed(chg->iio.sbux_chan, &r_sbu1); + if (rc < 0) { + smblib_err(chg, "Couldn't read SBU1 rc=%d\n", rc); + goto cleanup; + } + + if (r_sbu1 < r_thr) { + ret = true; + goto cleanup; + } + + /* select SBU2 as current source */ + rc = smblib_write(chg, TYPE_C_SBU_CFG_REG, SEL_SBU2_ISRC_VAL); + if (rc < 0) { + smblib_err(chg, "Couldn't select SBU1 rc=%d\n", rc); + goto cleanup; + } + + rc = iio_read_channel_processed(chg->iio.sbux_chan, &r_sbu2); + if (rc < 0) { + smblib_err(chg, "Couldn't read SBU1 rc=%d\n", rc); + goto cleanup; + } + + if (r_sbu2 < r_thr) + ret = true; +cleanup: + /* enable crude sensors */ + rc = smblib_masked_write(chg, TYPE_C_CRUDE_SENSOR_CFG_REG, + EN_SRC_CRUDE_SENSOR_BIT | EN_SNK_CRUDE_SENSOR_BIT, + EN_SRC_CRUDE_SENSOR_BIT | EN_SNK_CRUDE_SENSOR_BIT); + if (rc < 0) + smblib_err(chg, "Couldn't enable crude sensor rc=%d\n", rc); + + /* disable current source */ + rc = smblib_write(chg, TYPE_C_SBU_CFG_REG, 0); + if (rc < 0) + smblib_err(chg, "Couldn't select SBU1 rc=%d\n", rc); + + return ret; +} + int smblib_get_prop_charger_temp(struct smb_charger *chg, union power_supply_propval *val) { diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index 902396d14c33..04c797957a0e 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -336,6 +336,10 @@ enum { #define TYPEC_CCOUT_VALUE_BIT BIT(1) #define TYPEC_CCOUT_SRC_BIT BIT(0) +#define TYPE_C_CRUDE_SENSOR_CFG_REG (TYPEC_BASE + 0x4e) +#define EN_SRC_CRUDE_SENSOR_BIT BIT(1) +#define EN_SNK_CRUDE_SENSOR_BIT BIT(0) + #define TYPE_C_EXIT_STATE_CFG_REG (TYPEC_BASE + 0x50) #define BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT BIT(3) #define EXIT_SNK_BASED_ON_CC_BIT BIT(0) @@ -372,6 +376,10 @@ enum { #define TYPE_C_DEBOUNCE_OPTION_REG (TYPEC_BASE + 0x62) #define REDUCE_TCCDEBOUNCE_TO_2MS_BIT BIT(2) +#define TYPE_C_SBU_CFG_REG (TYPEC_BASE + 0x6A) +#define SEL_SBU1_ISRC_VAL 0x04 +#define SEL_SBU2_ISRC_VAL 0x01 + #define TYPEC_U_USB_CFG_REG (TYPEC_BASE + 0x70) #define EN_MICRO_USB_MODE_BIT BIT(0) -- GitLab From 94e06df5daabbf4ddb15bb35740d3a5d57fb08e7 Mon Sep 17 00:00:00 2001 From: Amit Nischal Date: Thu, 5 Jul 2018 11:21:53 +0530 Subject: [PATCH 0602/1001] ARM: dts: msm: Update the gcc and video clock nodes for SDMMAGPIE Update the GCC and VIDEOCC clock controller device nodes to register to actual clock controller drivers. Also update the GCC and VIDEOCC GDSCs by replacing the dummy nodes with actual GDSC regulator driver. Change-Id: Ie707e4cee199e11c2fde2c0e28ee4b18ab80a4dd Signed-off-by: Amit Nischal --- arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi | 28 ++++++++++---------- arch/arm64/boot/dts/qcom/sdmmagpie.dtsi | 17 +++++++----- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi index 7a7053222d1f..ad367a28b2ad 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi @@ -14,7 +14,7 @@ &soc { /* GDSCs in Global CC */ pcie_0_gdsc: qcom,gdsc@16b004 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "pcie_0_gdsc"; reg = <0x16b004 0x4>; qcom,poll-cfg-gdscr; @@ -22,7 +22,7 @@ }; pcie_tbu_gdsc: qcom,gdsc@128004 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "pcie_tbu_gdsc"; reg = <0x128004 0x4>; qcom,poll-cfg-gdscr; @@ -30,7 +30,7 @@ }; ufs_phy_gdsc: qcom,gdsc@177004 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "ufs_phy_gdsc"; reg = <0x177004 0x4>; qcom,poll-cfg-gdscr; @@ -38,7 +38,7 @@ }; usb30_prim_gdsc: qcom,gdsc@10f004 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "usb30_prim_gdsc"; reg = <0x10f004 0x4>; qcom,poll-cfg-gdscr; @@ -46,7 +46,7 @@ }; hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc: qcom,gdsc@17d030 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc"; reg = <0x17d030 0x4>; qcom,no-status-check-on-disable; @@ -55,7 +55,7 @@ }; hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc: qcom,gdsc@17d03c { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc"; reg = <0x17d03c 0x4>; qcom,no-status-check-on-disable; @@ -64,7 +64,7 @@ }; hlos1_vote_aggre_noc_mmu_tbu1_gdsc: qcom,gdsc@17d034 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "hlos1_vote_aggre_noc_mmu_tbu1_gdsc"; reg = <0x17d034 0x4>; qcom,no-status-check-on-disable; @@ -73,7 +73,7 @@ }; hlos1_vote_aggre_noc_mmu_tbu2_gdsc: qcom,gdsc@17d038 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "hlos1_vote_aggre_noc_mmu_tbu2_gdsc"; reg = <0x17d038 0x4>; qcom,no-status-check-on-disable; @@ -82,7 +82,7 @@ }; hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc: qcom,gdsc@17d040 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc"; reg = <0x17d040 0x4>; qcom,no-status-check-on-disable; @@ -91,7 +91,7 @@ }; hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc: qcom,gdsc@17d048 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc"; reg = <0x17d048 0x4>; qcom,no-status-check-on-disable; @@ -100,7 +100,7 @@ }; hlos1_vote_mmnoc_mmu_tbu_sf_gdsc: qcom,gdsc@17d044 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "hlos1_vote_mmnoc_mmu_tbu_sf_gdsc"; reg = <0x17d044 0x4>; qcom,no-status-check-on-disable; @@ -196,21 +196,21 @@ /* GDSCs in Video CC */ mvsc_gdsc: qcom,gdsc@0b00814 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "mvsc_gdsc"; reg = <0xab00814 0x4>; status = "disabled"; }; mvs0_gdsc: qcom,gdsc@ab00874 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "mvs0_gdsc"; reg = <0xab00874 0x4>; status = "disabled"; }; mvs1_gdsc: qcom,gdsc@ab008b4 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "mvs1_gdsc"; reg = <0xab008b4 0x4>; status = "disabled"; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index b56beacea724..bd56ac97bac0 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -643,9 +643,12 @@ mbox-names = "qdss_clk"; }; - clock_gcc: qcom,gcc { - compatible = "qcom,dummycc"; - clock-output-names = "gcc_clocks"; + clock_gcc: qcom,gcc@100000 { + compatible = "qcom,gcc-sdmmagpie", "syscon"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_cx_ao-supply = <&VDD_CX_LEVEL_AO>; + reg = <0x100000 0x1f0000>; + reg-names = "cc_base"; #clock-cells = <1>; #reset-cells = <1>; }; @@ -664,9 +667,11 @@ #reset-cells = <1>; }; - clock_videocc: qcom,videocc { - compatible = "qcom,dummycc"; - clock-output-names = "videocc_clocks"; + clock_videocc: qcom,videocc@ab00000 { + compatible = "qcom,videocc-sdmmagpie", "syscon"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + reg = <0xab00000 0x10000>; + reg-names = "cc_base"; #clock-cells = <1>; #reset-cells = <1>; }; -- GitLab From 4b7d7ed61a3444258d241c75576e93c73a3f2e45 Mon Sep 17 00:00:00 2001 From: Amit Nischal Date: Tue, 7 Aug 2018 10:53:57 +0530 Subject: [PATCH 0603/1001] defconfig: Enable GCC and VIDEOCC drivers for SDMMAGPIE Enable global and video clock controller drivers for SDMMAGPIE. Change-Id: Ibd0d1e816b32e6fecfb0c25971b7c93dc12d9ba3 Signed-off-by: Amit Nischal --- arch/arm64/configs/vendor/sdmsteppe-perf_defconfig | 2 ++ arch/arm64/configs/vendor/sdmsteppe_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig index afcb03ddfed3..7f4383065f05 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig @@ -472,6 +472,8 @@ CONFIG_MSM_VIDEOCC_SM6150=y CONFIG_MSM_DEBUGCC_SM6150=y CONFIG_MSM_CAMCC_SM6150=y CONFIG_MSM_DISPCC_SM6150=y +CONFIG_MSM_GCC_SDMMAGPIE=y +CONFIG_MSM_VIDEOCC_SDMMAGPIE=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_QCOM_APCS_IPC=y diff --git a/arch/arm64/configs/vendor/sdmsteppe_defconfig b/arch/arm64/configs/vendor/sdmsteppe_defconfig index 04247ca6e677..0b120ba645fe 100644 --- a/arch/arm64/configs/vendor/sdmsteppe_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe_defconfig @@ -489,6 +489,8 @@ CONFIG_MSM_VIDEOCC_SM6150=y CONFIG_MSM_DEBUGCC_SM6150=y CONFIG_MSM_CAMCC_SM6150=y CONFIG_MSM_DISPCC_SM6150=y +CONFIG_MSM_GCC_SDMMAGPIE=y +CONFIG_MSM_VIDEOCC_SDMMAGPIE=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_QCOM_APCS_IPC=y -- GitLab From bbf04994e277ea729778ef6f009b236be58b04b4 Mon Sep 17 00:00:00 2001 From: Umang Agrawal Date: Tue, 17 Jul 2018 12:53:59 +0530 Subject: [PATCH 0604/1001] ARM: dts: msm: Add SMB1390 and SMB1355 support to SM6150 Add SMB1390 charger pump and SMB1355 slave charger support to SM6150 IDP and QRD platform. Change-Id: I095e23b16e84de848ec71e3524773a6970808a9d Signed-off-by: Umang Agrawal --- arch/arm64/boot/dts/qcom/sm6150-idp.dtsi | 31 ++++++++++++++++++++ arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi | 13 ++++++++ arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi | 21 +++++++++++++ 3 files changed, 65 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi index 1467f00847a6..0289ffda6dad 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi @@ -12,6 +12,12 @@ #include +&qupv3_se3_i2c { + status = "ok"; + #include "smb1390.dtsi" + #include "smb1355.dtsi" +}; + &soc { }; @@ -113,4 +119,29 @@ qcom,battery-data = <&mtp_batterydata>; qcom,step-charging-enable; qcom,sw-jeita-enable; + qcom,sec-charger-config = <3>; +}; + +&smb1390 { + /delete-property/ interrupts; + interrupts = <0x0 0xc2 0x0 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&smb_stat_default>; + status = "ok"; +}; + +&smb1390_charger { + io-channels = <&pm6150_vadc ADC_AMUX_THM3>; + io-channel-names = "cp_die_temp"; + status = "ok"; +}; + +&smb1355 { + /delete-property/ interrupts; + interrupts = <0x0 0xc2 0x0 IRQ_TYPE_LEVEL_LOW>; + status = "ok"; +}; + +&smb1355_charger { + status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi index dc916bb2c432..877c3a4517d7 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi @@ -10,6 +10,8 @@ * GNU General Public License for more details. */ +#include + &soc { tlmm: pinctrl@03000000 { compatible = "qcom,sm6150-pinctrl"; @@ -866,4 +868,15 @@ output-low; }; }; + + smb_stat { + smb_stat_default: smb_stat_default { + pins = "gpio3"; + function = "normal"; + input-enable; + bias-pull-up; + qcom,pull-up-strength = ; + power-source = <0>; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi index 17710610b9d1..d981b1aafda9 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi @@ -13,6 +13,12 @@ #include "sm6150-thermal-overlay.dtsi" #include +&qupv3_se3_i2c { + status = "ok"; + #include "smb1390.dtsi" + #include "smb1355.dtsi" +}; + &soc { }; @@ -65,4 +71,19 @@ qcom,battery-data = <&mtp_batterydata>; qcom,step-charging-enable; qcom,sw-jeita-enable; + qcom,sec-charger-config = <1>; +}; + +&smb1390 { + /delete-property/ interrupts; + interrupts = <0x0 0xc2 0x0 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&smb_stat_default>; + status = "ok"; +}; + +&smb1390_charger { + io-channels = <&pm6150_vadc ADC_AMUX_THM3>; + io-channel-names = "cp_die_temp"; + status = "ok"; }; -- GitLab From 2cbb1907ef030092db6bd4112eb5e1b6a9803cc7 Mon Sep 17 00:00:00 2001 From: Arun KS Date: Thu, 9 Aug 2018 10:43:55 +0530 Subject: [PATCH 0605/1001] ARM: dts: msm: Add device tree for sa6155 and sa6155p Add initial device tree support for APQ and MSM version of SA6155 based automotive platforms. Change-Id: Icbf08e920b9ee755b91e5318a82f23a8b68b47a8 Signed-off-by: Arun KS --- .../devicetree/bindings/arm/msm/msm.txt | 3 +++ arch/arm64/boot/dts/qcom/Makefile | 11 ++++++-- .../boot/dts/qcom/sa6155-adp-star-overlay.dts | 25 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sa6155-adp-star.dts | 21 ++++++++++++++++ arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi | 23 +++++++++++++++++ arch/arm64/boot/dts/qcom/sa6155.dts | 21 ++++++++++++++++ arch/arm64/boot/dts/qcom/sa6155.dtsi | 20 +++++++++++++++ .../dts/qcom/sa6155p-adp-star-overlay.dts | 25 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sa6155p-adp-star.dts | 22 ++++++++++++++++ arch/arm64/boot/dts/qcom/sa6155p.dts | 21 ++++++++++++++++ arch/arm64/boot/dts/qcom/sa6155p.dtsi | 19 ++++++++++++++ 11 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/sa6155-adp-star-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sa6155-adp-star.dts create mode 100644 arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sa6155.dts create mode 100644 arch/arm64/boot/dts/qcom/sa6155.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sa6155p-adp-star-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sa6155p-adp-star.dts create mode 100644 arch/arm64/boot/dts/qcom/sa6155p.dts create mode 100644 arch/arm64/boot/dts/qcom/sa6155p.dtsi diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index 68dde5605044..f0e27cad2427 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -163,6 +163,9 @@ compatible = "qcom,sm6150-idp" compatible = "qcom,sm6150p-idp" compatible = "qcom,sm6150p" compatible = "qcom,sm6150p-qrd" +compatible = "qcom,sa6155-adp-star" +compatible = "qcom,sa6155p-adp-star" +compatible = "qcom,sa6155p" compatible = "qcom,qcs405-rumi" compatible = "qcom,qcs405-iot" compatible = "qcom,qcs403-iot" diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 2987cc075111..b1b5fcacab79 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -85,7 +85,9 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) sm6150p-qrd-overlay.dtbo \ sm6150p-idp-overlay.dtbo \ sm6150-external-codec-idp-overlay.dtbo \ - sm6150-usbc-idp-overlay.dtbo + sm6150-usbc-idp-overlay.dtbo \ + sa6155-adp-star-overlay.dtbo \ + sa6155p-adp-star-overlay.dtbo sm6150-rumi-overlay.dtbo-base := sm6150.dtb sm6150-qrd-overlay.dtbo-base := sm6150.dtb @@ -94,6 +96,8 @@ sm6150p-qrd-overlay.dtbo-base := sm6150p.dtb sm6150p-idp-overlay.dtbo-base := sm6150p.dtb sm6150-external-codec-idp-overlay.dtbo-base := sm6150.dtb sm6150-usbc-idp-overlay.dtbo-base := sm6150.dtb +sa6155-adp-star-overlay.dtbo-base := sa6155.dtb +sa6155p-adp-star-overlay.dtbo-base := sa6155p.dtb else dtb-$(CONFIG_ARCH_SM6150) += sm6150-rumi.dtb \ sm6150-qrd.dtb \ @@ -101,7 +105,10 @@ dtb-$(CONFIG_ARCH_SM6150) += sm6150-rumi.dtb \ sm6150p-qrd.dtb \ sm6150p-idp.dtb \ sm6150-external-codec-idp.dtb \ - sm6150-usbc-idp.dtb + sm6150-usbc-idp.dtb \ + sa6155-adp-star.dtb \ + sa6155p-adp-star.dtb + endif ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) diff --git a/arch/arm64/boot/dts/qcom/sa6155-adp-star-overlay.dts b/arch/arm64/boot/dts/qcom/sa6155-adp-star-overlay.dts new file mode 100644 index 000000000000..3593457e63d7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155-adp-star-overlay.dts @@ -0,0 +1,25 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "sa6155-adp-star.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA6155 ADP-STAR"; + compatible = "qcom,sa6155-adp-star", "qcom,sa6155", "qcom,adp-star"; + qcom,msm-id = <384 0x0>; + qcom,board-id = <25 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155-adp-star.dts b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dts new file mode 100644 index 000000000000..1cea61aa7024 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dts @@ -0,0 +1,21 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +#include "sa6155.dtsi" +#include "sa6155-adp-star.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA6155 ADP-STAR"; + compatible = "qcom,sa6155-adp-star", "qcom,sa6155", "qcom,adp-star"; + qcom,board-id = <25 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi new file mode 100644 index 000000000000..bed9204466fa --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi @@ -0,0 +1,23 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + qcom,lpass@62400000 { + status = "disabled"; + }; + + qcom,glink { + modem { + status = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155.dts b/arch/arm64/boot/dts/qcom/sa6155.dts new file mode 100644 index 000000000000..0494f3f96a36 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155.dts @@ -0,0 +1,21 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sa6155.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA6155 SoC"; + compatible = "qcom,sa6155"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155.dtsi b/arch/arm64/boot/dts/qcom/sa6155.dtsi new file mode 100644 index 000000000000..0c7d23ff5047 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155.dtsi @@ -0,0 +1,20 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sm6150.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA6155"; + compatible = "qcom,sa6155"; + qcom,msm-name = "SA6155"; + qcom,msm-id = <384 0x10000>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155p-adp-star-overlay.dts b/arch/arm64/boot/dts/qcom/sa6155p-adp-star-overlay.dts new file mode 100644 index 000000000000..ba038632f1e8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155p-adp-star-overlay.dts @@ -0,0 +1,25 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "sa6155-adp-star.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA6155P ADP-STAR"; + compatible = "qcom,sa6155p-adp-star", "qcom,sa6155p", "qcom,adp-star"; + qcom,msm-id = <377 0x0>; + qcom,board-id = <25 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155p-adp-star.dts b/arch/arm64/boot/dts/qcom/sa6155p-adp-star.dts new file mode 100644 index 000000000000..3ff625aa2bfb --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155p-adp-star.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sa6155p.dtsi" +#include "sa6155-adp-star.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA6155P ADP-STAR"; + compatible = "qcom,sa6155p-adp-star", "qcom,sa6155p", "qcom,adp-star"; + qcom,board-id = <25 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155p.dts b/arch/arm64/boot/dts/qcom/sa6155p.dts new file mode 100644 index 000000000000..371125467fd6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155p.dts @@ -0,0 +1,21 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sa6155p.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA6155P SoC"; + compatible = "qcom,sa6155p"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155p.dtsi b/arch/arm64/boot/dts/qcom/sa6155p.dtsi new file mode 100644 index 000000000000..83c0783cd5ca --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155p.dtsi @@ -0,0 +1,19 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sm6150.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA6155P"; + qcom,msm-name = "SA6155P"; + qcom,msm-id = <377 0>; +}; -- GitLab From a94c8b3986ec032bf4bd074b72b7397f62d10f52 Mon Sep 17 00:00:00 2001 From: Veerabhadrarao Badiganti Date: Mon, 13 Nov 2017 20:27:36 +0530 Subject: [PATCH 0606/1001] mmc: core: Return card status if sdr104_wa is not present On the targets in which sdr104 workaround is not needed, simply return card status from mmc_recovery_fallback_lower_speed() call. If any platform uses the tray for SD card, then even if the tray is inserted without sd card, card-detect gpio pulled low. And in card removal detection path we end-up in calling mmc_recovery_fallback_lower_speed(). If we don't return error or card status it may treat errors are due to CRC errors and try to fall-back to lower speed mode instead of marking the card as removed. Change-Id: I83a41c44f5b031663733d7ffa226c1feaa5c9203 Signed-off-by: Veerabhadrarao Badiganti --- drivers/mmc/core/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index e3b3c9164d07..d937363cfb4a 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -468,6 +468,9 @@ int mmc_recovery_fallback_lower_speed(struct mmc_host *host) mmc_host_clear_sdr104(host); err = mmc_hw_reset(host); host->card->sdr104_blocked = true; + } else { + /* If sdr104_wa is not present, just return status */ + err = host->bus_ops->alive(host); } if (err) pr_err("%s: %s: Fallback to lower speed mode failed with err=%d\n", -- GitLab From 723226e4edcb9b60f88e010fa0e6e3c62219cdfe Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Thu, 9 Aug 2018 09:56:13 +0530 Subject: [PATCH 0607/1001] clk: qcom: debugcc-qcs405: Update post div mask for measure nodes Post div mask is not able to correctly set the post div value which results in wrong measure. Update the same to correctly measure the clocks. Change-Id: I5f6560d045919778bdc13e4d72c5f459b0f8210e Signed-off-by: Shefali Jain --- drivers/clk/qcom/debugcc-qcs405.c | 186 +++++++++++++++--------------- 1 file changed, 93 insertions(+), 93 deletions(-) diff --git a/drivers/clk/qcom/debugcc-qcs405.c b/drivers/clk/qcom/debugcc-qcs405.c index 3002ab99504e..783d948fd7e3 100644 --- a/drivers/clk/qcom/debugcc-qcs405.c +++ b/drivers/clk/qcom/debugcc-qcs405.c @@ -134,192 +134,192 @@ static struct clk_debug_mux gcc_debug_mux = { .cbcr_offset = 0x74000, .src_sel_mask = 0x1FF, .src_sel_shift = 0, - .post_div_mask = 0xF000, + .post_div_mask = 0xF, .post_div_shift = 12, .en_mask = BIT(16), MUX_SRC_LIST( { "snoc_clk", 0x000, 1, GCC, - 0x000, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x000, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "pnoc_clk", 0x008, 1, GCC, - 0x008, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, - { "bimc_clk", 0x15A, 1, GCC, - 0x15A, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x008, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, + { "bimc_clk", 0x15A, 4, GCC, + 0x15A, 0x1FF, 0, 0xF, 12, 4, 0x74000, 0x74000, 0x74000 }, { "qpic_clk", 0x0C0, 1, GCC, - 0x0C0, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x0C0, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "ce1_clk", 0x138, 1, GCC, - 0x138, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x138, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "wcnss_m_clk", 0x08A, 1, GCC, - 0x08A, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x08A, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_apss_ahb_clk", 0x168, 1, GCC, - 0x168, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x168, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_bimc_gfx_clk", 0x2D, 1, GCC, - 0x2D, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x2D, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_ahb_clk", 0x88, 1, GCC, - 0x88, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x88, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup0_i2c_apps_clk", 0x99, 1, GCC, - 0x99, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x99, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup0_spi_apps_clk", 0x98, 1, GCC, - 0x98, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x98, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup1_i2c_apps_clk", 0x8B, 1, GCC, - 0x8B, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x8B, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup1_spi_apps_clk", 0x8A, 1, GCC, - 0x8A, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x8A, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup2_i2c_apps_clk", 0x8F, 1, GCC, - 0x8F, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x8F, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup2_spi_apps_clk", 0x8E, 1, GCC, - 0x8E, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x8E, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup3_i2c_apps_clk", 0x93, 1, GCC, - 0x93, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x93, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup3_spi_apps_clk", 0x92, 1, GCC, - 0x92, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x92, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup4_i2c_apps_clk", 0x95, 1, GCC, - 0x95, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x95, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_qup4_spi_apps_clk", 0x94, 1, GCC, - 0x94, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x94, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_uart0_apps_clk", 0x9A, 1, GCC, - 0x9A, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x9A, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_uart1_apps_clk", 0x8C, 1, GCC, - 0x8C, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x8C, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_uart2_apps_clk", 0x90, 1, GCC, - 0x90, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x90, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp1_uart3_apps_clk", 0x96, 1, GCC, - 0x96, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x96, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp2_ahb_clk", 0xA0, 1, GCC, - 0xA0, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xA0, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp2_qup0_i2c_apps_clk", 0xA3, 1, GCC, - 0xA2, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xA2, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp2_qup0_spi_apps_clk", 0xA2, 1, GCC, - 0xA3, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xA3, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp2_uart0_apps_clk", 0xA4, 1, GCC, - 0xA4, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xA4, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_boot_rom_ahb_clk", 0xF8, 1, GCC, - 0xF8, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xF8, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_dcc_clk", 0x1B9, 1, GCC, - 0x1B9, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1B9, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_eth_axi_clk", 0x80, 1, GCC, - 0x80, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x80, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_eth_ptp_clk", 0x83, 1, GCC, - 0x83, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x83, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_eth_rgmii_clk", 0x81, 1, GCC, - 0x81, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x81, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_eth_slave_ahb_clk", 0x82, 1, GCC, - 0x82, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x82, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_geni_ir_s_clk", 0xEE, 1, GCC, - 0xEE, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xEE, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_gp1_clk", 0x10, 1, GCC, - 0x10, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x10, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_gp2_clk", 0x11, 1, GCC, - 0x11, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x11, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_gp3_clk", 0x12, 1, GCC, - 0x12, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x12, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_ahb_clk", 0x1F6, 1, GCC, - 0x1F6, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1F6, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_axi_clk", 0x1F7, 1, GCC, - 0x1F7, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1F7, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_byte0_clk", 0x1FC, 1, GCC, - 0x1FC, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1FC, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_esc0_clk", 0x1FD, 1, GCC, - 0x1FD, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1FD, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_hdmi_app_clk", 0x1F2, 1, GCC, - 0x1F2, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1F2, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_hdmi_pclk_clk", 0x1F1, 1, GCC, - 0x1F1, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1F1, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_mdp_clk", 0x1F9, 1, GCC, - 0x1F9, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1F9, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_pclk0_clk", 0x1F8, 1, GCC, - 0x1F8, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1F8, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_vsync_clk", 0x1FB, 1, GCC, - 0x1FB, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1FB, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_oxili_ahb_clk", 0x1EB, 1, GCC, - 0x1EB, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1EB, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_oxili_gfx3d_clk", 0x1EA, 1, GCC, - 0x1EA, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1EA, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pcie_0_aux_clk", 0xAB, 1, GCC, - 0xAB, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xAB, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pcie_0_cfg_ahb_clk", 0xAA, 1, GCC, - 0xAA, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xAA, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pcie_0_mstr_axi_clk", 0xA9, 1, GCC, - 0xA9, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xA9, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pcie_0_pipe_clk", 0xAC, 1, GCC, - 0xAC, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xAC, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pcie_0_slv_axi_clk", 0xA8, 1, GCC, - 0xA8, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xA8, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pcnoc_usb2_clk", 0x9, 1, GCC, - 0x9, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x9, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pcnoc_usb3_clk", 0xA, 1, GCC, - 0xA, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xA, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pdm2_clk", 0xD2, 1, GCC, - 0xD2, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xD2, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pdm_ahb_clk", 0xD0, 1, GCC, - 0xD0, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xD0, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_prng_ahb_clk", 0xD8, 1, GCC, - 0xD8, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xD8, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pwm0_xo512_clk", 0xD3, 1, GCC, - 0xD3, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xD3, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pwm1_xo512_clk", 0xD4, 1, GCC, - 0xD4, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xD4, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_pwm2_xo512_clk", 0xD5, 1, GCC, - 0xD5, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xD5, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_sdcc1_ahb_clk", 0x69, 1, GCC, - 0x69, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x69, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_sdcc1_apps_clk", 0x68, 1, GCC, - 0x68, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x68, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_sdcc1_ice_core_clk", 0x6A, 1, GCC, - 0x6A, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x6A, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_sdcc2_ahb_clk", 0x71, 1, GCC, - 0x71, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x71, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_sdcc2_apps_clk", 0x70, 1, GCC, - 0x70, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x70, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_sys_noc_usb3_clk", 0x1, 1, GCC, - 0x1, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb20_mock_utmi_clk", 0x65, 1, GCC, - 0x65, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x65, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb2a_phy_sleep_clk", 0x63, 1, GCC, - 0x63, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x63, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb30_master_clk", 0x78, 1, GCC, - 0x78, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x78, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb30_mock_utmi_clk", 0x7A, 1, GCC, - 0x7A, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x7A, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb30_sleep_clk", 0x79, 1, GCC, - 0x79, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x79, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb3_phy_aux_clk", 0x7C, 1, GCC, - 0x7C, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x7C, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb3_phy_pipe_clk", 0x7B, 1, GCC, - 0x7B, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x7B, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb_hs_inactivity_timers_clk", 0x62, 1, GCC, - 0x62, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x62, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb_hs_phy_cfg_ahb_clk", 0x64, 1, GCC, - 0x64, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x64, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_usb_hs_system_clk", 0x60, 1, GCC, - 0x60, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x60, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_apss_tcu_clk", 0x159, 1, GCC, - 0x159, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x159, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_bimc_gpu_clk", 0x157, 1, GCC, - 0x157, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x157, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_bimc_mdss_clk", 0x15F, 1, GCC, - 0x15F, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x15F, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_crypto_ahb_clk", 0x13A, 1, GCC, - 0x13A, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x13A, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_crypto_axi_clk", 0x139, 1, GCC, - 0x139, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x139, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_crypto_clk", 0x138, 1, GCC, - 0x138, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x138, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_gfx_tbu_clk", 0x052, 1, GCC, - 0x052, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x052, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_gfx_tcu_clk", 0x053, 1, GCC, - 0x053, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x053, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_gtcu_ahb_clk", 0x058, 1, GCC, - 0x058, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x058, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdp_tbu_clk", 0x051, 1, GCC, - 0x051, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x051, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_qdss_dap_clk", 0x049, 1, GCC, - 0x049, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x049, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_smmu_cfg_clk", 0x05B, 1, GCC, - 0x049, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x049, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_geni_ir_h_clk", 0xEC, 1, GCC, - 0xEC, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0xEC, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_dcc_xo_clk", 0x1B8, 1, GCC, - 0x1B8, 0x1FF, 0, 0xF000, 12, 1, 0x74000, 0x74000, 0x74000 }, + 0x1B8, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "apcs_mux_clk", 0x16A, 1, CPU_CC, 0x000, 0x3, 8, 0xF, 11, 1, 0, 0, U32_MAX, 1 }, ), -- GitLab From 30064440acc4ba2d5959172821f967cb93f8683a Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Wed, 8 Aug 2018 13:58:05 +0530 Subject: [PATCH 0608/1001] clk: qcom: gcc: Add new frequency table for gcc_emac_ptp_clk_src The gcc_emac_ptp_clk_src is sharing frequency table with emac_clk_src and there is requirement to add new frequency level for emac_clk_src, so add the new frequency table for gcc_emac_ptp_clk_src. Change-Id: I7bfa8255d9e325fe65f0d164d01dfd08f2acab8d Signed-off-by: Shefali Jain --- drivers/clk/qcom/gcc-qcs405.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/clk/qcom/gcc-qcs405.c b/drivers/clk/qcom/gcc-qcs405.c index d656c595ae28..3f6c4328a7e0 100644 --- a/drivers/clk/qcom/gcc-qcs405.c +++ b/drivers/clk/qcom/gcc-qcs405.c @@ -873,12 +873,19 @@ static struct clk_rcg2 emac_clk_src = { }, }; +static const struct freq_tbl ftbl_emac_ptp_clk_src[] = { + F(50000000, P_GPLL1_OUT_MAIN, 10, 0, 0), + F(125000000, P_GPLL1_OUT_MAIN, 4, 0, 0), + F(250000000, P_GPLL1_OUT_MAIN, 2, 0, 0), + { } +}; + static struct clk_rcg2 emac_ptp_clk_src = { .cmd_rcgr = 0x4e014, .mnd_width = 0, .hid_width = 5, .parent_map = gcc_parent_map_4, - .freq_tbl = ftbl_emac_clk_src, + .freq_tbl = ftbl_emac_ptp_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "emac_ptp_clk_src", .parent_names = gcc_parent_names_4, -- GitLab From 544c788e679dffe08c58e2c13625ad7899b50798 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Mon, 25 Jun 2018 18:58:20 +0530 Subject: [PATCH 0609/1001] msm: ipa: Add WLAN FW SSR event Add WLAN FW SSR event to handle FW rejuvenate scenario. Change-Id: I417d46cc07f455792906a18f4b6dc8e5ca8ca3de Acked-by: Pooja Kumari Signed-off-by: Mohammed Javid --- drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c | 1 + include/uapi/linux/msm_ipa.h | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index e2be2bb72366..e339bfa624ce 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -75,6 +75,7 @@ const char *ipa3_event_name[] = { __stringify(IPA_PER_CLIENT_STATS_DISCONNECT_EVENT), __stringify(ADD_BRIDGE_VLAN_MAPPING), __stringify(DEL_BRIDGE_VLAN_MAPPING), + __stringify(WLAN_FWR_SSR_BEFORE_SHUTDOWN), }; const char *ipa3_hdr_l2_type_name[] = { diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index c7ca98a65db5..064567e45ae7 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -548,7 +548,13 @@ enum ipa_vlan_bridge_event { BRIDGE_VLAN_MAPPING_MAX }; -#define IPA_EVENT_MAX_NUM (BRIDGE_VLAN_MAPPING_MAX) +enum ipa_wlan_fw_ssr_event { + WLAN_FWR_SSR_BEFORE_SHUTDOWN = BRIDGE_VLAN_MAPPING_MAX, + IPA_WLAN_FW_SSR_EVENT_MAX +#define IPA_WLAN_FW_SSR_EVENT_MAX IPA_WLAN_FW_SSR_EVENT_MAX +}; + +#define IPA_EVENT_MAX_NUM (IPA_WLAN_FW_SSR_EVENT_MAX) #define IPA_EVENT_MAX ((int)IPA_EVENT_MAX_NUM) /** -- GitLab From 1dae55311427efadb3c4867addc2cd72da372b2b Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Wed, 8 Aug 2018 11:16:52 +0530 Subject: [PATCH 0610/1001] ARM: dts: msm: Update MX retention vote during VDD restriction for QCS405 Update MX retention vote during cold temperature condition for QCS405 based on latest recommendation. Change-Id: I3a69aea13aaf551192a51a85bd43df3319908bf9 Signed-off-by: Manaf Meethalavalappu Pallikunhi --- arch/arm64/boot/dts/qcom/qcs405-regulator.dtsi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcs405-regulator.dtsi b/arch/arm64/boot/dts/qcom/qcs405-regulator.dtsi index 89b2374a45d2..ca736f3c65dd 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-regulator.dtsi @@ -62,8 +62,7 @@ mx_cdev: mx-cdev-lvl { compatible = "qcom,regulator-cooling-device"; regulator-cdev-supply = <&pms405_s1_level>; - regulator-levels = - ; #cooling-cells = <2>; }; -- GitLab From 8755815ab51294dba38b4c0e41ec69412311e896 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Sun, 5 Aug 2018 10:06:31 +0300 Subject: [PATCH 0611/1001] wil6210: add TX latency statistics Collect statistics of TX latency. The latency is measured from the time the HW gets aware of new SKB to transmit until the HW indicates tx complete for this SKB. The statistics are shown via new "tx_latency" debugfs. Signed-off-by: Dedy Lansky Signed-off-by: Maya Erez Signed-off-by: Kalle Valo Git-commit: a24a3d6abb978d4abc25d541e787981e7ef555c8 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I0bd10d4b1a0b21eeded119bf5cf52e6c16e88515 Signed-off-by: Maya Erez --- drivers/net/wireless/ath/wil6210/debugfs.c | 125 +++++++++++++++++++ drivers/net/wireless/ath/wil6210/main.c | 1 + drivers/net/wireless/ath/wil6210/txrx.c | 38 ++++++ drivers/net/wireless/ath/wil6210/txrx.h | 2 + drivers/net/wireless/ath/wil6210/txrx_edma.c | 8 ++ drivers/net/wireless/ath/wil6210/wil6210.h | 14 +++ 6 files changed, 188 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index ed43d955a2b7..a1d48eec4093 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1840,6 +1840,126 @@ static const struct file_operations fops_mids = { .llseek = seq_lseek, }; +static int wil_tx_latency_debugfs_show(struct seq_file *s, void *data) +__acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) +{ + struct wil6210_priv *wil = s->private; + int i, bin; + + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { + struct wil_sta_info *p = &wil->sta[i]; + char *status = "unknown"; + u8 aid = 0; + u8 mid; + + if (!p->tx_latency_bins) + continue; + + switch (p->status) { + case wil_sta_unused: + status = "unused "; + break; + case wil_sta_conn_pending: + status = "pending "; + break; + case wil_sta_connected: + status = "connected"; + aid = p->aid; + break; + } + mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX; + seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status, + mid, aid); + + if (p->status == wil_sta_connected) { + u64 num_packets = 0; + u64 tx_latency_avg = p->stats.tx_latency_total_us; + + seq_puts(s, "Tx/Latency bin:"); + for (bin = 0; bin < WIL_NUM_LATENCY_BINS; bin++) { + seq_printf(s, " %lld", + p->tx_latency_bins[bin]); + num_packets += p->tx_latency_bins[bin]; + } + seq_puts(s, "\n"); + if (!num_packets) + continue; + do_div(tx_latency_avg, num_packets); + seq_printf(s, "Tx/Latency min/avg/max (us): %d/%lld/%d", + p->stats.tx_latency_min_us, + tx_latency_avg, + p->stats.tx_latency_max_us); + + seq_puts(s, "\n"); + } + } + + return 0; +} + +static int wil_tx_latency_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_tx_latency_debugfs_show, + inode->i_private); +} + +static ssize_t wil_tx_latency_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct wil6210_priv *wil = s->private; + int val, rc, i; + bool enable; + + rc = kstrtoint_from_user(buf, len, 0, &val); + if (rc) { + wil_err(wil, "Invalid argument\n"); + return rc; + } + if (val == 1) + /* default resolution */ + val = 500; + if (val && (val < 50 || val > 1000)) { + wil_err(wil, "Invalid resolution %d\n", val); + return -EINVAL; + } + + enable = !!val; + if (wil->tx_latency == enable) + return len; + + wil_info(wil, "%s TX latency measurements (resolution %dusec)\n", + enable ? "Enabling" : "Disabling", val); + + if (enable) { + size_t sz = sizeof(u64) * WIL_NUM_LATENCY_BINS; + + wil->tx_latency_res = val; + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { + struct wil_sta_info *sta = &wil->sta[i]; + + kfree(sta->tx_latency_bins); + sta->tx_latency_bins = kzalloc(sz, GFP_KERNEL); + if (!sta->tx_latency_bins) + return -ENOMEM; + sta->stats.tx_latency_min_us = U32_MAX; + sta->stats.tx_latency_max_us = 0; + sta->stats.tx_latency_total_us = 0; + } + } + wil->tx_latency = enable; + + return len; +} + +static const struct file_operations fops_tx_latency = { + .open = wil_tx_latency_seq_open, + .release = single_release, + .read = seq_read, + .write = wil_tx_latency_write, + .llseek = seq_lseek, +}; + static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -2174,6 +2294,7 @@ static const struct { {"srings", 0444, &fops_srings}, {"status_msg", 0444, &fops_status_msg}, {"rx_buff_mgmt", 0444, &fops_rx_buff_mgmt}, + {"tx_latency", 0644, &fops_tx_latency}, }; static void wil6210_debugfs_init_files(struct wil6210_priv *wil, @@ -2292,10 +2413,14 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) void wil6210_debugfs_remove(struct wil6210_priv *wil) { + int i; + debugfs_remove_recursive(wil->debug); wil->debug = NULL; kfree(wil->dbg_data.data_arr); + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) + kfree(wil->sta[i].tx_latency_bins); /* free pmc memory without sending command to fw, as it will * be reset on the way down anyway diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 30c42a7d5555..b40025be68a2 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -281,6 +281,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) } /* statistics */ memset(&sta->stats, 0, sizeof(sta->stats)); + sta->stats.tx_latency_min_us = U32_MAX; } static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index b6c0fb59258d..7020e5f48578 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1735,6 +1735,11 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct wil6210_vif *vif, */ wmb(); + if (wil->tx_latency) + *(ktime_t *)&skb->cb = ktime_get(); + else + memset(skb->cb, 0, sizeof(ktime_t)); + wil_w(wil, vring->hwtail, vring->swhead); return 0; @@ -1886,6 +1891,11 @@ static int __wil_tx_ring(struct wil6210_priv *wil, struct wil6210_vif *vif, */ wmb(); + if (wil->tx_latency) + *(ktime_t *)&skb->cb = ktime_get(); + else + memset(skb->cb, 0, sizeof(ktime_t)); + wil_w(wil, ring->hwtail, ring->swhead); return 0; @@ -2108,6 +2118,31 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) return NET_XMIT_DROP; } +void wil_tx_latency_calc(struct wil6210_priv *wil, struct sk_buff *skb, + struct wil_sta_info *sta) +{ + int skb_time_us; + int bin; + + if (!wil->tx_latency) + return; + + if (ktime_to_ms(*(ktime_t *)&skb->cb) == 0) + return; + + skb_time_us = ktime_us_delta(ktime_get(), *(ktime_t *)&skb->cb); + bin = skb_time_us / wil->tx_latency_res; + bin = min_t(int, bin, WIL_NUM_LATENCY_BINS - 1); + + wil_dbg_txrx(wil, "skb time %dus => bin %d\n", skb_time_us, bin); + sta->tx_latency_bins[bin]++; + sta->stats.tx_latency_total_us += skb_time_us; + if (skb_time_us < sta->stats.tx_latency_min_us) + sta->stats.tx_latency_min_us = skb_time_us; + if (skb_time_us > sta->stats.tx_latency_max_us) + sta->stats.tx_latency_max_us = skb_time_us; +} + /** * Clean up transmitted skb's from the Tx VRING * @@ -2194,6 +2229,9 @@ int wil_tx_complete(struct wil6210_vif *vif, int ringid) if (stats) { stats->tx_packets++; stats->tx_bytes += skb->len; + + wil_tx_latency_calc(wil, skb, + &wil->sta[cid]); } } else { ndev->stats.tx_errors++; diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index 3dfd7f916137..9d83be481839 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -620,5 +620,7 @@ void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, struct wil_tid_ampdu_rx *r); void wil_tx_data_init(struct wil_ring_tx_data *txdata); void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil); +void wil_tx_latency_calc(struct wil6210_priv *wil, struct sk_buff *skb, + struct wil_sta_info *sta); #endif /* WIL6210_TXRX_H */ diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index e9a1a50ee798..e44629f56b51 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.c +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -1230,6 +1230,9 @@ int wil_tx_sring_handler(struct wil6210_priv *wil, if (stats) { stats->tx_packets++; stats->tx_bytes += skb->len; + + wil_tx_latency_calc(wil, skb, + &wil->sta[cid]); } } else { ndev->stats.tx_errors++; @@ -1480,6 +1483,11 @@ static int __wil_tx_ring_tso_edma(struct wil6210_priv *wil, */ wmb(); + if (wil->tx_latency) + *(ktime_t *)&skb->cb = ktime_get(); + else + memset(skb->cb, 0, sizeof(ktime_t)); + wil_w(wil, ring->hwtail, ring->swhead); return 0; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 3f0909df541c..23f2982867c6 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -62,6 +62,8 @@ union wil_tx_desc; #define WIL_DEFAULT_BUS_REQUEST_KBPS 128000 /* ~1Gbps */ #define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */ +#define WIL_NUM_LATENCY_BINS 200 + /* maximum number of virtual interfaces the driver supports * (including the main interface) */ @@ -562,6 +564,9 @@ struct wil_net_stats { unsigned long rx_bytes; unsigned long tx_bytes; unsigned long tx_errors; + u32 tx_latency_min_us; + u32 tx_latency_max_us; + u64 tx_latency_total_us; unsigned long rx_dropped; unsigned long rx_non_data_frame; unsigned long rx_short_frame; @@ -723,6 +728,13 @@ struct wil_sta_info { u8 mid; enum wil_sta_status status; struct wil_net_stats stats; + /** + * 20 latency bins. 1st bin counts packets with latency + * of 0..tx_latency_res, last bin counts packets with latency + * of 19*tx_latency_res and above. + * tx_latency_res is configured from "tx_latency" debug-fs. + */ + u64 *tx_latency_bins; /* Rx BACK */ struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM]; spinlock_t tid_rx_lock; /* guarding tid_rx array */ @@ -960,6 +972,8 @@ struct wil6210_priv { struct wil_suspend_stats suspend_stats; struct wil_debugfs_data dbg_data; u8 force_edmg_channel; + bool tx_latency; /* collect TX latency measurements */ + size_t tx_latency_res; /* bin resolution in usec */ void *platform_handle; struct wil_platform_ops platform_ops; -- GitLab From e7591514a5a9026a933af54b850b5fb972303138 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Tue, 24 Jul 2018 10:44:25 +0300 Subject: [PATCH 0612/1001] wil6210: fix temperature debugfs For negative temperatures, "temp" debugfs is showing wrong values. Use signed types so proper calculations is done for sub zero temperatures. Change-Id: Ie44b2f679ccca6bb80b5fd57a9b3eb2ed38d4798 Signed-off-by: Dedy Lansky Signed-off-by: Maya Erez Signed-off-by: Kalle Valo Git-commit: 6d9eb7ebae3d7e951bc0999235ae7028eb4cae4f Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Signed-off-by: Maya Erez --- drivers/net/wireless/ath/wil6210/debugfs.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index a1d48eec4093..eef3c7047184 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1433,7 +1433,7 @@ static const struct file_operations fops_ssid = { }; /*---------temp------------*/ -static void print_temp(struct seq_file *s, const char *prefix, u32 t) +static void print_temp(struct seq_file *s, const char *prefix, s32 t) { switch (t) { case 0: @@ -1441,7 +1441,8 @@ static void print_temp(struct seq_file *s, const char *prefix, u32 t) seq_printf(s, "%s N/A\n", prefix); break; default: - seq_printf(s, "%s %d.%03d\n", prefix, t / 1000, t % 1000); + seq_printf(s, "%s %s%d.%03d\n", prefix, (t < 0 ? "-" : ""), + abs(t / 1000), abs(t % 1000)); break; } } @@ -1449,7 +1450,7 @@ static void print_temp(struct seq_file *s, const char *prefix, u32 t) static int wil_temp_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; - u32 t_m, t_r; + s32 t_m, t_r; int rc = wmi_get_temperature(wil, &t_m, &t_r); if (rc) { -- GitLab From 9c5104a7606d680458f02db8d4603a025fb5b348 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Sun, 5 Aug 2018 10:12:59 +0300 Subject: [PATCH 0613/1001] wil6210: align to latest auto generated wmi.h Align to latest version of the auto generated wmi file describing the interface with FW. Change-Id: Icd49719ed4e3584eebb9e11553012144f8b5ad55 Signed-off-by: Dedy Lansky Signed-off-by: Maya Erez Signed-off-by: Kalle Valo Git-commit: b5aeff16b20f65e6bb9ebafd06c1c96c2b503089 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Signed-off-by: Maya Erez --- drivers/net/wireless/ath/wil6210/wmi.h | 459 +++++++++++++++++++++++-- 1 file changed, 434 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index b198a1f809d9..0c687fcbc66b 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -53,6 +53,17 @@ * must always be kept equal to (WMI_RF_RX2TX_LENGTH+1) */ #define WMI_RF_RX2TX_CONF_LENGTH (4) +/* Qos configuration */ +#define WMI_QOS_NUM_OF_PRIORITY (4) +#define WMI_QOS_MIN_DEFAULT_WEIGHT (10) +#define WMI_QOS_VRING_SLOT_MIN_MS (2) +#define WMI_QOS_VRING_SLOT_MAX_MS (10) +/* (WMI_QOS_MIN_DEFAULT_WEIGHT * WMI_QOS_VRING_SLOT_MAX_MS / + * WMI_QOS_VRING_SLOT_MIN_MS) + */ +#define WMI_QOS_MAX_WEIGHT 50 +#define WMI_QOS_SET_VIF_PRIORITY (0xFF) +#define WMI_QOS_DEFAULT_PRIORITY (WMI_QOS_NUM_OF_PRIORITY) /* Mailbox interface * used for commands and events @@ -88,6 +99,8 @@ enum wmi_fw_capability { WMI_FW_CAPABILITY_CHANNEL_BONDING = 17, WMI_FW_CAPABILITY_REF_CLOCK_CONTROL = 18, WMI_FW_CAPABILITY_AP_SME_OFFLOAD_NONE = 19, + WMI_FW_CAPABILITY_MULTI_VIFS = 20, + WMI_FW_CAPABILITY_FT_ROAMING = 21, WMI_FW_CAPABILITY_BACK_WIN_SIZE_64 = 22, WMI_FW_CAPABILITY_AMSDU = 23, WMI_FW_CAPABILITY_MAX, @@ -113,6 +126,9 @@ enum wmi_command_id { WMI_SET_PROBED_SSID_CMDID = 0x0A, /* deprecated */ WMI_SET_LISTEN_INT_CMDID = 0x0B, + WMI_FT_AUTH_CMDID = 0x0C, + WMI_FT_REASSOC_CMDID = 0x0D, + WMI_UPDATE_FT_IES_CMDID = 0x0E, WMI_BCON_CTRL_CMDID = 0x0F, WMI_ADD_CIPHER_KEY_CMDID = 0x16, WMI_DELETE_CIPHER_KEY_CMDID = 0x17, @@ -210,7 +226,12 @@ enum wmi_command_id { WMI_GET_PCP_FACTOR_CMDID = 0x91B, /* Power Save Configuration Commands */ WMI_PS_DEV_PROFILE_CFG_CMDID = 0x91C, + WMI_RS_ENABLE_CMDID = 0x91E, + WMI_RS_CFG_EX_CMDID = 0x91F, + WMI_GET_DETAILED_RS_RES_EX_CMDID = 0x920, + /* deprecated */ WMI_RS_CFG_CMDID = 0x921, + /* deprecated */ WMI_GET_DETAILED_RS_RES_CMDID = 0x922, WMI_AOA_MEAS_CMDID = 0x923, WMI_BRP_SET_ANT_LIMIT_CMDID = 0x924, @@ -239,7 +260,9 @@ enum wmi_command_id { WMI_PRIO_TX_SECTORS_ORDER_CMDID = 0x9A5, WMI_PRIO_TX_SECTORS_NUMBER_CMDID = 0x9A6, WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_CMDID = 0x9A7, + /* deprecated */ WMI_BF_CONTROL_CMDID = 0x9AA, + WMI_BF_CONTROL_EX_CMDID = 0x9AB, WMI_TX_STATUS_RING_ADD_CMDID = 0x9C0, WMI_RX_STATUS_RING_ADD_CMDID = 0x9C1, WMI_TX_DESC_RING_ADD_CMDID = 0x9C2, @@ -255,6 +278,11 @@ enum wmi_command_id { WMI_GET_CCA_INDICATIONS_CMDID = 0xA07, WMI_SET_CCA_INDICATIONS_BI_AVG_NUM_CMDID = 0xA08, WMI_INTERNAL_FW_IOCTL_CMDID = 0xA0B, + WMI_LINK_STATS_CMDID = 0xA0C, + WMI_SET_GRANT_MCS_CMDID = 0xA0E, + WMI_SET_AP_SLOT_SIZE_CMDID = 0xA0F, + WMI_SET_VRING_PRIORITY_WEIGHT_CMDID = 0xA10, + WMI_SET_VRING_PRIORITY_CMDID = 0xA11, WMI_SET_MAC_ADDRESS_CMDID = 0xF003, WMI_ABORT_SCAN_CMDID = 0xF007, WMI_SET_PROMISCUOUS_MODE_CMDID = 0xF041, @@ -470,6 +498,30 @@ struct wmi_start_sched_scan_cmd { struct wmi_sched_scan_plan scan_plans[WMI_MAX_PLANS_NUM]; } __packed; +/* WMI_FT_AUTH_CMDID */ +struct wmi_ft_auth_cmd { + u8 bssid[WMI_MAC_LEN]; + /* enum wmi_channel */ + u8 channel; + /* enum wmi_channel */ + u8 edmg_channel; + u8 reserved[4]; +} __packed; + +/* WMI_FT_REASSOC_CMDID */ +struct wmi_ft_reassoc_cmd { + u8 bssid[WMI_MAC_LEN]; + u8 reserved[2]; +} __packed; + +/* WMI_UPDATE_FT_IES_CMDID */ +struct wmi_update_ft_ies_cmd { + /* Length of the FT IEs */ + __le16 ie_len; + u8 reserved[2]; + u8 ie_info[0]; +} __packed; + /* WMI_SET_PROBED_SSID_CMDID */ #define MAX_PROBED_SSID_INDEX (3) @@ -769,7 +821,11 @@ struct wmi_vring_cfg { u8 cid; /* Used when cidxtid = CIDXTID_EXTENDED_CID_TID */ u8 tid; - u8 reserved[2]; + /* Update the vring's priority for Qos purpose. Set to + * WMI_QOS_DEFAULT_PRIORITY to use MID's QoS priority + */ + u8 qos_priority; + u8 reserved; } __packed; enum wmi_vring_cfg_cmd_action { @@ -800,20 +856,6 @@ struct wmi_bcast_vring_cfg_cmd { struct wmi_bcast_vring_cfg vring_cfg; } __packed; -/* WMI_LO_POWER_CALIB_FROM_OTP_CMDID */ -struct wmi_lo_power_calib_from_otp_cmd { - /* index to read from OTP. zero based */ - u8 index; - u8 reserved[3]; -} __packed; - -/* WMI_LO_POWER_CALIB_FROM_OTP_EVENTID */ -struct wmi_lo_power_calib_from_otp_event { - /* wmi_fw_status */ - u8 status; - u8 reserved[3]; -} __packed; - struct wmi_edma_ring_cfg { __le64 ring_mem_base; /* size in number of items */ @@ -886,6 +928,20 @@ struct wmi_bcast_desc_ring_add_cmd { u8 reserved[4]; } __packed; +/* WMI_LO_POWER_CALIB_FROM_OTP_CMDID */ +struct wmi_lo_power_calib_from_otp_cmd { + /* index to read from OTP. zero based */ + u8 index; + u8 reserved[3]; +} __packed; + +/* WMI_LO_POWER_CALIB_FROM_OTP_EVENTID */ +struct wmi_lo_power_calib_from_otp_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + /* WMI_RING_BA_EN_CMDID */ struct wmi_ring_ba_en_cmd { u8 ring_id; @@ -1444,6 +1500,10 @@ struct wmi_fixed_scheduling_config_complete_event { u8 reserved[3]; } __packed; +/* This value exists for backwards compatibility only. + * Do not use it in new commands. + * Use dynamic arrays where possible. + */ #define WMI_NUM_MCS (13) /* WMI_FIXED_SCHEDULING_CONFIG_CMDID */ @@ -1503,12 +1563,12 @@ struct wmi_set_long_range_config_complete_event { u8 reserved[3]; } __packed; -/* payload max size is 236 bytes: max event buffer size (256) - WMI headers +/* payload max size is 1024 bytes: max event buffer size (1044) - WMI headers * (16) - prev struct field size (4) */ -#define WMI_MAX_IOCTL_PAYLOAD_SIZE (236) -#define WMI_MAX_IOCTL_REPLY_PAYLOAD_SIZE (236) -#define WMI_MAX_INTERNAL_EVENT_PAYLOAD_SIZE (236) +#define WMI_MAX_IOCTL_PAYLOAD_SIZE (1024) +#define WMI_MAX_IOCTL_REPLY_PAYLOAD_SIZE (1024) +#define WMI_MAX_INTERNAL_EVENT_PAYLOAD_SIZE (1024) enum wmi_internal_fw_ioctl_code { WMI_INTERNAL_FW_CODE_NONE = 0x0, @@ -1548,7 +1608,37 @@ struct wmi_internal_fw_event_event { __le32 payload[0]; } __packed; -/* WMI_BF_CONTROL_CMDID */ +/* WMI_SET_VRING_PRIORITY_WEIGHT_CMDID */ +struct wmi_set_vring_priority_weight_cmd { + /* Array of weights. Valid values are + * WMI_QOS_MIN_DEFAULT_WEIGHT...WMI_QOS_MAX_WEIGHT. Weight #0 is + * hard-coded WMI_QOS_MIN_WEIGHT. This array provide the weights + * #1..#3 + */ + u8 weight[3]; + u8 reserved; +} __packed; + +/* WMI_SET_VRING_PRIORITY_CMDID */ +struct wmi_vring_priority { + u8 vring_idx; + /* Weight index. Valid value is 0-3 */ + u8 priority; + u8 reserved[2]; +} __packed; + +/* WMI_SET_VRING_PRIORITY_CMDID */ +struct wmi_set_vring_priority_cmd { + /* number of entries in vring_priority. Set to + * WMI_QOS_SET_VIF_PRIORITY to update the VIF's priority, and there + * will be only one entry in vring_priority + */ + u8 num_of_vrings; + u8 reserved[3]; + struct wmi_vring_priority vring_priority[0]; +} __packed; + +/* WMI_BF_CONTROL_CMDID - deprecated */ struct wmi_bf_control_cmd { /* wmi_bf_triggers */ __le32 triggers; @@ -1590,6 +1680,97 @@ struct wmi_bf_control_cmd { u8 reserved2[2]; } __packed; +/* BF configuration for each MCS */ +struct wmi_bf_control_ex_mcs { + /* Long term throughput threshold [Mbps] */ + u8 long_term_mbps_th_tbl; + u8 reserved; + /* Long term timeout threshold table [msec] */ + __le16 long_term_trig_timeout_per_mcs; +} __packed; + +/* WMI_BF_CONTROL_EX_CMDID */ +struct wmi_bf_control_ex_cmd { + /* wmi_bf_triggers */ + __le32 triggers; + /* enum wmi_edmg_tx_mode */ + u8 tx_mode; + /* DISABLED = 0, ENABLED = 1 , DRY_RUN = 2 */ + u8 txss_mode; + /* DISABLED = 0, ENABLED = 1, DRY_RUN = 2 */ + u8 brp_mode; + /* Max cts threshold (correspond to + * WMI_BF_TRIGGER_MAX_CTS_FAILURE_IN_TXOP) + */ + u8 bf_trigger_max_cts_failure_thr; + /* Max cts threshold in dense (correspond to + * WMI_BF_TRIGGER_MAX_CTS_FAILURE_IN_TXOP) + */ + u8 bf_trigger_max_cts_failure_dense_thr; + /* Max b-ack threshold (correspond to + * WMI_BF_TRIGGER_MAX_BACK_FAILURE) + */ + u8 bf_trigger_max_back_failure_thr; + /* Max b-ack threshold in dense (correspond to + * WMI_BF_TRIGGER_MAX_BACK_FAILURE) + */ + u8 bf_trigger_max_back_failure_dense_thr; + u8 reserved0; + /* Wrong sectors threshold */ + __le32 wrong_sector_bis_thr; + /* BOOL to enable/disable long term trigger */ + u8 long_term_enable; + /* 1 = Update long term thresholds from the long_term_mbps_th_tbl and + * long_term_trig_timeout_per_mcs arrays, 0 = Ignore + */ + u8 long_term_update_thr; + u8 each_mcs_cfg_size; + u8 reserved1; + /* Configuration for each MCS */ + struct wmi_bf_control_ex_mcs each_mcs_cfg[0]; +} __packed; + +/* WMI_LINK_STATS_CMD */ +enum wmi_link_stats_action { + WMI_LINK_STATS_SNAPSHOT = 0x00, + WMI_LINK_STATS_PERIODIC = 0x01, + WMI_LINK_STATS_STOP_PERIODIC = 0x02, +}; + +/* WMI_LINK_STATS_EVENT record identifiers */ +enum wmi_link_stats_record_type { + WMI_LINK_STATS_TYPE_BASIC = 0x01, + WMI_LINK_STATS_TYPE_MAC = 0x02, + WMI_LINK_STATS_TYPE_PHY = 0x04, + WMI_LINK_STATS_TYPE_OTA = 0x08, +}; + +/* WMI_LINK_STATS_CMDID */ +struct wmi_link_stats_cmd { + /* bitmask of required record types + * (wmi_link_stats_record_type_e) + */ + __le32 record_type_mask; + /* 0xff for all cids */ + u8 cid; + /* wmi_link_stats_action_e */ + u8 action; + u8 reserved[6]; + /* for WMI_LINK_STATS_PERIODIC */ + __le32 interval_msec; +} __packed; + +/* WMI_SET_GRANT_MCS_CMDID */ +struct wmi_set_grant_mcs_cmd { + u8 mcs; + u8 reserved[3]; +} __packed; + +/* WMI_SET_AP_SLOT_SIZE_CMDID */ +struct wmi_set_ap_slot_size_cmd { + __le32 slot_size; +} __packed; + /* WMI Events * List of Events (target to host) */ @@ -1602,6 +1783,8 @@ enum wmi_event_id { WMI_SCHED_SCAN_RESULT_EVENTID = 0x1007, WMI_SCAN_COMPLETE_EVENTID = 0x100A, WMI_REPORT_STATISTICS_EVENTID = 0x100B, + WMI_FT_AUTH_STATUS_EVENTID = 0x100C, + WMI_FT_REASSOC_STATUS_EVENTID = 0x100D, WMI_RD_MEM_RSP_EVENTID = 0x1800, WMI_FW_READY_EVENTID = 0x1801, WMI_EXIT_FAST_MEM_ACC_MODE_EVENTID = 0x200, @@ -1678,7 +1861,12 @@ enum wmi_event_id { WMI_PCP_FACTOR_EVENTID = 0x191A, /* Power Save Configuration Events */ WMI_PS_DEV_PROFILE_CFG_EVENTID = 0x191C, + WMI_RS_ENABLE_EVENTID = 0x191E, + WMI_RS_CFG_EX_EVENTID = 0x191F, + WMI_GET_DETAILED_RS_RES_EX_EVENTID = 0x1920, + /* deprecated */ WMI_RS_CFG_DONE_EVENTID = 0x1921, + /* deprecated */ WMI_GET_DETAILED_RS_RES_EVENTID = 0x1922, WMI_AOA_MEAS_EVENTID = 0x1923, WMI_BRP_SET_ANT_LIMIT_EVENTID = 0x1924, @@ -1706,7 +1894,9 @@ enum wmi_event_id { WMI_PRIO_TX_SECTORS_ORDER_EVENTID = 0x19A5, WMI_PRIO_TX_SECTORS_NUMBER_EVENTID = 0x19A6, WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_EVENTID = 0x19A7, + /* deprecated */ WMI_BF_CONTROL_EVENTID = 0x19AA, + WMI_BF_CONTROL_EX_EVENTID = 0x19AB, WMI_TX_STATUS_RING_CFG_DONE_EVENTID = 0x19C0, WMI_RX_STATUS_RING_CFG_DONE_EVENTID = 0x19C1, WMI_TX_DESC_RING_CFG_DONE_EVENTID = 0x19C2, @@ -1722,6 +1912,12 @@ enum wmi_event_id { WMI_SET_CCA_INDICATIONS_BI_AVG_NUM_EVENTID = 0x1A08, WMI_INTERNAL_FW_EVENT_EVENTID = 0x1A0A, WMI_INTERNAL_FW_IOCTL_EVENTID = 0x1A0B, + WMI_LINK_STATS_CONFIG_DONE_EVENTID = 0x1A0C, + WMI_LINK_STATS_EVENTID = 0x1A0D, + WMI_SET_GRANT_MCS_EVENTID = 0x1A0E, + WMI_SET_AP_SLOT_SIZE_EVENTID = 0x1A0F, + WMI_SET_VRING_PRIORITY_WEIGHT_EVENTID = 0x1A10, + WMI_SET_VRING_PRIORITY_EVENTID = 0x1A11, WMI_SET_CHANNEL_EVENTID = 0x9000, WMI_ASSOC_REQ_EVENTID = 0x9001, WMI_EAPOL_RX_EVENTID = 0x9002, @@ -1990,6 +2186,33 @@ struct wmi_scan_complete_event { __le32 status; } __packed; +/* WMI_FT_AUTH_STATUS_EVENTID */ +struct wmi_ft_auth_status_event { + /* enum wmi_fw_status */ + u8 status; + u8 reserved[3]; + u8 mac_addr[WMI_MAC_LEN]; + __le16 ie_len; + u8 ie_info[0]; +} __packed; + +/* WMI_FT_REASSOC_STATUS_EVENTID */ +struct wmi_ft_reassoc_status_event { + /* enum wmi_fw_status */ + u8 status; + /* association id received from new AP */ + u8 aid; + /* enum wmi_channel */ + u8 channel; + /* enum wmi_channel */ + u8 edmg_channel; + u8 mac_addr[WMI_MAC_LEN]; + __le16 beacon_ie_len; + __le16 reassoc_req_ie_len; + __le16 reassoc_resp_ie_len; + u8 ie_info[0]; +} __packed; + /* wmi_rx_mgmt_info */ struct wmi_rx_mgmt_info { u8 mcs; @@ -2484,6 +2707,81 @@ struct wmi_rs_cfg { __le32 mcs_en_vec; } __packed; +enum wmi_edmg_tx_mode { + WMI_TX_MODE_DMG = 0x0, + WMI_TX_MODE_EDMG_CB1 = 0x1, + WMI_TX_MODE_EDMG_CB2 = 0x2, + WMI_TX_MODE_EDMG_CB1_LONG_LDPC = 0x3, + WMI_TX_MODE_EDMG_CB2_LONG_LDPC = 0x4, + WMI_TX_MODE_MAX, +}; + +/* Rate search parameters common configuration */ +struct wmi_rs_cfg_ex_common { + /* enum wmi_edmg_tx_mode */ + u8 mode; + /* stop threshold [0-100] */ + u8 stop_th; + /* MCS1 stop threshold [0-100] */ + u8 mcs1_fail_th; + u8 max_back_failure_th; + /* Debug feature for disabling internal RS trigger (which is + * currently triggered by BF Done) + */ + u8 dbg_disable_internal_trigger; + u8 reserved[3]; + __le32 back_failure_mask; +} __packed; + +/* Rate search parameters configuration per MCS */ +struct wmi_rs_cfg_ex_mcs { + /* The maximal allowed PER for each MCS + * MCS will be considered as failed if PER during RS is higher + */ + u8 per_threshold; + /* Number of MPDUs for each MCS + * this is the minimal statistic required to make an educated + * decision + */ + u8 min_frame_cnt; + u8 reserved[2]; +} __packed; + +/* WMI_RS_CFG_EX_CMDID */ +struct wmi_rs_cfg_ex_cmd { + /* Configuration for all MCSs */ + struct wmi_rs_cfg_ex_common common_cfg; + u8 each_mcs_cfg_size; + u8 reserved[3]; + /* Configuration for each MCS */ + struct wmi_rs_cfg_ex_mcs each_mcs_cfg[0]; +} __packed; + +/* WMI_RS_CFG_EX_EVENTID */ +struct wmi_rs_cfg_ex_event { + /* enum wmi_edmg_tx_mode */ + u8 mode; + /* enum wmi_fw_status */ + u8 status; + u8 reserved[2]; +} __packed; + +/* WMI_RS_ENABLE_CMDID */ +struct wmi_rs_enable_cmd { + u8 cid; + /* enable or disable rate search */ + u8 rs_enable; + u8 reserved[2]; + __le32 mcs_en_vec; +} __packed; + +/* WMI_RS_ENABLE_EVENTID */ +struct wmi_rs_enable_event { + /* enum wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + /* Slot types */ enum wmi_sched_scheme_slot_type { WMI_SCHED_SLOT_SP = 0x0, @@ -2576,7 +2874,7 @@ struct wmi_scheduling_scheme_event { u8 reserved[1]; } __packed; -/* WMI_RS_CFG_CMDID */ +/* WMI_RS_CFG_CMDID - deprecated */ struct wmi_rs_cfg_cmd { /* connection id */ u8 cid; @@ -2586,7 +2884,7 @@ struct wmi_rs_cfg_cmd { struct wmi_rs_cfg rs_cfg; } __packed; -/* WMI_RS_CFG_DONE_EVENTID */ +/* WMI_RS_CFG_DONE_EVENTID - deprecated */ struct wmi_rs_cfg_done_event { u8 cid; /* enum wmi_fw_status */ @@ -2594,7 +2892,7 @@ struct wmi_rs_cfg_done_event { u8 reserved[2]; } __packed; -/* WMI_GET_DETAILED_RS_RES_CMDID */ +/* WMI_GET_DETAILED_RS_RES_CMDID - deprecated */ struct wmi_get_detailed_rs_res_cmd { /* connection id */ u8 cid; @@ -2619,7 +2917,7 @@ struct wmi_rs_results { u8 mcs; } __packed; -/* WMI_GET_DETAILED_RS_RES_EVENTID */ +/* WMI_GET_DETAILED_RS_RES_EVENTID - deprecated */ struct wmi_get_detailed_rs_res_event { u8 cid; /* enum wmi_rs_results_status */ @@ -2629,6 +2927,45 @@ struct wmi_get_detailed_rs_res_event { u8 reserved[3]; } __packed; +/* WMI_GET_DETAILED_RS_RES_EX_CMDID */ +struct wmi_get_detailed_rs_res_ex_cmd { + u8 cid; + u8 reserved[3]; +} __packed; + +/* Rate search results */ +struct wmi_rs_results_ex_common { + /* RS timestamp */ + __le32 tsf; + /* RS selected MCS */ + u8 mcs; + /* enum wmi_edmg_tx_mode */ + u8 mode; + u8 reserved[2]; +} __packed; + +/* Rate search results */ +struct wmi_rs_results_ex_mcs { + /* number of sent MPDUs */ + u8 num_of_tx_pkt; + /* number of non-acked MPDUs */ + u8 num_of_non_acked_pkt; + u8 reserved[2]; +} __packed; + +/* WMI_GET_DETAILED_RS_RES_EX_EVENTID */ +struct wmi_get_detailed_rs_res_ex_event { + u8 cid; + /* enum wmi_rs_results_status */ + u8 status; + u8 reserved0[2]; + struct wmi_rs_results_ex_common common_rs_results; + u8 each_mcs_results_size; + u8 reserved1[3]; + /* Results for each MCS */ + struct wmi_rs_results_ex_mcs each_mcs_results[0]; +} __packed; + /* BRP antenna limit mode */ enum wmi_brp_ant_limit_mode { /* Disable BRP force antenna limit */ @@ -3379,13 +3716,20 @@ struct wmi_get_assoc_list_res_event { u8 reserved[3]; } __packed; -/* WMI_BF_CONTROL_EVENTID */ +/* WMI_BF_CONTROL_EVENTID - deprecated */ struct wmi_bf_control_event { /* wmi_fw_status */ u8 status; u8 reserved[3]; } __packed; +/* WMI_BF_CONTROL_EX_EVENTID */ +struct wmi_bf_control_ex_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + /* WMI_COMMAND_NOT_SUPPORTED_EVENTID */ struct wmi_command_not_supported_event { /* device id */ @@ -3455,4 +3799,69 @@ struct wmi_internal_fw_set_channel_event { u8 reserved[3]; } __packed; +/* WMI_LINK_STATS_CONFIG_DONE_EVENTID */ +struct wmi_link_stats_config_done_event { + /* wmi_fw_status_e */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_LINK_STATS_EVENTID */ +struct wmi_link_stats_event { + __le16 payload_size; + u8 has_next; + u8 reserved[5]; + /* a stream of records, e.g. wmi_link_stats_basic_s */ + u8 payload[0]; +} __packed; + +/* WMI_LINK_STATS_EVENT record struct */ +struct wmi_link_stats_basic { + /* WMI_LINK_STATS_TYPE_BASIC */ + u8 record_type_id; + u8 cid; + /* 0: fail; 1: OK; 2: retrying */ + u8 bf_status; + s8 rssi; + u8 sqi; + u8 selected_rfc; + __le16 bf_mcs; + __le32 tx_tpt; + __le32 tx_goodput; + __le32 rx_goodput; + __le16 my_rx_sector; + __le16 my_tx_sector; + __le16 other_rx_sector; + __le16 other_tx_sector; + __le32 reserved[2]; +} __packed; + +/* WMI_SET_GRANT_MCS_EVENTID */ +struct wmi_set_grant_mcs_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_SET_AP_SLOT_SIZE_EVENTID */ +struct wmi_set_ap_slot_size_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_SET_VRING_PRIORITY_WEIGHT_EVENTID */ +struct wmi_set_vring_priority_weight_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_SET_VRING_PRIORITY_EVENTID */ +struct wmi_set_vring_priority_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + #endif /* __WILOCITY_WMI_H__ */ -- GitLab From 3255290e8bc433c6d4e29939275733a27b97449a Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Sun, 5 Aug 2018 10:15:02 +0300 Subject: [PATCH 0614/1001] wil6210: add support for link statistics Driver can request FW to report link statistics using WMI_LINK_STATS_CMDID. FW will report statistics with WMI_LINK_STATS_EVENTID. Two categories of statistics defined: basic and global. New "link_stats" debugfs is used for requesting basic statistics report (write) and for reading the basic statistics (read). "link_stats_global" debugfs is used for requesting and reading the global statistics. Change-Id: I45575baae44ee32fbe0ed655e0a36e63c2364142 Signed-off-by: Dedy Lansky Signed-off-by: Maya Erez Signed-off-by: Kalle Valo Git-commit: 0c936b3c96337c3fd5ad4951ca7bdc54fa578a02 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Signed-off-by: Maya Erez --- drivers/net/wireless/ath/wil6210/debugfs.c | 219 +++++++++++++++++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 12 ++ drivers/net/wireless/ath/wil6210/wmi.c | 165 ++++++++++++++++ drivers/net/wireless/ath/wil6210/wmi.h | 57 ++++-- 4 files changed, 437 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index eef3c7047184..bb7a7fdfa755 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1961,6 +1961,223 @@ static const struct file_operations fops_tx_latency = { .llseek = seq_lseek, }; +static void wil_link_stats_print_basic(struct wil6210_vif *vif, + struct seq_file *s, + struct wmi_link_stats_basic *basic) +{ + char per[5] = "?"; + + if (basic->per_average != 0xff) + snprintf(per, sizeof(per), "%d%%", basic->per_average); + + seq_printf(s, "CID %d {\n" + "\tTxMCS %d TxTpt %d\n" + "\tGoodput(rx:tx) %d:%d\n" + "\tRxBcastFrames %d\n" + "\tRSSI %d SQI %d SNR %d PER %s\n" + "\tRx RFC %d Ant num %d\n" + "\tSectors(rx:tx) my %d:%d peer %d:%d\n" + "}\n", + basic->cid, + basic->bf_mcs, le32_to_cpu(basic->tx_tpt), + le32_to_cpu(basic->rx_goodput), + le32_to_cpu(basic->tx_goodput), + le32_to_cpu(basic->rx_bcast_frames), + basic->rssi, basic->sqi, basic->snr, per, + basic->selected_rfc, basic->rx_effective_ant_num, + basic->my_rx_sector, basic->my_tx_sector, + basic->other_rx_sector, basic->other_tx_sector); +} + +static void wil_link_stats_print_global(struct wil6210_priv *wil, + struct seq_file *s, + struct wmi_link_stats_global *global) +{ + seq_printf(s, "Frames(rx:tx) %d:%d\n" + "BA Frames(rx:tx) %d:%d\n" + "Beacons %d\n" + "Rx Errors (MIC:CRC) %d:%d\n" + "Tx Errors (no ack) %d\n", + le32_to_cpu(global->rx_frames), + le32_to_cpu(global->tx_frames), + le32_to_cpu(global->rx_ba_frames), + le32_to_cpu(global->tx_ba_frames), + le32_to_cpu(global->tx_beacons), + le32_to_cpu(global->rx_mic_errors), + le32_to_cpu(global->rx_crc_errors), + le32_to_cpu(global->tx_fail_no_ack)); +} + +static void wil_link_stats_debugfs_show_vif(struct wil6210_vif *vif, + struct seq_file *s) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + struct wmi_link_stats_basic *stats; + int i; + + if (!vif->fw_stats_ready) { + seq_puts(s, "no statistics\n"); + return; + } + + seq_printf(s, "TSF %lld\n", vif->fw_stats_tsf); + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { + if (wil->sta[i].status == wil_sta_unused) + continue; + if (wil->sta[i].mid != vif->mid) + continue; + + stats = &wil->sta[i].fw_stats_basic; + wil_link_stats_print_basic(vif, s, stats); + } +} + +static int wil_link_stats_debugfs_show(struct seq_file *s, void *data) +{ + struct wil6210_priv *wil = s->private; + struct wil6210_vif *vif; + int i, rc; + + rc = mutex_lock_interruptible(&wil->vif_mutex); + if (rc) + return rc; + + /* iterate over all MIDs and show per-cid statistics. Then show the + * global statistics + */ + for (i = 0; i < wil->max_vifs; i++) { + vif = wil->vifs[i]; + + seq_printf(s, "MID %d ", i); + if (!vif) { + seq_puts(s, "unused\n"); + continue; + } + + wil_link_stats_debugfs_show_vif(vif, s); + } + + mutex_unlock(&wil->vif_mutex); + + return 0; +} + +static int wil_link_stats_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_link_stats_debugfs_show, inode->i_private); +} + +static ssize_t wil_link_stats_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct wil6210_priv *wil = s->private; + int cid, interval, rc, i; + struct wil6210_vif *vif; + char *kbuf = kmalloc(len + 1, GFP_KERNEL); + + if (!kbuf) + return -ENOMEM; + + rc = simple_write_to_buffer(kbuf, len, ppos, buf, len); + if (rc != len) { + kfree(kbuf); + return rc >= 0 ? -EIO : rc; + } + + kbuf[len] = '\0'; + /* specify cid (use -1 for all cids) and snapshot interval in ms */ + rc = sscanf(kbuf, "%d %d", &cid, &interval); + kfree(kbuf); + if (rc < 0) + return rc; + if (rc < 2 || interval < 0) + return -EINVAL; + + wil_info(wil, "request link statistics, cid %d interval %d\n", + cid, interval); + + rc = mutex_lock_interruptible(&wil->vif_mutex); + if (rc) + return rc; + + for (i = 0; i < wil->max_vifs; i++) { + vif = wil->vifs[i]; + if (!vif) + continue; + + rc = wmi_link_stats_cfg(vif, WMI_LINK_STATS_TYPE_BASIC, + (cid == -1 ? 0xff : cid), interval); + if (rc) + wil_err(wil, "link statistics failed for mid %d\n", i); + } + mutex_unlock(&wil->vif_mutex); + + return len; +} + +static const struct file_operations fops_link_stats = { + .open = wil_link_stats_seq_open, + .release = single_release, + .read = seq_read, + .write = wil_link_stats_write, + .llseek = seq_lseek, +}; + +static int +wil_link_stats_global_debugfs_show(struct seq_file *s, void *data) +{ + struct wil6210_priv *wil = s->private; + + if (!wil->fw_stats_global.ready) + return 0; + + seq_printf(s, "TSF %lld\n", wil->fw_stats_global.tsf); + wil_link_stats_print_global(wil, s, &wil->fw_stats_global.stats); + + return 0; +} + +static int +wil_link_stats_global_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_link_stats_global_debugfs_show, + inode->i_private); +} + +static ssize_t +wil_link_stats_global_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct wil6210_priv *wil = s->private; + int interval, rc; + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); + + /* specify snapshot interval in ms */ + rc = kstrtoint_from_user(buf, len, 0, &interval); + if (rc || interval < 0) { + wil_err(wil, "Invalid argument\n"); + return -EINVAL; + } + + wil_info(wil, "request global link stats, interval %d\n", interval); + + rc = wmi_link_stats_cfg(vif, WMI_LINK_STATS_TYPE_GLOBAL, 0, interval); + if (rc) + wil_err(wil, "global link stats failed %d\n", rc); + + return rc ? rc : len; +} + +static const struct file_operations fops_link_stats_global = { + .open = wil_link_stats_global_seq_open, + .release = single_release, + .read = seq_read, + .write = wil_link_stats_global_write, + .llseek = seq_lseek, +}; + static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -2296,6 +2513,8 @@ static const struct { {"status_msg", 0444, &fops_status_msg}, {"rx_buff_mgmt", 0444, &fops_rx_buff_mgmt}, {"tx_latency", 0644, &fops_tx_latency}, + {"link_stats", 0644, &fops_link_stats}, + {"link_stats_global", 0644, &fops_link_stats_global}, }; static void wil6210_debugfs_init_files(struct wil6210_priv *wil, diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 23f2982867c6..4a5a7d375b0c 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -735,6 +735,7 @@ struct wil_sta_info { * tx_latency_res is configured from "tx_latency" debug-fs. */ u64 *tx_latency_bins; + struct wmi_link_stats_basic fw_stats_basic; /* Rx BACK */ struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM]; spinlock_t tid_rx_lock; /* guarding tid_rx array */ @@ -852,6 +853,8 @@ struct wil6210_vif { struct mutex probe_client_mutex; /* protect @probe_client_pending */ struct work_struct probe_client_worker; int net_queue_stopped; /* netif_tx_stop_all_queues invoked */ + bool fw_stats_ready; /* per-cid statistics are ready inside sta_info */ + u64 fw_stats_tsf; /* measurement timestamp */ }; /** @@ -879,6 +882,12 @@ struct wil_rx_buff_mgmt { unsigned long free_list_empty_cnt; /* statistics */ }; +struct wil_fw_stats_global { + bool ready; + u64 tsf; /* measurement timestamp */ + struct wmi_link_stats_global stats; +}; + struct wil6210_priv { struct pci_dev *pdev; u32 bar_size; @@ -1035,6 +1044,8 @@ struct wil6210_priv { u32 max_agg_wsize; u32 max_ampdu_size; + + struct wil_fw_stats_global fw_stats_global; }; #define wil_to_wiphy(i) (i->wiphy) @@ -1240,6 +1251,7 @@ int wmi_get_tt_cfg(struct wil6210_priv *wil, struct wmi_tt_data *tt_data); int wmi_port_allocate(struct wil6210_priv *wil, u8 mid, const u8 *mac, enum nl80211_iftype iftype); int wmi_port_delete(struct wil6210_priv *wil, u8 mid); +int wmi_link_stats_cfg(struct wil6210_vif *vif, u32 type, u8 cid, u32 interval); int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid, u8 cidxtid, u8 dialog_token, __le16 ba_param_set, __le16 ba_timeout, __le16 ba_seq_ctrl); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 0212c17c0343..7e5bd5c71360 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -465,6 +465,8 @@ static const char *cmdid2name(u16 cmdid) return "WMI_BCAST_DESC_RING_ADD_CMD"; case WMI_CFG_DEF_RX_OFFLOAD_CMDID: return "WMI_CFG_DEF_RX_OFFLOAD_CMD"; + case WMI_LINK_STATS_CMDID: + return "WMI_LINK_STATS_CMD"; default: return "Untracked CMD"; } @@ -599,6 +601,10 @@ static const char *eventid2name(u16 eventid) return "WMI_RX_DESC_RING_CFG_DONE_EVENT"; case WMI_CFG_DEF_RX_OFFLOAD_DONE_EVENTID: return "WMI_CFG_DEF_RX_OFFLOAD_DONE_EVENT"; + case WMI_LINK_STATS_CONFIG_DONE_EVENTID: + return "WMI_LINK_STATS_CONFIG_DONE_EVENT"; + case WMI_LINK_STATS_EVENTID: + return "WMI_LINK_STATS_EVENT"; default: return "Untracked EVENT"; } @@ -1372,6 +1378,130 @@ wmi_evt_sched_scan_result(struct wil6210_vif *vif, int id, void *d, int len) cfg80211_sched_scan_results(wiphy, 0); } +static void wil_link_stats_store_basic(struct wil6210_vif *vif, + struct wmi_link_stats_basic *basic) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + u8 cid = basic->cid; + struct wil_sta_info *sta; + + if (cid < 0 || cid >= WIL6210_MAX_CID) { + wil_err(wil, "invalid cid %d\n", cid); + return; + } + + sta = &wil->sta[cid]; + sta->fw_stats_basic = *basic; +} + +static void wil_link_stats_store_global(struct wil6210_vif *vif, + struct wmi_link_stats_global *global) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + + wil->fw_stats_global.stats = *global; +} + +static void wmi_link_stats_parse(struct wil6210_vif *vif, u64 tsf, + bool has_next, void *payload, + size_t payload_size) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + size_t hdr_size = sizeof(struct wmi_link_stats_record); + size_t stats_size, record_size, expected_size; + struct wmi_link_stats_record *hdr; + + if (payload_size < hdr_size) { + wil_err(wil, "link stats wrong event size %zu\n", payload_size); + return; + } + + while (payload_size >= hdr_size) { + hdr = payload; + stats_size = le16_to_cpu(hdr->record_size); + record_size = hdr_size + stats_size; + + if (payload_size < record_size) { + wil_err(wil, "link stats payload ended unexpectedly, size %zu < %zu\n", + payload_size, record_size); + return; + } + + switch (hdr->record_type_id) { + case WMI_LINK_STATS_TYPE_BASIC: + expected_size = sizeof(struct wmi_link_stats_basic); + if (stats_size < expected_size) { + wil_err(wil, "link stats invalid basic record size %zu < %zu\n", + stats_size, expected_size); + return; + } + if (vif->fw_stats_ready) { + /* clean old statistics */ + vif->fw_stats_tsf = 0; + vif->fw_stats_ready = 0; + } + + wil_link_stats_store_basic(vif, payload + hdr_size); + + if (!has_next) { + vif->fw_stats_tsf = tsf; + vif->fw_stats_ready = 1; + } + + break; + case WMI_LINK_STATS_TYPE_GLOBAL: + expected_size = sizeof(struct wmi_link_stats_global); + if (stats_size < sizeof(struct wmi_link_stats_global)) { + wil_err(wil, "link stats invalid global record size %zu < %zu\n", + stats_size, expected_size); + return; + } + + if (wil->fw_stats_global.ready) { + /* clean old statistics */ + wil->fw_stats_global.tsf = 0; + wil->fw_stats_global.ready = 0; + } + + wil_link_stats_store_global(vif, payload + hdr_size); + + if (!has_next) { + wil->fw_stats_global.tsf = tsf; + wil->fw_stats_global.ready = 1; + } + + break; + default: + break; + } + + /* skip to next record */ + payload += record_size; + payload_size -= record_size; + } +} + +static void +wmi_evt_link_stats(struct wil6210_vif *vif, int id, void *d, int len) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + struct wmi_link_stats_event *evt = d; + size_t payload_size; + + if (len < offsetof(struct wmi_link_stats_event, payload)) { + wil_err(wil, "stats event way too short %d\n", len); + return; + } + payload_size = le16_to_cpu(evt->payload_size); + if (len < sizeof(struct wmi_link_stats_event) + payload_size) { + wil_err(wil, "stats event too short %d\n", len); + return; + } + + wmi_link_stats_parse(vif, le64_to_cpu(evt->tsf), evt->has_next, + evt->payload, payload_size); +} + /** * Some events are ignored for purpose; and need not be interpreted as * "unhandled events" @@ -1409,6 +1539,7 @@ static const struct { {WMI_TOF_FTM_PER_DEST_RES_EVENTID, wmi_evt_per_dest_res}, {WMI_TOF_CHANNEL_INFO_EVENTID, wmi_evt_ignore}, {WMI_SCHED_SCAN_RESULT_EVENTID, wmi_evt_sched_scan_result}, + {WMI_LINK_STATS_EVENTID, wmi_evt_link_stats}, }; /* @@ -3453,3 +3584,37 @@ int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id) return 0; } + +int wmi_link_stats_cfg(struct wil6210_vif *vif, u32 type, u8 cid, u32 interval) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + struct wmi_link_stats_cmd cmd = { + .record_type_mask = cpu_to_le32(type), + .cid = cid, + .action = WMI_LINK_STATS_SNAPSHOT, + .interval_msec = cpu_to_le32(interval), + }; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_link_stats_config_done_event evt; + } __packed reply = { + .evt = {.status = WMI_FW_STATUS_FAILURE}, + }; + int rc; + + rc = wmi_call(wil, WMI_LINK_STATS_CMDID, vif->mid, &cmd, sizeof(cmd), + WMI_LINK_STATS_CONFIG_DONE_EVENTID, &reply, + sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS); + if (rc) { + wil_err(wil, "WMI_LINK_STATS_CMDID failed, rc %d\n", rc); + return rc; + } + + if (reply.evt.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "Link statistics config failed, status %d\n", + reply.evt.status); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 0c687fcbc66b..482c417cf081 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -1740,9 +1740,7 @@ enum wmi_link_stats_action { /* WMI_LINK_STATS_EVENT record identifiers */ enum wmi_link_stats_record_type { WMI_LINK_STATS_TYPE_BASIC = 0x01, - WMI_LINK_STATS_TYPE_MAC = 0x02, - WMI_LINK_STATS_TYPE_PHY = 0x04, - WMI_LINK_STATS_TYPE_OTA = 0x08, + WMI_LINK_STATS_TYPE_GLOBAL = 0x02, }; /* WMI_LINK_STATS_CMDID */ @@ -1756,7 +1754,7 @@ struct wmi_link_stats_cmd { /* wmi_link_stats_action_e */ u8 action; u8 reserved[6]; - /* for WMI_LINK_STATS_PERIODIC */ + /* range = 100 - 10000 */ __le32 interval_msec; } __packed; @@ -3808,32 +3806,59 @@ struct wmi_link_stats_config_done_event { /* WMI_LINK_STATS_EVENTID */ struct wmi_link_stats_event { + __le64 tsf; __le16 payload_size; u8 has_next; u8 reserved[5]; - /* a stream of records, e.g. wmi_link_stats_basic_s */ + /* a stream of wmi_link_stats_record_s */ u8 payload[0]; } __packed; -/* WMI_LINK_STATS_EVENT record struct */ -struct wmi_link_stats_basic { - /* WMI_LINK_STATS_TYPE_BASIC */ +/* WMI_LINK_STATS_EVENT */ +struct wmi_link_stats_record { + /* wmi_link_stats_record_type_e */ u8 record_type_id; + u8 reserved; + __le16 record_size; + u8 record[0]; +} __packed; + +/* WMI_LINK_STATS_TYPE_BASIC */ +struct wmi_link_stats_basic { u8 cid; - /* 0: fail; 1: OK; 2: retrying */ - u8 bf_status; s8 rssi; u8 sqi; + u8 bf_mcs; + u8 per_average; u8 selected_rfc; - __le16 bf_mcs; + u8 rx_effective_ant_num; + u8 my_rx_sector; + u8 my_tx_sector; + u8 other_rx_sector; + u8 other_tx_sector; + u8 reserved[7]; + /* 1/4 Db units */ + __le16 snr; __le32 tx_tpt; __le32 tx_goodput; __le32 rx_goodput; - __le16 my_rx_sector; - __le16 my_tx_sector; - __le16 other_rx_sector; - __le16 other_tx_sector; - __le32 reserved[2]; + __le32 bf_count; + __le32 rx_bcast_frames; +} __packed; + +/* WMI_LINK_STATS_TYPE_GLOBAL */ +struct wmi_link_stats_global { + /* all ack-able frames */ + __le32 rx_frames; + /* all ack-able frames */ + __le32 tx_frames; + __le32 rx_ba_frames; + __le32 tx_ba_frames; + __le32 tx_beacons; + __le32 rx_mic_errors; + __le32 rx_crc_errors; + __le32 tx_fail_no_ack; + u8 reserved[8]; } __packed; /* WMI_SET_GRANT_MCS_EVENTID */ -- GitLab From 0437600acae11fcc28ed4e0b765c631f186c3f81 Mon Sep 17 00:00:00 2001 From: Ahmad Masri Date: Tue, 24 Jul 2018 10:44:32 +0300 Subject: [PATCH 0615/1001] wil6210: allow scan on AP interface Scan is allowed only on client interfaces (STA/P2P). Allow scan on AP interface so that the AP can discover rouge or unauthorized neighbor APs. Change-Id: I8a473ff8f30d8c4745e2fc6477c4b8015c1663f7 Signed-off-by: Ahmad Masri Signed-off-by: Maya Erez Signed-off-by: Kalle Valo Git-commit: af2cd85e8dbd4241c21c0136d13e36b0043604ba Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Signed-off-by: Maya Erez --- drivers/net/wireless/ath/wil6210/cfg80211.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 0e254f073ca1..a8dc43432935 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -943,11 +943,12 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, wil_dbg_misc(wil, "scan: wdev=0x%p iftype=%d\n", wdev, wdev->iftype); - /* check we are client side */ + /* scan is supported on client interfaces and on AP interface */ switch (wdev->iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_DEVICE: + case NL80211_IFTYPE_AP: break; default: return -EOPNOTSUPP; -- GitLab From 7d8cea5740a027592acfb6675ada809e3484bd9e Mon Sep 17 00:00:00 2001 From: Hamad Kadmany Date: Tue, 24 Jul 2018 10:44:34 +0300 Subject: [PATCH 0616/1001] wil6210: increase firmware ready timeout Firmware ready event may take longer than current timeout in some scenarios, for example with multiple RFs connected where each requires an initial calibration. Increase the timeout to support these scenarios. Change-Id: Ie5d372fc3eb331c939265e0167b79f245d46379a Signed-off-by: Hamad Kadmany Signed-off-by: Maya Erez Signed-off-by: Kalle Valo Git-commit: 6ccae584014ef7074359eb4151086beef66ecfa9 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Signed-off-by: Maya Erez --- drivers/net/wireless/ath/wil6210/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index b40025be68a2..1b994e6162e6 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1331,7 +1331,7 @@ static int wil_get_otp_info(struct wil6210_priv *wil) static int wil_wait_for_fw_ready(struct wil6210_priv *wil) { - ulong to = msecs_to_jiffies(1000); + ulong to = msecs_to_jiffies(2000); ulong left = wait_for_completion_timeout(&wil->wmi_ready, to); if (0 == left) { -- GitLab From 586460f421705d7336720d2963231bf71db12e9c Mon Sep 17 00:00:00 2001 From: Ahmad Masri Date: Sun, 5 Aug 2018 10:18:47 +0300 Subject: [PATCH 0617/1001] wil6210: align to latest auto generated wmi.h Align to latest version of the auto generated wmi file describing the interface with FW. Change-Id: Ia4abfa8e16dc2c97265bb4fead9c6ecf2cce8522 Signed-off-by: Ahmad Masri Signed-off-by: Maya Erez Signed-off-by: Kalle Valo Git-commit: 6a363e8aa3828621eb4bc5e506f35f6ca9016d57 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Signed-off-by: Maya Erez --- drivers/net/wireless/ath/wil6210/wmi.h | 195 ++++++++++++++++++++++++- 1 file changed, 192 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 482c417cf081..30a7a61fbbf0 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -103,6 +103,8 @@ enum wmi_fw_capability { WMI_FW_CAPABILITY_FT_ROAMING = 21, WMI_FW_CAPABILITY_BACK_WIN_SIZE_64 = 22, WMI_FW_CAPABILITY_AMSDU = 23, + WMI_FW_CAPABILITY_RAW_MODE = 24, + WMI_FW_CAPABILITY_TX_REQ_EXT = 25, WMI_FW_CAPABILITY_MAX, }; @@ -137,6 +139,12 @@ enum wmi_command_id { WMI_SET_WSC_STATUS_CMDID = 0x41, WMI_PXMT_RANGE_CFG_CMDID = 0x42, WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x43, + WMI_RADAR_GENERAL_CONFIG_CMDID = 0x100, + WMI_RADAR_CONFIG_SELECT_CMDID = 0x101, + WMI_RADAR_PARAMS_CONFIG_CMDID = 0x102, + WMI_RADAR_SET_MODE_CMDID = 0x103, + WMI_RADAR_CONTROL_CMDID = 0x104, + WMI_RADAR_PCI_CONTROL_CMDID = 0x105, WMI_MEM_READ_CMDID = 0x800, WMI_MEM_WR_CMDID = 0x801, WMI_ECHO_CMDID = 0x803, @@ -177,6 +185,10 @@ enum wmi_command_id { WMI_SET_PCP_CHANNEL_CMDID = 0x829, WMI_GET_PCP_CHANNEL_CMDID = 0x82A, WMI_SW_TX_REQ_CMDID = 0x82B, + /* Event is shared between WMI_SW_TX_REQ_CMDID and + * WMI_SW_TX_REQ_EXT_CMDID + */ + WMI_SW_TX_REQ_EXT_CMDID = 0x82C, WMI_MLME_PUSH_CMDID = 0x835, WMI_BEAMFORMING_MGMT_CMDID = 0x836, WMI_BF_TXSS_MGMT_CMDID = 0x837, @@ -578,6 +590,109 @@ struct wmi_pxmt_snr2_range_cfg_cmd { s8 snr2range_arr[2]; } __packed; +/* WMI_RADAR_GENERAL_CONFIG_CMDID */ +struct wmi_radar_general_config_cmd { + /* Number of pulses (CIRs) in FW FIFO to initiate pulses transfer + * from FW to Host + */ + __le32 fifo_watermark; + /* In unit of us, in the range [100, 1000000] */ + __le32 t_burst; + /* Valid in the range [1, 32768], 0xFFFF means infinite */ + __le32 n_bursts; + /* In unit of 330Mhz clk, in the range [4, 2000]*330 */ + __le32 t_pulse; + /* In the range of [1,4096] */ + __le16 n_pulses; + /* Number of taps after cTap per CIR */ + __le16 n_samples; + /* Offset from the main tap (0 = zero-distance). In the range of [0, + * 255] + */ + u8 first_sample_offset; + /* Number of Pulses to average, 1, 2, 4, 8 */ + u8 pulses_to_avg; + /* Number of adjacent taps to average, 1, 2, 4, 8 */ + u8 samples_to_avg; + /* The index to config general params */ + u8 general_index; + u8 reserved[4]; +} __packed; + +/* WMI_RADAR_CONFIG_SELECT_CMDID */ +struct wmi_radar_config_select_cmd { + /* Select the general params index to use */ + u8 general_index; + u8 reserved[3]; + /* 0 means don't update burst_active_vector */ + __le32 burst_active_vector; + /* 0 means don't update pulse_active_vector */ + __le32 pulse_active_vector; +} __packed; + +/* WMI_RADAR_PARAMS_CONFIG_CMDID */ +struct wmi_radar_params_config_cmd { + /* The burst index selected to config */ + u8 burst_index; + /* 0-not active, 1-active */ + u8 burst_en; + /* The pulse index selected to config */ + u8 pulse_index; + /* 0-not active, 1-active */ + u8 pulse_en; + /* TX RF to use on current pulse */ + u8 tx_rfc_idx; + u8 tx_sector; + /* Offset from calibrated value.(expected to be 0)(value is row in + * Gain-LUT, not dB) + */ + s8 tx_rf_gain_comp; + /* expected to be 0 */ + s8 tx_bb_gain_comp; + /* RX RF to use on current pulse */ + u8 rx_rfc_idx; + u8 rx_sector; + /* Offset from calibrated value.(expected to be 0)(value is row in + * Gain-LUT, not dB) + */ + s8 rx_rf_gain_comp; + /* Value in dB.(expected to be 0) */ + s8 rx_bb_gain_comp; + /* Offset from calibrated value.(expected to be 0) */ + s8 rx_timing_offset; + u8 reserved[3]; +} __packed; + +/* WMI_RADAR_SET_MODE_CMDID */ +struct wmi_radar_set_mode_cmd { + /* 0-disable/1-enable */ + u8 enable; + /* enum wmi_channel */ + u8 channel; + /* In the range of [0,7], 0xff means use default */ + u8 tx_rfc_idx; + /* In the range of [0,7], 0xff means use default */ + u8 rx_rfc_idx; +} __packed; + +/* WMI_RADAR_CONTROL_CMDID */ +struct wmi_radar_control_cmd { + /* 0-stop/1-start */ + u8 start; + u8 reserved[3]; +} __packed; + +/* WMI_RADAR_PCI_CONTROL_CMDID */ +struct wmi_radar_pci_control_cmd { + /* pcie host buffer start address */ + __le64 base_addr; + /* pcie host control block address */ + __le64 control_block_addr; + /* pcie host buffer size */ + __le32 buffer_size; + __le32 reserved; +} __packed; + /* WMI_RF_MGMT_CMDID */ enum wmi_rf_mgmt_type { WMI_RF_MGMT_W_DISABLE = 0x00, @@ -717,7 +832,8 @@ struct wmi_pcp_start_cmd { u8 is_go; /* enum wmi_channel WMI_CHANNEL_9..WMI_CHANNEL_12 */ u8 edmg_channel; - u8 reserved[4]; + u8 raw_mode; + u8 reserved[3]; /* A-BFT length override if non-0 */ u8 abft_len; /* enum wmi_ap_sme_offload_mode_e */ @@ -738,6 +854,17 @@ struct wmi_sw_tx_req_cmd { u8 payload[0]; } __packed; +/* WMI_SW_TX_REQ_EXT_CMDID */ +struct wmi_sw_tx_req_ext_cmd { + u8 dst_mac[WMI_MAC_LEN]; + __le16 len; + __le16 duration_ms; + /* Channel to use, 0xFF for currently active channel */ + u8 channel; + u8 reserved[5]; + u8 payload[0]; +} __packed; + /* WMI_VRING_SWITCH_TIMING_CONFIG_CMDID */ struct wmi_vring_switch_timing_config_cmd { /* Set vring timing configuration: @@ -764,6 +891,7 @@ struct wmi_vring_cfg_schd { enum wmi_vring_cfg_encap_trans_type { WMI_VRING_ENC_TYPE_802_3 = 0x00, WMI_VRING_ENC_TYPE_NATIVE_WIFI = 0x01, + WMI_VRING_ENC_TYPE_NONE = 0x02, }; enum wmi_vring_cfg_ds_cfg { @@ -1175,8 +1303,8 @@ struct wmi_echo_cmd { } __packed; /* WMI_DEEP_ECHO_CMDID - * Check FW and ucode are alive - * Returned event: WMI_ECHO_RSP_EVENTID + * Check FW and uCode is alive + * Returned event: WMI_DEEP_ECHO_RSP_EVENTID */ struct wmi_deep_echo_cmd { __le32 value; @@ -1551,6 +1679,52 @@ struct wmi_set_multi_directed_omnis_config_event { u8 reserved[3]; } __packed; +/* WMI_RADAR_GENERAL_CONFIG_EVENTID */ +struct wmi_radar_general_config_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_RADAR_CONFIG_SELECT_EVENTID */ +struct wmi_radar_config_select_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; + /* In unit of bytes */ + __le32 fifo_size; + /* In unit of bytes */ + __le32 pulse_size; +} __packed; + +/* WMI_RADAR_PARAMS_CONFIG_EVENTID */ +struct wmi_radar_params_config_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_RADAR_SET_MODE_EVENTID */ +struct wmi_radar_set_mode_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_RADAR_CONTROL_EVENTID */ +struct wmi_radar_control_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_RADAR_PCI_CONTROL_EVENTID */ +struct wmi_radar_pci_control_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + /* WMI_SET_LONG_RANGE_CONFIG_CMDID */ struct wmi_set_long_range_config_cmd { __le32 reserved; @@ -1783,10 +1957,17 @@ enum wmi_event_id { WMI_REPORT_STATISTICS_EVENTID = 0x100B, WMI_FT_AUTH_STATUS_EVENTID = 0x100C, WMI_FT_REASSOC_STATUS_EVENTID = 0x100D, + WMI_RADAR_GENERAL_CONFIG_EVENTID = 0x1100, + WMI_RADAR_CONFIG_SELECT_EVENTID = 0x1101, + WMI_RADAR_PARAMS_CONFIG_EVENTID = 0x1102, + WMI_RADAR_SET_MODE_EVENTID = 0x1103, + WMI_RADAR_CONTROL_EVENTID = 0x1104, + WMI_RADAR_PCI_CONTROL_EVENTID = 0x1105, WMI_RD_MEM_RSP_EVENTID = 0x1800, WMI_FW_READY_EVENTID = 0x1801, WMI_EXIT_FAST_MEM_ACC_MODE_EVENTID = 0x200, WMI_ECHO_RSP_EVENTID = 0x1803, + WMI_DEEP_ECHO_RSP_EVENTID = 0x1804, /* deprecated */ WMI_FS_TUNE_DONE_EVENTID = 0x180A, /* deprecated */ @@ -1812,6 +1993,9 @@ enum wmi_event_id { WMI_DELBA_EVENTID = 0x1826, WMI_GET_SSID_EVENTID = 0x1828, WMI_GET_PCP_CHANNEL_EVENTID = 0x182A, + /* Event is shared between WMI_SW_TX_REQ_CMDID and + * WMI_SW_TX_REQ_EXT_CMDID + */ WMI_SW_TX_COMPLETE_EVENTID = 0x182B, WMI_BEAMFORMING_MGMT_DONE_EVENTID = 0x1836, WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837, @@ -2567,6 +2751,11 @@ struct wmi_echo_rsp_event { __le32 echoed_value; } __packed; +/* WMI_DEEP_ECHO_RSP_EVENTID */ +struct wmi_deep_echo_rsp_event { + __le32 echoed_value; +} __packed; + /* WMI_RF_PWR_ON_DELAY_RSP_EVENTID */ struct wmi_rf_pwr_on_delay_rsp_event { /* wmi_fw_status */ -- GitLab From 10391fb0adaec70c0bbf906956e1ce871ae928f3 Mon Sep 17 00:00:00 2001 From: Ahmad Masri Date: Tue, 24 Jul 2018 10:44:38 +0300 Subject: [PATCH 0618/1001] wil6210: off channel transmit management frames in AP mode Currently wil6210 ignores the channel field in the cfg80211_mgmt_tx_params struct for wil_cfg80211_ops mgmt_tx operation and sends all management frames on the serving channel. Add support for off-channel transmission of management frames (WIPHY_FLAG_OFFCHAN_TX) in AP mode. This is useful in enterprise APs for sending custom probe request frames. Change-Id: I0575a2d170c086cec2f60333dbf60f59d788446a Signed-off-by: Ahmad Masri Signed-off-by: Maya Erez Signed-off-by: Kalle Valo Git-commit: b698e2dfc24cd148ce32f622a20938037ebe06b7 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Signed-off-by: Maya Erez --- drivers/net/wireless/ath/wil6210/cfg80211.c | 47 ++++++++++++++--- drivers/net/wireless/ath/wil6210/main.c | 3 ++ drivers/net/wireless/ath/wil6210/wil6210.h | 2 + drivers/net/wireless/ath/wil6210/wmi.c | 56 +++++++++++++++++++++ 4 files changed, 101 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index a8dc43432935..6a4a3edbaa81 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1354,18 +1354,51 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, int rc; bool tx_status; - /* Note, currently we do not support the "wait" parameter, user-space - * must call remain_on_channel before mgmt_tx or listen on a channel - * another way (AP/PCP or connected station) - * in addition we need to check if specified "chan" argument is - * different from currently "listened" channel and fail if it is. + wil_dbg_misc(wil, "mgmt_tx: channel %d offchan %d, wait %d\n", + params->chan ? params->chan->hw_value : -1, + params->offchan, + params->wait); + + /* Note, currently we support the "wait" parameter only on AP mode. + * In other modes, user-space must call remain_on_channel before + * mgmt_tx or listen on a channel other than active one. */ - rc = wmi_mgmt_tx(vif, buf, len); - tx_status = (rc == 0); + if (params->chan && params->chan->hw_value == 0) { + wil_err(wil, "invalid channel\n"); + return -EINVAL; + } + + if (wdev->iftype != NL80211_IFTYPE_AP) { + wil_dbg_misc(wil, + "send WMI_SW_TX_REQ_CMDID on non-AP interfaces\n"); + rc = wmi_mgmt_tx(vif, buf, len); + goto out; + } + if (!params->chan || params->chan->hw_value == vif->channel) { + wil_dbg_misc(wil, + "send WMI_SW_TX_REQ_CMDID for on-channel\n"); + rc = wmi_mgmt_tx(vif, buf, len); + goto out; + } + + if (params->offchan == 0) { + wil_err(wil, + "invalid channel params: current %d requested %d, off-channel not allowed\n", + vif->channel, params->chan->hw_value); + return -EBUSY; + } + + /* use the wmi_mgmt_tx_ext only on AP mode and off-channel */ + rc = wmi_mgmt_tx_ext(vif, buf, len, params->chan->hw_value, + params->wait); + +out: + tx_status = (rc == 0); cfg80211_mgmt_tx_status(wdev, cookie ? *cookie : 0, buf, len, tx_status, GFP_KERNEL); + return rc; } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 1b994e6162e6..fb0da63c6322 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1134,6 +1134,9 @@ void wil_refresh_fw_capabilities(struct wil6210_priv *wil) wiphy->max_sched_scan_plans = WMI_MAX_PLANS_NUM; } + if (test_bit(WMI_FW_CAPABILITY_TX_REQ_EXT, wil->fw_capabilities)) + wiphy->flags |= WIPHY_FLAG_OFFCHAN_TX; + if (wil->platform_ops.set_features) { features = (test_bit(WMI_FW_CAPABILITY_REF_CLOCK_CONTROL, wil->fw_capabilities) && diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 4a5a7d375b0c..766c986e0fb7 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1406,6 +1406,8 @@ int wmi_start_sched_scan(struct wil6210_priv *wil, struct cfg80211_sched_scan_request *request); int wmi_stop_sched_scan(struct wil6210_priv *wil); int wmi_mgmt_tx(struct wil6210_vif *vif, const u8 *buf, size_t len); +int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len, + u8 channel, u16 duration_ms); int wil_wmi2spec_ch(u8 wmi_ch, u8 *spec_ch); int wil_spec2wmi_ch(u8 spec_ch, u8 *wmi_ch); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 7e5bd5c71360..ba0efb116876 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -467,6 +467,8 @@ static const char *cmdid2name(u16 cmdid) return "WMI_CFG_DEF_RX_OFFLOAD_CMD"; case WMI_LINK_STATS_CMDID: return "WMI_LINK_STATS_CMD"; + case WMI_SW_TX_REQ_EXT_CMDID: + return "WMI_SW_TX_REQ_EXT_CMDID"; default: return "Untracked CMD"; } @@ -3330,6 +3332,60 @@ int wmi_mgmt_tx(struct wil6210_vif *vif, const u8 *buf, size_t len) return rc; } +int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len, + u8 channel, u16 duration_ms) +{ + size_t total; + struct wil6210_priv *wil = vif_to_wil(vif); + struct ieee80211_mgmt *mgmt_frame = (void *)buf; + struct wmi_sw_tx_req_ext_cmd *cmd; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_sw_tx_complete_event evt; + } __packed evt = { + .evt = {.status = WMI_FW_STATUS_FAILURE}, + }; + int rc; + + wil_dbg_wmi(wil, "mgmt_tx_ext mid %d channel %d duration %d\n", + vif->mid, channel, duration_ms); + wil_hex_dump_wmi("mgmt_tx_ext frame ", DUMP_PREFIX_OFFSET, 16, 1, buf, + len, true); + + if (len < sizeof(struct ieee80211_hdr_3addr)) { + wil_err(wil, "short frame. len %zu\n", len); + return -EINVAL; + } + + total = sizeof(*cmd) + len; + if (total < len) { + wil_err(wil, "mgmt_tx_ext invalid len %zu\n", len); + return -EINVAL; + } + + cmd = kzalloc(total, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN); + cmd->len = cpu_to_le16(len); + memcpy(cmd->payload, buf, len); + cmd->channel = channel - 1; + cmd->duration_ms = cpu_to_le16(duration_ms); + + rc = wmi_call(wil, WMI_SW_TX_REQ_EXT_CMDID, vif->mid, cmd, total, + WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); + if (!rc && evt.evt.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "mgmt_tx_ext failed with status %d\n", + evt.evt.status); + rc = -EINVAL; + } + + kfree(cmd); + + return rc; +} + int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id) { int rc; -- GitLab From 9c0e2bd5050c5607b3fdadf1351383efcf96e493 Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Thu, 2 Aug 2018 12:50:43 +0530 Subject: [PATCH 0619/1001] defconfig: qcs405: Remove symlink to defconfigs in vendor subdirectory Kernel configuration files are moved under vendor subdirectory. Remove the symbolic link Change-Id: Ie95ad70c254d122d6aea78cfa56447380f32ef41 Signed-off-by: Avaneesh Kumar Dwivedi --- arch/arm/configs/qcs405-perf_defconfig | 1 - arch/arm/configs/qcs405_defconfig | 1 - arch/arm64/configs/qcs405-perf_defconfig | 1 - arch/arm64/configs/qcs405_defconfig | 1 - 4 files changed, 4 deletions(-) delete mode 120000 arch/arm/configs/qcs405-perf_defconfig delete mode 120000 arch/arm/configs/qcs405_defconfig delete mode 120000 arch/arm64/configs/qcs405-perf_defconfig delete mode 120000 arch/arm64/configs/qcs405_defconfig diff --git a/arch/arm/configs/qcs405-perf_defconfig b/arch/arm/configs/qcs405-perf_defconfig deleted file mode 120000 index 03b88505560a..000000000000 --- a/arch/arm/configs/qcs405-perf_defconfig +++ /dev/null @@ -1 +0,0 @@ -vendor/qcs405-perf_defconfig \ No newline at end of file diff --git a/arch/arm/configs/qcs405_defconfig b/arch/arm/configs/qcs405_defconfig deleted file mode 120000 index 372fd3e54d88..000000000000 --- a/arch/arm/configs/qcs405_defconfig +++ /dev/null @@ -1 +0,0 @@ -vendor/qcs405_defconfig \ No newline at end of file diff --git a/arch/arm64/configs/qcs405-perf_defconfig b/arch/arm64/configs/qcs405-perf_defconfig deleted file mode 120000 index 03b88505560a..000000000000 --- a/arch/arm64/configs/qcs405-perf_defconfig +++ /dev/null @@ -1 +0,0 @@ -vendor/qcs405-perf_defconfig \ No newline at end of file diff --git a/arch/arm64/configs/qcs405_defconfig b/arch/arm64/configs/qcs405_defconfig deleted file mode 120000 index 372fd3e54d88..000000000000 --- a/arch/arm64/configs/qcs405_defconfig +++ /dev/null @@ -1 +0,0 @@ -vendor/qcs405_defconfig \ No newline at end of file -- GitLab From b896907e90a5fa3b286a925db31848fb6813cf14 Mon Sep 17 00:00:00 2001 From: Rajesh Kemisetti Date: Tue, 20 Dec 2016 10:47:38 +0530 Subject: [PATCH 0620/1001] defconfig: msm: Enable Cx ipeak driver for sdmsteppe Enable common Cx ipeak driver for various multimedia clients like GPU, MDP, Venus and Camera modules. This is needed to handle Cx ipeak limit on sdmsteppe. Change-Id: I187f9f9205025a637d46dca07a3184c8bf8a7912 Signed-off-by: samit vats --- arch/arm64/configs/vendor/sdmsteppe-perf_defconfig | 1 + arch/arm64/configs/vendor/sdmsteppe_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig index afcb03ddfed3..b152ba3043a9 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig @@ -524,6 +524,7 @@ CONFIG_QCOM_FSA4480_I2C=y CONFIG_MSM_PERFORMANCE=y CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_QCOM_SMP2P_SLEEPSTATE=y +CONFIG_QCOM_CX_IPEAK=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y diff --git a/arch/arm64/configs/vendor/sdmsteppe_defconfig b/arch/arm64/configs/vendor/sdmsteppe_defconfig index 04247ca6e677..82a3ff062b10 100644 --- a/arch/arm64/configs/vendor/sdmsteppe_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe_defconfig @@ -545,6 +545,7 @@ CONFIG_QCOM_FSA4480_I2C=y CONFIG_MSM_PERFORMANCE=y CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_QCOM_SMP2P_SLEEPSTATE=y +CONFIG_QCOM_CX_IPEAK=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y -- GitLab From af21981a4e7d9fd5c82ab6ba5835f384bd1057ae Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Mon, 30 Jul 2018 12:10:06 -0700 Subject: [PATCH 0621/1001] power: smb5-lib: Fix USBIN Under-Voltage Lock-out issue Sometimes, the USB input under-voltage is easy to get triggered when there is a large cable IR drop, like when QC2/3 supplies 3A ICL at 5V when battery voltage is high. Reduce the AICL collapse deglitch filter time and step time so that the ICL can be lowered before the ASHDN is deglitched into UVLO and turns off the switcher. Change-Id: I72fd1a6549d6ea89b5c9f7ac05bc424d2bf142eb Signed-off-by: Harry Yang --- drivers/power/supply/qcom/qpnp-smb5.c | 7 +++++++ drivers/power/supply/qcom/smb5-reg.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index d4f72a380e4f..b3c566f11ad5 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -1553,6 +1553,13 @@ static int smb5_configure_typec(struct smb_charger *chg) return rc; } + rc = smblib_masked_write(chg, USBIN_LOAD_CFG_REG, + USBIN_IN_COLLAPSE_GF_SEL_MASK | USBIN_AICL_STEP_TIMING_SEL_MASK, + 0); + if (rc < 0) + dev_err(chg->dev, + "Couldn't set USBIN_LOAD_CFG_REG rc=%d\n", rc); + return rc; } diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index 902396d14c33..a4251d7d7568 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -258,6 +258,8 @@ enum { #define USBIN_LOAD_CFG_REG (USBIN_BASE + 0x65) #define ICL_OVERRIDE_AFTER_APSD_BIT BIT(4) +#define USBIN_AICL_STEP_TIMING_SEL_MASK GENMASK(3, 2) +#define USBIN_IN_COLLAPSE_GF_SEL_MASK GENMASK(1, 0) #define USBIN_ICL_OPTIONS_REG (USBIN_BASE + 0x66) #define CFG_USB3P0_SEL_BIT BIT(2) -- GitLab From 43d7c954b22e87f16a8304518d776f454f584578 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Wed, 18 Jul 2018 14:29:51 -0700 Subject: [PATCH 0622/1001] scsi: qla2xxx: Fix unintialized List head crash commit e3dde080ebbdbb4bda8eee35d770714fee8c59ac upstream. In case of IOCB Queue full or system where memory is low and driver receives large number of RSCN storm, the stale sp pointer can stay on gpnid_list resulting in page_fault. This patch fixes this issue by initializing the sp->elem list head and removing sp->elem before memory is freed. Following stack trace is seen 9 [ffff987b37d1bc60] page_fault at ffffffffad516768 [exception RIP: qla24xx_async_gpnid+496] 10 [ffff987b37d1bd10] qla24xx_async_gpnid at ffffffffc039866d [qla2xxx] 11 [ffff987b37d1bd80] qla2x00_do_work at ffffffffc036169c [qla2xxx] 12 [ffff987b37d1be38] qla2x00_do_dpc_all_vps at ffffffffc03adfed [qla2xxx] 13 [ffff987b37d1be78] qla2x00_do_dpc at ffffffffc036458a [qla2xxx] 14 [ffff987b37d1bec8] kthread at ffffffffacebae31 Fixes: 2d73ac6102d9 ("scsi: qla2xxx: Serialize GPNID for multiple RSCN") Cc: # v4.17+ Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla2xxx/qla_gs.c | 4 ++++ drivers/scsi/qla2xxx/qla_inline.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 59ecc4eda6cd..2a19ec0660cb 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3368,6 +3368,10 @@ int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id_t *id) return rval; done_free_sp: + spin_lock_irqsave(&vha->hw->vport_slock, flags); + list_del(&sp->elem); + spin_unlock_irqrestore(&vha->hw->vport_slock, flags); + if (sp->u.iocb_cmd.u.ctarg.req) { dma_free_coherent(&vha->hw->pdev->dev, sizeof(struct ct_sns_pkt), diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 9a2c86eacf44..3f5a0f0f8b62 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -221,6 +221,8 @@ qla2xxx_get_qpair_sp(struct qla_qpair *qpair, fc_port_t *fcport, gfp_t flag) sp->fcport = fcport; sp->iocbs = 1; sp->vha = qpair->vha; + INIT_LIST_HEAD(&sp->elem); + done: if (!sp) QLA_QPAIR_MARK_NOT_BUSY(qpair); -- GitLab From 01cda405c88b5ce1ff8c7d4006ec23ade2b0a507 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Wed, 18 Jul 2018 14:29:52 -0700 Subject: [PATCH 0623/1001] scsi: qla2xxx: Fix NPIV deletion by calling wait_for_sess_deletion commit efa93f48fa9d423fda166bc3b6c0cbb09682492e upstream. Add wait for session deletion to finish before freeing an NPIV scsi host. Fixes: 726b85487067 ("qla2xxx: Add framework for async fabric discovery") Cc: Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla2xxx/qla_attr.c | 1 + drivers/scsi/qla2xxx/qla_gbl.h | 1 + drivers/scsi/qla2xxx/qla_mid.c | 5 +++++ drivers/scsi/qla2xxx/qla_os.c | 2 +- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 9ce28c4f9812..b09d29931393 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -2142,6 +2142,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) msleep(1000); qla24xx_disable_vp(vha); + qla2x00_wait_for_sess_deletion(vha); vha->flags.delete_progress = 1; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index f852ca60c49f..89706341514e 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -200,6 +200,7 @@ void qla2x00_handle_login_done_event(struct scsi_qla_host *, fc_port_t *, uint16_t *); int qla24xx_post_gnl_work(struct scsi_qla_host *, fc_port_t *); int qla24xx_async_abort_cmd(srb_t *); +void qla2x00_wait_for_sess_deletion(scsi_qla_host_t *); /* * Global Functions in qla_mid.c source file. diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index d77dde89118e..375a88e18afe 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -152,10 +152,15 @@ qla24xx_disable_vp(scsi_qla_host_t *vha) { unsigned long flags; int ret; + fc_port_t *fcport; ret = qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL); atomic_set(&vha->loop_state, LOOP_DOWN); atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); + list_for_each_entry(fcport, &vha->vp_fcports, list) + fcport->logout_on_delete = 0; + + qla2x00_mark_all_devices_lost(vha, 0); /* Remove port id from vp target map */ spin_lock_irqsave(&vha->hw->vport_slock, flags); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 1be76695e692..6dbc2ab9090b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1136,7 +1136,7 @@ static inline int test_fcport_count(scsi_qla_host_t *vha) * qla2x00_wait_for_sess_deletion can only be called from remove_one. * it has dependency on UNLOADING flag to stop device discovery */ -static void +void qla2x00_wait_for_sess_deletion(scsi_qla_host_t *vha) { qla2x00_mark_all_devices_lost(vha, 0); -- GitLab From f70766f1338d534638914388529cd6a7263db858 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Wed, 18 Jul 2018 14:29:54 -0700 Subject: [PATCH 0624/1001] scsi: qla2xxx: Fix ISP recovery on unload commit b08abbd9f5996309f021684f9ca74da30dcca36a upstream. During unload process, the chip can encounter problem where a FW dump would be captured. For this case, the full reset sequence will be skip to bring the chip back to full operational state. Fixes: e315cd28b9ef ("[SCSI] qla2xxx: Code changes for qla data structure refactoring") Cc: Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla2xxx/qla_os.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 6dbc2ab9090b..7d7fb5bbb600 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -5794,8 +5794,9 @@ qla2x00_do_dpc(void *data) set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); } - if (test_and_clear_bit(ISP_ABORT_NEEDED, - &base_vha->dpc_flags)) { + if (test_and_clear_bit + (ISP_ABORT_NEEDED, &base_vha->dpc_flags) && + !test_bit(UNLOADING, &base_vha->dpc_flags)) { ql_dbg(ql_dbg_dpc, base_vha, 0x4007, "ISP abort scheduled.\n"); -- GitLab From a96feef5b07141f304a3e933da2abbd8dfdf5bf1 Mon Sep 17 00:00:00 2001 From: Anil Gurumurthy Date: Wed, 18 Jul 2018 14:29:55 -0700 Subject: [PATCH 0625/1001] scsi: qla2xxx: Return error when TMF returns commit b4146c4929ef61d5afca011474d59d0918a0cd82 upstream. Propagate the task management completion status properly to avoid unnecessary waits for commands to complete. Fixes: faef62d13463 ("[SCSI] qla2xxx: Fix Task Management command asynchronous handling") Cc: Signed-off-by: Anil Gurumurthy Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla2xxx/qla_init.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index bcde6130f121..1d42d38f5a45 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1326,11 +1326,10 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun, wait_for_completion(&tm_iocb->u.tmf.comp); - rval = tm_iocb->u.tmf.comp_status == CS_COMPLETE ? - QLA_SUCCESS : QLA_FUNCTION_FAILED; + rval = tm_iocb->u.tmf.data; - if ((rval != QLA_SUCCESS) || tm_iocb->u.tmf.data) { - ql_dbg(ql_dbg_taskm, vha, 0x8030, + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x8030, "TM IOCB failed (%x).\n", rval); } -- GitLab From a6d9dacf4e4487192410435cb1e063c3b79b18c7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 3 Aug 2018 14:44:59 +0200 Subject: [PATCH 0626/1001] genirq: Make force irq threading setup more robust commit d1f0301b3333eef5efbfa1fe0f0edbea01863d5d upstream. The support of force threading interrupts which are set up with both a primary and a threaded handler wreckaged the setup of regular requested threaded interrupts (primary handler == NULL). The reason is that it does not check whether the primary handler is set to the default handler which wakes the handler thread. Instead it replaces the thread handler with the primary handler as it would do with force threaded interrupts which have been requested via request_irq(). So both the primary and the thread handler become the same which then triggers the warnon that the thread handler tries to wakeup a not configured secondary thread. Fortunately this only happens when the driver omits the IRQF_ONESHOT flag when requesting the threaded interrupt, which is normaly caught by the sanity checks when force irq threading is disabled. Fix it by skipping the force threading setup when a regular threaded interrupt is requested. As a consequence the interrupt request which lacks the IRQ_ONESHOT flag is rejected correctly instead of silently wreckaging it. Fixes: 2a1d3ab8986d ("genirq: Handle force threading of irqs with primary and thread handler") Reported-by: Kurt Kanzenbach Signed-off-by: Thomas Gleixner Tested-by: Kurt Kanzenbach Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- kernel/irq/manage.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index b02caa442776..069311541577 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1030,6 +1030,13 @@ static int irq_setup_forced_threading(struct irqaction *new) if (new->flags & (IRQF_NO_THREAD | IRQF_PERCPU | IRQF_ONESHOT)) return 0; + /* + * No further action required for interrupts which are requested as + * threaded interrupts already + */ + if (new->handler == irq_default_primary_handler) + return 0; + new->flags |= IRQF_ONESHOT; /* @@ -1037,7 +1044,7 @@ static int irq_setup_forced_threading(struct irqaction *new) * thread handler. We force thread them as well by creating a * secondary action. */ - if (new->handler != irq_default_primary_handler && new->thread_fn) { + if (new->handler && new->thread_fn) { /* Allocate the secondary action */ new->secondary = kzalloc(sizeof(struct irqaction), GFP_KERNEL); if (!new->secondary) -- GitLab From e5bcbedadfd9646c862062071ade0612a78a70e3 Mon Sep 17 00:00:00 2001 From: Anna-Maria Gleixner Date: Tue, 31 Jul 2018 18:13:58 +0200 Subject: [PATCH 0627/1001] nohz: Fix local_timer_softirq_pending() commit 80d20d35af1edd632a5e7a3b9c0ab7ceff92769e upstream. local_timer_softirq_pending() checks whether the timer softirq is pending with: local_softirq_pending() & TIMER_SOFTIRQ. This is wrong because TIMER_SOFTIRQ is the softirq number and not a bitmask. So the test checks for the wrong bit. Use BIT(TIMER_SOFTIRQ) instead. Fixes: 5d62c183f9e9 ("nohz: Prevent a timer interrupt storm in tick_nohz_stop_sched_tick()") Signed-off-by: Anna-Maria Gleixner Signed-off-by: Thomas Gleixner Reviewed-by: Paul E. McKenney Reviewed-by: Daniel Bristot de Oliveira Acked-by: Frederic Weisbecker Cc: bigeasy@linutronix.de Cc: peterz@infradead.org Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/20180731161358.29472-1-anna-maria@linutronix.de Signed-off-by: Greg Kroah-Hartman --- kernel/time/tick-sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index bb2af74e6b62..ea3c062e7e1c 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -676,7 +676,7 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) static inline bool local_timer_softirq_pending(void) { - return local_softirq_pending() & TIMER_SOFTIRQ; + return local_softirq_pending() & BIT(TIMER_SOFTIRQ); } static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, -- GitLab From 2d898915ccf4838c04531c51a598469e921a5eb5 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 3 Aug 2018 15:31:34 +0200 Subject: [PATCH 0628/1001] nohz: Fix missing tick reprogram when interrupting an inline softirq commit 0a0e0829f990120cef165bbb804237f400953ec2 upstream. The full nohz tick is reprogrammed in irq_exit() only if the exit is not in a nesting interrupt. This stands as an optimization: whether a hardirq or a softirq is interrupted, the tick is going to be reprogrammed when necessary at the end of the inner interrupt, with even potential new updates on the timer queue. When soft interrupts are interrupted, it's assumed that they are executing on the tail of an interrupt return. In that case tick_nohz_irq_exit() is called after softirq processing to take care of the tick reprogramming. But the assumption is wrong: softirqs can be processed inline as well, ie: outside of an interrupt, like in a call to local_bh_enable() or from ksoftirqd. Inline softirqs don't reprogram the tick once they are done, as opposed to interrupt tail softirq processing. So if a tick interrupts an inline softirq processing, the next timer will neither be reprogrammed from the interrupting tick's irq_exit() nor after the interrupted softirq processing. This situation may leave the tick unprogrammed while timers are armed. To fix this, simply keep reprogramming the tick even if a softirq has been interrupted. That can be optimized further, but for now correctness is more important. Note that new timers enqueued in nohz_full mode after a softirq gets interrupted will still be handled just fine through self-IPIs triggered by the timer code. Reported-by: Anna-Maria Gleixner Signed-off-by: Frederic Weisbecker Signed-off-by: Thomas Gleixner Tested-by: Anna-Maria Gleixner Cc: stable@vger.kernel.org # 4.14+ Link: https://lkml.kernel.org/r/1533303094-15855-1-git-send-email-frederic@kernel.org Signed-off-by: Greg Kroah-Hartman --- kernel/softirq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/softirq.c b/kernel/softirq.c index e89c3b0cff6d..f40ac7191257 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -382,7 +382,7 @@ static inline void tick_irq_exit(void) /* Make sure that timer wheel updates are propagated */ if ((idle_cpu(cpu) && !need_resched()) || tick_nohz_full_cpu(cpu)) { - if (!in_interrupt()) + if (!in_irq()) tick_nohz_irq_exit(); } #endif -- GitLab From 09901e570c9e9d6bf302716edd3a5a14417a0657 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Sun, 5 Aug 2018 01:35:53 +0100 Subject: [PATCH 0629/1001] netlink: Don't shift on 64 for ngroups commit 91874ecf32e41b5d86a4cb9d60e0bee50d828058 upstream. It's legal to have 64 groups for netlink_sock. As user-supplied nladdr->nl_groups is __u32, it's possible to subscribe only to first 32 groups. The check for correctness of .bind() userspace supplied parameter is done by applying mask made from ngroups shift. Which broke Android as they have 64 groups and the shift for mask resulted in an overflow. Fixes: 61f4b23769f0 ("netlink: Don't shift with UB on nlk->ngroups") Cc: "David S. Miller" Cc: Herbert Xu Cc: Steffen Klassert Cc: netdev@vger.kernel.org Cc: stable@vger.kernel.org Reported-and-Tested-by: Nathan Chancellor Signed-off-by: Dmitry Safonov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/netlink/af_netlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 68c9d1833b95..c67abda5d639 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -981,8 +981,8 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, if (nlk->ngroups == 0) groups = 0; - else - groups &= (1ULL << nlk->ngroups) - 1; + else if (nlk->ngroups < 8*sizeof(groups)) + groups &= (1UL << nlk->ngroups) - 1; bound = nlk->bound; if (bound) { -- GitLab From dd69abaccbf78ba645ba46604a59b944695a2cb8 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 8 Jul 2018 19:35:02 -0400 Subject: [PATCH 0630/1001] ext4: fix false negatives *and* false positives in ext4_check_descriptors() commit 44de022c4382541cebdd6de4465d1f4f465ff1dd upstream. Ext4_check_descriptors() was getting called before s_gdb_count was initialized. So for file systems w/o the meta_bg feature, allocation bitmaps could overlap the block group descriptors and ext4 wouldn't notice. For file systems with the meta_bg feature enabled, there was a fencepost error which would cause the ext4_check_descriptors() to incorrectly believe that the block allocation bitmap overlaps with the block group descriptor blocks, and it would reject the mount. Fix both of these problems. Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Benjamin Gilbert Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 6b0c1ea95196..f30d2bf40471 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2301,7 +2301,7 @@ static int ext4_check_descriptors(struct super_block *sb, struct ext4_sb_info *sbi = EXT4_SB(sb); ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); ext4_fsblk_t last_block; - ext4_fsblk_t last_bg_block = sb_block + ext4_bg_num_gdb(sb, 0) + 1; + ext4_fsblk_t last_bg_block = sb_block + ext4_bg_num_gdb(sb, 0); ext4_fsblk_t block_bitmap; ext4_fsblk_t inode_bitmap; ext4_fsblk_t inode_table; @@ -4038,13 +4038,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) goto failed_mount2; } } + sbi->s_gdb_count = db_count; if (!ext4_check_descriptors(sb, logical_sb_block, &first_not_zeroed)) { ext4_msg(sb, KERN_ERR, "group descriptors corrupted!"); ret = -EFSCORRUPTED; goto failed_mount2; } - sbi->s_gdb_count = db_count; get_random_bytes(&sbi->s_next_generation, sizeof(u32)); spin_lock_init(&sbi->s_next_gen_lock); -- GitLab From ff28e5cc58c2015ae65ad0070a3c90898f69aa3b Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Thu, 14 Sep 2017 16:50:14 +0200 Subject: [PATCH 0631/1001] ACPI / PCI: Bail early in acpi_pci_add_bus() if there is no ACPI handle commit a0040c0145945d3bd203df8fa97f6dfa819f3f7d upstream. Hyper-V instances support PCI pass-through which is implemented through PV pci-hyperv driver. When a device is passed through, a new root PCI bus is created in the guest. The bus sits on top of VMBus and has no associated information in ACPI. acpi_pci_add_bus() in this case proceeds all the way to acpi_evaluate_dsm(), which reports ACPI: \: failed to evaluate _DSM (0x1001) While acpi_pci_slot_enumerate() and acpiphp_enumerate_slots() are protected against ACPI_HANDLE() being NULL and do nothing, acpi_evaluate_dsm() is not and gives us the error. It seems the correct fix is to not do anything in acpi_pci_add_bus() in such cases. Signed-off-by: Vitaly Kuznetsov Signed-off-by: Bjorn Helgaas Cc: Sinan Kaya Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index a8da543b3814..4708eb9df71b 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -624,7 +624,7 @@ void acpi_pci_add_bus(struct pci_bus *bus) union acpi_object *obj; struct pci_host_bridge *bridge; - if (acpi_pci_disabled || !bus->bridge) + if (acpi_pci_disabled || !bus->bridge || !ACPI_HANDLE(bus->bridge)) return; acpi_pci_slot_enumerate(bus); -- GitLab From 60baabc37bc18323e6346d28fd7b70729e345703 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sat, 14 Jul 2018 01:28:15 +0900 Subject: [PATCH 0632/1001] ring_buffer: tracing: Inherit the tracing setting to next ring buffer commit 73c8d8945505acdcbae137c2e00a1232e0be709f upstream. Maintain the tracing on/off setting of the ring_buffer when switching to the trace buffer snapshot. Taking a snapshot is done by swapping the backup ring buffer (max_tr_buffer). But since the tracing on/off setting is defined by the ring buffer, when swapping it, the tracing on/off setting can also be changed. This causes a strange result like below: /sys/kernel/debug/tracing # cat tracing_on 1 /sys/kernel/debug/tracing # echo 0 > tracing_on /sys/kernel/debug/tracing # cat tracing_on 0 /sys/kernel/debug/tracing # echo 1 > snapshot /sys/kernel/debug/tracing # cat tracing_on 1 /sys/kernel/debug/tracing # echo 1 > snapshot /sys/kernel/debug/tracing # cat tracing_on 0 We don't touch tracing_on, but snapshot changes tracing_on setting each time. This is an anomaly, because user doesn't know that each "ring_buffer" stores its own tracing-enable state and the snapshot is done by swapping ring buffers. Link: http://lkml.kernel.org/r/153149929558.11274.11730609978254724394.stgit@devbox Cc: Ingo Molnar Cc: Shuah Khan Cc: Tom Zanussi Cc: Hiraku Toyooka Cc: stable@vger.kernel.org Fixes: debdd57f5145 ("tracing: Make a snapshot feature available from userspace") Signed-off-by: Masami Hiramatsu [ Updated commit log and comment in the code ] Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- include/linux/ring_buffer.h | 1 + kernel/trace/ring_buffer.c | 16 ++++++++++++++++ kernel/trace/trace.c | 6 ++++++ 3 files changed, 23 insertions(+) diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h index 289e4d54e3e0..5caa062a02b2 100644 --- a/include/linux/ring_buffer.h +++ b/include/linux/ring_buffer.h @@ -160,6 +160,7 @@ void ring_buffer_record_enable(struct ring_buffer *buffer); void ring_buffer_record_off(struct ring_buffer *buffer); void ring_buffer_record_on(struct ring_buffer *buffer); int ring_buffer_record_is_on(struct ring_buffer *buffer); +int ring_buffer_record_is_set_on(struct ring_buffer *buffer); void ring_buffer_record_disable_cpu(struct ring_buffer *buffer, int cpu); void ring_buffer_record_enable_cpu(struct ring_buffer *buffer, int cpu); diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 36f018b15392..fd7809004297 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -3109,6 +3109,22 @@ int ring_buffer_record_is_on(struct ring_buffer *buffer) return !atomic_read(&buffer->record_disabled); } +/** + * ring_buffer_record_is_set_on - return true if the ring buffer is set writable + * @buffer: The ring buffer to see if write is set enabled + * + * Returns true if the ring buffer is set writable by ring_buffer_record_on(). + * Note that this does NOT mean it is in a writable state. + * + * It may return true when the ring buffer has been disabled by + * ring_buffer_record_disable(), as that is a temporary disabling of + * the ring buffer. + */ +int ring_buffer_record_is_set_on(struct ring_buffer *buffer) +{ + return !(atomic_read(&buffer->record_disabled) & RB_BUFFER_OFF); +} + /** * ring_buffer_record_disable_cpu - stop all writes into the cpu_buffer * @buffer: The ring buffer to stop writes to. diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index e268750bd4ad..20919489883f 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -1366,6 +1366,12 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu) arch_spin_lock(&tr->max_lock); + /* Inherit the recordable setting from trace_buffer */ + if (ring_buffer_record_is_set_on(tr->trace_buffer.buffer)) + ring_buffer_record_on(tr->max_buffer.buffer); + else + ring_buffer_record_off(tr->max_buffer.buffer); + buf = tr->trace_buffer.buffer; tr->trace_buffer.buffer = tr->max_buffer.buffer; tr->max_buffer.buffer = buf; -- GitLab From ea464580fef7a334d19f27538bc690168a821b5d Mon Sep 17 00:00:00 2001 From: Esben Haabendal Date: Mon, 9 Jul 2018 11:43:01 +0200 Subject: [PATCH 0633/1001] i2c: imx: Fix reinit_completion() use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 9f9e3e0d4dd3338b3f3dde080789f71901e1e4ff upstream. Make sure to call reinit_completion() before dma is started to avoid race condition where reinit_completion() is called after complete() and before wait_for_completion_timeout(). Signed-off-by: Esben Haabendal Fixes: ce1a78840ff7 ("i2c: imx: add DMA support for freescale i2c driver") Reviewed-by: Uwe Kleine-König Signed-off-by: Wolfram Sang Cc: stable@kernel.org Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-imx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index f96830ffd9f1..75c6b98585ba 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -376,6 +376,7 @@ static int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx, goto err_desc; } + reinit_completion(&dma->cmd_complete); txdesc->callback = i2c_imx_dma_callback; txdesc->callback_param = i2c_imx; if (dma_submit_error(dmaengine_submit(txdesc))) { @@ -619,7 +620,6 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, * The first byte must be transmitted by the CPU. */ imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR); - reinit_completion(&i2c_imx->dma->cmd_complete); time_left = wait_for_completion_timeout( &i2c_imx->dma->cmd_complete, msecs_to_jiffies(DMA_TIMEOUT)); @@ -678,7 +678,6 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, if (result) return result; - reinit_completion(&i2c_imx->dma->cmd_complete); time_left = wait_for_completion_timeout( &i2c_imx->dma->cmd_complete, msecs_to_jiffies(DMA_TIMEOUT)); -- GitLab From 0ea7fcfc7fe63de52eacb482c1ab47906b2d1251 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Thu, 12 Jul 2018 01:36:43 +0100 Subject: [PATCH 0634/1001] Btrfs: fix file data corruption after cloning a range and fsync commit bd3599a0e142cd73edd3b6801068ac3f48ac771a upstream. When we clone a range into a file we can end up dropping existing extent maps (or trimming them) and replacing them with new ones if the range to be cloned overlaps with a range in the destination inode. When that happens we add the new extent maps to the list of modified extents in the inode's extent map tree, so that a "fast" fsync (the flag BTRFS_INODE_NEEDS_FULL_SYNC not set in the inode) will see the extent maps and log corresponding extent items. However, at the end of range cloning operation we do truncate all the pages in the affected range (in order to ensure future reads will not get stale data). Sometimes this truncation will release the corresponding extent maps besides the pages from the page cache. If this happens, then a "fast" fsync operation will miss logging some extent items, because it relies exclusively on the extent maps being present in the inode's extent tree, leading to data loss/corruption if the fsync ends up using the same transaction used by the clone operation (that transaction was not committed in the meanwhile). An extent map is released through the callback btrfs_invalidatepage(), which gets called by truncate_inode_pages_range(), and it calls __btrfs_releasepage(). The later ends up calling try_release_extent_mapping() which will release the extent map if some conditions are met, like the file size being greater than 16Mb, gfp flags allow blocking and the range not being locked (which is the case during the clone operation) nor being the extent map flagged as pinned (also the case for cloning). The following example, turned into a test for fstests, reproduces the issue: $ mkfs.btrfs -f /dev/sdb $ mount /dev/sdb /mnt $ xfs_io -f -c "pwrite -S 0x18 9000K 6908K" /mnt/foo $ xfs_io -f -c "pwrite -S 0x20 2572K 156K" /mnt/bar $ xfs_io -c "fsync" /mnt/bar # reflink destination offset corresponds to the size of file bar, # 2728Kb minus 4Kb. $ xfs_io -c ""reflink ${SCRATCH_MNT}/foo 0 2724K 15908K" /mnt/bar $ xfs_io -c "fsync" /mnt/bar $ md5sum /mnt/bar 95a95813a8c2abc9aa75a6c2914a077e /mnt/bar $ mount /dev/sdb /mnt $ md5sum /mnt/bar 207fd8d0b161be8a84b945f0df8d5f8d /mnt/bar # digest should be 95a95813a8c2abc9aa75a6c2914a077e like before the # power failure In the above example, the destination offset of the clone operation corresponds to the size of the "bar" file minus 4Kb. So during the clone operation, the extent map covering the range from 2572Kb to 2728Kb gets trimmed so that it ends at offset 2724Kb, and a new extent map covering the range from 2724Kb to 11724Kb is created. So at the end of the clone operation when we ask to truncate the pages in the range from 2724Kb to 2724Kb + 15908Kb, the page invalidation callback ends up removing the new extent map (through try_release_extent_mapping()) when the page at offset 2724Kb is passed to that callback. Fix this by setting the bit BTRFS_INODE_NEEDS_FULL_SYNC whenever an extent map is removed at try_release_extent_mapping(), forcing the next fsync to search for modified extents in the fs/subvolume tree instead of relying on the presence of extent maps in memory. This way we can continue doing a "fast" fsync if the destination range of a clone operation does not overlap with an existing range or if any of the criteria necessary to remove an extent map at try_release_extent_mapping() is not met (file size not bigger then 16Mb or gfp flags do not allow blocking). CC: stable@vger.kernel.org # 3.16+ Signed-off-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/extent_io.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 7fa50e12f18e..5b62e06567a3 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -4280,6 +4280,7 @@ int try_release_extent_mapping(struct extent_map_tree *map, struct extent_map *em; u64 start = page_offset(page); u64 end = start + PAGE_SIZE - 1; + struct btrfs_inode *btrfs_inode = BTRFS_I(page->mapping->host); if (gfpflags_allow_blocking(mask) && page->mapping->host->i_size > SZ_16M) { @@ -4302,6 +4303,8 @@ int try_release_extent_mapping(struct extent_map_tree *map, extent_map_end(em) - 1, EXTENT_LOCKED | EXTENT_WRITEBACK, 0, NULL)) { + set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, + &btrfs_inode->runtime_flags); remove_extent_mapping(map, em); /* once for the rb tree */ free_extent_map(em); -- GitLab From 12c058df827213dcbbc42645fd5bcafb4057fb27 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Sun, 14 Jan 2018 12:39:01 +0200 Subject: [PATCH 0635/1001] nvme-pci: allocate device queues storage space at probe commit 147b27e4bd08406a6abebedbb478b431ec197be1 upstream. It may cause race by setting 'nvmeq' in nvme_init_request() because .init_request is called inside switching io scheduler, which may happen when the NVMe device is being resetted and its nvme queues are being freed and created. We don't have any sync between the two pathes. This patch changes the nvmeq allocation to occur at probe time so there is no way we can dereference it at init_request. [ 93.268391] kernel BUG at drivers/nvme/host/pci.c:408! [ 93.274146] invalid opcode: 0000 [#1] SMP [ 93.278618] Modules linked in: nfsv3 nfs_acl rpcsec_gss_krb5 auth_rpcgss nfsv4 dns_resolver nfs lockd grace fscache sunrpc ipmi_ssif vfat fat intel_rapl sb_edac x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel iTCO_wdt intel_cstate ipmi_si iTCO_vendor_support intel_uncore mxm_wmi mei_me ipmi_devintf intel_rapl_perf pcspkr sg ipmi_msghandler lpc_ich dcdbas mei shpchp acpi_power_meter wmi dm_multipath ip_tables xfs libcrc32c sd_mod mgag200 i2c_algo_bit drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops ttm drm ahci libahci nvme libata crc32c_intel nvme_core tg3 megaraid_sas ptp i2c_core pps_core dm_mirror dm_region_hash dm_log dm_mod [ 93.349071] CPU: 5 PID: 1842 Comm: sh Not tainted 4.15.0-rc2.ming+ #4 [ 93.356256] Hardware name: Dell Inc. PowerEdge R730xd/072T6D, BIOS 2.5.5 08/16/2017 [ 93.364801] task: 00000000fb8abf2a task.stack: 0000000028bd82d1 [ 93.371408] RIP: 0010:nvme_init_request+0x36/0x40 [nvme] [ 93.377333] RSP: 0018:ffffc90002537ca8 EFLAGS: 00010246 [ 93.383161] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000008 [ 93.391122] RDX: 0000000000000000 RSI: ffff880276ae0000 RDI: ffff88047bae9008 [ 93.399084] RBP: ffff88047bae9008 R08: ffff88047bae9008 R09: 0000000009dabc00 [ 93.407045] R10: 0000000000000004 R11: 000000000000299c R12: ffff880186bc1f00 [ 93.415007] R13: ffff880276ae0000 R14: 0000000000000000 R15: 0000000000000071 [ 93.422969] FS: 00007f33cf288740(0000) GS:ffff88047ba80000(0000) knlGS:0000000000000000 [ 93.431996] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 93.438407] CR2: 00007f33cf28e000 CR3: 000000047e5bb006 CR4: 00000000001606e0 [ 93.446368] Call Trace: [ 93.449103] blk_mq_alloc_rqs+0x231/0x2a0 [ 93.453579] blk_mq_sched_alloc_tags.isra.8+0x42/0x80 [ 93.459214] blk_mq_init_sched+0x7e/0x140 [ 93.463687] elevator_switch+0x5a/0x1f0 [ 93.467966] ? elevator_get.isra.17+0x52/0xc0 [ 93.472826] elv_iosched_store+0xde/0x150 [ 93.477299] queue_attr_store+0x4e/0x90 [ 93.481580] kernfs_fop_write+0xfa/0x180 [ 93.485958] __vfs_write+0x33/0x170 [ 93.489851] ? __inode_security_revalidate+0x4c/0x60 [ 93.495390] ? selinux_file_permission+0xda/0x130 [ 93.500641] ? _cond_resched+0x15/0x30 [ 93.504815] vfs_write+0xad/0x1a0 [ 93.508512] SyS_write+0x52/0xc0 [ 93.512113] do_syscall_64+0x61/0x1a0 [ 93.516199] entry_SYSCALL64_slow_path+0x25/0x25 [ 93.521351] RIP: 0033:0x7f33ce96aab0 [ 93.525337] RSP: 002b:00007ffe57570238 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 [ 93.533785] RAX: ffffffffffffffda RBX: 0000000000000006 RCX: 00007f33ce96aab0 [ 93.541746] RDX: 0000000000000006 RSI: 00007f33cf28e000 RDI: 0000000000000001 [ 93.549707] RBP: 00007f33cf28e000 R08: 000000000000000a R09: 00007f33cf288740 [ 93.557669] R10: 00007f33cf288740 R11: 0000000000000246 R12: 00007f33cec42400 [ 93.565630] R13: 0000000000000006 R14: 0000000000000001 R15: 0000000000000000 [ 93.573592] Code: 4c 8d 40 08 4c 39 c7 74 16 48 8b 00 48 8b 04 08 48 85 c0 74 16 48 89 86 78 01 00 00 31 c0 c3 8d 4a 01 48 63 c9 48 c1 e1 03 eb de <0f> 0b 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 85 f6 53 48 89 [ 93.594676] RIP: nvme_init_request+0x36/0x40 [nvme] RSP: ffffc90002537ca8 [ 93.602273] ---[ end trace 810dde3993e5f14e ]--- Reported-by: Yi Zhang Signed-off-by: Sagi Grimberg Signed-off-by: Christoph Hellwig Signed-off-by: Jon Derrick Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/host/pci.c | 61 +++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index f5643d107cc6..555d72020e27 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -77,7 +77,7 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown); * Represents an NVM Express device. Each nvme_dev is a PCI function. */ struct nvme_dev { - struct nvme_queue **queues; + struct nvme_queue *queues; struct blk_mq_tag_set tagset; struct blk_mq_tag_set admin_tagset; u32 __iomem *dbs; @@ -348,7 +348,7 @@ static int nvme_admin_init_hctx(struct blk_mq_hw_ctx *hctx, void *data, unsigned int hctx_idx) { struct nvme_dev *dev = data; - struct nvme_queue *nvmeq = dev->queues[0]; + struct nvme_queue *nvmeq = &dev->queues[0]; WARN_ON(hctx_idx != 0); WARN_ON(dev->admin_tagset.tags[0] != hctx->tags); @@ -370,7 +370,7 @@ static int nvme_init_hctx(struct blk_mq_hw_ctx *hctx, void *data, unsigned int hctx_idx) { struct nvme_dev *dev = data; - struct nvme_queue *nvmeq = dev->queues[hctx_idx + 1]; + struct nvme_queue *nvmeq = &dev->queues[hctx_idx + 1]; if (!nvmeq->tags) nvmeq->tags = &dev->tagset.tags[hctx_idx]; @@ -386,7 +386,7 @@ static int nvme_init_request(struct blk_mq_tag_set *set, struct request *req, struct nvme_dev *dev = set->driver_data; struct nvme_iod *iod = blk_mq_rq_to_pdu(req); int queue_idx = (set == &dev->tagset) ? hctx_idx + 1 : 0; - struct nvme_queue *nvmeq = dev->queues[queue_idx]; + struct nvme_queue *nvmeq = &dev->queues[queue_idx]; BUG_ON(!nvmeq); iod->nvmeq = nvmeq; @@ -900,7 +900,7 @@ static int nvme_poll(struct blk_mq_hw_ctx *hctx, unsigned int tag) static void nvme_pci_submit_async_event(struct nvme_ctrl *ctrl, int aer_idx) { struct nvme_dev *dev = to_nvme_dev(ctrl); - struct nvme_queue *nvmeq = dev->queues[0]; + struct nvme_queue *nvmeq = &dev->queues[0]; struct nvme_command c; memset(&c, 0, sizeof(c)); @@ -1146,7 +1146,6 @@ static void nvme_free_queue(struct nvme_queue *nvmeq) if (nvmeq->sq_cmds) dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth), nvmeq->sq_cmds, nvmeq->sq_dma_addr); - kfree(nvmeq); } static void nvme_free_queues(struct nvme_dev *dev, int lowest) @@ -1154,10 +1153,8 @@ static void nvme_free_queues(struct nvme_dev *dev, int lowest) int i; for (i = dev->ctrl.queue_count - 1; i >= lowest; i--) { - struct nvme_queue *nvmeq = dev->queues[i]; dev->ctrl.queue_count--; - dev->queues[i] = NULL; - nvme_free_queue(nvmeq); + nvme_free_queue(&dev->queues[i]); } } @@ -1189,10 +1186,8 @@ static int nvme_suspend_queue(struct nvme_queue *nvmeq) static void nvme_disable_admin_queue(struct nvme_dev *dev, bool shutdown) { - struct nvme_queue *nvmeq = dev->queues[0]; + struct nvme_queue *nvmeq = &dev->queues[0]; - if (!nvmeq) - return; if (nvme_suspend_queue(nvmeq)) return; @@ -1246,13 +1241,10 @@ static int nvme_alloc_sq_cmds(struct nvme_dev *dev, struct nvme_queue *nvmeq, return 0; } -static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, - int depth, int node) +static int nvme_alloc_queue(struct nvme_dev *dev, int qid, + int depth, int node) { - struct nvme_queue *nvmeq = kzalloc_node(sizeof(*nvmeq), GFP_KERNEL, - node); - if (!nvmeq) - return NULL; + struct nvme_queue *nvmeq = &dev->queues[qid]; nvmeq->cqes = dma_zalloc_coherent(dev->dev, CQ_SIZE(depth), &nvmeq->cq_dma_addr, GFP_KERNEL); @@ -1271,17 +1263,15 @@ static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, nvmeq->q_depth = depth; nvmeq->qid = qid; nvmeq->cq_vector = -1; - dev->queues[qid] = nvmeq; dev->ctrl.queue_count++; - return nvmeq; + return 0; free_cqdma: dma_free_coherent(dev->dev, CQ_SIZE(depth), (void *)nvmeq->cqes, nvmeq->cq_dma_addr); free_nvmeq: - kfree(nvmeq); - return NULL; + return -ENOMEM; } static int queue_request_irq(struct nvme_queue *nvmeq) @@ -1468,14 +1458,12 @@ static int nvme_pci_configure_admin_queue(struct nvme_dev *dev) if (result < 0) return result; - nvmeq = dev->queues[0]; - if (!nvmeq) { - nvmeq = nvme_alloc_queue(dev, 0, NVME_AQ_DEPTH, - dev_to_node(dev->dev)); - if (!nvmeq) - return -ENOMEM; - } + result = nvme_alloc_queue(dev, 0, NVME_AQ_DEPTH, + dev_to_node(dev->dev)); + if (result) + return result; + nvmeq = &dev->queues[0]; aqa = nvmeq->q_depth - 1; aqa |= aqa << 16; @@ -1505,7 +1493,7 @@ static int nvme_create_io_queues(struct nvme_dev *dev) for (i = dev->ctrl.queue_count; i <= dev->max_qid; i++) { /* vector == qid - 1, match nvme_create_queue */ - if (!nvme_alloc_queue(dev, i, dev->q_depth, + if (nvme_alloc_queue(dev, i, dev->q_depth, pci_irq_get_node(to_pci_dev(dev->dev), i - 1))) { ret = -ENOMEM; break; @@ -1514,7 +1502,7 @@ static int nvme_create_io_queues(struct nvme_dev *dev) max = min(dev->max_qid, dev->ctrl.queue_count - 1); for (i = dev->online_queues; i <= max; i++) { - ret = nvme_create_queue(dev->queues[i], i); + ret = nvme_create_queue(&dev->queues[i], i); if (ret) break; } @@ -1770,7 +1758,7 @@ static int nvme_setup_host_mem(struct nvme_dev *dev) static int nvme_setup_io_queues(struct nvme_dev *dev) { - struct nvme_queue *adminq = dev->queues[0]; + struct nvme_queue *adminq = &dev->queues[0]; struct pci_dev *pdev = to_pci_dev(dev->dev); int result, nr_io_queues; unsigned long size; @@ -1896,7 +1884,7 @@ static void nvme_disable_io_queues(struct nvme_dev *dev, int queues) retry: timeout = ADMIN_TIMEOUT; for (; i > 0; i--, sent++) - if (nvme_delete_queue(dev->queues[i], opcode)) + if (nvme_delete_queue(&dev->queues[i], opcode)) break; while (sent--) { @@ -2081,7 +2069,7 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown) queues = dev->online_queues - 1; for (i = dev->ctrl.queue_count - 1; i > 0; i--) - nvme_suspend_queue(dev->queues[i]); + nvme_suspend_queue(&dev->queues[i]); if (dead) { /* A device might become IO incapable very soon during @@ -2089,7 +2077,7 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown) * queue_count can be 0 here. */ if (dev->ctrl.queue_count) - nvme_suspend_queue(dev->queues[0]); + nvme_suspend_queue(&dev->queues[0]); } else { nvme_disable_io_queues(dev, queues); nvme_disable_admin_queue(dev, shutdown); @@ -2345,7 +2333,8 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) dev = kzalloc_node(sizeof(*dev), GFP_KERNEL, node); if (!dev) return -ENOMEM; - dev->queues = kzalloc_node((num_possible_cpus() + 1) * sizeof(void *), + + dev->queues = kzalloc_node((num_possible_cpus() + 1) * sizeof(struct nvme_queue), GFP_KERNEL, node); if (!dev->queues) goto free; -- GitLab From 4af9c61ad953ccc7dbd059a45e77e84db563bd41 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Tue, 23 Jan 2018 09:16:19 -0700 Subject: [PATCH 0636/1001] nvme-pci: Fix queue double allocations commit 62314e405fa101dbb82563394f9dfc225e3f1167 upstream. The queue count says the highest queue that's been allocated, so don't reallocate a queue lower than that. Fixes: 147b27e4bd0 ("nvme-pci: allocate device queues storage space at probe") Signed-off-by: Keith Busch Signed-off-by: Christoph Hellwig Signed-off-by: Jon Derrick Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/host/pci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 555d72020e27..a67d03716510 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1246,6 +1246,9 @@ static int nvme_alloc_queue(struct nvme_dev *dev, int qid, { struct nvme_queue *nvmeq = &dev->queues[qid]; + if (dev->ctrl.queue_count > qid) + return 0; + nvmeq->cqes = dma_zalloc_coherent(dev->dev, CQ_SIZE(depth), &nvmeq->cq_dma_addr, GFP_KERNEL); if (!nvmeq->cqes) -- GitLab From d626ac9669f29a4cd4d16ccf27349688a6dda2fd Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 16 Jul 2018 14:38:14 -0700 Subject: [PATCH 0637/1001] nvmet-fc: fix target sgl list on large transfers commit d082dc1562a2ff0947b214796f12faaa87e816a9 upstream. The existing code to carve up the sg list expected an sg element-per-page which can be very incorrect with iommu's remapping multiple memory pages to fewer bus addresses. To hit this error required a large io payload (greater than 256k) and a system that maps on a per-page basis. It's possible that large ios could get by fine if the system condensed the sgl list into the first 64 elements. This patch corrects the sg list handling by specifically walking the sg list element by element and attempting to divide the transfer up on a per-sg element boundary. While doing so, it still tries to keep sequences under 256k, but will exceed that rule if a single sg element is larger than 256k. Fixes: 48fa362b6c3f ("nvmet-fc: simplify sg list handling") Cc: # 4.14 Signed-off-by: James Smart Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/target/fc.c | 44 ++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c index 8e21211b904b..b7a5d1065378 100644 --- a/drivers/nvme/target/fc.c +++ b/drivers/nvme/target/fc.c @@ -58,8 +58,8 @@ struct nvmet_fc_ls_iod { struct work_struct work; } __aligned(sizeof(unsigned long long)); +/* desired maximum for a single sequence - if sg list allows it */ #define NVMET_FC_MAX_SEQ_LENGTH (256 * 1024) -#define NVMET_FC_MAX_XFR_SGENTS (NVMET_FC_MAX_SEQ_LENGTH / PAGE_SIZE) enum nvmet_fcp_datadir { NVMET_FCP_NODATA, @@ -74,6 +74,7 @@ struct nvmet_fc_fcp_iod { struct nvme_fc_cmd_iu cmdiubuf; struct nvme_fc_ersp_iu rspiubuf; dma_addr_t rspdma; + struct scatterlist *next_sg; struct scatterlist *data_sg; int data_sg_cnt; u32 total_length; @@ -1000,8 +1001,7 @@ nvmet_fc_register_targetport(struct nvmet_fc_port_info *pinfo, INIT_LIST_HEAD(&newrec->assoc_list); kref_init(&newrec->ref); ida_init(&newrec->assoc_cnt); - newrec->max_sg_cnt = min_t(u32, NVMET_FC_MAX_XFR_SGENTS, - template->max_sgl_segments); + newrec->max_sg_cnt = template->max_sgl_segments; ret = nvmet_fc_alloc_ls_iodlist(newrec); if (ret) { @@ -1717,6 +1717,7 @@ nvmet_fc_alloc_tgt_pgs(struct nvmet_fc_fcp_iod *fod) ((fod->io_dir == NVMET_FCP_WRITE) ? DMA_FROM_DEVICE : DMA_TO_DEVICE)); /* note: write from initiator perspective */ + fod->next_sg = fod->data_sg; return 0; @@ -1874,24 +1875,49 @@ nvmet_fc_transfer_fcp_data(struct nvmet_fc_tgtport *tgtport, struct nvmet_fc_fcp_iod *fod, u8 op) { struct nvmefc_tgt_fcp_req *fcpreq = fod->fcpreq; + struct scatterlist *sg = fod->next_sg; unsigned long flags; - u32 tlen; + u32 remaininglen = fod->total_length - fod->offset; + u32 tlen = 0; int ret; fcpreq->op = op; fcpreq->offset = fod->offset; fcpreq->timeout = NVME_FC_TGTOP_TIMEOUT_SEC; - tlen = min_t(u32, tgtport->max_sg_cnt * PAGE_SIZE, - (fod->total_length - fod->offset)); + /* + * for next sequence: + * break at a sg element boundary + * attempt to keep sequence length capped at + * NVMET_FC_MAX_SEQ_LENGTH but allow sequence to + * be longer if a single sg element is larger + * than that amount. This is done to avoid creating + * a new sg list to use for the tgtport api. + */ + fcpreq->sg = sg; + fcpreq->sg_cnt = 0; + while (tlen < remaininglen && + fcpreq->sg_cnt < tgtport->max_sg_cnt && + tlen + sg_dma_len(sg) < NVMET_FC_MAX_SEQ_LENGTH) { + fcpreq->sg_cnt++; + tlen += sg_dma_len(sg); + sg = sg_next(sg); + } + if (tlen < remaininglen && fcpreq->sg_cnt == 0) { + fcpreq->sg_cnt++; + tlen += min_t(u32, sg_dma_len(sg), remaininglen); + sg = sg_next(sg); + } + if (tlen < remaininglen) + fod->next_sg = sg; + else + fod->next_sg = NULL; + fcpreq->transfer_length = tlen; fcpreq->transferred_length = 0; fcpreq->fcp_error = 0; fcpreq->rsplen = 0; - fcpreq->sg = &fod->data_sg[fod->offset / PAGE_SIZE]; - fcpreq->sg_cnt = DIV_ROUND_UP(tlen, PAGE_SIZE); - /* * If the last READDATA request: check if LLDD supports * combined xfr with response. -- GitLab From a34399927da1efcb5e07273a4f0093b12d1dad01 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Thu, 9 Nov 2017 02:19:39 -0500 Subject: [PATCH 0638/1001] intel_idle: Graceful probe failure when MWAIT is disabled commit a4c447533a18ee86e07232d6344ba12b1f9c5077 upstream. When MWAIT is disabled, intel_idle refuses to probe. But it may mis-lead the user by blaming this on the model number: intel_idle: does not run on family 6 modesl 79 So defer the check for MWAIT until after the model# white-list check succeeds, and if the MWAIT check fails, tell the user how to fix it: intel_idle: Please enable MWAIT in BIOS SETUP Signed-off-by: Len Brown Signed-off-by: Rafael J. Wysocki Cc: Eduardo Valentin Signed-off-by: Greg Kroah-Hartman --- drivers/idle/intel_idle.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index f0b06b14e782..16249b0953ff 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -1061,7 +1061,7 @@ static const struct idle_cpu idle_cpu_dnv = { }; #define ICPU(model, cpu) \ - { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&cpu } + { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&cpu } static const struct x86_cpu_id intel_idle_ids[] __initconst = { ICPU(INTEL_FAM6_NEHALEM_EP, idle_cpu_nehalem), @@ -1125,6 +1125,11 @@ static int __init intel_idle_probe(void) return -ENODEV; } + if (!boot_cpu_has(X86_FEATURE_MWAIT)) { + pr_debug("Please enable MWAIT in BIOS SETUP\n"); + return -ENODEV; + } + if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF) return -ENODEV; -- GitLab From 27c41b170183d5d4ebbb6e4fdf41f035ef8617f8 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 23 Mar 2018 10:22:53 -0700 Subject: [PATCH 0639/1001] xfs: catch inode allocation state mismatch corruption commit ee457001ed6c6f31ddad69c24c1da8f377d8472d upstream. We recently came across a V4 filesystem causing memory corruption due to a newly allocated inode being setup twice and being added to the superblock inode list twice. From code inspection, the only way this could happen is if a newly allocated inode was not marked as free on disk (i.e. di_mode wasn't zero). Running the metadump on an upstream debug kernel fails during inode allocation like so: XFS: Assertion failed: ip->i_d.di_nblocks == 0, file: fs/xfs/xfs_inod= e.c, line: 838 ------------[ cut here ]------------ kernel BUG at fs/xfs/xfs_message.c:114! invalid opcode: 0000 [#1] PREEMPT SMP CPU: 11 PID: 3496 Comm: mkdir Not tainted 4.16.0-rc5-dgc #442 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/0= 1/2014 RIP: 0010:assfail+0x28/0x30 RSP: 0018:ffffc9000236fc80 EFLAGS: 00010202 RAX: 00000000ffffffea RBX: 0000000000004000 RCX: 0000000000000000 RDX: 00000000ffffffc0 RSI: 000000000000000a RDI: ffffffff8227211b RBP: ffffc9000236fce8 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000bec R11: f000000000000000 R12: ffffc9000236fd30 R13: ffff8805c76bab80 R14: ffff8805c77ac800 R15: ffff88083fb12e10 FS: 00007fac8cbff040(0000) GS:ffff88083fd00000(0000) knlGS:0000000000000= 000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fffa6783ff8 CR3: 00000005c6e2b003 CR4: 00000000000606e0 Call Trace: xfs_ialloc+0x383/0x570 xfs_dir_ialloc+0x6a/0x2a0 xfs_create+0x412/0x670 xfs_generic_create+0x1f7/0x2c0 ? capable_wrt_inode_uidgid+0x3f/0x50 vfs_mkdir+0xfb/0x1b0 SyS_mkdir+0xcf/0xf0 do_syscall_64+0x73/0x1a0 entry_SYSCALL_64_after_hwframe+0x42/0xb7 Extracting the inode number we crashed on from an event trace and looking at it with xfs_db: xfs_db> inode 184452204 xfs_db> p core.magic = 0x494e core.mode = 0100644 core.version = 2 core.format = 2 (extents) core.nlinkv2 = 1 core.onlink = 0 ..... Confirms that it is not a free inode on disk. xfs_repair also trips over this inode: ..... zero length extent (off = 0, fsbno = 0) in ino 184452204 correcting nextents for inode 184452204 bad attribute fork in inode 184452204, would clear attr fork bad nblocks 1 for inode 184452204, would reset to 0 bad anextents 1 for inode 184452204, would reset to 0 imap claims in-use inode 184452204 is free, would correct imap would have cleared inode 184452204 ..... disconnected inode 184452204, would move to lost+found And so we have a situation where the directory structure and the inobt thinks the inode is free, but the inode on disk thinks it is still in use. Where this corruption came from is not possible to diagnose, but we can detect it and prevent the kernel from oopsing on lookup. The reproducer now results in: $ sudo mkdir /mnt/scratch/{0,1,2,3,4,5}{0,1,2,3,4,5} mkdir: cannot create directory =E2=80=98/mnt/scratch/00=E2=80=99: File ex= ists mkdir: cannot create directory =E2=80=98/mnt/scratch/01=E2=80=99: File ex= ists mkdir: cannot create directory =E2=80=98/mnt/scratch/03=E2=80=99: Structu= re needs cleaning mkdir: cannot create directory =E2=80=98/mnt/scratch/04=E2=80=99: Input/o= utput error mkdir: cannot create directory =E2=80=98/mnt/scratch/05=E2=80=99: Input/o= utput error .... And this corruption shutdown: [ 54.843517] XFS (loop0): Corruption detected! Free inode 0xafe846c not= marked free on disk [ 54.845885] XFS (loop0): Internal error xfs_trans_cancel at line 1023 = of file fs/xfs/xfs_trans.c. Caller xfs_create+0x425/0x670 [ 54.848994] CPU: 10 PID: 3541 Comm: mkdir Not tainted 4.16.0-rc5-dgc #= 443 [ 54.850753] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIO= S 1.10.2-1 04/01/2014 [ 54.852859] Call Trace: [ 54.853531] dump_stack+0x85/0xc5 [ 54.854385] xfs_trans_cancel+0x197/0x1c0 [ 54.855421] xfs_create+0x425/0x670 [ 54.856314] xfs_generic_create+0x1f7/0x2c0 [ 54.857390] ? capable_wrt_inode_uidgid+0x3f/0x50 [ 54.858586] vfs_mkdir+0xfb/0x1b0 [ 54.859458] SyS_mkdir+0xcf/0xf0 [ 54.860254] do_syscall_64+0x73/0x1a0 [ 54.861193] entry_SYSCALL_64_after_hwframe+0x42/0xb7 [ 54.862492] RIP: 0033:0x7fb73bddf547 [ 54.863358] RSP: 002b:00007ffdaa553338 EFLAGS: 00000246 ORIG_RAX: 0000= 000000000053 [ 54.865133] RAX: ffffffffffffffda RBX: 00007ffdaa55449a RCX: 00007fb73= bddf547 [ 54.866766] RDX: 0000000000000001 RSI: 00000000000001ff RDI: 00007ffda= a55449a [ 54.868432] RBP: 00007ffdaa55449a R08: 00000000000001ff R09: 00005623a= 8670dd0 [ 54.870110] R10: 00007fb73be72d5b R11: 0000000000000246 R12: 000000000= 00001ff [ 54.871752] R13: 00007ffdaa5534b0 R14: 0000000000000000 R15: 00007ffda= a553500 [ 54.873429] XFS (loop0): xfs_do_force_shutdown(0x8) called from line 1= 024 of file fs/xfs/xfs_trans.c. Return address = ffffffff814cd050 [ 54.882790] XFS (loop0): Corruption of in-memory data detected. Shutt= ing down filesystem [ 54.884597] XFS (loop0): Please umount the filesystem and rectify the = problem(s) Note that this crash is only possible on v4 filesystemsi or v5 filesystems mounted with the ikeep mount option. For all other V5 filesystems, this problem cannot occur because we don't read inodes we are allocating from disk - we simply overwrite them with the new inode information. Signed-Off-By: Dave Chinner Reviewed-by: Carlos Maiolino Tested-by: Carlos Maiolino Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong Cc: Eduardo Valentin Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_icache.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index 43005fbe8b1e..26f9e66a3ec9 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -475,7 +475,28 @@ xfs_iget_cache_miss( trace_xfs_iget_miss(ip); - if ((VFS_I(ip)->i_mode == 0) && !(flags & XFS_IGET_CREATE)) { + + /* + * If we are allocating a new inode, then check what was returned is + * actually a free, empty inode. If we are not allocating an inode, + * the check we didn't find a free inode. + */ + if (flags & XFS_IGET_CREATE) { + if (VFS_I(ip)->i_mode != 0) { + xfs_warn(mp, +"Corruption detected! Free inode 0x%llx not marked free on disk", + ino); + error = -EFSCORRUPTED; + goto out_destroy; + } + if (ip->i_d.di_nblocks != 0) { + xfs_warn(mp, +"Corruption detected! Free inode 0x%llx has blocks allocated!", + ino); + error = -EFSCORRUPTED; + goto out_destroy; + } + } else if (VFS_I(ip)->i_mode == 0) { error = -ENOENT; goto out_destroy; } -- GitLab From 6f021e4ef39ace7f58c415856aef9308c70e89b9 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 17 Apr 2018 17:17:34 -0700 Subject: [PATCH 0640/1001] xfs: validate cached inodes are free when allocated commit afca6c5b2595fc44383919fba740c194b0b76aff upstream. A recent fuzzed filesystem image cached random dcache corruption when the reproducer was run. This often showed up as panics in lookup_slow() on a null inode->i_ops pointer when doing pathwalks. BUG: unable to handle kernel NULL pointer dereference at 0000000000000000 .... Call Trace: lookup_slow+0x44/0x60 walk_component+0x3dd/0x9f0 link_path_walk+0x4a7/0x830 path_lookupat+0xc1/0x470 filename_lookup+0x129/0x270 user_path_at_empty+0x36/0x40 path_listxattr+0x98/0x110 SyS_listxattr+0x13/0x20 do_syscall_64+0xf5/0x280 entry_SYSCALL_64_after_hwframe+0x42/0xb7 but had many different failure modes including deadlocks trying to lock the inode that was just allocated or KASAN reports of use-after-free violations. The cause of the problem was a corrupt INOBT on a v4 fs where the root inode was marked as free in the inobt record. Hence when we allocated an inode, it chose the root inode to allocate, found it in the cache and re-initialised it. We recently fixed a similar inode allocation issue caused by inobt record corruption problem in xfs_iget_cache_miss() in commit ee457001ed6c ("xfs: catch inode allocation state mismatch corruption"). This change adds similar checks to the cache-hit path to catch it, and turns the reproducer into a corruption shutdown situation. Reported-by: Wen Xu Signed-Off-By: Dave Chinner Reviewed-by: Christoph Hellwig Reviewed-by: Carlos Maiolino Reviewed-by: Darrick J. Wong [darrick: fix typos in comment] Signed-off-by: Darrick J. Wong Cc: Eduardo Valentin Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_icache.c | 73 +++++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index 26f9e66a3ec9..544b5211221c 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -305,6 +305,46 @@ xfs_reinit_inode( return error; } +/* + * If we are allocating a new inode, then check what was returned is + * actually a free, empty inode. If we are not allocating an inode, + * then check we didn't find a free inode. + * + * Returns: + * 0 if the inode free state matches the lookup context + * -ENOENT if the inode is free and we are not allocating + * -EFSCORRUPTED if there is any state mismatch at all + */ +static int +xfs_iget_check_free_state( + struct xfs_inode *ip, + int flags) +{ + if (flags & XFS_IGET_CREATE) { + /* should be a free inode */ + if (VFS_I(ip)->i_mode != 0) { + xfs_warn(ip->i_mount, +"Corruption detected! Free inode 0x%llx not marked free! (mode 0x%x)", + ip->i_ino, VFS_I(ip)->i_mode); + return -EFSCORRUPTED; + } + + if (ip->i_d.di_nblocks != 0) { + xfs_warn(ip->i_mount, +"Corruption detected! Free inode 0x%llx has blocks allocated!", + ip->i_ino); + return -EFSCORRUPTED; + } + return 0; + } + + /* should be an allocated inode */ + if (VFS_I(ip)->i_mode == 0) + return -ENOENT; + + return 0; +} + /* * Check the validity of the inode we just found it the cache */ @@ -354,12 +394,12 @@ xfs_iget_cache_hit( } /* - * If lookup is racing with unlink return an error immediately. + * Check the inode free state is valid. This also detects lookup + * racing with unlinks. */ - if (VFS_I(ip)->i_mode == 0 && !(flags & XFS_IGET_CREATE)) { - error = -ENOENT; + error = xfs_iget_check_free_state(ip, flags); + if (error) goto out_error; - } /* * If IRECLAIMABLE is set, we've torn down the VFS inode already. @@ -477,29 +517,12 @@ xfs_iget_cache_miss( /* - * If we are allocating a new inode, then check what was returned is - * actually a free, empty inode. If we are not allocating an inode, - * the check we didn't find a free inode. + * Check the inode free state is valid. This also detects lookup + * racing with unlinks. */ - if (flags & XFS_IGET_CREATE) { - if (VFS_I(ip)->i_mode != 0) { - xfs_warn(mp, -"Corruption detected! Free inode 0x%llx not marked free on disk", - ino); - error = -EFSCORRUPTED; - goto out_destroy; - } - if (ip->i_d.di_nblocks != 0) { - xfs_warn(mp, -"Corruption detected! Free inode 0x%llx has blocks allocated!", - ino); - error = -EFSCORRUPTED; - goto out_destroy; - } - } else if (VFS_I(ip)->i_mode == 0) { - error = -ENOENT; + error = xfs_iget_check_free_state(ip, flags); + if (error) goto out_destroy; - } /* * Preload the radix tree so we can insert safely under the -- GitLab From 59f35b983e8aeb98188c6ef93f8eabc594f8f953 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Fri, 8 Jun 2018 09:53:49 -0700 Subject: [PATCH 0641/1001] xfs: don't call xfs_da_shrink_inode with NULL bp commit bb3d48dcf86a97dc25fe9fc2c11938e19cb4399a upstream. xfs_attr3_leaf_create may have errored out before instantiating a buffer, for example if the blkno is out of range. In that case there is no work to do to remove it, and in fact xfs_da_shrink_inode will lead to an oops if we try. This also seems to fix a flaw where the original error from xfs_attr3_leaf_create gets overwritten in the cleanup case, and it removes a pointless assignment to bp which isn't used after this. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=199969 Reported-by: Xu, Wen Tested-by: Xu, Wen Signed-off-by: Eric Sandeen Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong Cc: Eduardo Valentin Signed-off-by: Greg Kroah-Hartman --- fs/xfs/libxfs/xfs_attr_leaf.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 5c16db86b38f..40e53a4fc0a6 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -785,9 +785,8 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args) ASSERT(blkno == 0); error = xfs_attr3_leaf_create(args, blkno, &bp); if (error) { - error = xfs_da_shrink_inode(args, 0, bp); - bp = NULL; - if (error) + /* xfs_attr3_leaf_create may not have instantiated a block */ + if (bp && (xfs_da_shrink_inode(args, 0, bp) != 0)) goto out; xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */ memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */ -- GitLab From 7d29fb53439c8c91874550cc078eda6db8feafe7 Mon Sep 17 00:00:00 2001 From: Shankara Pailoor Date: Tue, 5 Jun 2018 08:33:27 -0500 Subject: [PATCH 0642/1001] jfs: Fix inconsistency between memory allocation and ea_buf->max_size commit 92d34134193e5b129dc24f8d79cb9196626e8d7a upstream. The code is assuming the buffer is max_size length, but we weren't allocating enough space for it. Signed-off-by: Shankara Pailoor Signed-off-by: Dave Kleikamp Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- fs/jfs/xattr.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index c60f3d32ee91..a6797986b625 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -491,15 +491,17 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size) if (size > PSIZE) { /* * To keep the rest of the code simple. Allocate a - * contiguous buffer to work with + * contiguous buffer to work with. Make the buffer large + * enough to make use of the whole extent. */ - ea_buf->xattr = kmalloc(size, GFP_KERNEL); + ea_buf->max_size = (size + sb->s_blocksize - 1) & + ~(sb->s_blocksize - 1); + + ea_buf->xattr = kmalloc(ea_buf->max_size, GFP_KERNEL); if (ea_buf->xattr == NULL) return -ENOMEM; ea_buf->flag = EA_MALLOC; - ea_buf->max_size = (size + sb->s_blocksize - 1) & - ~(sb->s_blocksize - 1); if (ea_size == 0) return 0; -- GitLab From 1aa1166efaceef8972045b4aa25e6e0ab96d8a30 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 9 Aug 2018 12:16:40 +0200 Subject: [PATCH 0643/1001] Linux 4.14.62 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4bd65eabd298..d407ecfdee0b 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 61 +SUBLEVEL = 62 EXTRAVERSION = NAME = Petit Gorille -- GitLab From 6c4f841620d56c9ba657dbdc1996eeb0f08258d0 Mon Sep 17 00:00:00 2001 From: Kiran Gunda Date: Thu, 9 Aug 2018 16:00:23 +0530 Subject: [PATCH 0644/1001] defconfig: msm: enable PBS, VIBRATOR and MISC drivers for sm6150 Enable QPNP_PBS, QPNP_MISC and VIBRATOR_LDO drivers for PBS events and vibrator to be functional. Change-Id: I819ac1765b882a28a2f87f3f761aa739ded4e5af Signed-off-by: Kiran Gunda --- arch/arm64/configs/vendor/sdmsteppe-perf_defconfig | 3 +++ arch/arm64/configs/vendor/sdmsteppe_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig index afcb03ddfed3..2655f5d730a5 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig @@ -239,6 +239,7 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_MEMORY_STATE_TIME=y +CONFIG_QPNP_MISC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -428,6 +429,7 @@ CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_LEDS_QPNP_HAPTICS=y CONFIG_LEDS_QTI_TRI_LED=y +CONFIG_LEDS_QPNP_VIBRATOR_LDO=y CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_EDAC=y CONFIG_EDAC_KRYO_ARM64=y @@ -496,6 +498,7 @@ CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_QCOM_SMP2P=y +CONFIG_QPNP_PBS=y CONFIG_MSM_SERVICE_LOCATOR=y CONFIG_MSM_SERVICE_NOTIFIER=y CONFIG_MSM_SUBSYSTEM_RESTART=y diff --git a/arch/arm64/configs/vendor/sdmsteppe_defconfig b/arch/arm64/configs/vendor/sdmsteppe_defconfig index 04247ca6e677..adf5b5a625b3 100644 --- a/arch/arm64/configs/vendor/sdmsteppe_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe_defconfig @@ -246,6 +246,7 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_MEMORY_STATE_TIME=y +CONFIG_QPNP_MISC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -441,6 +442,7 @@ CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_LEDS_QPNP_HAPTICS=y CONFIG_LEDS_QTI_TRI_LED=y +CONFIG_LEDS_QPNP_VIBRATOR_LDO=y CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_EDAC=y CONFIG_EDAC_KRYO_ARM64=y @@ -514,6 +516,7 @@ CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_QCOM_WDOG_IPI_ENABLE=y CONFIG_QCOM_SMP2P=y +CONFIG_QPNP_PBS=y CONFIG_MSM_SERVICE_LOCATOR=y CONFIG_MSM_SERVICE_NOTIFIER=y CONFIG_MSM_SUBSYSTEM_RESTART=y -- GitLab From f35736259db9c8875c0ac3410fab4a7445695a47 Mon Sep 17 00:00:00 2001 From: Vevek Venkatesan Date: Fri, 27 Jul 2018 17:10:53 +0530 Subject: [PATCH 0645/1001] ARM: dts: msm: add Himax Touch panel support for SM6150 Add Himax touch controller driver support for SM6150 IDP. Change-Id: Ie4a774e641ebb616289e785398c27cf1fefdd337 Signed-off-by: Vevek Venkatesan --- .../bindings}/input/touchscreen/himax.txt | 18 +++++ arch/arm64/boot/dts/qcom/sm6150-idp.dtsi | 22 ++++++ arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi | 75 +++++++++++++++++++ 3 files changed, 115 insertions(+) rename Documentation/{ => devicetree/bindings}/input/touchscreen/himax.txt (75%) diff --git a/Documentation/input/touchscreen/himax.txt b/Documentation/devicetree/bindings/input/touchscreen/himax.txt similarity index 75% rename from Documentation/input/touchscreen/himax.txt rename to Documentation/devicetree/bindings/input/touchscreen/himax.txt index 37ddc6749b24..4b1743430fba 100644 --- a/Documentation/input/touchscreen/himax.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/himax.txt @@ -26,3 +26,21 @@ Optional properties: - himax,3v3-gpio : gpio acting as 3.3 v supply. - himax,report_type : Multi-touch protocol type. Default 0. 0 for protocol A, 1 for protocol B. + +Example: + i2c@884000 { + status = "okay"; + himax_ts@48 { + compatible = "himax,hxcommon"; + reg = <0x48>; + interrupt-parent = <&tlmm>; + interrupts = <89 0x2008>; + vdd-supply = <&pm6150_l10>; + avdd-supply = <&pm6150l_l7>; + himax,panel-coords = <0 1080 0 2160>; + himax,display-coords = <0 1080 0 2160>; + himax,irq-gpio = <&tlmm 89 0x00>; + himax,rst-gpio = <&tlmm 88 0x00>; + report_type = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi index 1467f00847a6..2b4f185dc567 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi @@ -63,6 +63,28 @@ status = "ok"; }; +&qupv3_se1_i2c { + status = "okay"; + himax_ts@48 { + compatible = "himax,hxcommon"; + reg = <0x48>; + interrupt-parent = <&tlmm>; + interrupts = <89 0x2008>; + vdd-supply = <&pm6150_l10>; + avdd-supply = <&pm6150l_l7>; + 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>; + himax,panel-coords = <0 1080 0 2160>; + himax,display-coords = <0 1080 0 2160>; + himax,irq-gpio = <&tlmm 89 0x00>; + himax,rst-gpio = <&tlmm 88 0x00>; + report_type = <1>; + }; +}; + &sdhc_1 { vdd-supply = <&pm6150l_l11>; qcom,vdd-voltage-level = <2950000 2950000>; diff --git a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi index dc916bb2c432..7f05f51a235f 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi @@ -852,6 +852,81 @@ }; }; + pmx_ts_int_active { + ts_int_active: ts_int_active { + mux { + pins = "gpio89"; + function = "gpio"; + }; + + config { + pins = "gpio89"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_suspend { + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio89"; + function = "gpio"; + }; + + config { + pins = "gpio89"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_reset_active { + ts_reset_active: ts_reset_active { + mux { + pins = "gpio88"; + function = "gpio"; + }; + + config { + pins = "gpio88"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_reset_suspend { + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio88"; + function = "gpio"; + }; + + config { + pins = "gpio88"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_release { + ts_release: ts_release { + mux { + pins = "gpio89", "gpio88"; + function = "gpio"; + }; + + config { + pins = "gpio89", "gpio88"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + }; }; -- GitLab From 175247ee357fb7c259787e7383a3581c896eacb1 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Thu, 9 Aug 2018 16:54:26 +0530 Subject: [PATCH 0646/1001] msm: camera: cpas: Add sm6150 camera hw version support Camera hardware version will be read at run time. This changes add support to sm6150 camera version ie 150. Change-Id: I77293d1f234e798f5b86c7ffd48281ead824f468 Signed-off-by: Ravikishore Pampana --- .../platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c index 1e51e552d1bf..7f531fdddd9e 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -105,6 +105,13 @@ static int cam_cpastop_get_hw_info(struct cam_hw_info *cpas_hw, (hw_caps->cpas_version.minor == 0) && (hw_caps->cpas_version.incr == 1)) soc_info->hw_version = CAM_CPAS_TITAN_175_V101; + } else if ((hw_caps->camera_version.major == 1) && + (hw_caps->camera_version.minor == 5) && + (hw_caps->camera_version.incr == 0)) { + if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 0) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_150_V100; } CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_info->hw_version); -- GitLab From c82c3d2372b78d27ed6eaa0863d3b00db5fd55dd Mon Sep 17 00:00:00 2001 From: John Dias Date: Fri, 22 Jun 2018 12:27:38 -0700 Subject: [PATCH 0647/1001] sched: walt: fix out-of-bounds access A computation in update_top_tasks() is indexing off the end of a top_tasks array. There's code to limit the index in the computation, but it's insufficient. Bug: 110529282 Change-Id: Idb5ff5e5800c014394bcb04638844bf1e057a40c Signed-off-by: John Dias Signed-off-by: Lingutla Chandrasekhar --- kernel/sched/walt.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index b093b1961fe1..1d53c299e7b1 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -655,14 +655,11 @@ static inline void inter_cluster_migration_fixup BUG_ON((s64)src_rq->nt_curr_runnable_sum < 0); } -static int load_to_index(u32 load) +static u32 load_to_index(u32 load) { - if (load < sched_load_granule) - return 0; - else if (load >= sched_ravg_window) - return NUM_LOAD_INDICES - 1; - else - return load / sched_load_granule; + u32 index = load / sched_load_granule; + + return min(index, (u32)(NUM_LOAD_INDICES - 1)); } static void -- GitLab From b21c7a67e878606a93e1ee0113208950cf50ad46 Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Wed, 25 Jul 2018 15:41:54 -0700 Subject: [PATCH 0648/1001] Revert "lowmemorykiller: fix cma accounting" This reverts commit 263316a1899f ("lowmemorykiller: fix cma accounting") Re-introducing __GFP_CMA so revert this change and correct the logic to simply check for MIGRATE_MOVABLE and __GFP_CMA. Change-Id: Ifae86190f6db38de973c31958afac7ac7845ee73 Signed-off-by: Liam Mark --- drivers/staging/android/lowmemorykiller.c | 9 ++------- include/linux/mmzone.h | 7 ------- mm/page_alloc.c | 5 ----- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 5275759becc1..d7f56b29eb90 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -264,13 +264,8 @@ static DEFINE_MUTEX(scan_mutex); static int can_use_cma_pages(gfp_t gfp_mask) { - int mtype = gfpflags_to_migratetype(gfp_mask); - - /* - * Assumes that all types of movable pages can be - * served by cma. Fix this if that changes. - */ - if (mtype == MIGRATE_MOVABLE) + if (gfpflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE && + (gfp_mask & __GFP_CMA)) return 1; return 0; diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 132b24533e16..68b4d9720ab7 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -66,13 +66,6 @@ enum migratetype { /* In mm/page_alloc.c; keep in sync also with show_migration_types() there */ extern char * const migratetype_names[MIGRATE_TYPES]; -/* - * Returns a list which contains the migrate types on to which - * an allocation falls back when the free list for the migrate - * type mtype is depleted. - * The end of the list is delimited by the type MIGRATE_TYPES. - */ -extern int *get_migratetype_fallbacks(int mtype); #ifdef CONFIG_CMA # define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 25b21de7786e..15eab84eca0d 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1855,11 +1855,6 @@ static int fallbacks[MIGRATE_TYPES][4] = { #endif }; -int *get_migratetype_fallbacks(int mtype) -{ - return fallbacks[mtype]; -} - #ifdef CONFIG_CMA static struct page *__rmqueue_cma_fallback(struct zone *zone, unsigned int order) -- GitLab From 88b42c30ebebdaef28e8b9259a21109e65e04b1f Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Tue, 7 Jun 2016 15:23:29 +0530 Subject: [PATCH 0649/1001] mm: fix cma accounting in zone_watermark_ok Some cases were reported on 3.18 where atomic unmovable allocations of order 2 fails, but kswapd does not wakeup. And in such cases it was seen that, when zone_watermark_ok check is performed to decide whether to wake up kswapd, there were lot of CMA pages of order 2 and above. This makes the watermark check succeed resulting in kswapd not being woken up. But since these atomic unmovable allocations can't come from CMA region, further atomic allocations keeps failing, without kswapd trying to reclaim. Usually concurrent movable allocations result in reclaim and improves the situtation, but the case reported was from a network test which was resulting in only atomic skb allocations being attempted. On 3.18 this was fixed by adding a cma free page counter and accouting the cma free pages properly in watermark calculations. Later this issue was indirectly fixed by the commit "mm, page_alloc: only enforce watermarks for order-0 allocations". But the commit "mm: add cma pcp list" brought the problem back because it includes MIGRATE_CMA within MIGRATE_PCPTYPES, and thus watermark check erroneously returns success for !ALLOC_CMA by finding free pages in cma free list. Change-Id: Id0e48b5c2f9deea93c5875c10d5ec72bd360df5f Signed-off-by: Vinayak Menon Signed-off-by: Charan Teja Reddy --- mm/page_alloc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 15eab84eca0d..c2a871a5661b 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -3080,6 +3080,14 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, continue; for (mt = 0; mt < MIGRATE_PCPTYPES; mt++) { +#ifdef CONFIG_CMA + /* + * Note that this check is needed only + * when MIGRATE_CMA < MIGRATE_PCPTYPES. + */ + if (mt == MIGRATE_CMA) + continue; +#endif if (!list_empty(&area->free_list[mt])) return true; } -- GitLab From 7081b33ca9fee10d1c12a34cfb93737cc36b9440 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Wed, 11 Jul 2018 19:07:20 -0700 Subject: [PATCH 0650/1001] ARM: dts: msm: Reduce size of offline-able memory region Since offline-able memory is in ZONE_MOVEABLE, it may not be used for GFP_KERNEL allocations. Experiments have shown that the previous setting causes the system to run out of memory for GFP_KERNEL type allocations. Change-Id: I3d284b324eb10ad1907e5eaf0df27c65acd29a3b Signed-off-by: Patrick Daly --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index acebb7e3c8dd..2be18d8a7b9f 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -39,7 +39,8 @@ mem-offline { compatible = "qcom,mem-offline"; - mem-percent = "35"; + /* 1 Gb out of 6 Gb*/ + mem-percent = "17"; granule = <512>; mboxes = <&qmp_aop 0>; }; -- GitLab From cd1be5fac519d6089289e513deb3b50ae3df9637 Mon Sep 17 00:00:00 2001 From: Shivaprasad Hongal Date: Thu, 9 Aug 2018 11:53:30 -0700 Subject: [PATCH 0651/1001] pfk: keymaster support to set/clear ice keys With new FBE key management changes, the keys are not available in the clear, but wrapped with an ephemeral key from keymaster. We cannot use a direct call to the qsee kernel to set/clear keys as they need to be unwrapped by keymaster first, which would then call in to the qsee kernel to set/clear the keys. Change-Id: Ie3fba8c0613d246efb5577ef6a0254171f082bfe Signed-off-by: Shivaprasad Hongal --- security/pfe/Kconfig | 13 +++ security/pfe/Makefile | 1 + security/pfe/pfk_ice.c | 206 ++++++++++++++++++++++++++++++++--------- security/pfe/pfk_ice.h | 26 ++++++ 4 files changed, 204 insertions(+), 42 deletions(-) diff --git a/security/pfe/Kconfig b/security/pfe/Kconfig index 0cd9e81a4952..9bc24a4dfcf2 100644 --- a/security/pfe/Kconfig +++ b/security/pfe/Kconfig @@ -25,4 +25,17 @@ config PFK Information is used when file is encrypted later using ICE or dm crypto engine +config PFK_WRAPPED_KEY_SUPPORTED + bool "Per-File-Key driver with wrapped key support" + depends on SECURITY + depends on SECURITY_SELINUX + depends on QSEECOM + depends on PFK + default n + help + Adds wrapped key support in PFK driver. Instead of setting + the key directly from vold, it unwraps the key in a secure + environment and sets the key in ICE. This is because the key + is not directly available in HLOS and needs to be unwrapped + in a secure environment. endmenu diff --git a/security/pfe/Makefile b/security/pfe/Makefile index 242a2165fccb..c52caf90a987 100644 --- a/security/pfe/Makefile +++ b/security/pfe/Makefile @@ -5,6 +5,7 @@ ccflags-y += -Isecurity/selinux -Isecurity/selinux/include ccflags-y += -Ifs/ext4 ccflags-y += -Ifs/crypto +ccflags-y += -Idrivers/misc obj-$(CONFIG_PFT) += pft.o obj-$(CONFIG_PFK) += pfk.o pfk_kc.o pfk_ice.o pfk_ext4.o diff --git a/security/pfe/pfk_ice.c b/security/pfe/pfk_ice.c index bf60dd18dd76..6452b4220136 100644 --- a/security/pfe/pfk_ice.c +++ b/security/pfe/pfk_ice.c @@ -24,7 +24,7 @@ #include #include #include "pfk_ice.h" - +#include "qseecom_kernel.h" /**********************************/ /** global definitions **/ @@ -55,48 +55,120 @@ TZ_SYSCALL_CREATE_PARAM_ID_1( \ TZ_SYSCALL_PARAM_TYPE_VAL) +#define CONTEXT_SIZE 0x1000 + +#define KEYMASTER_UTILS_CMD_ID 0x200UL +#define KEYMASTER_SET_ICE_KEY (KEYMASTER_UTILS_CMD_ID + 18UL) +#define KEYMASTER_CLEAR_ICE_KEY (KEYMASTER_UTILS_CMD_ID + 19UL) + #define ICE_KEY_SIZE 32 #define ICE_SALT_SIZE 32 static uint8_t ice_key[ICE_KEY_SIZE]; static uint8_t ice_salt[ICE_KEY_SIZE]; -int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, - char *storage_type) +static struct qseecom_handle *qhandle; + +static int set_wrapped_key(uint32_t index, const uint8_t *key, + const uint8_t *salt) +{ + int ret = 0; + u32 set_req_len = 0; + u32 set_rsp_len = 0; + struct pfk_ice_key_req *set_req_buf; + struct pfk_ice_key_rsp *set_rsp_buf; + + memcpy(ice_key, key, sizeof(ice_key)); + memcpy(ice_salt, salt, sizeof(ice_salt)); + + if (!qhandle) { + ret = qseecom_start_app(&qhandle, "keymaster64", + CONTEXT_SIZE); + if (ret) { + pr_err("Qseecom start app failed\n"); + return ret; + } + } + + set_req_buf = (struct pfk_ice_key_req *) qhandle->sbuf; + set_req_buf->cmd_id = KEYMASTER_SET_ICE_KEY; + set_req_buf->index = index; + set_req_buf->ice_key_offset = sizeof(struct pfk_ice_key_req); + set_req_buf->ice_key_size = ICE_KEY_SIZE; + set_req_buf->ice_salt_offset = set_req_buf->ice_key_offset + + set_req_buf->ice_key_size; + set_req_buf->ice_salt_size = ICE_SALT_SIZE; + + memcpy((uint8_t *) set_req_buf + set_req_buf->ice_key_offset, ice_key, + set_req_buf->ice_key_size); + memcpy((uint8_t *) set_req_buf + set_req_buf->ice_salt_offset, ice_salt, + set_req_buf->ice_salt_size); + + set_req_len = sizeof(struct pfk_ice_key_req) + set_req_buf->ice_key_size + + set_req_buf->ice_salt_size; + + set_rsp_buf = (struct pfk_ice_key_rsp *) (qhandle->sbuf + + set_req_len); + set_rsp_len = sizeof(struct pfk_ice_key_rsp); + + ret = qseecom_send_command(qhandle, + set_req_buf, set_req_len, + set_rsp_buf, set_rsp_len); + + if (ret) + pr_err("%s: Set wrapped key error: Status %d\n", __func__, + set_rsp_buf->ret); + + return ret; +} + +static int clear_wrapped_key(uint32_t index) +{ + int ret = 0; + + u32 clear_req_len = 0; + u32 clear_rsp_len = 0; + struct pfk_ice_key_req *clear_req_buf; + struct pfk_ice_key_rsp *clear_rsp_buf; + + clear_req_buf = (struct pfk_ice_key_req *) qhandle->sbuf; + memset(clear_req_buf, 0, sizeof(qhandle->sbuf)); + clear_req_buf->cmd_id = KEYMASTER_CLEAR_ICE_KEY; + clear_req_buf->index = index; + clear_req_len = sizeof(struct pfk_ice_key_req); + clear_rsp_buf = (struct pfk_ice_key_rsp *) (qhandle->sbuf + + QSEECOM_ALIGN(clear_req_len)); + clear_rsp_len = sizeof(struct pfk_ice_key_rsp); + + ret = qseecom_send_command(qhandle, clear_req_buf, clear_req_len, + clear_rsp_buf, clear_rsp_len); + if (ret) + pr_err("%s: Clear wrapped key error: Status %d\n", __func__, + clear_rsp_buf->ret); + + return ret; +} + +static int set_key(uint32_t index, const uint8_t *key, const uint8_t *salt) { struct scm_desc desc = {0}; - int ret, ret1; + int ret = 0; + uint32_t smc_id = 0; char *tzbuf_key = (char *)ice_key; char *tzbuf_salt = (char *)ice_salt; - char *s_type = storage_type; - uint32_t smc_id = 0; u32 tzbuflen_key = sizeof(ice_key); u32 tzbuflen_salt = sizeof(ice_salt); - if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { - pr_err("%s Invalid index %d\n", __func__, index); - return -EINVAL; - } - if (!key || !salt) { - pr_err("%s Invalid key/salt\n", __func__); - return -EINVAL; - } - if (!tzbuf_key || !tzbuf_salt) { pr_err("%s No Memory\n", __func__); return -ENOMEM; } - if (s_type == NULL) { - pr_err("%s Invalid Storage type\n", __func__); - return -EINVAL; - } - memset(tzbuf_key, 0, tzbuflen_key); memset(tzbuf_salt, 0, tzbuflen_salt); - memcpy(ice_key, key, tzbuflen_key); - memcpy(ice_salt, salt, tzbuflen_salt); + memcpy(ice_key, key, sizeof(ice_key)); + memcpy(ice_salt, salt, sizeof(ice_salt)); dmac_flush_range(tzbuf_key, tzbuf_key + tzbuflen_key); dmac_flush_range(tzbuf_salt, tzbuf_salt + tzbuflen_salt); @@ -110,33 +182,84 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, desc.args[3] = virt_to_phys(tzbuf_salt); desc.args[4] = tzbuflen_salt; + ret = scm_call2(smc_id, &desc); + if (ret) + pr_err("%s:SCM call Error: 0x%x\n", __func__, ret); + + return ret; +} + +static int clear_key(uint32_t index) +{ + struct scm_desc desc = {0}; + int ret = 0; + uint32_t smc_id = 0; + + smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; + + desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; + desc.args[0] = index; + + ret = scm_call2(smc_id, &desc); + if (ret) + pr_err("%s:SCM call Error: 0x%x\n", __func__, ret); + return ret; +} + +int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, + char *storage_type) +{ + int ret = 0, ret1 = 0; + char *s_type = storage_type; + + if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { + pr_err("%s Invalid index %d\n", __func__, index); + return -EINVAL; + } + if (!key || !salt) { + pr_err("%s Invalid key/salt\n", __func__); + return -EINVAL; + } + + if (s_type == NULL) { + pr_err("%s Invalid Storage type\n", __func__); + return -EINVAL; + } + ret = qcom_ice_setup_ice_hw((const char *)s_type, true); if (ret) { pr_err("%s: could not enable clocks: %d\n", __func__, ret); goto out; } - ret = scm_call2(smc_id, &desc); + if (pfk_wrapped_key_supported()) { + pr_debug("%s: Setting wrapped key\n", __func__); + ret = set_wrapped_key(index, key, salt); + } else { + pr_debug("%s: Setting keys with QSEE kernel\n", __func__); + ret = set_key(index, key, salt); + } + if (ret) { pr_err("%s: Set Key Error: %d\n", __func__, ret); if (ret == -EBUSY) { if (qcom_ice_setup_ice_hw((const char *)s_type, false)) pr_err("%s: clock disable failed\n", __func__); - goto out; + goto out; } /* Try to invalidate the key to keep ICE in proper state */ - smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; - desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; - desc.args[0] = index; - ret1 = scm_call2(smc_id, &desc); + if (pfk_wrapped_key_supported()) + ret1 = clear_wrapped_key(index); + else + ret1 = clear_key(index); + if (ret1) - pr_err("%s: Invalidate Key Error: %d\n", __func__, - ret1); + pr_err("%s: Invalidate key error: %d\n", __func__, ret); } ret1 = qcom_ice_setup_ice_hw((const char *)s_type, false); - if (ret1) - pr_err("%s: Error %d disabling clocks\n", __func__, ret1); + if (ret) + pr_err("%s: Error %d disabling clocks\n", __func__, ret); out: return ret; @@ -144,11 +267,8 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type) { - struct scm_desc desc = {0}; int ret = 0; - uint32_t smc_id = 0; - if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { pr_err("%s Invalid index %d\n", __func__, index); return -EINVAL; @@ -159,20 +279,22 @@ int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type) return -EINVAL; } - smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; - - desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; - desc.args[0] = index; - ret = qcom_ice_setup_ice_hw((const char *)storage_type, true); if (ret) { pr_err("%s: could not enable clocks: 0x%x\n", __func__, ret); return ret; } - ret = scm_call2(smc_id, &desc); + if (pfk_wrapped_key_supported()) { + ret = clear_wrapped_key(index); + pr_debug("%s: Clearing wrapped key\n", __func__); + } else { + pr_debug("%s: Clearing keys with QSEE kernel\n", __func__); + ret = clear_key(index); + } + if (ret) - pr_err("%s: Error: 0x%x\n", __func__, ret); + pr_err("%s: Invalidate key error: %d\n", __func__, ret); if (qcom_ice_setup_ice_hw((const char *)storage_type, false)) pr_err("%s: could not disable clocks\n", __func__); diff --git a/security/pfe/pfk_ice.h b/security/pfe/pfk_ice.h index a00193919116..5adfcb200b68 100644 --- a/security/pfe/pfk_ice.h +++ b/security/pfe/pfk_ice.h @@ -22,9 +22,35 @@ #include +struct __attribute__ ((__packed__)) pfk_ice_key_req { + uint32_t cmd_id; + uint32_t index; + uint32_t ice_key_offset; + uint32_t ice_key_size; + uint32_t ice_salt_offset; + uint32_t ice_salt_size; +}; + +struct __attribute__ ((__packed__)) pfk_ice_key_rsp { + uint32_t ret; + uint32_t cmd_id; +}; + int pfk_ice_init(void); int pfk_ice_deinit(void); +#ifdef CONFIG_PFK_WRAPPED_KEY_SUPPORTED +static inline bool pfk_wrapped_key_supported(void) +{ + return true; +} +#else +static inline bool pfk_wrapped_key_supported(void) +{ + return false; +} +#endif + int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, char *storage_type); int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type); -- GitLab From f2949d5cf686950ca613a2c4e0d618baab7cd334 Mon Sep 17 00:00:00 2001 From: Sreelakshmi Gownipalli Date: Thu, 9 Aug 2018 14:37:25 -0700 Subject: [PATCH 0652/1001] diag: Don't queue read to usb during disconnect Don't queue read to usb again when usb returns EIO error. Requeue the buffer to usb again only after receiving connect event. Change-Id: I18796722ad3b9baee26ed692f27eb9684ee37158 Signed-off-by: Sreelakshmi Gownipalli --- drivers/char/diag/diag_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/diag/diag_usb.c b/drivers/char/diag/diag_usb.c index bad5fcf0bbce..06169336dad8 100644 --- a/drivers/char/diag/diag_usb.c +++ b/drivers/char/diag/diag_usb.c @@ -286,7 +286,7 @@ static void usb_read_work_fn(struct work_struct *work) req->buf = ch->read_buf; req->length = USB_MAX_OUT_BUF; err = usb_diag_read(ch->hdl, req); - if (err) { + if (err && err != -EIO) { pr_debug("diag: In %s, error in reading from USB %s, err: %d\n", __func__, ch->name, err); atomic_set(&ch->read_pending, 0); -- GitLab From aa2bb7cf47bdd4c402a4d3155bc6fedfbe7c139d Mon Sep 17 00:00:00 2001 From: Carter Cooper Date: Tue, 3 Jul 2018 09:13:33 -0600 Subject: [PATCH 0653/1001] msm: kgsl: Define all the GMU VA space There were holes left in the GMU VA assignment space. Fill the entire struct space out with known valid addresses. Use this master list rather than recreating it in multiple locations. Change-Id: I3d801457df1fe19f4dc953af913c044df79e4172 Signed-off-by: Carter Cooper --- drivers/gpu/msm/adreno_a6xx_gmu.c | 61 ++++++--------- drivers/gpu/msm/kgsl_gmu.c | 121 ++++++++++++++++++------------ drivers/gpu/msm/kgsl_gmu.h | 13 ++-- 3 files changed, 105 insertions(+), 90 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 2a4e3c5b4a26..476bca6902de 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -472,23 +472,14 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) return 0; } -#define GMU_ITCM_VA_START 0x0 -#define GMU_ITCM_VA_END (GMU_ITCM_VA_START + 0x4000) /* 16 KB */ - -#define GMU_DTCM_VA_START 0x40000 -#define GMU_DTCM_VA_END (GMU_DTCM_VA_START + 0x4000) /* 16 KB */ - -#define GMU_ICACHE_VA_START 0x4000 -#define GMU_ICACHE_VA_END (GMU_ICACHE_VA_START + 0x3C000) /* 240 KB */ - static int load_gmu_fw(struct kgsl_device *device) { struct gmu_device *gmu = KGSL_GMU_DEVICE(device); uint8_t *fw = (uint8_t *)gmu->fw_image->data; - struct gmu_block_header *blk; - uint32_t *fwptr; int j; - int tcm_slot; + int tcm_addr; + struct gmu_block_header *blk; + struct gmu_memdesc *md; while (fw < (uint8_t *)gmu->fw_image->data + gmu->fw_image->size) { blk = (struct gmu_block_header *)fw; @@ -498,35 +489,31 @@ static int load_gmu_fw(struct kgsl_device *device) if (blk->size == 0) continue; - if ((blk->addr >= GMU_ITCM_VA_START) && - (blk->addr < GMU_ITCM_VA_END)) { - fwptr = (uint32_t *)fw; - tcm_slot = (blk->addr - GMU_ITCM_VA_START) - / sizeof(uint32_t); + md = gmu_get_memdesc(blk->addr, blk->size); + if (md == NULL) { + dev_err(&gmu->pdev->dev, + "No backing memory for 0x%8.8X\n", + blk->addr); + return -EINVAL; + } - for (j = 0; j < blk->size / sizeof(uint32_t); j++) - gmu_core_regwrite(device, - A6XX_GMU_CM3_ITCM_START + tcm_slot + j, - fwptr[j]); - } else if ((blk->addr >= GMU_DTCM_VA_START) && - (blk->addr < GMU_DTCM_VA_END)) { - fwptr = (uint32_t *)fw; - tcm_slot = (blk->addr - GMU_DTCM_VA_START) - / sizeof(uint32_t); + if (md->mem_type == GMU_ITCM || md->mem_type == GMU_DTCM) { + uint32_t *fwptr = (uint32_t *)fw; + + tcm_addr = (blk->addr - (uint32_t)md->gmuaddr) / + sizeof(uint32_t); + + if (md->mem_type == GMU_ITCM) + tcm_addr += A6XX_GMU_CM3_ITCM_START; + else + tcm_addr += A6XX_GMU_CM3_DTCM_START; for (j = 0; j < blk->size / sizeof(uint32_t); j++) - gmu_core_regwrite(device, - A6XX_GMU_CM3_DTCM_START + tcm_slot + j, + gmu_core_regwrite(device, tcm_addr + j, fwptr[j]); - } else if ((blk->addr >= GMU_ICACHE_VA_START) && - (blk->addr < GMU_ICACHE_VA_END)) { - if (!is_cached_fw_size_valid(blk->size)) { - dev_err(&gmu->pdev->dev, - "GMU firmware size too big\n"); - return -EINVAL; - - } - memcpy(gmu->icache_mem->hostptr, fw, blk->size); + } else { + /* Copy the memory directly */ + memcpy(md->hostptr, fw, blk->size); } fw += blk->size; diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index f88e074dfe31..1cca14ed98a5 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -40,16 +40,15 @@ struct gmu_iommu_context { #define DUMMY_SIZE SZ_4K -#define GMU_DCACHE_SIZE (SZ_256K - SZ_16K) /* GMU DCache VA size: 240KB */ -#define GMU_ICACHE_SIZE (SZ_256K - SZ_16K) /* GMU ICache VA size: 240KB */ - /* Define target specific GMU VMA configurations */ static const struct gmu_vma_entry { unsigned int start; unsigned int size; } gmu_vma[] = { - [GMU_CACHED_CODE] = { .start = 0x04000, .size = GMU_ICACHE_SIZE }, - [GMU_CACHED_DATA] = { .start = 0x44000, .size = GMU_DCACHE_SIZE }, + [GMU_ITCM] = { .start = 0x00000, .size = SZ_16K }, + [GMU_ICACHE] = { .start = 0x04000, .size = (SZ_256K - SZ_16K) }, + [GMU_DTCM] = { .start = 0x40000, .size = SZ_16K }, + [GMU_DCACHE] = { .start = 0x44000, .size = (SZ_256K - SZ_16K) }, [GMU_NONCACHED_KERNEL] = { .start = 0x60000000, .size = SZ_512M }, [GMU_NONCACHED_USER] = { .start = 0x80000000, .size = SZ_1G }, }; @@ -125,6 +124,9 @@ static int alloc_and_map(struct gmu_device *gmu, unsigned int ctx_id, int ret; struct iommu_domain *domain; + if (md->mem_type == GMU_ITCM || md->mem_type == GMU_DTCM) + return 0; + domain = gmu_ctx[ctx_id].domain; md->hostptr = dma_alloc_attrs(&gmu->pdev->dev, (size_t) md->size, @@ -145,6 +147,25 @@ static int alloc_and_map(struct gmu_device *gmu, unsigned int ctx_id, return ret; } +struct gmu_memdesc *gmu_get_memdesc(unsigned int addr, unsigned int size) +{ + int i; + struct gmu_memdesc *mem; + + for (i = 0; i < GMU_KERNEL_ENTRIES; i++) { + if (!test_bit(i, &gmu_kmem_bitmap)) + continue; + + mem = &gmu_kmem_entries[i]; + + if (addr >= mem->gmuaddr && + (addr + size < mem->gmuaddr + mem->size)) + return mem; + } + + return NULL; +} + /* * allocate_gmu_kmem() - allocates and maps uncached GMU kernel shared memory * @gmu: Pointer to GMU device @@ -152,10 +173,12 @@ static int alloc_and_map(struct gmu_device *gmu, unsigned int ctx_id, * @attrs: IOMMU mapping attributes */ static struct gmu_memdesc *allocate_gmu_kmem(struct gmu_device *gmu, - uint32_t mem_type, unsigned int size, unsigned int attrs) + enum gmu_mem_type mem_type, unsigned int size, + unsigned int attrs) { struct gmu_memdesc *md; - int ret, entry_idx = find_first_zero_bit( + int ret = 0; + int entry_idx = find_first_zero_bit( &gmu_kmem_bitmap, GMU_KERNEL_ENTRIES); if (entry_idx >= GMU_KERNEL_ENTRIES) { @@ -174,55 +197,54 @@ static struct gmu_memdesc *allocate_gmu_kmem(struct gmu_device *gmu, return ERR_PTR(-EINVAL); } - /* Allocate GMU virtual memory */ md = &gmu_kmem_entries[entry_idx]; md->gmuaddr = gmu_vma[mem_type].start + (num_uncached_entries * SZ_1M); set_bit(entry_idx, &gmu_kmem_bitmap); md->size = size; md->mem_type = mem_type; - break; - case GMU_CACHED_DATA: - if (size != GMU_DCACHE_SIZE) { - dev_err(&gmu->pdev->dev, - "Invalid cached GMU memory req %d\n", - size); - return ERR_PTR(-EINVAL); - } - /* Allocate GMU virtual memory */ + case GMU_DCACHE: md = &gmu_kmem_entries[entry_idx]; md->gmuaddr = gmu_vma[mem_type].start; set_bit(entry_idx, &gmu_kmem_bitmap); md->size = size; md->mem_type = mem_type; + break; + case GMU_ICACHE: + md = &gmu_kmem_entries[entry_idx]; + md->gmuaddr = gmu_vma[mem_type].start; + set_bit(entry_idx, &gmu_kmem_bitmap); + md->size = size; + md->mem_type = mem_type; break; - case GMU_CACHED_CODE: - if (size != GMU_ICACHE_SIZE) { - dev_err(&gmu->pdev->dev, - "Invalid cached GMU memory req %d\n", - size); - return ERR_PTR(-EINVAL); - } - /* Allocate GMU virtual memory */ + case GMU_ITCM: md = &gmu_kmem_entries[entry_idx]; md->gmuaddr = gmu_vma[mem_type].start; set_bit(entry_idx, &gmu_kmem_bitmap); md->size = size; md->mem_type = mem_type; + break; + case GMU_DTCM: + md = &gmu_kmem_entries[entry_idx]; + md->gmuaddr = gmu_vma[mem_type].start; + set_bit(entry_idx, &gmu_kmem_bitmap); + md->size = size; + md->mem_type = mem_type; break; + default: dev_err(&gmu->pdev->dev, - "Invalid memory type requested\n"); + "Invalid memory type (%d) requested\n", + mem_type); return ERR_PTR(-EINVAL); }; ret = alloc_and_map(gmu, GMU_CONTEXT_KERNEL, md, attrs); - if (ret) { clear_bit(entry_idx, &gmu_kmem_bitmap); md->gmuaddr = 0; @@ -235,15 +257,6 @@ static struct gmu_memdesc *allocate_gmu_kmem(struct gmu_device *gmu, return md; } -/* Checks if cached fw code size falls within the cached code segment range */ -bool is_cached_fw_size_valid(uint32_t size_in_bytes) -{ - if (size_in_bytes > gmu_vma[GMU_CACHED_CODE].size) - return false; - - return true; -} - static int gmu_iommu_cb_probe(struct gmu_device *gmu, struct gmu_iommu_context *ctx, struct device_node *node) @@ -342,18 +355,19 @@ static void gmu_kmem_close(struct gmu_device *gmu) gmu->dump_mem = NULL; gmu->gmu_log = NULL; - /* Unmap all memories in GMU kernel memory pool */ + /* Unmap and free all memories in GMU kernel memory pool */ for (i = 0; i < GMU_KERNEL_ENTRIES; i++) { + if (!test_bit(i, &gmu_kmem_bitmap)) + continue; + md = &gmu_kmem_entries[i]; - if (md->gmuaddr) + if (md->gmuaddr && md->mem_type != GMU_ITCM && + md->mem_type != GMU_DTCM) iommu_unmap(ctx->domain, md->gmuaddr, md->size); - } - /* Free GMU shared kernel memory */ - for (i = 0; i < GMU_KERNEL_ENTRIES; i++) { - md = &gmu_kmem_entries[i]; free_gmu_mem(gmu, md); + clear_bit(i, &gmu_kmem_bitmap); } @@ -390,6 +404,20 @@ static int gmu_memory_probe(struct kgsl_device *device, if (ret) return ret; + /* Reserve a memdesc for ITCM. No actually memory allocated */ + md = allocate_gmu_kmem(gmu, GMU_ITCM, gmu_vma[GMU_ITCM].size, 0); + if (IS_ERR(md)) { + ret = PTR_ERR(md); + goto err_ret; + } + + /* Reserve a memdesc for DTCM. No actually memory allocated */ + md = allocate_gmu_kmem(gmu, GMU_DTCM, gmu_vma[GMU_DTCM].size, 0); + if (IS_ERR(md)) { + ret = PTR_ERR(md); + goto err_ret; + } + /* Allocates & maps memory for WB DUMMY PAGE */ /* Must be the first alloc */ md = allocate_gmu_kmem(gmu, GMU_NONCACHED_KERNEL, @@ -400,7 +428,7 @@ static int gmu_memory_probe(struct kgsl_device *device, } /* Allocates & maps memory for DCACHE */ - md = allocate_gmu_kmem(gmu, GMU_CACHED_DATA, GMU_DCACHE_SIZE, + md = allocate_gmu_kmem(gmu, GMU_DCACHE, gmu_vma[GMU_DCACHE].size, (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); if (IS_ERR(md)) { ret = PTR_ERR(md); @@ -408,11 +436,10 @@ static int gmu_memory_probe(struct kgsl_device *device, } /* Allocates & maps memory for ICACHE */ - gmu->icache_mem = allocate_gmu_kmem(gmu, GMU_CACHED_CODE, - GMU_ICACHE_SIZE, + md = allocate_gmu_kmem(gmu, GMU_ICACHE, gmu_vma[GMU_ICACHE].size, (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); - if (IS_ERR(gmu->icache_mem)) { - ret = PTR_ERR(gmu->icache_mem); + if (IS_ERR(md)) { + ret = PTR_ERR(md); goto err_ret; } diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h index 8f3adf9332ce..32a9430f385f 100644 --- a/drivers/gpu/msm/kgsl_gmu.h +++ b/drivers/gpu/msm/kgsl_gmu.h @@ -71,10 +71,13 @@ extern struct gmu_dev_ops adreno_a6xx_gmudev; #define KGSL_GMU_DEVICE(_a) ((struct gmu_device *)((_a)->gmu_core.ptr)) enum gmu_mem_type { - GMU_CACHED_CODE = 0, - GMU_CACHED_DATA, + GMU_ITCM = 0, + GMU_ICACHE, + GMU_DTCM, + GMU_DCACHE, GMU_NONCACHED_KERNEL, - GMU_NONCACHED_USER + GMU_NONCACHED_USER, + GMU_MEM_TYPE_MAX, }; /** @@ -126,7 +129,6 @@ enum gmu_load_mode { * @bw_mem: pointer to BW data indirect buffer memory * @dump_mem: pointer to GMU debug dump memory * @gmu_log: gmu event log memory - * @icache_mem: gmu icache memory buffer * @hfi: HFI controller * @lm_config: GPU LM configuration data * @lm_dcvs_level: Minimal DCVS level that enable LM. LM disable in @@ -162,7 +164,6 @@ struct gmu_device { struct gmu_memdesc *bw_mem; struct gmu_memdesc *dump_mem; struct gmu_memdesc *gmu_log; - struct gmu_memdesc *icache_mem; struct kgsl_hfi hfi; unsigned int lm_config; unsigned int lm_dcvs_level; @@ -185,6 +186,6 @@ struct gmu_device { unsigned int fault_count; }; -bool is_cached_fw_size_valid(uint32_t size_in_bytes); +struct gmu_memdesc *gmu_get_memdesc(unsigned int addr, unsigned int size); #endif /* __KGSL_GMU_H */ -- GitLab From 643a39bf66f864449190323711b533cbe6624e25 Mon Sep 17 00:00:00 2001 From: Oleg Perelet Date: Tue, 7 Aug 2018 17:13:30 -0700 Subject: [PATCH 0654/1001] msm: kgsl: Hold GMU in reset during initialization In scenarious when cx_gdsc is on over slumber we need to keep GMU from executing code until fully initialized. Signed-off-by: Oleg Perelet Change-Id: I90740a19961dc27f217f2ddcf383ae776a3bb7a9 --- drivers/gpu/msm/adreno_a6xx_gmu.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index bbfab64bddf9..77e34f09713f 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -322,11 +322,6 @@ static int a6xx_gmu_start(struct kgsl_device *device) struct gmu_device *gmu = KGSL_GMU_DEVICE(device); kgsl_regwrite(device, A6XX_GMU_CX_GMU_WFI_CONFIG, 0x0); - /* Write 1 first to make sure the GMU is reset */ - gmu_core_regwrite(device, A6XX_GMU_CM3_SYSRESET, 1); - - /* Make sure putting in reset doesn't happen after clearing */ - wmb(); /* Bring GMU out of reset */ gmu_core_regwrite(device, A6XX_GMU_CM3_SYSRESET, 0); @@ -944,6 +939,10 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, int ret; unsigned int chipid = 0; + gmu_core_regwrite(device, A6XX_GMU_CM3_SYSRESET, 1); + /* Make sure M3 is in reset before going on */ + wmb(); + switch (boot_state) { case GMU_COLD_BOOT: /* Turn on TCM retention */ -- GitLab From c80d20642e9436d87892d4750d42998c36a70fd6 Mon Sep 17 00:00:00 2001 From: Conner Huff Date: Mon, 6 Aug 2018 13:43:17 -0600 Subject: [PATCH 0655/1001] net: qualcomm: rmnet: shs deliver return SHS skb responsibility changed to also deliver packets to network stack. Previously SHS would modify packets in orginal data path, now it will branch off and be in charge of calling netif_receive_skb Change-Id: Ieec44f6cddc5d2cef429d9944ff90b1558cd2dda Acked-by: Raul Martinez Signed-off-by: Subash Abhinov Kasiviswanathan Signed-off-by: Conner Huff --- drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c index 19fbddbcdef4..3e95d301b2ec 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c @@ -88,8 +88,10 @@ rmnet_deliver_skb(struct sk_buff *skb, struct rmnet_port *port) skb_set_mac_header(skb, 0); rmnet_shs_stamp = rcu_dereference(rmnet_shs_skb_entry); - if (rmnet_shs_stamp) + if (rmnet_shs_stamp) { rmnet_shs_stamp(skb, port); + return; + } if (!rmnet_check_skb_can_gro(skb)) gro_cells_receive(&priv->gro_cells, skb); -- GitLab From 79ba1073770d09f3c35ef9259ddeb990770bb888 Mon Sep 17 00:00:00 2001 From: Sreelakshmi Gownipalli Date: Wed, 18 Jul 2018 14:15:10 -0700 Subject: [PATCH 0656/1001] diag: Fix for diag communication during SSR During SSR diag doesn't queue buffers to read data from MHI. Queue buffers to MHI after SSR to read data. Change-Id: I7108f577c4fed2ad0a2a484bd88b06422ade5678 Signed-off-by: Sreelakshmi Gownipalli --- drivers/char/diag/diag_dci.c | 4 +-- drivers/char/diag/diagfwd_mhi.c | 44 +++++++++++++++++---------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 8c77d88245c5..0b0911baae09 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -249,8 +249,6 @@ static void dci_chk_handshake(unsigned long data) if (index < 0 || index >= NUM_DCI_PROC) return; - queue_work(driver->diag_dci_wq, - &dci_channel_status[index].handshake_work); } #endif @@ -2710,8 +2708,8 @@ static void diag_dci_init_handshake_remote(void) for (i = DCI_REMOTE_BASE; i < NUM_DCI_PROC; i++) { temp = &dci_channel_status[i]; temp->id = i; - setup_timer(&temp->wait_time, dci_chk_handshake, i); INIT_WORK(&temp->handshake_work, dci_handshake_work_fn); + setup_timer(&temp->wait_time, dci_chk_handshake, i); } } diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c index 215f5a54fa07..cd2af65ffa08 100644 --- a/drivers/char/diag/diagfwd_mhi.c +++ b/drivers/char/diag/diagfwd_mhi.c @@ -213,11 +213,10 @@ static int __mhi_close(struct diag_mhi_info *mhi_info, int close_flag) if (!mhi_info->enabled) return -ENODEV; - if (close_flag == CLOSE_CHANNELS) { - atomic_set(&(mhi_info->read_ch.opened), 0); - atomic_set(&(mhi_info->write_ch.opened), 0); + atomic_set(&(mhi_info->read_ch.opened), 0); + atomic_set(&(mhi_info->write_ch.opened), 0); + if (close_flag == CLOSE_CHANNELS) mhi_unprepare_from_transfer(mhi_info->mhi_dev); - } if (!(atomic_read(&(mhi_info->read_ch.opened)))) flush_workqueue(mhi_info->mhi_wq); @@ -270,6 +269,9 @@ static int __mhi_open(struct diag_mhi_info *mhi_info, int open_flag) if (!mhi_info->enabled) return -ENODEV; if (open_flag == OPEN_CHANNELS) { + if ((atomic_read(&(mhi_info->read_ch.opened))) && + (atomic_read(&(mhi_info->write_ch.opened)))) + return 0; err = mhi_prepare_for_transfer(mhi_info->mhi_dev); if (err) { pr_err("diag: In %s, unable to open ch, err: %d\n", @@ -598,14 +600,10 @@ static void diag_mhi_remove(struct mhi_device *mhi_dev) return; if (!mhi_info->enabled) return; + __mhi_close(mhi_info, CHANNELS_CLOSED); spin_lock_irqsave(&mhi_info->lock, flags); mhi_info->enabled = 0; spin_unlock_irqrestore(&mhi_info->lock, flags); - atomic_set(&(mhi_info->read_ch.opened), 0); - atomic_set(&(mhi_info->write_ch.opened), 0); - flush_workqueue(mhi_info->mhi_wq); - mhi_buf_tbl_clear(mhi_info); - diag_remote_dev_close(mhi_info->dev_id); } static int diag_mhi_probe(struct mhi_device *mhi_dev, @@ -620,23 +618,12 @@ static int diag_mhi_probe(struct mhi_device *mhi_dev, "received probe for %d\n", index); diag_mhi[index].mhi_dev = mhi_dev; - ret = diag_remote_init(); - if (ret) { - diag_remote_exit(); - return ret; - } - ret = diagfwd_bridge_init(); - if (ret) { - diagfwd_bridge_exit(); - diag_remote_exit(); - return ret; - } DIAG_LOG(DIAG_DEBUG_BRIDGE, "diag: mhi device is ready to open\n"); spin_lock_irqsave(&mhi_info->lock, flags); mhi_info->enabled = 1; spin_unlock_irqrestore(&mhi_info->lock, flags); - __mhi_open(&diag_mhi[index], CHANNELS_OPENED); + __mhi_open(&diag_mhi[index], OPEN_CHANNELS); queue_work(diag_mhi[index].mhi_wq, &(diag_mhi[index].open_work)); return ret; @@ -737,5 +724,20 @@ static struct mhi_driver diag_mhi_driver = { void diag_register_with_mhi(void) { + int ret = 0; + + ret = diag_remote_init(); + if (ret) { + diag_remote_exit(); + return; + } + + ret = diagfwd_bridge_init(); + if (ret) { + diagfwd_bridge_exit(); + diag_remote_exit(); + return; + } + mhi_driver_register(&diag_mhi_driver); } -- GitLab From 5861e25c9d73281fb3fa795db9c1e84c970eef21 Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Wed, 8 Aug 2018 17:37:22 -0700 Subject: [PATCH 0657/1001] ARM: dts: msm: Add V1 to msm-name property for SM8150 V1 Currently, the msm-name property for SM8150 is "sm8150", which can lead to ambiguity about the version of sm8150. Add "V1" to msm-name to eliminate ambiguity about sm8150 version. Change-Id: Ib8eb1ab3f7f9f3f0f3d5d717fc02b87669125558 Signed-off-by: Isaac J. Manjarres --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index acebb7e3c8dd..f9d8cd14560a 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -33,7 +33,7 @@ / { model = "Qualcomm Technologies, Inc. SM8150"; compatible = "qcom,sm8150"; - qcom,msm-name = "SM8150"; + qcom,msm-name = "SM8150 V1"; qcom,msm-id = <339 0x10000>; interrupt-parent = <&pdc>; -- GitLab From 781919db557c1d8907b035e3efe829c33b7b844c Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Wed, 8 Aug 2018 13:23:23 +0530 Subject: [PATCH 0658/1001] mm: cma: retry only on EBUSY Retry the cma alloc only when alloc_contig_range returns -EBUSY. This avoids unnecessary retries when the heap is full. Change-Id: If4626f0a0bc14e4b3a500283eb5a4c33b78fb6f2 Signed-off-by: Vinayak Menon --- mm/cma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/cma.c b/mm/cma.c index e4a219fa0a2d..c5ee6148a8a7 100644 --- a/mm/cma.c +++ b/mm/cma.c @@ -461,7 +461,8 @@ struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align, bitmap_maxno, start, bitmap_count, mask, offset); if (bitmap_no >= bitmap_maxno) { - if (retry_after_sleep < max_retries) { + if ((retry_after_sleep < max_retries) && + (ret == -EBUSY)) { start = 0; /* * update max retries if available free regions -- GitLab From af6ff923e6be3d9c5371b2f8b4bee1ed55d261ec Mon Sep 17 00:00:00 2001 From: Raviteja Tamatam Date: Fri, 13 Jul 2018 15:01:15 +0530 Subject: [PATCH 0659/1001] ARM: dts: msm: add sde node for SM6150 target Add sde node for SM6150 target which will be used by display driver. Change-Id: I300615d49a1ac83ef817cea526975c4ae59f4878 Signed-off-by: Raviteja Tamatam Signed-off-by: Sandeep Panda --- .../boot/dts/qcom/sm6150-idp-overlay.dts | 4 + arch/arm64/boot/dts/qcom/sm6150-idp.dtsi | 22 + arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi | 56 ++ .../boot/dts/qcom/sm6150-sde-display.dtsi | 229 ++++++++ arch/arm64/boot/dts/qcom/sm6150-sde-pll.dtsi | 64 ++ arch/arm64/boot/dts/qcom/sm6150-sde.dtsi | 547 ++++++++++++++++++ arch/arm64/boot/dts/qcom/sm6150.dtsi | 6 +- 7 files changed, 926 insertions(+), 2 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sm6150-sde-pll.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sm6150-sde.dtsi diff --git a/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts index f172568ec0e2..8e3fc9345069 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-idp-overlay.dts @@ -24,3 +24,7 @@ qcom,msm-id = <355 0x0>; qcom,board-id = <34 0>; }; + +&dsi_hx83112a_truly_vid_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi index 1467f00847a6..bc4bd148979b 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi @@ -11,6 +11,7 @@ */ #include +#include "sm6150-sde-display.dtsi" &soc { }; @@ -114,3 +115,24 @@ qcom,step-charging-enable; qcom,sw-jeita-enable; }; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 91 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 91 0>; +}; + +&dsi_hx83112a_truly_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 90 0>; + qcom,platform-reset-gpio = <&tlmm 91 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi index dc916bb2c432..015cafc2667f 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi @@ -469,6 +469,62 @@ }; }; + pmx_sde: pmx_sde { + sde_dsi_active: sde_dsi_active { + mux { + pins = "gpio91"; + function = "gpio"; + }; + + config { + pins = "gpio91"; + drive-strength = <8>; /* 8 mA */ + bias-disable = <0>; /* no pull */ + }; + }; + + sde_dsi_suspend: sde_dsi_suspend { + mux { + pins = "gpio91"; + function = "gpio"; + }; + + config { + pins = "gpio91"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + }; + + pmx_sde_te { + sde_te_active: sde_te_active { + mux { + pins = "gpio90"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio90"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + sde_te_suspend: sde_te_suspend { + mux { + pins = "gpio90"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio90"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + }; + /* SDC pin type */ sdc1_clk_on: sdc1_clk_on { config { diff --git a/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi new file mode 100644 index 000000000000..18802d41d15c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi @@ -0,0 +1,229 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "dsi-panel-sim-video.dtsi" +#include "dsi-panel-sim-cmd.dtsi" +#include "dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi" +#include + +&soc { + dsi_panel_pwr_supply: dsi_panel_pwr_supply { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + dsi_panel_pwr_supply_no_labibb: dsi_panel_pwr_supply_no_labibb { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + dsi_sim_vid_display: qcom,dsi-display@0 { + label = "dsi_sim_vid_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_sim_vid>; + }; + + dsi_sim_cmd_display: qcom,dsi-display@1 { + label = "dsi_sim_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_sim_cmd>; + }; + + dsi_hx83112a_truly_vid_display: qcom,dsi-display@2 { + label = "dsi_hx83112a_truly_vid_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_hx83112a_truly_video>; + }; + + sde_dsi: qcom,dsi-display { + compatible = "qcom,dsi-display"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + + clocks = <&mdss_dsi0_pll BYTE0_MUX_CLK>, + <&mdss_dsi0_pll PIX0_MUX_CLK>; + clock-names = "src_byte_clk0", "src_pixel_clk0"; + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,platform-te-gpio = <&tlmm 90 0>; + + vddio-supply = <&pm6150_l13>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + + qcom,dsi-display-list = + <&dsi_sim_vid_display + &dsi_sim_cmd_display + &dsi_hx83112a_truly_vid_display>; + }; + + sde_wb: qcom,wb-display@0 { + compatible = "qcom,wb-display"; + cell-index = <0>; + label = "wb_display"; + }; + + ext_disp: qcom,msm-ext-disp { + compatible = "qcom,msm-ext-disp"; + + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + }; + }; +}; + +&mdss_mdp { + connectors = <&sde_wb &sde_dsi>; +}; + +&dsi_sim_vid { + qcom,mdss-dsi-display-timings { + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x31>; + timing@0{ + qcom,mdss-dsi-panel-phy-timings = + [24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1c 08 09 05 02 04 a0]; + + qcom,display-topology = <1 0 1>, + <2 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_cmd { + qcom,mdss-dsi-display-timings { + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x31>; + timing@0{ + qcom,mdss-dsi-panel-phy-timings = + [24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1c 08 09 05 02 04 a0]; + + qcom,display-topology = <1 0 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <720 40 720 40 720 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@1{ + qcom,mdss-dsi-panel-phy-timings = + [24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1c 08 09 05 02 04 a0]; + qcom,display-topology = <1 0 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <540 40 540 40 540 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@2{ + qcom,mdss-dsi-panel-phy-timings = + [24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1c 08 09 05 02 04 a0]; + qcom,display-topology = <1 0 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <360 40 360 40 360 40>; + qcom,partial-update-enabled = "single_roi"; + }; + }; +}; + +&dsi_hx83112a_truly_video { + qcom,mdss-dsi-display-timings { + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x31>; + timing@0{ + qcom,mdss-dsi-panel-phy-timings = + [24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1f 08 09 05 02 04 a0 + 24 1c 08 09 05 02 04 a0]; + + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-sde-pll.dtsi b/arch/arm64/boot/dts/qcom/sm6150-sde-pll.dtsi new file mode 100644 index 000000000000..ae37a8c22eb7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-sde-pll.dtsi @@ -0,0 +1,64 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + mdss_dsi0_pll: qcom,mdss_dsi_pll@ae94400 { + compatible = "qcom,mdss_dsi_pll_14nm"; + label = "MDSS DSI 0 PLL"; + cell-index = <0>; + #clock-cells = <1>; + reg = <0xae94400 0x588>, + <0xaf03000 0x8>; + reg-names = "pll_base", "gdsc_base"; + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + gdsc-supply = <&mdss_core_gdsc>; + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dp_pll: qcom,mdss_dp_pll@c011000 { + status = "disabled"; + compatible = "qcom,mdss_dp_pll_7nm"; + label = "MDSS DP PLL"; + cell-index = <0>; + #clock-cells = <1>; + + reg = <0x088ea000 0x200>, + <0x088eaa00 0x200>, + <0x088ea200 0x200>, + <0x088ea600 0x200>, + <0xaf03000 0x8>; + reg-names = "pll_base", "phy_base", "ln_tx0_base", + "ln_tx1_base", "gdsc_base"; + + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; + clock-names = "iface_clk", "ref_clk_src", "gcc_iface", + "ref_clk", "pipe_clk"; + clock-rate = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi new file mode 100644 index 000000000000..89183060f29f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi @@ -0,0 +1,547 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + mdss_mdp: qcom,mdss_mdp@ae00000 { + compatible = "qcom,sde-kms"; + reg = <0x0ae00000 0x84208>, + <0x0aeb0000 0x2008>, + <0x0aeac000 0x214>; + reg-names = "mdp_phys", + "vbif_phys", + "regdma_phys"; + + clocks = + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_gcc GCC_DISP_HF_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_CLK>, + <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_LUT_CLK>, + <&clock_dispcc DISP_CC_MDSS_ROT_CLK>; + clock-names = "gcc_iface", "gcc_bus", + "iface_clk", "core_clk", "vsync_clk", + "lut_clk", "rot_clk"; + clock-rate = <0 0 0 256000000 19200000 256000000>; + clock-max-rate = <0 0 0 307000000 19200000 307000000>; + + sde-vdd-supply = <&mdss_core_gdsc>; + + /* interrupt config */ + interrupts = <0 83 0>; + interrupt-controller; + #interrupt-cells = <1>; + iommus = <&apps_smmu 0x800 0x0>; + + #address-cells = <1>; + #size-cells = <0>; + + #power-domain-cells = <0>; + + /* hw blocks */ + qcom,sde-off = <0x1000>; + qcom,sde-len = <0x45c>; + + qcom,sde-ctl-off = <0x2000 0x2200 0x2400 + 0x2600 0x2800 0x2a00>; + qcom,sde-ctl-size = <0x1e0>; + qcom,sde-ctl-display-pref = "primary", "none", "none", + "none", "none"; + + qcom,sde-mixer-off = <0x45000 0x46000 0x47000 + 0x0 0x0 0x0>; + qcom,sde-mixer-size = <0x320>; + qcom,sde-mixer-display-pref = "primary", "none", "none", + "none", "none", "none"; + + qcom,sde-dspp-top-off = <0x1300>; + qcom,sde-dspp-top-size = <0x80>; + qcom,sde-dspp-off = <0x55000>; + qcom,sde-dspp-size = <0x1800>; + + + qcom,sde-wb-off = <0x66000>; + qcom,sde-wb-size = <0x2c8>; + qcom,sde-wb-xin-id = <6>; + qcom,sde-wb-id = <2>; + qcom,sde-wb-clk-ctrl = <0x3b8 24>; + + qcom,sde-intf-off = <0x6b000 0x6b800 + 0x6c800>; + qcom,sde-intf-size = <0x2b8>; + qcom,sde-intf-type = "dp", "dsi", "dp"; + + qcom,sde-pp-off = <0x71000 0x71800 + 0x72000>; + qcom,sde-pp-slave = <0x0 0x0 0x0>; + qcom,sde-pp-size = <0xd4>; + + + qcom,sde-te2-off = <0x2000 0x2000 0x0>; + + qcom,sde-cdm-off = <0x7a200>; + qcom,sde-cdm-size = <0x224>; + + + qcom,sde-dither-off = <0x30e0 0x30e0 0x30e0 0x30e0>; + qcom,sde-dither-version = <0x00010000>; + qcom,sde-dither-size = <0x20>; + + qcom,sde-sspp-type = "vig", "dma", "dma", "dma", "dma"; + + qcom,sde-sspp-off = <0x5000 0x25000 0x27000 0x29000 + 0x2b000>; + qcom,sde-sspp-src-size = <0x1f0>; + + qcom,sde-sspp-xin-id = <0 1 5 9 13>; + qcom,sde-sspp-excl-rect = <1 1 1 1 1>; + qcom,sde-sspp-smart-dma-priority = <5 1 2 3 4>; + qcom,sde-smart-dma-rev = "smart_dma_v2p5"; + + qcom,sde-mixer-pair-mask = <3 0 1 0 0 0>; + + qcom,sde-mixer-blend-op-off = <0x20 0x38 0x50 0x68 0x80 0x98 + 0xb0 0xc8 0xe0 0xf8 0x110>; + + qcom,sde-max-per-pipe-bw-kbps = <4500000 + 4500000 4500000 + 4500000 4500000>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + qcom,sde-sspp-clk-ctrl = + <0x2ac 0>, <0x2ac 8>, <0x2b4 8>, <0x2bc 8>, + <0x2c4 8>; + qcom,sde-sspp-csc-off = <0x1a00>; + qcom,sde-csc-type = "csc-10bit"; + qcom,sde-qseed-type = "qseedv3lite"; + qcom,sde-sspp-qseed-off = <0xa00>; + qcom,sde-mixer-linewidth = <2560>; + qcom,sde-sspp-linewidth = <2160>; + qcom,sde-wb-linewidth = <2160>; + qcom,sde-mixer-blendstages = <0xb>; + qcom,sde-highest-bank-bit = <0x1>; + qcom,sde-ubwc-version = <0x200>; + qcom,sde-panic-per-pipe; + qcom,sde-has-cdp; + + qcom,sde-has-dim-layer; + qcom,sde-has-idle-pc; + + qcom,sde-max-bw-low-kbps = <4800000>; + qcom,sde-max-bw-high-kbps = <4800000>; + qcom,sde-min-core-ib-kbps = <2400000>; + qcom,sde-min-llcc-ib-kbps = <800000>; + qcom,sde-min-dram-ib-kbps = <800000>; + qcom,sde-dram-channels = <2>; + qcom,sde-num-nrt-paths = <0>; + + + qcom,sde-vbif-off = <0>; + qcom,sde-vbif-size = <0x1040>; + qcom,sde-vbif-id = <0>; + qcom,sde-vbif-memtype-0 = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-memtype-1 = <3 3 3 3 3 3>; + + qcom,sde-vbif-qos-rt-remap = <3 3 4 4 5 5 6 6>; + qcom,sde-vbif-qos-nrt-remap = <3 3 3 3 3 3 3 3>; + + /* macrotile & macrotile-qseed has the same configs */ + qcom,sde-danger-lut = <0x0000000f 0x0000ffff + 0x00000000 0x00000000 0x0000ffff>; + + qcom,sde-safe-lut-linear = <0 0xfff8>; + qcom,sde-safe-lut-macrotile = <0 0xf000>; + /* same as safe-lut-macrotile */ + qcom,sde-safe-lut-macrotile-qseed = <0 0xf000>; + qcom,sde-safe-lut-nrt = <0 0xffff>; + qcom,sde-safe-lut-cwb = <0 0xffff>; + + qcom,sde-qos-lut-linear = <0 0x00112222 0x22223357>; + qcom,sde-qos-lut-macrotile = <0 0x00112233 0x44556677>; + qcom,sde-qos-lut-macrotile-qseed = <0 0x00112233 0x66777777>; + qcom,sde-qos-lut-nrt = <0 0x00000000 0x00000000>; + qcom,sde-qos-lut-cwb = <0 0x75300000 0x00000000>; + + qcom,sde-cdp-setting = <1 1>, <1 0>; + + qcom,sde-qos-cpu-mask = <0x3>; + qcom,sde-qos-cpu-dma-latency = <300>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + + qcom,sde-reg-dma-off = <0>; + qcom,sde-reg-dma-version = <0x00010001>; + qcom,sde-reg-dma-trigger-off = <0x119c>; + + qcom,sde-secure-sid-mask = <0x0000801>; + + qcom,sde-sspp-vig-blocks { + qcom,sde-vig-csc-off = <0x1a00>; + qcom,sde-vig-qseed-off = <0xa00>; + qcom,sde-vig-qseed-size = <0xa0>; + qcom,sde-vig-inverse-pma; + }; + + + qcom,sde-dspp-blocks { + qcom,sde-dspp-igc = <0x0 0x00030001>; + qcom,sde-dspp-hsic = <0x800 0x00010007>; + qcom,sde-dspp-memcolor = <0x880 0x00010007>; + qcom,sde-dspp-hist = <0x800 0x00010007>; + qcom,sde-dspp-sixzone= <0x900 0x00010007>; + qcom,sde-dspp-vlut = <0xa00 0x00010008>; + qcom,sde-dspp-gamut = <0x1000 0x00040001>; + qcom,sde-dspp-pcc = <0x1700 0x00040000>; + qcom,sde-dspp-gc = <0x17c0 0x00010008>; + qcom,sde-dspp-dither = <0x82c 0x00010007>; + }; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "sde-vdd"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + + smmu_sde_sec: qcom,smmu_sde_sec_cb { + compatible = "qcom,smmu_sde_sec"; + iommus = <&apps_smmu 0x801 0x0>; + }; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "mdss_sde"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, + <22 512 0 4800000>, + <22 512 0 4800000>; + }; + + qcom,sde-reg-bus { + qcom,msm-bus,name = "mdss_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 150000>, + <1 590 0 300000>; + }; + }; + + sde_rscc: qcom,sde_rscc@af20000 { + cell-index = <0>; + compatible = "qcom,sde-rsc"; + reg = <0xaf20000 0x1c44>, + <0xaf30000 0x3fd4>; + reg-names = "drv", "wrapper"; + qcom,sde-rsc-version = <1>; + status = "disabled"; + + vdd-supply = <&mdss_core_gdsc>; + clocks = <&clock_dispcc DISP_CC_MDSS_RSCC_VSYNC_CLK>, + <&clock_dispcc DISP_CC_MDSS_NON_GDSC_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_RSCC_AHB_CLK>; + clock-names = "vsync_clk", "gdsc_clk", "iface_clk"; + clock-rate = <0 0 0>; + + qcom,sde-dram-channels = <2>; + + mboxes = <&disp_rsc 0>; + mbox-names = "disp_rsc"; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "disp_rsc_mnoc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20003 20515 0 0>, + <20003 20515 0 4800000>, + <20003 20515 0 4800000>; + }; + + qcom,sde-llcc-bus { + qcom,msm-bus,name = "disp_rsc_llcc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20001 20513 0 0>, + <20001 20513 0 6400000>, + <20001 20513 0 6400000>; + }; + + qcom,sde-ebi-bus { + qcom,msm-bus,name = "disp_rsc_ebi"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20000 20512 0 0>, + <20000 20512 0 6400000>, + <20000 20512 0 6400000>; + }; + }; + + mdss_rotator: qcom,mdss_rotator@ae00000 { + compatible = "qcom,sde_rotator"; + reg = <0x0ae00000 0xac000>, + <0x0aeb8000 0x3000>; + reg-names = "mdp_phys", + "rot_vbif_phys"; + + #list-cells = <1>; + + qcom,mdss-rot-mode = <1>; + qcom,mdss-highest-bank-bit = <0x1>; + + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_rotator"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <25 512 0 0>, + <25 512 0 6400000>, + <25 512 0 6400000>; + + rot-vdd-supply = <&mdss_core_gdsc>; + qcom,supply-names = "rot-vdd"; + + clocks = + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_ROT_CLK>; + clock-names = "gcc_iface", + "iface_clk", "rot_clk"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <2 0>; + + power-domains = <&mdss_mdp>; + + /* Offline rotator QoS setting */ + qcom,mdss-rot-vbif-qos-setting = <3 3 3 3 3 3 3 3>; + qcom,mdss-rot-vbif-memtype = <3 3>; + qcom,mdss-rot-cdp-setting = <1 1>; + qcom,mdss-rot-qos-lut = <0x0 0x0 0x0 0x0>; + qcom,mdss-rot-danger-lut = <0x0 0x0>; + qcom,mdss-rot-safe-lut = <0x0000ffff 0x0000ffff>; + + qcom,mdss-default-ot-rd-limit = <32>; + qcom,mdss-default-ot-wr-limit = <32>; + + qcom,mdss-sbuf-headroom = <20>; + + cache-slice-names = "rotator"; + cache-slices = <&llcc 4>; + + /* reg bus scale settings */ + rot_reg: qcom,rot-reg-bus { + qcom,msm-bus,name = "mdss_rot_reg"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>; + }; + + smmu_rot_unsec: qcom,smmu_rot_unsec_cb { + compatible = "qcom,smmu_sde_rot_unsec"; + iommus = <&apps_smmu 0xc40 0x0>; + }; + + smmu_rot_sec: qcom,smmu_rot_sec_cb { + compatible = "qcom,smmu_sde_rot_sec"; + iommus = <&apps_smmu 0xc41 0x0>; + }; + }; + + mdss_dsi0: qcom,mdss_dsi_ctrl0@ae94000 { + compatible = "qcom,dsi-ctrl-hw-v2.3"; + label = "dsi-ctrl-0"; + cell-index = <0>; + reg = <0xae94000 0x400>, + <0xaf08000 0x4>; + reg-names = "dsi_ctrl", "disp_cc_base"; + interrupt-parent = <&mdss_mdp>; + interrupts = <4 0>; + vdda-1p2-supply = <&pm6150l_l3>; + clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_ESC0_CLK>; + clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", + "pixel_clk", "pixel_clk_rcg", + "esc_clk"; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1232000>; + qcom,supply-max-voltage = <1232000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <0>; + }; + }; + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi_phy0: qcom,mdss_dsi_phy0@ae94400 { + compatible = "qcom,dsi-phy-v2.0"; + label = "dsi-phy-0"; + cell-index = <0>; + reg = <0xae94400 0x588>; + reg-names = "dsi_phy"; + vdda-0p9-supply = <&pm6150_l4>; + qcom,platform-strength-ctrl = [ff 06 + ff 06 + ff 06 + ff 06 + ff 00]; + qcom,platform-lane-config = [00 00 10 0f + 00 00 10 0f + 00 00 10 0f + 00 00 10 0f + 00 00 10 8f]; + qcom,platform-regulator-settings = [1d 1d 1d 1d 1d]; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + sde_dp: qcom,dp_display@0{ + status = "disabled"; + cell-index = <0>; + compatible = "qcom,dp-display"; + + vdda-1p2-supply = <&pm6150l_l3>; + vdda-0p9-supply = <&pm6150_l4>; + + reg = <0xae90000 0x0dc>, + <0xae90200 0x0c0>, + <0xae90400 0x508>, + <0xae90a00 0x094>, + <0x88eaa00 0x200>, + <0x88ea200 0x200>, + <0x88ea600 0x200>, + <0xaf02000 0x1a0>, + <0x780000 0x621c>, + <0x88ea040 0x10>, + <0x88e8000 0x20>, + <0x0aee1000 0x034>, + <0xae91000 0x094>; + /* dp_ctrl: dp_ahb, dp_aux, dp_link, dp_p0 */ + reg-names = "dp_ahb", "dp_aux", "dp_link", + "dp_p0", "dp_phy", "dp_ln_tx0", "dp_ln_tx1", + "dp_mmss_cc", "qfprom_physical", "dp_pll", + "usb3_dp_com", "hdcp_physical", "dp_p1"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <12 0>; + + qcom,phy-version = <0x420>; + qcom,aux-cfg0-settings = [20 00]; + qcom,aux-cfg1-settings = [24 13]; + qcom,aux-cfg2-settings = [28 24]; + qcom,aux-cfg3-settings = [2c 00]; + qcom,aux-cfg4-settings = [30 0a]; + qcom,aux-cfg5-settings = [34 26]; + qcom,aux-cfg6-settings = [38 0a]; + qcom,aux-cfg7-settings = [3c 03]; + qcom,aux-cfg8-settings = [40 b7]; + qcom,aux-cfg9-settings = [44 03]; + + qcom,max-pclk-frequency-khz = <675000>; + + qcom,mst-enable; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 2ffed070f418..a54ce5c7d454 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -1471,9 +1471,9 @@ interrupts = <0 129 0>; #mbox-cells = <1>; qcom,drv-id = <0>; - qcom,tcs-config = , - , + qcom,tcs-config = , , + , ; }; @@ -2673,3 +2673,5 @@ #include "sm6150-bus.dtsi" #include "sm6150-vidc.dtsi" #include "sm6150-audio.dtsi" +#include "sm6150-sde-pll.dtsi" +#include "sm6150-sde.dtsi" -- GitLab From 6ac42d8401d96f3fa113df75f63f3e94d64b0778 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Fri, 3 Aug 2018 14:56:35 +0530 Subject: [PATCH 0660/1001] ipa: update wlan upstream iface name Update WLAN upstream name to support STA SAP scenario with wlan1 iface. Change-Id: I0223c5b4aff8dfe24562a2c6d4ac581a7843224e Acked-by: Pooja Kumari Signed-off-by: Mohammed Javid --- drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 7aef668cc74b..c835e8ea7bee 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -67,6 +67,7 @@ MODULE_PARM_DESC(outstanding_low, "Outstanding low"); #define IPA_WWAN_DEV_NAME "rmnet_ipa%d" #define IPA_UPSTEAM_WLAN_IFACE_NAME "wlan0" +#define IPA_UPSTEAM_WLAN1_IFACE_NAME "wlan1" #define IPA_WWAN_RX_SOFTIRQ_THRESH 16 @@ -791,7 +792,8 @@ static enum ipa_upstream_type find_upstream_type(const char *upstreamIface) return IPA_UPSTEAM_MODEM; } - if (strcmp(IPA_UPSTEAM_WLAN_IFACE_NAME, upstreamIface) == 0) + if ((strcmp(IPA_UPSTEAM_WLAN_IFACE_NAME, upstreamIface) == 0) || + (strcmp(IPA_UPSTEAM_WLAN1_IFACE_NAME, upstreamIface) == 0)) return IPA_UPSTEAM_WLAN; else return MAX_NUM_OF_MUX_CHANNEL; -- GitLab From 4be8c079501681681207977f744b37beda1a3e33 Mon Sep 17 00:00:00 2001 From: Veerabhadrarao Badiganti Date: Sat, 7 Apr 2018 19:09:13 +0530 Subject: [PATCH 0661/1001] mmc: core: Return SD card status if sdr104_wa is not present On the targets in which sdr104 workaround is not needed, we simply return card status from mmc_recovery_fallback_lower_speed() call. This is to fix the issue that are observed with SD card tray holder. (1b6281740: mmc: core: Return card status if sdr104_wa is not present) Since this change is meant to fix issue observed with SD card tray holder, for other devices(eMMC/SDIO) we should ignore this. Change-Id: Ia7fcdfab4351cbb3df241f2e9f2da74bad20ca90 Signed-off-by: Veerabhadrarao Badiganti --- 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 d937363cfb4a..aecdfeaea9b2 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -468,7 +468,7 @@ int mmc_recovery_fallback_lower_speed(struct mmc_host *host) mmc_host_clear_sdr104(host); err = mmc_hw_reset(host); host->card->sdr104_blocked = true; - } else { + } else if (mmc_card_sd(host->card)) { /* If sdr104_wa is not present, just return status */ err = host->bus_ops->alive(host); } -- GitLab From 683d46d5691db8d951fe2eb160f757179435a1a7 Mon Sep 17 00:00:00 2001 From: Sankeerth Billakanti Date: Mon, 30 Jul 2018 16:12:07 +0530 Subject: [PATCH 0662/1001] drm/msm/dp: return number of displays as 0 if dp node is disabled When DP node is disabled in the DT file, dp driver is returning incorrect number of displays connected Change-Id: I94655ee40cb3785f8186f0eef5f88d3ec4020b09 Signed-off-by: Sankeerth Billakanti --- drivers/gpu/drm/msm/dp/dp_display.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 05550fc1a353..92a46827b151 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -2058,6 +2058,9 @@ int dp_display_get_displays(void **displays, int count) int dp_display_get_num_of_displays(void) { + if (!g_dp_display) + return 0; + return 1; } -- GitLab From 0324bbdd7b21cbb14cca399c4abc02cd1cd87969 Mon Sep 17 00:00:00 2001 From: Prashanth Vadde Date: Thu, 9 Aug 2018 14:46:12 +0530 Subject: [PATCH 0663/1001] ARM: dts: msm: Update GENI_IR node for QCS405 Update GENI-IR node in QCS405 to include it in sEVB100 and EVB4000 versions only. Change-Id: Ibea0614f9a79be96978ceb33880e2fd5ca0d696c Signed-off-by: Prashanth Vadde --- arch/arm64/boot/dts/qcom/qcs403.dtsi | 2 -- .../boot/dts/qcom/qcs405-geni-ir-overlay.dtsi | 35 +++++++++++++++++++ arch/arm64/boot/dts/qcom/qcs405-iot-sku2.dts | 1 + arch/arm64/boot/dts/qcom/qcs405-iot-sku3.dts | 1 + arch/arm64/boot/dts/qcom/qcs405-iot-sku4.dts | 1 + arch/arm64/boot/dts/qcom/qcs405-iot-sku5.dts | 1 + arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts | 1 + arch/arm64/boot/dts/qcom/qcs405-iot-sku7.dts | 1 + arch/arm64/boot/dts/qcom/qcs405-iot-sku8.dts | 1 + arch/arm64/boot/dts/qcom/qcs405.dtsi | 20 ----------- 10 files changed, 42 insertions(+), 22 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/qcs405-geni-ir-overlay.dtsi diff --git a/arch/arm64/boot/dts/qcom/qcs403.dtsi b/arch/arm64/boot/dts/qcom/qcs403.dtsi index 0934e29939ac..ddb57f3dd44d 100644 --- a/arch/arm64/boot/dts/qcom/qcs403.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs403.dtsi @@ -20,8 +20,6 @@ }; &soc { - /delete-node/ qcom,msm-geni-ir; - /delete-node/ qcom,msm-cpufreq; msm_cpufreq: qcom,msm-cpufreq { diff --git a/arch/arm64/boot/dts/qcom/qcs405-geni-ir-overlay.dtsi b/arch/arm64/boot/dts/qcom/qcs405-geni-ir-overlay.dtsi new file mode 100644 index 000000000000..95bbcd2ee793 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs405-geni-ir-overlay.dtsi @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qcs405-pinctrl.dtsi" + +&soc { + qcom,msm-geni-ir@740000 { + compatible = "qcom,msm-geni-ir"; + reg-names = "base"; + reg = <0x740000 0x1000>; + + interrupts = <0 59 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "geni-ir-core-irq"; + + clocks = <&clock_gcc GCC_GENI_IR_H_CLK>, + <&clock_gcc GCC_GENI_IR_S_CLK>; + clock-names = "iface_clk", "serial_clk"; + + pinctrl-names = "default"; + pinctrl-0 = <&ir_in_default>; + + resets = <&clock_gcc GCC_GENI_IR_BCR>; + reset-names = "geni_reset"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku2.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku2.dts index 1ff864c6fea7..2f034a8360f8 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku2.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku2.dts @@ -15,6 +15,7 @@ #include "qcs405.dtsi" #include "qcs405-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 4000 SPI IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku3.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku3.dts index 01426fac7078..198ccc831376 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku3.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku3.dts @@ -15,6 +15,7 @@ #include "qcs405.dtsi" #include "qcs405-nowcd-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" #include "qcs405-pinctrl.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku4.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku4.dts index 41e7bb1d2457..bbfce94ca0d8 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku4.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku4.dts @@ -15,6 +15,7 @@ #include "qcs405.dtsi" #include "qcs405-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 4000 DSI IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku5.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku5.dts index 2cb3dbb03341..695e0500101d 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku5.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku5.dts @@ -15,6 +15,7 @@ #include "qcs405.dtsi" #include "qcs405-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 4000 RGB IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts index a7e4149f4373..edd9d4d86dd0 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts @@ -15,6 +15,7 @@ #include "qcs405.dtsi" #include "qcs405-csra1-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 4000 CSRA1 IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku7.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku7.dts index b3b723b422b8..ceac14d652d3 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku7.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku7.dts @@ -15,6 +15,7 @@ #include "qcs405.dtsi" #include "qcs405-csra6-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 4000 CSRA6 IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku8.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku8.dts index ea43b030be69..ef26d1ae76d7 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku8.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku8.dts @@ -15,6 +15,7 @@ #include "qcs405.dtsi" #include "qcs405-amic-audio-overlay.dtsi" +#include "qcs405-geni-ir-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 4000 AMIC IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index 77f460faa5a7..13bb5fa4bd7e 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -1402,23 +1402,3 @@ extcon = <&usb3_extcon>; }; -&soc { - qcom,msm-geni-ir@740000 { - compatible = "qcom,msm-geni-ir"; - reg-names = "base"; - reg = <0x740000 0x1000>; - - interrupts = <0 59 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "geni-ir-core-irq"; - - clocks = <&clock_gcc GCC_GENI_IR_H_CLK>, - <&clock_gcc GCC_GENI_IR_S_CLK>; - clock-names = "iface_clk", "serial_clk"; - - pinctrl-names = "default"; - pinctrl-0 = <&ir_in_default>; - - resets = <&clock_gcc GCC_GENI_IR_BCR>; - reset-names = "geni_reset"; - }; -}; -- GitLab From 02f062d86d5f4a21f72a790e5f05b24203069bea Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Mon, 6 Aug 2018 12:58:30 +0530 Subject: [PATCH 0664/1001] msm: ipa: Validate routing rule id IPA driver expose routing rule id IOCTL's to user space. There is a chance of getting invalid routing rule id. Validate it before committing it to IPA hardware. Change-Id: If80b94d3a055f9212d25aff9a57d1b45001ba586 Signed-off-by: Mohammed Javid --- drivers/platform/msm/ipa/ipa_v3/ipa_rt.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c index 60017dff6b13..86161ccf0a21 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c @@ -923,6 +923,20 @@ static int __ipa_del_rt_tbl(struct ipa3_rt_tbl *entry) return 0; } +static int __ipa_rt_validate_rule_id(u16 rule_id) +{ + if (!rule_id) + return 0; + + if ((rule_id < ipahal_get_rule_id_hi_bit()) || + (rule_id >= ((ipahal_get_rule_id_hi_bit()<<1)-1))) { + IPAERR_RL("Invalid rule_id provided 0x%x\n", + rule_id); + return -EPERM; + } + + return 0; +} static int __ipa_rt_validate_hndls(const struct ipa_rt_rule *rule, struct ipa3_hdr_entry **hdr, struct ipa3_hdr_proc_ctx_entry **proc_ctx) @@ -1037,6 +1051,8 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, if (__ipa_rt_validate_hndls(rule, &hdr, &proc_ctx)) goto error; + if (__ipa_rt_validate_rule_id(rule_id)) + goto error; tbl = __ipa_add_rt_tbl(ip, name); if (tbl == NULL || (tbl->cookie != IPA_RT_TBL_COOKIE)) { -- GitLab From f05c2546c0c369f50b3bb7bdb0c56fe541933224 Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Mon, 6 Aug 2018 10:51:28 +0530 Subject: [PATCH 0665/1001] power: qpnp-qg: Add support for PM6150 Qgauge PM6150 supports a 10A resolution for IBAT. Enable the RECHARGE_SOC and CLK_ADJUST WA's. Change-Id: I5a48fcaad683c93ba9f24d3323d7b9b0888977c8 Signed-off-by: Anirudh Ghayal --- drivers/power/supply/qcom/qg-core.h | 2 ++ drivers/power/supply/qcom/qg-defs.h | 1 - drivers/power/supply/qcom/qg-reg.h | 5 ++++ drivers/power/supply/qcom/qg-util.c | 17 ++++++++++++- drivers/power/supply/qcom/qg-util.h | 1 + drivers/power/supply/qcom/qpnp-qg.c | 39 ++++++++++++++++++----------- 6 files changed, 49 insertions(+), 16 deletions(-) diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h index 70aa40c1134d..575b77aa3d01 100644 --- a/drivers/power/supply/qcom/qg-core.h +++ b/drivers/power/supply/qcom/qg-core.h @@ -96,6 +96,7 @@ struct qpnp_qg { struct votable *fifo_irq_disable_votable; struct votable *good_ocv_irq_disable_votable; u32 qg_base; + u8 qg_subtype; /* local data variables */ u32 batt_id_ohm; @@ -206,6 +207,7 @@ enum qg_irq { enum qg_wa_flags { QG_VBAT_LOW_WA = BIT(0), QG_RECHARGE_SOC_WA = BIT(1), + QG_CLK_ADJUST_WA = BIT(2), }; diff --git a/drivers/power/supply/qcom/qg-defs.h b/drivers/power/supply/qcom/qg-defs.h index 997ff701c77d..c398c697e014 100644 --- a/drivers/power/supply/qcom/qg-defs.h +++ b/drivers/power/supply/qcom/qg-defs.h @@ -37,7 +37,6 @@ #define TTF_AWAKE_VOTER "TTF_AWAKE_VOTER" #define V_RAW_TO_UV(V_RAW) div_u64(194637ULL * (u64)V_RAW, 1000) -#define I_RAW_TO_UA(I_RAW) div_s64(152588LL * (s64)I_RAW, 1000) #define FIFO_V_RESET_VAL 0x8000 #define FIFO_I_RESET_VAL 0x8000 diff --git a/drivers/power/supply/qcom/qg-reg.h b/drivers/power/supply/qcom/qg-reg.h index 894e0764301c..4048fd4d63a5 100644 --- a/drivers/power/supply/qcom/qg-reg.h +++ b/drivers/power/supply/qcom/qg-reg.h @@ -14,6 +14,11 @@ #define __QG_REG_H__ #define PERPH_TYPE_REG 0x04 + +#define PERPH_SUBTYPE_REG 0x05 +#define QG_ADC_IBAT_5A 0x3 +#define QG_ADC_IBAT_10A 0x4 + #define QG_TYPE 0x0D #define QG_STATUS1_REG 0x08 diff --git a/drivers/power/supply/qcom/qg-util.c b/drivers/power/supply/qcom/qg-util.c index 69eb4e9a848b..bd998c9652a5 100644 --- a/drivers/power/supply/qcom/qg-util.c +++ b/drivers/power/supply/qcom/qg-util.c @@ -127,6 +127,14 @@ int qg_read_raw_data(struct qpnp_qg *chip, int addr, u32 *data) return rc; } +s64 qg_iraw_to_ua(struct qpnp_qg *chip, int iraw) +{ + if (chip->qg_subtype == QG_ADC_IBAT_5A) + return div_s64(152588LL * (s64)iraw, 1000); + else + return div_s64(305176LL * (s64)iraw, 1000); +} + int get_fifo_length(struct qpnp_qg *chip, u32 *fifo_length, bool rt) { int rc; @@ -167,6 +175,8 @@ int get_sample_count(struct qpnp_qg *chip, u32 *sample_count) return rc; } +#define QG_CLK_RATE 32000 +#define QG_ACTUAL_CLK_RATE 32764 int get_sample_interval(struct qpnp_qg *chip, u32 *sample_interval) { int rc; @@ -181,6 +191,11 @@ int get_sample_interval(struct qpnp_qg *chip, u32 *sample_interval) *sample_interval = reg * 10; + if (chip->wa_flags & QG_CLK_ADJUST_WA) { + *sample_interval = DIV_ROUND_CLOSEST( + *sample_interval * QG_CLK_RATE, QG_ACTUAL_CLK_RATE); + } + return rc; } @@ -354,7 +369,7 @@ int qg_get_battery_current(struct qpnp_qg *chip, int *ibat_ua) } last_ibat = sign_extend32(last_ibat, 15); - *ibat_ua = I_RAW_TO_UA(last_ibat); + *ibat_ua = qg_iraw_to_ua(chip, last_ibat); release: /* release */ diff --git a/drivers/power/supply/qcom/qg-util.h b/drivers/power/supply/qcom/qg-util.h index 5dd6c85728f8..307b2ae54546 100644 --- a/drivers/power/supply/qcom/qg-util.h +++ b/drivers/power/supply/qcom/qg-util.h @@ -27,5 +27,6 @@ int qg_write_monotonic_soc(struct qpnp_qg *chip, int msoc); int qg_get_battery_temp(struct qpnp_qg *chip, int *batt_temp); int qg_get_battery_current(struct qpnp_qg *chip, int *ibat_ua); int qg_get_battery_voltage(struct qpnp_qg *chip, int *vbat_uv); +s64 qg_iraw_to_ua(struct qpnp_qg *chip, int iraw); #endif diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 09a109761f32..4b540ed49e0e 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -347,7 +347,7 @@ static int qg_process_fifo(struct qpnp_qg *chip, u32 fifo_length) temp = sign_extend32(fifo_i, 15); chip->kdata.fifo[j].v = V_RAW_TO_UV(fifo_v); - chip->kdata.fifo[j].i = I_RAW_TO_UA(temp); + chip->kdata.fifo[j].i = qg_iraw_to_ua(chip, temp); chip->kdata.fifo[j].interval = sample_interval; chip->kdata.fifo[j].count = sample_count; @@ -408,7 +408,7 @@ static int qg_process_accumulator(struct qpnp_qg *chip) temp = sign_extend64(acc_i, 23); chip->kdata.fifo[index].v = V_RAW_TO_UV(div_u64(acc_v, count)); - chip->kdata.fifo[index].i = I_RAW_TO_UA(div_s64(temp, count)); + chip->kdata.fifo[index].i = qg_iraw_to_ua(chip, div_s64(temp, count)); chip->kdata.fifo[index].interval = sample_interval; chip->kdata.fifo[index].count = count; chip->kdata.fifo_length++; @@ -966,11 +966,12 @@ static int qg_esr_estimate(struct qpnp_qg *chip) chip->esr_data[i].pre_esr_v = V_RAW_TO_UV(chip->esr_data[i].pre_esr_v); ibat = sign_extend32(chip->esr_data[i].pre_esr_i, 15); - chip->esr_data[i].pre_esr_i = I_RAW_TO_UA(ibat); + chip->esr_data[i].pre_esr_i = qg_iraw_to_ua(chip, ibat); chip->esr_data[i].post_esr_v = V_RAW_TO_UV(chip->esr_data[i].post_esr_v); ibat = sign_extend32(chip->esr_data[i].post_esr_i, 15); - chip->esr_data[i].post_esr_i = I_RAW_TO_UA(ibat); + chip->esr_data[i].post_esr_i = + qg_iraw_to_ua(chip, ibat); chip->esr_data[i].valid = true; @@ -2664,6 +2665,10 @@ static int qg_set_wa_flags(struct qpnp_qg *chip) if (chip->pmic_rev_id->rev4 == PMI632_V1P0_REV4) chip->wa_flags |= QG_VBAT_LOW_WA; break; + case PM6150_SUBTYPE: + chip->wa_flags |= QG_CLK_ADJUST_WA | + QG_RECHARGE_SOC_WA; + break; default: pr_err("Unsupported PMIC subtype %d\n", chip->pmic_rev_id->pmic_subtype); @@ -2681,6 +2686,14 @@ static int qg_hw_init(struct qpnp_qg *chip) int rc, temp; u8 reg; + /* read the QG perph_subtype */ + rc = qg_read(chip, chip->qg_base + PERPH_SUBTYPE_REG, + &chip->qg_subtype, 1); + if (rc < 0) { + pr_err("Failed to read QG subtype rc=%d", rc); + return rc; + } + rc = qg_set_wa_flags(chip); if (rc < 0) { pr_err("Failed to update PMIC type flags, rc=%d\n", rc); @@ -3589,21 +3602,19 @@ static int qpnp_qg_probe(struct platform_device *pdev) chip->batt_id_chan = iio_channel_get(&pdev->dev, "batt-id"); if (IS_ERR(chip->batt_id_chan)) { rc = PTR_ERR(chip->batt_id_chan); - if (rc != -EPROBE_DEFER) { + if (rc != -EPROBE_DEFER) pr_err("batt-id channel unavailable, rc=%d\n", rc); - chip->batt_id_chan = NULL; - return rc; - } + chip->batt_id_chan = NULL; + return rc; } chip->batt_therm_chan = iio_channel_get(&pdev->dev, "batt-therm"); if (IS_ERR(chip->batt_therm_chan)) { rc = PTR_ERR(chip->batt_therm_chan); - if (rc != -EPROBE_DEFER) { + if (rc != -EPROBE_DEFER) pr_err("batt-therm channel unavailable, rc=%d\n", rc); - chip->batt_therm_chan = NULL; - return rc; - } + chip->batt_therm_chan = NULL; + return rc; } chip->dev = &pdev->dev; @@ -3750,8 +3761,8 @@ static int qpnp_qg_probe(struct platform_device *pdev) } qg_get_battery_capacity(chip, &soc); - pr_info("QG initialized! battery_profile=%s SOC=%d\n", - qg_get_battery_type(chip), soc); + pr_info("QG initialized! battery_profile=%s SOC=%d QG_subtype=%d\n", + qg_get_battery_type(chip), soc, chip->qg_subtype); return rc; -- GitLab From 4fcb7655fb71d1488695d14d859fe5234c928d57 Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Tue, 24 Jul 2018 12:42:26 -0700 Subject: [PATCH 0666/1001] mhi: core: expose current state of MHI device to clients Some MHI control drivers and MHI clients needs current MHI device state, and execution environment to handle client specific requirements. CRs-Fixed: 2287705 Change-Id: I363508b393cc1e63827158b8b9f094ab380cb97c Signed-off-by: Sujeev Dias --- drivers/bus/mhi/core/mhi_boot.c | 2 +- drivers/bus/mhi/core/mhi_internal.h | 34 ++++------------------- drivers/bus/mhi/core/mhi_main.c | 16 +++++------ drivers/bus/mhi/core/mhi_pm.c | 19 ++++++++----- include/linux/mhi.h | 42 +++++++++++++++++++++++++++-- 5 files changed, 66 insertions(+), 47 deletions(-) diff --git a/drivers/bus/mhi/core/mhi_boot.c b/drivers/bus/mhi/core/mhi_boot.c index ff0dfccb8861..334a09ff8932 100644 --- a/drivers/bus/mhi/core/mhi_boot.c +++ b/drivers/bus/mhi/core/mhi_boot.c @@ -50,7 +50,7 @@ static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl) struct mhi_buf *mhi_buf; u32 sequence_id; u32 rx_status; - enum MHI_EE ee; + enum mhi_ee ee; struct image_info *rddm_image = mhi_cntrl->rddm_image; const u32 delayus = 100; u32 retry = (mhi_cntrl->timeout_ms * 1000) / delayus; diff --git a/drivers/bus/mhi/core/mhi_internal.h b/drivers/bus/mhi/core/mhi_internal.h index 520616f57a96..988894b34e6b 100644 --- a/drivers/bus/mhi/core/mhi_internal.h +++ b/drivers/bus/mhi/core/mhi_internal.h @@ -375,19 +375,6 @@ enum MHI_BRSTMODE { #define MHI_INVALID_BRSTMODE(mode) (mode != MHI_BRSTMODE_DISABLE && \ mode != MHI_BRSTMODE_ENABLE) -enum MHI_EE { - MHI_EE_PBL = 0x0, - MHI_EE_SBL = 0x1, - MHI_EE_AMSS = 0x2, - MHI_EE_BHIE = 0x3, - MHI_EE_RDDM = 0x4, - MHI_EE_PTHRU = 0x5, - MHI_EE_EDL = 0x6, - MHI_EE_MAX_SUPPORTED = MHI_EE_EDL, - MHI_EE_DISABLE_TRANSITION, /* local EE, not related to mhi spec */ - MHI_EE_MAX, -}; - extern const char * const mhi_ee_str[MHI_EE_MAX]; #define TO_MHI_EXEC_STR(ee) (((ee) >= MHI_EE_MAX) ? \ "INVALID_EE" : mhi_ee_str[ee]) @@ -408,18 +395,6 @@ extern const char * const mhi_state_tran_str[MHI_ST_TRANSITION_MAX]; #define TO_MHI_STATE_TRANS_STR(state) (((state) >= MHI_ST_TRANSITION_MAX) ? \ "INVALID_STATE" : mhi_state_tran_str[state]) -enum MHI_STATE { - MHI_STATE_RESET = 0x0, - MHI_STATE_READY = 0x1, - MHI_STATE_M0 = 0x2, - MHI_STATE_M1 = 0x3, - MHI_STATE_M2 = 0x4, - MHI_STATE_M3 = 0x5, - MHI_STATE_BHI = 0x7, - MHI_STATE_SYS_ERR = 0xFF, - MHI_STATE_MAX, -}; - extern const char * const mhi_state_str[MHI_STATE_MAX]; #define TO_MHI_STATE_STR(state) ((state >= MHI_STATE_MAX || \ !mhi_state_str[state]) ? \ @@ -596,7 +571,7 @@ struct mhi_chan { u32 intmod; enum dma_data_direction dir; struct db_cfg db_cfg; - enum MHI_EE ee; + enum mhi_ee ee; enum MHI_XFER_TYPE xfer_type; enum MHI_CH_STATE ch_state; enum MHI_EV_CCS ccs; @@ -663,8 +638,8 @@ enum MHI_PM_STATE __must_check mhi_tryset_pm_state( const char *to_mhi_pm_state_str(enum MHI_PM_STATE state); void mhi_reset_chan(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan); -enum MHI_EE mhi_get_exec_env(struct mhi_controller *mhi_cntrl); -enum MHI_STATE mhi_get_m_state(struct mhi_controller *mhi_cntrl); +enum mhi_ee mhi_get_exec_env(struct mhi_controller *mhi_cntrl); +enum mhi_dev_state mhi_get_m_state(struct mhi_controller *mhi_cntrl); int mhi_queue_state_transition(struct mhi_controller *mhi_cntrl, enum MHI_ST_TRANSITION state); void mhi_pm_st_worker(struct work_struct *work); @@ -720,7 +695,8 @@ void mhi_write_db(struct mhi_controller *mhi_cntrl, void __iomem *db_addr, void mhi_ring_cmd_db(struct mhi_controller *mhi_cntrl, struct mhi_cmd *mhi_cmd); void mhi_ring_chan_db(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan); -void mhi_set_mhi_state(struct mhi_controller *mhi_cntrl, enum MHI_STATE state); +void mhi_set_mhi_state(struct mhi_controller *mhi_cntrl, + enum mhi_dev_state state); int mhi_get_capability_offset(struct mhi_controller *mhi_cntrl, u32 capability, u32 *offset); int mhi_init_timesync(struct mhi_controller *mhi_cntrl); diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index 5b79d2fa168d..79749fc60a55 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -182,7 +182,7 @@ void mhi_ring_chan_db(struct mhi_controller *mhi_cntrl, db); } -enum MHI_EE mhi_get_exec_env(struct mhi_controller *mhi_cntrl) +enum mhi_ee mhi_get_exec_env(struct mhi_controller *mhi_cntrl) { u32 exec; int ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_EXECENV, &exec); @@ -190,7 +190,7 @@ enum MHI_EE mhi_get_exec_env(struct mhi_controller *mhi_cntrl) return (ret) ? MHI_EE_MAX : exec; } -enum MHI_STATE mhi_get_m_state(struct mhi_controller *mhi_cntrl) +enum mhi_dev_state mhi_get_m_state(struct mhi_controller *mhi_cntrl) { u32 state; int ret = mhi_read_reg_field(mhi_cntrl, mhi_cntrl->regs, MHISTATUS, @@ -920,7 +920,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, switch (type) { case MHI_PKT_TYPE_STATE_CHANGE_EVENT: { - enum MHI_STATE new_state; + enum mhi_dev_state new_state; new_state = MHI_TRE_GET_EV_STATE(local_rp); @@ -964,7 +964,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, case MHI_PKT_TYPE_EE_EVENT: { enum MHI_ST_TRANSITION st = MHI_ST_TRANSITION_MAX; - enum MHI_EE event = MHI_TRE_GET_EV_EXECENV(local_rp); + enum mhi_ee event = MHI_TRE_GET_EV_EXECENV(local_rp); MHI_LOG("MHI EE received event:%s\n", TO_MHI_EXEC_STR(event)); @@ -984,7 +984,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, write_lock_irq(&mhi_cntrl->pm_lock); mhi_cntrl->ee = event; write_unlock_irq(&mhi_cntrl->pm_lock); - wake_up(&mhi_cntrl->state_event); + wake_up_all(&mhi_cntrl->state_event); break; default: MHI_ERR("Unhandled EE event:%s\n", @@ -1160,7 +1160,7 @@ void mhi_ctrl_ev_task(unsigned long data) { struct mhi_event *mhi_event = (struct mhi_event *)data; struct mhi_controller *mhi_cntrl = mhi_event->mhi_cntrl; - enum MHI_STATE state = MHI_STATE_MAX; + enum mhi_dev_state state = MHI_STATE_MAX; enum MHI_PM_STATE pm_state = 0; int ret; @@ -1218,7 +1218,7 @@ irqreturn_t mhi_msi_handlr(int irq_number, void *dev) irqreturn_t mhi_intvec_threaded_handlr(int irq_number, void *dev) { struct mhi_controller *mhi_cntrl = dev; - enum MHI_STATE state = MHI_STATE_MAX; + enum mhi_dev_state state = MHI_STATE_MAX; enum MHI_PM_STATE pm_state = 0; MHI_VERB("Enter\n"); @@ -1247,7 +1247,7 @@ irqreturn_t mhi_intvec_handlr(int irq_number, void *dev) /* wake up any events waiting for state change */ MHI_VERB("Enter\n"); - wake_up(&mhi_cntrl->state_event); + wake_up_all(&mhi_cntrl->state_event); MHI_VERB("Exit\n"); return IRQ_WAKE_THREAD; diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c index 6ad7a1c6d7e9..cbae02a8dc64 100644 --- a/drivers/bus/mhi/core/mhi_pm.c +++ b/drivers/bus/mhi/core/mhi_pm.c @@ -148,7 +148,8 @@ enum MHI_PM_STATE __must_check mhi_tryset_pm_state( return mhi_cntrl->pm_state; } -void mhi_set_mhi_state(struct mhi_controller *mhi_cntrl, enum MHI_STATE state) +void mhi_set_mhi_state(struct mhi_controller *mhi_cntrl, + enum mhi_dev_state state) { if (state == MHI_STATE_RESET) { mhi_write_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL, @@ -357,7 +358,7 @@ int mhi_pm_m0_transition(struct mhi_controller *mhi_cntrl) mhi_cntrl->wake_put(mhi_cntrl, false); read_unlock_bh(&mhi_cntrl->pm_lock); - wake_up(&mhi_cntrl->state_event); + wake_up_all(&mhi_cntrl->state_event); MHI_VERB("Exited\n"); return 0; @@ -377,6 +378,7 @@ void mhi_pm_m1_transition(struct mhi_controller *mhi_cntrl) mhi_cntrl->M2++; write_unlock_irq(&mhi_cntrl->pm_lock); + wake_up_all(&mhi_cntrl->state_event); /* transfer pending, exit M2 immediately */ if (unlikely(atomic_read(&mhi_cntrl->dev_wake))) { @@ -409,7 +411,7 @@ int mhi_pm_m3_transition(struct mhi_controller *mhi_cntrl) to_mhi_pm_state_str(mhi_cntrl->pm_state)); return -EIO; } - wake_up(&mhi_cntrl->state_event); + wake_up_all(&mhi_cntrl->state_event); mhi_cntrl->M3++; MHI_LOG("Entered mhi_state:%s pm_state:%s\n", @@ -428,7 +430,7 @@ static int mhi_pm_amss_transition(struct mhi_controller *mhi_cntrl) write_lock_irq(&mhi_cntrl->pm_lock); mhi_cntrl->ee = MHI_EE_AMSS; write_unlock_irq(&mhi_cntrl->pm_lock); - wake_up(&mhi_cntrl->state_event); + wake_up_all(&mhi_cntrl->state_event); /* add elements to all HW event rings */ read_lock_bh(&mhi_cntrl->pm_lock); @@ -498,6 +500,9 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl, } write_unlock_irq(&mhi_cntrl->pm_lock); + /* wake up any threads waiting for state transitions */ + wake_up_all(&mhi_cntrl->state_event); + /* not handling sys_err, could be middle of shut down */ if (cur_state != transition_state) { MHI_LOG("Failed to transition to state:0x%x from:0x%x\n", @@ -550,7 +555,7 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl, /* release lock and wait for all pending thread to complete */ mutex_unlock(&mhi_cntrl->pm_mutex); MHI_LOG("Waiting for all pending threads to complete\n"); - wake_up(&mhi_cntrl->state_event); + wake_up_all(&mhi_cntrl->state_event); flush_work(&mhi_cntrl->st_worker); flush_work(&mhi_cntrl->fw_worker); @@ -697,7 +702,7 @@ void mhi_pm_st_worker(struct work_struct *work) mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl); write_unlock_irq(&mhi_cntrl->pm_lock); if (MHI_IN_PBL(mhi_cntrl->ee)) - wake_up(&mhi_cntrl->state_event); + wake_up_all(&mhi_cntrl->state_event); break; case MHI_ST_TRANSITION_SBL: write_lock_irq(&mhi_cntrl->pm_lock); @@ -722,7 +727,7 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) { int ret; u32 val; - enum MHI_EE current_ee; + enum mhi_ee current_ee; enum MHI_ST_TRANSITION next_state; MHI_LOG("Requested to power on\n"); diff --git a/include/linux/mhi.h b/include/linux/mhi.h index 40846e64ceaf..ced8dd1a769e 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -72,6 +72,44 @@ enum mhi_device_type { MHI_CONTROLLER_TYPE, }; +/** + * enum mhi_ee - device current execution enviornment + * @MHI_EE_PBL - device in PBL + * @MHI_EE_SBL - device in SBL + * @MHI_EE_AMSS - device in mission mode (firmware fully loaded) + * @MHI_EE_BHIE - device in special SBL that support BHI/e protocol + * @MHI_EE_RDDM - device in ram dump collection mode + * @MHI_EE_PTHRU - device in PBL but configured in pass thru mode + * @MHI_EE_EDL - device in emergency download mode + */ +enum mhi_ee { + MHI_EE_PBL = 0x0, + MHI_EE_SBL = 0x1, + MHI_EE_AMSS = 0x2, + MHI_EE_BHIE = 0x3, + MHI_EE_RDDM = 0x4, + MHI_EE_PTHRU = 0x5, + MHI_EE_EDL = 0x6, + MHI_EE_MAX_SUPPORTED = MHI_EE_EDL, + MHI_EE_DISABLE_TRANSITION, /* local EE, not related to mhi spec */ + MHI_EE_MAX, +}; + +/** + * enum mhi_dev_state - device current MHI state + */ +enum mhi_dev_state { + MHI_STATE_RESET = 0x0, + MHI_STATE_READY = 0x1, + MHI_STATE_M0 = 0x2, + MHI_STATE_M1 = 0x3, + MHI_STATE_M2 = 0x4, + MHI_STATE_M3 = 0x5, + MHI_STATE_BHI = 0x7, + MHI_STATE_SYS_ERR = 0xFF, + MHI_STATE_MAX, +}; + /** * struct image_info - firmware and rddm table table * @mhi_buf - Contain device firmware and rddm table @@ -195,8 +233,8 @@ struct mhi_controller { bool pre_init; rwlock_t pm_lock; u32 pm_state; - u32 ee; - u32 dev_state; + enum mhi_ee ee; + enum mhi_dev_state dev_state; bool wake_set; atomic_t dev_wake; atomic_t alloc_size; -- GitLab From 871477bcd6e0a989081da6c44fc11e042334f73a Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Fri, 10 Aug 2018 20:53:29 +0530 Subject: [PATCH 0667/1001] ARM: dts: msm: Update VADC support for PM6150 Correct name of channel vbat_sns. Change-Id: Iaf1542c9fce15fcfebb6c1d1d00928eba22d305c Signed-off-by: Jishnu Prakash --- arch/arm64/boot/dts/qcom/pm6150.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/pm6150.dtsi b/arch/arm64/boot/dts/qcom/pm6150.dtsi index 361394d60d0a..7e65025d0625 100644 --- a/arch/arm64/boot/dts/qcom/pm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/pm6150.dtsi @@ -91,7 +91,7 @@ vbat_sns { reg = ; - label = "vph_pwr"; + label = "vbat_sns"; qcom,pre-scaling = <1 3>; }; -- GitLab From 34a5ec3a5dff4751dbf9406e2a758bb2039a9dbb Mon Sep 17 00:00:00 2001 From: Sreelakshmi Gownipalli Date: Thu, 26 Jul 2018 12:12:27 -0700 Subject: [PATCH 0668/1001] diag: Enable diag over rpmsg communication Enable apps to wdsp diag communication over rpmsg. Changes were made to copy the data from glink buffer into diag buffer in the callback and queue a work to process the data in work queue and release the diag buffer in work queue. Change-Id: I53681785a72046bb5d0e9fa7461b97c0f776d412 Signed-off-by: Sreelakshmi Gownipalli --- drivers/char/diag/diag_masks.c | 3 + drivers/char/diag/diagfwd_peripheral.c | 6 +- drivers/char/diag/diagfwd_rpmsg.c | 160 ++++++++++++++++++++++--- drivers/char/diag/diagfwd_rpmsg.h | 5 +- 4 files changed, 152 insertions(+), 22 deletions(-) diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index 75413b9e472d..39e4933a0fdc 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -2209,6 +2209,9 @@ int diag_copy_to_user_log_mask(char __user *buf, size_t count, void diag_send_updates_peripheral(uint8_t peripheral) { + if (!driver->feature[peripheral].rcvd_feature_mask) + return; + if (!driver->feature[peripheral].sent_feature_mask) diag_send_feature_mask_update(peripheral); /* diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index 70bd169d84e2..772b05bed3fe 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -1081,8 +1081,10 @@ void diagfwd_close_transport(uint8_t transport, uint8_t peripheral) mutex_lock(&driver->diagfwd_channel_mutex[peripheral]); fwd_info = &early_init_info[transport][peripheral]; + mutex_unlock(&driver->diagfwd_channel_mutex[peripheral]); if (fwd_info->p_ops && fwd_info->p_ops->close) fwd_info->p_ops->close(fwd_info->ctxt); + mutex_lock(&driver->diagfwd_channel_mutex[peripheral]); fwd_info = &early_init_info[transport_open][peripheral]; dest_info = &peripheral_info[TYPE_CNTL][peripheral]; dest_info->inited = 1; @@ -1106,9 +1108,7 @@ void diagfwd_close_transport(uint8_t transport, uint8_t peripheral) * GLINK. GLINK supported peripheral mask update will * happen after glink buffers are initialized. */ - - if (dest_info->transport != TRANSPORT_RPMSG) - diagfwd_cntl_open(dest_info); + diagfwd_cntl_open(dest_info); init_fn(peripheral); mutex_unlock(&driver->diagfwd_channel_mutex[peripheral]); diagfwd_queue_read(&peripheral_info[TYPE_DATA][peripheral]); diff --git a/drivers/char/diag/diagfwd_rpmsg.c b/drivers/char/diag/diagfwd_rpmsg.c index b5aafc31ba3a..3647c18ed5bd 100644 --- a/drivers/char/diag/diagfwd_rpmsg.c +++ b/drivers/char/diag/diagfwd_rpmsg.c @@ -29,13 +29,22 @@ #include "diagfwd_rpmsg.h" #include "diag_ipc_logging.h" +struct diag_rpmsg_read_work { + struct diag_rpmsg_info *rpmsg_info; + const void *ptr_read_done; + const void *ptr_rx_done; + size_t ptr_read_size; + struct work_struct work; +}; + struct diag_rpmsg_info rpmsg_data[NUM_PERIPHERALS] = { { .peripheral = PERIPHERAL_MODEM, .type = TYPE_DATA, .edge = "mpss", .name = "DIAG_DATA", - .buf = NULL, + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -43,7 +52,8 @@ struct diag_rpmsg_info rpmsg_data[NUM_PERIPHERALS] = { .type = TYPE_DATA, .edge = "lpass", .name = "DIAG_DATA", - .buf = NULL, + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -51,7 +61,8 @@ struct diag_rpmsg_info rpmsg_data[NUM_PERIPHERALS] = { .type = TYPE_DATA, .edge = "wcnss", .name = "DIAG_DATA", - .buf = NULL, + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -59,7 +70,8 @@ struct diag_rpmsg_info rpmsg_data[NUM_PERIPHERALS] = { .type = TYPE_DATA, .edge = "dsps", .name = "DIAG_DATA", - .buf = NULL, + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -67,7 +79,8 @@ struct diag_rpmsg_info rpmsg_data[NUM_PERIPHERALS] = { .type = TYPE_DATA, .edge = "wdsp", .name = "DIAG_DATA", - .buf = NULL, + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -75,7 +88,8 @@ struct diag_rpmsg_info rpmsg_data[NUM_PERIPHERALS] = { .type = TYPE_DATA, .edge = "cdsp", .name = "DIAG_DATA", - .buf = NULL, + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL } }; @@ -86,6 +100,8 @@ struct diag_rpmsg_info rpmsg_cntl[NUM_PERIPHERALS] = { .type = TYPE_CNTL, .edge = "mpss", .name = "DIAG_CTRL", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -93,6 +109,8 @@ struct diag_rpmsg_info rpmsg_cntl[NUM_PERIPHERALS] = { .type = TYPE_CNTL, .edge = "lpass", .name = "DIAG_CTRL", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -100,6 +118,8 @@ struct diag_rpmsg_info rpmsg_cntl[NUM_PERIPHERALS] = { .type = TYPE_CNTL, .edge = "wcnss", .name = "DIAG_CTRL", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -107,6 +127,8 @@ struct diag_rpmsg_info rpmsg_cntl[NUM_PERIPHERALS] = { .type = TYPE_CNTL, .edge = "dsps", .name = "DIAG_CTRL", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -114,6 +136,8 @@ struct diag_rpmsg_info rpmsg_cntl[NUM_PERIPHERALS] = { .type = TYPE_CNTL, .edge = "wdsp", .name = "DIAG_CTRL", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -121,6 +145,8 @@ struct diag_rpmsg_info rpmsg_cntl[NUM_PERIPHERALS] = { .type = TYPE_CNTL, .edge = "cdsp", .name = "DIAG_CTRL", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL } }; @@ -131,6 +157,8 @@ struct diag_rpmsg_info rpmsg_dci[NUM_PERIPHERALS] = { .type = TYPE_DCI, .edge = "mpss", .name = "DIAG_DCI_DATA", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -138,6 +166,8 @@ struct diag_rpmsg_info rpmsg_dci[NUM_PERIPHERALS] = { .type = TYPE_DCI, .edge = "lpass", .name = "DIAG_DCI_DATA", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -145,6 +175,8 @@ struct diag_rpmsg_info rpmsg_dci[NUM_PERIPHERALS] = { .type = TYPE_DCI, .edge = "wcnss", .name = "DIAG_DCI_DATA", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -152,6 +184,8 @@ struct diag_rpmsg_info rpmsg_dci[NUM_PERIPHERALS] = { .type = TYPE_DCI, .edge = "dsps", .name = "DIAG_DCI_DATA", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -159,6 +193,8 @@ struct diag_rpmsg_info rpmsg_dci[NUM_PERIPHERALS] = { .type = TYPE_DCI, .edge = "wdsp", .name = "DIAG_DCI_DATA", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -166,6 +202,8 @@ struct diag_rpmsg_info rpmsg_dci[NUM_PERIPHERALS] = { .type = TYPE_DCI, .edge = "cdsp", .name = "DIAG_DCI_DATA", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL } }; @@ -176,6 +214,8 @@ struct diag_rpmsg_info rpmsg_cmd[NUM_PERIPHERALS] = { .type = TYPE_CMD, .edge = "mpss", .name = "DIAG_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -183,6 +223,8 @@ struct diag_rpmsg_info rpmsg_cmd[NUM_PERIPHERALS] = { .type = TYPE_CMD, .edge = "lpass", .name = "DIAG_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -190,6 +232,8 @@ struct diag_rpmsg_info rpmsg_cmd[NUM_PERIPHERALS] = { .type = TYPE_CMD, .edge = "wcnss", .name = "DIAG_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -197,6 +241,8 @@ struct diag_rpmsg_info rpmsg_cmd[NUM_PERIPHERALS] = { .type = TYPE_CMD, .edge = "dsps", .name = "DIAG_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -204,6 +250,8 @@ struct diag_rpmsg_info rpmsg_cmd[NUM_PERIPHERALS] = { .type = TYPE_CMD, .edge = "wdsp", .name = "DIAG_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -211,6 +259,8 @@ struct diag_rpmsg_info rpmsg_cmd[NUM_PERIPHERALS] = { .type = TYPE_CMD, .edge = "cdsp", .name = "DIAG_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL } }; @@ -221,6 +271,8 @@ struct diag_rpmsg_info rpmsg_dci_cmd[NUM_PERIPHERALS] = { .type = TYPE_DCI_CMD, .edge = "mpss", .name = "DIAG_DCI_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -228,6 +280,8 @@ struct diag_rpmsg_info rpmsg_dci_cmd[NUM_PERIPHERALS] = { .type = TYPE_DCI_CMD, .edge = "lpass", .name = "DIAG_DCI_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -235,6 +289,8 @@ struct diag_rpmsg_info rpmsg_dci_cmd[NUM_PERIPHERALS] = { .type = TYPE_DCI_CMD, .edge = "wcnss", .name = "DIAG_DCI_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -242,6 +298,8 @@ struct diag_rpmsg_info rpmsg_dci_cmd[NUM_PERIPHERALS] = { .type = TYPE_DCI_CMD, .edge = "dsps", .name = "DIAG_DCI_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -249,6 +307,8 @@ struct diag_rpmsg_info rpmsg_dci_cmd[NUM_PERIPHERALS] = { .type = TYPE_DCI_CMD, .edge = "wdsp", .name = "DIAG_DCI_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL }, { @@ -256,6 +316,8 @@ struct diag_rpmsg_info rpmsg_dci_cmd[NUM_PERIPHERALS] = { .type = TYPE_DCI_CMD, .edge = "cdsp", .name = "DIAG_DCI_CMD", + .buf1 = NULL, + .buf2 = NULL, .hdl = NULL } }; @@ -265,7 +327,7 @@ static void diag_state_close_rpmsg(void *ctxt); static int diag_rpmsg_write(void *ctxt, unsigned char *buf, int len); static int diag_rpmsg_read(void *ctxt, unsigned char *buf, int buf_len); static void diag_rpmsg_queue_read(void *ctxt); - +static void diag_rpmsg_notify_rx_work_fn(struct work_struct *work); static struct diag_peripheral_ops rpmsg_ops = { .open = diag_state_open_rpmsg, .close = diag_state_close_rpmsg, @@ -341,7 +403,11 @@ static int diag_rpmsg_read(void *ctxt, unsigned char *buf, int buf_len) "diag:RPMSG channel not opened"); return -EIO; } - rpmsg_info->buf = buf; + if (!rpmsg_info->buf1) + rpmsg_info->buf1 = buf; + else if (!rpmsg_info->buf2) + rpmsg_info->buf2 = buf; + return ret_val; } @@ -418,9 +484,10 @@ static void diag_rpmsg_open_work_fn(struct work_struct *work) return; if (!rpmsg_info->inited) return; - atomic_set(&rpmsg_info->opened, 1); - diagfwd_channel_open(rpmsg_info->fwd_ctxt); - diagfwd_late_open(rpmsg_info->fwd_ctxt); + if (rpmsg_info->type != TYPE_CNTL) { + diagfwd_channel_open(rpmsg_info->fwd_ctxt); + diagfwd_late_open(rpmsg_info->fwd_ctxt); + } DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n", rpmsg_info->name); } @@ -442,16 +509,71 @@ static int diag_rpmsg_notify_cb(struct rpmsg_device *rpdev, void *data, int len, void *priv, u32 src) { struct diag_rpmsg_info *rpmsg_info = NULL; + struct diag_rpmsg_read_work *read_work; + void *buf; - rpmsg_info = (struct diag_rpmsg_info *)priv; + rpmsg_info = dev_get_drvdata(&rpdev->dev); if (!rpmsg_info) return 0; - memcpy(rpmsg_info->buf, data, len); - diagfwd_channel_read_done(rpmsg_info->fwd_ctxt, rpmsg_info->buf, len); - rpmsg_info->buf = NULL; + + if (!rpmsg_info->buf1 && !rpmsg_info->buf2) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "dropping data for %s len %d\n", + rpmsg_info->name, len); + return 0; + } + + if (rpmsg_info->buf1) + buf = rpmsg_info->buf1; + else + buf = rpmsg_info->buf2; + + if (!buf) + return 0; + + memcpy(buf, data, len); + + read_work = kmalloc(sizeof(*read_work), GFP_ATOMIC); + if (!read_work) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Could not allocate read_work\n"); + return 0; + } + read_work->rpmsg_info = rpmsg_info; + read_work->ptr_read_done = buf; + read_work->ptr_read_size = len; + INIT_WORK(&read_work->work, diag_rpmsg_notify_rx_work_fn); + queue_work(rpmsg_info->wq, &read_work->work); return 0; } +static void diag_rpmsg_notify_rx_work_fn(struct work_struct *work) +{ + struct diag_rpmsg_read_work *read_work = container_of(work, + struct diag_rpmsg_read_work, work); + struct diag_rpmsg_info *rpmsg_info = read_work->rpmsg_info; + struct mutex *channel_mutex; + + if (!rpmsg_info || !rpmsg_info->hdl) { + kfree(read_work); + return; + } + + channel_mutex = &driver->diagfwd_channel_mutex[rpmsg_info->peripheral]; + mutex_lock(channel_mutex); + diagfwd_channel_read_done(rpmsg_info->fwd_ctxt, + (unsigned char *)(read_work->ptr_read_done), + read_work->ptr_read_size); + mutex_unlock(channel_mutex); + + if (read_work->ptr_read_done == rpmsg_info->buf1) + rpmsg_info->buf1 = NULL; + else if (read_work->ptr_read_done == rpmsg_info->buf2) + rpmsg_info->buf2 = NULL; + + kfree(read_work); +} + static void rpmsg_late_init(struct diag_rpmsg_info *rpmsg_info) { struct diagfwd_info *fwd_info = NULL; @@ -547,6 +669,8 @@ int diag_rpmsg_init(void) (void *)rpmsg_info, &rpmsg_ops, &(rpmsg_info->fwd_ctxt)); rpmsg_info->inited = 1; + diagfwd_channel_open(rpmsg_info->fwd_ctxt); + diagfwd_late_open(rpmsg_info->fwd_ctxt); __diag_rpmsg_init(&rpmsg_data[peripheral]); __diag_rpmsg_init(&rpmsg_cmd[peripheral]); __diag_rpmsg_init(&rpmsg_dci[peripheral]); @@ -606,7 +730,7 @@ static struct diag_rpmsg_info *diag_get_rpmsg_ptr(char *name) return NULL; if (!strcmp(name, "DIAG_CMD")) return &rpmsg_cmd[PERIPHERAL_WDSP]; - else if (!strcmp(name, "DIAG_CNTL")) + else if (!strcmp(name, "DIAG_CTRL")) return &rpmsg_cntl[PERIPHERAL_WDSP]; else if (!strcmp(name, "DIAG_DATA")) return &rpmsg_data[PERIPHERAL_WDSP]; @@ -631,6 +755,8 @@ static int diag_rpmsg_probe(struct rpmsg_device *rpdev) if (rpmsg_info) { rpmsg_info->hdl = rpdev; dev_set_drvdata(&rpdev->dev, rpmsg_info); + atomic_set(&rpmsg_info->opened, 1); + diagfwd_channel_read(rpmsg_info->fwd_ctxt); queue_work(rpmsg_info->wq, &rpmsg_info->open_work); } @@ -651,7 +777,7 @@ static void diag_rpmsg_remove(struct rpmsg_device *rpdev) static struct rpmsg_device_id rpmsg_diag_table[] = { { .name = "DIAG_CMD" }, - { .name = "DIAG_CNTL" }, + { .name = "DIAG_CTRL" }, { .name = "DIAG_DATA" }, { .name = "DIAG_DCI_CMD" }, { .name = "DIAG_DCI_DATA" }, diff --git a/drivers/char/diag/diagfwd_rpmsg.h b/drivers/char/diag/diagfwd_rpmsg.h index 44b195952b33..2bed0324912a 100644 --- a/drivers/char/diag/diagfwd_rpmsg.h +++ b/drivers/char/diag/diagfwd_rpmsg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -35,7 +35,8 @@ struct diag_rpmsg_info { struct work_struct read_work; struct work_struct late_init_work; struct diagfwd_info *fwd_ctxt; - void *buf; + void *buf1; + void *buf2; }; extern struct diag_rpmsg_info rpmsg_data[NUM_PERIPHERALS]; -- GitLab From 76663f56fb8c1c9d5727217ba226c33f4868ec07 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Tue, 24 Jul 2018 10:43:15 -0700 Subject: [PATCH 0669/1001] net: qrtr: mhi: Create list for pending ul transfers QRTR does not serialize sends like the dl path. Create a list of pending transactions so multiple transfers can happen at the same time without corruption. If there is a sock attached to the skb, take a reference to the sock. This prevents the sock from being released while waiting for the ul callback from MHI. Change-Id: I2d9359ec616497f3dda4f2762d142cdd33796a88 Signed-off-by: Chris Lew --- net/qrtr/mhi.c | 79 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 17 deletions(-) diff --git a/net/qrtr/mhi.c b/net/qrtr/mhi.c index 9370e48b5cbe..85a8a1a99944 100644 --- a/net/qrtr/mhi.c +++ b/net/qrtr/mhi.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "qrtr.h" @@ -21,9 +22,29 @@ struct qrtr_mhi_dev { struct qrtr_endpoint ep; struct mhi_device *mhi_dev; struct device *dev; - struct completion ul_done; + spinlock_t ul_lock; /* lock to protect ul_pkts */ + struct list_head ul_pkts; }; +struct qrtr_mhi_pkt { + struct list_head node; + struct sk_buff *skb; + struct kref refcount; + struct completion done; +}; + +static void qrtr_mhi_pkt_release(struct kref *ref) +{ + struct qrtr_mhi_pkt *pkt = container_of(ref, struct qrtr_mhi_pkt, + refcount); + struct sock *sk = pkt->skb->sk; + + consume_skb(pkt->skb); + if (sk) + sock_put(sk); + kfree(pkt); +} + /* from mhi to qrtr */ static void qcom_mhi_qrtr_dl_callback(struct mhi_device *mhi_dev, struct mhi_result *mhi_res) @@ -45,39 +66,63 @@ static void qcom_mhi_qrtr_ul_callback(struct mhi_device *mhi_dev, struct mhi_result *mhi_res) { struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev); - struct sk_buff *skb = mhi_res->buf_addr; + struct qrtr_mhi_pkt *pkt; - if (!mhi_res->transaction_status) { - complete(&qdev->ul_done); - consume_skb(skb); - } else { - kfree_skb(skb); - } + spin_lock_bh(&qdev->ul_lock); + pkt = list_first_entry(&qdev->ul_pkts, struct qrtr_mhi_pkt, node); + list_del(&pkt->node); + complete_all(&pkt->done); + + kref_put(&pkt->refcount, qrtr_mhi_pkt_release); + spin_unlock_bh(&qdev->ul_lock); } /* from qrtr to mhi */ static int qcom_mhi_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb) { struct qrtr_mhi_dev *qdev = container_of(ep, struct qrtr_mhi_dev, ep); + struct qrtr_mhi_pkt *pkt; int rc; rc = skb_linearize(skb); - if (rc) - goto out; + if (rc) { + kfree_skb(skb); + return rc; + } + + pkt = kzalloc(sizeof(*pkt), GFP_KERNEL); + if (!pkt) { + kfree_skb(skb); + return -ENOMEM; + } - reinit_completion(&qdev->ul_done); + init_completion(&pkt->done); + kref_init(&pkt->refcount); + kref_get(&pkt->refcount); + pkt->skb = skb; + + spin_lock_bh(&qdev->ul_lock); + list_add_tail(&pkt->node, &qdev->ul_pkts); rc = mhi_queue_transfer(qdev->mhi_dev, DMA_TO_DEVICE, skb, skb->len, MHI_EOT); - if (rc) - goto out; + if (rc) { + list_del(&pkt->node); + kfree_skb(skb); + kfree(pkt); + spin_unlock_bh(&qdev->ul_lock); + return rc; + } + spin_unlock_bh(&qdev->ul_lock); + if (skb->sk) + sock_hold(skb->sk); - rc = wait_for_completion_interruptible_timeout(&qdev->ul_done, HZ * 5); + rc = wait_for_completion_interruptible_timeout(&pkt->done, HZ * 5); if (rc > 0) rc = 0; else if (rc == 0) rc = -ETIMEDOUT; -out: + kref_put(&pkt->refcount, qrtr_mhi_pkt_release); return rc; } @@ -95,7 +140,8 @@ static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev, qdev->dev = &mhi_dev->dev; qdev->ep.xmit = qcom_mhi_qrtr_send; - init_completion(&qdev->ul_done); + INIT_LIST_HEAD(&qdev->ul_pkts); + spin_lock_init(&qdev->ul_lock); rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO); if (rc) @@ -113,7 +159,6 @@ static void qcom_mhi_qrtr_remove(struct mhi_device *mhi_dev) struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev); qrtr_endpoint_unregister(&qdev->ep); - complete(&qdev->ul_done); dev_set_drvdata(&mhi_dev->dev, NULL); } -- GitLab From 6489cf0c9a33c000578029485af22384d71866c7 Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Tue, 31 Jul 2018 18:12:44 -0700 Subject: [PATCH 0670/1001] power: smb5-lib: Modify max USBIN voltage seen by userspace Non-QC2.0-compliant adaptors, as the name suggests, support only a subset of the three voltage levels (5, 9 and 12V). For example, a non-compliant adaptor might support only up to 9V and not 12V (5V is supported as a bare minimum). Thus, when a request for 12V is made, it will collapse and unexpected behaviour will ensue. Therefore for such adaptors, modify the maximum USBIN voltage provided to userspace as follows: return the voltage that is the next lesser value than the voltage that has been determined to be unsupported by the adaptor. Also, reject all requests from userspace for these unsupported voltage levels. NOTE: This is only applicable to platforms that use SW INOV. The existing MAX_PULSES based solution works only for platforms that use HW INOV. To be clear, modifying the MAX_PULSES register happens in both HW and SW INOV modes, but only produces the desired effect in SW INOV mode. These two solutions do not interfere with each other and can coexist. Change-Id: I99abea1651c5c89d5d895eb51587e30c0d5c52ea Signed-off-by: Guru Das Srinagesh --- drivers/power/supply/qcom/smb5-lib.c | 29 ++++++++++++++++++++++++---- drivers/power/supply/qcom/smb5-lib.h | 8 +++++++- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 2f3717e79039..ca779e39a0d1 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -1893,11 +1893,21 @@ int smblib_dp_dm(struct smb_charger *chg, int val) pr_err("Failed to force 5V\n"); break; case POWER_SUPPLY_DP_DM_FORCE_9V: + if (chg->qc2_unsupported_voltage == QC2_NON_COMPLIANT_9V) { + smblib_err(chg, "Couldn't set 9V: unsupported\n"); + return -EINVAL; + } + rc = smblib_force_vbus_voltage(chg, FORCE_9V_BIT); if (rc < 0) pr_err("Failed to force 9V\n"); break; case POWER_SUPPLY_DP_DM_FORCE_12V: + if (chg->qc2_unsupported_voltage == QC2_NON_COMPLIANT_12V) { + smblib_err(chg, "Couldn't set 12V: unsupported\n"); + return -EINVAL; + } + rc = smblib_force_vbus_voltage(chg, FORCE_12V_BIT); if (rc < 0) pr_err("Failed to force 12V\n"); @@ -2094,6 +2104,15 @@ int smblib_get_prop_usb_voltage_max(struct smb_charger *chg, { switch (chg->real_charger_type) { case POWER_SUPPLY_TYPE_USB_HVDCP: + if (chg->qc2_unsupported_voltage == QC2_NON_COMPLIANT_9V) { + val->intval = MICRO_5V; + break; + } else if (chg->qc2_unsupported_voltage == + QC2_NON_COMPLIANT_12V) { + val->intval = MICRO_9V; + break; + } + /* else, fallthrough */ case POWER_SUPPLY_TYPE_USB_HVDCP_3: case POWER_SUPPLY_TYPE_USB_PD: if (chg->smb_version == PMI632_SUBTYPE) @@ -3118,7 +3137,8 @@ irqreturn_t usbin_uv_irq_handler(int irq, void *data) wdata = &chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data->storm_data; reset_storm_count(wdata); - if (!chg->non_compliant_chg_detected && + /* Workaround for non-QC2.0-compliant chargers follows */ + if (!chg->qc2_unsupported_voltage && apsd->pst == POWER_SUPPLY_TYPE_USB_HVDCP) { rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat); if (rc < 0) @@ -3133,11 +3153,11 @@ irqreturn_t usbin_uv_irq_handler(int irq, void *data) smblib_err(chg, "Couldn't read QC2 max pulses rc=%d\n", rc); - chg->non_compliant_chg_detected = true; chg->qc2_max_pulses = (max_pulses & HVDCP_PULSE_COUNT_MAX_QC2_MASK); if (stat & QC_12V_BIT) { + chg->qc2_unsupported_voltage = QC2_NON_COMPLIANT_12V; rc = smblib_masked_write(chg, HVDCP_PULSE_COUNT_MAX_REG, HVDCP_PULSE_COUNT_MAX_QC2_MASK, HVDCP_PULSE_COUNT_MAX_QC2_9V); @@ -3146,6 +3166,7 @@ irqreturn_t usbin_uv_irq_handler(int irq, void *data) rc); } else if (stat & QC_9V_BIT) { + chg->qc2_unsupported_voltage = QC2_NON_COMPLIANT_9V; rc = smblib_masked_write(chg, HVDCP_PULSE_COUNT_MAX_REG, HVDCP_PULSE_COUNT_MAX_QC2_MASK, HVDCP_PULSE_COUNT_MAX_QC2_5V); @@ -3745,7 +3766,7 @@ static void typec_src_removal(struct smb_charger *chg) * if non-compliant charger caused UV, restore original max pulses * and turn SUSPEND_ON_COLLAPSE_USBIN_BIT back on. */ - if (chg->non_compliant_chg_detected) { + if (chg->qc2_unsupported_voltage) { rc = smblib_masked_write(chg, HVDCP_PULSE_COUNT_MAX_REG, HVDCP_PULSE_COUNT_MAX_QC2_MASK, chg->qc2_max_pulses); @@ -3760,7 +3781,7 @@ static void typec_src_removal(struct smb_charger *chg) smblib_err(chg, "Couldn't turn on SUSPEND_ON_COLLAPSE_USBIN_BIT rc=%d\n", rc); - chg->non_compliant_chg_detected = false; + chg->qc2_unsupported_voltage = QC2_COMPLIANT; } if (chg->use_extcon) diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 447c269df1f2..1dbbd318211b 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -79,6 +79,12 @@ enum sink_src_mode { UNATTACHED_MODE, }; +enum qc2_non_comp_voltage { + QC2_COMPLIANT, + QC2_NON_COMPLIANT_9V, + QC2_NON_COMPLIANT_12V +}; + enum { BOOST_BACK_WA = BIT(0), }; @@ -373,7 +379,7 @@ struct smb_charger { u32 wa_flags; int boost_current_ua; int qc2_max_pulses; - bool non_compliant_chg_detected; + enum qc2_non_comp_voltage qc2_unsupported_voltage; /* extcon for VBUS / ID notification to USB for uUSB */ struct extcon_dev *extcon; -- GitLab From 35ad63802b32d85ddf25212f935da55f8e246f8a Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Mon, 5 Mar 2018 18:01:22 -0800 Subject: [PATCH 0671/1001] sound: usb: Stop endpoints upon disable audio stream request Currently driver is issuing stop endpoint command after issuing SET_ALT 0. As part of SET_ALT 0 endpoint drop context flag is set before issuing configure endpoint command. As per XHCI spec endpoint should be in stopped state before setting drop context flag otherwise configure endpoint command may result into undefined behavior. Fix this by issuing stop endpoint command before SET_ALT 0. Change-Id: If9ef60db2b0f1af4d6e5e0722414ce738d6580ad Signed-off-by: Hemant Kumar --- sound/usb/usb_audio_qmi_svc.c | 43 +++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c index 9c3e49b12800..d8a38f264dd4 100644 --- a/sound/usb/usb_audio_qmi_svc.c +++ b/sound/usb/usb_audio_qmi_svc.c @@ -758,25 +758,6 @@ static void uaudio_dev_intf_cleanup(struct usb_device *udev, struct intf_info *info) { - struct usb_host_endpoint *ep; - - if (info->data_ep_pipe) { - ep = usb_pipe_endpoint(udev, info->data_ep_pipe); - if (!ep) - pr_debug("%s: no data ep\n", __func__); - else - usb_stop_endpoint(udev, ep); - info->data_ep_pipe = 0; - } - if (info->sync_ep_pipe) { - ep = usb_pipe_endpoint(udev, info->sync_ep_pipe); - if (!ep) - pr_debug("%s: no sync ep\n", __func__); - else - usb_stop_endpoint(udev, ep); - info->sync_ep_pipe = 0; - } - uaudio_iommu_unmap(MEM_XFER_RING, info->data_xfer_ring_va, info->data_xfer_ring_size, info->data_xfer_ring_size); info->data_xfer_ring_va = 0; @@ -1016,6 +997,7 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle, struct snd_usb_audio *chip = NULL; struct uaudio_qmi_svc *svc = uaudio_svc; struct intf_info *info; + struct usb_host_endpoint *ep; int pcm_format; u8 pcm_card_num, pcm_dev_num, direction; int info_idx = -EINVAL, datainterval = -EINVAL, ret = 0; @@ -1108,6 +1090,29 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle, uadev[pcm_card_num].ctrl_intf = chip->ctrl_intf; + if (!req_msg->enable) { + info = &uadev[pcm_card_num].info[info_idx]; + if (info->data_ep_pipe) { + ep = usb_pipe_endpoint(uadev[pcm_card_num].udev, + info->data_ep_pipe); + if (!ep) + pr_debug("%s: no data ep\n", __func__); + else + usb_stop_endpoint(uadev[pcm_card_num].udev, ep); + info->data_ep_pipe = 0; + } + + if (info->sync_ep_pipe) { + ep = usb_pipe_endpoint(uadev[pcm_card_num].udev, + info->sync_ep_pipe); + if (!ep) + pr_debug("%s: no sync ep\n", __func__); + else + usb_stop_endpoint(uadev[pcm_card_num].udev, ep); + info->sync_ep_pipe = 0; + } + } + ret = snd_usb_enable_audio_stream(subs, datainterval, req_msg->enable); if (!ret && req_msg->enable) -- GitLab From 40bdd637b15dfe923f46eabb8e20a72e483aee2a Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Fri, 20 Apr 2018 14:55:52 -0700 Subject: [PATCH 0672/1001] kasan: add no_sanitize attribute for clang builds KASAN uses the __no_sanitize_address macro to disable instrumentation of particular functions. Right now it's defined only for GCC build, which causes false positives when clang is used. This patch adds a definition for clang. Note, that clang's revision 329612 or higher is required. Change-Id: Ia828b8cfcd53b2c9ba9e751df40e3181933aaa59 [andreyknvl@google.com: remove redundant #ifdef CONFIG_KASAN check] Link: http://lkml.kernel.org/r/c79aa31a2a2790f6131ed607c58b0dd45dd62a6c.1523967959.git.andreyknvl@google.com Link: http://lkml.kernel.org/r/4ad725cc903f8534f8c8a60f0daade5e3d674f8d.1523554166.git.andreyknvl@google.com Signed-off-by: Andrey Konovalov Acked-by: Andrey Ryabinin Cc: Alexander Potapenko Cc: Dmitry Vyukov Cc: David Rientjes Cc: Thomas Gleixner Cc: Ingo Molnar Cc: David Woodhouse Cc: Andrey Konovalov Cc: Will Deacon Cc: Greg Kroah-Hartman Cc: Paul Lawrence Cc: Sandipan Das Cc: Kees Cook Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Git-commit: 12c8f25a016dff69ee284aa3338bebfd2cfcba33 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Prasad Sodagudi --- include/linux/compiler-clang.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h index af722dea7562..c456227e898e 100644 --- a/include/linux/compiler-clang.h +++ b/include/linux/compiler-clang.h @@ -17,6 +17,9 @@ */ #define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) +#undef __no_sanitize_address +#define __no_sanitize_address __attribute__((no_sanitize("address"))) + /* Clang doesn't have a way to turn it off per-function, yet. */ #ifdef __noretpoline #undef __noretpoline -- GitLab From 960bbe820d2e8e86fd959281207e8d75a9186d39 Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Fri, 10 Aug 2018 22:16:45 +0530 Subject: [PATCH 0673/1001] ARM: dts: msm: Update the QG SDAM address and enable capacity learning QG uses SDAM7, update its address accordingly. Also, enable capacity learning feedback. Change-Id: I417d46cc07f455792906a18f4b6dc8e5ca8ca3d8 Signed-off-by: Anirudh Ghayal --- arch/arm64/boot/dts/qcom/pm6150.dtsi | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/pm6150.dtsi b/arch/arm64/boot/dts/qcom/pm6150.dtsi index 361394d60d0a..e4e1763b2e4f 100644 --- a/arch/arm64/boot/dts/qcom/pm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/pm6150.dtsi @@ -408,6 +408,8 @@ qcom,qg-iterm-ma = <100>; qcom,hold-soc-while-full; qcom,linearize-soc; + qcom,cl-feedback-on; + qcom,pmic-revid = <&pm6150_revid>; io-channels = <&pm6150_vadc ADC_BAT_THERM_PU2>, <&pm6150_vadc ADC_BAT_ID_PU2>; @@ -430,9 +432,9 @@ "qg-good-ocv"; }; - qcom,qg-sdam@b500 { + qcom,qg-sdam@b600 { status = "okay"; - reg = <0xb500 0x100>; + reg = <0xb600 0x100>; }; }; -- GitLab From ac0aff3cdd3c0df47c7178b1ab9b8825cc2815cb Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Fri, 10 Aug 2018 22:26:40 +0530 Subject: [PATCH 0674/1001] power: Add power supply property to force recharge POWER_SUPPLY_PROP_FORCE_RECHARGE can be used by FG/QG to force a recharge. Change-Id: I417d46cc07f455792906a18f4b6dc8e5ca8ca3d9 Signed-off-by: Anirudh Ghayal --- drivers/power/supply/power_supply_sysfs.c | 1 + include/linux/power_supply.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 17dce361efb9..f7d2e49e3675 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -381,6 +381,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(esr_actual), POWER_SUPPLY_ATTR(esr_nominal), POWER_SUPPLY_ATTR(soh), + POWER_SUPPLY_ATTR(force_recharge), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 0d370cd2b3ae..a3e179fe58a0 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -307,6 +307,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_ESR_ACTUAL, POWER_SUPPLY_PROP_ESR_NOMINAL, POWER_SUPPLY_PROP_SOH, + POWER_SUPPLY_PROP_FORCE_RECHARGE, /* Local extensions of type int64_t */ POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT, /* Properties of type `const char *' */ -- GitLab From a80b1d7f23da91a56f9beacc495eb8c967756b27 Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Thu, 9 Aug 2018 13:40:12 +0530 Subject: [PATCH 0675/1001] msm: sps: Allow for different IOVAs for buffers in BAM-to-BAM mode Different BAMs may have different IOVAs for the desc and data fifo buffers if they use different SMMUs. Do not assume they will be the same. Change-Id: I6bfaf4254da40e7bd99dc01110f10ee1906cf3d2 Signed-off-by: Siva Kumar Akkireddi --- drivers/platform/msm/sps/sps_rm.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/sps/sps_rm.c b/drivers/platform/msm/sps/sps_rm.c index 2fc420a64efa..013017c581e2 100644 --- a/drivers/platform/msm/sps/sps_rm.c +++ b/drivers/platform/msm/sps/sps_rm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2015, 2017, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -176,6 +176,8 @@ static int sps_rm_assign(struct sps_pipe *pipe, struct sps_connection *map) { struct sps_connect *cfg = &pipe->connect; + unsigned long desc_iova; + unsigned long data_iova; /* Check ownership and BAM */ if ((cfg->mode == SPS_MODE_SRC && map->client_src != NULL) || @@ -220,8 +222,24 @@ static int sps_rm_assign(struct sps_pipe *pipe, /* Copy parameters to client connect state */ pipe->connect.src_pipe_index = map->src.pipe_index; pipe->connect.dest_pipe_index = map->dest.pipe_index; + + /* + * The below assignment to connect.desc and connect.data will + * overwrite the previous values given by the first client + * in a BAM-to-BAM connection. Prevent that since the IOVAs + * may be different for the same physical buffers if the + * BAMs use different SMMUs. + */ + if (pipe->bam->props.options & SPS_BAM_SMMU_EN) { + desc_iova = pipe->connect.desc.iova; + data_iova = pipe->connect.data.iova; + } pipe->connect.desc = map->desc; pipe->connect.data = map->data; + if (pipe->bam->props.options & SPS_BAM_SMMU_EN) { + pipe->connect.desc.iova = desc_iova; + pipe->connect.data.iova = data_iova; + } pipe->client_state = SPS_STATE_ALLOCATE; -- GitLab From b6a9335ffe40e81f74d17eafe11950275fc8b98c Mon Sep 17 00:00:00 2001 From: himta ram Date: Wed, 8 Aug 2018 17:46:47 +0530 Subject: [PATCH 0676/1001] defconfig: qcs405: Enable Power driver for BT Enable config flags for BT power driver for QCS405. This driver sets the voltage on regulators as per the DTS entries which helps in powering up BT Chip (WCN3990). Change-Id: I542beda1dd6a925c35c0256db3011d70bc1df9ad Signed-off-by: Hemant Gupta Signed-off-by: Himta Ram --- arch/arm/configs/vendor/qcs405-perf_defconfig | 10 ++++------ arch/arm/configs/vendor/qcs405_defconfig | 10 ++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/arch/arm/configs/vendor/qcs405-perf_defconfig b/arch/arm/configs/vendor/qcs405-perf_defconfig index 1de5a83d0f23..14420b3eb670 100644 --- a/arch/arm/configs/vendor/qcs405-perf_defconfig +++ b/arch/arm/configs/vendor/qcs405-perf_defconfig @@ -181,12 +181,10 @@ CONFIG_NET_CLS_ACT=y CONFIG_QRTR=y CONFIG_QRTR_SMD=y 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 +# CONFIG_BT_BREDR is not set +# CONFIG_BT_LE is not set +# CONFIG_BT_DEBUGFS is not set +CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y diff --git a/arch/arm/configs/vendor/qcs405_defconfig b/arch/arm/configs/vendor/qcs405_defconfig index d8a0f5407420..807bed8d0722 100644 --- a/arch/arm/configs/vendor/qcs405_defconfig +++ b/arch/arm/configs/vendor/qcs405_defconfig @@ -186,12 +186,10 @@ CONFIG_NET_CLS_ACT=y CONFIG_QRTR=y CONFIG_QRTR_SMD=y 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 +# CONFIG_BT_BREDR is not set +# CONFIG_BT_LE is not set +# CONFIG_BT_DEBUGFS is not set +CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y -- GitLab From 06b9fb5242533b5c3e1a44a49be4ad5e5b53a842 Mon Sep 17 00:00:00 2001 From: Tingwei Zhang Date: Sat, 11 Aug 2018 12:01:31 +0800 Subject: [PATCH 0677/1001] coresight: tmc: Fix write point for ETR sg mode Write point of ETR could be over 4GB on device with more than 4GB memory. Align the write point to phys_addr_t type to fix write point overflow issue. Change-Id: I0cd4aca2214b090101762ccc7a0ed1534f6dff11 Signed-off-by: Tingwei Zhang --- drivers/hwtracing/coresight/coresight-tmc-etr.c | 2 +- drivers/hwtracing/coresight/coresight-tmc.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 0df879000532..7dca9f856f25 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -352,7 +352,7 @@ static void tmc_etr_sg_mem_reset(uint32_t *vaddr, uint32_t size) tmc_etr_sg_tbl_flush(vaddr, size); } -void tmc_etr_sg_rwp_pos(struct tmc_drvdata *drvdata, uint32_t rwp) +void tmc_etr_sg_rwp_pos(struct tmc_drvdata *drvdata, phys_addr_t rwp) { uint32_t i = 0, pte_n = 0, last_pte; uint32_t *virt_st_tbl, *virt_pte; diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index ffe2fde6d193..8dc0cef4f800 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -271,7 +271,7 @@ int tmc_etr_bam_init(struct amba_device *adev, extern struct byte_cntr *byte_cntr_init(struct amba_device *adev, struct tmc_drvdata *drvdata); extern const struct coresight_ops tmc_etr_cs_ops; -extern void tmc_etr_sg_rwp_pos(struct tmc_drvdata *drvdata, uint32_t rwp); +extern void tmc_etr_sg_rwp_pos(struct tmc_drvdata *drvdata, phys_addr_t rwp); extern const struct coresight_ops tmc_etr_cs_ops; -- GitLab From f44a0e133996227b103cd7fa4b13afcb2fd8126d Mon Sep 17 00:00:00 2001 From: Umang Agrawal Date: Fri, 10 Aug 2018 21:51:33 +0530 Subject: [PATCH 0678/1001] ARM: dts: msm: Fix spmi address cells and battery data specs for sm6150 Update SPMI bus address/size cell configuration to use one cell each to represent address/size of slave nodes. While at it, add MLP battery profile and move batterydata to core dtsi file. Change-Id: Ibffe97fb2326bc93ff34cfb46b3af338ab23d03c Signed-off-by: Umang Agrawal --- .../qg-batterydata-mlp356477-2800mah.dtsi | 1040 +++++++++++++++++ arch/arm64/boot/dts/qcom/sm6150-idp.dtsi | 7 - arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi | 7 - arch/arm64/boot/dts/qcom/sm6150.dtsi | 10 +- 4 files changed, 1048 insertions(+), 16 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/qg-batterydata-mlp356477-2800mah.dtsi diff --git a/arch/arm64/boot/dts/qcom/qg-batterydata-mlp356477-2800mah.dtsi b/arch/arm64/boot/dts/qcom/qg-batterydata-mlp356477-2800mah.dtsi new file mode 100644 index 000000000000..3b1801077f76 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qg-batterydata-mlp356477-2800mah.dtsi @@ -0,0 +1,1040 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +qcom,mlp356477_2800mah { + /* mlp356477_2800mah_averaged_MasterSlave_Mar13th2018 */ + qcom,max-voltage-uv = <4400000>; + qcom,fg-cc-cv-threshold-mv = <4390>; + qcom,fastchg-current-ma = <4200>; + qcom,batt-id-kohm = <82>; + qcom,battery-beta = <4250>; + qcom,battery-therm-kohm = <100>; + qcom,battery-type = + "mlp356477_2800mah_averaged_MasterSlave_Mar13th2018"; + qcom,qg-batt-profile-ver = <100>; + + qcom,jeita-fcc-ranges = <0 150 560000 + 151 450 4200000 + 451 550 2380000>; + qcom,jeita-fv-ranges = <0 150 4150000 + 151 450 4400000 + 451 550 4150000>; + + /* COOL = 15 DegC, WARM = 45 DegC */ + qcom,jeita-soft-thresholds = <0x4621 0x20b8>; + /* COLD = 0 DegC, HOT = 55 DegC */ + qcom,jeita-hard-thresholds = <0x58cd 0x181d>; + + qcom,fcc1-temp-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-data = <2715 2788 2861 2898 2908>; + }; + + qcom,fcc2-temp-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-data = <2864 2846 2860 2868 2865 2865>; + }; + + qcom,pc-temp-v1-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <43494 43682 43812 43865 43879>, + <43243 43420 43582 43645 43659>, + <42984 43174 43350 43418 43434>, + <42737 42940 43115 43191 43208>, + <42506 42710 42878 42958 42978>, + <42287 42479 42641 42722 42746>, + <42087 42250 42407 42489 42514>, + <41903 42027 42175 42255 42281>, + <41709 41807 41948 42023 42050>, + <41489 41592 41723 41794 41822>, + <41265 41381 41502 41568 41596>, + <41069 41176 41286 41348 41374>, + <40898 40982 41074 41131 41155>, + <40720 40799 40871 40921 40942>, + <40501 40613 40673 40716 40735>, + <40269 40405 40482 40518 40534>, + <40088 40193 40295 40329 40343>, + <39955 40022 40116 40148 40162>, + <39834 39894 39952 39975 39988>, + <39708 39765 39807 39818 39827>, + <39583 39577 39645 39659 39667>, + <39447 39345 39420 39461 39475>, + <39277 39148 39173 39221 39239>, + <39089 38991 38991 39014 39028>, + <38930 38860 38851 38860 38868>, + <38794 38758 38733 38728 38732>, + <38683 38676 38628 38611 38612>, + <38607 38602 38535 38507 38505>, + <38548 38529 38451 38414 38409>, + <38501 38462 38373 38327 38317>, + <38466 38407 38305 38251 38234>, + <38437 38360 38245 38182 38160>, + <38405 38317 38193 38121 38092>, + <38366 38277 38147 38067 38030>, + <38329 38240 38109 38022 37980>, + <38300 38203 38069 37977 37929>, + <38273 38170 38027 37921 37863>, + <38236 38130 37980 37857 37784>, + <38162 38057 37912 37781 37700>, + <38062 37946 37816 37690 37609>, + <37947 37830 37704 37585 37507>, + <37801 37713 37578 37463 37382>, + <37644 37575 37436 37322 37239>, + <37473 37394 37270 37162 37082>, + <37320 37251 37129 37032 36959>, + <37220 37161 37058 36960 36899>, + <37185 37129 37033 36942 36880>, + <37156 37103 37014 36927 36865>, + <37120 37070 36988 36902 36835>, + <37014 36957 36885 36755 36652>, + <36682 36593 36544 36398 36287>, + <36204 36109 36077 35921 35807>, + <35597 35486 35476 35307 35181>, + <34771 34630 34656 34460 34321>, + <33460 33262 33379 33128 32955>, + <30000 30000 30000 30000 30000>; + }; + + qcom,pc-temp-v2-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <43865 43850 43830 43805 43740 43725>, + <43432 43429 43514 43528 43481 43467>, + <43037 43064 43219 43264 43228 43216>, + <42685 42767 42948 43012 42983 42973>, + <42369 42526 42700 42773 42744 42738>, + <42075 42296 42458 42537 42509 42505>, + <41776 42059 42213 42303 42277 42272>, + <41517 41822 41972 42071 42047 42041>, + <41353 41571 41739 41843 41820 41814>, + <41239 41298 41515 41619 41595 41589>, + <41095 41069 41297 41398 41374 41368>, + <40895 40928 41088 41181 41158 41151>, + <40650 40808 40884 40967 40946 40938>, + <40329 40611 40677 40763 40742 40734>, + <39941 40284 40461 40566 40541 40534>, + <39654 39989 40259 40373 40348 40342>, + <39456 39811 40087 40180 40164 40158>, + <39278 39662 39920 39993 39985 39980>, + <39086 39459 39722 39821 39814 39808>, + <38900 39184 39492 39664 39651 39646>, + <38740 38924 39264 39483 39469 39466>, + <38598 38721 39048 39237 39230 39230>, + <38480 38546 38846 38982 38986 38989>, + <38386 38403 38678 38799 38809 38813>, + <38308 38282 38535 38654 38669 38674>, + <38240 38189 38406 38530 38547 38552>, + <38182 38125 38286 38419 38438 38442>, + <38127 38075 38179 38320 38341 38343>, + <38076 38030 38090 38229 38250 38250>, + <38028 37992 38012 38144 38166 38164>, + <37978 37955 37949 38066 38089 38086>, + <37927 37916 37900 37993 38019 38016>, + <37875 37875 37857 37925 37953 37949>, + <37820 37832 37817 37860 37884 37875>, + <37763 37788 37781 37801 37812 37795>, + <37699 37738 37740 37738 37728 37702>, + <37630 37680 37688 37671 37625 37587>, + <37555 37613 37625 37600 37519 37469>, + <37475 37537 37552 37525 37430 37374>, + <37392 37448 37465 37446 37352 37292>, + <37308 37349 37363 37353 37263 37200>, + <37222 37237 37238 37238 37151 37088>, + <37133 37114 37101 37106 37022 36960>, + <37035 36989 36957 36952 36870 36813>, + <36935 36875 36859 36862 36807 36758>, + <36817 36792 36792 36828 36785 36734>, + <36752 36754 36762 36812 36769 36719>, + <36667 36707 36710 36780 36736 36687>, + <36541 36633 36613 36721 36656 36581>, + <36342 36472 36411 36517 36379 36276>, + <36024 36149 36031 36113 35946 35829>, + <35575 35650 35485 35584 35386 35258>, + <34953 34964 34771 34884 34643 34500>, + <34073 34007 33739 33902 33598 33440>, + <32647 32474 32144 32393 32025 31829>, + <30018 28051 26513 28737 27554 26991>; + }; + + qcom,pc-temp-z1-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <14442 13243 12339 11979 11839>, + <14411 13218 12328 11916 11773>, + <14392 13199 12294 11893 11756>, + <14384 13180 12273 11879 11745>, + <14381 13174 12263 11870 11738>, + <14377 13179 12257 11863 11735>, + <14369 13182 12253 11858 11731>, + <14358 13175 12250 11851 11726>, + <14349 13158 12248 11847 11722>, + <14339 13146 12242 11845 11720>, + <14332 13143 12237 11845 11719>, + <14327 13144 12237 11844 11718>, + <14321 13142 12238 11840 11716>, + <14313 13135 12234 11837 11715>, + <14306 13128 12222 11835 11714>, + <14299 13120 12215 11834 11714>, + <14293 13113 12211 11833 11713>, + <14293 13111 12203 11830 11714>, + <14297 13119 12202 11828 11715>, + <14304 13129 12210 11831 11716>, + <14312 13133 12215 11837 11718>, + <14318 13130 12221 11841 11721>, + <14319 13125 12230 11843 11726>, + <14320 13135 12234 11846 11730>, + <14324 13151 12236 11852 11734>, + <14340 13158 12238 11860 11737>, + <14358 13165 12247 11865 11741>, + <14373 13167 12258 11870 11747>, + <14389 13165 12260 11873 11752>, + <14394 13167 12258 11877 11757>, + <14373 13169 12256 11880 11760>, + <14334 13168 12253 11886 11764>, + <14321 13167 12247 11892 11768>, + <14348 13170 12248 11897 11772>, + <14378 13177 12260 11901 11778>, + <14371 13182 12271 11905 11783>, + <14343 13188 12277 11910 11788>, + <14331 13194 12283 11917 11792>, + <14346 13205 12290 11924 11797>, + <14369 13219 12300 11931 11803>, + <14389 13228 12307 11937 11809>, + <14412 13237 12311 11941 11815>, + <14410 13245 12315 11945 11820>, + <14367 13259 12315 11949 11823>, + <14429 13239 12311 11954 11824>, + <14440 13243 12333 11959 11830>, + <14452 13241 12320 11961 11828>, + <14443 13243 12329 11964 11831>, + <14484 13241 12332 11968 11836>, + <14448 13263 12343 11977 11845>, + <14473 13293 12346 11988 11856>, + <14501 13300 12357 12000 11864>, + <14521 13333 12374 12015 11879>, + <14603 13373 12420 12034 11897>, + <14603 13373 12420 12034 11897>, + <14603 13373 12420 12034 11897>; + }; + + qcom,pc-temp-z2-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <9070 11213 10264 10349 10299>, + <9403 10211 10276 10386 10313>, + <9826 10116 10342 10430 10322>, + <9983 10114 10362 10447 10350>, + <9978 10115 10368 10437 10342>, + <9967 10120 10372 10407 10282>, + <9846 10126 10371 10393 10237>, + <9534 10132 10368 10388 10217>, + <9372 10137 10365 10382 10206>, + <9574 10141 10365 10378 10208>, + <9873 10143 10365 10386 10216>, + <9940 10145 10357 10384 10231>, + <9908 10147 10346 10370 10273>, + <9890 10148 10344 10357 10310>, + <9864 10149 10352 10353 10325>, + <9749 10147 10354 10353 10336>, + <9714 10144 10347 10355 10342>, + <10069 10146 10343 10360 10343>, + <10530 10156 10344 10366 10344>, + <10637 10166 10343 10378 10353>, + <10631 10154 10344 10396 10363>, + <10605 10119 10374 10405 10360>, + <10392 10103 10415 10412 10326>, + <10061 10118 10414 10414 10294>, + <9958 10135 10371 10402 10266>, + <9962 10132 10339 10387 10241>, + <9968 10117 10335 10377 10241>, + <9971 10107 10337 10360 10253>, + <9975 10109 10342 10353 10270>, + <9977 10112 10351 10373 10299>, + <9855 10116 10359 10397 10330>, + <9628 10123 10362 10398 10343>, + <9563 10131 10365 10389 10349>, + <9597 10143 10370 10392 10366>, + <9647 10159 10379 10443 10415>, + <9714 10166 10389 10499 10464>, + <9809 10169 10397 10520 10486>, + <9844 10172 10405 10533 10511>, + <9756 10186 10432 10548 10531>, + <9631 10212 10505 10586 10563>, + <9541 10225 10551 10621 10587>, + <9445 10161 10538 10637 10540>, + <9378 10144 10527 10646 10468>, + <9335 10322 10539 10611 10495>, + <9269 13378 10554 10627 10491>, + <9218 14361 10475 10629 10534>, + <9220 14794 10469 10642 10588>, + <9212 15070 10496 10651 10586>, + <9188 13785 10469 10739 10647>, + <9170 13219 10622 10694 10458>, + <9151 12652 10655 10557 10325>, + <9135 12236 10610 10495 10272>, + <9116 11644 10496 10432 10195>, + <9081 11027 10456 10300 10139>, + <9081 11027 10456 10300 10139>, + <9081 11027 10456 10300 10139>; + }; + + qcom,pc-temp-z3-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <19308 19258 19367 19369 19345>, + <19567 19611 19463 19395 19370>, + <19850 19705 19512 19411 19381>, + <19967 19740 19520 19416 19385>, + <19987 19749 19515 19414 19384>, + <19996 19735 19507 19405 19379>, + <19860 19713 19499 19400 19373>, + <19484 19698 19492 19395 19369>, + <19288 19687 19483 19391 19365>, + <19508 19679 19473 19388 19362>, + <19829 19673 19467 19382 19358>, + <19858 19667 19463 19378 19357>, + <19678 19660 19461 19372 19355>, + <19567 19648 19461 19369 19353>, + <19627 19641 19463 19369 19353>, + <19647 19646 19465 19368 19355>, + <19577 19654 19458 19367 19355>, + <19415 19653 19447 19366 19345>, + <19268 19631 19443 19365 19337>, + <19258 19613 19443 19365 19337>, + <19258 19623 19446 19366 19337>, + <19260 19652 19459 19374 19342>, + <19450 19665 19480 19393 19364>, + <19797 19666 19494 19403 19379>, + <19919 19667 19506 19402 19379>, + <19924 19671 19511 19400 19378>, + <19927 19681 19507 19400 19374>, + <19922 19686 19499 19400 19366>, + <19906 19684 19492 19399 19360>, + <19891 19680 19487 19397 19359>, + <19798 19673 19482 19393 19359>, + <19639 19661 19476 19390 19359>, + <19579 19650 19470 19386 19357>, + <19566 19644 19465 19382 19355>, + <19553 19639 19460 19380 19352>, + <19468 19636 19457 19378 19348>, + <19316 19630 19455 19375 19346>, + <19261 19624 19453 19373 19344>, + <19262 19618 19450 19371 19343>, + <19263 19609 19443 19369 19345>, + <19264 19576 19437 19368 19347>, + <19267 19367 19435 19368 19350>, + <19269 19261 19432 19367 19353>, + <19270 19260 19421 19365 19353>, + <19274 19257 19413 19361 19354>, + <19278 19257 19368 19354 19332>, + <19278 19257 19367 19346 19332>, + <19279 19257 19362 19331 19323>, + <19282 19257 19368 19326 19327>, + <19284 19257 19354 19338 19350>, + <19287 19257 19361 19346 19348>, + <19290 19257 19368 19356 19347>, + <19295 19257 19370 19353 19356>, + <19308 19258 19392 19382 19373>, + <19308 19258 19392 19382 19373>, + <19308 19258 19392 19382 19373>; + }; + + qcom,pc-temp-z4-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <16598 15992 15337 14972 14879>, + <16815 16035 15386 15059 14940>, + <16561 15923 15277 14982 14899>, + <16283 15657 15173 14901 14842>, + <15982 15436 15082 14879 14824>, + <15774 15304 15020 14868 14816>, + <15800 15207 14988 14856 14809>, + <15941 15154 14966 14843 14802>, + <16005 15119 14946 14830 14794>, + <15750 15094 14928 14818 14785>, + <15383 15076 14912 14807 14775>, + <15316 15063 14897 14797 14766>, + <15433 15048 14884 14788 14757>, + <15501 15033 14874 14778 14748>, + <15463 15025 14866 14769 14737>, + <15509 15037 14860 14760 14725>, + <15596 15057 14852 14751 14718>, + <15677 15056 14841 14742 14715>, + <15729 15002 14835 14738 14712>, + <15708 14951 14832 14736 14709>, + <15684 15017 14833 14735 14707>, + <15650 15207 14923 14756 14718>, + <15508 15302 15068 14837 14777>, + <15298 15313 15091 14879 14814>, + <15235 15319 15040 14870 14809>, + <15282 15294 14989 14855 14800>, + <15330 15200 14962 14841 14793>, + <15320 15131 14943 14826 14787>, + <15270 15105 14932 14814 14780>, + <15232 15088 14926 14805 14771>, + <15276 15076 14923 14798 14761>, + <15373 15065 14921 14794 14754>, + <15397 15057 14920 14791 14747>, + <15385 15051 14919 14789 14742>, + <15376 15043 14916 14787 14738>, + <15430 15036 14914 14786 14736>, + <15544 15016 14915 14794 14745>, + <15577 14998 14918 14811 14767>, + <15550 14991 14917 14816 14774>, + <15520 14987 14909 14811 14768>, + <15502 14998 14896 14803 14760>, + <15491 15139 14873 14788 14752>, + <15475 15211 14850 14774 14747>, + <15445 15195 14842 14774 14750>, + <15345 15130 14813 14764 14741>, + <15318 15079 14802 14736 14721>, + <15308 15066 14777 14720 14700>, + <15301 15057 14757 14705 14684>, + <15285 15045 14739 14698 14668>, + <15274 15053 14775 14717 14688>, + <15294 15076 14782 14719 14696>, + <15311 15080 14778 14712 14701>, + <15326 15091 14779 14719 14701>, + <15354 15108 14768 14706 14703>, + <15354 15108 14768 14706 14703>, + <15354 15108 14768 14706 14703>; + }; + + qcom,pc-temp-z5-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <10764 10957 12110 13794 13670>, + <11745 12925 13686 14768 14977>, + <12716 14010 14746 16056 16445>, + <13404 14718 15521 16744 17361>, + <13905 15321 16180 16789 17415>, + <14200 15933 16545 16568 17166>, + <13611 16455 16653 16420 16940>, + <11869 16730 16710 16364 16838>, + <10978 16895 16699 16401 16763>, + <12521 17062 16594 16402 16659>, + <14783 17315 16549 16292 16587>, + <15011 17507 16656 16178 16634>, + <13819 17490 16845 16003 16770>, + <13134 17527 17100 15977 16943>, + <13823 17638 17538 16159 17435>, + <14192 17626 17786 16425 18421>, + <13660 17482 17557 16723 18632>, + <12194 17384 17254 17131 17493>, + <10877 17447 17366 17305 16542>, + <10795 17704 18253 17609 16717>, + <10808 18910 18937 18108 17070>, + <10857 21136 18167 17900 17037>, + <13850 21892 16713 16569 16529>, + <19285 19957 16394 15708 16174>, + <21102 17736 16736 15560 16006>, + <20977 17560 17186 15557 15832>, + <20752 18050 17734 15845 15773>, + <20272 18693 18431 16567 15708>, + <19413 19705 19132 17289 15707>, + <18772 20743 19927 17959 16182>, + <17386 21034 20581 18611 16967>, + <15327 21059 21018 19179 17620>, + <14631 21034 21355 19699 18403>, + <14512 21133 21507 20256 19056>, + <14338 21373 21604 21000 19675>, + <13329 21460 21643 21494 20064>, + <11563 21322 21601 20994 19488>, + <10927 21163 21493 19730 18023>, + <10937 21134 21270 19156 17559>, + <10948 21040 20651 18991 17865>, + <10942 20318 20135 18929 18319>, + <10912 14582 19994 18903 18925>, + <10885 11608 19761 18788 19444>, + <10861 11587 18126 17802 18686>, + <10871 11314 17978 17266 18426>, + <10857 11130 15054 17271 15914>, + <10841 11088 15214 17078 16658>, + <10831 11067 15184 16484 17071>, + <10841 11046 15966 16365 19357>, + <10877 11142 14378 15551 19427>, + <10922 11156 14140 15626 17699>, + <10887 11109 14272 16679 16814>, + <10848 11069 14202 15606 17668>, + <10790 10995 15166 19180 19716>, + <10790 10995 15166 19180 19716>, + <10790 10995 15166 19180 19716>; + }; + + qcom,pc-temp-z6-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <17029 15901 15123 14807 14723>, + <17156 16022 15165 14844 14750>, + <17081 15990 15131 14815 14734>, + <16977 15851 15090 14780 14711>, + <16818 15720 15039 14766 14700>, + <16645 15630 15000 14756 14693>, + <16486 15560 14978 14746 14686>, + <16331 15519 14962 14737 14680>, + <16255 15490 14945 14728 14674>, + <16244 15468 14929 14720 14668>, + <16238 15452 14916 14712 14662>, + <16217 15438 14905 14704 14656>, + <16172 15422 14897 14697 14651>, + <16139 15401 14891 14691 14646>, + <16146 15390 14887 14686 14642>, + <16166 15395 14883 14681 14638>, + <16163 15403 14876 14677 14633>, + <16120 15402 14866 14672 14627>, + <16076 15372 14862 14670 14622>, + <16063 15345 14862 14670 14621>, + <16057 15380 14865 14671 14621>, + <16055 15480 14915 14684 14629>, + <16092 15533 14991 14732 14668>, + <16168 15543 15006 14757 14692>, + <16218 15549 14992 14753 14691>, + <16251 15541 14976 14746 14687>, + <16270 15511 14964 14741 14683>, + <16266 15488 14954 14735 14676>, + <16246 15479 14948 14730 14671>, + <16227 15473 14944 14726 14666>, + <16204 15467 14942 14722 14662>, + <16176 15459 14941 14719 14659>, + <16164 15454 14939 14716 14657>, + <16159 15453 14938 14715 14654>, + <16154 15453 14937 14714 14651>, + <16145 15453 14936 14714 14649>, + <16133 15450 14939 14717 14652>, + <16130 15447 14943 14725 14662>, + <16133 15449 14943 14727 14665>, + <16139 15454 14940 14725 14664>, + <16147 15454 14936 14723 14663>, + <16161 15429 14929 14718 14662>, + <16171 15417 14922 14712 14662>, + <16178 15424 14918 14713 14664>, + <16162 15408 14909 14708 14663>, + <16165 15399 14883 14694 14643>, + <16168 15398 14875 14684 14633>, + <16172 15401 14867 14670 14622>, + <16179 15405 14866 14665 14618>, + <16193 15425 14881 14682 14641>, + <16228 15451 14892 14690 14645>, + <16262 15468 14902 14695 14650>, + <16300 15497 14912 14700 14657>, + <16361 15535 14930 14716 14672>, + <16361 15535 14930 14716 14672>, + <16361 15535 14930 14716 14672>; + }; + + qcom,pc-temp-y1-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <7929 6704 6050 5566 5322 5235>, + <8028 6701 6050 5560 5320 5234>, + <8101 6693 6051 5554 5318 5233>, + <8151 6684 6051 5548 5316 5231>, + <8179 6676 6052 5543 5313 5230>, + <8186 6673 6053 5540 5311 5228>, + <8157 6667 6054 5539 5308 5225>, + <8120 6659 6054 5538 5305 5222>, + <8110 6663 6055 5536 5302 5222>, + <8104 6693 6056 5529 5299 5222>, + <8099 6717 6055 5525 5298 5222>, + <8120 6716 6050 5525 5297 5220>, + <8146 6707 6044 5526 5296 5217>, + <8147 6706 6044 5528 5295 5216>, + <8147 6707 6049 5533 5293 5217>, + <8146 6709 6052 5536 5291 5217>, + <8135 6705 6053 5534 5290 5219>, + <8119 6699 6055 5532 5288 5221>, + <8100 6700 6057 5532 5289 5221>, + <8079 6708 6062 5531 5290 5220>, + <8070 6715 6065 5531 5292 5219>, + <8070 6712 6067 5532 5294 5220>, + <8076 6706 6071 5532 5296 5222>, + <8117 6703 6071 5532 5297 5223>, + <8170 6702 6070 5532 5298 5225>, + <8167 6702 6069 5532 5299 5227>, + <8118 6700 6068 5535 5301 5229>, + <8084 6699 6065 5539 5305 5232>, + <8087 6697 6062 5540 5309 5236>, + <8100 6691 6059 5541 5311 5240>, + <8092 6688 6059 5542 5314 5243>, + <8059 6691 6063 5546 5317 5244>, + <8043 6695 6069 5550 5320 5245>, + <8027 6693 6072 5553 5324 5247>, + <8011 6677 6077 5556 5329 5251>, + <8021 6667 6080 5558 5333 5255>, + <8050 6679 6081 5563 5336 5258>, + <8082 6697 6082 5568 5339 5261>, + <8123 6698 6085 5570 5342 5263>, + <8148 6684 6094 5571 5348 5265>, + <8101 6675 6101 5572 5352 5268>, + <8041 6691 6098 5581 5353 5271>, + <8104 6707 6096 5586 5356 5275>, + <8088 6704 6102 5586 5363 5282>, + <8048 6708 6104 5593 5368 5284>, + <8055 6725 6098 5595 5370 5288>, + <8059 6724 6114 5601 5370 5288>, + <8092 6743 6089 5598 5376 5290>, + <8157 6750 6086 5605 5374 5291>, + <8197 6722 6104 5609 5381 5293>, + <8269 6738 6105 5608 5384 5292>, + <8288 6759 6112 5624 5392 5304>, + <8380 6766 6128 5643 5400 5313>, + <8422 6779 6149 5656 5417 5324>, + <8422 6779 6149 5656 5417 5324>, + <8422 6779 6149 5656 5417 5324>; + }; + + qcom,pc-temp-y2-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <9654 9643 10639 11070 11121 11086>, + <9654 9643 10662 11056 11097 11058>, + <9655 9643 10675 11037 11063 11029>, + <9655 9871 10680 11014 11027 11001>, + <9656 10190 10680 10988 10997 10976>, + <9656 10325 10677 10959 10981 10958>, + <9657 10308 10664 10918 10973 10946>, + <9657 10282 10644 10881 10967 10935>, + <9657 10301 10632 10875 10959 10916>, + <9658 10440 10623 10874 10933 10882>, + <9658 10534 10619 10874 10919 10864>, + <9658 10489 10626 10869 10936 10874>, + <9659 10417 10643 10861 10961 10888>, + <9658 10413 10676 10856 10952 10885>, + <9657 10487 10748 10851 10897 10860>, + <9657 10553 10801 10851 10866 10840>, + <9657 10580 10826 10885 10876 10837>, + <9657 10597 10843 10946 10896 10845>, + <9657 10521 10842 11018 10943 10884>, + <9656 10042 10822 11115 11060 10984>, + <9656 9696 10809 11159 11120 11034>, + <9656 9682 10815 11129 11098 11013>, + <9656 9676 10826 11091 11071 10987>, + <9656 9675 10835 11085 11079 11009>, + <9656 9676 10846 11088 11121 11106>, + <9655 9676 10848 11093 11154 11162>, + <9655 9675 10684 11108 11176 11166>, + <9655 9671 10460 11130 11199 11168>, + <9655 9668 10652 11152 11224 11182>, + <9654 9665 11565 11178 11263 11214>, + <9654 9662 12069 11192 11286 11238>, + <9654 9660 11796 11199 11310 11257>, + <9654 9659 11319 11203 11338 11277>, + <9654 9657 10963 11202 11344 11307>, + <9654 9656 10643 11198 11320 11345>, + <9654 9655 10423 11189 11299 11359>, + <9653 9654 10140 11148 11294 11325>, + <9653 9653 9828 11108 11301 11280>, + <9653 9653 9733 11099 11301 11271>, + <9653 9653 9707 11096 11290 11278>, + <9653 9652 9692 11071 11287 11277>, + <9653 9652 9681 10975 11329 11250>, + <9653 9652 9674 10939 11356 11231>, + <9653 9652 9668 10913 11303 11229>, + <9653 9652 9664 10802 11253 11135>, + <9653 9652 9663 10839 11180 11044>, + <9653 9652 9661 10832 11146 11009>, + <9652 9652 9660 10811 11105 10962>, + <9652 9651 9659 10794 11061 10965>, + <9651 9651 9658 10764 11053 10938>, + <9650 9651 9658 10711 10981 10871>, + <9650 9651 9656 10651 10927 10829>, + <9649 9651 9654 10594 10851 10747>, + <9648 9651 9654 10531 10798 10659>, + <9648 9651 9654 10531 10798 10659>, + <9648 9651 9654 10531 10798 10659>; + }; + + qcom,pc-temp-y3-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <14501 13677 13390 13309 13301 13279>, + <14412 13657 13393 13309 13294 13279>, + <14328 13634 13397 13311 13289 13279>, + <14249 13612 13400 13312 13285 13279>, + <14179 13596 13403 13314 13283 13279>, + <14117 13590 13406 13315 13282 13279>, + <14063 13594 13408 13315 13283 13280>, + <14017 13600 13410 13316 13286 13281>, + <13976 13594 13412 13317 13287 13282>, + <13939 13548 13416 13319 13287 13282>, + <13929 13515 13419 13321 13287 13282>, + <13957 13513 13421 13322 13289 13282>, + <13986 13512 13423 13323 13291 13282>, + <13945 13509 13422 13325 13291 13283>, + <13843 13504 13414 13328 13291 13284>, + <13803 13497 13407 13329 13291 13286>, + <13797 13488 13401 13328 13292 13287>, + <13793 13478 13395 13325 13294 13288>, + <13788 13470 13387 13324 13297 13290>, + <13783 13465 13376 13323 13301 13294>, + <13783 13458 13367 13322 13303 13296>, + <13788 13428 13360 13315 13297 13290>, + <13796 13384 13354 13306 13287 13281>, + <13814 13362 13349 13303 13283 13278>, + <13843 13349 13346 13300 13281 13277>, + <13874 13344 13341 13299 13280 13277>, + <13910 13351 13308 13299 13280 13277>, + <13952 13369 13266 13299 13282 13277>, + <13999 13391 13259 13298 13282 13277>, + <14052 13422 13259 13299 13283 13277>, + <14110 13460 13258 13299 13283 13277>, + <14174 13503 13258 13298 13283 13277>, + <14243 13554 13259 13298 13283 13277>, + <14318 13615 13263 13298 13283 13277>, + <14398 13690 13285 13299 13283 13278>, + <14481 13777 13302 13299 13283 13278>, + <14568 13879 13294 13296 13281 13277>, + <14658 13996 13281 13292 13279 13276>, + <14750 14118 13282 13292 13278 13276>, + <14850 14247 13299 13292 13277 13277>, + <14963 14377 13319 13293 13277 13277>, + <15082 14502 13343 13295 13277 13278>, + <15198 14624 13368 13298 13277 13278>, + <15302 14737 13402 13303 13278 13276>, + <15264 14824 13470 13304 13280 13278>, + <15439 14801 13476 13307 13284 13280>, + <15557 14824 13517 13316 13291 13286>, + <15783 14890 13560 13319 13292 13287>, + <16058 14961 13607 13332 13295 13287>, + <16423 15021 13665 13332 13292 13286>, + <16935 15095 13703 13333 13294 13286>, + <17701 15215 13779 13341 13296 13289>, + <18847 15382 13934 13350 13299 13292>, + <20636 15571 14143 13370 13308 13299>, + <20636 15571 14143 13370 13308 13299>, + <20636 15571 14143 13370 13308 13299>; + }; + + qcom,pc-temp-y4-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <17448 17305 16798 16610 16483 16470>, + <17520 17330 16862 16610 16486 16469>, + <17601 17378 16934 16609 16489 16468>, + <17679 17433 17001 16608 16491 16467>, + <17744 17479 17051 16607 16493 16467>, + <17783 17501 17070 16605 16493 16466>, + <17798 17503 17059 16603 16493 16466>, + <17813 17504 17041 16601 16492 16466>, + <17918 17511 17030 16599 16493 16466>, + <18180 17550 17023 16599 16497 16470>, + <18279 17608 17020 16599 16500 16473>, + <18148 17742 17034 16602 16502 16478>, + <17945 17902 17062 16609 16506 16483>, + <17736 17876 17086 16619 16512 16487>, + <17506 17547 17110 16638 16523 16492>, + <17399 17320 17134 16659 16535 16498>, + <17363 17344 17161 16679 16546 16506>, + <17328 17386 17183 16703 16560 16518>, + <17266 17370 17170 16748 16586 16537>, + <17193 17216 17080 16821 16630 16569>, + <17141 17060 16974 16852 16651 16585>, + <17100 16974 16865 16754 16602 16552>, + <17077 16908 16761 16616 16529 16502>, + <17070 16873 16703 16567 16502 16483>, + <17066 16851 16662 16543 16489 16473>, + <17066 16841 16647 16535 16485 16469>, + <17066 16841 16681 16535 16485 16470>, + <17067 16842 16727 16535 16487 16471>, + <17070 16843 16732 16537 16489 16474>, + <17074 16844 16721 16543 16497 16482>, + <17079 16845 16716 16549 16507 16491>, + <17088 16852 16721 16554 16521 16504>, + <17095 16866 16730 16558 16535 16515>, + <17099 16879 16732 16556 16540 16518>, + <17103 16893 16714 16549 16540 16515>, + <17111 16906 16704 16540 16534 16509>, + <17124 16920 16735 16528 16505 16492>, + <17134 16932 16784 16517 16477 16475>, + <17142 16941 16805 16517 16476 16471>, + <17149 16947 16815 16522 16479 16469>, + <17157 16950 16818 16530 16481 16469>, + <17167 16948 16818 16544 16482 16469>, + <17187 16945 16817 16555 16481 16467>, + <17208 16947 16815 16561 16471 16454>, + <17140 16965 16826 16575 16477 16456>, + <17176 16961 16849 16584 16493 16477>, + <17202 16977 16893 16606 16503 16495>, + <17281 17046 16954 16635 16528 16531>, + <17390 17107 17025 16679 16557 16532>, + <17524 17131 17054 16682 16515 16493>, + <17690 17101 17038 16673 16527 16498>, + <17978 17060 17051 16712 16548 16514>, + <18577 17063 17124 16764 16588 16554>, + <20156 17135 17255 16879 16727 16719>, + <20156 17135 17255 16879 16727 16719>, + <20156 17135 17255 16879 16727 16719>; + }; + + qcom,pc-temp-y5-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <10030 8712 14223 14774 19943 16308>, + <10448 8888 14349 15148 18667 15835>, + <10794 10562 14526 15365 17009 15457>, + <11054 12204 14713 15466 15353 15176>, + <11214 13579 14867 15489 14086 14997>, + <11260 14452 14948 15472 13593 14920>, + <11143 14948 14973 15335 13800 15003>, + <11001 15270 14986 15151 14123 15144>, + <11151 15028 14986 15098 14118 15087>, + <11850 13370 14973 15056 13826 14716>, + <12871 12246 14930 14978 13664 14315>, + <15188 13353 14287 14743 13788 13961>, + <17100 15163 13386 14398 13870 13634>, + <15786 15495 13334 14078 13643 13482>, + <12439 15197 13853 13740 13191 13549>, + <11406 14993 14346 13497 12887 13638>, + <11547 15443 14672 13207 12793 13546>, + <11662 16191 15006 12923 12796 13423>, + <11574 16138 15417 13004 13001 13548>, + <11364 14708 15994 13654 13569 14033>, + <11181 13284 16419 14434 14193 14440>, + <10986 12599 16670 15491 14905 14826>, + <10835 12068 16832 16433 15541 15160>, + <10734 11544 16827 16644 15650 15196>, + <10666 10962 16682 16591 15306 15346>, + <10655 10655 16390 16622 15048 15474>, + <10654 10648 14341 16597 15293 15494>, + <10654 10645 11728 16540 15744 15472>, + <10689 10665 11156 16578 15865 15229>, + <10734 10802 11032 16695 15749 14663>, + <10745 10946 10959 16756 15607 14352>, + <10765 11017 10901 16831 15502 14290>, + <10797 11076 10865 16959 15400 14311>, + <10882 11177 11054 17363 15705 14665>, + <10953 11367 12196 18097 16573 15740>, + <10940 11520 13011 18310 16919 16424>, + <10897 11584 12496 17269 16620 16376>, + <10863 11627 11602 15914 16091 16215>, + <10835 11630 11486 15213 15448 16327>, + <10820 11595 11681 14700 14692 16543>, + <10867 11570 11787 14330 14365 16550>, + <10955 11579 11797 14105 14243 16259>, + <11030 11596 11778 14219 14209 16346>, + <11029 11509 11647 14611 15058 16893>, + <11044 11331 11779 14198 14882 16382>, + <11143 11388 11508 14156 14882 14589>, + <11321 11488 11654 14603 16012 16142>, + <11356 11493 11662 14001 15040 14960>, + <11206 11613 11939 14918 15399 14828>, + <10932 11747 12726 15439 17093 17327>, + <10539 11665 12655 15981 17753 17255>, + <10263 11585 12280 16288 17881 17960>, + <9994 11459 12118 16141 17436 18200>, + <9668 11818 11932 16090 17352 17825>, + <9668 11818 11932 16090 17352 17825>, + <9668 11818 11932 16090 17352 17825>; + }; + + qcom,pc-temp-y6-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <7467 6132 5538 5158 5055 5027>, + <7418 6176 5550 5158 5053 5026>, + <7371 6205 5557 5158 5050 5025>, + <7326 6223 5561 5157 5048 5025>, + <7283 6232 5562 5156 5046 5025>, + <7242 6234 5562 5154 5046 5025>, + <7194 6227 5555 5152 5046 5025>, + <7159 6211 5540 5150 5047 5026>, + <7167 6191 5531 5149 5047 5027>, + <7202 6161 5522 5149 5048 5028>, + <7216 6144 5519 5149 5049 5029>, + <7195 6170 5520 5150 5051 5030>, + <7155 6214 5522 5151 5053 5031>, + <7075 6207 5523 5154 5055 5033>, + <6953 6119 5523 5160 5058 5035>, + <6899 6058 5522 5167 5061 5038>, + <6884 6060 5524 5172 5065 5041>, + <6872 6065 5527 5177 5070 5045>, + <6853 6054 5521 5188 5079 5052>, + <6834 5986 5487 5208 5095 5064>, + <6828 5923 5449 5216 5102 5070>, + <6826 5892 5413 5184 5083 5056>, + <6825 5871 5381 5138 5056 5035>, + <6839 5868 5365 5122 5045 5028>, + <6867 5872 5355 5114 5040 5024>, + <6893 5878 5349 5111 5038 5023>, + <6923 5895 5343 5112 5039 5023>, + <6956 5926 5339 5113 5040 5024>, + <6991 5960 5339 5115 5042 5026>, + <7030 5999 5342 5118 5045 5028>, + <7074 6044 5346 5121 5048 5031>, + <7122 6096 5354 5124 5053 5034>, + <7175 6156 5367 5126 5057 5038>, + <7232 6222 5383 5127 5059 5039>, + <7293 6297 5405 5127 5060 5039>, + <7357 6380 5430 5127 5058 5038>, + <7425 6470 5458 5124 5049 5032>, + <7495 6568 5491 5120 5041 5027>, + <7567 6667 5530 5121 5040 5027>, + <7643 6768 5579 5127 5041 5027>, + <7727 6867 5632 5133 5042 5028>, + <7816 6963 5689 5144 5044 5028>, + <7908 7053 5751 5155 5044 5028>, + <7994 7135 5817 5167 5043 5024>, + <7959 7206 5905 5181 5046 5026>, + <8096 7192 5921 5188 5056 5034>, + <8195 7214 5976 5205 5063 5044>, + <8412 7280 6034 5219 5072 5055>, + <8678 7350 6096 5248 5083 5055>, + <9031 7405 6155 5252 5069 5043>, + <9521 7454 6196 5257 5074 5046>, + <10251 7535 6282 5285 5084 5053>, + <11352 7666 6442 5320 5100 5069>, + <13075 7846 6646 5385 5148 5123>, + <13075 7846 6646 5385 5148 5123>, + <13075 7846 6646 5385 5148 5123>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi index 1467f00847a6..aa48c4c7dffa 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi @@ -15,13 +15,6 @@ &soc { }; -/ { - mtp_batterydata: qcom,battery-data { - qcom,batt-id-range-pct = <15>; - #include "qg-batterydata-alium-3600mah.dtsi" - }; -}; - &qupv3_se0_2uart { status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi index 17710610b9d1..893c4f96e6d1 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi @@ -16,13 +16,6 @@ &soc { }; -/ { - mtp_batterydata: qcom,battery-data { - qcom,batt-id-range-pct = <15>; - #include "qg-batterydata-alium-3600mah.dtsi" - }; -}; - &ufsphy_mem { compatible = "qcom,ufs-phy-qmp-v3-660"; diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 2ffed070f418..3525832c4822 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -896,6 +896,12 @@ < 1708800 MHZ_TO_MBPS(1017, 4) >, < 2208000 MHZ_TO_MBPS(1804, 4) >; }; + + mtp_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "qg-batterydata-alium-3600mah.dtsi" + #include "qg-batterydata-mlp356477-2800mah.dtsi" + }; }; &soc { @@ -1696,8 +1702,8 @@ interrupts = ; qcom,ee = <0>; qcom,channel = <0>; - #address-cells = <2>; - #size-cells = <0>; + #address-cells = <1>; + #size-cells = <1>; interrupt-controller; #interrupt-cells = <4>; cell-index = <0>; -- GitLab From e2f75a427fde0bd61ff46300466e2cf1c68a95ee Mon Sep 17 00:00:00 2001 From: Amit Nischal Date: Fri, 10 Aug 2018 23:52:35 +0530 Subject: [PATCH 0679/1001] clk: qcom: Mark video_cc_xo_clk as CRITICAL video_cc_xo_clk is required to be always on for venus gdsc operation so marking the clock as critical. Change-Id: I400da165095369de53250b28448c0caffd563916 Signed-off-by: Amit Nischal --- drivers/clk/qcom/videocc-sm6150.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/qcom/videocc-sm6150.c b/drivers/clk/qcom/videocc-sm6150.c index 844d78de958d..4aa1cfa0714f 100644 --- a/drivers/clk/qcom/videocc-sm6150.c +++ b/drivers/clk/qcom/videocc-sm6150.c @@ -317,7 +317,7 @@ static struct clk_branch video_cc_xo_clk = { "video_cc_xo_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, -- GitLab From 0a767362bb24d38895eee649b1edc3b57e447d70 Mon Sep 17 00:00:00 2001 From: Ramprasad Katkam Date: Tue, 7 Aug 2018 21:44:15 +0530 Subject: [PATCH 0680/1001] Documentation: sound: Add documentation for swr port mapping in wcd937x Add Documentation for soundwire Port mapping of swr slaves on wcd937x codec nodes. Change-Id: I8e26aa54127b5d77f26b40e5e38bd5437883b522 Signed-off-by: Ramprasad Katkam --- .../devicetree/bindings/sound/wcd_codec.txt | 19 +++++++++++++++++++ .../bindings/soundwire/swr-mstr-ctrl.txt | 4 ++++ 2 files changed, 23 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/wcd_codec.txt b/Documentation/devicetree/bindings/sound/wcd_codec.txt index 20e87c4164d2..8d582798fddf 100644 --- a/Documentation/devicetree/bindings/sound/wcd_codec.txt +++ b/Documentation/devicetree/bindings/sound/wcd_codec.txt @@ -550,6 +550,14 @@ Tanggu Codec Required properties: - compatible: "qcom,wcd937x-codec"; + - qcom,rx_swr_ch_map: mapping of swr rx slave port configuration to port_type and also + corresponding master port type it need to attach. + format: + same port_id configurations have to be grouped, and in ascending order. + - qcom,tx_swr_ch_map: mapping of swr tx slave port configuration to port_type and also + corresponding master port type it need to attach. + format: + same port_id configurations have to be grouped, and in ascending order. - qcom,wcd-rst-gpio-node: Phandle reference to the DT node having codec reset gpio configuration. If this property is not defined, it is expected to atleast define "qcom,cdc-reset-gpio" property. @@ -585,6 +593,17 @@ Optional properties: Example: wcd937x_codec: wcd937x-codec { compatible = "qcom,wcd937x-codec"; + qcom,rx_swr_ch_map = <0 HPH_L 0x1 0 HPH_L>, + <0 HPH_R 0x2 0 HPH_R>, <1 CLSH 0x3 0 CLSH>, + <2 COMP_L 0x1 0 COMP_L>, <2 COMP_R 0x2 0 COMP_R>, + <3 LO 0x1 0 LO>, <4 DSD_L 0x1 0 DSD_L>, + <4 DSD_R 0x2 0 DSD_R>; + qcom,tx_swr_ch_map = <0 ADC1 0x1 0 ADC1>, + <1 ADC2 0x1 0 ADC3>, <1 ADC3 0x2 0 ADC4>, + <2 DMIC0 0x1 0 DMIC0>, <2 DMIC1 0x2 0 DMIC1>, + <2 MBHC 0x4 0 DMIC2>, <3 DMIC2 0x1 0 DMIC4>, + <3 DMIC3 0x2 0 DMIC5>, <3 DMIC4 0x4 0 DMIC6>, + <3 DMIC5 0x8 0 DMIC7>; qcom,wcd-rst-gpio-node = <&wcd937x_rst_gpio>; qcom,rx-slave = <&wcd937x_rx_slave>; diff --git a/Documentation/devicetree/bindings/soundwire/swr-mstr-ctrl.txt b/Documentation/devicetree/bindings/soundwire/swr-mstr-ctrl.txt index ba92e093b134..41822f28acd6 100644 --- a/Documentation/devicetree/bindings/soundwire/swr-mstr-ctrl.txt +++ b/Documentation/devicetree/bindings/soundwire/swr-mstr-ctrl.txt @@ -22,6 +22,9 @@ Required properties: which the swr-devid is <0x0 0x032000> where 0x03 represents device Unique_ID, 0x20 represents Part_Id1 and 0x00 represents part_Id2. +Optional properties: +- mipi-sdw-clock-stop-mode0-supported : should be set to 1 if all + the slaves under the master supports clock stop mode 0 Example: @@ -46,4 +49,5 @@ swr0: swr_master { compatible = "qcom,wsa881x"; reg = <0x00 0x042000>; }; + mipi-sdw-clock-stop-mode0-supported = <0>; }; -- GitLab From bec6bb5dc9416702baab8e6e25a36f4e1d99aae7 Mon Sep 17 00:00:00 2001 From: Archit Saxena Date: Thu, 9 Aug 2018 18:59:12 +0530 Subject: [PATCH 0681/1001] ARM: dts: msm: Add rtb node for rtb dump enablement Add rtb node for qcs405 to enable rtb log collection while parsing ramdump. Change-Id: I97d98a298f7045db0b74b4bbc9be66fb91360151 Signed-off-by: Archit Saxena --- arch/arm64/boot/dts/qcom/qcs405.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index 1d6e5d534a81..fa4a6f9c8e99 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -287,6 +287,11 @@ reg-names = "pshold-base", "tcsr-boot-misc-detect"; }; + qcom,msm-rtb { + compatible = "qcom,msm-rtb"; + qcom,rtb-size = <0x100000>; + }; + qcom,mpm2-sleep-counter@4a3000 { compatible = "qcom,mpm2-sleep-counter"; reg = <0x4a3000 0x1000>; -- GitLab From d812ee35ced160dc9d85299301825bc1446ce335 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Sat, 11 Aug 2018 16:20:27 +0530 Subject: [PATCH 0682/1001] msm: camera: Add support for nominal l1 clock Add support for nominal l1 clock level in camera. This clock level required for sm6150 camera nodes. Change-Id: I7f2b13453c31135c06c35ff4cf1f7e422766d83c Signed-off-by: Ravikishore Pampana --- .../msm/camera/cam_utils/cam_soc_util.c | 6 +++++- .../msm/camera/cam_utils/cam_soc_util.h | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c index c38e2889b701..9056b2b87e03 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c +++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c @@ -46,8 +46,10 @@ static const char *cam_soc_util_get_string_from_level( return "SVSL1[4]"; case CAM_NOMINAL_VOTE: return "NOM[5]"; + case CAM_NOMINALL1_VOTE: + return "NOML1[6]"; case CAM_TURBO_VOTE: - return "TURBO[6]"; + return "TURBO[7]"; default: return ""; } @@ -227,6 +229,8 @@ int cam_soc_util_get_level_from_string(const char *string, *level = CAM_SVSL1_VOTE; } else if (!strcmp(string, "nominal")) { *level = CAM_NOMINAL_VOTE; + } else if (!strcmp(string, "nominal_l1")) { + *level = CAM_NOMINALL1_VOTE; } else if (!strcmp(string, "turbo")) { *level = CAM_TURBO_VOTE; } else { diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h index 94a5898dd399..f6dac3528ec9 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h +++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h @@ -44,14 +44,15 @@ /** * enum cam_vote_level - Enum for voting level * - * @CAM_SUSPEND_VOTE : Suspend vote - * @CAM_MINSVS_VOTE : Min SVS vote - * @CAM_LOWSVS_VOTE : Low SVS vote - * @CAM_SVS_VOTE : SVS vote - * @CAM_SVSL1_VOTE : SVS Plus vote - * @CAM_NOMINAL_VOTE : Nominal vote - * @CAM_TURBO_VOTE : Turbo vote - * @CAM_MAX_VOTE : Max voting level, This is invalid level. + * @CAM_SUSPEND_VOTE : Suspend vote + * @CAM_MINSVS_VOTE : Min SVS vote + * @CAM_LOWSVS_VOTE : Low SVS vote + * @CAM_SVS_VOTE : SVS vote + * @CAM_SVSL1_VOTE : SVS Plus vote + * @CAM_NOMINAL_VOTE : Nominal vote + * @CAM_NOMINALL1_VOTE: Nominal plus vote + * @CAM_TURBO_VOTE : Turbo vote + * @CAM_MAX_VOTE : Max voting level, This is invalid level. */ enum cam_vote_level { CAM_SUSPEND_VOTE, @@ -60,6 +61,7 @@ enum cam_vote_level { CAM_SVS_VOTE, CAM_SVSL1_VOTE, CAM_NOMINAL_VOTE, + CAM_NOMINALL1_VOTE, CAM_TURBO_VOTE, CAM_MAX_VOTE, }; -- GitLab From e5e26600ef73a78c7c46a736fc5d98c846fc5190 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Sat, 11 Aug 2018 14:55:47 +0530 Subject: [PATCH 0683/1001] ARM: dts: msm: Enable remotefs for SM6150 Enable rmtfs module for modem processor, which needs access to store data onto eMMC/UFS device. The shared memory size used by modem and apps for this purpose is 2MB. Change-Id: Ibb31568ac72aed06d67a440ed5c97bc818ffc3db Signed-off-by: Ankit Jain --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index a54ce5c7d454..83e16db1476f 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -2428,6 +2428,15 @@ vdd-3.3-ch0-supply = <&pm6150l_l10>; qcom,vdd-0.8-cx-mx-config = <640000 640000>; }; + + qcom,rmtfs_sharedmem@0 { + compatible = "qcom,sharedmem-uio"; + reg = <0x0 0x200000>; + reg-names = "rmtfs"; + qcom,client-id = <0x00000001>; + qcom,guard-memory; + }; + }; #include "pm6150.dtsi" -- GitLab From 1100fbab72046731bf840588d4613c22eb27967c Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Sat, 11 Aug 2018 18:41:19 +0530 Subject: [PATCH 0684/1001] power: qpnp-qg: Fix the return error check in QGauge ADC reads over IIO return positive value on success. Fix the return error check. Change-Id: Ib8eb1ab3f7f9f3f0f3d5d717fc02b87669125556 Signed-off-by: Anirudh Ghayal --- drivers/power/supply/qcom/qpnp-qg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 4b540ed49e0e..4d6101f97993 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -2394,7 +2394,7 @@ static int get_batt_id_ohm(struct qpnp_qg *chip, u32 *batt_id_ohm) /* Read battery-id */ rc = iio_read_channel_processed(chip->batt_id_chan, &batt_id_mv); - if (rc) { + if (rc < 0) { pr_err("Failed to read BATT_ID over ADC, rc=%d\n", rc); return rc; } @@ -2573,7 +2573,7 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip) use_pon_ocv: if (use_pon_ocv == true) { rc = qg_get_battery_temp(chip, &batt_temp); - if (rc) { + if (rc < 0) { pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc); goto done; } -- GitLab From 42c8fadaa56a31b568b6abbb55043c68963ac426 Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Sat, 11 Aug 2018 17:24:54 +0530 Subject: [PATCH 0685/1001] clk: qcom: Update mdss_ahb_clk clock divider for SM6150 RCG divider of disp_cc_mdss_ahb_clk clock is required to be updated to generate 37.5MHz and 75MHz frequencies, so update the same on SM6150. Also keep the gpll0_main clock source enabled by default as it is required for generating 37.5MHz and 75MHz frequencies. Change-Id: I07db5e6ec96c5cb13df96209041e79bfb2c0e450 Signed-off-by: Odelu Kukatla --- drivers/clk/qcom/dispcc-sm6150.c | 6 ++++-- drivers/clk/qcom/gcc-sm6150.c | 4 ++-- include/dt-bindings/clock/qcom,gcc-sm6150.h | 2 ++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/clk/qcom/dispcc-sm6150.c b/drivers/clk/qcom/dispcc-sm6150.c index ba931b52fda3..4338b833faea 100644 --- a/drivers/clk/qcom/dispcc-sm6150.c +++ b/drivers/clk/qcom/dispcc-sm6150.c @@ -160,8 +160,8 @@ static struct clk_alpha_pll disp_cc_pll0_out_main = { static const struct freq_tbl ftbl_disp_cc_mdss_ahb_clk_src[] = { F(19200000, P_BI_TCXO, 1, 0, 0), - F(37500000, P_GPLL0_OUT_MAIN, 16, 0, 0), - F(75000000, P_GPLL0_OUT_MAIN, 8, 0, 0), + F(37500000, P_GPLL0_OUT_MAIN, 8, 0, 0), + F(75000000, P_GPLL0_OUT_MAIN, 4, 0, 0), { } }; @@ -171,10 +171,12 @@ static struct clk_rcg2 disp_cc_mdss_ahb_clk_src = { .hid_width = 5, .parent_map = disp_cc_parent_map_4, .freq_tbl = ftbl_disp_cc_mdss_ahb_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "disp_cc_mdss_ahb_clk_src", .parent_names = disp_cc_parent_names_4, .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, .vdd_class = &vdd_cx, .num_rate_max = VDD_NUM, diff --git a/drivers/clk/qcom/gcc-sm6150.c b/drivers/clk/qcom/gcc-sm6150.c index 5310730a1623..99d716f9f7c3 100644 --- a/drivers/clk/qcom/gcc-sm6150.c +++ b/drivers/clk/qcom/gcc-sm6150.c @@ -3424,6 +3424,8 @@ static const struct qcom_reset_map gcc_sm6150_resets[] = { [GCC_PCIE_PHY_COM_BCR] = { 0x6f010 }, [GCC_UFS_PHY_BCR] = { 0x77000 }, [GCC_USB20_SEC_BCR] = { 0xa6000 }, + [GCC_USB3_DP_PHY_PRIM_SP0_BCR] = { 0x50010 }, + [GCC_USB3PHY_PHY_PRIM_SP0_BCR] = { 0x50008 }, }; static struct clk_dfs gcc_dfs_clocks[] = { @@ -3501,10 +3503,8 @@ static int gcc_sm6150_probe(struct platform_device *pdev) * Disable the GPLL0 active input to MM blocks and GPU * via MISC registers. */ - regmap_update_bits(regmap, GCC_DISPLAY_MISC, 0x1, 0x1); regmap_update_bits(regmap, GCC_CAMERA_MISC, 0x1, 0x1); regmap_update_bits(regmap, GCC_VIDEO_MISC, 0x1, 0x1); - regmap_update_bits(regmap, GCC_GPU_MISC, 0x3, 0x3); ret = qcom_cc_really_probe(pdev, &gcc_sm6150_desc, regmap); if (ret) { diff --git a/include/dt-bindings/clock/qcom,gcc-sm6150.h b/include/dt-bindings/clock/qcom,gcc-sm6150.h index 2b1678111e43..82f3326cd9cc 100644 --- a/include/dt-bindings/clock/qcom,gcc-sm6150.h +++ b/include/dt-bindings/clock/qcom,gcc-sm6150.h @@ -204,5 +204,7 @@ #define GCC_PCIE_PHY_COM_BCR 9 #define GCC_UFS_PHY_BCR 10 #define GCC_USB20_SEC_BCR 11 +#define GCC_USB3_DP_PHY_PRIM_SP0_BCR 12 +#define GCC_USB3PHY_PHY_PRIM_SP0_BCR 13 #endif -- GitLab From ead929621dfda42b3572931ba37d5e091c07dbc8 Mon Sep 17 00:00:00 2001 From: Srinivas Ramana Date: Sat, 11 Aug 2018 19:47:12 +0530 Subject: [PATCH 0686/1001] socinfo: msm: Give name to IDP hw platformid Add support to name the hw_platform id of IDP platform. Change-Id: Ifcacf3ac4dd5f75e3ae1257054b64bb850bf316e Signed-off-by: Srinivas Ramana --- drivers/soc/qcom/socinfo.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 88ef903c211c..e752ad57a83a 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -68,6 +68,7 @@ enum { HW_PLATFORM_SBC = 24, HW_PLATFORM_ADP = 25, HW_PLATFORM_IOT = 32, + HW_PLATFORM_IDP = 34, HW_PLATFORM_INVALID }; @@ -89,7 +90,8 @@ const char *hw_platform[] = { [HW_PLATFORM_STP] = "STP", [HW_PLATFORM_SBC] = "SBC", [HW_PLATFORM_ADP] = "ADP", - [HW_PLATFORM_IOT] = "IOT" + [HW_PLATFORM_IOT] = "IOT", + [HW_PLATFORM_IDP] = "IDP" }; enum { -- GitLab From c8e3f9919bbcf37efc6be1316c56671b03480c92 Mon Sep 17 00:00:00 2001 From: Prateek Sood Date: Fri, 10 Aug 2018 18:38:10 +0530 Subject: [PATCH 0687/1001] ARM: dts: msm: Add scandump sizes for SM6150 CPUs Add scandump sizes for each CPU on the SM6150 chipset to ensure that the correct scandump sizes are used for each CPU. Change-Id: I0eabc71c3fd28af63ca511810aaa36261cdb7bfe Signed-off-by: Prateek Sood --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index a54ce5c7d454..903070e893dc 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -1202,6 +1202,8 @@ qcom,pet-time = <9360>; qcom,ipi-ping; qcom,wakeup-enable; + qcom,scandump-sizes = <0x10100 0x10100 0x10100 0x10100 + 0x10100 0x10100 0x25900 0x25900>; }; qcom,chd_sliver { -- GitLab From ba52753aa3d969e2713adf599f32bed0753e3a43 Mon Sep 17 00:00:00 2001 From: Veerabhadrarao Badiganti Date: Fri, 16 Mar 2018 13:40:35 +0530 Subject: [PATCH 0688/1001] mmc: card: Call blk_requeue_request() with queue-lock held blk_requeue_request() must be called with queue lock held. If it is called without this lock then there is a chance that block- queue would be accessed simultaneously by more than one entity (sat request completion & re-queue) and both can mess-up the queue pointers which can result in unexpected results. Change-Id: If81711ecf65a185f4c8dc19b8568621460c93db8 Signed-off-by: Veerabhadrarao Badiganti --- drivers/mmc/core/block.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index a84c2ce7161a..33aa47ba39b6 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -2633,11 +2633,11 @@ static struct mmc_cmdq_req *mmc_blk_cmdq_rw_prep( static void mmc_blk_cmdq_requeue_rw_rq(struct mmc_queue *mq, struct request *req) { - struct mmc_card *card = mq->card; - struct mmc_host *host = card->host; + struct request_queue *q = req->q; - blk_requeue_request(req->q, req); - mmc_put_card(host->card); + spin_lock_irq(q->queue_lock); + blk_requeue_request(q, req); + spin_unlock_irq(q->queue_lock); } static int mmc_blk_cmdq_issue_rw_rq(struct mmc_queue *mq, struct request *req) @@ -3543,9 +3543,16 @@ static int mmc_blk_cmdq_issue_rq(struct mmc_queue *mq, struct request *req) * If issuing of the request fails with eitehr EBUSY or * EAGAIN error, re-queue the request. * This case would occur with ICE calls. + * For request which gets completed successfully or + * errored out, we release host lock in completion or + * error handling softirq context. But here the request + * is neither completed nor erred-out, so release the + * host lock explicitly. */ - if (ret == -EBUSY || ret == -EAGAIN) + if (ret == -EBUSY || ret == -EAGAIN) { mmc_blk_cmdq_requeue_rw_rq(mq, req); + mmc_put_card(host->card); + } } } -- GitLab From 1bc42e8f7e1f797a8aece13fe2a73787e8d7b5b0 Mon Sep 17 00:00:00 2001 From: Ramprasad Katkam Date: Sat, 4 Aug 2018 00:49:48 +0530 Subject: [PATCH 0689/1001] ARM: dts: msm: Add swr port mapping for sm6150 Add soundwire port information for wcd937x codec. Change-Id: I14e2ab8b02e2496f8737835a26e089710d31e50a Signed-off-by: Ramprasad Katkam --- arch/arm64/boot/dts/qcom/qcs405-wsa881x.dtsi | 2 +- .../boot/dts/qcom/sm6150-audio-overlay.dtsi | 106 +++++++++++++----- arch/arm64/boot/dts/qcom/sm6150-audio.dtsi | 2 +- .../boot/dts/qcom/sm6150-external-codec.dtsi | 9 +- arch/arm64/boot/dts/qcom/sm6150-wsa881x.dtsi | 14 ++- .../sound/audio-codec-port-types.h | 44 ++++---- 6 files changed, 123 insertions(+), 54 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcs405-wsa881x.dtsi b/arch/arm64/boot/dts/qcom/qcs405-wsa881x.dtsi index 7f08ec94ef83..cbcfc52bea80 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-wsa881x.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-wsa881x.dtsi @@ -33,7 +33,7 @@ <6 SPKR_R_BOOST 0x3>, <7 SPKR_L_VI 0x3>, <8 SPKR_R_VI 0x3>; qcom,swr-num-dev = <2>; - + qcom,swr_master_id = <1>; wsa881x_0211: wsa881x@20170211 { compatible = "qcom,wsa881x"; reg = <0x0 0x20170211>; diff --git a/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi index 8c4d761bfc59..855ad451cc24 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi @@ -20,56 +20,89 @@ #include "sm6150-lpi.dtsi" #include +#include &bolero { qcom,num-macros = <4>; qcom,va-without-decimation; - wsa_macro: wsa-macro@62F00000 { - compatible = "qcom,wsa-macro"; - reg = <0x62F00000 0x0>; - clock-names = "wsa_core_clk", "wsa_npl_clk"; - clocks = <&clock_audio_wsa_1 0>, - <&clock_audio_wsa_2 0>; - qcom,wsa-swr-gpios = <&wsa_swr_gpios>; - }; - - va_macro: va-macro@62F20000 { - compatible = "qcom,va-macro"; - reg = <0x62F20000 0x0>; - clock-names = "va_core_clk"; - clocks = <&clock_audio_va 0>; + tx_macro: tx-macro@62ec0000 { + compatible = "qcom,tx-macro"; + reg = <0x62ec0000 0x0>; + clock-names = "tx_core_clk", "tx_npl_clk"; + clocks = <&clock_audio_tx_1 0>, + <&clock_audio_tx_2 0>; + qcom,tx-swr-gpios = <&tx_swr_gpios>; + qcom,tx-dmic-sample-rate = <4800000>; + swr_2: tx_swr_master { + compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + qcom,swr_master_id = <3>; + swrm-io-base = <0x62ed0000 0x0>; + interrupts = <0 137 0>, <0 528 0>; + interrupt-names = "swr_master_irq", "swr_wake_irq"; + qcom,swr-num-ports = <5>; + qcom,swr-port-mapping = <1 PCM_OUT1 0xF>, + <2 ADC1 0x1>, <2 ADC2 0x2>, + <3 ADC3 0x1>, <3 ADC4 0x2>, + <4 DMIC0 0x1>, <4 DMIC1 0x2>, + <4 DMIC2 0x4>, <4 DMIC3 0x8>, + <5 DMIC4 0x1>, <5 DMIC5 0x2>, + <5 DMIC6 0x4>, <5 DMIC7 0x8>; + qcom,swr-num-dev = <1>; + qcom,swr-clock-stop-mode0 = <1>; + wcd937x_tx_slave: wcd937x-tx-slave { + compatible = "qcom,wcd937x-slave"; + reg = <0x0 0x01170223>; + }; + }; }; - rx_macro: rx-macro@62EE0000 { + rx_macro: rx-macro@62ee0000 { compatible = "qcom,rx-macro"; - reg = <0x62EE0000 0x0>; + reg = <0x62ee0000 0x0>; clock-names = "rx_core_clk", "rx_npl_clk"; clocks = <&clock_audio_rx_1 0>, <&clock_audio_rx_2 0>; qcom,rx-swr-gpios = <&rx_swr_gpios>; - qcom,rx_mclk_mode_muxsel = <0x62C25020>; + qcom,rx_mclk_mode_muxsel = <0x62c25020>; swr_1: rx_swr_master { compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + qcom,swr_master_id = <2>; + swrm-io-base = <0x62ef0000 0x0>; + interrupts = <0 138 0>; + interrupt-names = "swr_master_irq"; + qcom,swr-num-ports = <5>; + qcom,swr-port-mapping = <1 HPH_L 0x1>, + <1 HPH_R 0x2>, <2 CLSH 0x3>, + <3 COMP_L 0x1>, <3 COMP_R 0x2>, + <4 LO 0x1>, <5 DSD_L 0x1>, + <5 DSD_R 0x2>; + qcom,swr-num-dev = <1>; + qcom,swr-clock-stop-mode0 = <1>; wcd937x_rx_slave: wcd937x-rx-slave { compatible = "qcom,wcd937x-slave"; + reg = <0x0 0x01170224>; }; }; }; - tx_macro: tx-macro@62EC0000 { - compatible = "qcom,tx-macro"; - reg = <0x62EC0000 0x0>; - clock-names = "tx_core_clk", "tx_npl_clk"; - clocks = <&clock_audio_tx_1 0>, - <&clock_audio_tx_2 0>; - qcom,tx-swr-gpios = <&tx_swr_gpios>; - qcom,tx-dmic-sample-rate = <4800000>; - swr_2: tx_swr_master { - compatible = "qcom,swr-mstr"; - wcd937x_tx_slave: wcd937x-tx-slave { - compatible = "qcom,wcd937x-slave"; - }; - }; + wsa_macro: wsa-macro@62f00000 { + compatible = "qcom,wsa-macro"; + reg = <0x62f00000 0x0>; + clock-names = "wsa_core_clk", "wsa_npl_clk"; + clocks = <&clock_audio_wsa_1 0>, + <&clock_audio_wsa_2 0>; + qcom,wsa-swr-gpios = <&wsa_swr_gpios>; + }; + + va_macro: va-macro@62f20000 { + compatible = "qcom,va-macro"; + reg = <0x62f20000 0x0>; + clock-names = "va_core_clk"; + clocks = <&clock_audio_va 0>; }; }; @@ -125,6 +158,17 @@ &soc { wcd937x_codec: wcd937x-codec { compatible = "qcom,wcd937x-codec"; + qcom,rx_swr_ch_map = <0 HPH_L 0x1 0 HPH_L>, + <0 HPH_R 0x2 0 HPH_R>, <1 CLSH 0x3 0 CLSH>, + <2 COMP_L 0x1 0 COMP_L>, <2 COMP_R 0x2 0 COMP_R>, + <3 LO 0x1 0 LO>, <4 DSD_L 0x1 0 DSD_L>, + <4 DSD_R 0x2 0 DSD_R>; + qcom,tx_swr_ch_map = <0 ADC1 0x1 0 ADC1>, + <1 ADC2 0x1 0 ADC3>, <1 ADC3 0x2 0 ADC4>, + <2 DMIC0 0x1 0 DMIC0>, <2 DMIC1 0x2 0 DMIC1>, + <2 MBHC 0x4 0 DMIC2>, <3 DMIC2 0x1 0 DMIC4>, + <3 DMIC3 0x2 0 DMIC5>, <3 DMIC4 0x4 0 DMIC6>, + <3 DMIC5 0x8 0 DMIC7>; qcom,wcd-rst-gpio-node = <&wcd937x_rst_gpio>; qcom,rx-slave = <&wcd937x_rx_slave>; diff --git a/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi b/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi index 625b5531be48..4a757afe3efe 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi @@ -14,7 +14,7 @@ #include "msm-audio-lpass.dtsi" &msm_audio_ion { - iommus = <&apps_smmu 0x1b21 0x0>; + iommus = <&apps_smmu 0x1721 0x0>; qcom,smmu-sid-mask = /bits/ 64 <0xf>; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-external-codec.dtsi b/arch/arm64/boot/dts/qcom/sm6150-external-codec.dtsi index 5a5daeaa9a95..c629f08dd587 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-external-codec.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-external-codec.dtsi @@ -17,6 +17,7 @@ }; }; +#include #include "sm6150-wcd.dtsi" &sm6150_snd { @@ -114,7 +115,13 @@ compatible = "qcom,swr-mstr"; #address-cells = <2>; #size-cells = <0>; - + qcom,swr-num-ports = <8>; + qcom,swr-port-mapping = <1 SPKR_L 0x1>, + <2 SPKR_L_COMP 0xF>, <3 SPKR_L_BOOST 0x3>, + <4 SPKR_R 0x1>, <5 SPKR_R_COMP 0xF>, + <6 SPKR_R_BOOST 0x3>, <7 SPKR_L_VI 0x3>, + <8 SPKR_R_VI 0x3>; + qcom,swr_master_id = <1>; wsa881x_11: wsa881x@11 { compatible = "qcom,wsa881x"; reg = <0x00 0x20170211>; diff --git a/arch/arm64/boot/dts/qcom/sm6150-wsa881x.dtsi b/arch/arm64/boot/dts/qcom/sm6150-wsa881x.dtsi index 539d3866ba80..0772619d8dea 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-wsa881x.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-wsa881x.dtsi @@ -17,12 +17,24 @@ }; }; +#include + &wsa_macro { swr_0: wsa_swr_master { compatible = "qcom,swr-mstr"; #address-cells = <2>; #size-cells = <0>; - + qcom,swr_master_id = <1>; + swrm-io-base = <0x62f10000 0x0>; + interrupts = <0 136 0>; + interrupt-names = "swr_master_irq"; + qcom,swr-num-ports = <8>; + qcom,swr-port-mapping = <1 SPKR_L 0x1>, + <2 SPKR_L_COMP 0xF>, <3 SPKR_L_BOOST 0x3>, + <4 SPKR_R 0x1>, <5 SPKR_R_COMP 0xF>, + <6 SPKR_R_BOOST 0x3>, <7 SPKR_L_VI 0x3>, + <8 SPKR_R_VI 0x3>; + qcom,swr-num-dev = <2>; wsa881x_0211: wsa881x@20170211 { compatible = "qcom,wsa881x"; reg = <0x0 0x20170211>; diff --git a/include/dt-bindings/sound/audio-codec-port-types.h b/include/dt-bindings/sound/audio-codec-port-types.h index b795d0db7db3..8a9d7cf4ca45 100644 --- a/include/dt-bindings/sound/audio-codec-port-types.h +++ b/include/dt-bindings/sound/audio-codec-port-types.h @@ -9,24 +9,30 @@ #define SPKR_R_BOOST 6 #define SPKR_R_COMP 7 #define SPKR_R_VI 8 -#define HPH 9 -#define COMPANDER 10 -#define CLSH 11 -#define LO 12 -#define DSD 13 -#define MBHC 14 -#define ADC1 15 -#define ADC2 16 -#define ADC3 17 -#define DMIC1 18 -#define DMIC2 19 -#define DMIC3 20 -#define DMIC4 21 -#define DMIC5 22 -#define DMIC6 23 -#define DMIC7 24 -#define DMIC8 25 -#define DMIC9 26 -#define DMIC10 27 +#define HPH_L 9 +#define HPH_R 10 +#define COMP_L 11 +#define COMP_R 12 +#define CLSH 13 +#define LO 14 +#define DSD_L 15 +#define DSD_R 16 +#define MBHC 17 +#define ADC1 18 +#define ADC2 19 +#define ADC3 20 +#define ADC4 21 +#define DMIC0 22 +#define DMIC1 23 +#define DMIC2 24 +#define DMIC3 25 +#define DMIC4 26 +#define DMIC5 27 +#define DMIC6 28 +#define DMIC7 29 +#define DMIC8 30 +#define DMIC9 31 +#define DMIC10 32 +#define PCM_OUT1 33 #endif /* __AUDIO_CODEC_PORT_TYPES_H */ -- GitLab From c09878959fe318e4156b2ea903dbc535b097c2cf Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Sun, 12 Aug 2018 17:03:58 +0530 Subject: [PATCH 0690/1001] msm: ipa3: Fix to not send filter/route hash table indices to modem When hashing is not supported in HW, modem will not expect filter/route hash table indices to be sent. Make a change to not to send the table indices when hashing is not supported. Change-Id: If4581761774db81ea46de9d09ef5d283c1dc582d Acked-by: Ashok Vuyyuru Signed-off-by: Mohammed Javid --- .../platform/msm/ipa/ipa_v3/ipa_qmi_service.c | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c index be216d052e17..018240ab6963 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -476,26 +476,30 @@ static int ipa3_qmi_init_modem_send_sync_msg(void) IPA_MEM_PART(modem_comp_decomp_ofst) + IPA_MEM_PART(modem_comp_decomp_size) + smem_restr_bytes - 1; - req.v4_hash_route_tbl_info_valid = true; - req.v4_hash_route_tbl_info.route_tbl_start_addr = - IPA_MEM_PART(v4_rt_hash_ofst) + smem_restr_bytes; - req.v4_hash_route_tbl_info.num_indices = - IPA_MEM_PART(v4_modem_rt_index_hi); - - req.v6_hash_route_tbl_info_valid = true; - req.v6_hash_route_tbl_info.route_tbl_start_addr = - IPA_MEM_PART(v6_rt_hash_ofst) + smem_restr_bytes; - req.v6_hash_route_tbl_info.num_indices = - IPA_MEM_PART(v6_modem_rt_index_hi); - - req.v4_hash_filter_tbl_start_addr_valid = true; - req.v4_hash_filter_tbl_start_addr = - IPA_MEM_PART(v4_flt_hash_ofst) + smem_restr_bytes; - - req.v6_hash_filter_tbl_start_addr_valid = true; - req.v6_hash_filter_tbl_start_addr = - IPA_MEM_PART(v6_flt_hash_ofst) + smem_restr_bytes; - + /* if hashing not supported, Modem filter/routing hash + * tables should not fill with valid data. + */ + if (!ipa3_ctx->ipa_fltrt_not_hashable) { + req.v4_hash_route_tbl_info_valid = true; + req.v4_hash_route_tbl_info.route_tbl_start_addr = + IPA_MEM_PART(v4_rt_hash_ofst) + smem_restr_bytes; + req.v4_hash_route_tbl_info.num_indices = + IPA_MEM_PART(v4_modem_rt_index_hi); + + req.v6_hash_route_tbl_info_valid = true; + req.v6_hash_route_tbl_info.route_tbl_start_addr = + IPA_MEM_PART(v6_rt_hash_ofst) + smem_restr_bytes; + req.v6_hash_route_tbl_info.num_indices = + IPA_MEM_PART(v6_modem_rt_index_hi); + + req.v4_hash_filter_tbl_start_addr_valid = true; + req.v4_hash_filter_tbl_start_addr = + IPA_MEM_PART(v4_flt_hash_ofst) + smem_restr_bytes; + + req.v6_hash_filter_tbl_start_addr_valid = true; + req.v6_hash_filter_tbl_start_addr = + IPA_MEM_PART(v6_flt_hash_ofst) + smem_restr_bytes; + } req.hw_stats_quota_base_addr_valid = true; req.hw_stats_quota_base_addr = IPA_MEM_PART(stats_quota_ofst) + smem_restr_bytes; -- GitLab From 1d62eb3a93c916cb9227dfbeb8970f5c82c580fa Mon Sep 17 00:00:00 2001 From: Shrey Vijay Date: Mon, 26 Feb 2018 15:01:22 +0530 Subject: [PATCH 0691/1001] i2c-qcom-geni: Calculate transfer timeout based on payload size Large I2C transfers gets timed out, which can take more than 1 second for completion. To support such large transfers, calculate transfer completion timeout based on the payload size. Change-Id: Iccb8466ae334ba2940588528be18235f63f2fddd Signed-off-by: Shrey Vijay --- drivers/i2c/busses/i2c-qcom-geni.c | 34 +++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index db708ea669d1..3e3c8abe9bcf 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -77,6 +77,10 @@ #define I2C_AUTO_SUSPEND_DELAY 250 +#define I2C_TIMEOUT_SAFETY_COEFFICIENT 10 + +#define I2C_TIMEOUT_MIN_USEC 500000 + enum i2c_se_mode { UNINITIALIZED, FIFO_SE_DMA, @@ -89,6 +93,7 @@ struct geni_i2c_dev { unsigned int tx_wm; int irq; int err; + u32 xfer_timeout; struct i2c_adapter adap; struct completion xfer; struct i2c_msg *cur; @@ -192,12 +197,26 @@ static inline void qcom_geni_i2c_conf(struct geni_i2c_dev *gi2c, int dfs) mb(); } +static inline void qcom_geni_i2c_calc_timeout(struct geni_i2c_dev *gi2c) +{ + + struct geni_i2c_clk_fld *clk_itr = geni_i2c_clk_map + gi2c->clk_fld_idx; + size_t bit_cnt = gi2c->cur->len*9; + size_t bit_usec = (bit_cnt*USEC_PER_SEC)/clk_itr->clk_freq_out; + size_t xfer_max_usec = (bit_usec*I2C_TIMEOUT_SAFETY_COEFFICIENT) + + I2C_TIMEOUT_MIN_USEC; + + gi2c->xfer_timeout = usecs_to_jiffies(xfer_max_usec); + +} + static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) { if (gi2c->cur) GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, - "len:%d, slv-addr:0x%x, RD/WR:%d\n", gi2c->cur->len, - gi2c->cur->addr, gi2c->cur->flags); + "len:%d, slv-addr:0x%x, RD/WR:%d timeout:%u\n", + gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags, + gi2c->xfer_timeout); if (err == I2C_NACK || err == GENI_ABORT_DONE) { GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", @@ -476,6 +495,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], struct device *tx_dev = gi2c->wrapper_dev; gi2c->cur = &msgs[i]; + qcom_geni_i2c_calc_timeout(gi2c); if (!gi2c->cfg_sent) { segs++; sg_init_table(gi2c->tx_sg, segs); @@ -569,7 +589,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], tx_cookie = dmaengine_submit(gi2c->tx_desc); dma_async_issue_pending(gi2c->tx_c); - timeout = wait_for_completion_timeout(&gi2c->xfer, HZ); + timeout = wait_for_completion_timeout(&gi2c->xfer, + gi2c->xfer_timeout); if (msgs[i].flags & I2C_M_RD) geni_se_iommu_unmap_buf(rx_dev, &gi2c->rx_ph, msgs[i].len, DMA_FROM_DEVICE); @@ -579,7 +600,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (!timeout) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, - "GSI Txn timed out\n"); + "GSI Txn timed out: %u len: %d\n", + gi2c->xfer_timeout, gi2c->cur->len); gi2c->err = -ETIMEDOUT; } if (gi2c->err) { @@ -635,6 +657,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, m_param |= ((msgs[i].addr & 0x7F) << SLV_ADDR_SHFT); gi2c->cur = &msgs[i]; + qcom_geni_i2c_calc_timeout(gi2c); mode = msgs[i].len > 32 ? SE_DMA : FIFO_MODE; ret = geni_se_select_mode(gi2c->base, mode); if (ret) { @@ -684,7 +707,8 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, } /* Ensure FIFO write go through before waiting for Done evet */ mb(); - timeout = wait_for_completion_timeout(&gi2c->xfer, HZ); + timeout = wait_for_completion_timeout(&gi2c->xfer, + gi2c->xfer_timeout); if (!timeout) { geni_i2c_err(gi2c, GENI_TIMEOUT); gi2c->cur = NULL; -- GitLab From fe5d837a84119f0b4bab403b65ff617a98ff7771 Mon Sep 17 00:00:00 2001 From: Shrey Vijay Date: Thu, 24 May 2018 14:48:28 +0530 Subject: [PATCH 0692/1001] i2c-qcom-geni: Handle corner cases in GSI transfer Add check to handle if the IOMMU buffer mapping fails, also make sure to unmap buffer in case of prep_slave_sg failure. Change-Id: I926a6ce5b10a3c7f29210cba5179cc795ec0c1b4 Signed-off-by: Shrey Vijay --- drivers/i2c/busses/i2c-qcom-geni.c | 43 +++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 3e3c8abe9bcf..2014b8ac466a 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -526,8 +526,16 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (msgs[i].flags & I2C_M_RD) { sg_init_table(&gi2c->rx_sg, 1); - geni_se_iommu_map_buf(rx_dev, &gi2c->rx_ph, msgs[i].buf, - msgs[i].len, DMA_FROM_DEVICE); + ret = geni_se_iommu_map_buf(rx_dev, &gi2c->rx_ph, + msgs[i].buf, msgs[i].len, + DMA_FROM_DEVICE); + if (ret) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "geni_se_iommu_map_buf for rx failed :%d\n", + ret); + goto geni_i2c_gsi_xfer_out; + + } gi2c->rx_t.dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->rx_ph); gi2c->rx_t.dword[1] = @@ -548,7 +556,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "prep_slave_sg for rx failed\n"); gi2c->err = -ENOMEM; - goto geni_i2c_gsi_xfer_out; + goto geni_i2c_err_prep_sg; } gi2c->rx_desc->callback = gi2c_gsi_rx_cb; gi2c->rx_desc->callback_param = &gi2c->rx_cb; @@ -557,8 +565,16 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], rx_cookie = dmaengine_submit(gi2c->rx_desc); dma_async_issue_pending(gi2c->rx_c); } else { - geni_se_iommu_map_buf(tx_dev, &gi2c->tx_ph, msgs[i].buf, - msgs[i].len, DMA_TO_DEVICE); + ret = geni_se_iommu_map_buf(tx_dev, &gi2c->tx_ph, + msgs[i].buf, msgs[i].len, + DMA_TO_DEVICE); + if (ret) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "geni_se_iommu_map_buf for tx failed :%d\n", + ret); + goto geni_i2c_gsi_xfer_out; + + } gi2c->tx_t.dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->tx_ph); gi2c->tx_t.dword[1] = @@ -580,7 +596,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "prep_slave_sg for tx failed\n"); gi2c->err = -ENOMEM; - goto geni_i2c_gsi_xfer_out; + goto geni_i2c_err_prep_sg; } gi2c->tx_desc->callback = gi2c_gsi_tx_cb; gi2c->tx_desc->callback_param = &gi2c->tx_cb; @@ -591,12 +607,6 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], timeout = wait_for_completion_timeout(&gi2c->xfer, gi2c->xfer_timeout); - if (msgs[i].flags & I2C_M_RD) - geni_se_iommu_unmap_buf(rx_dev, &gi2c->rx_ph, - msgs[i].len, DMA_FROM_DEVICE); - else - geni_se_iommu_unmap_buf(tx_dev, &gi2c->tx_ph, - msgs[i].len, DMA_TO_DEVICE); if (!timeout) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, @@ -604,12 +614,21 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], gi2c->xfer_timeout, gi2c->cur->len); gi2c->err = -ETIMEDOUT; } +geni_i2c_err_prep_sg: + if (msgs[i].flags & I2C_M_RD) + geni_se_iommu_unmap_buf(rx_dev, &gi2c->rx_ph, + msgs[i].len, DMA_FROM_DEVICE); + else + geni_se_iommu_unmap_buf(tx_dev, &gi2c->tx_ph, + msgs[i].len, DMA_TO_DEVICE); + if (gi2c->err) { dmaengine_terminate_all(gi2c->tx_c); gi2c->cfg_sent = 0; goto geni_i2c_gsi_xfer_out; } } + geni_i2c_gsi_xfer_out: if (!ret && gi2c->err) ret = gi2c->err; -- GitLab From 63f37e778bcf814a181735320d3231544c9e0707 Mon Sep 17 00:00:00 2001 From: Ghanim Fodi Date: Sun, 12 Aug 2018 18:39:29 +0300 Subject: [PATCH 0693/1001] msm: ipa: Enable RMNET_IPA3 compilation for sdxprairie Enable RMNET_IPA3 module for IPA rmnet functionality which is needed for sdxprairie. This enables also all the dependent features, QRTR and QMI. CRs-Fixed: 2295428 Change-Id: I7c36dbe10c0c1b47cd7a9b8c72eaf538d81a99f8 Signed-off-by: Ghanim Fodi --- arch/arm/configs/vendor/sdxprairie-perf_defconfig | 3 +++ arch/arm/configs/vendor/sdxprairie_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm/configs/vendor/sdxprairie-perf_defconfig b/arch/arm/configs/vendor/sdxprairie-perf_defconfig index ff61ff4057d4..69881b3407e4 100644 --- a/arch/arm/configs/vendor/sdxprairie-perf_defconfig +++ b/arch/arm/configs/vendor/sdxprairie-perf_defconfig @@ -133,6 +133,7 @@ CONFIG_BRIDGE_EBT_SNAT=y CONFIG_BRIDGE=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_PRIO=y +CONFIG_QRTR=y CONFIG_BT=y CONFIG_BT_RFCOMM=y CONFIG_BT_RFCOMM_TTY=y @@ -259,6 +260,7 @@ CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_USB_BAM=y CONFIG_IPA3=y CONFIG_IPA_WDI_UNIFIED_API=y +CONFIG_RMNET_IPA3=y CONFIG_ECM_IPA=y CONFIG_RNDIS_IPA=y CONFIG_IPA_UT=y @@ -269,6 +271,7 @@ CONFIG_ARM_SMMU=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y +CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y CONFIG_PWM=y CONFIG_ANDROID=y diff --git a/arch/arm/configs/vendor/sdxprairie_defconfig b/arch/arm/configs/vendor/sdxprairie_defconfig index 7d08a7eae535..0b8de0c0489b 100644 --- a/arch/arm/configs/vendor/sdxprairie_defconfig +++ b/arch/arm/configs/vendor/sdxprairie_defconfig @@ -133,6 +133,7 @@ CONFIG_BRIDGE_EBT_SNAT=y CONFIG_BRIDGE=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_PRIO=y +CONFIG_QRTR=y CONFIG_CFG80211=y CONFIG_RFKILL=y CONFIG_DMA_CMA=y @@ -249,6 +250,7 @@ CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_IPA3=y CONFIG_IPA_WDI_UNIFIED_API=y +CONFIG_RMNET_IPA3=y CONFIG_ECM_IPA=y CONFIG_RNDIS_IPA=y CONFIG_IPA_UT=y @@ -259,6 +261,7 @@ CONFIG_ARM_SMMU=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y +CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y CONFIG_MSM_BOOT_STATS=y CONFIG_PWM=y -- GitLab From 88caa9ae463fea52b2d089258461764f68f18830 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Thu, 19 Jul 2018 20:16:39 +0530 Subject: [PATCH 0694/1001] msm: ipa: Setting appropriate config on MHI ep Couple of configuration updates on MHI ep, - During MHI suspend sequence, suspend DL channels first and followed by UL channels. Because, if MHI suspended during high tput scenario, there could be a chance that Q6 is still pumping data towards it. Due to which UL channels disconnection will fail and assert the device. - Set ep_delay on MHI CLIENT PROD ep upon connect, to prevent some random data getting into IPA before even Q6 configures it. - During SSR in pre-shutdown cleanup, set ep_delay and holb on MHI ep's to make sure there is no ipa stall due to some packet in/out. Since the ep configs are done by Q6 and which is down in SSR. Change-Id: Ie315892a2d1403a7e1f2ecf40c7b6c12d4e93c91 Signed-off-by: Mohammed Javid --- .../msm/ipa/ipa_clients/ipa_mhi_client.c | 20 +++--- drivers/platform/msm/ipa/ipa_v3/ipa.c | 10 ++- drivers/platform/msm/ipa/ipa_v3/ipa_client.c | 72 +++++++++++++++++-- drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 5 +- drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c | 31 ++++++++ 5 files changed, 120 insertions(+), 18 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c index 6cbfa4bcc12f..a4dceb6ca176 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c @@ -2136,6 +2136,15 @@ int ipa_mhi_suspend(bool force) IPA_MHI_ERR("ipa_mhi_set_state failed %d\n", res); return res; } + + res = ipa_mhi_suspend_dl(force); + if (res) { + IPA_MHI_ERR("ipa_mhi_suspend_dl failed %d\n", res); + goto fail_suspend_dl_channel; + } + + usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN, IPA_MHI_SUSPEND_SLEEP_MAX); + res = ipa_mhi_suspend_ul(force, &empty, &force_clear); if (res) { IPA_MHI_ERR("ipa_mhi_suspend_ul failed %d\n", res); @@ -2176,12 +2185,6 @@ int ipa_mhi_suspend(bool force) } usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN, IPA_MHI_SUSPEND_SLEEP_MAX); - res = ipa_mhi_suspend_dl(force); - if (res) { - IPA_MHI_ERR("ipa_mhi_suspend_dl failed %d\n", res); - goto fail_suspend_dl_channel; - } - if (!empty) ipa_set_tag_process_before_gating(false); @@ -2195,7 +2198,6 @@ int ipa_mhi_suspend(bool force) IPA_MHI_FUNC_EXIT(); return 0; -fail_suspend_dl_channel: fail_release_cons: if (!ipa_pm_is_used()) ipa_mhi_request_prod(); @@ -2209,7 +2211,6 @@ int ipa_mhi_suspend(bool force) IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); fail_suspend_ul_channel: ipa_mhi_resume_channels(true, ipa_mhi_client_ctx->ul_channels); - ipa_mhi_set_state(IPA_MHI_STATE_STARTED); if (force_clear) { if ( ipa_mhi_disable_force_clear(ipa_mhi_client_ctx->qmi_req_id)) { @@ -2219,6 +2220,9 @@ int ipa_mhi_suspend(bool force) IPA_MHI_DBG("force clear datapath disabled\n"); ipa_mhi_client_ctx->qmi_req_id++; } +fail_suspend_dl_channel: + ipa_mhi_resume_channels(true, ipa_mhi_client_ctx->dl_channels); + ipa_mhi_set_state(IPA_MHI_STATE_STARTED); return res; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 683906ae2993..5382f14faea3 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -2548,6 +2548,9 @@ void ipa3_q6_pre_shutdown_cleanup(void) ipa3_q6_pipe_delay(true); ipa3_q6_avoid_holb(); + if (ipa3_ctx->ipa_config_is_mhi) + ipa3_set_reset_client_cons_pipe_sus_holb(true, + IPA_CLIENT_MHI_CONS); if (ipa3_q6_clean_q6_tables()) { IPAERR("Failed to clean Q6 tables\n"); /* @@ -2568,8 +2571,11 @@ void ipa3_q6_pre_shutdown_cleanup(void) * on pipe reset procedure */ ipa3_q6_pipe_delay(false); - - ipa3_set_usb_prod_pipe_delay(); + ipa3_set_reset_client_prod_pipe_delay(true, + IPA_CLIENT_USB_PROD); + if (ipa3_ctx->ipa_config_is_mhi) + ipa3_set_reset_client_prod_pipe_delay(true, + IPA_CLIENT_MHI_PROD); IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); IPADBG_LOW("Exit with success\n"); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index 3aaf7f50e5a2..7f0e29211efc 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -1345,27 +1345,32 @@ static int ipa3_stop_ul_chan_with_data_drain(u32 qmi_req_id, } /* - * Set USB PROD pipe delay for MBIM/RMNET config + * Set reset ep_delay for CLIENT PROD pipe * Clocks, should be voted before calling this API * locks should be taken before calling this API */ -void ipa3_set_usb_prod_pipe_delay(void) +int ipa3_set_reset_client_prod_pipe_delay(bool set_reset, + enum ipa_client_type client) { - int result; + int result = 0; int pipe_idx; struct ipa3_ep_context *ep; struct ipa_ep_cfg_ctrl ep_ctrl; memset(&ep_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl)); - ep_ctrl.ipa_ep_delay = true; + ep_ctrl.ipa_ep_delay = set_reset; + if (IPA_CLIENT_IS_CONS(client)) { + IPAERR("client (%d) not PROD\n", client); + return -EINVAL; + } - pipe_idx = ipa3_get_ep_mapping(IPA_CLIENT_USB_PROD); + pipe_idx = ipa3_get_ep_mapping(client); if (pipe_idx == IPA_EP_NOT_ALLOCATED) { - IPAERR("client (%d) not valid\n", IPA_CLIENT_USB_PROD); - return; + IPAERR("client (%d) not valid\n", client); + return -EINVAL; } ep = &ipa3_ctx->ep[pipe_idx]; @@ -1382,6 +1387,59 @@ void ipa3_set_usb_prod_pipe_delay(void) IPADBG("client (ep: %d) success\n", pipe_idx); } client_lock_unlock_cb(pipe_idx, false); + return result; +} + +int ipa3_set_reset_client_cons_pipe_sus_holb(bool set_reset, + enum ipa_client_type client) +{ + int pipe_idx; + struct ipa3_ep_context *ep; + struct ipa_ep_cfg_ctrl ep_suspend; + struct ipa_ep_cfg_holb ep_holb; + + memset(&ep_suspend, 0, sizeof(ep_suspend)); + memset(&ep_holb, 0, sizeof(ep_holb)); + + ep_suspend.ipa_ep_suspend = set_reset; + ep_holb.tmr_val = 0; + ep_holb.en = set_reset; + + if (IPA_CLIENT_IS_PROD(client)) { + IPAERR("client (%d) not CONS\n", client); + return -EINVAL; + } + + pipe_idx = ipa3_get_ep_mapping(client); + + if (pipe_idx == IPA_EP_NOT_ALLOCATED) { + IPAERR("client (%d) not valid\n", client); + return -EINVAL; + } + + ep = &ipa3_ctx->ep[pipe_idx]; + /* Setting sus/holb on MHI_CONS with skip_ep_cfg */ + client_lock_unlock_cb(pipe_idx, true); + if (ep->valid && ep->skip_ep_cfg) { + if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) + ipahal_write_reg_n_fields( + IPA_ENDP_INIT_CTRL_n, + pipe_idx, &ep_suspend); + /* + * ipa3_cfg_ep_holb is not used here because we are + * setting HOLB on Q6 pipes, and from APPS perspective + * they are not valid, therefore, the above function + * will fail. + */ + ipahal_write_reg_n_fields( + IPA_ENDP_INIT_HOL_BLOCK_TIMER_n, + pipe_idx, &ep_holb); + ipahal_write_reg_n_fields( + IPA_ENDP_INIT_HOL_BLOCK_EN_n, + pipe_idx, &ep_holb); + } + client_lock_unlock_cb(pipe_idx, false); + return 0; } void ipa3_xdci_ep_delay_rm(u32 clnt_hdl) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 699e0bd0363c..25aebbe63daf 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1966,7 +1966,10 @@ int ipa3_xdci_disconnect(u32 clnt_hdl, bool should_force_clear, u32 qmi_req_id); void ipa3_xdci_ep_delay_rm(u32 clnt_hdl); void ipa3_register_lock_unlock_callback(int (*client_cb)(bool), u32 ipa_ep_idx); void ipa3_deregister_lock_unlock_callback(u32 ipa_ep_idx); -void ipa3_set_usb_prod_pipe_delay(void); +int ipa3_set_reset_client_prod_pipe_delay(bool set_reset, + enum ipa_client_type client); +int ipa3_set_reset_client_cons_pipe_sus_holb(bool set_reset, + enum ipa_client_type client); int ipa3_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, bool should_force_clear, u32 qmi_req_id, bool is_dpl); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c index 35a0e61d46df..0f472bec575a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c @@ -198,6 +198,7 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, union __packed gsi_channel_scratch ch_scratch; struct ipa3_ep_context *ep; const struct ipa_gsi_ep_config *ep_cfg; + struct ipa_ep_cfg_ctrl ep_cfg_ctrl; IPA_MHI_FUNC_ENTRY(); @@ -334,6 +335,20 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, *params->mhi = ch_scratch.mhi; + if (IPA_CLIENT_IS_PROD(ep->client) && ep->skip_ep_cfg) { + memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl)); + ep_cfg_ctrl.ipa_ep_delay = true; + ep->ep_delay_set = true; + res = ipa3_cfg_ep_ctrl(ipa_ep_idx, &ep_cfg_ctrl); + if (res) + IPA_MHI_ERR("client (ep: %d) failed result=%d\n", + ipa_ep_idx, res); + else + IPA_MHI_DBG("client (ep: %d) success\n", ipa_ep_idx); + } else { + ep->ep_delay_set = false; + } + IPA_MHI_DBG("Starting channel\n"); res = gsi_start_channel(ep->gsi_chan_hdl); if (res) { @@ -517,6 +532,7 @@ int ipa3_disconnect_mhi_pipe(u32 clnt_hdl) { struct ipa3_ep_context *ep; int res; + struct ipa_ep_cfg_ctrl ep_cfg_ctrl; IPA_MHI_FUNC_ENTRY(); @@ -531,6 +547,21 @@ int ipa3_disconnect_mhi_pipe(u32 clnt_hdl) } ep = &ipa3_ctx->ep[clnt_hdl]; + if (ep->ep_delay_set == true) { + memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl)); + ep_cfg_ctrl.ipa_ep_delay = false; + res = ipa3_cfg_ep_ctrl(clnt_hdl, + &ep_cfg_ctrl); + if (res) { + IPAERR + ("client(ep:%d) failed to remove delay res=%d\n", + clnt_hdl, res); + } else { + IPADBG("client (ep: %d) delay removed\n", + clnt_hdl); + ep->ep_delay_set = false; + } + } res = gsi_dealloc_channel(ep->gsi_chan_hdl); if (res) { -- GitLab From 6789060792560415a5753843b055b532d71c5916 Mon Sep 17 00:00:00 2001 From: Ghanim Fodi Date: Sun, 12 Aug 2018 23:39:11 +0300 Subject: [PATCH 0695/1001] ARM: dts: msm: add rmnet_ipa node for sdxprairie Add devicetree nodes for rmnet_ipa driver. This is to enable embedded traffic between modem and APPS going through IPA H/W. CRs-Fixed: 2295428 Change-Id: Ifa159ff71102e23a2338e41f853bcc257412e306 Signed-off-by: Ghanim Fodi --- arch/arm64/boot/dts/qcom/sdxprairie.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi index 42b9c875dcf3..d8ed44602fef 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi @@ -181,6 +181,11 @@ compatible = "qcom,msm_gsi"; }; + qcom,rmnet-ipa { + compatible = "qcom,rmnet-ipa3"; + qcom,rmnet-ipa-ssr; + }; + ipa_hw: qcom,ipa@01e00000 { compatible = "qcom,ipa"; reg = <0x1e00000 0xc0000>, -- GitLab From cf6cb1291960eb6be9653705d09a6e4c98b52942 Mon Sep 17 00:00:00 2001 From: Veerabhadrarao Badiganti Date: Mon, 9 Oct 2017 22:49:49 +0530 Subject: [PATCH 0696/1001] mmc: card: Service RPMB requests with priority over other requests RPMB requests are initiated from TZ and TZ gets blocked from servicing other tasks/requests till it completes RPMB request. Delays in servicing RPMB request may result in system-level stability/performance issues. Below is the issue observed: 1. TZ rpmb API is called to update TA rollback information. TZ forwards the request to HLOS mmc driver via rpmb-service. 2. mmc driver services the rpmb requests only after finishing the outstanding IO requests. 3. As part of handling an IO requests, mmc driver makes ICE call for getting encryption keys, which in-turn makes call to TZ. 4. Since ICE driver finds TZ is busy/blocked it returns ice request with -EBUSY error. 5. The failed requests with -EBUSY error would re-queued back. 6. The IO requests keep getting failed and keep getting re-queued and mmc driver never gets a chance to service rpmb requests. 7. This results in a deadlock senario. So RPMB requests need to be serviced immediately. If there is any outstanding RPMB request, then mmc driver should stop pulling any more new requests. The moment its done with serving ongoing requests, It should start processing RPMB request. Change-Id: I2d0f98a11716ef946551cc1a967e70a38e91d6ac Signed-off-by: Veerabhadrarao Badiganti --- drivers/mmc/core/block.c | 8 ++++++++ drivers/mmc/core/host.c | 2 ++ drivers/mmc/core/queue.c | 5 ++++- include/linux/mmc/host.h | 3 +++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 33aa47ba39b6..441edfe0912b 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -908,6 +908,12 @@ static int mmc_blk_ioctl_rpmb_cmd(struct block_device *bdev, goto idata_free; } + /* + * Ensure rpmb_req_pending flag is synchronized between multiple + * entities which may use rpmb ioclts with a lock. + */ + mutex_lock(&card->host->rpmb_req_mutex); + atomic_set(&card->host->rpmb_req_pending, 1); mmc_get_card(card); if (mmc_card_doing_bkops(card)) { @@ -1023,6 +1029,8 @@ static int mmc_blk_ioctl_rpmb_cmd(struct block_device *bdev, cmd_rel_host: mmc_put_card(card); + atomic_set(&card->host->rpmb_req_pending, 0); + mutex_unlock(&card->host->rpmb_req_mutex); idata_free: for (i = 0; i < MMC_IOC_MAX_RPMB_CMD; i++) { diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index d89dc8ecb009..a6fc7f68ec0c 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -698,6 +698,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) INIT_DELAYED_WORK(&host->sdio_irq_work, sdio_irq_work); setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host); + mutex_init(&host->rpmb_req_mutex); + /* * By default, hosts do not support SGIO or large requests. * They have to set these according to their abilities. diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 67fa942ec544..e2dd4c03b20e 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -84,7 +84,9 @@ static inline void mmc_cmdq_ready_wait(struct mmc_host *host, * be any other direct command active. * 3. cmdq state should be unhalted. * 4. cmdq state shouldn't be in error state. - * 5. free tag available to process the new request. + * 5. There is no outstanding RPMB request pending. + * 6. free tag available to process the new request. + * (This must be the last condtion to check) */ wait_event(ctx->wait, kthread_should_stop() || (mmc_peek_request(mq) && @@ -96,6 +98,7 @@ static inline void mmc_cmdq_ready_wait(struct mmc_host *host, && !(!host->card->part_curr && mmc_host_cq_disable(host) && !mmc_card_suspended(host->card)) && !test_bit(CMDQ_STATE_ERR, &ctx->curr_state) + && !atomic_read(&host->rpmb_req_pending) && !mmc_check_blk_queue_start_tag(q, mq->cmdq_req_peeked))); } diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 426f8d78415d..0cf555098c82 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -704,6 +704,9 @@ struct mmc_host { */ void *cmdq_private; struct mmc_request *err_mrq; + + atomic_t rpmb_req_pending; + struct mutex rpmb_req_mutex; unsigned long private[0] ____cacheline_aligned; }; -- GitLab From aa4a0148bc1e386696c0d523c33702c084e0eeb6 Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Fri, 15 Jun 2018 10:45:22 +0530 Subject: [PATCH 0697/1001] mmc: cmdq: Notify higher layer of ice errors This patch completes with the received error without any error handling. Since this request is not even prepared, there's no need for error handling to be done. Hence, notify higher layers with appropriate error in the event of errors during ice configuration. CRs-fixed: 2259462 Change-Id: I49f352bd1b79054849da1de3532a9b318e970af0 Signed-off-by: Asutosh Das --- drivers/mmc/core/block.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 33aa47ba39b6..f27c5cacb309 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -3552,6 +3552,13 @@ static int mmc_blk_cmdq_issue_rq(struct mmc_queue *mq, struct request *req) if (ret == -EBUSY || ret == -EAGAIN) { mmc_blk_cmdq_requeue_rw_rq(mq, req); mmc_put_card(host->card); + } else if (ret == -ENOMEM) { + /* + * Elaborate error handling is not needed for + * system errors. Let the higher layer decide + * on the next steps. + */ + goto out; } } } -- GitLab From e902c784a656ebc3fcf584624218ac0b51600237 Mon Sep 17 00:00:00 2001 From: Jayden Cha Date: Wed, 8 Aug 2018 11:37:01 +0530 Subject: [PATCH 0698/1001] leds: PCA9955B: 24-channel constant current LED driver The PCA9956B is an I2C bus controlled 24-channel LED driver. Each LED output has its own 8-bit fixed-frequency PWM controller to control the brightness of the LED. Change-Id: I2675231c52874a3f4c37496699c94c0ef7a395fb Signed-off-by: Jayden Cha Git-commit: 5dcf8ffdfb7f622b32a54e1ad9d42a0e7f8b2217 Git-repo: https://source.codeaurora.org/external/mob-pwr-pl/mpp/ldd/commit/pca9956b?h=pca9956b.rpi.linux-4.9.41 [pvadde@codeaurora.org: Making it as a built-in module] Signed-off-by: Prashanth Vadde --- .../devicetree/bindings/leds/Nxp-ledseg.txt | 55 ++ drivers/leds/Kconfig | 9 + drivers/leds/Makefile | 1 + drivers/leds/leds-pca9956b.c | 528 ++++++++++++++++++ drivers/leds/leds-pca9956b.h | 111 ++++ 5 files changed, 704 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/Nxp-ledseg.txt create mode 100644 drivers/leds/leds-pca9956b.c create mode 100644 drivers/leds/leds-pca9956b.h diff --git a/Documentation/devicetree/bindings/leds/Nxp-ledseg.txt b/Documentation/devicetree/bindings/leds/Nxp-ledseg.txt new file mode 100644 index 000000000000..c53c3a065822 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/Nxp-ledseg.txt @@ -0,0 +1,55 @@ +NXP LED segment driver devicetree bindings + +Required properties: + + - compatible : "nxp,pca9956b" for PCA9956b + - nxp,mode1 : MODE1 register + - nxp,mode2 : MODE2 register + - nxp,ledout0~5 : LED output state registers + - nxp,defaultiref : LED output gain control default value + +LED sub-node properties: + - reg: number of LED line, 0 to 24 + - label: (optional) name of LED + - linux,default-trigger : (optional) + +Example: +pca9956b { + /* I2C version */ + reg = <0x7d>; + + /* nxp-ledseg properties */ + + compatible = "nxp,pca9956b"; + + pinctrl-names = "default"; + pinctrl-0 = <&pca9956b_pins>; + + pca9956b,support_initialize = <1>; + pca9956b,mode1 = <0x09>; + pca9956b,mode2 = <0x05>; + + pca9956b,ledout0 = <0xaa>; + pca9956b,ledout1 = <0xaa>; + pca9956b,ledout2 = <0xaa>; + pca9956b,ledout3 = <0xff>; + pca9956b,ledout4 = <0xff>; + pca9956b,ledout5 = <0xff>; + pca9956b,defaultiref = <0x2f>; + + out0@0 { + label = "ledsec1_b"; + reg = <0x0>; + }; + + out1@1 { + label = "ledsec1_g"; + reg = <0x1>; + }; + + out5@5 { + label = "ledsec1_g"; + reg = <0x5>; + linux,default_trigger = "heartbeat"; + }; +}; diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index da8b46f9ec7f..1ab5f21c0a0c 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -406,6 +406,15 @@ config LEDS_PCA963X LED driver chip accessed via the I2C bus. Supported devices include PCA9633 and PCA9634 +config LEDS_PCA9956B + tristate "LED support for PCA9956B I2C chip" + depends on LEDS_CLASS + depends on I2C + help + This option enables support for LEDs connected to the PCA9956B + LED driver chip accessed via the I2C bus. Supported + devices include PCA9956B + config LEDS_QPNP_FLASH_V2 tristate "Support for QPNP V2 Flash LEDs" depends on LEDS_CLASS && MFD_SPMI_PMIC diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index e8e7a2ec587c..9ea6d8a1cd6d 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_LEDS_OT200) += leds-ot200.o obj-$(CONFIG_LEDS_FSG) += leds-fsg.o obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o obj-$(CONFIG_LEDS_PCA963X) += leds-pca963x.o +obj-$(CONFIG_LEDS_PCA9956B) += leds-pca9956b.o obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o obj-$(CONFIG_LEDS_DA9052) += leds-da9052.o obj-$(CONFIG_LEDS_QPNP_FLASH_V2) += leds-qpnp-flash-v2.o diff --git a/drivers/leds/leds-pca9956b.c b/drivers/leds/leds-pca9956b.c new file mode 100644 index 000000000000..b54e7a21635e --- /dev/null +++ b/drivers/leds/leds-pca9956b.c @@ -0,0 +1,528 @@ +/* + * leds-pca9956b.c - NXP PCA9956B LED segment driver + * + * Copyright (C) 2017 NXP Semiconductors + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "leds-pca9956b.h" + +#define PCA9956B_LED_NUM 24 +#define MAX_DEVICES 32 + +#define DRIVER_NAME "nxp-ledseg" +#define DRIVER_VERSION "17.11.28" + +struct pca9956b_chip { + struct i2c_client *client; + struct mutex lock; + struct pca9956b_led *leds; +}; + +struct pca9956b_led { + struct led_classdev led_cdev; + struct pca9956b_chip *chip; + int led_num; + char name[32]; +}; + +static struct device *pca9956b_dev; + +/* + * Read one byte from given register address. + */ +static int pca9956b_read_reg(struct pca9956b_chip *chip, int reg, uint8_t *val) +{ + int ret = i2c_smbus_read_byte_data(chip->client, reg); + + if (ret < 0) { + dev_err(&chip->client->dev, "failed reading register\n"); + return ret; + } + + *val = (uint8_t)ret; + return 0; +} + +/* + * Write one byte to the given register address. + */ +static int pca9956b_write_reg(struct pca9956b_chip *chip, int reg, uint8_t val) +{ + int ret = i2c_smbus_write_byte_data(chip->client, reg, val); + + if (ret < 0) { + dev_err(&chip->client->dev, "failed writing register\n"); + return ret; + } + + return 0; +} + +/* + * Read string from device tree property and write it to the register. + */ +static int pca9956b_readWrite_reg(struct pca9956b_chip *chip, + char *readStr, int writeRegAddr) +{ + struct device_node *np = chip->client->dev.of_node; + uint32_t reg_value; + int ret; + + ret = of_property_read_u32(np, readStr, ®_value); + if (ret < 0) { + dev_err(&chip->client->dev, + "[%s]: Unable to read %s\n", + __func__, readStr); + return ret; + } + + mutex_lock(&chip->lock); + + ret = pca9956b_write_reg(chip, writeRegAddr, (uint8_t)reg_value); + if (ret < 0) { + dev_err(&chip->client->dev, + "[%s]: Unable to write %s , value = 0x%x\n", + __func__, readStr, reg_value); + mutex_unlock(&chip->lock); + return ret; + } + + mutex_unlock(&chip->lock); + + return ret; +} + +/* + * Store one byte to given register address. + */ +static ssize_t pca9956b_storeReg(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct pca9956b_chip *chip = dev_get_drvdata(dev); + unsigned int ret, reg_value, reg_addr; + + ret = sscanf(buf, "%x %x", ®_addr, ®_value); + if (ret == 0) { + dev_err(&chip->client->dev, + "[%s] fail to pca9956b out.\n", + __func__); + return count; + } + + if (reg_addr < PCA9956B_MODE1 || reg_addr > PCA9956B_IREFALL) { + dev_err(&chip->client->dev, + "[%s] Out of range. Reg = 0x%x\n", + __func__, reg_addr); + return count; + } + + mutex_lock(&chip->lock); + + ret = pca9956b_write_reg(chip, reg_addr, (uint8_t)reg_value); + if (ret != 0) + dev_err(&chip->client->dev, + "[%s] Operation [0x%x , %d] is failed.\n", + __func__, reg_addr, reg_value); + + mutex_unlock(&chip->lock); + + return count; +} + +/* + * Show all registers + */ +static ssize_t pca9956b_showReg(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct pca9956b_chip *chip = dev_get_drvdata(dev); + uint8_t reg_value = 0; + int ret, i; + char *bufp = buf; + + mutex_lock(&chip->lock); + + for (i = PCA9956B_MODE1; i < PCA9956B_IREFALL; i++) { + ret = pca9956b_read_reg(chip, i, ®_value); + if (ret != 0) + dev_err(&chip->client->dev, + "[%s] Reading reg[0x%x] is failed.\n", + __func__, i); + + bufp += snprintf(bufp, PAGE_SIZE, + "Addr[0x%x] = 0x%x\n", i, reg_value); + } + + mutex_unlock(&chip->lock); + + return strlen(buf); +} + +static DEVICE_ATTR(reg, 0664, + pca9956b_showReg, pca9956b_storeReg); + +/* + * Show error register. + */ +static ssize_t pca9956_showErr(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct pca9956b_chip *chip = dev_get_drvdata(dev); + uint8_t reg_value = 0; + int ret, i; + char *bufp = buf; + + mutex_lock(&chip->lock); + + for (i = PCA9956B_EFLAG0 ; i <= PCA9956B_EFLAG4 ; i++) { + ret = pca9956b_read_reg(chip, i, ®_value); + if (ret != 0) + dev_err(&chip->client->dev, + "[%s] Reading [0x%x] is failed.\n", + __func__, i); + + bufp += snprintf(bufp, PAGE_SIZE, "PCA9956B_EFLAG[%d] = 0x%x\n", + i - PCA9956B_EFLAG0, reg_value); + } + + mutex_unlock(&chip->lock); + + return strlen(buf); +} +static DEVICE_ATTR(err, 0664, + pca9956_showErr, NULL); + +static struct attribute *attrs[] = { + &dev_attr_err.attr, + &dev_attr_reg.attr, + NULL, /* Need to NULL terminate the list of attributes */ +}; + +static struct attribute_group attr_group = { + .attrs = attrs, +}; + +/* + * Individual PWM set function + */ +static void pca9956b_brightness_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct pca9956b_led *pca9956b; + struct pca9956b_chip *chip; + int ret; + + pca9956b = container_of(led_cdev, struct pca9956b_led, led_cdev); + chip = pca9956b->chip; + + mutex_lock(&chip->lock); + ret = pca9956b_write_reg(chip, + PCA9956B_PWM0 + pca9956b->led_num, + value); + if (ret != 0) + dev_err(&chip->client->dev, "[%s] is failed = %d.\n", + __func__, ret); + + mutex_unlock(&chip->lock); +} + +/* + * Individual PWM get function + */ +static enum led_brightness pca9956b_brightness_get( + struct led_classdev *led_cdev) +{ + struct pca9956b_led *pca9956b; + struct pca9956b_chip *chip; + int ret; + uint8_t reg_value; + + pca9956b = container_of(led_cdev, struct pca9956b_led, led_cdev); + chip = pca9956b->chip; + + mutex_lock(&chip->lock); + ret = pca9956b_read_reg(chip, PCA9956B_PWM0 + pca9956b->led_num, + ®_value); + if (ret != 0) + dev_err(&chip->client->dev, "[%s] is failed = %d.\n", + __func__, ret); + + mutex_unlock(&chip->lock); + + return reg_value; +} + +static int pca9956b_registerClassDevice(struct i2c_client *client, + struct pca9956b_chip *chip) +{ + int i = 0, err, reg; + struct device_node *np = client->dev.of_node, *child; + struct pca9956b_led *led; + + for_each_child_of_node(np, child) { + err = of_property_read_u32(child, "reg", ®); + if (err) { + of_node_put(child); + pr_err(DRIVER_NAME": Failed to get child node"); + return err; + } + if (reg < 0 || reg >= PCA9956B_LED_NUM) { + of_node_put(child); + pr_err(DRIVER_NAME": Invalid reg value"); + return -EINVAL; + } + + led = &chip->leds[reg]; + led->led_cdev.name = + of_get_property(child, "label", NULL) ? : child->name; + led->led_cdev.default_trigger = + of_get_property(child, "linux,default-trigger", NULL); + led->led_cdev.brightness_set = pca9956b_brightness_set; + led->led_cdev.brightness_get = pca9956b_brightness_get; + led->chip = chip; + led->led_num = reg; + i++; + + err = led_classdev_register(&client->dev, + &led->led_cdev); + if (err < 0) { + pr_err(DRIVER_NAME": Failed to register LED class dev"); + goto exit; + } + } + + return 0; +exit: + while (i--) + led_classdev_unregister(&chip->leds[i].led_cdev); + + return err; +} + +/* + * Read properties and write it to register. + */ +static int pca9956b_setup(struct pca9956b_chip *chip) +{ + struct device_node *np = chip->client->dev.of_node; + int ret; + uint32_t reg_value; + + ret = of_property_read_u32(np, "pca9956b,support_initialize", + ®_value); + if (ret < 0) { + pr_err("[%s]: Unable to pca9956b,support_initialize\n", + __func__); + return ret; + } + + if (reg_value == 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,mode1", + PCA9956B_MODE1); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,mode2", + PCA9956B_MODE2); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,ledout0", + PCA9956B_LEDOUT0); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,ledout1", + PCA9956B_LEDOUT1); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,ledout2", + PCA9956B_LEDOUT2); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,ledout3", + PCA9956B_LEDOUT3); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,ledout4", + PCA9956B_LEDOUT4); + if (ret < 0) + return ret; + + ret = pca9956b_readWrite_reg(chip, "pca9956b,ledout5", + PCA9956B_LEDOUT5); + if (ret < 0) + return ret; + + /* set default IREF to all IREF */ + { + int reg_addr; + + ret = of_property_read_u32(np, "pca9956b,defaultiref", + ®_value); + if (ret < 0) { + dev_err(&chip->client->dev, + "[%s]: Unable to read pca9956b,defaultiref\n", + __func__); + return ret; + } + mutex_lock(&chip->lock); + + for (reg_addr = PCA9956B_IREF0; + reg_addr <= PCA9956B_IREF23; reg_addr++) { + ret = pca9956b_write_reg(chip, reg_addr, + (uint8_t)reg_value); + if (ret < 0) { + dev_err(&chip->client->dev, + "[%s]: Unable to write reg0x%x[0x%x]\n", + __func__, reg_addr, reg_value); + mutex_unlock(&chip->lock); + return ret; + } + } + mutex_unlock(&chip->lock); + } + + /* set IREF0 ~ IREF23 if required */ + + return ret; +} + + +static int pca9956b_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pca9956b_chip *chip; + struct pca9956b_led *led; + int ret; + int i; + + pr_info(DRIVER_NAME": (I2C) "DRIVER_VERSION"\n"); + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "SMBUS Byte Data not Supported\n"); + return -EIO; + } + + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->leds = devm_kzalloc(&client->dev, sizeof(*led)*PCA9956B_LED_NUM, + GFP_KERNEL); + if (!chip->leds) { + devm_kfree(&client->dev, chip); + return -ENOMEM; + } + + i2c_set_clientdata(client, chip); + + mutex_init(&chip->lock); + chip->client = client; + + /* LED device class registration */ + ret = pca9956b_registerClassDevice(client, chip); + if (ret < 0) + goto exit; + + /* Configuration setup */ + ret = pca9956b_setup(chip); + if (ret < 0) + goto err_setup; + + pca9956b_dev = &client->dev; + + ret = sysfs_create_group(&pca9956b_dev->kobj, &attr_group); + if (ret) { + dev_err(&client->dev, + "Failed to create sysfs group for pca9956b\n"); + goto err_setup; + } + + return 0; + +err_setup: + for (i = 0; i < PCA9956B_LED_NUM; i++) + led_classdev_unregister(&chip->leds[i].led_cdev); +exit: + mutex_destroy(&chip->lock); + devm_kfree(&client->dev, chip->leds); + devm_kfree(&client->dev, chip); + return ret; +} + +static int pca9956b_remove(struct i2c_client *client) +{ + struct pca9956b_chip *dev = i2c_get_clientdata(client); + int i; + + for (i = 0; i < PCA9956B_LED_NUM; i++) + led_classdev_unregister(&dev->leds[i].led_cdev); + + sysfs_remove_group(&pca9956b_dev->kobj, &attr_group); + + mutex_destroy(&dev->lock); + devm_kfree(&client->dev, dev->leds); + devm_kfree(&client->dev, dev); + return 0; +} + +static const struct of_device_id pca9956b_dt_ids[] = { + { .compatible = "nxp,pca9956b",}, +}; + +static const struct i2c_device_id pca9956b_id[] = { + {DRIVER_NAME"-i2c", 0, }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pca9956b_id); + +static struct i2c_driver pca9956b_driver = { + .driver = { + .name = DRIVER_NAME"-i2c", + .of_match_table = of_match_ptr(pca9956b_dt_ids), + }, + .probe = pca9956b_probe, + .remove = pca9956b_remove, + .id_table = pca9956b_id, +}; + +static int __init pca9956b_init(void) +{ + return i2c_add_driver(&pca9956b_driver); +} + +static void __exit pca9956b_exit(void) +{ + i2c_del_driver(&pca9956b_driver); +} +module_init(pca9956b_init); +module_exit(pca9956b_exit); +MODULE_AUTHOR("NXP Semiconductors"); +MODULE_DESCRIPTION("PCA9956B : 24-channel constant current LED driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/leds/leds-pca9956b.h b/drivers/leds/leds-pca9956b.h new file mode 100644 index 000000000000..af50a134e5f7 --- /dev/null +++ b/drivers/leds/leds-pca9956b.h @@ -0,0 +1,111 @@ +/* + * leds-pca9956b.h - NXP PCA9956B LED segment driver + * + * Copyright (C) 2017 NXP Semiconductors + * + * 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. + */ + +#ifndef PCA9956B_H + +/* Register address */ +enum { + PCA9956B_MODE1 = 0x00, /* AIF, SLEEP, SUBn, ALLCALL */ + PCA9956B_MODE2, /* OVERTEMP, ERROR, DMBLNK, CLRERR, OCH */ + PCA9956B_LEDOUT0, /* LED driver output state */ + PCA9956B_LEDOUT1, + PCA9956B_LEDOUT2, + PCA9956B_LEDOUT3, + PCA9956B_LEDOUT4, + PCA9956B_LEDOUT5, + PCA9956B_GRPPWM, /* DMBLINK set 0, then GRPPWM controls */ + /* global brightness */ + PCA9956B_GRPFREQ, /* DMBLINK set 1, then GRPFREQ controls */ + /* global blinking period */ + + /* 10 : 0x0A */ + PCA9956B_PWM0, /* Brightness control */ + PCA9956B_PWM1, + PCA9956B_PWM2, + PCA9956B_PWM3, + PCA9956B_PWM4, + PCA9956B_PWM5, + PCA9956B_PWM6, + PCA9956B_PWM7, + PCA9956B_PWM8, + PCA9956B_PWM9, + + /* 20 : 0x14 */ + PCA9956B_PWM10, + PCA9956B_PWM11, + PCA9956B_PWM12, + PCA9956B_PWM13, + PCA9956B_PWM14, + PCA9956B_PWM15, + PCA9956B_PWM16, + PCA9956B_PWM17, + PCA9956B_PWM18, + PCA9956B_PWM19, + + /* 30 : 0x1E */ + PCA9956B_PWM20, + PCA9956B_PWM21, + PCA9956B_PWM22, + PCA9956B_PWM23, + PCA9956B_IREF0, /* Output current control */ + PCA9956B_IREF1, + PCA9956B_IREF2, + PCA9956B_IREF3, + PCA9956B_IREF4, + PCA9956B_IREF5, + + /* 40 : 0x28 */ + PCA9956B_IREF6, + PCA9956B_IREF7, + PCA9956B_IREF8, + PCA9956B_IREF9, + PCA9956B_IREF10, + PCA9956B_IREF11, + PCA9956B_IREF12, + PCA9956B_IREF13, + PCA9956B_IREF14, + PCA9956B_IREF15, + + /* 50 : 0x32 */ + PCA9956B_IREF16, + PCA9956B_IREF17, + PCA9956B_IREF18, + PCA9956B_IREF19, + PCA9956B_IREF20, + PCA9956B_IREF21, + PCA9956B_IREF22, + PCA9956B_IREF23, + PCA9956B_OFFSET, /* led turn-on delay */ + PCA9956B_SUBADR1, /* I2C bus subaddress */ + + /* 60 : 0x3C */ + PCA9956B_SUBADR2, + PCA9956B_SUBADR3, + PCA9956B_ALLCALLADR, /* Allows all the PCA9956Bs on the bus to be */ + /* programmed at the same time */ + PCA9956B_PWMALL, /* brightness control for all LEDn outputs */ + PCA9956B_IREFALL, /* output current value for all LED outputs */ + PCA9956B_EFLAG0, /* LED error detection */ + PCA9956B_EFLAG1, + PCA9956B_EFLAG2, + PCA9956B_EFLAG3, + PCA9956B_EFLAG4, + + /* 70 : 0x46 */ + PCA9956B_EFLAG5, +}; + +#endif /* PCA9956B_H */ -- GitLab From b4b5eda87f3bf33eef7a3fa5482f8494b49ce132 Mon Sep 17 00:00:00 2001 From: Prashanth Vadde Date: Wed, 8 Aug 2018 14:21:08 +0530 Subject: [PATCH 0699/1001] ARM: dts: msm: Support PCA9956B LED on QCS405 Add PCA9956B LED interface node support on QCS405 platform. Change-Id: I12503ed3c21549c6e569a4603371c08ce6ca911b Signed-off-by: Prashanth Vadde --- .../boot/dts/qcom/qcs405-led-pca9956.dtsi | 247 ++++++++++++++++++ arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi | 15 ++ arch/arm64/boot/dts/qcom/qcs405.dtsi | 26 ++ 3 files changed, 288 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/qcs405-led-pca9956.dtsi diff --git a/arch/arm64/boot/dts/qcom/qcs405-led-pca9956.dtsi b/arch/arm64/boot/dts/qcom/qcs405-led-pca9956.dtsi new file mode 100644 index 000000000000..332e805923a9 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs405-led-pca9956.dtsi @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&i2c_2 { + status = "ok"; + qcom,clk-freq-out = <100000>; + + /* PCA9956B LED Drivers */ + nxp-ledseg-i2c@65 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nxp,pca9956b"; + reg = <0x65>; + pca9956b,support_initialize = <1>; + pca9956b,mode1 = <0x09>; + pca9956b,mode2 = <0x05>; + + pca9956b,ledout0 = <0xAA>; + pca9956b,ledout1 = <0xAA>; + pca9956b,ledout2 = <0xAA>; + pca9956b,ledout3 = <0xFF>; + pca9956b,ledout4 = <0xFF>; + pca9956b,ledout5 = <0xFF>; + pca9956b,defaultiref = <0x2f>; + out0@0 { + label = "ledsec5_b"; + reg = <0x0>; + }; + out1@1 { + label = "ledsec5_g"; + reg = <0x1>; + }; + out2@2 { + label = "ledsec5_r"; + reg = <0x2>; + }; + out3@3 { + label = "ledsec6_b"; + reg = <0x3>; + }; + out4@4 { + label = "ledsec6_g"; + reg = <0x4>; + }; + out5@5 { + label = "ledsec6_r"; + reg = <0x5>; + }; + out6@6 { + label = "ledsec7_b"; + reg = <0x6>; + }; + out7@7 { + label = "ledsec7_g"; + reg = <0x7>; + }; + out8@8 { + label = "ledsec7_r"; + reg = <0x8>; + }; + out9@9 { + label = "ledsec8_b"; + reg = <0x9>; + }; + out10@10 { + label = "ledsec8_g"; + reg = <0xA>; + }; + out11@11 { + label = "ledsec8_r"; + reg = <0xB>; + }; + out12@12 { + label = "ledsec1_b"; + reg = <0xC>; + }; + out13@13 { + label = "ledsec1_g"; + reg = <0xD>; + }; + out14@14 { + label = "ledsec1_r"; + reg = <0xE>; + }; + out15@15 { + label = "ledsec2_b"; + reg = <0xF>; + }; + out16@16 { + label = "ledsec2_g"; + reg = <0x10>; + }; + out17@17 { + label = "ledsec2_r"; + reg = <0x11>; + }; + out18@18 { + label = "ledsec3_b"; + reg = <0x12>; + }; + out19@19 { + label = "ledsec3_g"; + reg = <0x13>; + }; + out20@20 { + label = "ledsec3_r"; + reg = <0x14>; + }; + out21@21 { + label = "ledsec4_b"; + reg = <0x15>; + }; + out22@22 { + label = "ledsec4_g"; + reg = <0x16>; + }; + out23@23 { + label = "ledsec4_r"; + reg = <0x17>; + }; + }; + + nxp-ledseg-i2c@69 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nxp,pca9956b"; + reg = <0x69>; + pca9956b,support_initialize = <1>; + pca9956b,mode1 = <0x09>; + pca9956b,mode2 = <0x05>; + + pca9956b,ledout0 = <0xAA>; + pca9956b,ledout1 = <0xAA>; + pca9956b,ledout2 = <0xAA>; + pca9956b,ledout3 = <0xFF>; + pca9956b,ledout4 = <0xFF>; + pca9956b,ledout5 = <0xFF>; + pca9956b,defaultiref = <0x2f>; + out0@0 { + label = "ledsec9_b"; + reg = <0x0>; + }; + out1@1 { + label = "ledsec9_g"; + reg = <0x1>; + }; + out2@2 { + label = "ledsec9_r"; + reg = <0x2>; + }; + out3@3 { + label = "ledsec10_b"; + reg = <0x3>; + }; + out4@4 { + label = "ledsec10_g"; + reg = <0x4>; + }; + out5@5 { + label = "ledsec10_r"; + reg = <0x5>; + }; + out6@6 { + label = "ledsec11_b"; + reg = <0x6>; + }; + out7@7 { + label = "ledsec11_g"; + reg = <0x7>; + }; + out8@8 { + label = "ledsec11_r"; + reg = <0x8>; + }; + out9@9 { + label = "ledsec12_b"; + reg = <0x9>; + }; + out10@10 { + label = "ledsec12_g"; + reg = <0xA>; + }; + out11@11 { + label = "ledsec12_r"; + reg = <0xB>; + }; + out12@12 { + label = "ledsec13_b"; + reg = <0xC>; + }; + out13@13 { + label = "ledsec13_g"; + reg = <0xD>; + }; + out14@14 { + label = "ledsec13_r"; + reg = <0xE>; + }; + out15@15 { + label = "ledsec14_b"; + reg = <0xF>; + }; + out16@16 { + label = "ledsec14_g"; + reg = <0x10>; + }; + out17@17 { + label = "ledsec14_r"; + reg = <0x11>; + }; + out18@18 { + label = "ledsec15_b"; + reg = <0x12>; + }; + out19@19 { + label = "ledsec15_g"; + reg = <0x13>; + }; + out20@20 { + label = "ledsec15_r"; + reg = <0x14>; + }; + out21@21 { + label = "ledsec16_b"; + reg = <0x15>; + }; + out22@22 { + label = "ledsec16_g"; + reg = <0x16>; + }; + out23@23 { + label = "ledsec16_r"; + reg = <0x17>; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi index 5cc5c5e532a2..cd961550d980 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi @@ -1160,6 +1160,21 @@ }; }; }; + + pca9956b_reset_gpio: pca9956b_reset_gpio { + mux { + pins = "gpio95"; + function = "gpio"; + }; + + config { + pins = "gpio95"; + drive-strength = <2>; + bias-pull-up; + output-high; + }; + }; + sec_mi2s_sck { sec_mi2s_sck_sleep: sec_mi2s_sck_sleep { mux { diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index 9d6a5a0fcfcb..0ff20e4b04f2 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -1441,3 +1441,29 @@ extcon = <&usb3_extcon>; }; +#include "qcs405-led-pca9956.dtsi" + +&soc { + i2c_2: i2c@78b6000 { /* BLSP1 QUP2 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x78b6000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 96 0>; + dmas = <&dma_blsp1 10 64 0x20000020 0x20>, + <&dma_blsp1 11 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP1_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_2_active &pca9956b_reset_gpio>; + pinctrl-1 = <&i2c_2_sleep>; + status = "ok"; + }; +}; -- GitLab From 745112d664bc2584f74f8bd2f61f708187f7bf8a Mon Sep 17 00:00:00 2001 From: Monika Singh Date: Wed, 27 Jun 2018 17:55:19 +0530 Subject: [PATCH 0700/1001] Migrate mpq demux and TSPP driver from kernel 4.9 to 4.14 This change migrates all the relevant files consisting of the mpq demux driver, its plugins, including the addition of TSPPv1 HW driver. The snapshot is taken as of msm-4.9, 'commit 7b86834562b1ef2b3b466 ("Migrate mpq demux driver from kernel 4.4 to 4.9")'. In addition, introduce a few code changes to fix warnings, typos and other style issues. Change-Id: I115c400d2ae46eb7221723af630d4747de3e482d Signed-off-by: Monika Singh --- .../bindings/platform/msm/msm_demux.txt | 13 + .../bindings/platform/msm/msm_tspp.txt | 83 + drivers/media/platform/msm/Kconfig | 2 + drivers/media/platform/msm/Makefile | 4 +- drivers/media/platform/msm/broadcast/Kconfig | 14 + drivers/media/platform/msm/broadcast/Makefile | 4 + drivers/media/platform/msm/broadcast/tspp.c | 3330 +++++++++++ drivers/media/platform/msm/dvb/Kconfig | 10 + drivers/media/platform/msm/dvb/Makefile | 2 + .../media/platform/msm/dvb/adapter/Makefile | 7 + .../platform/msm/dvb/adapter/mpq_adapter.c | 208 + .../msm/dvb/adapter/mpq_stream_buffer.c | 825 +++ drivers/media/platform/msm/dvb/demux/Kconfig | 38 + drivers/media/platform/msm/dvb/demux/Makefile | 14 + .../msm/dvb/demux/mpq_dmx_plugin_common.c | 5204 +++++++++++++++++ .../msm/dvb/demux/mpq_dmx_plugin_common.h | 1031 ++++ .../msm/dvb/demux/mpq_dmx_plugin_sw.c | 318 + .../msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c | 1994 +++++++ .../media/platform/msm/dvb/demux/mpq_sdmx.c | 1025 ++++ .../media/platform/msm/dvb/demux/mpq_sdmx.h | 377 ++ .../platform/msm/dvb/include/mpq_adapter.h | 222 + .../platform/msm/dvb/include/mpq_dvb_debug.h | 41 + .../msm/dvb/include/mpq_stream_buffer.h | 494 ++ include/linux/qcom_tspp.h | 124 + 24 files changed, 15383 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/platform/msm/msm_demux.txt create mode 100644 Documentation/devicetree/bindings/platform/msm/msm_tspp.txt create mode 100644 drivers/media/platform/msm/broadcast/Kconfig create mode 100644 drivers/media/platform/msm/broadcast/Makefile create mode 100644 drivers/media/platform/msm/broadcast/tspp.c create mode 100644 drivers/media/platform/msm/dvb/Kconfig create mode 100644 drivers/media/platform/msm/dvb/Makefile create mode 100644 drivers/media/platform/msm/dvb/adapter/Makefile create mode 100644 drivers/media/platform/msm/dvb/adapter/mpq_adapter.c create mode 100644 drivers/media/platform/msm/dvb/adapter/mpq_stream_buffer.c create mode 100644 drivers/media/platform/msm/dvb/demux/Kconfig create mode 100644 drivers/media/platform/msm/dvb/demux/Makefile create mode 100644 drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c create mode 100644 drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h create mode 100644 drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_sw.c create mode 100644 drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c create mode 100644 drivers/media/platform/msm/dvb/demux/mpq_sdmx.c create mode 100644 drivers/media/platform/msm/dvb/demux/mpq_sdmx.h create mode 100644 drivers/media/platform/msm/dvb/include/mpq_adapter.h create mode 100644 drivers/media/platform/msm/dvb/include/mpq_dvb_debug.h create mode 100644 drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h create mode 100644 include/linux/qcom_tspp.h diff --git a/Documentation/devicetree/bindings/platform/msm/msm_demux.txt b/Documentation/devicetree/bindings/platform/msm/msm_demux.txt new file mode 100644 index 000000000000..c192a43d58f9 --- /dev/null +++ b/Documentation/devicetree/bindings/platform/msm/msm_demux.txt @@ -0,0 +1,13 @@ +* Demux + +Demux is responsible for demuxing the transport stream contents +to respective elementary streams + +Required properties: +- compatible : Should be "qcom,demux" + +Example: + + demux { + compatible = "qcom,demux"; + }; diff --git a/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt b/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt new file mode 100644 index 000000000000..70377b4a9551 --- /dev/null +++ b/Documentation/devicetree/bindings/platform/msm/msm_tspp.txt @@ -0,0 +1,83 @@ +* TSPP ( QTI Transport Stream Packet Processor ) + +Hardware driver for QTI TSIF 12seg wrapper core, which consists of a TSPP, a +BAM (Bus access manager, used for DMA) and two TSIF inputs. + +The TSPP driver is responsible for: + - TSPP/TSIF hardware configuration (using SPS driver to configure BAM hardware) + - TSIF GPIO/Clocks configuration + - Memory resource management + - Handling TSIF/TSPP interrupts and BAM events + - TSPP Power management + +Required properties: +- compatible : Should be "qcom,msm_tspp" +- reg : Specifies the base physical addresses and sizes of TSIF, TSPP & BAM registers. +- reg-names : Specifies the register names of TSIF, TSPP & BAM base registers. +- interrupts : Specifies the interrupts associated with TSIF 12 seg core. +- interrupt-names: Specifies interrupt names for TSIF, TSPP & BAM interrupts. +- clock-names: Specifies the clock names used for interface & reference clocks. +- clocks: GCC_TSIF_AHB_CLK clock for interface clock & GCC_TSIF_REF_CLK clock for reference clock. +- qcom, msm_bus,name: Should be "tsif" +- qcom, msm_bus,num_cases: Depends on the use cases for bus scaling +- qcom, msm_bus,num_paths: The paths for source and destination ports +- qcom, msm_bus,vectors: Vectors for bus topology. +- pinctrl-names: Names for the TSIF mode configuration to specify which TSIF interface is active. +- qcom,smmu-s1-bypass : Boolean flag to bypass SMMU stage 1 translation. +- iommus : A list of phandle and IOMMU specifier pairs that describe the IOMMU master interfaces of the device. + +Example: + + tspp: msm_tspp@0x8880000 { + compatible = "qcom,msm_tspp"; + reg = <0x088a7000 0x200>, /* MSM_TSIF0_PHYS */ + <0x088a8000 0x200>, /* MSM_TSIF1_PHYS */ + <0x088a9000 0x1000>, /* MSM_TSPP_PHYS */ + <0x08884000 0x23000>; /* MSM_TSPP_BAM_PHYS */ + reg-names = "MSM_TSIF0_PHYS", + "MSM_TSIF1_PHYS", + "MSM_TSPP_PHYS", + "MSM_TSPP_BAM_PHYS"; + interrupts = <0 121 0>, /* TSIF_TSPP_IRQ */ + <0 119 0>, /* TSIF0_IRQ */ + <0 120 0>, /* TSIF1_IRQ */ + <0 122 0>; /* TSIF_BAM_IRQ */ + interrupt-names = "TSIF_TSPP_IRQ", + "TSIF0_IRQ", + "TSIF1_IRQ", + "TSIF_BAM_IRQ"; + + clock-names = "iface_clk", "ref_clk"; + clocks = <&clock_gcc GCC_TSIF_AHB_CLK>, + <&clock_gcc GCC_TSIF_REF_CLK>; + + qcom,msm-bus,name = "tsif"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <82 512 0 0>, /* No vote */ + <82 512 12288 24576>; + /* Max. bandwidth, 2xTSIF, each max of 96Mbps */ + + pinctrl-names = "disabled", + "tsif0-mode1", "tsif0-mode2", + "tsif1-mode1", "tsif1-mode2", + "dual-tsif-mode1", "dual-tsif-mode2"; + + pinctrl-0 = <>; /* disabled */ + pinctrl-1 = <&tsif0_signals_active>; /* tsif0-mode1 */ + pinctrl-2 = <&tsif0_signals_active + &tsif0_sync_active>; /* tsif0-mode2 */ + pinctrl-3 = <&tsif1_signals_active>; /* tsif1-mode1 */ + pinctrl-4 = <&tsif1_signals_active + &tsif1_sync_active>; /* tsif1-mode2 */ + pinctrl-5 = <&tsif0_signals_active + &tsif1_signals_active>; /* dual-tsif-mode1 */ + pinctrl-6 = <&tsif0_signals_active + &tsif0_sync_active + &tsif1_signals_active + &tsif1_sync_active>; /* dual-tsif-mode2 */ + + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x20 0x0f>; + }; diff --git a/drivers/media/platform/msm/Kconfig b/drivers/media/platform/msm/Kconfig index 0d7769455311..9c43ecb5ac31 100644 --- a/drivers/media/platform/msm/Kconfig +++ b/drivers/media/platform/msm/Kconfig @@ -16,3 +16,5 @@ menuconfig SPECTRA_CAMERA source "drivers/media/platform/msm/vidc/Kconfig" source "drivers/media/platform/msm/sde/Kconfig" source "drivers/media/platform/msm/npu/Kconfig" +source "drivers/media/platform/msm/dvb/Kconfig" +source "drivers/media/platform/msm/broadcast/Kconfig" diff --git a/drivers/media/platform/msm/Makefile b/drivers/media/platform/msm/Makefile index 1a3763dc0ec6..18ea8e6d97c9 100644 --- a/drivers/media/platform/msm/Makefile +++ b/drivers/media/platform/msm/Makefile @@ -5,4 +5,6 @@ obj-y += sde/ obj-$(CONFIG_MSM_NPU) += npu/ obj-$(CONFIG_MSM_VIDC_V4L2) += vidc/ -obj-$(CONFIG_SPECTRA_CAMERA) += camera/ \ No newline at end of file +obj-$(CONFIG_SPECTRA_CAMERA) += camera/ +obj-$(CONFIG_TSPP) += broadcast/ +obj-$(CONFIG_DVB_MPQ) += dvb/ diff --git a/drivers/media/platform/msm/broadcast/Kconfig b/drivers/media/platform/msm/broadcast/Kconfig new file mode 100644 index 000000000000..cdd1b2091179 --- /dev/null +++ b/drivers/media/platform/msm/broadcast/Kconfig @@ -0,0 +1,14 @@ +# +# MSM Broadcast subsystem drivers +# + +config TSPP + depends on ARCH_QCOM + tristate "TSPP (Transport Stream Packet Processor) Support" + ---help--- + Transport Stream Packet Processor v1 is used to offload the + processing of MPEG transport streams from the main processor. + It is used to process incoming transport streams from TSIF + to supports use-cases such as transport stream live play + and recording. + This can also be compiled as a loadable module. diff --git a/drivers/media/platform/msm/broadcast/Makefile b/drivers/media/platform/msm/broadcast/Makefile new file mode 100644 index 000000000000..3735bdc212ad --- /dev/null +++ b/drivers/media/platform/msm/broadcast/Makefile @@ -0,0 +1,4 @@ +# +# Makefile for MSM Broadcast subsystem drivers. +# +obj-$(CONFIG_TSPP) += tspp.o diff --git a/drivers/media/platform/msm/broadcast/tspp.c b/drivers/media/platform/msm/broadcast/tspp.c new file mode 100644 index 000000000000..9a701ccf1912 --- /dev/null +++ b/drivers/media/platform/msm/broadcast/tspp.c @@ -0,0 +1,3330 @@ +/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include /* Just for modules */ +#include /* Only for KERN_INFO */ +#include /* Error macros */ +#include /* Linked list */ +#include +#include /* Needed for the macros */ +#include /* IO macros */ +#include /* Device drivers need this */ +#include /* Externally defined globals */ +#include /* Runtime power management */ +#include +#include /* copy_to_user */ +#include /* kfree, kzalloc */ +#include /* XXX_ mem_region */ +#include +#include /* dma_XXX */ +#include /* DMA pools */ +#include /* msleep */ +#include +#include +#include /* poll() file op */ +#include /* wait() macros, sleeping */ +#include /* BIT() macro */ +#include +#include +#include /* BAM stuff */ +#include /* Timer services */ +#include /* Jiffies counter */ +#include +#include +#include +#include +#include +#include +#include /* tasklet */ +#include /* Timer */ +#include + +/* + * General defines + */ +#define TSPP_TSIF_INSTANCES 2 +#define TSPP_GPIOS_PER_TSIF 4 +#define TSPP_FILTER_TABLES 3 +#define TSPP_MAX_DEVICES 1 +#define TSPP_NUM_CHANNELS 16 +#define TSPP_NUM_PRIORITIES 16 +#define TSPP_NUM_KEYS 8 +#define INVALID_CHANNEL 0xFFFFFFFF +#define TSPP_BAM_DEFAULT_IPC_LOGLVL 2 + +#define TSPP_SMMU_IOVA_START (0x10000000) +#define TSPP_SMMU_IOVA_SIZE (0x40000000) + +/* + * BAM descriptor FIFO size (in number of descriptors). + * Max number of descriptors allowed by SPS which is 8K-1. + */ +#define TSPP_SPS_DESCRIPTOR_COUNT (8 * 1024 - 1) +#define TSPP_PACKET_LENGTH 188 +#define TSPP_MIN_BUFFER_SIZE (TSPP_PACKET_LENGTH) + +/* Max descriptor buffer size allowed by SPS */ +#define TSPP_MAX_BUFFER_SIZE (32 * 1024 - 1) + +/* + * Returns whether to use DMA pool for TSPP output buffers. + * For buffers smaller than page size, using DMA pool + * provides better memory utilization as dma_alloc_coherent + * allocates minimum of page size. + */ +#define TSPP_USE_DMA_POOL(buff_size) ((buff_size) < PAGE_SIZE) + +/* + * Max allowed TSPP buffers/descriptors. + * If SPS desc FIFO holds X descriptors, we can queue up to X-1 descriptors. + */ +#define TSPP_NUM_BUFFERS (TSPP_SPS_DESCRIPTOR_COUNT - 1) +#define TSPP_TSIF_DEFAULT_TIME_LIMIT 60 +#define SPS_DESCRIPTOR_SIZE 8 +#define MIN_ACCEPTABLE_BUFFER_COUNT 2 +#define TSPP_DEBUG(msg...) + +/* + * TSIF register offsets + */ +#define TSIF_STS_CTL_OFF (0x0) +#define TSIF_TIME_LIMIT_OFF (0x4) +#define TSIF_CLK_REF_OFF (0x8) +#define TSIF_LPBK_FLAGS_OFF (0xc) +#define TSIF_LPBK_DATA_OFF (0x10) +#define TSIF_TEST_CTL_OFF (0x14) +#define TSIF_TEST_MODE_OFF (0x18) +#define TSIF_TEST_RESET_OFF (0x1c) +#define TSIF_TEST_EXPORT_OFF (0x20) +#define TSIF_TEST_CURRENT_OFF (0x24) +#define TSIF_TTS_CTL_OFF (0x38) + +#define TSIF_DATA_PORT_OFF (0x100) + +/* bits for TSIF_STS_CTL register */ +#define TSIF_STS_CTL_EN_IRQ BIT(28) +#define TSIF_STS_CTL_PACK_AVAIL BIT(27) +#define TSIF_STS_CTL_1ST_PACKET BIT(26) +#define TSIF_STS_CTL_OVERFLOW BIT(25) +#define TSIF_STS_CTL_LOST_SYNC BIT(24) +#define TSIF_STS_CTL_TIMEOUT BIT(23) +#define TSIF_STS_CTL_INV_SYNC BIT(21) +#define TSIF_STS_CTL_INV_NULL BIT(20) +#define TSIF_STS_CTL_INV_ERROR BIT(19) +#define TSIF_STS_CTL_INV_ENABLE BIT(18) +#define TSIF_STS_CTL_INV_DATA BIT(17) +#define TSIF_STS_CTL_INV_CLOCK BIT(16) +#define TSIF_STS_CTL_SPARE BIT(15) +#define TSIF_STS_CTL_EN_NULL BIT(11) +#define TSIF_STS_CTL_EN_ERROR BIT(10) +#define TSIF_STS_CTL_LAST_BIT BIT(9) +#define TSIF_STS_CTL_EN_TIME_LIM BIT(8) +#define TSIF_STS_CTL_EN_TCR BIT(7) +#define TSIF_STS_CTL_TEST_MODE BIT(6) +#define TSIF_STS_CTL_MODE_2 BIT(5) +#define TSIF_STS_CTL_EN_DM BIT(4) +#define TSIF_STS_CTL_STOP BIT(3) +#define TSIF_STS_CTL_START BIT(0) + +/* bits for TSIF_TTS_CTRL register */ +#define TSIF_TTS_CTL_TTS_ENDIANNESS BIT(4) +#define TSIF_TTS_CTL_TTS_SOURCE BIT(3) +#define TSIF_TTS_CTL_TTS_LENGTH_1 BIT(1) +#define TSIF_TTS_CTL_TTS_LENGTH_0 BIT(0) + +/* + * TSPP register offsets + */ +#define TSPP_RST 0x00 +#define TSPP_CLK_CONTROL 0x04 +#define TSPP_CONFIG 0x08 +#define TSPP_CONTROL 0x0C +#define TSPP_PS_DISABLE 0x10 +#define TSPP_MSG_IRQ_STATUS 0x14 +#define TSPP_MSG_IRQ_MASK 0x18 +#define TSPP_IRQ_STATUS 0x1C +#define TSPP_IRQ_MASK 0x20 +#define TSPP_IRQ_CLEAR 0x24 +#define TSPP_PIPE_ERROR_STATUS(_n) (0x28 + (_n << 2)) +#define TSPP_STATUS 0x68 +#define TSPP_CURR_TSP_HEADER 0x6C +#define TSPP_CURR_PID_FILTER 0x70 +#define TSPP_SYSTEM_KEY(_n) (0x74 + (_n << 2)) +#define TSPP_CBC_INIT_VAL(_n) (0x94 + (_n << 2)) +#define TSPP_DATA_KEY_RESET 0x9C +#define TSPP_KEY_VALID 0xA0 +#define TSPP_KEY_ERROR 0xA4 +#define TSPP_TEST_CTRL 0xA8 +#define TSPP_VERSION 0xAC +#define TSPP_GENERICS 0xB0 +#define TSPP_NOP 0xB4 + +/* + * Register bit definitions + */ +/* TSPP_RST */ +#define TSPP_RST_RESET BIT(0) + +/* TSPP_CLK_CONTROL */ +#define TSPP_CLK_CONTROL_FORCE_CRYPTO BIT(9) +#define TSPP_CLK_CONTROL_FORCE_PES_PL BIT(8) +#define TSPP_CLK_CONTROL_FORCE_PES_AF BIT(7) +#define TSPP_CLK_CONTROL_FORCE_RAW_CTRL BIT(6) +#define TSPP_CLK_CONTROL_FORCE_PERF_CNT BIT(5) +#define TSPP_CLK_CONTROL_FORCE_CTX_SEARCH BIT(4) +#define TSPP_CLK_CONTROL_FORCE_TSP_PROC BIT(3) +#define TSPP_CLK_CONTROL_FORCE_CONS_AHB2MEM BIT(2) +#define TSPP_CLK_CONTROL_FORCE_TS_AHB2MEM BIT(1) +#define TSPP_CLK_CONTROL_SET_CLKON BIT(0) + +/* TSPP_CONFIG */ +#define TSPP_CONFIG_SET_PACKET_LENGTH(_a, _b) (_a = (_a & 0xF0) | \ +((_b & 0xF) << 8)) +#define TSPP_CONFIG_GET_PACKET_LENGTH(_a) ((_a >> 8) & 0xF) +#define TSPP_CONFIG_DUP_WITH_DISC_EN BIT(7) +#define TSPP_CONFIG_PES_SYNC_ERROR_MASK BIT(6) +#define TSPP_CONFIG_PS_LEN_ERR_MASK BIT(5) +#define TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK BIT(4) +#define TSPP_CONFIG_PS_CONT_ERR_MASK BIT(3) +#define TSPP_CONFIG_PS_DUP_TSP_MASK BIT(2) +#define TSPP_CONFIG_TSP_ERR_IND_MASK BIT(1) +#define TSPP_CONFIG_TSP_SYNC_ERR_MASK BIT(0) + +/* TSPP_CONTROL */ +#define TSPP_CONTROL_PID_FILTER_LOCK BIT(5) +#define TSPP_CONTROL_FORCE_KEY_CALC BIT(4) +#define TSPP_CONTROL_TSP_CONS_SRC_DIS BIT(3) +#define TSPP_CONTROL_TSP_TSIF1_SRC_DIS BIT(2) +#define TSPP_CONTROL_TSP_TSIF0_SRC_DIS BIT(1) +#define TSPP_CONTROL_PERF_COUNT_INIT BIT(0) + +/* TSPP_MSG_IRQ_STATUS + TSPP_MSG_IRQ_MASK */ +#define TSPP_MSG_TSPP_IRQ BIT(2) +#define TSPP_MSG_TSIF_1_IRQ BIT(1) +#define TSPP_MSG_TSIF_0_IRQ BIT(0) + +/* TSPP_IRQ_STATUS + TSPP_IRQ_MASK + TSPP_IRQ_CLEAR */ +#define TSPP_IRQ_STATUS_TSP_RD_CMPL BIT(19) +#define TSPP_IRQ_STATUS_KEY_ERROR BIT(18) +#define TSPP_IRQ_STATUS_KEY_SWITCHED_BAD BIT(17) +#define TSPP_IRQ_STATUS_KEY_SWITCHED BIT(16) +#define TSPP_IRQ_STATUS_PS_BROKEN(_n) BIT((_n)) + +/* TSPP_PIPE_ERROR_STATUS */ +#define TSPP_PIPE_PES_SYNC_ERROR BIT(3) +#define TSPP_PIPE_PS_LENGTH_ERROR BIT(2) +#define TSPP_PIPE_PS_CONTINUITY_ERROR BIT(1) +#define TSPP_PIP_PS_LOST_START BIT(0) + +/* TSPP_STATUS */ +#define TSPP_STATUS_TSP_PKT_AVAIL BIT(10) +#define TSPP_STATUS_TSIF1_DM_REQ BIT(6) +#define TSPP_STATUS_TSIF0_DM_REQ BIT(2) +#define TSPP_CURR_FILTER_TABLE BIT(0) + +/* TSPP_GENERICS */ +#define TSPP_GENERICS_CRYPTO_GEN BIT(12) +#define TSPP_GENERICS_MAX_CONS_PIPES BIT(7) +#define TSPP_GENERICS_MAX_PIPES BIT(2) +#define TSPP_GENERICS_TSIF_1_GEN BIT(1) +#define TSPP_GENERICS_TSIF_0_GEN BIT(0) + +/* + * TSPP memory regions + */ +#define TSPP_PID_FILTER_TABLE0 0x800 +#define TSPP_PID_FILTER_TABLE1 0x880 +#define TSPP_PID_FILTER_TABLE2 0x900 +#define TSPP_GLOBAL_PERFORMANCE 0x980 /* see tspp_global_performance */ +#define TSPP_PIPE_CONTEXT 0x990 /* see tspp_pipe_context */ +#define TSPP_PIPE_PERFORMANCE 0x998 /* see tspp_pipe_performance */ +#define TSPP_TSP_BUFF_WORD(_n) (0xC10 + (_n << 2)) +#define TSPP_DATA_KEY 0xCD0 + +struct debugfs_entry { + const char *name; + mode_t mode; + int offset; +}; + +static const struct debugfs_entry debugfs_tsif_regs[] = { + {"sts_ctl", 0644, TSIF_STS_CTL_OFF}, + {"time_limit", 0644, TSIF_TIME_LIMIT_OFF}, + {"clk_ref", 0644, TSIF_CLK_REF_OFF}, + {"lpbk_flags", 0644, TSIF_LPBK_FLAGS_OFF}, + {"lpbk_data", 0644, TSIF_LPBK_DATA_OFF}, + {"test_ctl", 0644, TSIF_TEST_CTL_OFF}, + {"test_mode", 0644, TSIF_TEST_MODE_OFF}, + {"test_reset", 0200, TSIF_TEST_RESET_OFF}, + {"test_export", 0644, TSIF_TEST_EXPORT_OFF}, + {"test_current", 0444, TSIF_TEST_CURRENT_OFF}, + {"data_port", 0400, TSIF_DATA_PORT_OFF}, + {"tts_source", 0600, TSIF_TTS_CTL_OFF}, +}; + +static const struct debugfs_entry debugfs_tspp_regs[] = { + {"rst", 0644, TSPP_RST}, + {"clk_control", 0644, TSPP_CLK_CONTROL}, + {"config", 0644, TSPP_CONFIG}, + {"control", 0644, TSPP_CONTROL}, + {"ps_disable", 0644, TSPP_PS_DISABLE}, + {"msg_irq_status", 0644, TSPP_MSG_IRQ_STATUS}, + {"msg_irq_mask", 0644, TSPP_MSG_IRQ_MASK}, + {"irq_status", 0644, TSPP_IRQ_STATUS}, + {"irq_mask", 0644, TSPP_IRQ_MASK}, + {"irq_clear", 0644, TSPP_IRQ_CLEAR}, + {"status", 0644, TSPP_STATUS}, + {"curr_tsp_header", 0644, TSPP_CURR_TSP_HEADER}, + {"curr_pid_filter", 0644, TSPP_CURR_PID_FILTER}, + {"data_key_reset", 0644, TSPP_DATA_KEY_RESET}, + {"key_valid", 0644, TSPP_KEY_VALID}, + {"key_error", 0644, TSPP_KEY_ERROR}, + {"test_ctrl", 0644, TSPP_TEST_CTRL}, + {"version", 0644, TSPP_VERSION}, + {"generics", 0644, TSPP_GENERICS}, + {"pid_filter_table0", 0644, TSPP_PID_FILTER_TABLE0}, + {"pid_filter_table1", 0644, TSPP_PID_FILTER_TABLE1}, + {"pid_filter_table2", 0644, TSPP_PID_FILTER_TABLE2}, + {"tsp_total_num", 0644, TSPP_GLOBAL_PERFORMANCE}, + {"tsp_ignored_num", 0644, TSPP_GLOBAL_PERFORMANCE + 4}, + {"tsp_err_ind_num", 0644, TSPP_GLOBAL_PERFORMANCE + 8}, + {"tsp_sync_err_num", 0644, TSPP_GLOBAL_PERFORMANCE + 16}, + {"pipe_context", 0644, TSPP_PIPE_CONTEXT}, + {"pipe_performance", 0644, TSPP_PIPE_PERFORMANCE}, + {"data_key", 0644, TSPP_DATA_KEY} +}; + +struct tspp_pid_filter { + u32 filter; /* see FILTER_ macros */ + u32 config; /* see FILTER_ macros */ +}; + +/* tsp_info */ +#define FILTER_HEADER_ERROR_MASK BIT(7) +#define FILTER_TRANS_END_DISABLE BIT(6) +#define FILTER_DEC_ON_ERROR_EN BIT(5) +#define FILTER_DECRYPT BIT(4) +#define FILTER_HAS_ENCRYPTION(_p) (_p->config & FILTER_DECRYPT) +#define FILTER_GET_PIPE_NUMBER0(_p) (_p->config & 0xF) +#define FILTER_SET_PIPE_NUMBER0(_p, _b) (_p->config = \ + (_p->config & ~0xF) | (_b & 0xF)) +#define FILTER_GET_PIPE_PROCESS0(_p) ((_p->filter >> 30) & 0x3) +#define FILTER_SET_PIPE_PROCESS0(_p, _b) (_p->filter = \ + (_p->filter & ~(0x3<<30)) | ((_b & 0x3) << 30)) +#define FILTER_GET_PIPE_PID(_p) ((_p->filter >> 13) & 0x1FFF) +#define FILTER_SET_PIPE_PID(_p, _b) (_p->filter = \ + (_p->filter & ~(0x1FFF<<13)) | ((_b & 0x1FFF) << 13)) +#define FILTER_GET_PID_MASK(_p) (_p->filter & 0x1FFF) +#define FILTER_SET_PID_MASK(_p, _b) (_p->filter = \ + (_p->filter & ~0x1FFF) | (_b & 0x1FFF)) +#define FILTER_GET_PIPE_PROCESS1(_p) ((_p->config >> 30) & 0x3) +#define FILTER_SET_PIPE_PROCESS1(_p, _b) (_p->config = \ + (_p->config & ~(0x3<<30)) | ((_b & 0x3) << 30)) +#define FILTER_GET_KEY_NUMBER(_p) ((_p->config >> 8) & 0x7) +#define FILTER_SET_KEY_NUMBER(_p, _b) (_p->config = \ + (_p->config & ~(0x7<<8)) | ((_b & 0x7) << 8)) + +struct tspp_global_performance_regs { + u32 tsp_total; + u32 tsp_ignored; + u32 tsp_error; + u32 tsp_sync; +}; + +struct tspp_pipe_context_regs { + u16 pes_bytes_left; + u16 count; + u32 tsif_suffix; +} __packed; +#define CONTEXT_GET_STATE(_a) (_a & 0x3) +#define CONTEXT_UNSPEC_LENGTH BIT(11) +#define CONTEXT_GET_CONT_COUNT(_a) ((_a >> 12) & 0xF) + +struct tspp_pipe_performance_regs { + u32 tsp_total; + u32 ps_duplicate_tsp; + u32 tsp_no_payload; + u32 tsp_broken_ps; + u32 ps_total_num; + u32 ps_continuity_error; + u32 ps_length_error; + u32 pes_sync_error; +}; + +struct tspp_tsif_device { + void __iomem *base; + u32 time_limit; + u32 ref_count; + enum tspp_tsif_mode mode; + int clock_inverse; + int data_inverse; + int sync_inverse; + int enable_inverse; + u32 tsif_irq; + + /* debugfs */ + struct dentry *dent_tsif; + struct dentry *debugfs_tsif_regs[ARRAY_SIZE(debugfs_tsif_regs)]; + u32 stat_rx; + u32 stat_overflow; + u32 stat_lost_sync; + u32 stat_timeout; + enum tsif_tts_source tts_source; + u32 lpass_timer_enable; +}; + +enum tspp_buf_state { + TSPP_BUF_STATE_EMPTY, /* buffer has been allocated, but not waiting */ + TSPP_BUF_STATE_WAITING, /* buffer is waiting to be filled */ + TSPP_BUF_STATE_DATA, /* buffer is not empty and can be read */ + TSPP_BUF_STATE_LOCKED /* buffer is being read by a client */ +}; + +struct tspp_mem_buffer { + struct tspp_mem_buffer *next; + struct sps_mem_buffer sps; + struct tspp_data_descriptor desc; /* buffer descriptor for kernel api */ + enum tspp_buf_state state; + size_t filled; /* how much data this buffer is holding */ + int read_index; /* where to start reading data from */ +}; + +/* this represents each char device 'channel' */ +struct tspp_channel { + struct tspp_device *pdev; /* can use container_of instead? */ + struct sps_pipe *pipe; + struct sps_connect config; + struct sps_register_event event; + struct tspp_mem_buffer *data; /* list of buffers */ + struct tspp_mem_buffer *read; /* first buffer ready to be read */ + struct tspp_mem_buffer *waiting; /* first outstanding transfer */ + struct tspp_mem_buffer *locked; /* buffer currently being read */ + wait_queue_head_t in_queue; /* set when data is received */ + u32 id; /* channel id (0-15) */ + int used; /* is this channel in use? */ + int key; /* which encryption key index is used */ + u32 buffer_size; /* size of the sps transfer buffers */ + u32 max_buffers; /* how many buffers should be allocated */ + u32 buffer_count; /* how many buffers are actually allocated */ + u32 filter_count; /* how many filters have been added to this channel */ + u32 int_freq; /* generate interrupts every x descriptors */ + enum tspp_source src; + enum tspp_mode mode; + tspp_notifier *notifier; /* used only with kernel api */ + void *notify_data; /* data to be passed with the notifier */ + u32 expiration_period_ms; /* notification on partially filled buffers */ + struct timer_list expiration_timer; + struct dma_pool *dma_pool; + tspp_memfree *memfree; /* user defined memory free function */ + void *user_info; /* user cookie passed to memory alloc/free function */ +}; + +struct tspp_pid_filter_table { + struct tspp_pid_filter filter[TSPP_NUM_PRIORITIES]; +}; + +struct tspp_key_entry { + u32 even_lsb; + u32 even_msb; + u32 odd_lsb; + u32 odd_msb; +}; + +struct tspp_key_table { + struct tspp_key_entry entry[TSPP_NUM_KEYS]; +}; + +struct tspp_pinctrl { + struct pinctrl *pinctrl; + + struct pinctrl_state *disabled; + struct pinctrl_state *tsif0_mode1; + struct pinctrl_state *tsif0_mode2; + struct pinctrl_state *tsif1_mode1; + struct pinctrl_state *tsif1_mode2; + struct pinctrl_state *dual_mode1; + struct pinctrl_state *dual_mode2; + + bool tsif0_active; + bool tsif1_active; +}; + +/* this represents the actual hardware device */ +struct tspp_device { + struct list_head devlist; /* list of all devices */ + struct platform_device *pdev; + void __iomem *base; + uint32_t tsif_bus_client; + unsigned int tspp_irq; + unsigned int bam_irq; + unsigned long bam_handle; + struct sps_bam_props bam_props; + struct wakeup_source ws; + spinlock_t spinlock; + struct tasklet_struct tlet; + struct tspp_tsif_device tsif[TSPP_TSIF_INSTANCES]; + /* clocks */ + struct clk *tsif_pclk; + struct clk *tsif_ref_clk; + /* regulators */ + struct regulator *tsif_vreg; + /* data */ + struct tspp_pid_filter_table *filters[TSPP_FILTER_TABLES]; + struct tspp_channel channels[TSPP_NUM_CHANNELS]; + struct tspp_key_table *tspp_key_table; + struct tspp_global_performance_regs *tspp_global_performance; + struct tspp_pipe_context_regs *tspp_pipe_context; + struct tspp_pipe_performance_regs *tspp_pipe_performance; + bool req_irqs; + /* pinctrl */ + struct mutex mutex; + struct tspp_pinctrl pinctrl; + unsigned int tts_source; /* Time stamp source type LPASS timer/TCR */ + struct dma_iommu_mapping *iommu_mapping; + + struct dentry *dent; + struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)]; +}; + +static int tspp_key_entry; +static u32 channel_id; /* next channel id number to assign */ + +static LIST_HEAD(tspp_devices); + +/*** IRQ ***/ +static irqreturn_t tspp_isr(int irq, void *dev) +{ + struct tspp_device *device = dev; + u32 status, mask; + u32 data; + + status = readl_relaxed(device->base + TSPP_IRQ_STATUS); + mask = readl_relaxed(device->base + TSPP_IRQ_MASK); + status &= mask; + + if (!status) { + pr_warn("%s: spurious interrupt\n", __func__); + return IRQ_NONE; + } + + if (status & TSPP_IRQ_STATUS_KEY_ERROR) { + /* read the key error info */ + data = readl_relaxed(device->base + TSPP_KEY_ERROR); + pr_err("%s: key error 0x%x\n", __func__, data); + } + if (status & TSPP_IRQ_STATUS_KEY_SWITCHED_BAD) { + data = readl_relaxed(device->base + TSPP_KEY_VALID); + pr_err("%s: key invalidated: 0x%x\n", __func__, data); + } + if (status & TSPP_IRQ_STATUS_KEY_SWITCHED) + pr_debug("%s: key switched\n", __func__); + + if (status & 0xffff) + pr_debug("%s: broken pipe %d\n", __func__, status & 0xffff); + + writel_relaxed(status, device->base + TSPP_IRQ_CLEAR); + + /* + * Before returning IRQ_HANDLED to the generic interrupt handling + * framework need to make sure all operations including clearing of + * interrupt status registers in the hardware is performed. + * Thus a barrier after clearing the interrupt status register + * is required to guarantee that the interrupt status register has + * really been cleared by the time we return from this handler. + */ + wmb(); + return IRQ_HANDLED; +} + +static irqreturn_t tsif_isr(int irq, void *dev) +{ + struct tspp_tsif_device *tsif_device = dev; + u32 sts_ctl = ioread32(tsif_device->base + TSIF_STS_CTL_OFF); + + if (!(sts_ctl & (TSIF_STS_CTL_PACK_AVAIL | + TSIF_STS_CTL_OVERFLOW | + TSIF_STS_CTL_LOST_SYNC | + TSIF_STS_CTL_TIMEOUT))) + return IRQ_NONE; + + if (sts_ctl & TSIF_STS_CTL_OVERFLOW) + tsif_device->stat_overflow++; + + if (sts_ctl & TSIF_STS_CTL_LOST_SYNC) + tsif_device->stat_lost_sync++; + + if (sts_ctl & TSIF_STS_CTL_TIMEOUT) + tsif_device->stat_timeout++; + + iowrite32(sts_ctl, tsif_device->base + TSIF_STS_CTL_OFF); + + /* + * Before returning IRQ_HANDLED to the generic interrupt handling + * framework need to make sure all operations including clearing of + * interrupt status registers in the hardware is performed. + * Thus a barrier after clearing the interrupt status register + * is required to guarantee that the interrupt status register has + * really been cleared by the time we return from this handler. + */ + wmb(); + return IRQ_HANDLED; +} + +/*** callbacks ***/ +static void tspp_sps_complete_cb(struct sps_event_notify *notify) +{ + struct tspp_device *pdev; + + if (!notify || !notify->user) + return; + + pdev = notify->user; + tasklet_schedule(&pdev->tlet); +} + +static void tspp_expiration_timer(unsigned long data) +{ + struct tspp_device *pdev = (struct tspp_device *)data; + + if (pdev) + tasklet_schedule(&pdev->tlet); +} + +/*** tasklet ***/ +static void tspp_sps_complete_tlet(unsigned long data) +{ + int i; + int complete; + unsigned long flags; + struct sps_iovec iovec; + struct tspp_channel *channel; + struct tspp_device *device = (struct tspp_device *)data; + + spin_lock_irqsave(&device->spinlock, flags); + + for (i = 0; i < TSPP_NUM_CHANNELS; i++) { + complete = 0; + channel = &device->channels[i]; + + if (!channel->used || !channel->waiting) + continue; + + /* stop the expiration timer */ + if (channel->expiration_period_ms) + del_timer(&channel->expiration_timer); + + /* get completions */ + while (channel->waiting->state == TSPP_BUF_STATE_WAITING) { + if (sps_get_iovec(channel->pipe, &iovec) != 0) { + pr_err("%s: error in iovec on channel %d\n", + __func__, channel->id); + break; + } + if (iovec.size == 0) + break; + + if (DESC_FULL_ADDR(iovec.flags, iovec.addr) + != channel->waiting->sps.phys_base) + pr_err("%s: buffer mismatch\n", __func__); + + complete = 1; + channel->waiting->state = TSPP_BUF_STATE_DATA; + channel->waiting->filled = iovec.size; + channel->waiting->read_index = 0; + + if (channel->src == TSPP_SOURCE_TSIF0) + device->tsif[0].stat_rx++; + else if (channel->src == TSPP_SOURCE_TSIF1) + device->tsif[1].stat_rx++; + + /* update the pointers */ + channel->waiting = channel->waiting->next; + } + + /* wake any waiting processes */ + if (complete) { + wake_up_interruptible(&channel->in_queue); + + /* call notifiers */ + if (channel->notifier) + channel->notifier(channel->id, + channel->notify_data); + } + + /* restart expiration timer */ + if (channel->expiration_period_ms) + mod_timer(&channel->expiration_timer, + jiffies + + msecs_to_jiffies( + channel->expiration_period_ms)); + } + + spin_unlock_irqrestore(&device->spinlock, flags); +} + +static int tspp_config_gpios(struct tspp_device *device, + enum tspp_source source, + int enable) +{ + int ret; + struct pinctrl_state *s; + struct tspp_pinctrl *p = &device->pinctrl; + bool mode2; + + /* + * TSIF devices are handled separately, however changing of the pinctrl + * state must be protected from race condition. + */ + if (mutex_lock_interruptible(&device->mutex)) + return -ERESTARTSYS; + + switch (source) { + case TSPP_SOURCE_TSIF0: + mode2 = device->tsif[0].mode == TSPP_TSIF_MODE_2; + if (enable == p->tsif1_active) { + if (enable) + /* Both tsif enabled */ + s = mode2 ? p->dual_mode2 : p->dual_mode1; + else + /* Both tsif disabled */ + s = p->disabled; + } else if (enable) { + /* Only tsif0 is enabled */ + s = mode2 ? p->tsif0_mode2 : p->tsif0_mode1; + } else { + /* Only tsif1 is enabled */ + s = mode2 ? p->tsif1_mode2 : p->tsif1_mode1; + } + + ret = pinctrl_select_state(p->pinctrl, s); + if (!ret) + p->tsif0_active = enable; + break; + case TSPP_SOURCE_TSIF1: + mode2 = device->tsif[1].mode == TSPP_TSIF_MODE_2; + if (enable == p->tsif0_active) { + if (enable) + /* Both tsif enabled */ + s = mode2 ? p->dual_mode2 : p->dual_mode1; + else + /* Both tsif disabled */ + s = p->disabled; + } else if (enable) { + /* Only tsif1 is enabled */ + s = mode2 ? p->tsif1_mode2 : p->tsif1_mode1; + } else { + /* Only tsif0 is enabled */ + s = mode2 ? p->tsif0_mode2 : p->tsif0_mode1; + } + + ret = pinctrl_select_state(p->pinctrl, s); + if (!ret) + p->tsif1_active = enable; + break; + default: + pr_err("%s: invalid source %d\n", __func__, source); + mutex_unlock(&device->mutex); + return -EINVAL; + } + + if (ret) + pr_err("%s: failed to change pinctrl state, ret=%d\n", + __func__, ret); + + mutex_unlock(&device->mutex); + return ret; +} + +static int tspp_get_pinctrl(struct tspp_device *device) +{ + struct pinctrl *pinctrl; + struct pinctrl_state *state; + + pinctrl = devm_pinctrl_get(&device->pdev->dev); + if (IS_ERR_OR_NULL(pinctrl)) { + pr_err("%s: unable to get pinctrl handle\n", __func__); + return -EINVAL; + } + device->pinctrl.pinctrl = pinctrl; + + state = pinctrl_lookup_state(pinctrl, "disabled"); + if (IS_ERR_OR_NULL(state)) { + pr_err("%s: unable to find state %s\n", __func__, "disabled"); + return -EINVAL; + } + device->pinctrl.disabled = state; + + state = pinctrl_lookup_state(pinctrl, "tsif0-mode1"); + if (IS_ERR_OR_NULL(state)) { + pr_err("%s: unable to find state %s\n", + __func__, "tsif0-mode1"); + return -EINVAL; + } + device->pinctrl.tsif0_mode1 = state; + + state = pinctrl_lookup_state(pinctrl, "tsif0-mode2"); + if (IS_ERR_OR_NULL(state)) { + pr_err("%s: unable to find state %s\n", + __func__, "tsif0-mode2"); + return -EINVAL; + } + device->pinctrl.tsif0_mode2 = state; + + state = pinctrl_lookup_state(pinctrl, "tsif1-mode1"); + if (IS_ERR_OR_NULL(state)) { + pr_err("%s: unable to find state %s\n", + __func__, "tsif1-mode1"); + return -EINVAL; + } + device->pinctrl.tsif1_mode1 = state; + + state = pinctrl_lookup_state(pinctrl, "tsif1-mode2"); + if (IS_ERR_OR_NULL(state)) { + pr_err("%s: unable to find state %s\n", + __func__, "tsif1-mode2"); + return -EINVAL; + } + device->pinctrl.tsif1_mode2 = state; + + state = pinctrl_lookup_state(pinctrl, "dual-tsif-mode1"); + if (IS_ERR_OR_NULL(state)) { + pr_err("%s: unable to find state %s\n", + __func__, "dual-tsif-mode1"); + return -EINVAL; + } + device->pinctrl.dual_mode1 = state; + + state = pinctrl_lookup_state(pinctrl, "dual-tsif-mode2"); + if (IS_ERR_OR_NULL(state)) { + pr_err("%s: unable to find state %s\n", + __func__, "dual-tsif-mode2"); + return -EINVAL; + } + device->pinctrl.dual_mode2 = state; + + device->pinctrl.tsif0_active = false; + device->pinctrl.tsif1_active = false; + + return 0; +} + + +/*** Clock functions ***/ +static int tspp_clock_start(struct tspp_device *device) +{ + int rc; + + if (device->tsif_bus_client) { + rc = msm_bus_scale_client_update_request( + device->tsif_bus_client, 1); + if (rc) { + pr_err("%s: can't enable bus\n", __func__); + return -EBUSY; + } + } + + if (device->tsif_vreg) { + rc = regulator_set_voltage(device->tsif_vreg, + RPMH_REGULATOR_LEVEL_OFF, + RPMH_REGULATOR_LEVEL_MAX); + if (rc) { + pr_err("%s: unable to set CX voltage\n", __func__); + if (device->tsif_bus_client) + msm_bus_scale_client_update_request( + device->tsif_bus_client, 0); + return rc; + } + } + + if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) { + pr_err("%s: can't start %s\n", __func__, "pclk"); + + if (device->tsif_vreg) { + regulator_set_voltage(device->tsif_vreg, + RPMH_REGULATOR_LEVEL_OFF, + RPMH_REGULATOR_LEVEL_MAX); + } + + if (device->tsif_bus_client) + msm_bus_scale_client_update_request( + device->tsif_bus_client, 0); + return -EBUSY; + } + + if (device->tsif_ref_clk && + clk_prepare_enable(device->tsif_ref_clk) != 0) { + pr_err("%s: can't start %s\n", __func__, "ref clk"); + clk_disable_unprepare(device->tsif_pclk); + if (device->tsif_vreg) { + regulator_set_voltage(device->tsif_vreg, + RPMH_REGULATOR_LEVEL_OFF, + RPMH_REGULATOR_LEVEL_MAX); + } + + if (device->tsif_bus_client) + msm_bus_scale_client_update_request( + device->tsif_bus_client, 0); + return -EBUSY; + } + + return 0; +} + +static void tspp_clock_stop(struct tspp_device *device) +{ + int rc; + + if (device->tsif_pclk) + clk_disable_unprepare(device->tsif_pclk); + + if (device->tsif_ref_clk) + clk_disable_unprepare(device->tsif_ref_clk); + + if (device->tsif_vreg) { + rc = regulator_set_voltage(device->tsif_vreg, + RPMH_REGULATOR_LEVEL_OFF, + RPMH_REGULATOR_LEVEL_MAX); + if (rc) + pr_err("%s: unable to set CX voltage\n", __func__); + } + + if (device->tsif_bus_client) { + rc = msm_bus_scale_client_update_request( + device->tsif_bus_client, 0); + if (rc) + pr_err("%s: can't disable bus\n", __func__); + } +} + +/*** TSIF functions ***/ +static int tspp_start_tsif(struct tspp_tsif_device *tsif_device) +{ + int start_hardware = 0; + u32 ctl; + + if (tsif_device->ref_count == 0) { + start_hardware = 1; + } else if (tsif_device->ref_count > 0) { + ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF); + if ((ctl & TSIF_STS_CTL_START) != 1) { + /* this hardware should already be running */ + pr_err("%s: tsif hw not started but ref count > 0\n", + __func__); + start_hardware = 1; + } + } + + if (start_hardware) { + ctl = TSIF_STS_CTL_EN_IRQ | + TSIF_STS_CTL_EN_DM | + TSIF_STS_CTL_PACK_AVAIL | + TSIF_STS_CTL_OVERFLOW | + TSIF_STS_CTL_LOST_SYNC; + + if (tsif_device->clock_inverse) + ctl |= TSIF_STS_CTL_INV_CLOCK; + + if (tsif_device->data_inverse) + ctl |= TSIF_STS_CTL_INV_DATA; + + if (tsif_device->sync_inverse) + ctl |= TSIF_STS_CTL_INV_SYNC; + + if (tsif_device->enable_inverse) + ctl |= TSIF_STS_CTL_INV_ENABLE; + + switch (tsif_device->mode) { + case TSPP_TSIF_MODE_LOOPBACK: + ctl |= TSIF_STS_CTL_EN_NULL | + TSIF_STS_CTL_EN_ERROR | + TSIF_STS_CTL_TEST_MODE; + break; + case TSPP_TSIF_MODE_1: + ctl |= TSIF_STS_CTL_EN_TIME_LIM; + if (tsif_device->tts_source != TSIF_TTS_LPASS_TIMER) + ctl |= TSIF_STS_CTL_EN_TCR; + break; + case TSPP_TSIF_MODE_2: + ctl |= TSIF_STS_CTL_EN_TIME_LIM | + TSIF_STS_CTL_MODE_2; + if (tsif_device->tts_source != TSIF_TTS_LPASS_TIMER) + ctl |= TSIF_STS_CTL_EN_TCR; + break; + default: + pr_warn("%s: unknown tsif mode 0x%x\n", __func__, + tsif_device->mode); + } + + writel_relaxed(ctl, tsif_device->base + TSIF_STS_CTL_OFF); + /* write Status control register */ + wmb(); + writel_relaxed(tsif_device->time_limit, + tsif_device->base + TSIF_TIME_LIMIT_OFF); + /* assure register configuration is done before starting TSIF */ + wmb(); + writel_relaxed(ctl | TSIF_STS_CTL_START, + tsif_device->base + TSIF_STS_CTL_OFF); + /* assure TSIF start configuration */ + wmb(); + } + + ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF); + if (!(ctl & TSIF_STS_CTL_START)) + return -EBUSY; + + tsif_device->ref_count++; + return 0; +} + +static void tspp_stop_tsif(struct tspp_tsif_device *tsif_device) +{ + if (tsif_device->ref_count == 0) + return; + + tsif_device->ref_count--; + + if (tsif_device->ref_count == 0) { + writel_relaxed(TSIF_STS_CTL_STOP, + tsif_device->base + TSIF_STS_CTL_OFF); + /* assure TSIF stop configuration */ + wmb(); + } +} + +/*** local TSPP functions ***/ +static int tspp_channels_in_use(struct tspp_device *pdev) +{ + int i; + int count = 0; + + for (i = 0; i < TSPP_NUM_CHANNELS; i++) + count += (pdev->channels[i].used ? 1 : 0); + + return count; +} + +static struct tspp_device *tspp_find_by_id(int id) +{ + struct tspp_device *dev; + + list_for_each_entry(dev, &tspp_devices, devlist) { + if (dev->pdev->id == id) + return dev; + } + return NULL; +} + +static int tspp_get_key_entry(void) +{ + int i; + + for (i = 0; i < TSPP_NUM_KEYS; i++) { + if (!(tspp_key_entry & (1 << i))) { + tspp_key_entry |= (1 << i); + return i; + } + } + return 1 < TSPP_NUM_KEYS; +} + +static void tspp_free_key_entry(int entry) +{ + if (entry > TSPP_NUM_KEYS) { + pr_err("%s: index out of bounds\n", __func__); + return; + } + + tspp_key_entry &= ~(1 << entry); +} + +static int tspp_iommu_init(struct tspp_device *device) +{ + struct dma_iommu_mapping *iommu_map; + struct device_node *node; + int s1_bypass; + int ret; + + node = device->pdev->dev.of_node; + + iommu_map = arm_iommu_create_mapping(&platform_bus_type, + TSPP_SMMU_IOVA_START, + TSPP_SMMU_IOVA_SIZE); + if (IS_ERR(iommu_map)) { + pr_err("%s: iommu_create_mapping failure\n", __func__); + return PTR_ERR(iommu_map); + } + + s1_bypass = of_property_read_bool(node, "qcom,smmu-s1-bypass"); + ret = iommu_domain_set_attr(iommu_map->domain, + DOMAIN_ATTR_S1_BYPASS, &s1_bypass); + if (ret) { + pr_err("%s: IOMMU set s1 bypass (%d) failed (%d)\n", __func__, + s1_bypass, ret); + } + + if (arm_iommu_attach_device(&device->pdev->dev, iommu_map)) { + pr_err("%s: can't arm_iommu_attach_device\n", __func__); + arm_iommu_release_mapping(iommu_map); + return -EIO; + } + + device->iommu_mapping = iommu_map; + return 0; +} + +static void tspp_iommu_release_iomapping(struct tspp_device *device) +{ + if (device->iommu_mapping) + arm_iommu_release_mapping(device->iommu_mapping); + + device->iommu_mapping = NULL; +} + +static int tspp_alloc_buffer(u32 channel_id, struct tspp_data_descriptor *desc, + u32 size, struct dma_pool *dma_pool, tspp_allocator *alloc, void *user) +{ + if (size < TSPP_MIN_BUFFER_SIZE || + size > TSPP_MAX_BUFFER_SIZE) { + pr_err("%s: bad buffer size %d\n", __func__, size); + return -ENOMEM; + } + + if (alloc) { + TSPP_DEBUG("%s: using alloc function\n"); + desc->virt_base = alloc(channel_id, size, + &desc->phys_base, &desc->dma_base, user); + } else { + if (!dma_pool) + desc->virt_base = dma_alloc_coherent(NULL, size, + &desc->phys_base, GFP_KERNEL); + else + desc->virt_base = dma_pool_alloc(dma_pool, GFP_KERNEL, + &desc->phys_base); + + if (desc->virt_base == 0) { + pr_err("%s: dma buffer allocation failed %d\n", + __func__, size); + return -ENOMEM; + } + } + + desc->size = size; + return 0; +} + +static int tspp_queue_buffer(struct tspp_channel *channel, + struct tspp_mem_buffer *buffer) +{ + int rc; + u32 flags = 0; + + /* make sure the interrupt frequency is valid */ + if (channel->int_freq < 1) + channel->int_freq = 1; + + /* generate interrupt according to requested frequency */ + if (buffer->desc.id % channel->int_freq == channel->int_freq-1) + flags = SPS_IOVEC_FLAG_INT; + + /* start the transfer */ + rc = sps_transfer_one(channel->pipe, + buffer->sps.phys_base, + buffer->sps.size, + flags ? channel->pdev : NULL, + flags); + if (rc < 0) + return rc; + + buffer->state = TSPP_BUF_STATE_WAITING; + + return 0; +} + +static int tspp_global_reset(struct tspp_device *pdev) +{ + u32 i, val; + + /* stop all TSIFs */ + for (i = 0; i < TSPP_TSIF_INSTANCES; i++) { + pdev->tsif[i].ref_count = 1; /* allows stopping hw */ + tspp_stop_tsif(&pdev->tsif[i]); /* will reset ref_count to 0 */ + pdev->tsif[i].time_limit = TSPP_TSIF_DEFAULT_TIME_LIMIT; + pdev->tsif[i].clock_inverse = 0; + pdev->tsif[i].data_inverse = 0; + pdev->tsif[i].sync_inverse = 0; + pdev->tsif[i].enable_inverse = 0; + pdev->tsif[i].lpass_timer_enable = 0; + } + writel_relaxed(TSPP_RST_RESET, pdev->base + TSPP_RST); + /* assure state is reset before continuing with configuration */ + wmb(); + + /* TSPP tables */ + for (i = 0; i < TSPP_FILTER_TABLES; i++) + memset_io(pdev->filters[i], + 0, sizeof(*pdev->filters[i])); + + /* disable all filters */ + val = (2 << TSPP_NUM_CHANNELS) - 1; + writel_relaxed(val, pdev->base + TSPP_PS_DISABLE); + + /* TSPP registers */ + val = readl_relaxed(pdev->base + TSPP_CONTROL); + writel_relaxed(val | TSPP_CLK_CONTROL_FORCE_PERF_CNT, + pdev->base + TSPP_CONTROL); + /* assure tspp performance count clock is set to 0 */ + wmb(); + memset_io(pdev->tspp_global_performance, 0, + sizeof(*pdev->tspp_global_performance)); + memset_io(pdev->tspp_pipe_context, 0, + sizeof(*pdev->tspp_pipe_context)); + memset_io(pdev->tspp_pipe_performance, 0, + sizeof(*pdev->tspp_pipe_performance)); + /* assure tspp pipe context registers are set to 0 */ + wmb(); + writel_relaxed(val & ~TSPP_CLK_CONTROL_FORCE_PERF_CNT, + pdev->base + TSPP_CONTROL); + /* assure tspp performance count clock is reset */ + wmb(); + + val = readl_relaxed(pdev->base + TSPP_CONFIG); + val &= ~(TSPP_CONFIG_PS_LEN_ERR_MASK | + TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK | + TSPP_CONFIG_PS_CONT_ERR_MASK); + TSPP_CONFIG_SET_PACKET_LENGTH(val, TSPP_PACKET_LENGTH); + writel_relaxed(val, pdev->base + TSPP_CONFIG); + writel_relaxed(0x0007ffff, pdev->base + TSPP_IRQ_MASK); + writel_relaxed(0x000fffff, pdev->base + TSPP_IRQ_CLEAR); + writel_relaxed(0, pdev->base + TSPP_RST); + /* assure tspp reset clear */ + wmb(); + + tspp_key_entry = 0; + + return 0; +} + +static void tspp_channel_init(struct tspp_channel *channel, + struct tspp_device *pdev) +{ + channel->pdev = pdev; + channel->data = NULL; + channel->read = NULL; + channel->waiting = NULL; + channel->locked = NULL; + channel->id = channel_id++; + channel->used = 0; + channel->buffer_size = TSPP_MIN_BUFFER_SIZE; + channel->max_buffers = TSPP_NUM_BUFFERS; + channel->buffer_count = 0; + channel->filter_count = 0; + channel->int_freq = 1; + channel->src = TSPP_SOURCE_NONE; + channel->mode = TSPP_MODE_DISABLED; + channel->notifier = NULL; + channel->notify_data = NULL; + channel->expiration_period_ms = 0; + channel->memfree = NULL; + channel->user_info = NULL; + init_waitqueue_head(&channel->in_queue); +} + +static void tspp_set_tsif_mode(struct tspp_channel *channel, + enum tspp_tsif_mode mode) +{ + int index; + + switch (channel->src) { + case TSPP_SOURCE_TSIF0: + index = 0; + break; + case TSPP_SOURCE_TSIF1: + index = 1; + break; + default: + pr_warn("%s: can't set mode for non-tsif source %d\n", __func__, + channel->src); + return; + } + channel->pdev->tsif[index].mode = mode; +} + +static void tspp_set_signal_inversion(struct tspp_channel *channel, + int clock_inverse, int data_inverse, + int sync_inverse, int enable_inverse) +{ + int index; + + switch (channel->src) { + case TSPP_SOURCE_TSIF0: + index = 0; + break; + case TSPP_SOURCE_TSIF1: + index = 1; + break; + default: + return; + } + channel->pdev->tsif[index].clock_inverse = clock_inverse; + channel->pdev->tsif[index].data_inverse = data_inverse; + channel->pdev->tsif[index].sync_inverse = sync_inverse; + channel->pdev->tsif[index].enable_inverse = enable_inverse; +} + +static int tspp_is_buffer_size_aligned(u32 size, enum tspp_mode mode) +{ + u32 alignment; + + switch (mode) { + case TSPP_MODE_RAW: + /* must be a multiple of 192 */ + alignment = (TSPP_PACKET_LENGTH + 4); + if (size % alignment) + return 0; + return 1; + + case TSPP_MODE_RAW_NO_SUFFIX: + /* must be a multiple of 188 */ + alignment = TSPP_PACKET_LENGTH; + if (size % alignment) + return 0; + return 1; + + case TSPP_MODE_DISABLED: + case TSPP_MODE_PES: + default: + /* no alignment requirement */ + return 1; + } + +} + +static u32 tspp_align_buffer_size_by_mode(u32 size, enum tspp_mode mode) +{ + u32 new_size; + u32 alignment; + + switch (mode) { + case TSPP_MODE_RAW: + /* must be a multiple of 192 */ + alignment = (TSPP_PACKET_LENGTH + 4); + break; + + case TSPP_MODE_RAW_NO_SUFFIX: + /* must be a multiple of 188 */ + alignment = TSPP_PACKET_LENGTH; + break; + + case TSPP_MODE_DISABLED: + case TSPP_MODE_PES: + default: + /* no alignment requirement - give the user what he asks for */ + alignment = 1; + break; + } + /* align up */ + new_size = (((size + alignment - 1) / alignment) * alignment); + return new_size; +} + +static void tspp_destroy_buffers(u32 channel_id, struct tspp_channel *channel) +{ + int i; + struct tspp_mem_buffer *pbuf, *temp; + + pbuf = channel->data; + for (i = 0; i < channel->buffer_count; i++) { + if (pbuf->desc.phys_base) { + if (channel->memfree) { + channel->memfree(channel_id, + pbuf->desc.size, + pbuf->desc.virt_base, + pbuf->desc.phys_base, + channel->user_info); + } else { + if (!channel->dma_pool) + dma_free_coherent( + &channel->pdev->pdev->dev, + pbuf->desc.size, + pbuf->desc.virt_base, + pbuf->desc.phys_base); + else + dma_pool_free(channel->dma_pool, + pbuf->desc.virt_base, + pbuf->desc.phys_base); + } + pbuf->desc.phys_base = 0; + } + pbuf->desc.virt_base = 0; + pbuf->state = TSPP_BUF_STATE_EMPTY; + temp = pbuf; + pbuf = pbuf->next; + kfree(temp); + } +} + +static int msm_tspp_req_irqs(struct tspp_device *device) +{ + int rc; + int i; + int j; + + rc = request_irq(device->tspp_irq, tspp_isr, IRQF_SHARED, + dev_name(&device->pdev->dev), device); + if (rc) { + pr_err("%s: failed to request TSPP IRQ %d : %d\n", __func__, + device->tspp_irq, rc); + return rc; + } + + for (i = 0; i < TSPP_TSIF_INSTANCES; i++) { + rc = request_irq(device->tsif[i].tsif_irq, + tsif_isr, IRQF_SHARED, dev_name(&device->pdev->dev), + &device->tsif[i]); + if (rc) { + pr_err("%s: failed to request TSIF%d IRQ: %d\n", + __func__, i, rc); + goto failed; + } + } + device->req_irqs = true; + return 0; + +failed: + free_irq(device->tspp_irq, device); + for (j = 0; j < i; j++) + free_irq(device->tsif[j].tsif_irq, device); + + return rc; +} + +static inline void msm_tspp_free_irqs(struct tspp_device *device) +{ + int i; + + for (i = 0; i < TSPP_TSIF_INSTANCES; i++) + free_irq(device->tsif[i].tsif_irq, &device->tsif[i]); + + free_irq(device->tspp_irq, device); + device->req_irqs = false; +} + +/*** TSPP API functions ***/ + +/** + * tspp_open_stream - open a TSPP stream for use. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * @source: stream source parameters. + * + * Return error status + * + */ +int tspp_open_stream(u32 dev, u32 channel_id, + struct tspp_select_source *source) +{ + u32 val; + int rc; + struct tspp_device *pdev; + struct tspp_channel *channel; + bool req_irqs = false; + + TSPP_DEBUG("%s: %d %d %d %d\n", __func__, dev, channel_id, + source->source, source->mode); + + if (dev >= TSPP_MAX_DEVICES) { + pr_err("%s: device id out of range[0, %d]\n", + __func__, TSPP_MAX_DEVICES); + return -ENODEV; + } + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + channel = &pdev->channels[channel_id]; + channel->src = source->source; + tspp_set_tsif_mode(channel, source->mode); + tspp_set_signal_inversion(channel, source->clk_inverse, + source->data_inverse, source->sync_inverse, + source->enable_inverse); + + /* Request IRQ resources on first open */ + if (!pdev->req_irqs && (source->source == TSPP_SOURCE_TSIF0 || + source->source == TSPP_SOURCE_TSIF1)) { + rc = msm_tspp_req_irqs(pdev); + if (rc) + return rc; + req_irqs = true; + } + + switch (source->source) { + case TSPP_SOURCE_TSIF0: + if (tspp_config_gpios(pdev, channel->src, 1) != 0) { + rc = -EBUSY; + pr_err("%s: error enabling %s\n", + __func__, "tsif0 GPIOs"); + goto free_irq; + } + /* make sure TSIF0 is running & enabled */ + if (tspp_start_tsif(&pdev->tsif[0]) != 0) { + rc = -EBUSY; + pr_err("%s: error starting %s\n", __func__, "tsif0"); + goto free_irq; + } + if (pdev->tsif[0].ref_count == 1) { + val = readl_relaxed(pdev->base + TSPP_CONTROL); + writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF0_SRC_DIS, + pdev->base + TSPP_CONTROL); + /* Assure BAM TS PKT packet processing is enabled */ + wmb(); + } + break; + case TSPP_SOURCE_TSIF1: + if (tspp_config_gpios(pdev, channel->src, 1) != 0) { + rc = -EBUSY; + pr_err("%s: error enabling %s\n", + __func__, "tsif1 GPIOs"); + goto free_irq; + } + /* make sure TSIF1 is running & enabled */ + if (tspp_start_tsif(&pdev->tsif[1]) != 0) { + rc = -EBUSY; + pr_err("%s: error starting %s\n", __func__, "tsif1"); + goto free_irq; + } + if (pdev->tsif[1].ref_count == 1) { + val = readl_relaxed(pdev->base + TSPP_CONTROL); + writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF1_SRC_DIS, + pdev->base + TSPP_CONTROL); + /* Assure BAM TS PKT packet processing is enabled */ + wmb(); + } + break; + case TSPP_SOURCE_MEM: + break; + default: + pr_err("%s: channel %d invalid source %d\n", __func__, + channel->id, source->source); + return -EBUSY; + } + + return 0; + +free_irq: + /* Free irqs only if were requested during opening of this stream */ + if (req_irqs) + msm_tspp_free_irqs(pdev); + return rc; +} +EXPORT_SYMBOL(tspp_open_stream); + +/** + * tspp_close_stream - close a TSPP stream. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * + * Return error status + * + */ +int tspp_close_stream(u32 dev, u32 channel_id) +{ + u32 val; + u32 prev_ref_count = 0; + struct tspp_device *pdev; + struct tspp_channel *channel; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", __func__, + TSPP_NUM_CHANNELS); + return -ECHRNG; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -EBUSY; + } + channel = &pdev->channels[channel_id]; + + switch (channel->src) { + case TSPP_SOURCE_TSIF0: + prev_ref_count = pdev->tsif[0].ref_count; + tspp_stop_tsif(&pdev->tsif[0]); + if (tspp_config_gpios(pdev, channel->src, 0) != 0) + pr_err("%s: error disabling %s\n", + __func__, "tsif0 GPIOs"); + + if (prev_ref_count == 1) { + val = readl_relaxed(pdev->base + TSPP_CONTROL); + writel_relaxed(val | TSPP_CONTROL_TSP_TSIF0_SRC_DIS, + pdev->base + TSPP_CONTROL); + /* Assure BAM TS PKT packet processing is disabled */ + wmb(); + } + break; + case TSPP_SOURCE_TSIF1: + prev_ref_count = pdev->tsif[1].ref_count; + tspp_stop_tsif(&pdev->tsif[1]); + if (tspp_config_gpios(pdev, channel->src, 0) != 0) + pr_err("%s: error disabling %s\n", + __func__, "tsif1 GPIOs"); + + if (prev_ref_count == 1) { + val = readl_relaxed(pdev->base + TSPP_CONTROL); + writel_relaxed(val | TSPP_CONTROL_TSP_TSIF1_SRC_DIS, + pdev->base + TSPP_CONTROL); + /* Assure BAM TS PKT packet processing is disabled */ + wmb(); + } + break; + case TSPP_SOURCE_MEM: + break; + case TSPP_SOURCE_NONE: + break; + } + + channel->src = TSPP_SOURCE_NONE; + + /* Free requested interrupts to save power */ + if ((pdev->tsif[0].ref_count + pdev->tsif[1].ref_count) == 0 && + prev_ref_count) + msm_tspp_free_irqs(pdev); + + return 0; +} +EXPORT_SYMBOL(tspp_close_stream); + +static int tspp_init_sps_device(struct tspp_device *dev) +{ + int ret; + + ret = sps_register_bam_device(&dev->bam_props, &dev->bam_handle); + if (ret) { + pr_err("%s: failed to register bam device, err-%d\n", + __func__, ret); + return ret; + } + + ret = sps_device_reset(dev->bam_handle); + if (ret) { + sps_deregister_bam_device(dev->bam_handle); + pr_err("%s: error resetting bam device, err=%d\n", + __func__, ret); + return ret; + } + + return 0; +} + +/** + * tspp_open_channel - open a TSPP channel. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * + * Return error status + * + */ +int tspp_open_channel(u32 dev, u32 channel_id) +{ + int rc = 0; + struct sps_connect *config; + struct sps_register_event *event; + struct tspp_channel *channel; + struct tspp_device *pdev; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + channel = &pdev->channels[channel_id]; + + if (channel->used) { + pr_err("%s: channel already in use\n", __func__); + return -EBUSY; + } + + config = &channel->config; + event = &channel->event; + + /* start the clocks if needed */ + if (tspp_channels_in_use(pdev) == 0) { + rc = tspp_clock_start(pdev); + if (rc) + return rc; + + if (pdev->bam_handle == SPS_DEV_HANDLE_INVALID) { + rc = tspp_init_sps_device(pdev); + if (rc) { + tspp_clock_stop(pdev); + return rc; + } + } + + __pm_stay_awake(&pdev->ws); + } + + /* mark it as used */ + channel->used = 1; + + /* start the bam */ + channel->pipe = sps_alloc_endpoint(); + if (channel->pipe == NULL) { + pr_err("%s: error allocating endpoint\n", __func__); + rc = -ENOMEM; + goto err_sps_alloc; + } + + /* get default configuration */ + sps_get_config(channel->pipe, config); + + config->source = pdev->bam_handle; + config->destination = SPS_DEV_HANDLE_MEM; + config->mode = SPS_MODE_SRC; + config->options = + SPS_O_AUTO_ENABLE | /* connection is auto-enabled */ + SPS_O_STREAMING | /* streaming mode */ + SPS_O_DESC_DONE | /* interrupt on end of descriptor */ + SPS_O_ACK_TRANSFERS | /* must use sps_get_iovec() */ + SPS_O_HYBRID; /* Read actual descriptors in sps_get_iovec() */ + config->src_pipe_index = channel->id; + config->desc.size = + TSPP_SPS_DESCRIPTOR_COUNT * SPS_DESCRIPTOR_SIZE; + config->desc.base = dma_alloc_coherent(&pdev->pdev->dev, + config->desc.size, + &config->desc.phys_base, + GFP_KERNEL); + if (config->desc.base == 0) { + pr_err("%s: error allocating sps descriptors\n", __func__); + rc = -ENOMEM; + goto err_desc_alloc; + } + + memset(config->desc.base, 0, config->desc.size); + + rc = sps_connect(channel->pipe, config); + if (rc) { + pr_err("%s: error connecting bam\n", __func__); + goto err_connect; + } + + event->mode = SPS_TRIGGER_CALLBACK; + event->options = SPS_O_DESC_DONE; + event->callback = tspp_sps_complete_cb; + event->xfer_done = NULL; + event->user = pdev; + + rc = sps_register_event(channel->pipe, event); + if (rc) { + pr_err("%s: error registering event\n", __func__); + goto err_event; + } + + init_timer(&channel->expiration_timer); + channel->expiration_timer.function = tspp_expiration_timer; + channel->expiration_timer.data = (unsigned long)pdev; + channel->expiration_timer.expires = 0xffffffffL; + + rc = pm_runtime_get(&pdev->pdev->dev); + if (rc < 0) { + pr_err( + "%s: Runtime PM : Unable to wake up tspp device, rc = %d\n", + __func__, rc); + } + return 0; + +err_event: + sps_disconnect(channel->pipe); +err_connect: + dma_free_coherent(&pdev->pdev->dev, config->desc.size, + config->desc.base, config->desc.phys_base); +err_desc_alloc: + sps_free_endpoint(channel->pipe); +err_sps_alloc: + channel->used = 0; + return rc; +} +EXPORT_SYMBOL(tspp_open_channel); + +/** + * tspp_close_channel - close a TSPP channel. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * + * Return error status + * + */ +int tspp_close_channel(u32 dev, u32 channel_id) +{ + int i; + int id; + int table_idx; + u32 val; + unsigned long flags; + + struct sps_connect *config; + struct tspp_device *pdev; + struct tspp_channel *channel; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + channel = &pdev->channels[channel_id]; + + /* if the channel is not used, we are done */ + if (!channel->used) + return 0; + + /* + * Need to protect access to used and waiting fields, as they are + * used by the tasklet which is invoked from interrupt context + */ + spin_lock_irqsave(&pdev->spinlock, flags); + channel->used = 0; + channel->waiting = NULL; + spin_unlock_irqrestore(&pdev->spinlock, flags); + + if (channel->expiration_period_ms) + del_timer(&channel->expiration_timer); + + channel->notifier = NULL; + channel->notify_data = NULL; + channel->expiration_period_ms = 0; + + config = &channel->config; + pdev = channel->pdev; + + /* disable pipe (channel) */ + val = readl_relaxed(pdev->base + TSPP_PS_DISABLE); + writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE); + /* Assure PS_DISABLE register is set */ + wmb(); + + /* unregister all filters for this channel */ + for (table_idx = 0; table_idx < TSPP_FILTER_TABLES; table_idx++) { + for (i = 0; i < TSPP_NUM_PRIORITIES; i++) { + struct tspp_pid_filter *filter = + &pdev->filters[table_idx]->filter[i]; + id = FILTER_GET_PIPE_NUMBER0(filter); + if (id == channel->id) { + if (FILTER_HAS_ENCRYPTION(filter)) + tspp_free_key_entry( + FILTER_GET_KEY_NUMBER(filter)); + filter->config = 0; + filter->filter = 0; + } + } + } + channel->filter_count = 0; + + /* disconnect the bam */ + if (sps_disconnect(channel->pipe) != 0) + pr_warn("%s: Error freeing sps endpoint (%d)\n", + __func__, channel->id); + + /* destroy the buffers */ + dma_free_coherent(&pdev->pdev->dev, config->desc.size, + config->desc.base, config->desc.phys_base); + + sps_free_endpoint(channel->pipe); + + tspp_destroy_buffers(channel_id, channel); + + dma_pool_destroy(channel->dma_pool); + channel->dma_pool = NULL; + + channel->src = TSPP_SOURCE_NONE; + channel->mode = TSPP_MODE_DISABLED; + channel->memfree = NULL; + channel->user_info = NULL; + channel->buffer_count = 0; + channel->data = NULL; + channel->read = NULL; + channel->locked = NULL; + + if (tspp_channels_in_use(pdev) == 0) { + sps_deregister_bam_device(pdev->bam_handle); + pdev->bam_handle = SPS_DEV_HANDLE_INVALID; + + __pm_relax(&pdev->ws); + tspp_clock_stop(pdev); + } + + pm_runtime_put(&pdev->pdev->dev); + + return 0; +} +EXPORT_SYMBOL(tspp_close_channel); + +/** + * tspp_get_ref_clk_counter - return the TSIF clock reference (TCR) counter. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @source: The TSIF source from which the counter should be read + * @tcr_counter: the value of TCR counter + * + * Return error status + * + * TCR increments at a rate equal to 27 MHz/256 = 105.47 kHz. + * If source is neither TSIF 0 or TSIF1 0 is returned. + */ +int tspp_get_ref_clk_counter(u32 dev, enum tspp_source source, u32 *tcr_counter) +{ + struct tspp_device *pdev; + struct tspp_tsif_device *tsif_device; + + if (!tcr_counter) + return -EINVAL; + + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + + switch (source) { + case TSPP_SOURCE_TSIF0: + tsif_device = &pdev->tsif[0]; + break; + + case TSPP_SOURCE_TSIF1: + tsif_device = &pdev->tsif[1]; + break; + + default: + tsif_device = NULL; + break; + } + + if (tsif_device && tsif_device->ref_count) + *tcr_counter = ioread32(tsif_device->base + TSIF_CLK_REF_OFF); + else + *tcr_counter = 0; + + return 0; +} +EXPORT_SYMBOL(tspp_get_ref_clk_counter); + +/** + * tspp_get_lpass_time_counter - return the LPASS Timer counter value. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @source: The TSIF source from which the counter should be read + * @tcr_counter: the value of TCR counter + * + * Return error status + * + * If source is neither TSIF 0 or TSIF1 0 is returned. + */ +int tspp_get_lpass_time_counter(u32 dev, enum tspp_source source, + u64 *lpass_time_counter) +{ + return -EPERM; +} +EXPORT_SYMBOL(tspp_get_lpass_time_counter); + +/** + * tspp_get_tts_source - Return the TTS source value. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @tts_source:Updated TTS source type + * + * Return error status + * + */ +int tspp_get_tts_source(u32 dev, int *tts_source) +{ + struct tspp_device *pdev; + + if (tts_source == NULL) + return -EINVAL; + + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + + *tts_source = pdev->tts_source; + + return 0; +} +EXPORT_SYMBOL(tspp_get_tts_source); + +/** + * tspp_add_filter - add a TSPP filter to a channel. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * @filter: TSPP filter parameters + * + * Return error status + * + */ +int tspp_add_filter(u32 dev, u32 channel_id, + struct tspp_filter *filter) +{ + int i, rc; + int other_channel; + int entry; + u32 val, pid, enabled; + struct tspp_device *pdev; + struct tspp_pid_filter p; + struct tspp_channel *channel; + + TSPP_DEBUG("%s: add filter\n"); + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + + channel = &pdev->channels[channel_id]; + + if (filter->source > TSPP_SOURCE_MEM) { + pr_err("%s: invalid source\n", __func__); + return -ENOSR; + } + + if (filter->priority >= TSPP_NUM_PRIORITIES) { + pr_err("%s: invalid filter priority\n", __func__); + return -ENOSR; + } + + channel->mode = filter->mode; + /* + * if buffers are already allocated, verify they fulfil + * the alignment requirements. + */ + if ((channel->buffer_count > 0) && + (!tspp_is_buffer_size_aligned(channel->buffer_size, channel->mode))) + pr_warn("%s: buffers allocated with incorrect alignment\n", + __func__); + + if (filter->mode == TSPP_MODE_PES) { + for (i = 0; i < TSPP_NUM_PRIORITIES; i++) { + struct tspp_pid_filter *tspp_filter = + &pdev->filters[channel->src]->filter[i]; + pid = FILTER_GET_PIPE_PID((tspp_filter)); + enabled = FILTER_GET_PIPE_PROCESS0(tspp_filter); + if (enabled && (pid == filter->pid)) { + other_channel = + FILTER_GET_PIPE_NUMBER0(tspp_filter); + pr_err( + "%s: pid 0x%x already in use by channel %d\n", + __func__, filter->pid, other_channel); + return -EBADSLT; + } + } + } + + /* make sure this priority is not already in use */ + enabled = FILTER_GET_PIPE_PROCESS0( + (&(pdev->filters[channel->src]->filter[filter->priority]))); + if (enabled) { + pr_err("%s: filter priority %d source %d is already enabled\n", + __func__, filter->priority, channel->src); + return -ENOSR; + } + + if (channel->mode == TSPP_MODE_PES) { + /* + * if we are already processing in PES mode, disable pipe + * (channel) and filter to be updated + */ + val = readl_relaxed(pdev->base + TSPP_PS_DISABLE); + writel_relaxed(val | (1 << channel->id), + pdev->base + TSPP_PS_DISABLE); + /* Assure PS_DISABLE register is set */ + wmb(); + } + + /* update entry */ + p.filter = 0; + p.config = FILTER_TRANS_END_DISABLE; + FILTER_SET_PIPE_PROCESS0((&p), filter->mode); + FILTER_SET_PIPE_PID((&p), filter->pid); + FILTER_SET_PID_MASK((&p), filter->mask); + FILTER_SET_PIPE_NUMBER0((&p), channel->id); + FILTER_SET_PIPE_PROCESS1((&p), TSPP_MODE_DISABLED); + if (filter->decrypt) { + entry = tspp_get_key_entry(); + if (entry == -1) { + pr_err("%s: no more keys available\n", __func__); + } else { + p.config |= FILTER_DECRYPT; + FILTER_SET_KEY_NUMBER((&p), entry); + } + } + + pdev->filters[channel->src]->filter[filter->priority].config = p.config; + pdev->filters[channel->src]->filter[filter->priority].filter = p.filter; + + /* + * allocate buffers if needed (i.e. if user did has not already called + * tspp_allocate_buffers() explicitly). + */ + if (channel->buffer_count == 0) { + channel->buffer_size = + tspp_align_buffer_size_by_mode(channel->buffer_size, + channel->mode); + rc = tspp_allocate_buffers(dev, channel->id, + channel->max_buffers, + channel->buffer_size, + channel->int_freq, NULL, NULL, NULL); + if (rc != 0) { + pr_err("%s: tspp_allocate_buffers failed\n", __func__); + return rc; + } + } + + /* reenable pipe */ + val = readl_relaxed(pdev->base + TSPP_PS_DISABLE); + writel_relaxed(val & ~(1 << channel->id), pdev->base + TSPP_PS_DISABLE); + /* Assure PS_DISABLE register is reset */ + wmb(); + val = readl_relaxed(pdev->base + TSPP_PS_DISABLE); + + channel->filter_count++; + + return 0; +} +EXPORT_SYMBOL(tspp_add_filter); + +/** + * tspp_remove_filter - remove a TSPP filter from a channel. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * @filter: TSPP filter parameters + * + * Return error status + * + */ +int tspp_remove_filter(u32 dev, u32 channel_id, + struct tspp_filter *filter) +{ + int entry; + u32 val; + struct tspp_device *pdev; + int src; + struct tspp_pid_filter *tspp_filter; + struct tspp_channel *channel; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + if (!filter) { + pr_err("%s: NULL filter pointer\n", __func__); + return -EINVAL; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + if (filter->priority >= TSPP_NUM_PRIORITIES) { + pr_err("%s: invalid filter priority\n", __func__); + return -ENOSR; + } + channel = &pdev->channels[channel_id]; + + src = channel->src; + if ((src == TSPP_SOURCE_TSIF0) || (src == TSPP_SOURCE_TSIF1)) + tspp_filter = &(pdev->filters[src]->filter[filter->priority]); + else { + pr_err("%s: wrong source type %d\n", __func__, src); + return -EINVAL; + } + + + /* disable pipe (channel) */ + val = readl_relaxed(pdev->base + TSPP_PS_DISABLE); + writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE); + /* Assure PS_DISABLE register is set */ + wmb(); + + /* update data keys */ + if (tspp_filter->config & FILTER_DECRYPT) { + entry = FILTER_GET_KEY_NUMBER(tspp_filter); + tspp_free_key_entry(entry); + } + + /* update pid table */ + tspp_filter->config = 0; + tspp_filter->filter = 0; + + channel->filter_count--; + + /* reenable pipe */ + val = readl_relaxed(pdev->base + TSPP_PS_DISABLE); + writel_relaxed(val & ~(1 << channel->id), + pdev->base + TSPP_PS_DISABLE); + /* Assure PS_DISABLE register is reset */ + wmb(); + val = readl_relaxed(pdev->base + TSPP_PS_DISABLE); + + return 0; +} +EXPORT_SYMBOL(tspp_remove_filter); + +/** + * tspp_set_key - set TSPP key in key table. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * @key: TSPP key parameters + * + * Return error status + * + */ +int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key) +{ + int i; + int id; + int key_index; + int data; + struct tspp_channel *channel; + struct tspp_device *pdev; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + channel = &pdev->channels[channel_id]; + + /* read the key index used by this channel */ + for (i = 0; i < TSPP_NUM_PRIORITIES; i++) { + struct tspp_pid_filter *tspp_filter = + &(pdev->filters[channel->src]->filter[i]); + id = FILTER_GET_PIPE_NUMBER0(tspp_filter); + if (id == channel->id) { + if (FILTER_HAS_ENCRYPTION(tspp_filter)) { + key_index = FILTER_GET_KEY_NUMBER(tspp_filter); + break; + } + } + } + if (i == TSPP_NUM_PRIORITIES) { + pr_err("%s: no encryption on this channel\n"); + return -ENOKEY; + } + + if (key->parity == TSPP_KEY_PARITY_EVEN) { + pdev->tspp_key_table->entry[key_index].even_lsb = key->lsb; + pdev->tspp_key_table->entry[key_index].even_msb = key->msb; + } else { + pdev->tspp_key_table->entry[key_index].odd_lsb = key->lsb; + pdev->tspp_key_table->entry[key_index].odd_msb = key->msb; + } + data = readl_relaxed(channel->pdev->base + TSPP_KEY_VALID); + + return 0; +} +EXPORT_SYMBOL(tspp_set_key); + +/** + * tspp_register_notification - register TSPP channel notification function. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * @notify: notification function + * @userdata: user data to pass to notification function + * @timer_ms: notification for partially filled buffers + * + * Return error status + * + */ +int tspp_register_notification(u32 dev, u32 channel_id, + tspp_notifier *notify, void *userdata, u32 timer_ms) +{ + struct tspp_channel *channel; + struct tspp_device *pdev; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + channel = &pdev->channels[channel_id]; + channel->notifier = notify; + channel->notify_data = userdata; + channel->expiration_period_ms = timer_ms; + + return 0; +} +EXPORT_SYMBOL(tspp_register_notification); + +/** + * tspp_unregister_notification - unregister TSPP channel notification function. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * + * Return error status + * + */ +int tspp_unregister_notification(u32 dev, u32 channel_id) +{ + struct tspp_channel *channel; + struct tspp_device *pdev; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + channel = &pdev->channels[channel_id]; + channel->notifier = NULL; + channel->notify_data = 0; + return 0; +} +EXPORT_SYMBOL(tspp_unregister_notification); + +/** + * tspp_get_buffer - get TSPP data buffer. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * + * Return error status + * + */ +const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id) +{ + struct tspp_mem_buffer *buffer; + struct tspp_channel *channel; + struct tspp_device *pdev; + unsigned long flags; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return NULL; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return NULL; + } + + spin_lock_irqsave(&pdev->spinlock, flags); + + channel = &pdev->channels[channel_id]; + + if (!channel->read) { + spin_unlock_irqrestore(&pdev->spinlock, flags); + pr_warn("%s: no buffer to get on channel %d\n", __func__, + channel->id); + return NULL; + } + + buffer = channel->read; + /* see if we have any buffers ready to read */ + if (buffer->state != TSPP_BUF_STATE_DATA) { + spin_unlock_irqrestore(&pdev->spinlock, flags); + return NULL; + } + + if (buffer->state == TSPP_BUF_STATE_DATA) { + /* mark the buffer as busy */ + buffer->state = TSPP_BUF_STATE_LOCKED; + + /* increment the pointer along the list */ + channel->read = channel->read->next; + } + + spin_unlock_irqrestore(&pdev->spinlock, flags); + + return &buffer->desc; +} +EXPORT_SYMBOL(tspp_get_buffer); + +/** + * tspp_release_buffer - release TSPP data buffer back to TSPP. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * @descriptor_id: buffer descriptor ID + * + * Return error status + * + */ +int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id) +{ + int i, found = 0; + struct tspp_mem_buffer *buffer; + struct tspp_channel *channel; + struct tspp_device *pdev; + unsigned long flags; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + + spin_lock_irqsave(&pdev->spinlock, flags); + + channel = &pdev->channels[channel_id]; + + if (descriptor_id > channel->buffer_count) + pr_warn("%s: invalid desc id: 0x%08x\n", + __func__, descriptor_id); + + /* find the correct descriptor */ + buffer = channel->locked; + for (i = 0; i < channel->buffer_count; i++) { + if (buffer->desc.id == descriptor_id) { + found = 1; + break; + } + buffer = buffer->next; + } + channel->locked = channel->locked->next; + + if (!found) { + spin_unlock_irqrestore(&pdev->spinlock, flags); + pr_err("%s: cant find desc %d\n", __func__, descriptor_id); + return -EINVAL; + } + + /* make sure the buffer is in the expected state */ + if (buffer->state != TSPP_BUF_STATE_LOCKED) { + spin_unlock_irqrestore(&pdev->spinlock, flags); + pr_err("%s: buffer %d not locked\n", __func__, descriptor_id); + return -EINVAL; + } + /* unlock the buffer and requeue it */ + buffer->state = TSPP_BUF_STATE_WAITING; + + if (tspp_queue_buffer(channel, buffer)) + pr_warn("%s: can't requeue buffer\n", __func__); + + spin_unlock_irqrestore(&pdev->spinlock, flags); + + return 0; +} +EXPORT_SYMBOL(tspp_release_buffer); + +/** + * tspp_allocate_buffers - allocate TSPP data buffers. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS) + * @count: number of buffers to allocate + * @size: size of each buffer to allocate + * @int_freq: interrupt frequency + * @alloc: user defined memory allocator function. Pass NULL for default. + * @memfree: user defined memory free function. Pass NULL for default. + * @user: user data to pass to the memory allocator/free function + * + * Return error status + * + * The user can optionally call this function explicitly to allocate the TSPP + * data buffers. Alternatively, if the user did not call this function, it + * is called implicitly by tspp_add_filter(). + */ +int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count, u32 size, + u32 int_freq, tspp_allocator *alloc, + tspp_memfree *memfree, void *user) +{ + struct tspp_channel *channel; + struct tspp_device *pdev; + struct tspp_mem_buffer *last = NULL; + + if (channel_id >= TSPP_NUM_CHANNELS) { + pr_err("%s: channel id out of range[0, %d]\n", + __func__, TSPP_NUM_CHANNELS); + return -ECHRNG; + } + + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + + if (count < MIN_ACCEPTABLE_BUFFER_COUNT) { + pr_err("%s: tspp requires a minimum of %d buffers\n", __func__, + MIN_ACCEPTABLE_BUFFER_COUNT); + return -EINVAL; + } + + if (count > TSPP_NUM_BUFFERS) { + pr_err("%s: tspp requires a maximum of %d buffers\n", __func__, + TSPP_NUM_BUFFERS); + return -EINVAL; + } + + channel = &pdev->channels[channel_id]; + + /* allow buffer allocation only if there was no previous buffer + * allocation for this channel. + */ + if (channel->buffer_count > 0) { + pr_err("%s: buffers already allocated for channel %u\n", + __func__, channel_id); + return -EINVAL; + } + + channel->max_buffers = count; + + /* set up interrupt frequency */ + if (int_freq > channel->max_buffers) { + int_freq = channel->max_buffers; + pr_debug("%s: setting interrupt frequency to %u\n", __func__, + int_freq); + } + channel->int_freq = int_freq; + /* + * it is the responsibility of the caller to tspp_allocate_buffers(), + * whether it's the user or the driver, to make sure the size parameter + * is compatible to the channel mode. + */ + channel->buffer_size = size; + + /* save user defined memory free function for later use */ + channel->memfree = memfree; + channel->user_info = user; + + /* + * For small buffers, create a DMA pool so that memory + * is not wasted through dma_alloc_coherent. + */ + if (TSPP_USE_DMA_POOL(channel->buffer_size)) { + channel->dma_pool = dma_pool_create("tspp", + &pdev->pdev->dev, channel->buffer_size, 0, 0); + if (!channel->dma_pool) { + pr_err("%s: Can't allocate memory pool\n", __func__); + return -ENOMEM; + } + } else { + channel->dma_pool = NULL; + } + + + for (channel->buffer_count = 0; + channel->buffer_count < channel->max_buffers; + channel->buffer_count++) { + + /* allocate the descriptor */ + struct tspp_mem_buffer *desc = + kmalloc(sizeof(struct tspp_mem_buffer), GFP_KERNEL); + if (!desc) { + pr_warn("%s: Can't allocate desc %d\n", + __func__, channel->buffer_count); + break; + } + + desc->desc.id = channel->buffer_count; + /* allocate the buffer */ + if (tspp_alloc_buffer(channel_id, &desc->desc, + channel->buffer_size, channel->dma_pool, + alloc, user) != 0) { + kfree(desc); + pr_warn("%s: Can't allocate buffer %d\n", + __func__, channel->buffer_count); + break; + } + + /* add the descriptor to the list */ + desc->filled = 0; + desc->read_index = 0; + if (!channel->data) { + channel->data = desc; + desc->next = channel->data; + } else { + if (last != NULL) + last->next = desc; + } + last = desc; + desc->next = channel->data; + + /* prepare the sps descriptor */ + desc->sps.phys_base = desc->desc.phys_base; + desc->sps.base = desc->desc.virt_base; + desc->sps.size = desc->desc.size; + + /* start the transfer */ + if (tspp_queue_buffer(channel, desc)) + pr_err("%s: can't queue buffer %d\n", __func__, + desc->desc.id); + } + + if (channel->buffer_count < channel->max_buffers) { + /* + * we failed to allocate the requested number of buffers. + * we don't allow a partial success, so need to clean up here. + */ + tspp_destroy_buffers(channel_id, channel); + channel->buffer_count = 0; + + dma_pool_destroy(channel->dma_pool); + channel->dma_pool = NULL; + return -ENOMEM; + } + + channel->waiting = channel->data; + channel->read = channel->data; + channel->locked = channel->data; + + /* Now that buffers are scheduled to HW, kick data expiration timer */ + if (channel->expiration_period_ms) + mod_timer(&channel->expiration_timer, + jiffies + + msecs_to_jiffies( + channel->expiration_period_ms)); + + return 0; +} +EXPORT_SYMBOL(tspp_allocate_buffers); + +/** + * tspp_detach_ion_dma_buff - detach the mapped ion dma buffer from TSPP device + * It will detach previously mapped DMA buffer from TSPP device. + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @ion_dma_buf: It contains required members for ION buffer dma mapping. + * + * Return error status + * + */ +int tspp_detach_ion_dma_buff(u32 dev, struct tspp_ion_dma_buf_info *ion_dma_buf) +{ + struct tspp_device *pdev; + int dir = DMA_FROM_DEVICE; + + if (ion_dma_buf == NULL || ion_dma_buf->dbuf == NULL || + ion_dma_buf->table == NULL || ion_dma_buf->table->sgl == NULL || + ion_dma_buf->smmu_map == false) { + pr_err("%s: invalid input argument\n", __func__); + return -EINVAL; + } + + if (dev >= TSPP_MAX_DEVICES) { + pr_err("%s: device id out of range[0, %d]\n", + __func__, TSPP_MAX_DEVICES); + return -ENODEV; + } + + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + + + dma_unmap_sg(&pdev->pdev->dev, ion_dma_buf->table->sgl, + ion_dma_buf->table->nents, dir); + dma_buf_unmap_attachment(ion_dma_buf->attach, ion_dma_buf->table, dir); + dma_buf_detach(ion_dma_buf->dbuf, ion_dma_buf->attach); + dma_buf_put(ion_dma_buf->dbuf); + + ion_dma_buf->smmu_map = false; + return 0; +} +EXPORT_SYMBOL(tspp_detach_ion_dma_buff); + +/** + * tspp_allocate_dma_buffer - Allocates DMA buffer using dma_alloc_coherent + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @size: Size of memory to be allocated + * @paddr: Returns the physical address of the allocated memory + * + * Return error status + * + */ +void *tspp_allocate_dma_buffer(u32 dev, int size, phys_addr_t *paddr) +{ + + struct tspp_device *pdev; + + if (dev >= TSPP_MAX_DEVICES) { + pr_err("%s: device id out of range[0, %d]\n", + __func__, TSPP_MAX_DEVICES); + return NULL; + } + + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return NULL; + } + + return dma_alloc_coherent(&pdev->pdev->dev, + size, paddr, GFP_KERNEL); +} +EXPORT_SYMBOL(tspp_allocate_dma_buffer); + +/** + * tspp_free_dma_buffer - Free the allocated memmory + * + * @dev: TSPP device (up to TSPP_MAX_DEVICES) + * @size: Size of allocated memory + * @vaddr: Virtual address of the allocated memory + * @paddr: Physical address of the allocated memory + * + * Return error status + * + */ +int tspp_free_dma_buffer(u32 dev, int size, void *vaddr, dma_addr_t paddr) +{ + + struct tspp_device *pdev; + + if (dev >= TSPP_MAX_DEVICES) { + pr_err("%s: device id out of range[0, %d]\n", + __func__, TSPP_MAX_DEVICES); + return -ENODEV; + } + + pdev = tspp_find_by_id(dev); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, dev); + return -ENODEV; + } + + dma_free_coherent(&pdev->pdev->dev, + size, vaddr, paddr); + + return 0; +} +EXPORT_SYMBOL(tspp_free_dma_buffer); + + +/*** debugfs ***/ +static int debugfs_iomem_x32_set(void *data, u64 val) +{ + int rc; + int clock_started = 0; + struct tspp_device *pdev; + + pdev = tspp_find_by_id(0); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, 0); + return 0; + } + + if (tspp_channels_in_use(pdev) == 0) { + rc = tspp_clock_start(pdev); + if (rc) { + pr_err("%s: tspp_clock_start failed %d\n", + __func__, rc); + return 0; + } + clock_started = 1; + } + + writel_relaxed(val, data); + /* Assure register write */ + wmb(); + + if (clock_started) + tspp_clock_stop(pdev); + return 0; +} + +static int debugfs_iomem_x32_get(void *data, u64 *val) +{ + int rc; + int clock_started = 0; + struct tspp_device *pdev; + + pdev = tspp_find_by_id(0); + if (!pdev) { + pr_err("%s: can't find device %d\n", __func__, 0); + *val = 0; + return 0; + } + + if (tspp_channels_in_use(pdev) == 0) { + rc = tspp_clock_start(pdev); + if (rc) { + pr_err("%s: tspp_clock_start failed %d\n", + __func__, rc); + *val = 0; + return 0; + } + clock_started = 1; + } + + *val = readl_relaxed(data); + + if (clock_started) + tspp_clock_stop(pdev); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, debugfs_iomem_x32_get, + debugfs_iomem_x32_set, "0x%08llx"); + +static void tsif_debugfs_init(struct tspp_tsif_device *tsif_device, + int instance) +{ + char name[10]; + + snprintf(name, sizeof(name), "tsif%d", instance); + tsif_device->dent_tsif = debugfs_create_dir( + name, NULL); + if (tsif_device->dent_tsif) { + int i; + void __iomem *base = tsif_device->base; + + for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++) { + tsif_device->debugfs_tsif_regs[i] = + debugfs_create_file( + debugfs_tsif_regs[i].name, + debugfs_tsif_regs[i].mode, + tsif_device->dent_tsif, + base + debugfs_tsif_regs[i].offset, + &fops_iomem_x32); + } + + debugfs_create_u32( + "stat_rx_chunks", 0664, + tsif_device->dent_tsif, + &tsif_device->stat_rx); + + debugfs_create_u32( + "stat_overflow", 0664, + tsif_device->dent_tsif, + &tsif_device->stat_overflow); + + debugfs_create_u32( + "stat_lost_sync", 0664, + tsif_device->dent_tsif, + &tsif_device->stat_lost_sync); + + debugfs_create_u32( + "stat_timeout", 0664, + tsif_device->dent_tsif, + &tsif_device->stat_timeout); + } +} + +static void tsif_debugfs_exit(struct tspp_tsif_device *tsif_device) +{ + int i; + + debugfs_remove_recursive(tsif_device->dent_tsif); + tsif_device->dent_tsif = NULL; + for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++) + tsif_device->debugfs_tsif_regs[i] = NULL; +} + +static void tspp_debugfs_init(struct tspp_device *device, int instance) +{ + char name[10]; + + snprintf(name, sizeof(name), "tspp%d", instance); + device->dent = debugfs_create_dir( + name, NULL); + if (device->dent) { + int i; + void __iomem *base = device->base; + + for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++) + device->debugfs_regs[i] = + debugfs_create_file( + debugfs_tspp_regs[i].name, + debugfs_tspp_regs[i].mode, + device->dent, + base + debugfs_tspp_regs[i].offset, + &fops_iomem_x32); + } +} + +static void tspp_debugfs_exit(struct tspp_device *device) +{ + int i; + + debugfs_remove_recursive(device->dent); + for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++) + device->debugfs_regs[i] = NULL; +} + +static int msm_tspp_map_irqs(struct platform_device *pdev, + struct tspp_device *device) +{ + int rc; + + /* get IRQ numbers from platform information */ + + /* map TSPP IRQ */ + rc = platform_get_irq_byname(pdev, "TSIF_TSPP_IRQ"); + if (rc > 0) { + device->tspp_irq = rc; + } else { + pr_err("%s: failed to get %s\n", __func__, "TSPP IRQ"); + return -EINVAL; + } + + /* map TSIF IRQs */ + rc = platform_get_irq_byname(pdev, "TSIF0_IRQ"); + if (rc > 0) { + device->tsif[0].tsif_irq = rc; + } else { + pr_err("%s: failed to get %s\n", __func__, "TSIF0 IRQ"); + return -EINVAL; + } + + rc = platform_get_irq_byname(pdev, "TSIF1_IRQ"); + if (rc > 0) { + device->tsif[1].tsif_irq = rc; + } else { + pr_err("%s: failed to get %s\n", __func__, "TSIF1 IRQ"); + return -EINVAL; + } + + /* map BAM IRQ */ + rc = platform_get_irq_byname(pdev, "TSIF_BAM_IRQ"); + if (rc > 0) { + device->bam_irq = rc; + } else { + pr_err("%s: failed to get %s\n", __func__, "TSPP BAM IRQ"); + return -EINVAL; + } + + return 0; +} + +static int msm_tspp_probe(struct platform_device *pdev) +{ + int rc = -ENODEV; + u32 version; + u32 i; + struct tspp_device *device; + struct resource *mem_tsif0; + struct resource *mem_tsif1; + struct resource *mem_tspp; + struct resource *mem_bam; + struct msm_bus_scale_pdata *tspp_bus_pdata = NULL; + unsigned long rate; + + if (pdev->dev.of_node) { + /* ID is always 0 since there is only 1 instance of TSPP */ + pdev->id = 0; + tspp_bus_pdata = msm_bus_cl_get_pdata(pdev); + } else { + /* must have device tree data */ + pr_err("%s: Device tree data not available\n", __func__); + rc = -EINVAL; + goto out; + } + + /* OK, we will use this device */ + device = kzalloc(sizeof(*device), GFP_KERNEL); + if (!device) { + rc = -ENOMEM; + goto out; + } + + /* set up references */ + device->pdev = pdev; + platform_set_drvdata(pdev, device); + + /* setup pin control */ + rc = tspp_get_pinctrl(device); + if (rc) { + pr_err("%s: failed to get pin control data, rc=%d\n", + __func__, rc); + goto err_pinctrl; + } + + /* register bus client */ + if (tspp_bus_pdata) { + device->tsif_bus_client = + msm_bus_scale_register_client(tspp_bus_pdata); + if (!device->tsif_bus_client) + pr_err("%s: Unable to register bus client\n", __func__); + } else { + device->tsif_bus_client = 0; + } + + /* map regulators */ + device->tsif_vreg = devm_regulator_get_optional(&pdev->dev, "vdd_cx"); + if (IS_ERR_OR_NULL(device->tsif_vreg)) { + rc = PTR_ERR(device->tsif_vreg); + device->tsif_vreg = NULL; + if (rc == -ENODEV) { + pr_notice("%s: vdd_cx regulator will not be used\n", + __func__); + } else { + pr_err("%s: failed to get CX regulator, err=%d\n", + __func__, rc); + goto err_regulator; + } + } else { + /* Set an initial voltage and enable the regulator */ + rc = regulator_set_voltage(device->tsif_vreg, + RPMH_REGULATOR_LEVEL_OFF, + RPMH_REGULATOR_LEVEL_MAX); + if (rc) { + pr_err("%s: Unable to set CX voltage\n", __func__); + goto err_regulator; + } + + rc = regulator_enable(device->tsif_vreg); + if (rc) { + pr_err("%s: Unable to enable CX regulator\n", __func__); + goto err_regulator; + } + } + + /* map clocks */ + device->tsif_pclk = clk_get(&pdev->dev, "iface_clk"); + if (IS_ERR_OR_NULL(device->tsif_pclk)) { + rc = PTR_ERR(device->tsif_pclk); + device->tsif_pclk = NULL; + goto err_pclock; + } + + device->tsif_ref_clk = clk_get(&pdev->dev, "ref_clk"); + if (IS_ERR_OR_NULL(device->tsif_ref_clk)) { + rc = PTR_ERR(device->tsif_ref_clk); + device->tsif_ref_clk = NULL; + goto err_refclock; + } + rate = clk_round_rate(device->tsif_ref_clk, 1); + rc = clk_set_rate(device->tsif_ref_clk, rate); + if (rc) + goto err_res_tsif0; + + /* map I/O memory */ + mem_tsif0 = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "MSM_TSIF0_PHYS"); + if (!mem_tsif0) { + pr_err("%s: Missing tsif0 MEM resource\n", __func__); + rc = -ENXIO; + goto err_res_tsif0; + } + device->tsif[0].base = ioremap(mem_tsif0->start, + resource_size(mem_tsif0)); + if (!device->tsif[0].base) { + pr_err("%s: ioremap failed\n", __func__); + goto err_map_tsif0; + } + + mem_tsif1 = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "MSM_TSIF1_PHYS"); + if (!mem_tsif1) { + pr_err("%s: missing tsif1 MEM resource\n", __func__); + rc = -ENXIO; + goto err_res_tsif1; + } + device->tsif[1].base = ioremap(mem_tsif1->start, + resource_size(mem_tsif1)); + if (!device->tsif[1].base) { + pr_err("%s: ioremap failed\n", __func__); + goto err_map_tsif1; + } + + mem_tspp = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "MSM_TSPP_PHYS"); + if (!mem_tspp) { + pr_err("%s: missing MEM resource\n", __func__); + rc = -ENXIO; + goto err_res_dev; + } + device->base = ioremap(mem_tspp->start, resource_size(mem_tspp)); + if (!device->base) { + pr_err("%s: ioremap failed\n", __func__); + goto err_map_dev; + } + + mem_bam = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "MSM_TSPP_BAM_PHYS"); + if (!mem_bam) { + pr_err("%s: Missing bam MEM resource\n", __func__); + rc = -ENXIO; + goto err_res_bam; + } + memset(&device->bam_props, 0, sizeof(device->bam_props)); + device->bam_props.phys_addr = mem_bam->start; + device->bam_props.virt_addr = ioremap(mem_bam->start, + resource_size(mem_bam)); + if (!device->bam_props.virt_addr) { + pr_err("%s: ioremap failed\n", __func__); + goto err_map_bam; + } + + if (msm_tspp_map_irqs(pdev, device)) + goto err_irq; + device->req_irqs = false; + + if (tspp_iommu_init(device)) + goto err_iommu; + + device->tts_source = TSIF_TTS_TCR; + for (i = 0; i < TSPP_TSIF_INSTANCES; i++) + device->tsif[i].tts_source = device->tts_source; + + /* power management */ + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + tspp_debugfs_init(device, 0); + + for (i = 0; i < TSPP_TSIF_INSTANCES; i++) + tsif_debugfs_init(&device->tsif[i], i); + + wakeup_source_init(&device->ws, dev_name(&pdev->dev)); + + /* set up pointers to ram-based 'registers' */ + device->filters[0] = device->base + TSPP_PID_FILTER_TABLE0; + device->filters[1] = device->base + TSPP_PID_FILTER_TABLE1; + device->filters[2] = device->base + TSPP_PID_FILTER_TABLE2; + device->tspp_key_table = device->base + TSPP_DATA_KEY; + device->tspp_global_performance = + device->base + TSPP_GLOBAL_PERFORMANCE; + device->tspp_pipe_context = + device->base + TSPP_PIPE_CONTEXT; + device->tspp_pipe_performance = + device->base + TSPP_PIPE_PERFORMANCE; + + device->bam_props.summing_threshold = 0x10; + device->bam_props.irq = device->bam_irq; + device->bam_props.manage = SPS_BAM_MGR_LOCAL; + /*add SPS BAM log level*/ + device->bam_props.ipc_loglevel = TSPP_BAM_DEFAULT_IPC_LOGLVL; + + if (tspp_clock_start(device) != 0) { + pr_err("%s: Can't start clocks\n", __func__); + goto err_clock; + } + + device->bam_handle = SPS_DEV_HANDLE_INVALID; + + spin_lock_init(&device->spinlock); + mutex_init(&device->mutex); + tasklet_init(&device->tlet, tspp_sps_complete_tlet, + (unsigned long)device); + + /* initialize everything to a known state */ + tspp_global_reset(device); + + version = readl_relaxed(device->base + TSPP_VERSION); + /* + * TSPP version can be bits [7:0] or alternatively, + * TSPP major version is bits [31:28]. + */ + if ((version != 0x1) && (((version >> 28) & 0xF) != 0x1)) + pr_err("%s: unrecognized hw version=%d\n", __func__, version); + + /* initialize the channels */ + for (i = 0; i < TSPP_NUM_CHANNELS; i++) + tspp_channel_init(&(device->channels[i]), device); + + /* stop the clocks for power savings */ + tspp_clock_stop(device); + + /* everything is ok, so add the device to the list */ + list_add_tail(&(device->devlist), &tspp_devices); + return 0; + +err_clock: + tspp_debugfs_exit(device); + for (i = 0; i < TSPP_TSIF_INSTANCES; i++) + tsif_debugfs_exit(&device->tsif[i]); +err_iommu: + tspp_iommu_release_iomapping(device); +err_irq: + iounmap(device->bam_props.virt_addr); +err_map_bam: +err_res_bam: + iounmap(device->base); +err_map_dev: +err_res_dev: + iounmap(device->tsif[1].base); +err_map_tsif1: +err_res_tsif1: + iounmap(device->tsif[0].base); +err_map_tsif0: +err_res_tsif0: + if (device->tsif_ref_clk) + clk_put(device->tsif_ref_clk); +err_refclock: + if (device->tsif_pclk) + clk_put(device->tsif_pclk); +err_pclock: + if (device->tsif_vreg) + regulator_disable(device->tsif_vreg); +err_regulator: + if (device->tsif_bus_client) + msm_bus_scale_unregister_client(device->tsif_bus_client); +err_pinctrl: + kfree(device); + +out: + return rc; +} + +static int msm_tspp_remove(struct platform_device *pdev) +{ + struct tspp_channel *channel; + u32 i; + + struct tspp_device *device = platform_get_drvdata(pdev); + + /* free the buffers, and delete the channels */ + for (i = 0; i < TSPP_NUM_CHANNELS; i++) { + channel = &device->channels[i]; + tspp_close_channel(device->pdev->id, i); + } + + for (i = 0; i < TSPP_TSIF_INSTANCES; i++) + tsif_debugfs_exit(&device->tsif[i]); + + mutex_destroy(&device->mutex); + + if (device->tsif_bus_client) + msm_bus_scale_unregister_client(device->tsif_bus_client); + + wakeup_source_trash(&device->ws); + if (device->req_irqs) + msm_tspp_free_irqs(device); + + iounmap(device->bam_props.virt_addr); + iounmap(device->base); + for (i = 0; i < TSPP_TSIF_INSTANCES; i++) + iounmap(device->tsif[i].base); + + if (device->tsif_ref_clk) + clk_put(device->tsif_ref_clk); + + if (device->tsif_pclk) + clk_put(device->tsif_pclk); + + if (device->tsif_vreg) + regulator_disable(device->tsif_vreg); + + tspp_iommu_release_iomapping(device); + arm_iommu_detach_device(&pdev->dev); + + pm_runtime_disable(&pdev->dev); + + kfree(device); + + return 0; +} + +/*** power management ***/ + +static int tspp_runtime_suspend(struct device *dev) +{ + pr_debug("%s: pm_runtime: suspending\n", __func__); + return 0; +} + +static int tspp_runtime_resume(struct device *dev) +{ + pr_debug("%s: pm_runtime: resuming\n", __func__); + return 0; +} + +static const struct dev_pm_ops tspp_dev_pm_ops = { + .runtime_suspend = tspp_runtime_suspend, + .runtime_resume = tspp_runtime_resume, +}; + +static const struct of_device_id msm_match_table[] = { + {.compatible = "qcom,msm_tspp"}, + {}, +}; + +static struct platform_driver msm_tspp_driver = { + .probe = msm_tspp_probe, + .remove = msm_tspp_remove, + .driver = { + .name = "msm_tspp", + .pm = &tspp_dev_pm_ops, + .of_match_table = msm_match_table, + }, +}; + + +static int __init mod_init(void) +{ + int rc; + + /* register the driver, and check hardware */ + rc = platform_driver_register(&msm_tspp_driver); + if (rc) + pr_err("%s: platform_driver_register failed: %d\n", + __func__, rc); + + return rc; +} + +static void __exit mod_exit(void) +{ + /* delete low level driver */ + platform_driver_unregister(&msm_tspp_driver); +} + +module_init(mod_init); +module_exit(mod_exit); + +MODULE_DESCRIPTION("TSPP platform device"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/dvb/Kconfig b/drivers/media/platform/msm/dvb/Kconfig new file mode 100644 index 000000000000..e205c8172075 --- /dev/null +++ b/drivers/media/platform/msm/dvb/Kconfig @@ -0,0 +1,10 @@ +config DVB_MPQ + tristate "Qualcomm Technologies Inc Multimedia Processor DVB Adapter" + depends on ARCH_QCOM && DVB_CORE + default n + + help + Support for Qualcomm Technologies Inc MPQ based DVB adapter. + Say Y or M if you own such a device and want to use it. + +source "drivers/media/platform/msm/dvb/demux/Kconfig" diff --git a/drivers/media/platform/msm/dvb/Makefile b/drivers/media/platform/msm/dvb/Makefile new file mode 100644 index 000000000000..81c4d78ae090 --- /dev/null +++ b/drivers/media/platform/msm/dvb/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_DVB_MPQ) += adapter/ +obj-$(CONFIG_DVB_MPQ_DEMUX) += demux/ diff --git a/drivers/media/platform/msm/dvb/adapter/Makefile b/drivers/media/platform/msm/dvb/adapter/Makefile new file mode 100644 index 000000000000..662bf99c4d7e --- /dev/null +++ b/drivers/media/platform/msm/dvb/adapter/Makefile @@ -0,0 +1,7 @@ +ccflags-y += -Idrivers/media/dvb-core/ +ccflags-y += -Idrivers/media/platform/msm/dvb/include/ +ccflags-y += -Idrivers/media/platform/msm/dvb/demux/ + +obj-$(CONFIG_DVB_MPQ) += mpq-adapter.o + +mpq-adapter-y := mpq_adapter.o mpq_stream_buffer.o diff --git a/drivers/media/platform/msm/dvb/adapter/mpq_adapter.c b/drivers/media/platform/msm/dvb/adapter/mpq_adapter.c new file mode 100644 index 000000000000..17f5eda8e514 --- /dev/null +++ b/drivers/media/platform/msm/dvb/adapter/mpq_adapter.c @@ -0,0 +1,208 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include + +#include "mpq_adapter.h" +#include "mpq_dvb_debug.h" + + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +/* data-structure holding MPQ adapter information */ +static struct +{ + /* MPQ adapter registered to dvb-core */ + struct dvb_adapter adapter; + + /* mutex protect against the data-structure */ + struct mutex mutex; + + /* List of stream interfaces registered to the MPQ adapter */ + struct { + /* pointer to the stream buffer using for data tunneling */ + struct mpq_streambuffer *stream_buffer; + + /* callback triggered when the stream interface is registered */ + mpq_adapter_stream_if_callback callback; + + /* parameter passed to the callback function */ + void *user_param; + } interfaces[MPQ_ADAPTER_MAX_NUM_OF_INTERFACES]; +} mpq_info; + + +/** + * Initialize MPQ DVB adapter module. + * + * Return error status + */ +static int __init mpq_adapter_init(void) +{ + int i; + int result; + + MPQ_DVB_DBG_PRINT("%s executed\n", __func__); + + mutex_init(&mpq_info.mutex); + + /* reset stream interfaces list */ + for (i = 0; i < MPQ_ADAPTER_MAX_NUM_OF_INTERFACES; i++) { + mpq_info.interfaces[i].stream_buffer = NULL; + mpq_info.interfaces[i].callback = NULL; + } + + /* register a new dvb-adapter to dvb-core */ + result = dvb_register_adapter(&mpq_info.adapter, + "Qualcomm Technologies, Inc. DVB adapter", + THIS_MODULE, NULL, adapter_nr); + if (result < 0) { + MPQ_DVB_ERR_PRINT( + "%s: dvb_register_adapter failed, errno %d\n", + __func__, + result); + } + + return result; +} + + +/** + * Cleanup MPQ DVB adapter module. + */ +static void __exit mpq_adapter_exit(void) +{ + MPQ_DVB_DBG_PRINT("%s executed\n", __func__); + + /* un-register adapter from dvb-core */ + dvb_unregister_adapter(&mpq_info.adapter); + mutex_destroy(&mpq_info.mutex); +} + +struct dvb_adapter *mpq_adapter_get(void) +{ + return &mpq_info.adapter; +} +EXPORT_SYMBOL(mpq_adapter_get); + + +int mpq_adapter_register_stream_if( + enum mpq_adapter_stream_if interface_id, + struct mpq_streambuffer *stream_buffer) +{ + int ret; + + if (interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES) { + ret = -EINVAL; + goto register_failed; + } + + if (mutex_lock_interruptible(&mpq_info.mutex)) { + ret = -ERESTARTSYS; + goto register_failed; + } + + if (mpq_info.interfaces[interface_id].stream_buffer != NULL) { + /* already registered interface */ + ret = -EINVAL; + goto register_failed_unlock_mutex; + } + + mpq_info.interfaces[interface_id].stream_buffer = stream_buffer; + mutex_unlock(&mpq_info.mutex); + + /* + * If callback is installed, trigger it to notify that + * stream interface was registered. + */ + if (mpq_info.interfaces[interface_id].callback != NULL) { + mpq_info.interfaces[interface_id].callback( + interface_id, + mpq_info.interfaces[interface_id].user_param); + } + + return 0; + +register_failed_unlock_mutex: + mutex_unlock(&mpq_info.mutex); +register_failed: + return ret; +} +EXPORT_SYMBOL(mpq_adapter_register_stream_if); + + +int mpq_adapter_unregister_stream_if( + enum mpq_adapter_stream_if interface_id) +{ + if (interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES) + return -EINVAL; + + if (mutex_lock_interruptible(&mpq_info.mutex)) + return -ERESTARTSYS; + + /* clear the registered interface */ + mpq_info.interfaces[interface_id].stream_buffer = NULL; + + mutex_unlock(&mpq_info.mutex); + + return 0; +} +EXPORT_SYMBOL(mpq_adapter_unregister_stream_if); + + +int mpq_adapter_get_stream_if( + enum mpq_adapter_stream_if interface_id, + struct mpq_streambuffer **stream_buffer) +{ + if ((interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES) || + (stream_buffer == NULL)) + return -EINVAL; + + if (mutex_lock_interruptible(&mpq_info.mutex)) + return -ERESTARTSYS; + + *stream_buffer = mpq_info.interfaces[interface_id].stream_buffer; + + mutex_unlock(&mpq_info.mutex); + + return 0; +} +EXPORT_SYMBOL(mpq_adapter_get_stream_if); + + +int mpq_adapter_notify_stream_if( + enum mpq_adapter_stream_if interface_id, + mpq_adapter_stream_if_callback callback, + void *user_param) +{ + if (interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES) + return -EINVAL; + + if (mutex_lock_interruptible(&mpq_info.mutex)) + return -ERESTARTSYS; + + mpq_info.interfaces[interface_id].callback = callback; + mpq_info.interfaces[interface_id].user_param = user_param; + + mutex_unlock(&mpq_info.mutex); + + return 0; +} +EXPORT_SYMBOL(mpq_adapter_notify_stream_if); + + +module_init(mpq_adapter_init); +module_exit(mpq_adapter_exit); + +MODULE_DESCRIPTION("Qualcomm Technologies Inc. MPQ adapter"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/dvb/adapter/mpq_stream_buffer.c b/drivers/media/platform/msm/dvb/adapter/mpq_stream_buffer.c new file mode 100644 index 000000000000..2fb0fb67bd7a --- /dev/null +++ b/drivers/media/platform/msm/dvb/adapter/mpq_stream_buffer.c @@ -0,0 +1,825 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include "mpq_dvb_debug.h" +#include "mpq_stream_buffer.h" + + +int mpq_streambuffer_init( + struct mpq_streambuffer *sbuff, + enum mpq_streambuffer_mode mode, + struct mpq_streambuffer_buffer_desc *data_buffers, + u32 data_buff_num, + void *packet_buff, + size_t packet_buff_size) +{ + if ((sbuff == NULL) || (data_buffers == NULL) || + (packet_buff == NULL) || (data_buff_num == 0)) + return -EINVAL; + + if (data_buff_num > 1) { + if (mode != MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) + return -EINVAL; + /* Linear buffer group */ + dvb_ringbuffer_init( + &sbuff->raw_data, + data_buffers, + data_buff_num * + sizeof(struct mpq_streambuffer_buffer_desc)); + } else { + if (mode != MPQ_STREAMBUFFER_BUFFER_MODE_RING) + return -EINVAL; + /* Single ring-buffer */ + dvb_ringbuffer_init(&sbuff->raw_data, + data_buffers[0].base, data_buffers[0].size); + } + sbuff->mode = mode; + sbuff->buffers = data_buffers; + sbuff->pending_buffers_count = 0; + sbuff->buffers_num = data_buff_num; + sbuff->cb = NULL; + dvb_ringbuffer_init(&sbuff->packet_data, packet_buff, packet_buff_size); + + return 0; +} +EXPORT_SYMBOL(mpq_streambuffer_init); + +void mpq_streambuffer_terminate(struct mpq_streambuffer *sbuff) +{ + spin_lock(&sbuff->packet_data.lock); + spin_lock(&sbuff->raw_data.lock); + sbuff->packet_data.error = -ENODEV; + sbuff->raw_data.error = -ENODEV; + spin_unlock(&sbuff->raw_data.lock); + spin_unlock(&sbuff->packet_data.lock); + + wake_up_all(&sbuff->raw_data.queue); + wake_up_all(&sbuff->packet_data.queue); +} +EXPORT_SYMBOL(mpq_streambuffer_terminate); + +ssize_t mpq_streambuffer_pkt_next( + struct mpq_streambuffer *sbuff, + ssize_t idx, size_t *pktlen) +{ + ssize_t packet_idx; + + spin_lock(&sbuff->packet_data.lock); + + /* buffer was released, return no packet available */ + if (sbuff->packet_data.error == -ENODEV) { + spin_unlock(&sbuff->packet_data.lock); + return -ENODEV; + } + + packet_idx = dvb_ringbuffer_pkt_next(&sbuff->packet_data, idx, pktlen); + spin_unlock(&sbuff->packet_data.lock); + + return packet_idx; +} +EXPORT_SYMBOL(mpq_streambuffer_pkt_next); + + +ssize_t mpq_streambuffer_pkt_read( + struct mpq_streambuffer *sbuff, + size_t idx, + struct mpq_streambuffer_packet_header *packet, + u8 *user_data) +{ + int ret; + size_t read_len; + + spin_lock(&sbuff->packet_data.lock); + + /* buffer was released, return no packet available */ + if (sbuff->packet_data.error == -ENODEV) { + spin_unlock(&sbuff->packet_data.lock); + return -ENODEV; + } + + /* read-out the packet header first */ + ret = dvb_ringbuffer_pkt_read( + &sbuff->packet_data, idx, 0, + (u8 *)packet, + sizeof(struct mpq_streambuffer_packet_header)); + + /* verify length, at least packet header should exist */ + if (ret != sizeof(struct mpq_streambuffer_packet_header)) { + spin_unlock(&sbuff->packet_data.lock); + return -EINVAL; + } + + read_len = ret; + + /* read-out private user-data if there are such */ + if ((packet->user_data_len) && (user_data != NULL)) { + ret = dvb_ringbuffer_pkt_read( + &sbuff->packet_data, + idx, + sizeof(struct mpq_streambuffer_packet_header), + user_data, + packet->user_data_len); + + if (ret < 0) { + spin_unlock(&sbuff->packet_data.lock); + return ret; + } + + read_len += ret; + } + + spin_unlock(&sbuff->packet_data.lock); + + return read_len; +} +EXPORT_SYMBOL(mpq_streambuffer_pkt_read); + + +int mpq_streambuffer_pkt_dispose( + struct mpq_streambuffer *sbuff, + size_t idx, + int dispose_data) +{ + int ret; + struct mpq_streambuffer_packet_header packet; + + if (sbuff == NULL) + return -EINVAL; + + spin_lock(&sbuff->packet_data.lock); + + /* check if buffer was released */ + if (sbuff->packet_data.error == -ENODEV) { + spin_unlock(&sbuff->packet_data.lock); + return -ENODEV; + } + + /* read-out the packet header first */ + ret = dvb_ringbuffer_pkt_read(&sbuff->packet_data, idx, + 0, + (u8 *)&packet, + sizeof(struct mpq_streambuffer_packet_header)); + + spin_unlock(&sbuff->packet_data.lock); + + if (ret != sizeof(struct mpq_streambuffer_packet_header)) + return -EINVAL; + + if ((sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) || + (dispose_data)) { + /* Advance the read pointer in the raw-data buffer first */ + ret = mpq_streambuffer_data_read_dispose(sbuff, + packet.raw_data_len); + if (ret != 0) + return ret; + } + + spin_lock(&sbuff->packet_data.lock); + spin_lock(&sbuff->raw_data.lock); + + /* check if buffer was released */ + if ((sbuff->packet_data.error == -ENODEV) || + (sbuff->raw_data.error == -ENODEV)) { + spin_unlock(&sbuff->raw_data.lock); + spin_unlock(&sbuff->packet_data.lock); + return -ENODEV; + } + + /* Move read pointer to the next linear buffer for subsequent reads */ + if ((sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) && + (packet.raw_data_len > 0)) { + struct mpq_streambuffer_buffer_desc *desc; + + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pread]; + + desc->write_ptr = 0; + desc->read_ptr = 0; + + DVB_RINGBUFFER_SKIP(&sbuff->raw_data, + sizeof(struct mpq_streambuffer_buffer_desc)); + sbuff->pending_buffers_count--; + + wake_up_all(&sbuff->raw_data.queue); + } + + /* Now clear the packet from the packet header */ + dvb_ringbuffer_pkt_dispose(&sbuff->packet_data, idx); + + spin_unlock(&sbuff->raw_data.lock); + spin_unlock(&sbuff->packet_data.lock); + + return 0; +} +EXPORT_SYMBOL(mpq_streambuffer_pkt_dispose); + +int mpq_streambuffer_pkt_write( + struct mpq_streambuffer *sbuff, + struct mpq_streambuffer_packet_header *packet, + u8 *user_data) +{ + ssize_t idx; + size_t len; + + if ((sbuff == NULL) || (packet == NULL)) + return -EINVAL; + + spin_lock(&sbuff->packet_data.lock); + + /* check if buffer was released */ + if (sbuff->packet_data.error == -ENODEV) { + spin_unlock(&sbuff->packet_data.lock); + return -ENODEV; + } + + /* Make sure we can go to the next linear buffer */ + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR && + sbuff->pending_buffers_count == sbuff->buffers_num && + packet->raw_data_len) { + spin_unlock(&sbuff->packet_data.lock); + return -ENOSPC; + } + + len = sizeof(struct mpq_streambuffer_packet_header) + + packet->user_data_len; + + /* Make sure enough space available for packet header */ + if (dvb_ringbuffer_free(&sbuff->packet_data) < + (len + DVB_RINGBUFFER_PKTHDRSIZE)) { + spin_unlock(&sbuff->packet_data.lock); + return -ENOSPC; + } + + /* Starting writing packet header */ + idx = dvb_ringbuffer_pkt_start(&sbuff->packet_data, len); + + /* Write non-user private data header */ + dvb_ringbuffer_write(&sbuff->packet_data, + (u8 *)packet, + sizeof(struct mpq_streambuffer_packet_header)); + + /* Write user's own private data header */ + dvb_ringbuffer_write(&sbuff->packet_data, + user_data, + packet->user_data_len); + + dvb_ringbuffer_pkt_close(&sbuff->packet_data, idx); + + /* Move write pointer to next linear buffer for subsequent writes */ + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR && + packet->raw_data_len) { + DVB_RINGBUFFER_PUSH(&sbuff->raw_data, + sizeof(struct mpq_streambuffer_buffer_desc)); + sbuff->pending_buffers_count++; + } + + spin_unlock(&sbuff->packet_data.lock); + wake_up_all(&sbuff->packet_data.queue); + + return idx; +} +EXPORT_SYMBOL(mpq_streambuffer_pkt_write); + +ssize_t mpq_streambuffer_data_write( + struct mpq_streambuffer *sbuff, + const u8 *buf, size_t len) +{ + int res; + + if ((sbuff == NULL) || (buf == NULL)) + return -EINVAL; + + spin_lock(&sbuff->raw_data.lock); + + /* check if buffer was released */ + if (sbuff->raw_data.error == -ENODEV) { + spin_unlock(&sbuff->raw_data.lock); + return -ENODEV; + } + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) { + if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len)) { + spin_unlock(&sbuff->raw_data.lock); + return -ENOSPC; + } + /* + * Secure buffers are not permitted to be mapped into kernel + * memory, and so buffer base address may be NULL + */ + if (sbuff->raw_data.data == NULL) { + spin_unlock(&sbuff->raw_data.lock); + return -EPERM; + } + res = dvb_ringbuffer_write(&sbuff->raw_data, buf, len); + wake_up_all(&sbuff->raw_data.queue); + } else { + /* Linear buffer group */ + struct mpq_streambuffer_buffer_desc *desc; + + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pwrite]; + + /* + * Secure buffers are not permitted to be mapped into kernel + * memory, and so buffer base address may be NULL + */ + if (desc->base == NULL) { + spin_unlock(&sbuff->raw_data.lock); + return -EPERM; + } + + if ((sbuff->pending_buffers_count == sbuff->buffers_num) || + ((desc->size - desc->write_ptr) < len)) { + MPQ_DVB_DBG_PRINT( + "%s: No space available %d pending buffers out of %d", + __func__, + sbuff->pending_buffers_count, + sbuff->buffers_num); + spin_unlock(&sbuff->raw_data.lock); + return -ENOSPC; + } + memcpy(desc->base + desc->write_ptr, buf, len); + desc->write_ptr += len; + res = len; + } + + spin_unlock(&sbuff->raw_data.lock); + return res; +} +EXPORT_SYMBOL(mpq_streambuffer_data_write); + + +int mpq_streambuffer_data_write_deposit( + struct mpq_streambuffer *sbuff, + size_t len) +{ + if (sbuff == NULL) + return -EINVAL; + + spin_lock(&sbuff->raw_data.lock); + + /* check if buffer was released */ + if (sbuff->raw_data.error == -ENODEV) { + spin_unlock(&sbuff->raw_data.lock); + return -ENODEV; + } + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) { + if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len)) { + spin_unlock(&sbuff->raw_data.lock); + return -ENOSPC; + } + + DVB_RINGBUFFER_PUSH(&sbuff->raw_data, len); + wake_up_all(&sbuff->raw_data.queue); + } else { + /* Linear buffer group */ + struct mpq_streambuffer_buffer_desc *desc = + (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pwrite]; + + if ((sbuff->pending_buffers_count == sbuff->buffers_num) || + ((desc->size - desc->write_ptr) < len)) { + MPQ_DVB_ERR_PRINT( + "%s: No space available\n", + __func__); + spin_unlock(&sbuff->raw_data.lock); + return -ENOSPC; + } + desc->write_ptr += len; + } + + spin_unlock(&sbuff->raw_data.lock); + return 0; +} +EXPORT_SYMBOL(mpq_streambuffer_data_write_deposit); + + +ssize_t mpq_streambuffer_data_read( + struct mpq_streambuffer *sbuff, + u8 *buf, size_t len) +{ + ssize_t actual_len = 0; + u32 offset; + + if ((sbuff == NULL) || (buf == NULL)) + return -EINVAL; + + spin_lock(&sbuff->raw_data.lock); + + /* check if buffer was released */ + if (sbuff->raw_data.error == -ENODEV) { + spin_unlock(&sbuff->raw_data.lock); + return -ENODEV; + } + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) { + /* + * Secure buffers are not permitted to be mapped into kernel + * memory, and so buffer base address may be NULL + */ + if (sbuff->raw_data.data == NULL) { + spin_unlock(&sbuff->raw_data.lock); + return -EPERM; + } + + offset = sbuff->raw_data.pread; + actual_len = dvb_ringbuffer_avail(&sbuff->raw_data); + if (actual_len < len) + len = actual_len; + if (len) + dvb_ringbuffer_read(&sbuff->raw_data, buf, len); + + wake_up_all(&sbuff->raw_data.queue); + } else { + /* Linear buffer group */ + struct mpq_streambuffer_buffer_desc *desc; + + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pread]; + + /* + * Secure buffers are not permitted to be mapped into kernel + * memory, and so buffer base address may be NULL + */ + if (desc->base == NULL) { + spin_unlock(&sbuff->raw_data.lock); + return -EPERM; + } + + actual_len = (desc->write_ptr - desc->read_ptr); + if (actual_len < len) + len = actual_len; + memcpy(buf, desc->base + desc->read_ptr, len); + offset = desc->read_ptr; + desc->read_ptr += len; + } + + spin_unlock(&sbuff->raw_data.lock); + + if (sbuff->cb) + sbuff->cb(sbuff, offset, len, sbuff->cb_user_data); + + return len; +} +EXPORT_SYMBOL(mpq_streambuffer_data_read); + + +ssize_t mpq_streambuffer_data_read_user( + struct mpq_streambuffer *sbuff, + u8 __user *buf, size_t len) +{ + ssize_t actual_len = 0; + u32 offset; + + if ((sbuff == NULL) || (buf == NULL)) + return -EINVAL; + + /* check if buffer was released */ + if (sbuff->raw_data.error == -ENODEV) + return -ENODEV; + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) { + /* + * Secure buffers are not permitted to be mapped into kernel + * memory, and so buffer base address may be NULL + */ + if (sbuff->raw_data.data == NULL) + return -EPERM; + + offset = sbuff->raw_data.pread; + actual_len = dvb_ringbuffer_avail(&sbuff->raw_data); + if (actual_len < len) + len = actual_len; + if (len) + dvb_ringbuffer_read_user(&sbuff->raw_data, buf, len); + wake_up_all(&sbuff->raw_data.queue); + } else { + /* Linear buffer group */ + struct mpq_streambuffer_buffer_desc *desc; + + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pread]; + + /* + * Secure buffers are not permitted to be mapped into kernel + * memory, and so buffer base address may be NULL + */ + if (desc->base == NULL) + return -EPERM; + + actual_len = (desc->write_ptr - desc->read_ptr); + if (actual_len < len) + len = actual_len; + if (copy_to_user(buf, desc->base + desc->read_ptr, len)) + return -EFAULT; + + offset = desc->read_ptr; + desc->read_ptr += len; + } + + if (sbuff->cb) + sbuff->cb(sbuff, offset, len, sbuff->cb_user_data); + + return len; +} +EXPORT_SYMBOL(mpq_streambuffer_data_read_user); + +int mpq_streambuffer_data_read_dispose( + struct mpq_streambuffer *sbuff, + size_t len) +{ + u32 offset; + + if (sbuff == NULL) + return -EINVAL; + + spin_lock(&sbuff->raw_data.lock); + + /* check if buffer was released */ + if (sbuff->raw_data.error == -ENODEV) { + spin_unlock(&sbuff->raw_data.lock); + return -ENODEV; + } + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) { + if (unlikely(dvb_ringbuffer_avail(&sbuff->raw_data) < len)) { + spin_unlock(&sbuff->raw_data.lock); + return -EINVAL; + } + + offset = sbuff->raw_data.pread; + DVB_RINGBUFFER_SKIP(&sbuff->raw_data, len); + wake_up_all(&sbuff->raw_data.queue); + } else { + struct mpq_streambuffer_buffer_desc *desc; + + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pread]; + offset = desc->read_ptr; + + if ((desc->read_ptr + len) > desc->size) + desc->read_ptr = desc->size; + else + desc->read_ptr += len; + } + + spin_unlock(&sbuff->raw_data.lock); + + if (sbuff->cb) + sbuff->cb(sbuff, offset, len, sbuff->cb_user_data); + + return 0; +} +EXPORT_SYMBOL(mpq_streambuffer_data_read_dispose); + + +int mpq_streambuffer_get_buffer_handle( + struct mpq_streambuffer *sbuff, + int read_buffer, + int *handle) +{ + struct mpq_streambuffer_buffer_desc *desc = NULL; + + if ((sbuff == NULL) || (handle == NULL)) + return -EINVAL; + + spin_lock(&sbuff->raw_data.lock); + + /* check if buffer was released */ + if (sbuff->raw_data.error == -ENODEV) { + spin_unlock(&sbuff->raw_data.lock); + return -ENODEV; + } + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) { + *handle = sbuff->buffers[0].handle; + } else { + if (read_buffer) + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pread]; + else + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pwrite]; + *handle = desc->handle; + } + + spin_unlock(&sbuff->raw_data.lock); + + return 0; +} +EXPORT_SYMBOL(mpq_streambuffer_get_buffer_handle); + + +int mpq_streambuffer_register_data_dispose( + struct mpq_streambuffer *sbuff, + mpq_streambuffer_dispose_cb cb_func, + void *user_data) +{ + if ((sbuff == NULL) || (cb_func == NULL)) + return -EINVAL; + + sbuff->cb = cb_func; + sbuff->cb_user_data = user_data; + + return 0; +} +EXPORT_SYMBOL(mpq_streambuffer_register_data_dispose); + + +ssize_t mpq_streambuffer_data_free( + struct mpq_streambuffer *sbuff) +{ + struct mpq_streambuffer_buffer_desc *desc; + + if (sbuff == NULL) + return -EINVAL; + + spin_lock(&sbuff->raw_data.lock); + + /* check if buffer was released */ + if (sbuff->raw_data.error == -ENODEV) { + spin_unlock(&sbuff->raw_data.lock); + return -ENODEV; + } + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) { + spin_unlock(&sbuff->raw_data.lock); + return dvb_ringbuffer_free(&sbuff->raw_data); + } + + if (sbuff->pending_buffers_count == sbuff->buffers_num) { + spin_unlock(&sbuff->raw_data.lock); + return 0; + } + + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pwrite]; + + spin_unlock(&sbuff->raw_data.lock); + + return desc->size - desc->write_ptr; +} +EXPORT_SYMBOL(mpq_streambuffer_data_free); + + +ssize_t mpq_streambuffer_data_avail( + struct mpq_streambuffer *sbuff) +{ + struct mpq_streambuffer_buffer_desc *desc; + + if (sbuff == NULL) + return -EINVAL; + + spin_lock(&sbuff->raw_data.lock); + + /* check if buffer was released */ + if (sbuff->raw_data.error == -ENODEV) { + spin_unlock(&sbuff->raw_data.lock); + return -ENODEV; + } + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) { + ssize_t avail = dvb_ringbuffer_avail(&sbuff->raw_data); + + spin_unlock(&sbuff->raw_data.lock); + return avail; + } + + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pread]; + + spin_unlock(&sbuff->raw_data.lock); + + return desc->write_ptr - desc->read_ptr; +} +EXPORT_SYMBOL(mpq_streambuffer_data_avail); + +int mpq_streambuffer_get_data_rw_offset( + struct mpq_streambuffer *sbuff, + u32 *read_offset, + u32 *write_offset) +{ + if (sbuff == NULL) + return -EINVAL; + + spin_lock(&sbuff->raw_data.lock); + + /* check if buffer was released */ + if (sbuff->raw_data.error == -ENODEV) { + spin_unlock(&sbuff->raw_data.lock); + return -ENODEV; + } + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_RING) { + if (read_offset) + *read_offset = sbuff->raw_data.pread; + if (write_offset) + *write_offset = sbuff->raw_data.pwrite; + } else { + struct mpq_streambuffer_buffer_desc *desc; + + if (read_offset) { + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pread]; + *read_offset = desc->read_ptr; + } + if (write_offset) { + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pwrite]; + *write_offset = desc->write_ptr; + } + } + + spin_unlock(&sbuff->raw_data.lock); + + return 0; +} +EXPORT_SYMBOL(mpq_streambuffer_get_data_rw_offset); + +ssize_t mpq_streambuffer_metadata_free(struct mpq_streambuffer *sbuff) +{ + ssize_t free; + + if (sbuff == NULL) + return -EINVAL; + + spin_lock(&sbuff->packet_data.lock); + + /* check if buffer was released */ + if (sbuff->packet_data.error == -ENODEV) { + spin_unlock(&sbuff->packet_data.lock); + return -ENODEV; + } + + free = dvb_ringbuffer_free(&sbuff->packet_data); + + spin_unlock(&sbuff->packet_data.lock); + + return free; +} +EXPORT_SYMBOL(mpq_streambuffer_metadata_free); + +int mpq_streambuffer_flush(struct mpq_streambuffer *sbuff) +{ + struct mpq_streambuffer_buffer_desc *desc; + size_t len; + int idx; + int ret = 0; + + if (sbuff == NULL) + return -EINVAL; + + spin_lock(&sbuff->packet_data.lock); + spin_lock(&sbuff->raw_data.lock); + + /* Check if buffer was released */ + if (sbuff->packet_data.error == -ENODEV || + sbuff->raw_data.error == -ENODEV) { + ret = -ENODEV; + goto end; + } + + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) + while (sbuff->pending_buffers_count) { + desc = (struct mpq_streambuffer_buffer_desc *) + &sbuff->raw_data.data[sbuff->raw_data.pread]; + desc->write_ptr = 0; + desc->read_ptr = 0; + DVB_RINGBUFFER_SKIP(&sbuff->raw_data, + sizeof(struct mpq_streambuffer_buffer_desc)); + sbuff->pending_buffers_count--; + } + else + dvb_ringbuffer_flush(&sbuff->raw_data); + + /* + * Dispose all packets (simply flushing is not enough since we want + * the packets' status to move to disposed). + */ + do { + idx = dvb_ringbuffer_pkt_next(&sbuff->packet_data, -1, &len); + if (idx >= 0) + dvb_ringbuffer_pkt_dispose(&sbuff->packet_data, idx); + } while (idx >= 0); + +end: + spin_unlock(&sbuff->raw_data.lock); + spin_unlock(&sbuff->packet_data.lock); + return ret; +} +EXPORT_SYMBOL(mpq_streambuffer_flush); diff --git a/drivers/media/platform/msm/dvb/demux/Kconfig b/drivers/media/platform/msm/dvb/demux/Kconfig new file mode 100644 index 000000000000..5b10e2ff36b0 --- /dev/null +++ b/drivers/media/platform/msm/dvb/demux/Kconfig @@ -0,0 +1,38 @@ +comment "Qualcomm Technologies, Inc. Demux device config" +menuconfig DVB_MPQ_DEMUX + tristate "DVB Demux Device" + depends on DVB_MPQ && ION + default n + + help + Support for Qualcomm Technologies Inc based dvb demux device. + Say Y if you own such a device and want to use it. + The Demux device is used to stream playback either + from TSIF interface or from DVR interface. + +config DVB_MPQ_NUM_DMX_DEVICES + int "Number of demux devices" + depends on DVB_MPQ_DEMUX + default 4 + range 1 255 + + help + Configure number of demux devices. + Depends on your use-cases for maximum concurrent stream playback. + +config DVB_MPQ_TSPP1 + bool "TSPPv1 plugin" + depends on DVB_MPQ_DEMUX && TSPP + help + Use this option if your HW has + Transport Stream Packet Processor(TSPP) version1 support. + Demux may take adavantage of HW capabilities to perform + some tasks in HW instead of SW. + +config DVB_MPQ_SW + bool "Software plugin" + depends on DVB_MPQ_DEMUX && !DVB_MPQ_TSPP1 + help + Use this option if your HW does not have any + TSPP hardware support. All demux tasks will be + performed in SW. diff --git a/drivers/media/platform/msm/dvb/demux/Makefile b/drivers/media/platform/msm/dvb/demux/Makefile new file mode 100644 index 000000000000..c08fa85a8d5d --- /dev/null +++ b/drivers/media/platform/msm/dvb/demux/Makefile @@ -0,0 +1,14 @@ + +ccflags-y += -Idrivers/media/dvb-core/ +ccflags-y += -Idrivers/media/platform/msm/dvb/include/ +ccflags-y += -Idrivers/misc/ + +obj-$(CONFIG_DVB_MPQ_DEMUX) += mpq-dmx-hw-plugin.o + +mpq-dmx-hw-plugin-y := mpq_dmx_plugin_common.o + +mpq-dmx-hw-plugin-$(CONFIG_QSEECOM) += mpq_sdmx.o + +mpq-dmx-hw-plugin-$(CONFIG_DVB_MPQ_TSPP1) += mpq_dmx_plugin_tspp_v1.o + +mpq-dmx-hw-plugin-$(CONFIG_DVB_MPQ_SW) += mpq_dmx_plugin_sw.o diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c new file mode 100644 index 000000000000..06d05f9512af --- /dev/null +++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c @@ -0,0 +1,5204 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include "mpq_dvb_debug.h" +#include "mpq_dmx_plugin_common.h" +#include "mpq_sdmx.h" +#include +#include +#include +#include +#include + +#define SDMX_MAJOR_VERSION_MATCH (8) + +/* Length of mandatory fields that must exist in header of video PES */ +#define PES_MANDATORY_FIELDS_LEN 9 + +/* Index of first byte in TS packet holding STC */ +#define STC_LOCATION_IDX 188 + +#define MAX_PES_LENGTH (SZ_64K) + +#define MAX_TS_PACKETS_FOR_SDMX_PROCESS (500) + +/* + * PES header length field is 8 bits so PES header length after this field + * can be up to 256 bytes. + * Preceding fields of the PES header total to 9 bytes + * (including the PES header length field). + */ +#define MAX_PES_HEADER_LENGTH (256 + PES_MANDATORY_FIELDS_LEN) + +/* TS packet with adaptation field only can take up the entire TSP */ +#define MAX_TSP_ADAPTATION_LENGTH (184) + +#define MAX_SDMX_METADATA_LENGTH \ + (TS_PACKET_HEADER_LENGTH + \ + MAX_TSP_ADAPTATION_LENGTH + \ + MAX_PES_HEADER_LENGTH) + +#define SDMX_METADATA_BUFFER_SIZE (64*1024) +#define SDMX_SECTION_BUFFER_SIZE (64*1024) +#define SDMX_PCR_BUFFER_SIZE (64*1024) + +/* Number of demux devices, has default of linux configuration */ +static int mpq_demux_device_num = CONFIG_DVB_MPQ_NUM_DMX_DEVICES; +module_param(mpq_demux_device_num, int, 0444); + +/* ION heap IDs used for allocating video output buffer */ +static int video_secure_ion_heap = ION_CP_MM_HEAP_ID; +module_param(video_secure_ion_heap, int, 0644); +MODULE_PARM_DESC(video_secure_ion_heap, + "ION heap for secure video buffer allocation"); + +static int video_nonsecure_ion_heap = ION_SYSTEM_HEAP_ID; +module_param(video_nonsecure_ion_heap, int, 0644); +MODULE_PARM_DESC(video_nonsecure_ion_heap, + "ION heap for non-secure video buffer allocation"); + +/* Value of TS packet scramble bits field for even key */ +static int mpq_sdmx_scramble_even = 0x2; +module_param(mpq_sdmx_scramble_even, int, 0644); + +/* Value of TS packet scramble bits field for odd key */ +static int mpq_sdmx_scramble_odd = 0x3; +module_param(mpq_sdmx_scramble_odd, int, 0644); + +/* + * Default action (discard or pass) taken when scramble bit is not one of the + * pass-through / odd / even values. + * When set packets will be discarded, otherwise passed through. + */ +static int mpq_sdmx_scramble_default_discard = 1; +module_param(mpq_sdmx_scramble_default_discard, int, 0644); + +/* Max number of TS packets allowed as input for a single sdmx process */ +static int mpq_sdmx_proc_limit = MAX_TS_PACKETS_FOR_SDMX_PROCESS; +module_param(mpq_sdmx_proc_limit, int, 0644); + +/* Debug flag for secure demux process */ +static int mpq_sdmx_debug; +module_param(mpq_sdmx_debug, int, 0644); + +/* + * Indicates whether the demux should search for frame boundaries + * and notify on video packets on frame-basis or whether to provide + * only video PES packet payloads as-is. + */ +static int video_framing = 1; +module_param(video_framing, int, 0644); + +/* TSIF operation mode: 1 = TSIF_MODE_1, 2 = TSIF_MODE_2, 3 = TSIF_LOOPBACK */ +static int tsif_mode = 2; +module_param(tsif_mode, int, 0644); + +/* Inverse TSIF clock signal */ +static int clock_inv; +module_param(clock_inv, int, 0644); + +/* Global data-structure for managing demux devices */ +static struct +{ + /* ION demux client used for memory allocation */ + struct ion_client *ion_client; + + /* demux devices array */ + struct mpq_demux *devices; + + /* Stream buffers objects used for tunneling to decoders */ + struct mpq_streambuffer + decoder_buffers[MPQ_ADAPTER_MAX_NUM_OF_INTERFACES]; + + /* Indicates whether secure demux TZ application is available */ + int secure_demux_app_loaded; +} mpq_dmx_info; + + +int mpq_dmx_get_param_scramble_odd(void) +{ + return mpq_sdmx_scramble_odd; +} + +int mpq_dmx_get_param_scramble_even(void) +{ + return mpq_sdmx_scramble_even; +} + +int mpq_dmx_get_param_scramble_default_discard(void) +{ + return mpq_sdmx_scramble_default_discard; +} + +int mpq_dmx_get_param_tsif_mode(void) +{ + return tsif_mode; +} + +int mpq_dmx_get_param_clock_inv(void) +{ + return clock_inv; +} + +/* Check that PES header is valid and that it is a video PES */ +static int mpq_dmx_is_valid_video_pes(struct pes_packet_header *pes_header) +{ + /* start-code valid? */ + if ((pes_header->packet_start_code_prefix_1 != 0) || + (pes_header->packet_start_code_prefix_2 != 0) || + (pes_header->packet_start_code_prefix_3 != 1)) + return -EINVAL; + + /* stream_id is video? */ + if ((pes_header->stream_id & 0xF0) != 0xE0) + return -EINVAL; + + return 0; +} + +/* Check if a framing pattern is a video frame pattern or a header pattern */ +static inline int mpq_dmx_is_video_frame( + enum dmx_video_codec codec, + u64 pattern_type) +{ + switch (codec) { + case DMX_VIDEO_CODEC_MPEG2: + if ((pattern_type == DMX_IDX_MPEG_I_FRAME_START) || + (pattern_type == DMX_IDX_MPEG_P_FRAME_START) || + (pattern_type == DMX_IDX_MPEG_B_FRAME_START)) + return 1; + return 0; + + case DMX_VIDEO_CODEC_H264: + if ((pattern_type == DMX_IDX_H264_IDR_START) || + (pattern_type == DMX_IDX_H264_NON_IDR_START)) + return 1; + return 0; + + case DMX_VIDEO_CODEC_VC1: + if (pattern_type == DMX_IDX_VC1_FRAME_START) + return 1; + return 0; + + default: + return -EINVAL; + } +} + +/* + * mpq_dmx_get_pattern_params - Returns the required video + * patterns for framing operation based on video codec. + * + * @video_codec: the video codec. + * @patterns: a pointer to the pattern parameters, updated by this function. + * @patterns_num: number of patterns, updated by this function. + */ +static inline int mpq_dmx_get_pattern_params( + enum dmx_video_codec video_codec, + const struct dvb_dmx_video_patterns + *patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM], + int *patterns_num) +{ + switch (video_codec) { + case DMX_VIDEO_CODEC_MPEG2: + patterns[0] = dvb_dmx_get_pattern(DMX_IDX_MPEG_SEQ_HEADER); + patterns[1] = dvb_dmx_get_pattern(DMX_IDX_MPEG_GOP); + patterns[2] = dvb_dmx_get_pattern(DMX_IDX_MPEG_I_FRAME_START); + patterns[3] = dvb_dmx_get_pattern(DMX_IDX_MPEG_P_FRAME_START); + patterns[4] = dvb_dmx_get_pattern(DMX_IDX_MPEG_B_FRAME_START); + *patterns_num = 5; + break; + + case DMX_VIDEO_CODEC_H264: + patterns[0] = dvb_dmx_get_pattern(DMX_IDX_H264_SPS); + patterns[1] = dvb_dmx_get_pattern(DMX_IDX_H264_PPS); + patterns[2] = dvb_dmx_get_pattern(DMX_IDX_H264_IDR_START); + patterns[3] = dvb_dmx_get_pattern(DMX_IDX_H264_NON_IDR_START); + patterns[4] = dvb_dmx_get_pattern(DMX_IDX_H264_SEI); + *patterns_num = 5; + break; + + case DMX_VIDEO_CODEC_VC1: + patterns[0] = dvb_dmx_get_pattern(DMX_IDX_VC1_SEQ_HEADER); + patterns[1] = dvb_dmx_get_pattern(DMX_IDX_VC1_ENTRY_POINT); + patterns[2] = dvb_dmx_get_pattern(DMX_IDX_VC1_FRAME_START); + *patterns_num = 3; + break; + + default: + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + *patterns_num = 0; + return -EINVAL; + } + + return 0; +} + +static int mpq_dmx_dmabuf_map(int ion_fd, struct sg_table **sgt, + struct dma_buf_attachment **attach, + struct dma_buf **dmabuf) +{ + struct dma_buf *new_dma_buf = NULL; + struct dma_buf_attachment *new_attach = NULL; + struct sg_table *new_sgt = NULL; + int ret = 0; + + new_dma_buf = dma_buf_get(ion_fd); + if (new_dma_buf == NULL) { + MPQ_DVB_ERR_PRINT("%s: dma_buf_get() for ion_fd %d failed\n", + __func__, ion_fd); + ret = -ENOMEM; + goto err; + } + + new_attach = dma_buf_attach(new_dma_buf, + &mpq_dmx_info.devices[0].pdev->dev); + + if (IS_ERR(new_attach)) { + MPQ_DVB_ERR_PRINT("%s: dma_buf_attach() for ion_fd %d failed\n", + __func__, ion_fd); + ret = -ENOMEM; + goto err_put; + } + + new_sgt = dma_buf_map_attachment(new_attach, DMA_BIDIRECTIONAL); + if (IS_ERR(new_sgt)) { + ret = PTR_ERR(new_sgt); + MPQ_DVB_ERR_PRINT( + "%s: dma_buf_map_attachment for ion_fd %d failed ret = %d\n", + __func__, ion_fd, ret); + goto err_detach; + } + *sgt = new_sgt; + *attach = new_attach; + *dmabuf = new_dma_buf; + + return ret; + +err_detach: + dma_buf_detach(new_dma_buf, new_attach); +err_put: + dma_buf_put(new_dma_buf); +err: + return ret; +} + +static void mpq_dmx_dmabuf_unmap(struct sg_table *sgt, + struct dma_buf_attachment *attach, + struct dma_buf *dmabuf) +{ + dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); + dma_buf_detach(dmabuf, attach); + dma_buf_put(dmabuf); +} + +/* convert ion_fd to phys_adds and virt_addr*/ +static int mpq_dmx_vaddr_map(int ion_fd, + phys_addr_t *paddr, void **vaddr, + struct sg_table **sgt, + struct dma_buf_attachment **attach, + size_t *sb_length, struct dma_buf **dmabuf) +{ + struct dma_buf *new_dma_buf = NULL; + struct dma_buf_attachment *new_attach = NULL; + struct sg_table *new_sgt = NULL; + void *new_va = NULL; + int ret = 0; + + ret = mpq_dmx_dmabuf_map(ion_fd, &new_sgt, &new_attach, &new_dma_buf); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: qseecom_dmabuf_map for ion_fd %d failed ret = %d\n", + __func__, ion_fd, ret); + goto err; + } + + *paddr = sg_dma_address(new_sgt->sgl); + *sb_length = new_sgt->sgl->length; + + dma_buf_begin_cpu_access(new_dma_buf, DMA_BIDIRECTIONAL); + /* TODO: changing kmap to vmap otherwise you need to map + * each 4K chunk need to be mapped and stored its address; + */ + new_va = dma_buf_vmap(new_dma_buf); + if (!new_va) { + MPQ_DVB_ERR_PRINT("%s: dma_buf_kmap failed\n", __func__); + ret = -ENOMEM; + goto err_unmap; + } + *dmabuf = new_dma_buf; + *attach = new_attach; + *sgt = new_sgt; + *vaddr = new_va; + return ret; + +err_unmap: + MPQ_DVB_ERR_PRINT("%s Map fail\n", __func__); + dma_buf_end_cpu_access(new_dma_buf, DMA_BIDIRECTIONAL); + mpq_dmx_dmabuf_unmap(new_sgt, new_attach, new_dma_buf); +err: + MPQ_DVB_ERR_PRINT("%s Init fail\n", __func__); + return ret; +} + +static void mpq_dmx_vaddr_unmap(void *vaddr, struct sg_table *sgt, + struct dma_buf_attachment *attach, + struct dma_buf *dmabuf) +{ + dma_buf_vunmap(dmabuf, vaddr); + dma_buf_end_cpu_access(dmabuf, DMA_BIDIRECTIONAL); + mpq_dmx_dmabuf_unmap(sgt, attach, dmabuf); +} + +static int mpq_dmx_paddr_map(int ion_fd, + phys_addr_t *paddr, + struct sg_table **sgt, + struct dma_buf_attachment **attach, + size_t *sb_length, struct dma_buf **dmabuf) +{ + struct dma_buf *new_dma_buf = NULL; + struct dma_buf_attachment *new_attach = NULL; + struct sg_table *new_sgt = NULL; + int ret = 0; + + ret = mpq_dmx_dmabuf_map(ion_fd, &new_sgt, &new_attach, &new_dma_buf); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: qseecom_dmabuf_map for ion_fd %d failed ret = %d\n", + __func__, ion_fd, ret); + goto err; + } + + *paddr = sg_dma_address(new_sgt->sgl); + *sb_length = new_sgt->sgl->length; + + dma_buf_begin_cpu_access(new_dma_buf, DMA_BIDIRECTIONAL); + *dmabuf = new_dma_buf; + *attach = new_attach; + *sgt = new_sgt; + return ret; + +err: + return ret; +} + +static void mpq_dmx_paddr_unmap(struct sg_table *sgt, + struct dma_buf_attachment *attach, + struct dma_buf *dmabuf) +{ + dma_buf_end_cpu_access(dmabuf, DMA_BIDIRECTIONAL); + mpq_dmx_dmabuf_unmap(sgt, attach, dmabuf); +} + +/* + * mpq_dmx_update_decoder_stat - + * Update decoder output statistics in debug-fs. + * + * @mpq_feed: decoder feed object + */ +void mpq_dmx_update_decoder_stat(struct mpq_feed *mpq_feed) +{ + ktime_t curr_time; + u32 delta_time_ms; + struct mpq_demux *mpq_demux = mpq_feed->mpq_demux; + enum mpq_adapter_stream_if idx; + + if (!dvb_dmx_is_video_feed(mpq_feed->dvb_demux_feed)) + return; + + if (mpq_feed->video_info.stream_interface <= + MPQ_ADAPTER_VIDEO3_STREAM_IF) + idx = mpq_feed->video_info.stream_interface; + else + return; + + curr_time = ktime_get(); + if (unlikely(!mpq_demux->decoder_stat[idx].out_count)) { + mpq_demux->decoder_stat[idx].out_last_time = curr_time; + mpq_demux->decoder_stat[idx].out_count++; + return; + } + + /* calculate time-delta between frame */ + delta_time_ms = mpq_dmx_calc_time_delta(curr_time, + mpq_demux->decoder_stat[idx].out_last_time); + + mpq_demux->decoder_stat[idx].out_interval_sum += delta_time_ms; + + mpq_demux->decoder_stat[idx].out_interval_average = + mpq_demux->decoder_stat[idx].out_interval_sum / + mpq_demux->decoder_stat[idx].out_count; + + if (delta_time_ms > mpq_demux->decoder_stat[idx].out_interval_max) + mpq_demux->decoder_stat[idx].out_interval_max = delta_time_ms; + + mpq_demux->decoder_stat[idx].out_last_time = curr_time; + mpq_demux->decoder_stat[idx].out_count++; +} + +/* + * mpq_dmx_update_sdmx_stat - + * Update SDMX statistics in debug-fs. + * + * @mpq_demux: mpq_demux object + * @bytes_processed: number of bytes processed by sdmx + * @process_start_time: time before sdmx process was triggered + * @process_end_time: time after sdmx process finished + */ +static inline void mpq_dmx_update_sdmx_stat(struct mpq_demux *mpq_demux, + u32 bytes_processed, ktime_t process_start_time, + ktime_t process_end_time) +{ + u32 packets_num; + u32 process_time; + + mpq_demux->sdmx_process_count++; + packets_num = bytes_processed / mpq_demux->demux.ts_packet_size; + mpq_demux->sdmx_process_packets_sum += packets_num; + mpq_demux->sdmx_process_packets_average = + mpq_demux->sdmx_process_packets_sum / + mpq_demux->sdmx_process_count; + + process_time = + mpq_dmx_calc_time_delta(process_end_time, process_start_time); + + mpq_demux->sdmx_process_time_sum += process_time; + mpq_demux->sdmx_process_time_average = + mpq_demux->sdmx_process_time_sum / + mpq_demux->sdmx_process_count; + + if ((mpq_demux->sdmx_process_count == 1) || + (packets_num < mpq_demux->sdmx_process_packets_min)) + mpq_demux->sdmx_process_packets_min = packets_num; + + if ((mpq_demux->sdmx_process_count == 1) || + (process_time > mpq_demux->sdmx_process_time_max)) + mpq_demux->sdmx_process_time_max = process_time; +} + +static int mpq_sdmx_log_level_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t mpq_sdmx_log_level_read(struct file *fp, + char __user *user_buffer, size_t count, loff_t *position) +{ + char user_str[16]; + struct mpq_demux *mpq_demux = fp->private_data; + int ret; + + ret = scnprintf(user_str, 16, "%d", mpq_demux->sdmx_log_level); + ret = simple_read_from_buffer(user_buffer, count, position, + user_str, ret+1); + + return ret; +} + +static ssize_t mpq_sdmx_log_level_write(struct file *fp, + const char __user *user_buffer, size_t count, loff_t *position) +{ + char user_str[16]; + int ret; + int ret_count; + int level; + struct mpq_demux *mpq_demux = fp->private_data; + + if (count == 0 || count >= 16) + return -EINVAL; + + memset(user_str, '\0', sizeof(user_str)); + + ret_count = simple_write_to_buffer(user_str, 15, position, user_buffer, + count); + if (ret_count < 0) + return ret_count; + else if (ret_count == 0) + return -EINVAL; + + ret = kstrtoint(user_str, 0, &level); + if (ret) + return ret; + + if (level < SDMX_LOG_NO_PRINT || level > SDMX_LOG_VERBOSE) + return -EINVAL; + + mutex_lock(&mpq_demux->mutex); + mpq_demux->sdmx_log_level = level; + if (mpq_demux->sdmx_session_handle != SDMX_INVALID_SESSION_HANDLE) { + ret = sdmx_set_log_level(mpq_demux->sdmx_session_handle, + mpq_demux->sdmx_log_level); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: Could not set sdmx log level. ret = %d\n", + __func__, ret); + mutex_unlock(&mpq_demux->mutex); + return -EINVAL; + } + } + + mutex_unlock(&mpq_demux->mutex); + return ret_count; +} + +static const struct file_operations sdmx_debug_fops = { + .open = mpq_sdmx_log_level_open, + .read = mpq_sdmx_log_level_read, + .write = mpq_sdmx_log_level_write, + .owner = THIS_MODULE, +}; + +/* Extend dvb-demux debugfs with common plug-in entries */ +void mpq_dmx_init_debugfs_entries(struct mpq_demux *mpq_demux) +{ + int i; + char file_name[50]; + struct dentry *debugfs_decoder_dir; + + /* + * Extend dvb-demux debugfs with HW statistics. + * Note that destruction of debugfs directory is done + * when dvb-demux is terminated. + */ + mpq_demux->hw_notification_count = 0; + mpq_demux->hw_notification_interval = 0; + mpq_demux->hw_notification_size = 0; + mpq_demux->hw_notification_min_size = 0xFFFFFFFF; + + if (mpq_demux->demux.dmx.debugfs_demux_dir == NULL) + return; + + debugfs_create_u32( + "hw_notification_interval", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->hw_notification_interval); + + debugfs_create_u32( + "hw_notification_min_interval", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->hw_notification_min_interval); + + debugfs_create_u32( + "hw_notification_count", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->hw_notification_count); + + debugfs_create_u32( + "hw_notification_size", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->hw_notification_size); + + debugfs_create_u32( + "hw_notification_min_size", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->hw_notification_min_size); + + debugfs_decoder_dir = debugfs_create_dir("decoder", + mpq_demux->demux.dmx.debugfs_demux_dir); + + for (i = 0; + debugfs_decoder_dir && + (i < MPQ_ADAPTER_MAX_NUM_OF_INTERFACES); + i++) { + snprintf(file_name, 50, "decoder%d_drop_count", i); + debugfs_create_u32( + file_name, + 0444, + debugfs_decoder_dir, + &mpq_demux->decoder_stat[i].drop_count); + + snprintf(file_name, 50, "decoder%d_out_count", i); + debugfs_create_u32( + file_name, + 0444, + debugfs_decoder_dir, + &mpq_demux->decoder_stat[i].out_count); + + snprintf(file_name, 50, "decoder%d_out_interval_sum", i); + debugfs_create_u32( + file_name, + 0444, + debugfs_decoder_dir, + &mpq_demux->decoder_stat[i].out_interval_sum); + + snprintf(file_name, 50, "decoder%d_out_interval_average", i); + debugfs_create_u32( + file_name, + 0444, + debugfs_decoder_dir, + &mpq_demux->decoder_stat[i].out_interval_average); + + snprintf(file_name, 50, "decoder%d_out_interval_max", i); + debugfs_create_u32( + file_name, + 0444, + debugfs_decoder_dir, + &mpq_demux->decoder_stat[i].out_interval_max); + + snprintf(file_name, 50, "decoder%d_ts_errors", i); + debugfs_create_u32( + file_name, + 0444, + debugfs_decoder_dir, + &mpq_demux->decoder_stat[i].ts_errors); + + snprintf(file_name, 50, "decoder%d_cc_errors", i); + debugfs_create_u32( + file_name, + 0444, + debugfs_decoder_dir, + &mpq_demux->decoder_stat[i].cc_errors); + } + + debugfs_create_u32( + "sdmx_process_count", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->sdmx_process_count); + + debugfs_create_u32( + "sdmx_process_time_sum", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->sdmx_process_time_sum); + + debugfs_create_u32( + "sdmx_process_time_average", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->sdmx_process_time_average); + + debugfs_create_u32( + "sdmx_process_time_max", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->sdmx_process_time_max); + + debugfs_create_u32( + "sdmx_process_packets_sum", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->sdmx_process_packets_sum); + + debugfs_create_u32( + "sdmx_process_packets_average", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->sdmx_process_packets_average); + + debugfs_create_u32( + "sdmx_process_packets_min", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + &mpq_demux->sdmx_process_packets_min); + + debugfs_create_file("sdmx_log_level", + 0664, + mpq_demux->demux.dmx.debugfs_demux_dir, + mpq_demux, + &sdmx_debug_fops); +} + +/* Update dvb-demux debugfs with HW notification statistics */ +void mpq_dmx_update_hw_statistics(struct mpq_demux *mpq_demux) +{ + ktime_t curr_time; + u32 delta_time_ms; + + curr_time = ktime_get(); + if (likely(mpq_demux->hw_notification_count)) { + /* calculate time-delta between notifications */ + delta_time_ms = mpq_dmx_calc_time_delta(curr_time, + mpq_demux->last_notification_time); + + mpq_demux->hw_notification_interval = delta_time_ms; + + if ((mpq_demux->hw_notification_count == 1) || + (mpq_demux->hw_notification_interval && + mpq_demux->hw_notification_interval < + mpq_demux->hw_notification_min_interval)) + mpq_demux->hw_notification_min_interval = + mpq_demux->hw_notification_interval; + } + + mpq_demux->hw_notification_count++; + mpq_demux->last_notification_time = curr_time; +} + +static void mpq_sdmx_check_app_loaded(void) +{ + int session; + u32 version; + int ret; + + ret = sdmx_open_session(&session); + if (ret != SDMX_SUCCESS) { + MPQ_DVB_ERR_PRINT( + "%s: Could not initialize session with SDMX. ret = %d\n", + __func__, ret); + mpq_dmx_info.secure_demux_app_loaded = 0; + return; + } + + /* Check proper sdmx major version */ + ret = sdmx_get_version(session, &version); + if (ret != SDMX_SUCCESS) { + MPQ_DVB_ERR_PRINT( + "%s: Could not get sdmx version. ret = %d\n", + __func__, ret); + } else { + if ((version >> 8) != SDMX_MAJOR_VERSION_MATCH) { + MPQ_DVB_ERR_PRINT( + "%s: sdmx major version does not match", + __func__); + MPQ_DVB_ERR_PRINT( + "%s: version : expected=%d, actual=%d\n", + __func__, SDMX_MAJOR_VERSION_MATCH, + (version >> 8)); + } else { + MPQ_DVB_DBG_PRINT( + "%s: sdmx major version is ok = %d\n", + __func__, SDMX_MAJOR_VERSION_MATCH); + } + } + + mpq_dmx_info.secure_demux_app_loaded = 1; + sdmx_close_session(session); +} + +int mpq_dmx_plugin_init(mpq_dmx_init dmx_init_func, + struct platform_device *pdev) +{ + int i; + int j; + int result; + struct mpq_demux *mpq_demux; + struct dvb_adapter *mpq_adapter; + struct mpq_feed *feed; + + if (pdev == NULL) { + MPQ_DVB_ERR_PRINT("%s: NULL platform device\n", __func__); + return -EINVAL; + } + MPQ_DVB_DBG_PRINT("%s executed, device num %d\n", + __func__, + mpq_demux_device_num); + + mpq_adapter = mpq_adapter_get(); + + if (mpq_adapter == NULL) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_adapter is not valid\n", + __func__); + result = -EPERM; + goto init_failed; + } + + if (mpq_demux_device_num == 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_demux_device_num set to 0\n", + __func__); + + result = -EPERM; + goto init_failed; + } + + mpq_dmx_info.devices = NULL; + mpq_dmx_info.ion_client = NULL; + + mpq_dmx_info.secure_demux_app_loaded = 0; + + /* Allocate memory for all MPQ devices */ + mpq_dmx_info.devices = + vzalloc(mpq_demux_device_num*sizeof(struct mpq_demux)); + + if (!mpq_dmx_info.devices) { + result = -ENOMEM; + goto init_failed; + goto init_failed; + } + + /* Initialize and register all demux devices to the system */ + for (i = 0; i < mpq_demux_device_num; i++) { + mpq_demux = mpq_dmx_info.devices+i; + mpq_demux->idx = i; + + /* Set platform device */ + mpq_demux->pdev = pdev; + /* initialize demux source to memory by default */ + mpq_demux->source = DMX_SOURCE_DVR0 + i; + + mutex_init(&mpq_demux->mutex); + + mpq_demux->num_secure_feeds = 0; + mpq_demux->num_active_feeds = 0; + mpq_demux->sdmx_filter_count = 0; + mpq_demux->sdmx_session_handle = SDMX_INVALID_SESSION_HANDLE; + mpq_demux->sdmx_eos = 0; + mpq_demux->sdmx_log_level = SDMX_LOG_NO_PRINT; + mpq_demux->ts_packet_timestamp_source = 0; + mpq_demux->disable_cache_ops = 1; + + if (mpq_demux->demux.feednum > MPQ_MAX_DMX_FILES) { + MPQ_DVB_ERR_PRINT( + "%s: actual feednum (%d) larger than MPQ_MAX_DMX_FILES\n", + __func__, + mpq_demux->demux.feednum); + result = -EINVAL; + goto init_failed_free_demux_devices; + } + + /* Initialize private feed info */ + for (j = 0; j < MPQ_MAX_DMX_FILES; j++) { + feed = &mpq_demux->feeds[j]; + memset(feed, 0, sizeof(*feed)); + feed->sdmx_filter_handle = SDMX_INVALID_FILTER_HANDLE; + feed->mpq_demux = mpq_demux; + feed->session_id = 0; + } + + /* + * mpq_demux_plugin_hw_init should be implemented + * by the specific plugin + */ + result = dmx_init_func(mpq_adapter, mpq_demux); + if (result < 0) { + MPQ_DVB_ERR_PRINT( + "%s: dmx_init_func (errno=%d)\n", + __func__, + result); + + goto init_failed_free_demux_devices; + } + + mpq_demux->is_initialized = 1; + + /* + * dvb-demux is now initialized, + * update back-pointers of private feeds + */ + for (j = 0; j < MPQ_MAX_DMX_FILES; j++) { + feed = &mpq_demux->feeds[j]; + feed->dvb_demux_feed = &mpq_demux->demux.feed[j]; + mpq_demux->demux.feed[j].priv = feed; + } + + /* + * Add capability of receiving input from memory. + * Every demux in our system may be connected to memory input, + * or any live input. + */ + mpq_demux->fe_memory.source = DMX_MEMORY_FE; + result = + mpq_demux->demux.dmx.add_frontend( + &mpq_demux->demux.dmx, + &mpq_demux->fe_memory); + + if (result < 0) { + MPQ_DVB_ERR_PRINT( + "%s: add_frontend (mem) failed (errno=%d)\n", + __func__, + result); + + goto init_failed_free_demux_devices; + } + } + + return 0; + +init_failed_free_demux_devices: + mpq_dmx_plugin_exit(); +init_failed: + return result; +} + +void mpq_dmx_plugin_exit(void) +{ + int i; + struct mpq_demux *mpq_demux; + + MPQ_DVB_DBG_PRINT("%s executed\n", __func__); + + if (mpq_dmx_info.devices != NULL) { + for (i = 0; i < mpq_demux_device_num; i++) { + mpq_demux = mpq_dmx_info.devices + i; + + if (!mpq_demux->is_initialized) + continue; + + if (mpq_demux->mpq_dmx_plugin_release) + mpq_demux->mpq_dmx_plugin_release(mpq_demux); + + mpq_demux->demux.dmx.remove_frontend( + &mpq_demux->demux.dmx, + &mpq_demux->fe_memory); + + if (mpq_dmx_info.secure_demux_app_loaded) + mpq_sdmx_close_session(mpq_demux); + mutex_destroy(&mpq_demux->mutex); + dvb_dmxdev_release(&mpq_demux->dmxdev); + dvb_dmx_release(&mpq_demux->demux); + } + + vfree(mpq_dmx_info.devices); + mpq_dmx_info.devices = NULL; + } +} + +int mpq_dmx_set_source( + struct dmx_demux *demux, + const dmx_source_t *src) +{ + int i; + int dvr_index; + int dmx_index; + struct dvb_demux *dvb_demux = demux->priv; + struct mpq_demux *mpq_demux; + + if ((mpq_dmx_info.devices == NULL) || (dvb_demux == NULL)) { + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + mpq_demux = dvb_demux->priv; + if (mpq_demux == NULL) { + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + /* + * For dvr sources, + * verify that this source is connected to the respective demux + */ + dmx_index = mpq_demux - mpq_dmx_info.devices; + + if (*src >= DMX_SOURCE_DVR0) { + dvr_index = *src - DMX_SOURCE_DVR0; + + if (dvr_index != dmx_index) { + MPQ_DVB_ERR_PRINT( + "%s: can't connect demux%d to dvr%d\n", + __func__, + dmx_index, + dvr_index); + return -EINVAL; + } + } + + /* + * For front-end sources, + * verify that this source is not already set to different demux + */ + for (i = 0; i < mpq_demux_device_num; i++) { + if ((&mpq_dmx_info.devices[i] != mpq_demux) && + (mpq_dmx_info.devices[i].source == *src)) { + MPQ_DVB_ERR_PRINT( + "%s: demux%d source can't be set\n", + __func__, dmx_index); + MPQ_DVB_ERR_PRINT( + "%s: demux%d occupies this source already\n", + __func__, i); + return -EBUSY; + } + } + + mpq_demux->source = *src; + return 0; +} + +int mpq_dmx_map_buffer(struct dmx_demux *demux, + struct dmx_buffer *dmx_buffer, + struct ion_dma_buff_info *dma_buffer, + void **kernel_mem) +{ + struct dvb_demux *dvb_demux = demux->priv; + struct mpq_demux *mpq_demux; + int ret; + + if ((mpq_dmx_info.devices == NULL) || (dvb_demux == NULL) || + (dmx_buffer == NULL) || (kernel_mem == NULL) || + (dmx_buffer->handle <= 0)) { + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + mpq_demux = dvb_demux->priv; + if (mpq_demux == NULL) { + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + ret = mpq_dmx_vaddr_map(dmx_buffer->handle, &dma_buffer->pa, + &dma_buffer->va, &dma_buffer->sgt, + &dma_buffer->attach, &dma_buffer->len, + &dma_buffer->dmabuf); + if (ret) { + MPQ_DVB_ERR_PRINT("%s: Failed to map vaddr for ion_fd %d\n", + __func__, dmx_buffer->handle); + return -ENOMEM; + } + + if (dma_buffer->va != NULL) { + *kernel_mem = dma_buffer->va; + } else { + MPQ_DVB_ERR_PRINT("%s: Fail to map buffer\n", __func__); + return -ENOMEM; + } + + return 0; +} + +int mpq_dmx_unmap_buffer(struct dmx_demux *demux, + struct ion_dma_buff_info *dma_buffer) +{ + struct dvb_demux *dvb_demux = demux->priv; + struct mpq_demux *mpq_demux; + + if ((mpq_dmx_info.devices == NULL) || (dvb_demux == NULL) || + (dma_buffer == NULL)) { + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + mpq_demux = dvb_demux->priv; + if (mpq_demux == NULL) { + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + mpq_dmx_vaddr_unmap(dma_buffer->va, dma_buffer->sgt, + dma_buffer->attach, dma_buffer->dmabuf); + memset(dma_buffer, 0, sizeof(struct ion_dma_buff_info)); + + return 0; +} + +int mpq_dmx_reuse_decoder_buffer(struct dvb_demux_feed *feed, int cookie) +{ + struct mpq_demux *mpq_demux = feed->demux->priv; + + MPQ_DVB_DBG_PRINT("%s: cookie=%d\n", __func__, cookie); + + if (cookie < 0) { + MPQ_DVB_ERR_PRINT("%s: invalid cookie parameter\n", __func__); + return -EINVAL; + } + + if (dvb_dmx_is_video_feed(feed)) { + struct mpq_video_feed_info *feed_data; + struct mpq_feed *mpq_feed; + struct mpq_streambuffer *stream_buffer; + int ret; + + mutex_lock(&mpq_demux->mutex); + mpq_feed = feed->priv; + feed_data = &mpq_feed->video_info; + + spin_lock(&feed_data->video_buffer_lock); + stream_buffer = feed_data->video_buffer; + if (stream_buffer == NULL) { + MPQ_DVB_ERR_PRINT( + "%s: invalid feed, feed_data->video_buffer is NULL\n", + __func__); + spin_unlock(&feed_data->video_buffer_lock); + mutex_unlock(&mpq_demux->mutex); + return -EINVAL; + } + + ret = mpq_streambuffer_pkt_dispose(stream_buffer, cookie, 1); + spin_unlock(&feed_data->video_buffer_lock); + mutex_unlock(&mpq_demux->mutex); + + return ret; + } + MPQ_DVB_ERR_PRINT("%s: Invalid feed type %d\n", + __func__, feed->pes_type); + + return -EINVAL; +} + +/** + * Handles the details of internal decoder buffer allocation via ION. + * Internal helper function. + * @feed_data: decoder feed object + * @dec_buffs: buffer information + * @client: ION client + * + * Return error status + */ +static int mpq_dmx_init_internal_buffers( + struct mpq_demux *mpq_demux, + struct mpq_video_feed_info *feed_data, + struct dmx_decoder_buffers *dec_buffs) +{ + struct ion_dma_buff_info *dbuf = NULL; + int size = 0; + int ret = 0; + + MPQ_DVB_DBG_PRINT("%s: Internal decoder buffer allocation\n", __func__); + + size = dec_buffs->buffers_size; + size = ALIGN(size, SZ_4K); + + dbuf = &feed_data->buffer_desc.buff_dma_info[0]; + memset(dbuf, 0, sizeof(struct ion_dma_buff_info)); + + dbuf->dmabuf = ion_alloc(size, + ION_HEAP(video_secure_ion_heap) | + ION_HEAP(video_nonsecure_ion_heap), + mpq_demux->decoder_alloc_flags); + + if (IS_ERR_OR_NULL(dbuf->dmabuf)) { + ret = PTR_ERR(dbuf->dmabuf); + MPQ_DVB_ERR_PRINT( + "%s: FAILED to allocate sdmx buffer %d\n", + __func__, ret); + ret = -ENOMEM; + goto err; + } + + dbuf->attach = dma_buf_attach(dbuf->dmabuf, + &mpq_demux->pdev->dev); + if (IS_ERR_OR_NULL(dbuf->attach)) { + MPQ_DVB_ERR_PRINT("%s: dma_buf_attach fail\n", __func__); + dma_buf_put(dbuf->dmabuf); + ret = -ENOMEM; + goto err_put; + } + + dbuf->sgt = dma_buf_map_attachment(dbuf->attach, DMA_BIDIRECTIONAL); + if (IS_ERR_OR_NULL(dbuf->sgt)) { + ret = PTR_ERR(dbuf->sgt); + MPQ_DVB_ERR_PRINT( + "%s: dma_buf_map_attachment failed ret = %d\n", + __func__, ret); + goto err_detach; + } + + dbuf->pa = sg_dma_address(dbuf->sgt->sgl); + dbuf->len = dbuf->sgt->sgl->length; + + dma_buf_begin_cpu_access(dbuf->dmabuf, DMA_BIDIRECTIONAL); + dbuf->va = dma_buf_vmap(dbuf->dmabuf); + if (!dbuf->va) { + MPQ_DVB_ERR_PRINT("%s: dma_buf_vmap failed\n", __func__); + dma_buf_end_cpu_access(dbuf->dmabuf, DMA_BIDIRECTIONAL); + mpq_dmx_dmabuf_unmap(dbuf->sgt, dbuf->attach, dbuf->dmabuf); + ret = -ENOMEM; + goto err; + } + + feed_data->buffer_desc.decoder_buffers_num = 1; + feed_data->buffer_desc.desc[0].base = dbuf->va; + feed_data->buffer_desc.desc[0].size = size; + feed_data->buffer_desc.desc[0].read_ptr = 0; + feed_data->buffer_desc.desc[0].write_ptr = 0; + return 0; + +err_detach: + dma_buf_detach(dbuf->dmabuf, dbuf->attach); +err_put: + dma_buf_put(dbuf->dmabuf); +err: + return ret; + +} + +/** + * Handles the details of external decoder buffers allocated by user. + * Each buffer is mapped into kernel memory and an ION handle is obtained, and + * decoder feed object is updated with related information. + * Internal helper function. + * @feed_data: decoder feed object + * @dec_buffs: buffer information + * @client: ION client + * + * Return error status + */ +static int mpq_dmx_init_external_buffers( + struct mpq_video_feed_info *feed_data, + struct dmx_decoder_buffers *dec_buffs, + bool is_secure_feed) +{ + struct ion_dma_buff_info buff; + int actual_buffer_size = 0; + int ret = 0; + int i; + + /* + * Payload buffer was allocated externally (through ION). + * Map the ion handles to kernel memory + */ + MPQ_DVB_DBG_PRINT("%s: External decoder buffer allocation\n", __func__); + memset(&buff, 0, sizeof(struct ion_dma_buff_info)); + + actual_buffer_size = dec_buffs->buffers_size; + if (!dec_buffs->is_linear) { + MPQ_DVB_DBG_PRINT("%s: Ex. Ring-buffer\n", __func__); + feed_data->buffer_desc.decoder_buffers_num = 1; + } else { + MPQ_DVB_DBG_PRINT("%s: Ex. Linear\n", __func__); + feed_data->buffer_desc.decoder_buffers_num = + dec_buffs->buffers_num; + } + + for (i = 0; i < feed_data->buffer_desc.decoder_buffers_num; i++) { + if (is_secure_feed == false) { + mpq_dmx_vaddr_map(dec_buffs->handles[i], &buff.pa, + &buff.va, &buff.sgt, &buff.attach, + &buff.len, &buff.dmabuf); + + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: Failed mapping buffer %d\n", + __func__, i); + goto init_failed; + } + memcpy(&feed_data->buffer_desc.buff_dma_info[i], &buff, + sizeof(struct ion_dma_buff_info)); + + } else { + mpq_dmx_paddr_map(dec_buffs->handles[i], &buff.pa, + &buff.sgt, &buff.attach, + &buff.len, &buff.dmabuf); + + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: Failed mapping buffer %d\n", + __func__, i); + goto init_failed; + } + memcpy(&feed_data->buffer_desc.buff_dma_info[i], &buff, + sizeof(struct ion_dma_buff_info)); + + } + if (buff.va) + feed_data->buffer_desc.desc[i].base = buff.va; + else + feed_data->buffer_desc.desc[i].base = NULL; + + feed_data->buffer_desc.desc[i].handle = + dec_buffs->handles[i]; + feed_data->buffer_desc.desc[i].size = + dec_buffs->buffers_size; + feed_data->buffer_desc.desc[i].read_ptr = 0; + feed_data->buffer_desc.desc[i].write_ptr = 0; + + memset(&buff, 0, sizeof(struct ion_dma_buff_info)); + + MPQ_DVB_DBG_PRINT( + "%s: Buffer #%d: handle=%d, size=%d\n", + __func__, i, + feed_data->buffer_desc.desc[i].handle, + feed_data->buffer_desc.desc[i].size); + } + + return 0; + +init_failed: + MPQ_DVB_DBG_PRINT("%s: Init failed\n", __func__); + + for (i = 0; i < feed_data->buffer_desc.decoder_buffers_num; i++) { + struct ion_dma_buff_info *buff = + &feed_data->buffer_desc.buff_dma_info[i]; + if (feed_data->buffer_desc.desc[i].base) { + mpq_dmx_vaddr_unmap(buff->va, buff->sgt, + buff->attach, + buff->dmabuf); + feed_data->buffer_desc.desc[i].base = NULL; + } + feed_data->buffer_desc.desc[i].size = 0; + memset(buff, 0, sizeof(struct ion_dma_buff_info)); + } + return ret; +} + +/** + * Handles the details of initializing the mpq_streambuffer object according + * to the user decoder buffer configuration: External/Internal buffers and + * ring/linear buffering mode. + * Internal helper function. + * @feed: dvb demux feed object, contains the buffers configuration + * @feed_data: decoder feed object + * @stream_buffer: stream buffer object to initialize + * + * Return error status + */ +static int mpq_dmx_init_streambuffer( + struct mpq_feed *feed, + struct mpq_video_feed_info *feed_data, + struct mpq_streambuffer *stream_buffer) +{ + int ret; + void *packet_buffer = NULL; + struct mpq_demux *mpq_demux = feed->mpq_demux; + struct dmx_decoder_buffers *dec_buffs = NULL; + enum mpq_streambuffer_mode mode; + bool is_secure_feed = false; + + dec_buffs = feed->dvb_demux_feed->feed.ts.decoder_buffers; + is_secure_feed = feed->dvb_demux_feed->secure_mode.is_secured; + + /* Allocate packet buffer holding the meta-data */ + packet_buffer = vmalloc(VIDEO_META_DATA_BUFFER_SIZE); + + if (packet_buffer == NULL) { + ret = -ENOMEM; + goto end; + } + + MPQ_DVB_DBG_PRINT("%s: dec_buffs: num=%d, size=%d, linear=%d\n", + __func__, + dec_buffs->buffers_num, + dec_buffs->buffers_size, + dec_buffs->is_linear); + + if (dec_buffs->buffers_num == 0) + ret = mpq_dmx_init_internal_buffers( + mpq_demux, feed_data, dec_buffs); + else + ret = mpq_dmx_init_external_buffers( + feed_data, dec_buffs, is_secure_feed); + + if (ret != 0) + goto init_failed_free_packet_buffer; + + mode = dec_buffs->is_linear ? MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR : + MPQ_STREAMBUFFER_BUFFER_MODE_RING; + ret = mpq_streambuffer_init( + feed_data->video_buffer, + mode, + feed_data->buffer_desc.desc, + feed_data->buffer_desc.decoder_buffers_num, + packet_buffer, + VIDEO_META_DATA_BUFFER_SIZE); + + if (ret != 0) + goto init_failed_free_packet_buffer; + + goto end; + + +init_failed_free_packet_buffer: + vfree(packet_buffer); +end: + return ret; +} + +static void mpq_dmx_release_streambuffer( + struct mpq_feed *feed, + struct mpq_video_feed_info *feed_data, + struct mpq_streambuffer *video_buffer, + struct ion_client *client) +{ + int buf_num = 0; + int i; + struct dmx_decoder_buffers *dec_buffs = + feed->dvb_demux_feed->feed.ts.decoder_buffers; + struct ion_dma_buff_info *buff = NULL; + + mpq_adapter_unregister_stream_if(feed_data->stream_interface); + + mpq_streambuffer_terminate(video_buffer); + + vfree(video_buffer->packet_data.data); + + buf_num = feed_data->buffer_desc.decoder_buffers_num; + + for (i = 0; i < buf_num; i++) { + buff = &feed_data->buffer_desc.buff_dma_info[i]; + if (buff->va) { + if (feed_data->buffer_desc.desc[i].base) { + mpq_dmx_vaddr_unmap(buff->va, buff->sgt, + buff->attach, buff->dmabuf); + feed_data->buffer_desc.desc[i].base = NULL; + } + + /* + * Un-share the buffer if kernel it the one that + * shared it. + */ + if (!dec_buffs->buffers_num && + feed_data->buffer_desc.shared_file) { + fput(feed_data->buffer_desc.shared_file); + feed_data->buffer_desc.shared_file = NULL; + } + + feed_data->buffer_desc.desc[i].size = 0; + } else if (buff->pa) { + mpq_dmx_paddr_unmap(buff->sgt, buff->attach, + buff->dmabuf); + buff->pa = 0; + } + memset(buff, 0, sizeof(struct ion_dma_buff_info)); + } +} + +int mpq_dmx_flush_stream_buffer(struct dvb_demux_feed *feed) +{ + struct mpq_feed *mpq_feed = feed->priv; + struct mpq_video_feed_info *feed_data = &mpq_feed->video_info; + struct mpq_streambuffer *sbuff; + int ret = 0; + + if (!dvb_dmx_is_video_feed(feed)) { + MPQ_DVB_DBG_PRINT("%s: not a video feed, feed type=%d\n", + __func__, feed->pes_type); + return 0; + } + + spin_lock(&feed_data->video_buffer_lock); + + sbuff = feed_data->video_buffer; + if (sbuff == NULL) { + MPQ_DVB_DBG_PRINT("%s: feed_data->video_buffer is NULL\n", + __func__); + spin_unlock(&feed_data->video_buffer_lock); + return -ENODEV; + } + + feed_data->pending_pattern_len = 0; + + ret = mpq_streambuffer_flush(sbuff); + if (ret) + MPQ_DVB_ERR_PRINT("%s: mpq_streambuffer_flush failed, ret=%d\n", + __func__, ret); + + spin_unlock(&feed_data->video_buffer_lock); + + return ret; +} + +static int mpq_dmx_flush_buffer(struct dmx_ts_feed *ts_feed, size_t length) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; + int ret = 0; + + if (mutex_lock_interruptible(&demux->mutex)) + return -ERESTARTSYS; + + dvbdmx_ts_reset_pes_state(feed); + + if (dvb_dmx_is_video_feed(feed)) { + MPQ_DVB_DBG_PRINT("%s: flushing video buffer\n", __func__); + + ret = mpq_dmx_flush_stream_buffer(feed); + } + mutex_unlock(&demux->mutex); + return ret; +} + +/** + * mpq_dmx_init_video_feed - Initializes of video feed information + * used to pass data directly to decoder. + * + * @mpq_feed: The mpq feed object + * + * Return error code. + */ +int mpq_dmx_init_video_feed(struct mpq_feed *mpq_feed) +{ + int ret; + struct mpq_video_feed_info *feed_data = &mpq_feed->video_info; + struct mpq_demux *mpq_demux = mpq_feed->mpq_demux; + struct mpq_streambuffer *stream_buffer; + + /* get and store framing information if required */ + if (video_framing) { + mpq_dmx_get_pattern_params( + mpq_feed->dvb_demux_feed->video_codec, + feed_data->patterns, &feed_data->patterns_num); + if (!feed_data->patterns_num) { + MPQ_DVB_ERR_PRINT( + "%s: FAILED to get framing pattern parameters\n", + __func__); + + ret = -EINVAL; + goto init_failed_free_priv_data; + } + } + + /* Register the new stream-buffer interface to MPQ adapter */ + switch (mpq_feed->dvb_demux_feed->pes_type) { + case DMX_PES_VIDEO0: + feed_data->stream_interface = + MPQ_ADAPTER_VIDEO0_STREAM_IF; + break; + + case DMX_PES_VIDEO1: + feed_data->stream_interface = + MPQ_ADAPTER_VIDEO1_STREAM_IF; + break; + + case DMX_PES_VIDEO2: + feed_data->stream_interface = + MPQ_ADAPTER_VIDEO2_STREAM_IF; + break; + + case DMX_PES_VIDEO3: + feed_data->stream_interface = + MPQ_ADAPTER_VIDEO3_STREAM_IF; + break; + + default: + MPQ_DVB_ERR_PRINT( + "%s: Invalid pes type %d\n", + __func__, + mpq_feed->dvb_demux_feed->pes_type); + ret = -EINVAL; + goto init_failed_free_priv_data; + } + + /* make sure not occupied already */ + stream_buffer = NULL; + mpq_adapter_get_stream_if( + feed_data->stream_interface, + &stream_buffer); + if (stream_buffer != NULL) { + MPQ_DVB_ERR_PRINT( + "%s: Video interface %d already occupied!\n", + __func__, + feed_data->stream_interface); + ret = -EBUSY; + goto init_failed_free_priv_data; + } + + feed_data->video_buffer = + &mpq_dmx_info.decoder_buffers[feed_data->stream_interface]; + + ret = mpq_dmx_init_streambuffer( + mpq_feed, feed_data, feed_data->video_buffer); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_dmx_init_streambuffer failed, err = %d\n", + __func__, ret); + goto init_failed_free_priv_data; + } + + ret = mpq_adapter_register_stream_if( + feed_data->stream_interface, + feed_data->video_buffer); + + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_adapter_register_stream_if failed, err = %d\n", + __func__, ret); + goto init_failed_free_stream_buffer; + } + + spin_lock_init(&feed_data->video_buffer_lock); + + feed_data->pes_header_left_bytes = PES_MANDATORY_FIELDS_LEN; + feed_data->pes_header_offset = 0; + mpq_feed->dvb_demux_feed->pusi_seen = 0; + mpq_feed->dvb_demux_feed->peslen = 0; + feed_data->fullness_wait_cancel = 0; + mpq_streambuffer_get_data_rw_offset(feed_data->video_buffer, NULL, + &feed_data->frame_offset); + feed_data->last_pattern_offset = 0; + feed_data->pending_pattern_len = 0; + feed_data->last_framing_match_type = 0; + feed_data->found_sequence_header_pattern = 0; + memset(&feed_data->prefix_size, 0, + sizeof(struct dvb_dmx_video_prefix_size_masks)); + feed_data->first_prefix_size = 0; + feed_data->saved_pts_dts_info.pts_exist = 0; + feed_data->saved_pts_dts_info.dts_exist = 0; + feed_data->new_pts_dts_info.pts_exist = 0; + feed_data->new_pts_dts_info.dts_exist = 0; + feed_data->saved_info_used = 1; + feed_data->new_info_exists = 0; + feed_data->first_pts_dts_copy = 1; + feed_data->tei_errs = 0; + feed_data->last_continuity = -1; + feed_data->continuity_errs = 0; + feed_data->ts_packets_num = 0; + feed_data->ts_dropped_bytes = 0; + + mpq_demux->decoder_stat[feed_data->stream_interface].drop_count = 0; + mpq_demux->decoder_stat[feed_data->stream_interface].out_count = 0; + mpq_demux->decoder_stat[feed_data->stream_interface].out_interval_sum + = 0; + mpq_demux->decoder_stat[feed_data->stream_interface].out_interval_max + = 0; + mpq_demux->decoder_stat[feed_data->stream_interface].ts_errors = 0; + mpq_demux->decoder_stat[feed_data->stream_interface].cc_errors = 0; + + return 0; + +init_failed_free_stream_buffer: + mpq_dmx_release_streambuffer(mpq_feed, feed_data, + feed_data->video_buffer, mpq_demux->ion_client); + mpq_adapter_unregister_stream_if(feed_data->stream_interface); +init_failed_free_priv_data: + feed_data->video_buffer = NULL; + return ret; +} + +/** + * mpq_dmx_terminate_video_feed - terminate video feed information + * that was previously initialized in mpq_dmx_init_video_feed + * + * @mpq_feed: The mpq feed used for the video TS packets + * + * Return error code. + */ +int mpq_dmx_terminate_video_feed(struct mpq_feed *mpq_feed) +{ + struct mpq_streambuffer *video_buffer; + struct mpq_video_feed_info *feed_data; + struct mpq_demux *mpq_demux; + + if (mpq_feed == NULL) + return -EINVAL; + + mpq_demux = mpq_feed->mpq_demux; + feed_data = &mpq_feed->video_info; + + spin_lock(&feed_data->video_buffer_lock); + video_buffer = feed_data->video_buffer; + feed_data->video_buffer = NULL; + wake_up_all(&video_buffer->raw_data.queue); + spin_unlock(&feed_data->video_buffer_lock); + + mpq_dmx_release_streambuffer(mpq_feed, feed_data, + video_buffer, mpq_demux->ion_client); + + return 0; +} + +struct dvb_demux_feed *mpq_dmx_peer_rec_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux_feed *tmp; + struct dvb_demux *dvb_demux = feed->demux; + + list_for_each_entry(tmp, &dvb_demux->feed_list, list_head) { + if (tmp != feed && tmp->state == DMX_STATE_GO && + tmp->feed.ts.buffer.ringbuff == + feed->feed.ts.buffer.ringbuff) { + MPQ_DVB_DBG_PRINT( + "%s: main feed pid=%d, secondary feed pid=%d\n", + __func__, tmp->pid, feed->pid); + return tmp; + } + } + + return NULL; +} + +static int mpq_sdmx_alloc_data_buf(struct mpq_feed *mpq_feed, size_t size) +{ + struct mpq_demux *mpq_demux = mpq_feed->mpq_demux; + int ret = 0; + struct sdmx_buff_descriptor *desc = &mpq_feed->data_desc; + + desc->virt_base = dma_alloc_coherent(&mpq_demux->pdev->dev, + size, &desc->phys_base, + GFP_KERNEL); + if (IS_ERR_OR_NULL(desc->virt_base)) { + ret = PTR_ERR(desc->virt_base); + MPQ_DVB_ERR_PRINT("%s: dma_alloc_coherent failed ret = %d\n", + __func__, ret); + return ret; + } + desc->size = size; + dvb_ringbuffer_init(&mpq_feed->sdmx_buf, desc->virt_base, size); + + return 0; +} + +static int mpq_sdmx_free_data_buf(struct mpq_feed *mpq_feed) +{ + struct mpq_demux *mpq_demux = mpq_feed->mpq_demux; + struct sdmx_buff_descriptor *desc = &mpq_feed->data_desc; + + dma_free_coherent(&mpq_demux->pdev->dev, + desc->size, desc->virt_base, + desc->phys_base); + + memset(desc, 0, sizeof(struct sdmx_buff_descriptor)); + return 0; +} +static int mpq_sdmx_init_metadata_buffer(struct mpq_demux *mpq_demux, + struct mpq_feed *feed, struct sdmx_buff_descr *metadata_buff_desc) +{ + + int ret = 0; + struct sdmx_buff_descriptor *desc = &feed->metadata_desc; + + desc->virt_base = dma_alloc_coherent(&mpq_demux->pdev->dev, + SDMX_METADATA_BUFFER_SIZE, + &desc->phys_base, + GFP_KERNEL); + if (IS_ERR_OR_NULL(desc->virt_base)) { + ret = PTR_ERR(desc->virt_base); + MPQ_DVB_ERR_PRINT( + "%s: dma_buf_map_attachment failed ret = %d\n", + __func__, ret); + return ret; + } + desc->size = SDMX_METADATA_BUFFER_SIZE; + + metadata_buff_desc->size = SDMX_METADATA_BUFFER_SIZE; + metadata_buff_desc->base_addr = desc->phys_base; + dvb_ringbuffer_init(&feed->metadata_buf, desc->virt_base, + SDMX_METADATA_BUFFER_SIZE); + + return 0; +} + +static int mpq_sdmx_terminate_metadata_buffer(struct mpq_feed *mpq_feed) +{ + + struct mpq_demux *mpq_demux = mpq_feed->mpq_demux; + + struct sdmx_buff_descriptor *desc = &mpq_feed->data_desc; + + dma_free_coherent(&mpq_demux->pdev->dev, + desc->size, desc->virt_base, + desc->phys_base); + + memset(desc, 0, sizeof(struct sdmx_buff_descriptor)); + return 0; +} +int mpq_dmx_terminate_feed(struct dvb_demux_feed *feed) +{ + int ret = 0; + struct mpq_demux *mpq_demux; + struct mpq_feed *mpq_feed; + struct mpq_feed *main_rec_feed = NULL; + struct dvb_demux_feed *tmp; + + if (feed == NULL) + return -EINVAL; + + mpq_demux = feed->demux->priv; + + mutex_lock(&mpq_demux->mutex); + mpq_feed = feed->priv; + + if (mpq_feed->sdmx_filter_handle != SDMX_INVALID_FILTER_HANDLE) { + if (mpq_feed->filter_type == SDMX_RAW_FILTER) { + tmp = mpq_dmx_peer_rec_feed(feed); + if (tmp) + main_rec_feed = tmp->priv; + } + + if (main_rec_feed) { + /* This feed is part of a recording filter */ + MPQ_DVB_DBG_PRINT( + "%s: Removing raw pid %d from filter %d\n", + __func__, feed->pid, + mpq_feed->sdmx_filter_handle); + ret = sdmx_remove_raw_pid( + mpq_demux->sdmx_session_handle, + mpq_feed->sdmx_filter_handle, feed->pid); + if (ret) + MPQ_DVB_ERR_PRINT( + "%s: SDMX_remove_raw_pid failed. ret = %d\n", + __func__, ret); + + /* If this feed that we are removing was set as primary, + * now other feeds should be set as primary + */ + if (!mpq_feed->secondary_feed) + main_rec_feed->secondary_feed = 0; + } else { + MPQ_DVB_DBG_PRINT("%s: Removing filter %d, pid %d\n", + __func__, mpq_feed->sdmx_filter_handle, + feed->pid); + ret = sdmx_remove_filter(mpq_demux->sdmx_session_handle, + mpq_feed->sdmx_filter_handle); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: SDMX_remove_filter failed. ret = %d\n", + __func__, ret); + } + + mpq_demux->sdmx_filter_count--; + mpq_feed->sdmx_filter_handle = + SDMX_INVALID_FILTER_HANDLE; + } + + mpq_sdmx_close_session(mpq_demux); + if (mpq_demux->num_secure_feeds > 0) + mpq_demux->num_secure_feeds--; + else + MPQ_DVB_DBG_PRINT("%s: Invalid secure feed count= %u\n", + __func__, mpq_demux->num_secure_feeds); + } + + if (dvb_dmx_is_video_feed(feed)) { + + ret = mpq_dmx_terminate_video_feed(mpq_feed); + if (ret) + MPQ_DVB_ERR_PRINT( + "%s: mpq_dmx_terminate_video_feed failed. ret = %d\n", + __func__, ret); + } + + if (mpq_feed->sdmx_dma_buff.va) { + wake_up_all(&mpq_feed->sdmx_buf.queue); + mpq_sdmx_free_data_buf(mpq_feed); + } + + mpq_sdmx_terminate_metadata_buffer(mpq_feed); + if (mpq_demux->num_active_feeds > 0) + mpq_demux->num_active_feeds--; + else + MPQ_DVB_DBG_PRINT("%s: Invalid num_active_feeds count = %u\n", + __func__, mpq_demux->num_active_feeds); + + mutex_unlock(&mpq_demux->mutex); + + return ret; +} + +int mpq_dmx_decoder_fullness_init(struct dvb_demux_feed *feed) +{ + struct mpq_feed *mpq_feed; + + if (dvb_dmx_is_video_feed(feed)) { + struct mpq_video_feed_info *feed_data; + + mpq_feed = feed->priv; + feed_data = &mpq_feed->video_info; + feed_data->fullness_wait_cancel = 0; + + return 0; + } + + MPQ_DVB_DBG_PRINT("%s: Invalid feed type %d\n", __func__, + feed->pes_type); + + return -EINVAL; +} + +/** + * Returns whether the free space of decoder's output + * buffer is larger than specific number of bytes. + * + * @sbuff: MPQ stream buffer used for decoder data. + * @required_space: number of required free bytes in the buffer + * + * Return 1 if required free bytes are available, 0 otherwise. + */ +static inline int mpq_dmx_check_video_decoder_fullness( + struct mpq_streambuffer *sbuff, + size_t required_space) +{ + ssize_t free = mpq_streambuffer_data_free(sbuff); + ssize_t free_meta = mpq_streambuffer_metadata_free(sbuff); + + /* Verify meta-data buffer can contain at least 1 packet */ + if (free_meta < VIDEO_META_DATA_PACKET_SIZE) + return 0; + + /* + * For linear buffers, verify there's enough space for this TSP + * and an additional buffer is free, as framing might required one + * more buffer to be available. + */ + if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) + return (free >= required_space && + sbuff->pending_buffers_count < sbuff->buffers_num-1); + else + /* Ring buffer mode */ + return (free >= required_space); +} + +/** + * Checks whether decoder's output buffer has free space + * for specific number of bytes, if not, the function waits + * until the amount of free-space is available. + * + * @feed: decoder's feed object + * @required_space: number of required free bytes in the buffer + * @lock_feed: indicates whether mutex should be held before + * accessing the feed information. If the caller of this function + * already holds a mutex then this should be set to 0 and 1 otherwise. + * + * Return 0 if required space is available and error code + * in case waiting on buffer fullness was aborted. + */ +static int mpq_dmx_decoder_fullness_check( + struct dvb_demux_feed *feed, + size_t required_space, + int lock_feed) +{ + struct mpq_demux *mpq_demux = feed->demux->priv; + struct mpq_streambuffer *sbuff = NULL; + struct mpq_video_feed_info *feed_data; + struct mpq_feed *mpq_feed; + int ret = 0; + + if (!dvb_dmx_is_video_feed(feed)) { + MPQ_DVB_DBG_PRINT("%s: Invalid feed type %d\n", + __func__, + feed->pes_type); + return -EINVAL; + } + + if (lock_feed) { + mutex_lock(&mpq_demux->mutex); + } else if (!mutex_is_locked(&mpq_demux->mutex)) { + MPQ_DVB_ERR_PRINT( + "%s: Mutex should have been locked\n", + __func__); + return -EINVAL; + } + + mpq_feed = feed->priv; + feed_data = &mpq_feed->video_info; + + sbuff = feed_data->video_buffer; + if (sbuff == NULL) { + if (lock_feed) + mutex_unlock(&mpq_demux->mutex); + MPQ_DVB_ERR_PRINT("%s: mpq_streambuffer object is NULL\n", + __func__); + return -EINVAL; + } + + if ((feed_data->video_buffer != NULL) && + (!feed_data->fullness_wait_cancel) && + (!mpq_dmx_check_video_decoder_fullness(sbuff, + required_space))) { + DEFINE_WAIT(__wait); + + for (;;) { + prepare_to_wait(&sbuff->raw_data.queue, + &__wait, + TASK_INTERRUPTIBLE); + if (!feed_data->video_buffer || + feed_data->fullness_wait_cancel || + mpq_dmx_check_video_decoder_fullness(sbuff, + required_space)) + break; + + if (!signal_pending(current)) { + mutex_unlock(&mpq_demux->mutex); + schedule(); + mutex_lock(&mpq_demux->mutex); + continue; + } + + ret = -ERESTARTSYS; + break; + } + finish_wait(&sbuff->raw_data.queue, &__wait); + } + + if (ret < 0) { + if (lock_feed) + mutex_unlock(&mpq_demux->mutex); + return ret; + } + + if ((feed_data->fullness_wait_cancel) || + (feed_data->video_buffer == NULL)) { + if (lock_feed) + mutex_unlock(&mpq_demux->mutex); + return -EINVAL; + } + + if (lock_feed) + mutex_unlock(&mpq_demux->mutex); + return 0; +} + +int mpq_dmx_decoder_fullness_wait( + struct dvb_demux_feed *feed, + size_t required_space) +{ + return mpq_dmx_decoder_fullness_check(feed, required_space, 1); +} + +int mpq_dmx_decoder_fullness_abort(struct dvb_demux_feed *feed) +{ + if (dvb_dmx_is_video_feed(feed)) { + struct mpq_feed *mpq_feed; + struct mpq_video_feed_info *feed_data; + struct dvb_ringbuffer *video_buff; + + mpq_feed = feed->priv; + feed_data = &mpq_feed->video_info; + + feed_data->fullness_wait_cancel = 1; + + spin_lock(&feed_data->video_buffer_lock); + if (feed_data->video_buffer == NULL) { + MPQ_DVB_DBG_PRINT( + "%s: video_buffer released\n", __func__); + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + video_buff = &feed_data->video_buffer->raw_data; + wake_up_all(&video_buff->queue); + spin_unlock(&feed_data->video_buffer_lock); + + return 0; + } + MPQ_DVB_ERR_PRINT( + "%s: Invalid feed type %d\n", __func__, feed->pes_type); + + return -EINVAL; +} + +int mpq_dmx_parse_mandatory_pes_header( + struct dvb_demux_feed *feed, + struct mpq_video_feed_info *feed_data, + struct pes_packet_header *pes_header, + const u8 *buf, + u32 *ts_payload_offset, + int *bytes_avail) +{ + int left_size, copy_len; + + if (feed_data->pes_header_offset < PES_MANDATORY_FIELDS_LEN) { + left_size = + PES_MANDATORY_FIELDS_LEN - + feed_data->pes_header_offset; + + copy_len = (left_size > *bytes_avail) ? + *bytes_avail : + left_size; + + memcpy((u8 *)((u8 *)pes_header + feed_data->pes_header_offset), + (buf + *ts_payload_offset), + copy_len); + + feed_data->pes_header_offset += copy_len; + + if (left_size > *bytes_avail) + return -EINVAL; + + /* else - we have beginning of PES header */ + *bytes_avail -= left_size; + *ts_payload_offset += left_size; + + /* Make sure the PES packet is valid */ + if (mpq_dmx_is_valid_video_pes(pes_header) < 0) { + /* + * Since the new PES header parsing + * failed, reset pusi_seen to drop all + * data until next PUSI + */ + feed->pusi_seen = 0; + feed_data->pes_header_offset = 0; + + MPQ_DVB_ERR_PRINT( + "%s: invalid packet\n", + __func__); + + return -EINVAL; + } + + feed_data->pes_header_left_bytes = + pes_header->pes_header_data_length; + } + + return 0; +} + +static inline void mpq_dmx_get_pts_dts(struct mpq_video_feed_info *feed_data, + struct pes_packet_header *pes_header) +{ + struct dmx_pts_dts_info *info = &(feed_data->new_pts_dts_info); + + /* Get PTS/DTS information from PES header */ + + if ((pes_header->pts_dts_flag == 2) || + (pes_header->pts_dts_flag == 3)) { + info->pts_exist = 1; + + info->pts = + ((u64)pes_header->pts_1 << 30) | + ((u64)pes_header->pts_2 << 22) | + ((u64)pes_header->pts_3 << 15) | + ((u64)pes_header->pts_4 << 7) | + (u64)pes_header->pts_5; + } else { + info->pts_exist = 0; + info->pts = 0; + } + + if (pes_header->pts_dts_flag == 3) { + info->dts_exist = 1; + + info->dts = + ((u64)pes_header->dts_1 << 30) | + ((u64)pes_header->dts_2 << 22) | + ((u64)pes_header->dts_3 << 15) | + ((u64)pes_header->dts_4 << 7) | + (u64)pes_header->dts_5; + } else { + info->dts_exist = 0; + info->dts = 0; + } + + feed_data->new_info_exists = 1; +} + +int mpq_dmx_parse_remaining_pes_header( + struct dvb_demux_feed *feed, + struct mpq_video_feed_info *feed_data, + struct pes_packet_header *pes_header, + const u8 *buf, + u32 *ts_payload_offset, + int *bytes_avail) +{ + int left_size, copy_len; + + /* Remaining header bytes that need to be processed? */ + if (!feed_data->pes_header_left_bytes) + return 0; + + /* Did we capture the PTS value (if exists)? */ + if ((*bytes_avail != 0) && + (feed_data->pes_header_offset < + (PES_MANDATORY_FIELDS_LEN+5)) && + ((pes_header->pts_dts_flag == 2) || + (pes_header->pts_dts_flag == 3))) { + + /* 5 more bytes should be there */ + left_size = + PES_MANDATORY_FIELDS_LEN + 5 - + feed_data->pes_header_offset; + + copy_len = (left_size > *bytes_avail) ? + *bytes_avail : + left_size; + + memcpy((u8 *)((u8 *)pes_header + feed_data->pes_header_offset), + (buf + *ts_payload_offset), + copy_len); + + feed_data->pes_header_offset += copy_len; + feed_data->pes_header_left_bytes -= copy_len; + + if (left_size > *bytes_avail) + return -EINVAL; + + /* else - we have the PTS */ + *bytes_avail -= copy_len; + *ts_payload_offset += copy_len; + } + + /* Did we capture the DTS value (if exist)? */ + if ((*bytes_avail != 0) && + (feed_data->pes_header_offset < + (PES_MANDATORY_FIELDS_LEN+10)) && + (pes_header->pts_dts_flag == 3)) { + + /* 5 more bytes should be there */ + left_size = + PES_MANDATORY_FIELDS_LEN + 10 - + feed_data->pes_header_offset; + + copy_len = (left_size > *bytes_avail) ? + *bytes_avail : + left_size; + + memcpy((u8 *)((u8 *)pes_header + feed_data->pes_header_offset), + (buf + *ts_payload_offset), + copy_len); + + feed_data->pes_header_offset += copy_len; + feed_data->pes_header_left_bytes -= copy_len; + + if (left_size > *bytes_avail) + return -EINVAL; + + /* else - we have the DTS */ + *bytes_avail -= copy_len; + *ts_payload_offset += copy_len; + } + + /* Any more header bytes?! */ + if (feed_data->pes_header_left_bytes >= *bytes_avail) { + feed_data->pes_header_left_bytes -= *bytes_avail; + return -EINVAL; + } + + /* get PTS/DTS information from PES header to be written later */ + mpq_dmx_get_pts_dts(feed_data, pes_header); + + /* Got PES header, process payload */ + *bytes_avail -= feed_data->pes_header_left_bytes; + *ts_payload_offset += feed_data->pes_header_left_bytes; + feed_data->pes_header_left_bytes = 0; + + return 0; +} + +static void mpq_dmx_check_continuity(struct mpq_video_feed_info *feed_data, + int current_continuity, + int discontinuity_indicator) +{ + const int max_continuity = 0x0F; /* 4 bits in the TS packet header */ + + /* sanity check */ + if (unlikely((current_continuity < 0) || + (current_continuity > max_continuity))) { + MPQ_DVB_DBG_PRINT( + "%s: received invalid continuity counter value %d\n", + __func__, current_continuity); + return; + } + + /* reset last continuity */ + if ((feed_data->last_continuity == -1) || + (discontinuity_indicator)) { + feed_data->last_continuity = current_continuity; + return; + } + + /* check for continuity errors */ + if (current_continuity != + ((feed_data->last_continuity + 1) & max_continuity)) + feed_data->continuity_errs++; + + /* save for next time */ + feed_data->last_continuity = current_continuity; +} + +static inline void mpq_dmx_prepare_es_event_data( + struct mpq_streambuffer_packet_header *packet, + struct mpq_adapter_video_meta_data *meta_data, + struct mpq_video_feed_info *feed_data, + struct mpq_streambuffer *stream_buffer, + struct dmx_data_ready *data, + int cookie) +{ + struct dmx_pts_dts_info *pts_dts; + + if (meta_data->packet_type == DMX_PES_PACKET) { + pts_dts = &meta_data->info.pes.pts_dts_info; + data->buf.stc = meta_data->info.pes.stc; + } else { + pts_dts = &meta_data->info.framing.pts_dts_info; + data->buf.stc = meta_data->info.framing.stc; + } + + pts_dts = meta_data->packet_type == DMX_PES_PACKET ? + &meta_data->info.pes.pts_dts_info : + &meta_data->info.framing.pts_dts_info; + + data->data_length = 0; + data->buf.handle = packet->raw_data_handle; + data->buf.cookie = cookie; + data->buf.offset = packet->raw_data_offset; + data->buf.len = packet->raw_data_len; + data->buf.pts_exists = pts_dts->pts_exist; + data->buf.pts = pts_dts->pts; + data->buf.dts_exists = pts_dts->dts_exist; + data->buf.dts = pts_dts->dts; + data->buf.tei_counter = feed_data->tei_errs; + data->buf.cont_err_counter = feed_data->continuity_errs; + data->buf.ts_packets_num = feed_data->ts_packets_num; + data->buf.ts_dropped_bytes = feed_data->ts_dropped_bytes; + data->status = DMX_OK_DECODER_BUF; + + MPQ_DVB_DBG_PRINT("%s: cookie=%d\n", __func__, data->buf.cookie); + + /* reset counters */ + feed_data->ts_packets_num = 0; + feed_data->ts_dropped_bytes = 0; + feed_data->tei_errs = 0; + feed_data->continuity_errs = 0; +} + +static int mpq_sdmx_dvr_buffer_desc(struct mpq_demux *mpq_demux, + struct sdmx_buff_descr *buf_desc) +{ + struct dvb_ringbuffer *rbuf = (struct dvb_ringbuffer *) + mpq_demux->demux.dmx.dvr_input.ringbuff; + struct ion_dma_buff_info *dma_buff = + &mpq_demux->demux.dmx.dvr_input.buff_dma_info; + if (dma_buff->pa) { + buf_desc->base_addr = (u64)dma_buff->pa; + buf_desc->size = rbuf->size; + } + + return 0; +} + +static inline int mpq_dmx_notify_overflow(struct dvb_demux_feed *feed) +{ + struct dmx_data_ready data; + + data.data_length = 0; + data.status = DMX_OVERRUN_ERROR; + return feed->data_ready_cb.ts(&feed->feed.ts, &data); +} + +/** + * mpq_dmx_decoder_frame_closure - Helper function to handle closing current + * pending frame upon reaching EOS. + * + * @mpq_demux - mpq demux instance + * @mpq_feed - mpq feed object + */ +static void mpq_dmx_decoder_frame_closure(struct mpq_demux *mpq_demux, + struct mpq_feed *mpq_feed) +{ + struct mpq_streambuffer_packet_header packet; + struct mpq_streambuffer *stream_buffer; + struct mpq_adapter_video_meta_data meta_data; + struct mpq_video_feed_info *feed_data; + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + struct dmx_data_ready data; + int cookie; + + feed_data = &mpq_feed->video_info; + + /* + * spin-lock is taken to protect against manipulation of video + * output buffer by the API (terminate video feed, re-use of video + * buffers). + */ + spin_lock(&feed_data->video_buffer_lock); + stream_buffer = feed_data->video_buffer; + + if (stream_buffer == NULL) { + MPQ_DVB_DBG_PRINT("%s: video_buffer released\n", __func__); + spin_unlock(&feed_data->video_buffer_lock); + return; + } + + /* Report last pattern found */ + if ((feed_data->pending_pattern_len) && + mpq_dmx_is_video_frame(feed->video_codec, + feed_data->last_framing_match_type)) { + meta_data.packet_type = DMX_FRAMING_INFO_PACKET; + mpq_dmx_write_pts_dts(feed_data, + &(meta_data.info.framing.pts_dts_info)); + mpq_dmx_save_pts_dts(feed_data); + packet.user_data_len = + sizeof(struct mpq_adapter_video_meta_data); + packet.raw_data_len = feed_data->pending_pattern_len; + packet.raw_data_offset = feed_data->frame_offset; + meta_data.info.framing.pattern_type = + feed_data->last_framing_match_type; + meta_data.info.framing.stc = feed_data->last_framing_match_stc; + meta_data.info.framing.continuity_error_counter = + feed_data->continuity_errs; + meta_data.info.framing.transport_error_indicator_counter = + feed_data->tei_errs; + meta_data.info.framing.ts_dropped_bytes = + feed_data->ts_dropped_bytes; + meta_data.info.framing.ts_packets_num = + feed_data->ts_packets_num; + + mpq_streambuffer_get_buffer_handle(stream_buffer, + 0, /* current write buffer handle */ + &packet.raw_data_handle); + + mpq_dmx_update_decoder_stat(mpq_feed); + + /* Writing meta-data that includes the framing information */ + cookie = mpq_streambuffer_pkt_write(stream_buffer, &packet, + (u8 *)&meta_data); + if (cookie >= 0) { + mpq_dmx_prepare_es_event_data(&packet, &meta_data, + feed_data, stream_buffer, &data, cookie); + feed->data_ready_cb.ts(&feed->feed.ts, &data); + } else { + MPQ_DVB_ERR_PRINT( + "%s: mpq_streambuffer_pkt_write failed, ret=%d\n", + __func__, cookie); + } + } + + spin_unlock(&feed_data->video_buffer_lock); +} + +/** + * mpq_dmx_decoder_pes_closure - Helper function to handle closing current PES + * upon reaching EOS. + * + * @mpq_demux - mpq demux instance + * @mpq_feed - mpq feed object + */ +static void mpq_dmx_decoder_pes_closure(struct mpq_demux *mpq_demux, + struct mpq_feed *mpq_feed) +{ + struct mpq_streambuffer_packet_header packet; + struct mpq_streambuffer *stream_buffer; + struct mpq_adapter_video_meta_data meta_data; + struct mpq_video_feed_info *feed_data; + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + struct dmx_data_ready data; + int cookie; + + feed_data = &mpq_feed->video_info; + + /* + * spin-lock is taken to protect against manipulation of video + * output buffer by the API (terminate video feed, re-use of video + * buffers). + */ + spin_lock(&feed_data->video_buffer_lock); + stream_buffer = feed_data->video_buffer; + + if (stream_buffer == NULL) { + MPQ_DVB_DBG_PRINT("%s: video_buffer released\n", __func__); + spin_unlock(&feed_data->video_buffer_lock); + return; + } + + /* + * Close previous PES. + * Push new packet to the meta-data buffer. + */ + if ((feed->pusi_seen) && (feed_data->pes_header_left_bytes == 0)) { + packet.raw_data_len = feed->peslen; + mpq_streambuffer_get_buffer_handle(stream_buffer, + 0, /* current write buffer handle */ + &packet.raw_data_handle); + packet.raw_data_offset = feed_data->frame_offset; + packet.user_data_len = + sizeof(struct mpq_adapter_video_meta_data); + + mpq_dmx_write_pts_dts(feed_data, + &(meta_data.info.pes.pts_dts_info)); + + meta_data.packet_type = DMX_PES_PACKET; + meta_data.info.pes.stc = feed_data->prev_stc; + + mpq_dmx_update_decoder_stat(mpq_feed); + + cookie = mpq_streambuffer_pkt_write(stream_buffer, &packet, + (u8 *)&meta_data); + if (cookie >= 0) { + /* Save write offset where new PES will begin */ + mpq_streambuffer_get_data_rw_offset(stream_buffer, NULL, + &feed_data->frame_offset); + mpq_dmx_prepare_es_event_data(&packet, &meta_data, + feed_data, stream_buffer, &data, cookie); + feed->data_ready_cb.ts(&feed->feed.ts, &data); + } else { + MPQ_DVB_ERR_PRINT( + "%s: mpq_streambuffer_pkt_write failed, ret=%d\n", + __func__, cookie); + } + } + /* Reset PES info */ + feed->peslen = 0; + feed_data->pes_header_offset = 0; + feed_data->pes_header_left_bytes = PES_MANDATORY_FIELDS_LEN; + + spin_unlock(&feed_data->video_buffer_lock); +} + +static int mpq_dmx_process_video_packet_framing( + struct dvb_demux_feed *feed, + const u8 *buf, + u64 curr_stc) +{ + int bytes_avail; + u32 ts_payload_offset; + struct mpq_video_feed_info *feed_data; + const struct ts_packet_header *ts_header; + struct mpq_streambuffer *stream_buffer; + struct pes_packet_header *pes_header; + struct mpq_demux *mpq_demux; + struct mpq_feed *mpq_feed; + + struct dvb_dmx_video_patterns_results framing_res; + struct mpq_streambuffer_packet_header packet; + struct mpq_adapter_video_meta_data meta_data; + int bytes_written = 0; + int bytes_to_write = 0; + int found_patterns = 0; + int first_pattern = 0; + int i; + int is_video_frame = 0; + int pending_data_len = 0; + int ret = 0; + int discontinuity_indicator = 0; + struct dmx_data_ready data; + struct dmx_framing_packet_info *framing; + + mpq_demux = feed->demux->priv; + + mpq_feed = feed->priv; + feed_data = &mpq_feed->video_info; + + /* + * spin-lock is taken to protect against manipulation of video + * output buffer by the API (terminate video feed, re-use of video + * buffers). Mutex on the video-feed cannot be held here + * since SW demux holds a spin-lock while calling write_to_decoder + */ + spin_lock(&feed_data->video_buffer_lock); + stream_buffer = feed_data->video_buffer; + + if (stream_buffer == NULL) { + MPQ_DVB_DBG_PRINT( + "%s: video_buffer released\n", + __func__); + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + ts_header = (const struct ts_packet_header *)buf; + + pes_header = &feed_data->pes_header; + + /* Make sure this TS packet has a payload and not scrambled */ + if ((ts_header->sync_byte != 0x47) || + (ts_header->adaptation_field_control == 0) || + (ts_header->adaptation_field_control == 2) || + (ts_header->transport_scrambling_control)) { + /* continue to next packet */ + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + if (ts_header->payload_unit_start_indicator) { /* PUSI? */ + if (feed->pusi_seen) { /* Did we see PUSI before? */ + /* + * Double check that we are not in middle of + * previous PES header parsing. + */ + if (feed_data->pes_header_left_bytes != 0) + MPQ_DVB_ERR_PRINT( + "%s: received PUSI while handling PES header of previous PES\n", + __func__); + + feed->peslen = 0; + feed_data->pes_header_offset = 0; + feed_data->pes_header_left_bytes = + PES_MANDATORY_FIELDS_LEN; + } else { + feed->pusi_seen = 1; + } + } + + /* + * Parse PES data only if PUSI was encountered, + * otherwise the data is dropped + */ + if (!feed->pusi_seen) { + spin_unlock(&feed_data->video_buffer_lock); + return 0; /* drop and wait for next packets */ + } + + ts_payload_offset = sizeof(struct ts_packet_header); + + /* + * Skip adaptation field if exists. + * Save discontinuity indicator if exists. + */ + if (ts_header->adaptation_field_control == 3) { + const struct ts_adaptation_field *adaptation_field = + (const struct ts_adaptation_field *)(buf + + ts_payload_offset); + + discontinuity_indicator = + adaptation_field->discontinuity_indicator; + ts_payload_offset += buf[ts_payload_offset] + 1; + } + + bytes_avail = TS_PACKET_SIZE - ts_payload_offset; + + /* Get the mandatory fields of the video PES header */ + if (mpq_dmx_parse_mandatory_pes_header(feed, feed_data, + pes_header, buf, + &ts_payload_offset, + &bytes_avail)) { + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + if (mpq_dmx_parse_remaining_pes_header(feed, feed_data, + pes_header, buf, + &ts_payload_offset, + &bytes_avail)) { + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + /* + * If we reached here, + * then we are now at the PES payload data + */ + if (bytes_avail == 0) { + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + /* + * the decoder requires demux to do framing, + * so search for the patterns now. + */ + found_patterns = dvb_dmx_video_pattern_search( + feed_data->patterns, + feed_data->patterns_num, + (buf + ts_payload_offset), + bytes_avail, + &feed_data->prefix_size, + &framing_res); + + if (!feed_data->found_sequence_header_pattern) { + for (i = 0; i < found_patterns; i++) { + if ((framing_res.info[i].type == + DMX_IDX_MPEG_SEQ_HEADER) || + (framing_res.info[i].type == + DMX_IDX_H264_SPS) || + (framing_res.info[i].type == + DMX_IDX_VC1_SEQ_HEADER)) { + + MPQ_DVB_DBG_PRINT( + "%s: Found Sequence Pattern", __func__); + MPQ_DVB_DBG_PRINT( + "i = %d, offset = %d, type = %lld\n", i, + framing_res.info[i].offset, + framing_res.info[i].type); + + first_pattern = i; + feed_data->found_sequence_header_pattern = 1; + ts_payload_offset += + framing_res.info[i].offset; + bytes_avail -= framing_res.info[i].offset; + + if (framing_res.info[i].used_prefix_size) { + feed_data->first_prefix_size = + framing_res.info[i].used_prefix_size; + } + break; + } + } + } + + /* + * If decoder requires demux to do framing, + * pass data to decoder only after sequence header + * or equivalent is found. Otherwise the data is dropped. + */ + if (!feed_data->found_sequence_header_pattern) { + feed_data->prev_stc = curr_stc; + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + /* Update error counters based on TS header */ + feed_data->ts_packets_num++; + feed_data->tei_errs += ts_header->transport_error_indicator; + mpq_demux->decoder_stat[feed_data->stream_interface].ts_errors += + ts_header->transport_error_indicator; + mpq_dmx_check_continuity(feed_data, + ts_header->continuity_counter, + discontinuity_indicator); + mpq_demux->decoder_stat[feed_data->stream_interface].cc_errors += + feed_data->continuity_errs; + + /* Need to back-up the PTS information of the very first frame */ + if (feed_data->first_pts_dts_copy) { + for (i = first_pattern; i < found_patterns; i++) { + is_video_frame = mpq_dmx_is_video_frame( + feed->video_codec, + framing_res.info[i].type); + + if (is_video_frame == 1) { + mpq_dmx_save_pts_dts(feed_data); + feed_data->first_pts_dts_copy = 0; + break; + } + } + } + + /* + * write prefix used to find first Sequence pattern, if needed. + * feed_data->patterns[0]->pattern always contains the sequence + * header pattern. + */ + if (feed_data->first_prefix_size) { + ret = mpq_streambuffer_data_write(stream_buffer, + feed_data->patterns[0]->pattern, + feed_data->first_prefix_size); + if (ret < 0) { + mpq_demux->decoder_stat + [feed_data->stream_interface].drop_count += + feed_data->first_prefix_size; + feed_data->ts_dropped_bytes += + feed_data->first_prefix_size; + MPQ_DVB_DBG_PRINT("%s: could not write prefix\n", + __func__); + if (ret == -ENOSPC) + mpq_dmx_notify_overflow(feed); + } else { + MPQ_DVB_DBG_PRINT( + "%s: Writing pattern prefix of size %d\n", + __func__, feed_data->first_prefix_size); + /* + * update the length of the data we report + * to include the size of the prefix that was used. + */ + feed_data->pending_pattern_len += + feed_data->first_prefix_size; + } + } + + feed->peslen += bytes_avail; + pending_data_len += bytes_avail; + + meta_data.packet_type = DMX_FRAMING_INFO_PACKET; + packet.user_data_len = sizeof(struct mpq_adapter_video_meta_data); + + /* + * Go over all the patterns that were found in this packet. + * For each pattern found, write the relevant data to the data + * buffer, then write the respective meta-data. + * Each pattern can only be reported when the next pattern is found + * (in order to know the data length). + * There are three possible cases for each pattern: + * 1. This is the very first pattern we found in any TS packet in this + * feed. + * 2. This is the first pattern found in this TS packet, but we've + * already found patterns in previous packets. + * 3. This is not the first pattern in this packet, i.e., we've + * already found patterns in this TS packet. + */ + for (i = first_pattern; i < found_patterns; i++) { + if (i == first_pattern) { + /* + * The way to identify the very first pattern: + * 1. It's the first pattern found in this packet. + * 2. The pending_pattern_len, which indicates the + * data length of the previous pattern that has + * not yet been reported, is usually 0. However, + * it may be larger than 0 if a prefix was used + * to find this pattern (i.e., the pattern was + * split over two TS packets). In that case, + * pending_pattern_len equals first_prefix_size. + * first_prefix_size is set to 0 later in this + * function. + */ + if (feed_data->first_prefix_size == + feed_data->pending_pattern_len) { + /* + * This is the very first pattern, so no + * previous pending frame data exists. + * Update frame info and skip to the + * next frame. + */ + feed_data->last_framing_match_type = + framing_res.info[i].type; + feed_data->last_pattern_offset = + framing_res.info[i].offset; + if (framing_res.info[i].used_prefix_size) + feed_data->last_framing_match_stc = + feed_data->prev_stc; + else + feed_data->last_framing_match_stc = + curr_stc; + continue; + } + /* + * This is the first pattern in this + * packet and previous frame from + * previous packet is pending for report + */ + bytes_to_write = framing_res.info[i].offset; + } else { + /* Previous pending frame is in the same packet */ + bytes_to_write = + framing_res.info[i].offset - + feed_data->last_pattern_offset; + } + + ret = mpq_streambuffer_data_write( + stream_buffer, + (buf + ts_payload_offset + bytes_written), + bytes_to_write); + if (ret < 0) { + mpq_demux->decoder_stat + [feed_data->stream_interface].drop_count += + bytes_to_write; + feed_data->ts_dropped_bytes += bytes_to_write; + MPQ_DVB_DBG_PRINT( + "%s: Couldn't write %d bytes to data buffer, ret=%d\n", + __func__, bytes_to_write, ret); + if (ret == -ENOSPC) + mpq_dmx_notify_overflow(feed); + } else { + bytes_written += bytes_to_write; + pending_data_len -= bytes_to_write; + feed_data->pending_pattern_len += bytes_to_write; + } + + is_video_frame = mpq_dmx_is_video_frame( + feed->video_codec, + feed_data->last_framing_match_type); + if (is_video_frame == 1) { + mpq_dmx_write_pts_dts(feed_data, + &(meta_data.info.framing.pts_dts_info)); + mpq_dmx_save_pts_dts(feed_data); + + packet.raw_data_len = feed_data->pending_pattern_len - + framing_res.info[i].used_prefix_size; + packet.raw_data_offset = feed_data->frame_offset; + + framing = &meta_data.info.framing; + framing->pattern_type = + feed_data->last_framing_match_type; + framing->stc = feed_data->last_framing_match_stc; + framing->continuity_error_counter = + feed_data->continuity_errs; + framing->transport_error_indicator_counter = + feed_data->tei_errs; + framing->ts_dropped_bytes = + feed_data->ts_dropped_bytes; + framing->ts_packets_num = + feed_data->ts_packets_num; + + mpq_streambuffer_get_buffer_handle( + stream_buffer, + 0, /* current write buffer handle */ + &packet.raw_data_handle); + + mpq_dmx_update_decoder_stat(mpq_feed); + + /* + * Write meta-data that includes the framing information + */ + ret = mpq_streambuffer_pkt_write(stream_buffer, &packet, + (u8 *)&meta_data); + if (ret < 0) { + MPQ_DVB_ERR_PRINT + ("%s: mpq_sb_pkt_write failed ret=%d\n", + __func__, ret); + if (ret == -ENOSPC) + mpq_dmx_notify_overflow(feed); + } else { + mpq_dmx_prepare_es_event_data( + &packet, &meta_data, feed_data, + stream_buffer, &data, ret); + + /* Trigger ES Data Event for VPTS */ + feed->data_ready_cb.ts(&feed->feed.ts, &data); + + if (feed_data->video_buffer->mode == + MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) + feed_data->frame_offset = 0; + else + mpq_streambuffer_get_data_rw_offset( + feed_data->video_buffer, + NULL, + &feed_data->frame_offset); + } + + /* + * In linear buffers, after writing the packet + * we switched over to a new linear buffer for the new + * frame. In that case, we should re-write the prefix + * of the existing frame if any exists. + */ + if ((MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR == + feed_data->video_buffer->mode) && + framing_res.info[i].used_prefix_size) { + ret = mpq_streambuffer_data_write(stream_buffer, + feed_data->prev_pattern + + DVB_DMX_MAX_PATTERN_LEN - + framing_res.info[i].used_prefix_size, + framing_res.info[i].used_prefix_size); + + if (ret < 0) { + feed_data->pending_pattern_len = 0; + mpq_demux->decoder_stat + [feed_data->stream_interface]. + drop_count += bytes_avail; + feed_data->ts_dropped_bytes += + framing_res.info[i].used_prefix_size; + if (ret == -ENOSPC) + mpq_dmx_notify_overflow(feed); + } else { + feed_data->pending_pattern_len = + framing_res.info[i].used_prefix_size; + } + } else { + s32 offset = (s32)feed_data->frame_offset; + u32 buff_size = + feed_data->video_buffer->buffers[0].size; + + offset -= framing_res.info[i].used_prefix_size; + offset += (offset < 0) ? buff_size : 0; + feed_data->pending_pattern_len = + framing_res.info[i].used_prefix_size; + + if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == + feed_data->video_buffer->mode) { + feed_data->frame_offset = (u32)offset; + } + } + } + + /* save the last match for next time */ + feed_data->last_framing_match_type = + framing_res.info[i].type; + feed_data->last_pattern_offset = + framing_res.info[i].offset; + if (framing_res.info[i].used_prefix_size) + feed_data->last_framing_match_stc = feed_data->prev_stc; + else + feed_data->last_framing_match_stc = curr_stc; + } + + feed_data->prev_stc = curr_stc; + feed_data->first_prefix_size = 0; + + /* + * Save the trailing of the TS packet as we might have a pattern + * split that we need to re-use when closing the next + * video linear buffer. + */ + if (MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR == + feed_data->video_buffer->mode) + memcpy(feed_data->prev_pattern, + buf + TS_PACKET_SIZE - DVB_DMX_MAX_PATTERN_LEN, + DVB_DMX_MAX_PATTERN_LEN); + + if (pending_data_len) { + ret = mpq_streambuffer_data_write( + stream_buffer, + (buf + ts_payload_offset + bytes_written), + pending_data_len); + + if (ret < 0) { + mpq_demux->decoder_stat + [feed_data->stream_interface].drop_count += + pending_data_len; + feed_data->ts_dropped_bytes += pending_data_len; + MPQ_DVB_DBG_PRINT( + "%s: Couldn't write %d pending bytes to data buffer, ret=%d\n", + __func__, pending_data_len, ret); + if (ret == -ENOSPC) + mpq_dmx_notify_overflow(feed); + } else { + feed_data->pending_pattern_len += pending_data_len; + } + } + + spin_unlock(&feed_data->video_buffer_lock); + return 0; +} + +static int mpq_dmx_process_video_packet_no_framing( + struct dvb_demux_feed *feed, + const u8 *buf, + u64 curr_stc) +{ + int bytes_avail; + u32 ts_payload_offset; + struct mpq_video_feed_info *feed_data; + const struct ts_packet_header *ts_header; + struct mpq_streambuffer *stream_buffer; + struct pes_packet_header *pes_header; + struct mpq_demux *mpq_demux; + struct mpq_feed *mpq_feed; + int discontinuity_indicator = 0; + struct dmx_data_ready data; + int cookie; + int ret; + + mpq_demux = feed->demux->priv; + mpq_feed = feed->priv; + feed_data = &mpq_feed->video_info; + + /* + * spin-lock is taken to protect against manipulation of video + * output buffer by the API (terminate video feed, re-use of video + * buffers). Mutex on the video-feed cannot be held here + * since SW demux holds a spin-lock while calling write_to_decoder + */ + spin_lock(&feed_data->video_buffer_lock); + stream_buffer = feed_data->video_buffer; + if (stream_buffer == NULL) { + MPQ_DVB_DBG_PRINT( + "%s: video_buffer released\n", + __func__); + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + ts_header = (const struct ts_packet_header *)buf; + + pes_header = &feed_data->pes_header; + + /* Make sure this TS packet has a payload and not scrambled */ + if ((ts_header->sync_byte != 0x47) || + (ts_header->adaptation_field_control == 0) || + (ts_header->adaptation_field_control == 2) || + (ts_header->transport_scrambling_control)) { + /* continue to next packet */ + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + if (ts_header->payload_unit_start_indicator) { /* PUSI? */ + if (feed->pusi_seen) { /* Did we see PUSI before? */ + struct mpq_streambuffer_packet_header packet; + struct mpq_adapter_video_meta_data meta_data; + + /* + * Close previous PES. + * Push new packet to the meta-data buffer. + * Double check that we are not in middle of + * previous PES header parsing. + */ + + if (feed_data->pes_header_left_bytes == 0) { + packet.raw_data_len = feed->peslen; + mpq_streambuffer_get_buffer_handle( + stream_buffer, + 0, /* current write buffer handle */ + &packet.raw_data_handle); + packet.raw_data_offset = + feed_data->frame_offset; + packet.user_data_len = + sizeof(struct + mpq_adapter_video_meta_data); + + mpq_dmx_write_pts_dts(feed_data, + &(meta_data.info.pes.pts_dts_info)); + + /* Mark that we detected start of new PES */ + feed_data->first_pts_dts_copy = 1; + + meta_data.packet_type = DMX_PES_PACKET; + meta_data.info.pes.stc = feed_data->prev_stc; + + mpq_dmx_update_decoder_stat(mpq_feed); + + cookie = mpq_streambuffer_pkt_write( + stream_buffer, &packet, + (u8 *)&meta_data); + if (cookie < 0) { + MPQ_DVB_ERR_PRINT + ("%s: write failed, ret=%d\n", + __func__, cookie); + } else { + /* + * Save write offset where new PES + * will begin + */ + mpq_streambuffer_get_data_rw_offset( + stream_buffer, + NULL, + &feed_data->frame_offset); + + mpq_dmx_prepare_es_event_data( + &packet, &meta_data, + feed_data, + stream_buffer, &data, cookie); + + feed->data_ready_cb.ts(&feed->feed.ts, + &data); + } + } else { + MPQ_DVB_ERR_PRINT( + "%s: received PUSI while handling PES header of previous PES\n", + __func__); + } + + /* Reset PES info */ + feed->peslen = 0; + feed_data->pes_header_offset = 0; + feed_data->pes_header_left_bytes = + PES_MANDATORY_FIELDS_LEN; + } else { + feed->pusi_seen = 1; + } + + feed_data->prev_stc = curr_stc; + } + + /* + * Parse PES data only if PUSI was encountered, + * otherwise the data is dropped + */ + if (!feed->pusi_seen) { + spin_unlock(&feed_data->video_buffer_lock); + return 0; /* drop and wait for next packets */ + } + + ts_payload_offset = sizeof(struct ts_packet_header); + + /* + * Skip adaptation field if exists. + * Save discontinuity indicator if exists. + */ + if (ts_header->adaptation_field_control == 3) { + const struct ts_adaptation_field *adaptation_field = + (const struct ts_adaptation_field *)(buf + + ts_payload_offset); + + discontinuity_indicator = + adaptation_field->discontinuity_indicator; + ts_payload_offset += buf[ts_payload_offset] + 1; + } + + bytes_avail = TS_PACKET_SIZE - ts_payload_offset; + + /* Get the mandatory fields of the video PES header */ + if (mpq_dmx_parse_mandatory_pes_header(feed, feed_data, + pes_header, buf, + &ts_payload_offset, + &bytes_avail)) { + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + if (mpq_dmx_parse_remaining_pes_header(feed, feed_data, + pes_header, buf, + &ts_payload_offset, + &bytes_avail)) { + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + /* + * If we reached here, + * then we are now at the PES payload data + */ + if (bytes_avail == 0) { + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + /* + * Need to back-up the PTS information + * of the start of new PES + */ + if (feed_data->first_pts_dts_copy) { + mpq_dmx_save_pts_dts(feed_data); + feed_data->first_pts_dts_copy = 0; + } + + /* Update error counters based on TS header */ + feed_data->ts_packets_num++; + feed_data->tei_errs += ts_header->transport_error_indicator; + mpq_demux->decoder_stat[feed_data->stream_interface].ts_errors += + ts_header->transport_error_indicator; + mpq_dmx_check_continuity(feed_data, + ts_header->continuity_counter, + discontinuity_indicator); + mpq_demux->decoder_stat[feed_data->stream_interface].cc_errors += + feed_data->continuity_errs; + + ret = mpq_streambuffer_data_write(stream_buffer, buf+ts_payload_offset, + bytes_avail); + if (ret < 0) { + mpq_demux->decoder_stat + [feed_data->stream_interface].drop_count += bytes_avail; + feed_data->ts_dropped_bytes += bytes_avail; + if (ret == -ENOSPC) + mpq_dmx_notify_overflow(feed); + } else { + feed->peslen += bytes_avail; + } + + spin_unlock(&feed_data->video_buffer_lock); + + return 0; +} + +/* function ptr used in several places, handle differently */ +int mpq_dmx_decoder_buffer_status(struct dvb_demux_feed *feed, + struct dmx_buffer_status *dmx_buffer_status) +{ + + if (dvb_dmx_is_video_feed(feed)) { + struct mpq_demux *mpq_demux = feed->demux->priv; + struct mpq_video_feed_info *feed_data; + struct mpq_streambuffer *video_buff; + struct mpq_feed *mpq_feed; + + mutex_lock(&mpq_demux->mutex); + + mpq_feed = feed->priv; + feed_data = &mpq_feed->video_info; + video_buff = feed_data->video_buffer; + if (!video_buff) { + mutex_unlock(&mpq_demux->mutex); + return -EINVAL; + } + + dmx_buffer_status->error = video_buff->raw_data.error; + + if (video_buff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) { + dmx_buffer_status->fullness = + video_buff->buffers[0].size * + video_buff->pending_buffers_count; + dmx_buffer_status->free_bytes = + video_buff->buffers[0].size * + (video_buff->buffers_num - + video_buff->pending_buffers_count); + dmx_buffer_status->size = + video_buff->buffers[0].size * + video_buff->buffers_num; + } else { + dmx_buffer_status->fullness = + mpq_streambuffer_data_avail(video_buff); + dmx_buffer_status->free_bytes = + mpq_streambuffer_data_free(video_buff); + dmx_buffer_status->size = video_buff->buffers[0].size; + } + + mpq_streambuffer_get_data_rw_offset( + video_buff, + &dmx_buffer_status->read_offset, + &dmx_buffer_status->write_offset); + + mutex_unlock(&mpq_demux->mutex); + + } else { + MPQ_DVB_ERR_PRINT("%s: Invalid feed type %d\n", + __func__, feed->pes_type); + return -EINVAL; + } + return 0; +} + +int mpq_dmx_process_video_packet( + struct dvb_demux_feed *feed, + const u8 *buf) +{ + u64 curr_stc; + struct mpq_demux *mpq_demux = feed->demux->priv; + + if ((mpq_demux->source >= DMX_SOURCE_DVR0) && + (mpq_demux->demux.tsp_format != DMX_TSP_FORMAT_192_TAIL)) { + curr_stc = 0; + } else { + curr_stc = buf[STC_LOCATION_IDX + 2] << 16; + curr_stc += buf[STC_LOCATION_IDX + 1] << 8; + curr_stc += buf[STC_LOCATION_IDX]; + curr_stc *= 256; /* convert from 105.47 KHZ to 27MHz */ + } + + if (!video_framing) + return mpq_dmx_process_video_packet_no_framing(feed, buf, + curr_stc); + else + return mpq_dmx_process_video_packet_framing(feed, buf, + curr_stc); +} + +int mpq_dmx_extract_pcr_and_dci(const u8 *buf, u64 *pcr, int *dci) +{ + const struct ts_packet_header *ts_header; + const struct ts_adaptation_field *adaptation_field; + + if (buf == NULL || pcr == NULL || dci == NULL) + return 0; + + ts_header = (const struct ts_packet_header *)buf; + + /* Make sure this TS packet has a adaptation field */ + if ((ts_header->sync_byte != 0x47) || + (ts_header->adaptation_field_control == 0) || + (ts_header->adaptation_field_control == 1) || + ts_header->transport_error_indicator) + return 0; + + adaptation_field = (const struct ts_adaptation_field *) + (buf + sizeof(struct ts_packet_header)); + + if ((!adaptation_field->adaptation_field_length) || + (!adaptation_field->PCR_flag)) + return 0; /* 0 adaptation field or no PCR */ + + *pcr = ((u64)adaptation_field->program_clock_reference_base_1) << 25; + *pcr += ((u64)adaptation_field->program_clock_reference_base_2) << 17; + *pcr += ((u64)adaptation_field->program_clock_reference_base_3) << 9; + *pcr += ((u64)adaptation_field->program_clock_reference_base_4) << 1; + *pcr += adaptation_field->program_clock_reference_base_5; + *pcr *= 300; + *pcr += (((u64)adaptation_field->program_clock_reference_ext_1) << 8) + + adaptation_field->program_clock_reference_ext_2; + + *dci = adaptation_field->discontinuity_indicator; + + return 1; +} + +int mpq_dmx_process_pcr_packet( + struct dvb_demux_feed *feed, + const u8 *buf) +{ + u64 stc; + struct dmx_data_ready data; + struct mpq_demux *mpq_demux = feed->demux->priv; + + if (mpq_dmx_extract_pcr_and_dci(buf, &data.pcr.pcr, + &data.pcr.disc_indicator_set) == 0) + return 0; + + /* + * When we play from front-end, we configure HW + * to output the extra timestamp, if we are playing + * from DVR, we don't have a timestamp if the packet + * format is not 192-tail. + */ + if ((mpq_demux->source >= DMX_SOURCE_DVR0) && + (mpq_demux->demux.tsp_format != DMX_TSP_FORMAT_192_TAIL)) { + stc = 0; + } else { + stc = buf[STC_LOCATION_IDX + 2] << 16; + stc += buf[STC_LOCATION_IDX + 1] << 8; + stc += buf[STC_LOCATION_IDX]; + stc *= 256; /* convert from 105.47 KHZ to 27MHz */ + } + + data.data_length = 0; + data.pcr.stc = stc; + data.status = DMX_OK_PCR; + feed->data_ready_cb.ts(&feed->feed.ts, &data); + + return 0; +} + +int mpq_dmx_decoder_eos_cmd(struct mpq_feed *mpq_feed) +{ + struct mpq_video_feed_info *feed_data = &mpq_feed->video_info; + struct mpq_streambuffer *stream_buffer; + struct mpq_streambuffer_packet_header oob_packet; + struct mpq_adapter_video_meta_data oob_meta_data; + int ret; + + spin_lock(&feed_data->video_buffer_lock); + stream_buffer = feed_data->video_buffer; + + if (stream_buffer == NULL) { + MPQ_DVB_DBG_PRINT("%s: video_buffer released\n", __func__); + spin_unlock(&feed_data->video_buffer_lock); + return 0; + } + + memset(&oob_packet, 0, sizeof(oob_packet)); + oob_packet.user_data_len = sizeof(oob_meta_data); + oob_meta_data.packet_type = DMX_EOS_PACKET; + + ret = mpq_streambuffer_pkt_write(stream_buffer, &oob_packet, + (u8 *)&oob_meta_data); + + spin_unlock(&feed_data->video_buffer_lock); + return (ret < 0) ? ret : 0; +} + +void mpq_dmx_convert_tts(struct dvb_demux_feed *feed, + const u8 timestamp[TIMESTAMP_LEN], + u64 *timestampIn27Mhz) +{ + if (unlikely(!timestampIn27Mhz)) + return; + + *timestampIn27Mhz = timestamp[2] << 16; + *timestampIn27Mhz += timestamp[1] << 8; + *timestampIn27Mhz += timestamp[0]; + *timestampIn27Mhz *= 256; /* convert from 105.47 KHZ to 27MHz */ +} + +int mpq_sdmx_open_session(struct mpq_demux *mpq_demux) +{ + enum sdmx_status ret = SDMX_SUCCESS; + enum sdmx_proc_mode proc_mode; + enum sdmx_pkt_format pkt_format; + + MPQ_DVB_DBG_PRINT("%s: ref_count %d\n", + __func__, mpq_demux->sdmx_session_ref_count); + + if (mpq_demux->sdmx_session_ref_count) { + /* session is already open */ + mpq_demux->sdmx_session_ref_count++; + return ret; + } + + proc_mode = (mpq_demux->demux.playback_mode == DMX_PB_MODE_PUSH) ? + SDMX_PUSH_MODE : SDMX_PULL_MODE; + MPQ_DVB_DBG_PRINT( + "%s: Proc mode = %s\n", + __func__, SDMX_PUSH_MODE == proc_mode ? "Push" : "Pull"); + + if (mpq_demux->source < DMX_SOURCE_DVR0) { + pkt_format = SDMX_192_BYTE_PKT; + } else if (mpq_demux->demux.tsp_format == DMX_TSP_FORMAT_188) { + pkt_format = SDMX_188_BYTE_PKT; + } else if (mpq_demux->demux.tsp_format == DMX_TSP_FORMAT_192_TAIL) { + pkt_format = SDMX_192_BYTE_PKT; + } else { + MPQ_DVB_ERR_PRINT("%s: invalid tsp format\n", __func__); + return -EINVAL; + } + + MPQ_DVB_DBG_PRINT("%s: (%s) source, packet format: %d\n", + __func__, + (mpq_demux->source < DMX_SOURCE_DVR0) ? + "frontend" : "DVR", pkt_format); + + /* open session and set configuration */ + ret = sdmx_open_session(&mpq_demux->sdmx_session_handle); + if (ret != SDMX_SUCCESS) { + MPQ_DVB_ERR_PRINT("%s: Could not open session. ret=%d\n", + __func__, ret); + return ret; + } + + MPQ_DVB_DBG_PRINT("%s: new session_handle = %d\n", + __func__, mpq_demux->sdmx_session_handle); + + ret = sdmx_set_session_cfg(mpq_demux->sdmx_session_handle, + proc_mode, + SDMX_PKT_ENC_MODE, + pkt_format, + mpq_sdmx_scramble_odd, + mpq_sdmx_scramble_even); + if (ret != SDMX_SUCCESS) { + MPQ_DVB_ERR_PRINT("%s: Could not set session config. ret=%d\n", + __func__, ret); + sdmx_close_session(mpq_demux->sdmx_session_handle); + mpq_demux->sdmx_session_handle = SDMX_INVALID_SESSION_HANDLE; + return -EINVAL; + } + + ret = sdmx_set_log_level(mpq_demux->sdmx_session_handle, + mpq_demux->sdmx_log_level); + if (ret != SDMX_SUCCESS) { + MPQ_DVB_ERR_PRINT("%s: Could not set log level. ret=%d\n", + __func__, ret); + /* Don't fail open session if just log level setting failed */ + ret = 0; + } + + mpq_demux->sdmx_process_count = 0; + mpq_demux->sdmx_process_time_sum = 0; + mpq_demux->sdmx_process_time_average = 0; + mpq_demux->sdmx_process_time_max = 0; + mpq_demux->sdmx_process_packets_sum = 0; + mpq_demux->sdmx_process_packets_average = 0; + mpq_demux->sdmx_process_packets_min = 0; + + mpq_demux->sdmx_session_ref_count++; + return ret; +} + +int mpq_sdmx_close_session(struct mpq_demux *mpq_demux) +{ + int ret = 0; + enum sdmx_status status; + + MPQ_DVB_DBG_PRINT("%s: session_handle = %d, ref_count %d\n", + __func__, + mpq_demux->sdmx_session_handle, + mpq_demux->sdmx_session_ref_count); + + if (!mpq_demux->sdmx_session_ref_count) + return -EINVAL; + + if (mpq_demux->sdmx_session_ref_count == 1) { + status = sdmx_close_session(mpq_demux->sdmx_session_handle); + if (status != SDMX_SUCCESS) { + MPQ_DVB_ERR_PRINT("%s: sdmx_close_session failed %d\n", + __func__, status); + } + mpq_demux->sdmx_eos = 0; + mpq_demux->sdmx_session_handle = SDMX_INVALID_SESSION_HANDLE; + } + + mpq_demux->sdmx_session_ref_count--; + + return ret; +} + +static int mpq_sdmx_get_buffer_chunks(struct mpq_demux *mpq_demux, + struct ion_dma_buff_info *buff_info, + u32 actual_buff_size, + struct sdmx_buff_descr buff_chunks[SDMX_MAX_PHYSICAL_CHUNKS]) +{ + int i; + struct sg_table *sg_ptr; + struct scatterlist *sg; + u32 chunk_size; + int ret; + + memset(buff_chunks, 0, + sizeof(struct sdmx_buff_descr) * SDMX_MAX_PHYSICAL_CHUNKS); + + sg_ptr = buff_info->sgt; + if (IS_ERR_OR_NULL(sg_ptr)) { + ret = PTR_ERR(sg_ptr); + MPQ_DVB_ERR_PRINT("%s: ion_sg_table failed, ret=%d\n", + __func__, ret); + if (!ret) + ret = -EINVAL; + return ret; + } + + if (sg_ptr->nents == 0) { + MPQ_DVB_ERR_PRINT("%s: num of scattered entries is 0\n", + __func__); + return -EINVAL; + } + + if (sg_ptr->nents > SDMX_MAX_PHYSICAL_CHUNKS) { + MPQ_DVB_ERR_PRINT( + "%s: num of scattered entries %d greater than max supported %d\n", + __func__, sg_ptr->nents, SDMX_MAX_PHYSICAL_CHUNKS); + return -EINVAL; + } + + sg = sg_ptr->sgl; + for (i = 0; i < sg_ptr->nents; i++) { + buff_chunks[i].base_addr = (u64)sg_dma_address(sg); + + if (sg->length > actual_buff_size) + chunk_size = actual_buff_size; + else + chunk_size = sg->length; + + buff_chunks[i].size = chunk_size; + sg = sg_next(sg); + actual_buff_size -= chunk_size; + } + + return 0; +} + +static int mpq_sdmx_init_data_buffer(struct mpq_demux *mpq_demux, + struct mpq_feed *feed, u32 *num_buffers, + struct sdmx_data_buff_descr buf_desc[DMX_MAX_DECODER_BUFFER_NUM], + enum sdmx_buf_mode *buf_mode) +{ + struct dvb_demux_feed *dvbdmx_feed = feed->dvb_demux_feed; + struct dvb_ringbuffer *buffer; + struct mpq_video_feed_info *feed_data = &feed->video_info; + struct ion_dma_buff_info *sdmx_buff; + int ret; + int i; + + *buf_mode = SDMX_RING_BUF; + + if (dvb_dmx_is_video_feed(feed->dvb_demux_feed)) { + + if (feed_data->buffer_desc.decoder_buffers_num > 1) + *buf_mode = SDMX_LINEAR_GROUP_BUF; + *num_buffers = feed_data->buffer_desc.decoder_buffers_num; + + MPQ_DVB_ERR_PRINT("%s: video feed case no of buffers=%zu\n", + __func__, *num_buffers); + + for (i = 0; i < *num_buffers; i++) { + buf_desc[i].length = + feed_data->buffer_desc.desc[i].size; + + ret = mpq_sdmx_get_buffer_chunks(mpq_demux, + &feed_data->buffer_desc.buff_dma_info[i], + buf_desc[i].length, + buf_desc[i].buff_chunks); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_sdmx_get_buffer_chunks failed\n", + __func__); + return ret; + } + } + + return 0; + } + + *num_buffers = 1; + if (dvb_dmx_is_sec_feed(dvbdmx_feed) || + dvb_dmx_is_pcr_feed(dvbdmx_feed)) { + buffer = &feed->sdmx_buf; + sdmx_buff = &feed->sdmx_dma_buff; + + buf_desc[0].length = buffer->size; + buf_desc[0].buff_chunks[0].base_addr = + feed->data_desc.phys_base; + buf_desc[0].buff_chunks[0].size = feed->data_desc.size; + } else { + buffer = (struct dvb_ringbuffer *) + dvbdmx_feed->feed.ts.buffer.ringbuff; + + sdmx_buff = &dvbdmx_feed->feed.ts.buffer.buff_dma_info; + + if (sdmx_buff == NULL) { + MPQ_DVB_ERR_PRINT( + "%s: Invalid buffer allocation\n", + __func__); + return -ENOMEM; + } + + buf_desc[0].length = buffer->size; + ret = mpq_sdmx_get_buffer_chunks(mpq_demux, sdmx_buff, + buf_desc[0].length, + buf_desc[0].buff_chunks); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_sdmx_get_buffer_chunks failed\n", + __func__); + return ret; + } + + } + return 0; +} + +static int mpq_sdmx_filter_setup(struct mpq_demux *mpq_demux, + struct dvb_demux_feed *dvbdmx_feed) +{ + int ret = 0; + struct mpq_feed *feed; + struct mpq_feed *main_rec_feed = NULL; + struct dvb_demux_feed *tmp; + struct sdmx_buff_descr metadata_buff_desc; + struct sdmx_data_buff_descr *data_buff_desc = NULL; + u32 data_buf_num = DMX_MAX_DECODER_BUFFER_NUM; + enum sdmx_buf_mode buf_mode; + enum sdmx_raw_out_format ts_out_format = SDMX_188_OUTPUT; + u32 filter_flags = 0; + + feed = dvbdmx_feed->priv; + + if (dvb_dmx_is_sec_feed(dvbdmx_feed)) { + feed->filter_type = SDMX_SECTION_FILTER; + if (dvbdmx_feed->feed.sec.check_crc) + filter_flags |= SDMX_FILTER_FLAG_VERIFY_SECTION_CRC; + MPQ_DVB_DBG_PRINT("%s: SDMX_SECTION_FILTER\n", __func__); + } else if (dvb_dmx_is_pcr_feed(dvbdmx_feed)) { + feed->filter_type = SDMX_PCR_FILTER; + MPQ_DVB_DBG_PRINT("%s: SDMX_PCR_FILTER\n", __func__); + } else if (dvb_dmx_is_video_feed(dvbdmx_feed)) { + feed->filter_type = SDMX_SEPARATED_PES_FILTER; + MPQ_DVB_DBG_PRINT("%s: SDMX_SEPARATED_PES_FILTER\n", __func__); + } else if (dvb_dmx_is_rec_feed(dvbdmx_feed)) { + feed->filter_type = SDMX_RAW_FILTER; + switch (dvbdmx_feed->tsp_out_format) { + case (DMX_TSP_FORMAT_188): + ts_out_format = SDMX_188_OUTPUT; + break; + case (DMX_TSP_FORMAT_192_HEAD): + ts_out_format = SDMX_192_HEAD_OUTPUT; + break; + case (DMX_TSP_FORMAT_192_TAIL): + ts_out_format = SDMX_192_TAIL_OUTPUT; + break; + default: + MPQ_DVB_ERR_PRINT( + "%s: Unsupported TS output format %d\n", + __func__, dvbdmx_feed->tsp_out_format); + return -EINVAL; + } + MPQ_DVB_DBG_PRINT("%s: SDMX_RAW_FILTER\n", __func__); + } else { + feed->filter_type = SDMX_PES_FILTER; + MPQ_DVB_DBG_PRINT("%s: SDMX_PES_FILTER\n", __func__); + } + + data_buff_desc = vmalloc( + sizeof(*data_buff_desc)*DMX_MAX_DECODER_BUFFER_NUM); + if (!data_buff_desc) { + MPQ_DVB_ERR_PRINT( + "%s: failed to allocate memory for data buffer\n", + __func__); + return -ENOMEM; + } + + /* + * Recording feed sdmx filter handle lookup: + * In case this is a recording filter with multiple feeds, + * this feed is either the first feed of a new recording filter, + * or it is another feed of an existing filter for which a filter was + * already opened with sdmx. In such case, we need to look up in the + * feed pool for a allocated feed with same output buffer (meaning they + * belong to the same filter) and to use the already allocated sdmx + * filter handle. + */ + if (feed->filter_type == SDMX_RAW_FILTER) { + tmp = mpq_dmx_peer_rec_feed(dvbdmx_feed); + if (tmp) + main_rec_feed = tmp->priv; + } + + /* + * If this PID is not part of existing recording filter, + * configure a new filter to SDMX. + */ + if (!main_rec_feed) { + feed->secondary_feed = 0; + + MPQ_DVB_DBG_PRINT("%s: Adding new sdmx filter", __func__); + MPQ_DVB_DBG_PRINT("%s: pid %d, flags=0x%X, ts_out_format=%d\n", + __func__, dvbdmx_feed->pid, filter_flags, + ts_out_format); + + /* Meta-data initialization, + * Recording filters do no need meta-data buffers. + */ + if (dvb_dmx_is_rec_feed(dvbdmx_feed)) { + metadata_buff_desc.base_addr = 0; + metadata_buff_desc.size = 0; + } else { + ret = mpq_sdmx_init_metadata_buffer(mpq_demux, feed, + &metadata_buff_desc); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: Failed to initialize metadata buffer. ret=%d\n", + __func__, ret); + goto sdmx_filter_setup_failed; + } + } + + ret = mpq_sdmx_init_data_buffer(mpq_demux, feed, &data_buf_num, + data_buff_desc, &buf_mode); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: Failed to initialize data buffer. ret=%d\n", + __func__, ret); + mpq_sdmx_terminate_metadata_buffer(feed); + goto sdmx_filter_setup_failed; + } + ret = sdmx_add_filter(mpq_demux->sdmx_session_handle, + dvbdmx_feed->pid, + feed->filter_type, + &metadata_buff_desc, + buf_mode, + data_buf_num, + data_buff_desc, + &feed->sdmx_filter_handle, + ts_out_format, + filter_flags); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: SDMX_add_filter failed. ret = %d\n", + __func__, ret); + ret = -ENODEV; + mpq_sdmx_terminate_metadata_buffer(feed); + goto sdmx_filter_setup_failed; + } + + MPQ_DVB_DBG_PRINT( + "%s: filter pid=%d, handle=%d, data buffer(s)=%d, size=%d\n", + __func__, dvbdmx_feed->pid, + feed->sdmx_filter_handle, + data_buf_num, data_buff_desc[0].length); + + mpq_demux->sdmx_filter_count++; + } else { + MPQ_DVB_DBG_PRINT( + "%s: Adding RAW pid to sdmx, pid %d\n", + __func__, dvbdmx_feed->pid); + + feed->secondary_feed = 1; + feed->sdmx_filter_handle = main_rec_feed->sdmx_filter_handle; + ret = sdmx_add_raw_pid(mpq_demux->sdmx_session_handle, + feed->sdmx_filter_handle, dvbdmx_feed->pid); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: FAILED to add raw pid, ret=%d\n", + __func__, ret); + ret = -ENODEV; + goto sdmx_filter_setup_failed; + } + } + + /* + * If pid has a key ladder id associated, we need to + * set it to SDMX. + */ + if (dvbdmx_feed->secure_mode.is_secured && + dvbdmx_feed->cipher_ops.operations_count) { + MPQ_DVB_DBG_PRINT( + "%s: set key-ladder %d to PID %d\n", + __func__, + dvbdmx_feed->cipher_ops.operations[0].key_ladder_id, + dvbdmx_feed->cipher_ops.pid); + + ret = sdmx_set_kl_ind(mpq_demux->sdmx_session_handle, + dvbdmx_feed->cipher_ops.pid, + dvbdmx_feed->cipher_ops.operations[0].key_ladder_id); + + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: FAILED to set key ladder, ret=%d\n", + __func__, ret); + } + } + + vfree(data_buff_desc); + return 0; + +sdmx_filter_setup_failed: + vfree(data_buff_desc); + return ret; +} + +/** + * mpq_sdmx_init_feed - initialize secure demux related elements of mpq feed + * + * @mpq_demux: mpq_demux object + * @mpq_feed: mpq_feed object + * + * Note: the function assumes mpq_demux->mutex locking is done by caller. + */ +static int mpq_sdmx_init_feed(struct mpq_demux *mpq_demux, + struct mpq_feed *mpq_feed) +{ + int ret; + + ret = mpq_sdmx_open_session(mpq_demux); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_sdmx_open_session failed, ret=%d\n", + __func__, ret); + + ret = -ENODEV; + goto init_sdmx_feed_failed; + } + + /* PCR and sections have internal buffer for SDMX */ + if (dvb_dmx_is_pcr_feed(mpq_feed->dvb_demux_feed)) + ret = mpq_sdmx_alloc_data_buf(mpq_feed, SDMX_PCR_BUFFER_SIZE); + else if (dvb_dmx_is_sec_feed(mpq_feed->dvb_demux_feed)) + ret = mpq_sdmx_alloc_data_buf(mpq_feed, + SDMX_SECTION_BUFFER_SIZE); + else + ret = 0; + + if (ret) { + MPQ_DVB_ERR_PRINT("%s: init buffer failed, ret=%d\n", + __func__, ret); + goto init_sdmx_feed_failed_free_sdmx; + } + + ret = mpq_sdmx_filter_setup(mpq_demux, mpq_feed->dvb_demux_feed); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_sdmx_filter_setup failed, ret=%d\n", + __func__, ret); + goto init_sdmx_feed_failed_free_data_buff; + } + + mpq_demux->num_secure_feeds++; + return 0; + +init_sdmx_feed_failed_free_data_buff: + mpq_sdmx_free_data_buf(mpq_feed); +init_sdmx_feed_failed_free_sdmx: + mpq_sdmx_close_session(mpq_demux); +init_sdmx_feed_failed: + return ret; +} + +int mpq_dmx_init_mpq_feed(struct dvb_demux_feed *feed) +{ + int ret = 0; + struct mpq_demux *mpq_demux = feed->demux->priv; + struct mpq_feed *mpq_feed = feed->priv; + + if (mutex_lock_interruptible(&mpq_demux->mutex)) + return -ERESTARTSYS; + + mpq_feed->sdmx_filter_handle = SDMX_INVALID_FILTER_HANDLE; + + if (feed->type != DMX_TYPE_SEC) + feed->feed.ts.flush_buffer = mpq_dmx_flush_buffer; + + if (dvb_dmx_is_video_feed(feed)) { + ret = mpq_dmx_init_video_feed(mpq_feed); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_dmx_init_video_feed failed, ret=%d\n", + __func__, ret); + goto init_mpq_feed_end; + } + } + + /* + * sdmx is not relevant for recording filters, which always use + * regular filters (non-sdmx) + */ + if (!mpq_sdmx_is_loaded() || !feed->secure_mode.is_secured || + dvb_dmx_is_rec_feed(feed)) { + if (!mpq_sdmx_is_loaded()) + mpq_demux->sdmx_session_handle = + SDMX_INVALID_SESSION_HANDLE; + MPQ_DVB_ERR_PRINT( + " %s: init feed exit\n", + __func__); + goto init_mpq_feed_end; + } + MPQ_DVB_ERR_PRINT( + "%s: mpq_sdmx_init_feed enter\n", + __func__); + MPQ_DVB_DBG_PRINT("%s: Init sdmx feed start\n", __func__); + + /* Initialization of secure demux filters (PES/PCR/Video/Section) */ + ret = mpq_sdmx_init_feed(mpq_demux, mpq_feed); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_sdmx_init_feed failed, ret=%d\n", + __func__, ret); + if (dvb_dmx_is_video_feed(feed)) + mpq_dmx_terminate_video_feed(mpq_feed); + } + +init_mpq_feed_end: + if (!ret) { + mpq_demux->num_active_feeds++; + mpq_feed->session_id++; + } + mutex_unlock(&mpq_demux->mutex); + return ret; +} + +/** + * Note: Called only when filter is in "GO" state - after feed has been started. + */ +int mpq_dmx_set_cipher_ops(struct dvb_demux_feed *feed, + struct dmx_cipher_operations *cipher_ops) +{ + struct mpq_feed *mpq_feed; + struct mpq_demux *mpq_demux; + int ret = 0; + + if (!feed || !feed->priv || !cipher_ops) { + MPQ_DVB_ERR_PRINT( + "%s: invalid parameters\n", + __func__); + return -EINVAL; + } + + MPQ_DVB_DBG_PRINT("%s(%d, %d, %d)\n", + __func__, cipher_ops->pid, + cipher_ops->operations_count, + cipher_ops->operations[0].key_ladder_id); + + if ((cipher_ops->operations_count > 1) || + (cipher_ops->operations_count && + cipher_ops->operations[0].encrypt)) { + MPQ_DVB_ERR_PRINT( + "%s: Invalid cipher operations, count=%d, encrypt=%d\n", + __func__, cipher_ops->operations_count, + cipher_ops->operations[0].encrypt); + return -EINVAL; + } + + if (!feed->secure_mode.is_secured) { + /* + * Filter is not configured as secured, setting cipher + * operations is not allowed. + */ + MPQ_DVB_ERR_PRINT( + "%s: Cannot set cipher operations to non-secure filter\n", + __func__); + return -EPERM; + } + + mpq_feed = feed->priv; + mpq_demux = mpq_feed->mpq_demux; + + mutex_lock(&mpq_demux->mutex); + + /* + * Feed is running in secure mode, this secure mode request is to + * update the key ladder id + */ + if ((mpq_demux->sdmx_session_handle != SDMX_INVALID_SESSION_HANDLE) && + cipher_ops->operations_count) { + ret = sdmx_set_kl_ind(mpq_demux->sdmx_session_handle, + cipher_ops->pid, + cipher_ops->operations[0].key_ladder_id); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: FAILED to set key ladder, ret=%d\n", + __func__, ret); + ret = -ENODEV; + } + } + + mutex_unlock(&mpq_demux->mutex); + + return ret; +} + +static int mpq_sdmx_invalidate_buffer(struct mpq_feed *mpq_feed) +{ + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + struct dvb_ringbuffer *buffer; + int ret = 0; + + if (!dvb_dmx_is_video_feed(feed)) { + if (dvb_dmx_is_sec_feed(feed) || + dvb_dmx_is_pcr_feed(feed)) { + buffer = (struct dvb_ringbuffer *) + &mpq_feed->sdmx_buf; + } else { + buffer = (struct dvb_ringbuffer *) + feed->feed.ts.buffer.ringbuff; + } + } + return ret; +} + +static void mpq_sdmx_prepare_filter_status(struct mpq_demux *mpq_demux, + struct sdmx_filter_status *filter_sts, + struct mpq_feed *mpq_feed) +{ + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + struct mpq_video_feed_info *feed_data; + struct mpq_streambuffer *sbuff; + + filter_sts->filter_handle = mpq_feed->sdmx_filter_handle; + filter_sts->metadata_fill_count = + dvb_ringbuffer_avail(&mpq_feed->metadata_buf); + filter_sts->metadata_write_offset = mpq_feed->metadata_buf.pwrite; + filter_sts->error_indicators = 0; + filter_sts->status_indicators = 0; + + MPQ_DVB_DBG_PRINT( + "%s: Filter meta-data buffer status: fill count = %d, write_offset = %d\n", + __func__, filter_sts->metadata_fill_count, + filter_sts->metadata_write_offset); + + if (!dvb_dmx_is_video_feed(feed)) { + struct dvb_ringbuffer *buffer; + + if (dvb_dmx_is_sec_feed(feed) || + dvb_dmx_is_pcr_feed(feed)) { + buffer = (struct dvb_ringbuffer *) + &mpq_feed->sdmx_buf; + } else { + buffer = (struct dvb_ringbuffer *) + feed->feed.ts.buffer.ringbuff; + } + + filter_sts->data_fill_count = dvb_ringbuffer_avail(buffer); + filter_sts->data_write_offset = buffer->pwrite; + + MPQ_DVB_DBG_PRINT( + "%s: Filter buffers status: fill count = %d, write_offset = %d\n", + __func__, filter_sts->data_fill_count, + filter_sts->data_write_offset); + + return; + } + + /* Video feed - decoder buffers */ + feed_data = &mpq_feed->video_info; + + spin_lock(&mpq_feed->video_info.video_buffer_lock); + sbuff = feed_data->video_buffer; + if (sbuff == NULL) { + MPQ_DVB_DBG_PRINT( + "%s: video_buffer released\n", + __func__); + spin_unlock(&feed_data->video_buffer_lock); + return; + } + + if (feed_data->buffer_desc.decoder_buffers_num > 1) { + /* linear mode */ + filter_sts->data_fill_count = sbuff->pending_buffers_count; + filter_sts->data_write_offset = + sbuff->raw_data.pwrite / + sizeof(struct mpq_streambuffer_buffer_desc); + } else { + /* ring buffer mode */ + filter_sts->data_fill_count = + mpq_streambuffer_data_avail(sbuff); + mpq_streambuffer_get_data_rw_offset(sbuff, NULL, + &filter_sts->data_write_offset); + + } + + spin_unlock(&mpq_feed->video_info.video_buffer_lock); + + MPQ_DVB_DBG_PRINT( + "%s: Decoder buffers filter status: fill count = %d, write_offset = %d\n", + __func__, filter_sts->data_fill_count, + filter_sts->data_write_offset); +} + +static int mpq_sdmx_section_filtering(struct mpq_feed *mpq_feed, + struct dvb_demux_filter *f, + struct sdmx_metadata_header *header) +{ + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + int ret; + u8 neq = 0; + u8 xor; + u8 tmp; + int i; + + if (!mutex_is_locked(&mpq_feed->mpq_demux->mutex)) { + MPQ_DVB_ERR_PRINT( + "%s: Mutex should have been locked\n", + __func__); + return -EINVAL; + } + + for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { + tmp = DVB_RINGBUFFER_PEEK(&mpq_feed->sdmx_buf, i); + xor = f->filter.filter_value[i] ^ tmp; + + if (f->maskandmode[i] & xor) + return 0; + + neq |= f->maskandnotmode[i] & xor; + } + + if (f->doneq && !neq) + return 0; + + if (feed->demux->playback_mode == DMX_PB_MODE_PULL) { + mutex_unlock(&mpq_feed->mpq_demux->mutex); + + ret = feed->demux->buffer_ctrl.sec(&f->filter, + header->payload_length, 1); + + mutex_lock(&mpq_feed->mpq_demux->mutex); + + if (ret) { + MPQ_DVB_DBG_PRINT( + "%s: buffer_ctrl.sec aborted\n", + __func__); + return ret; + } + + if (mpq_feed->sdmx_filter_handle == + SDMX_INVALID_FILTER_HANDLE) { + MPQ_DVB_DBG_PRINT("%s: filter was stopped\n", + __func__); + return -ENODEV; + } + } + + if (mpq_feed->sdmx_buf.pread + header->payload_length < + mpq_feed->sdmx_buf.size) { + feed->cb.sec(&mpq_feed->sdmx_buf.data[mpq_feed->sdmx_buf.pread], + header->payload_length, + NULL, 0, &f->filter); + } else { + int split = mpq_feed->sdmx_buf.size - mpq_feed->sdmx_buf.pread; + + feed->cb.sec(&mpq_feed->sdmx_buf.data[mpq_feed->sdmx_buf.pread], + split, + &mpq_feed->sdmx_buf.data[0], + header->payload_length - split, + &f->filter); + } + + return 0; +} + +static int mpq_sdmx_check_ts_stall(struct mpq_demux *mpq_demux, + struct mpq_feed *mpq_feed, + struct sdmx_filter_status *sts, + size_t req, + int events_only) +{ + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + int ret; + + if (!mutex_is_locked(&mpq_feed->mpq_demux->mutex)) { + MPQ_DVB_ERR_PRINT( + "%s: Mutex should have been locked\n", + __func__); + return -EINVAL; + } + + /* + * For PULL mode need to verify there is enough space for the dmxdev + * event. Also, if data buffer is full we want to stall until some + * data is removed from it to prevent calling the sdmx when it cannot + * output data to the still full buffer. + */ + if (mpq_demux->demux.playback_mode == DMX_PB_MODE_PULL) { + MPQ_DVB_DBG_PRINT("%s: Stalling for events and %zu bytes\n", + __func__, req); + + mutex_unlock(&mpq_demux->mutex); + + ret = mpq_demux->demux.buffer_ctrl.ts(&feed->feed.ts, req, 1); + MPQ_DVB_DBG_PRINT("%s: stall result = %d\n", + __func__, ret); + + mutex_lock(&mpq_demux->mutex); + + if (mpq_feed->sdmx_filter_handle == + SDMX_INVALID_FILTER_HANDLE) { + MPQ_DVB_DBG_PRINT("%s: filter was stopped\n", + __func__); + return -ENODEV; + } + + return ret; + } + + return 0; +} + +/* Handle filter results for filters with no extra meta-data */ +static void mpq_sdmx_pes_filter_results(struct mpq_demux *mpq_demux, + struct mpq_feed *mpq_feed, + struct sdmx_filter_status *sts) +{ + int ret; + struct sdmx_metadata_header header; + struct sdmx_pes_counters counters; + struct dmx_data_ready data_event; + struct dmx_data_ready pes_event; + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + struct dvb_ringbuffer *buf = (struct dvb_ringbuffer *) + feed->feed.ts.buffer.ringbuff; + ssize_t bytes_avail; + + if ((!sts->metadata_fill_count) && (!sts->data_fill_count)) + goto pes_filter_check_overflow; + + MPQ_DVB_DBG_PRINT( + "%s: Meta: fill=%u, write=%u. Data: fill=%u, write=%u\n", + __func__, sts->metadata_fill_count, sts->metadata_write_offset, + sts->data_fill_count, sts->data_write_offset); + + mpq_feed->metadata_buf.pwrite = sts->metadata_write_offset; + + if ((sts->metadata_fill_count == 0) && + (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)) { + ssize_t free = dvb_ringbuffer_free(buf); + + ret = 0; + if ((free + SZ_2K) < MAX_PES_LENGTH) + ret = mpq_sdmx_check_ts_stall(mpq_demux, mpq_feed, sts, + free + SZ_2K, 0); + else + MPQ_DVB_ERR_PRINT( + "%s: Cannot stall when free space bigger than max PES size\n", + __func__); + if (ret) { + MPQ_DVB_DBG_PRINT( + "%s: mpq_sdmx_check_ts_stall aborted\n", + __func__); + return; + } + } + + while (sts->metadata_fill_count) { + bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf); + if (bytes_avail < (sizeof(header) + sizeof(counters))) { + MPQ_DVB_ERR_PRINT( + "%s: metadata_fill_count is %d less than required %zu bytes\n", + __func__, + sts->metadata_fill_count, + sizeof(header) + sizeof(counters)); + + /* clean-up remaining bytes to try to recover */ + DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf, + bytes_avail); + sts->metadata_fill_count = 0; + break; + } + + dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *)&header, + sizeof(header)); + MPQ_DVB_DBG_PRINT( + "%s: metadata header: start=%u, length=%u\n", + __func__, header.payload_start, header.payload_length); + sts->metadata_fill_count -= sizeof(header); + + dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *)&counters, + sizeof(counters)); + sts->metadata_fill_count -= sizeof(counters); + + /* Notify new data in buffer */ + data_event.status = DMX_OK; + data_event.data_length = header.payload_length; + ret = mpq_sdmx_check_ts_stall(mpq_demux, mpq_feed, sts, + data_event.data_length, 0); + if (ret) { + MPQ_DVB_DBG_PRINT( + "%s: mpq_sdmx_check_ts_stall aborted\n", + __func__); + return; + } + + feed->data_ready_cb.ts(&feed->feed.ts, &data_event); + + /* Notify new complete PES */ + pes_event.status = DMX_OK_PES_END; + pes_event.pes_end.actual_length = header.payload_length; + pes_event.pes_end.start_gap = 0; + pes_event.data_length = 0; + + /* Parse error indicators */ + if (sts->error_indicators & SDMX_FILTER_ERR_INVALID_PES_LEN) + pes_event.pes_end.pes_length_mismatch = 1; + else + pes_event.pes_end.pes_length_mismatch = 0; + + pes_event.pes_end.disc_indicator_set = 0; + + pes_event.pes_end.stc = 0; + pes_event.pes_end.tei_counter = counters.transport_err_count; + pes_event.pes_end.cont_err_counter = + counters.continuity_err_count; + pes_event.pes_end.ts_packets_num = + counters.pes_ts_count; + + ret = mpq_sdmx_check_ts_stall(mpq_demux, mpq_feed, sts, 0, 1); + if (ret) { + MPQ_DVB_DBG_PRINT( + "%s: mpq_sdmx_check_ts_stall aborted\n", + __func__); + return; + } + feed->data_ready_cb.ts(&feed->feed.ts, &pes_event); + } + +pes_filter_check_overflow: + if ((mpq_demux->demux.playback_mode == DMX_PB_MODE_PUSH) && + (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)) { + MPQ_DVB_ERR_PRINT("%s: DMX_OVERRUN_ERROR\n", __func__); + mpq_dmx_notify_overflow(feed); + } + + if (sts->status_indicators & SDMX_FILTER_STATUS_EOS) { + data_event.data_length = 0; + data_event.status = DMX_OK_EOS; + feed->data_ready_cb.ts(&feed->feed.ts, &data_event); + } +} + +static void mpq_sdmx_section_filter_results(struct mpq_demux *mpq_demux, + struct mpq_feed *mpq_feed, + struct sdmx_filter_status *sts) +{ + struct sdmx_metadata_header header; + struct dmx_data_ready event; + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + struct dvb_demux_filter *f; + struct dmx_section_feed *sec = &feed->feed.sec; + ssize_t bytes_avail; + + /* Parse error indicators */ + if (sts->error_indicators & SDMX_FILTER_ERR_SEC_VERIF_CRC32_FAIL) { + MPQ_DVB_DBG_PRINT("%s: Notify CRC err event\n", __func__); + event.status = DMX_CRC_ERROR; + event.data_length = 0; + dvb_dmx_notify_section_event(feed, &event, 1); + } + + if (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL) + MPQ_DVB_ERR_PRINT("%s: internal section buffer overflowed!\n", + __func__); + + if ((!sts->metadata_fill_count) && (!sts->data_fill_count)) + goto section_filter_check_eos; + + mpq_feed->metadata_buf.pwrite = sts->metadata_write_offset; + mpq_feed->sdmx_buf.pwrite = sts->data_write_offset; + + while (sts->metadata_fill_count) { + bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf); + if (bytes_avail < sizeof(header)) { + MPQ_DVB_ERR_PRINT( + "%s: metadata_fill_count is %d less than required %zu bytes\n", + __func__, + sts->metadata_fill_count, + sizeof(header)); + + /* clean-up remaining bytes to try to recover */ + DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf, + bytes_avail); + sts->metadata_fill_count = 0; + break; + } + + dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *) &header, + sizeof(header)); + sts->metadata_fill_count -= sizeof(header); + MPQ_DVB_DBG_PRINT( + "%s: metadata header: start=%u, length=%u\n", + __func__, header.payload_start, header.payload_length); + + f = feed->filter; + do { + if (mpq_sdmx_section_filtering(mpq_feed, f, &header)) + return; + } while ((f = f->next) && sec->is_filtering); + + DVB_RINGBUFFER_SKIP(&mpq_feed->sdmx_buf, header.payload_length); + } + +section_filter_check_eos: + if (sts->status_indicators & SDMX_FILTER_STATUS_EOS) { + event.data_length = 0; + event.status = DMX_OK_EOS; + dvb_dmx_notify_section_event(feed, &event, 1); + } +} + +static void mpq_sdmx_decoder_filter_results(struct mpq_demux *mpq_demux, + struct mpq_feed *mpq_feed, + struct sdmx_filter_status *sts) +{ + struct sdmx_metadata_header header; + struct sdmx_pes_counters counters; + int pes_header_offset; + struct ts_packet_header *ts_header; + struct ts_adaptation_field *ts_adapt; + struct pes_packet_header *pes_header; + u8 metadata_buf[MAX_SDMX_METADATA_LENGTH]; + struct mpq_streambuffer *sbuf; + int ret; + struct dmx_data_ready data_event; + struct dmx_data_ready data; + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + ssize_t bytes_avail; + + if ((!sts->metadata_fill_count) && (!sts->data_fill_count)) + goto decoder_filter_check_flags; + + /* Update meta data buffer write pointer */ + mpq_feed->metadata_buf.pwrite = sts->metadata_write_offset; + + if ((mpq_demux->demux.playback_mode == DMX_PB_MODE_PULL) && + (sts->error_indicators & SDMX_FILTER_ERR_D_LIN_BUFS_FULL)) { + MPQ_DVB_DBG_PRINT("%s: Decoder stall...\n", __func__); + + ret = mpq_dmx_decoder_fullness_check( + mpq_feed->dvb_demux_feed, 0, 0); + if (ret) { + /* we reach here if demuxing was aborted */ + MPQ_DVB_DBG_PRINT( + "%s: mpq_dmx_decoder_fullness_check aborted\n", + __func__); + return; + } + } + + while (sts->metadata_fill_count) { + struct mpq_streambuffer_packet_header packet; + struct mpq_adapter_video_meta_data meta_data; + + bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf); + if (bytes_avail < (sizeof(header) + sizeof(counters))) { + MPQ_DVB_ERR_PRINT( + "%s: metadata_fill_count is %d less than required %zu bytes\n", + __func__, + sts->metadata_fill_count, + sizeof(header) + sizeof(counters)); + + /* clean-up remaining bytes to try to recover */ + DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf, + bytes_avail); + sts->metadata_fill_count = 0; + break; + } + + /* Read metadata header */ + dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *)&header, + sizeof(header)); + sts->metadata_fill_count -= sizeof(header); + MPQ_DVB_DBG_PRINT( + "%s: metadata header: start=%u, length=%u, metadata=%u\n", + __func__, header.payload_start, header.payload_length, + header.metadata_length); + + /* Read metadata - PES counters */ + dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *)&counters, + sizeof(counters)); + sts->metadata_fill_count -= sizeof(counters); + + /* Read metadata - TS & PES headers */ + bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf); + if ((header.metadata_length < MAX_SDMX_METADATA_LENGTH) && + (header.metadata_length >= sizeof(counters)) && + (bytes_avail >= + (header.metadata_length - sizeof(counters)))) { + dvb_ringbuffer_read(&mpq_feed->metadata_buf, + metadata_buf, + header.metadata_length - sizeof(counters)); + } else { + MPQ_DVB_ERR_PRINT( + "%s: meta-data size %d larger than available meta-data %zd or max allowed %d\n", + __func__, header.metadata_length, + bytes_avail, + MAX_SDMX_METADATA_LENGTH); + + /* clean-up remaining bytes to try to recover */ + DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf, + bytes_avail); + sts->metadata_fill_count = 0; + break; + } + + sts->metadata_fill_count -= + (header.metadata_length - sizeof(counters)); + + ts_header = (struct ts_packet_header *)&metadata_buf[0]; + if (ts_header->adaptation_field_control == 1) { + ts_adapt = NULL; + pes_header_offset = sizeof(*ts_header); + } else { + ts_adapt = (struct ts_adaptation_field *) + &metadata_buf[sizeof(*ts_header)]; + pes_header_offset = sizeof(*ts_header) + 1 + + ts_adapt->adaptation_field_length; + } + pes_header = (struct pes_packet_header *) + &metadata_buf[pes_header_offset]; + meta_data.packet_type = DMX_PES_PACKET; + /* TODO - set to real STC when SDMX supports it */ + meta_data.info.pes.stc = 0; + + if (pes_header->pts_dts_flag & 0x2) { + meta_data.info.pes.pts_dts_info.pts_exist = 1; + meta_data.info.pes.pts_dts_info.pts = + ((u64)pes_header->pts_1 << 30) | + ((u64)pes_header->pts_2 << 22) | + ((u64)pes_header->pts_3 << 15) | + ((u64)pes_header->pts_4 << 7) | + (u64)pes_header->pts_5; + } else { + meta_data.info.pes.pts_dts_info.pts_exist = 0; + } + + if (pes_header->pts_dts_flag & 0x1) { + meta_data.info.pes.pts_dts_info.dts_exist = 1; + meta_data.info.pes.pts_dts_info.dts = + ((u64)pes_header->dts_1 << 30) | + ((u64)pes_header->dts_2 << 22) | + ((u64)pes_header->dts_3 << 15) | + ((u64)pes_header->dts_4 << 7) | + (u64)pes_header->dts_5; + } else { + meta_data.info.pes.pts_dts_info.dts_exist = 0; + } + + spin_lock(&mpq_feed->video_info.video_buffer_lock); + + mpq_feed->video_info.tei_errs = + counters.transport_err_count; + mpq_feed->video_info.continuity_errs = + counters.continuity_err_count; + mpq_feed->video_info.ts_packets_num = + counters.pes_ts_count; + mpq_feed->video_info.ts_dropped_bytes = + counters.drop_count * + mpq_demux->demux.ts_packet_size; + + sbuf = mpq_feed->video_info.video_buffer; + if (sbuf == NULL) { + MPQ_DVB_DBG_PRINT( + "%s: video_buffer released\n", + __func__); + spin_unlock(&mpq_feed->video_info.video_buffer_lock); + return; + } + + if (!header.payload_length) { + MPQ_DVB_DBG_PRINT( + "%s: warnning - video frame with 0 length, dropping\n", + __func__); + spin_unlock(&mpq_feed->video_info.video_buffer_lock); + continue; + } + + packet.raw_data_len = header.payload_length; + packet.user_data_len = sizeof(meta_data); + mpq_streambuffer_get_buffer_handle(sbuf, 0, + &packet.raw_data_handle); + mpq_streambuffer_get_data_rw_offset(sbuf, + NULL, &packet.raw_data_offset); + ret = mpq_streambuffer_data_write_deposit(sbuf, + header.payload_length); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_streambuffer_data_write_deposit failed. ret=%d\n", + __func__, ret); + } + mpq_dmx_update_decoder_stat(mpq_feed); + ret = mpq_streambuffer_pkt_write(sbuf, &packet, + (u8 *)&meta_data); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_streambuffer_pkt_write failed, ret=%d\n", + __func__, ret); + } else { + mpq_dmx_prepare_es_event_data( + &packet, &meta_data, &mpq_feed->video_info, + sbuf, &data, ret); + MPQ_DVB_DBG_PRINT("%s: Notify ES Event\n", __func__); + feed->data_ready_cb.ts(&feed->feed.ts, &data); + } + + spin_unlock(&mpq_feed->video_info.video_buffer_lock); + } + +decoder_filter_check_flags: + if ((mpq_demux->demux.playback_mode == DMX_PB_MODE_PUSH) && + (sts->error_indicators & SDMX_FILTER_ERR_D_LIN_BUFS_FULL)) { + MPQ_DVB_ERR_PRINT("%s: DMX_OVERRUN_ERROR\n", __func__); + mpq_dmx_notify_overflow(mpq_feed->dvb_demux_feed); + } + + if (sts->status_indicators & SDMX_FILTER_STATUS_EOS) { + /* Notify decoder via the stream buffer */ + ret = mpq_dmx_decoder_eos_cmd(mpq_feed); + if (ret) + MPQ_DVB_ERR_PRINT( + "%s: Failed to notify decoder on EOS, ret=%d\n", + __func__, ret); + + /* Notify user filter */ + data_event.data_length = 0; + data_event.status = DMX_OK_EOS; + mpq_feed->dvb_demux_feed->data_ready_cb.ts( + &mpq_feed->dvb_demux_feed->feed.ts, &data_event); + } +} + +static void mpq_sdmx_pcr_filter_results(struct mpq_demux *mpq_demux, + struct mpq_feed *mpq_feed, + struct sdmx_filter_status *sts) +{ + int ret; + struct sdmx_metadata_header header; + struct dmx_data_ready data; + struct dvb_ringbuffer *rbuff = &mpq_feed->sdmx_buf; + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + u8 buf[TS_PACKET_HEADER_LENGTH + MAX_TSP_ADAPTATION_LENGTH + + TIMESTAMP_LEN]; + size_t stc_len = 0; + ssize_t bytes_avail; + + if (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL) + MPQ_DVB_ERR_PRINT("%s: internal PCR buffer overflowed!\n", + __func__); + + if ((!sts->metadata_fill_count) && (!sts->data_fill_count)) + goto pcr_filter_check_eos; + + if (mpq_demux->demux.tsp_format == DMX_TSP_FORMAT_192_TAIL) + stc_len = 4; + + mpq_feed->metadata_buf.pwrite = sts->metadata_write_offset; + rbuff->pwrite = sts->data_write_offset; + + while (sts->metadata_fill_count) { + bytes_avail = dvb_ringbuffer_avail(&mpq_feed->metadata_buf); + if (bytes_avail < sizeof(header)) { + MPQ_DVB_ERR_PRINT( + "%s: metadata_fill_count is %d less than required %zu bytes\n", + __func__, + sts->metadata_fill_count, + sizeof(header)); + + /* clean-up remaining bytes to try to recover */ + DVB_RINGBUFFER_SKIP(&mpq_feed->metadata_buf, + bytes_avail); + sts->metadata_fill_count = 0; + break; + } + + dvb_ringbuffer_read(&mpq_feed->metadata_buf, (u8 *) &header, + sizeof(header)); + MPQ_DVB_DBG_PRINT( + "%s: metadata header: start=%u, length=%u\n", + __func__, header.payload_start, header.payload_length); + sts->metadata_fill_count -= sizeof(header); + + dvb_ringbuffer_read(rbuff, buf, header.payload_length); + + if (mpq_dmx_extract_pcr_and_dci(buf, &data.pcr.pcr, + &data.pcr.disc_indicator_set)) { + + if (stc_len) { + data.pcr.stc = + buf[header.payload_length-2] << 16; + data.pcr.stc += + buf[header.payload_length-3] << 8; + data.pcr.stc += buf[header.payload_length-4]; + /* convert from 105.47 KHZ to 27MHz */ + data.pcr.stc *= 256; + } else { + data.pcr.stc = 0; + } + + data.data_length = 0; + data.status = DMX_OK_PCR; + ret = mpq_sdmx_check_ts_stall( + mpq_demux, mpq_feed, sts, 0, 1); + if (ret) { + MPQ_DVB_DBG_PRINT( + "%s: mpq_sdmx_check_ts_stall aborted\n", + __func__); + return; + } + feed->data_ready_cb.ts(&feed->feed.ts, &data); + } + } + +pcr_filter_check_eos: + if (sts->status_indicators & SDMX_FILTER_STATUS_EOS) { + data.data_length = 0; + data.status = DMX_OK_EOS; + feed->data_ready_cb.ts(&feed->feed.ts, &data); + } +} + +static void mpq_sdmx_raw_filter_results(struct mpq_demux *mpq_demux, + struct mpq_feed *mpq_feed, + struct sdmx_filter_status *sts) +{ + int ret; + ssize_t new_data; + struct dmx_data_ready data_event; + struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed; + struct dvb_ringbuffer *buf = (struct dvb_ringbuffer *) + feed->feed.ts.buffer.ringbuff; + + if ((!sts->metadata_fill_count) && (!sts->data_fill_count)) + goto raw_filter_check_flags; + + new_data = sts->data_write_offset - + buf->pwrite; + if (new_data < 0) + new_data += buf->size; + + ret = mpq_sdmx_check_ts_stall(mpq_demux, mpq_feed, sts, + new_data + feed->demux->ts_packet_size, 0); + if (ret) { + MPQ_DVB_DBG_PRINT( + "%s: mpq_sdmx_check_ts_stall aborted\n", + __func__); + return; + } + + data_event.status = DMX_OK; + data_event.data_length = new_data; + feed->data_ready_cb.ts(&feed->feed.ts, &data_event); + MPQ_DVB_DBG_PRINT("%s: Callback DMX_OK, size=%d\n", + __func__, data_event.data_length); + +raw_filter_check_flags: + if ((mpq_demux->demux.playback_mode == DMX_PB_MODE_PUSH) && + (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)) { + MPQ_DVB_DBG_PRINT("%s: DMX_OVERRUN_ERROR\n", __func__); + mpq_dmx_notify_overflow(feed); + } + + if (sts->status_indicators & SDMX_FILTER_STATUS_EOS) { + data_event.data_length = 0; + data_event.status = DMX_OK_EOS; + feed->data_ready_cb.ts(&feed->feed.ts, &data_event); + } + +} + +static void mpq_sdmx_process_results(struct mpq_demux *mpq_demux) +{ + int i; + int sdmx_filters; + struct sdmx_filter_status *sts; + struct mpq_feed *mpq_feed; + u8 mpq_feed_idx; + + sdmx_filters = mpq_demux->sdmx_filter_count; + for (i = 0; i < sdmx_filters; i++) { + sts = &mpq_demux->sdmx_filters_state.status[i]; + MPQ_DVB_DBG_PRINT( + "%s: Filter: handle=%d, status=0x%x, errors=0x%x\n", + __func__, sts->filter_handle, sts->status_indicators, + sts->error_indicators); + MPQ_DVB_DBG_PRINT("%s: Metadata fill count=%d (write=%d)\n", + __func__, sts->metadata_fill_count, + sts->metadata_write_offset); + MPQ_DVB_DBG_PRINT("%s: Data fill count=%d (write=%d)\n", + __func__, sts->data_fill_count, sts->data_write_offset); + + mpq_feed_idx = mpq_demux->sdmx_filters_state.mpq_feed_idx[i]; + mpq_feed = &mpq_demux->feeds[mpq_feed_idx]; + if ((mpq_feed->dvb_demux_feed->state != DMX_STATE_GO) || + (sts->filter_handle != mpq_feed->sdmx_filter_handle) || + mpq_feed->secondary_feed || + (mpq_demux->sdmx_filters_state.session_id[i] != + mpq_feed->session_id)) + continue; + + /* Invalidate output buffer before processing the results */ + if (!mpq_demux->disable_cache_ops) + mpq_sdmx_invalidate_buffer(mpq_feed); + + if (sts->error_indicators & SDMX_FILTER_ERR_MD_BUF_FULL) + MPQ_DVB_ERR_PRINT( + "%s: meta-data buff for pid %d overflowed!\n", + __func__, mpq_feed->dvb_demux_feed->pid); + + switch (mpq_feed->filter_type) { + case SDMX_PCR_FILTER: + mpq_sdmx_pcr_filter_results(mpq_demux, mpq_feed, sts); + break; + case SDMX_PES_FILTER: + mpq_sdmx_pes_filter_results(mpq_demux, mpq_feed, + sts); + break; + case SDMX_SEPARATED_PES_FILTER: + mpq_sdmx_decoder_filter_results(mpq_demux, mpq_feed, + sts); + break; + case SDMX_SECTION_FILTER: + mpq_sdmx_section_filter_results(mpq_demux, mpq_feed, + sts); + break; + case SDMX_RAW_FILTER: + mpq_sdmx_raw_filter_results(mpq_demux, mpq_feed, sts); + break; + default: + break; + } + } +} + +static int mpq_sdmx_process_buffer(struct mpq_demux *mpq_demux, + struct sdmx_buff_descr *input, + u32 fill_count, + u32 read_offset) +{ + struct sdmx_filter_status *sts; + struct mpq_feed *mpq_feed; + u8 flags = 0; + u32 errors; + u32 status; + u32 prev_read_offset; + u32 prev_fill_count; + enum sdmx_status sdmx_res; + int i; + int filter_index = 0; + int bytes_read; + ktime_t process_start_time; + ktime_t process_end_time; + + mutex_lock(&mpq_demux->mutex); + + /* + * All active filters may get totally closed and therefore + * sdmx session may get terminated, in such case nothing to process + */ + if (mpq_demux->sdmx_session_handle == SDMX_INVALID_SESSION_HANDLE) { + MPQ_DVB_DBG_PRINT( + "%s: sdmx filters aborted, filter-count %d, session %d\n", + __func__, mpq_demux->sdmx_filter_count, + mpq_demux->sdmx_session_handle); + mutex_unlock(&mpq_demux->mutex); + return 0; + } + + /* Set input flags */ + if (mpq_demux->sdmx_eos) + flags |= SDMX_INPUT_FLAG_EOS; + if (mpq_sdmx_debug) + flags |= SDMX_INPUT_FLAG_DBG_ENABLE; + + /* Build up to date filter status array */ + for (i = 0; i < MPQ_MAX_DMX_FILES; i++) { + mpq_feed = &mpq_demux->feeds[i]; + if ((mpq_feed->sdmx_filter_handle != SDMX_INVALID_FILTER_HANDLE) + && (!mpq_feed->secondary_feed)) { + sts = mpq_demux->sdmx_filters_state.status + + filter_index; + mpq_sdmx_prepare_filter_status(mpq_demux, sts, + mpq_feed); + mpq_demux->sdmx_filters_state.mpq_feed_idx[filter_index] + = i; + mpq_demux->sdmx_filters_state.session_id[filter_index] = + mpq_feed->session_id; + filter_index++; + } + } + + /* Sanity check */ + if (filter_index != mpq_demux->sdmx_filter_count) { + mutex_unlock(&mpq_demux->mutex); + MPQ_DVB_ERR_PRINT( + "%s: Updated %d SDMX filters status but should be %d\n", + __func__, filter_index, mpq_demux->sdmx_filter_count); + return -ERESTART; + } + + MPQ_DVB_DBG_PRINT( + "%s: Before SDMX_process: input read_offset=%u, fill count=%u\n", + __func__, read_offset, fill_count); + + process_start_time = ktime_get(); + + prev_read_offset = read_offset; + prev_fill_count = fill_count; + sdmx_res = sdmx_process(mpq_demux->sdmx_session_handle, flags, input, + &fill_count, &read_offset, &errors, &status, + mpq_demux->sdmx_filter_count, + mpq_demux->sdmx_filters_state.status); + + process_end_time = ktime_get(); + bytes_read = prev_fill_count - fill_count; + + mpq_dmx_update_sdmx_stat(mpq_demux, bytes_read, + process_start_time, process_end_time); + + MPQ_DVB_DBG_PRINT( + "%s: SDMX result=%d, input_fill_count=%u, read_offset=%u, read %d bytes from input, status=0x%X, errors=0x%X\n", + __func__, sdmx_res, fill_count, read_offset, bytes_read, + status, errors); + + if ((sdmx_res == SDMX_SUCCESS) || + (sdmx_res == SDMX_STATUS_STALLED_IN_PULL_MODE)) { + if (sdmx_res == SDMX_STATUS_STALLED_IN_PULL_MODE) + MPQ_DVB_DBG_PRINT("%s: SDMX stalled for PULL mode\n", + __func__); + + mpq_sdmx_process_results(mpq_demux); + } else { + MPQ_DVB_ERR_PRINT( + "%s: SDMX Process returned %d\n", + __func__, sdmx_res); + } + + mutex_unlock(&mpq_demux->mutex); + + return bytes_read; +} + +int mpq_sdmx_process(struct mpq_demux *mpq_demux, + struct sdmx_buff_descr *input, + u32 fill_count, + u32 read_offset, + size_t tsp_size) +{ + int ret; + int todo; + int total_bytes_read = 0; + int limit = mpq_sdmx_proc_limit * tsp_size; + + MPQ_DVB_DBG_PRINT( + "%s: read_offset=%u, fill_count=%u, tsp_size=%zu\n", + __func__, read_offset, fill_count, tsp_size); + + while (fill_count >= tsp_size) { + todo = fill_count > limit ? limit : fill_count; + ret = mpq_sdmx_process_buffer(mpq_demux, input, todo, + read_offset); + + if (mpq_demux->demux.sw_filter_abort) { + MPQ_DVB_ERR_PRINT( + "%s: Demuxing from DVR was aborted\n", + __func__); + return -ENODEV; + } + + if (ret > 0) { + total_bytes_read += ret; + fill_count -= ret; + read_offset += ret; + if (read_offset >= input->size) + read_offset -= input->size; + } else { + /* + * ret < 0: some error occurred + * ret == 0: not enough data (less than 1 TS packet) + */ + if (ret < 0) + MPQ_DVB_ERR_PRINT( + "%s: mpq_sdmx_process_buffer failed, returned %d\n", + __func__, ret); + break; + } + } + + return total_bytes_read; +} + +static int mpq_sdmx_write(struct mpq_demux *mpq_demux, + struct ion_dma_buff_info *dvr_input_buff, + const char *buf, + size_t count) +{ + struct ion_dma_buff_info *buff; + struct dvb_ringbuffer *rbuf; + struct sdmx_buff_descr buf_desc; + u32 read_offset; + int ret; + + if (mpq_demux == NULL || dvr_input_buff == NULL) { + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + buff = &mpq_demux->demux.dmx.dvr_input.buff_dma_info; + rbuf = (struct dvb_ringbuffer *)mpq_demux->demux.dmx.dvr_input.ringbuff; + + ret = mpq_sdmx_dvr_buffer_desc(mpq_demux, &buf_desc); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: Failed to init input buffer descriptor. ret = %d\n", + __func__, ret); + return ret; + } + read_offset = mpq_demux->demux.dmx.dvr_input.ringbuff->pread; + + return mpq_sdmx_process(mpq_demux, &buf_desc, count, + read_offset, mpq_demux->demux.ts_packet_size); + return 0; +} + +int mpq_dmx_write(struct dmx_demux *demux, const char *buf, size_t count) +{ + struct dvb_demux *dvb_demux; + struct mpq_demux *mpq_demux; + int ret = count; + + if (demux == NULL) + return -EINVAL; + + dvb_demux = demux->priv; + mpq_demux = dvb_demux->priv; + + /* Route through secure demux - process secure feeds if any exist */ + if (mpq_sdmx_is_loaded() && mpq_demux->sdmx_filter_count) { + ret = mpq_sdmx_write(mpq_demux, + &demux->dvr_input.buff_dma_info, + buf, + count); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_sdmx_write failed. ret = %d\n", + __func__, ret); + ret = count; + } + } + + /* + * Route through sw filter - process non-secure feeds if any exist. + * For sw filter, should process the same amount of bytes the sdmx + * process managed to consume, unless some sdmx error occurred, for + * which should process the whole buffer + */ + if (mpq_demux->num_active_feeds > mpq_demux->num_secure_feeds) + dvb_dmx_swfilter_format(dvb_demux, buf, ret, + dvb_demux->tsp_format); + + if (signal_pending(current)) + return -EINTR; + + return ret; +} + +int mpq_sdmx_is_loaded(void) +{ + static int sdmx_load_checked; + + if (!sdmx_load_checked) { + mpq_sdmx_check_app_loaded(); + sdmx_load_checked = 1; + } + + return mpq_dmx_info.secure_demux_app_loaded; +} + +int mpq_dmx_oob_command(struct dvb_demux_feed *feed, + struct dmx_oob_command *cmd) +{ + struct mpq_feed *mpq_feed = feed->priv; + struct mpq_demux *mpq_demux = mpq_feed->mpq_demux; + struct dmx_data_ready event; + int ret = 0; + + mutex_lock(&mpq_demux->mutex); + mpq_feed = feed->priv; + + if (!dvb_dmx_is_video_feed(feed) && !dvb_dmx_is_pcr_feed(feed) && + !feed->secure_mode.is_secured) { + mutex_unlock(&mpq_demux->mutex); + return 0; + } + + event.data_length = 0; + + switch (cmd->type) { + case DMX_OOB_CMD_EOS: + event.status = DMX_OK_EOS; + if (!feed->secure_mode.is_secured) { + if (dvb_dmx_is_video_feed(feed)) { + if (!video_framing) + mpq_dmx_decoder_pes_closure(mpq_demux, + mpq_feed); + else + mpq_dmx_decoder_frame_closure(mpq_demux, + mpq_feed); + ret = mpq_dmx_decoder_eos_cmd(mpq_feed); + if (ret) + MPQ_DVB_ERR_PRINT( + "%s: Couldn't write oob eos packet\n", + __func__); + } + ret = feed->data_ready_cb.ts(&feed->feed.ts, &event); + } else if (!mpq_demux->sdmx_eos) { + struct sdmx_buff_descr buf_desc; + + mpq_demux->sdmx_eos = 1; + ret = mpq_sdmx_dvr_buffer_desc(mpq_demux, &buf_desc); + if (!ret) { + mutex_unlock(&mpq_demux->mutex); + mpq_sdmx_process_buffer(mpq_demux, &buf_desc, + 0, 0); + return 0; + } + } + break; + case DMX_OOB_CMD_MARKER: + event.status = DMX_OK_MARKER; + event.marker.id = cmd->params.marker.id; + + if (feed->type == DMX_TYPE_SEC) + ret = dvb_dmx_notify_section_event(feed, &event, 1); + else + /* MPQ_TODO: Notify decoder via the stream buffer */ + ret = feed->data_ready_cb.ts(&feed->feed.ts, &event); + break; + + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&mpq_demux->mutex); + return ret; +} diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h new file mode 100644 index 000000000000..9b00dacbfc38 --- /dev/null +++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h @@ -0,0 +1,1031 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MPQ_DMX_PLUGIN_COMMON_H +#define _MPQ_DMX_PLUGIN_COMMON_H + +#include + +#include "dvbdev.h" +#include "dmxdev.h" +#include "demux.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "mpq_adapter.h" +#include "mpq_sdmx.h" + +#define TS_PACKET_SYNC_BYTE (0x47) +#define TS_PACKET_SIZE (188) +#define TS_PACKET_HEADER_LENGTH (4) + +/* Length of mandatory fields that must exist in header of video PES */ +#define PES_MANDATORY_FIELDS_LEN 9 + +/* + * 500 PES header packets in the meta-data buffer, + * should be more than enough + */ +#define VIDEO_NUM_OF_PES_PACKETS 500 + +#define VIDEO_META_DATA_PACKET_SIZE \ + (DVB_RINGBUFFER_PKTHDRSIZE + \ + sizeof(struct mpq_streambuffer_packet_header) + \ + sizeof(struct mpq_adapter_video_meta_data)) + +#define VIDEO_META_DATA_BUFFER_SIZE \ + (VIDEO_NUM_OF_PES_PACKETS * VIDEO_META_DATA_PACKET_SIZE) + +/* Max number open() request can be done on demux device */ +#define MPQ_MAX_DMX_FILES 128 + +/* TSIF alias name length */ +#define TSIF_NAME_LENGTH 20 + +enum demux_cache_ops { +DEMUX_CACHE_CLEAN, +DEMUX_CACHE_INVALIDATE, +}; + +/** + * struct ts_packet_header - Transport packet header + * as defined in MPEG2 transport stream standard. + */ +struct ts_packet_header { +#if defined(__BIG_ENDIAN_BITFIELD) + unsigned sync_byte:8; + unsigned transport_error_indicator:1; + unsigned payload_unit_start_indicator:1; + unsigned transport_priority:1; + unsigned pid_msb:5; + unsigned pid_lsb:8; + unsigned transport_scrambling_control:2; + unsigned adaptation_field_control:2; + unsigned continuity_counter:4; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + unsigned sync_byte:8; + unsigned pid_msb:5; + unsigned transport_priority:1; + unsigned payload_unit_start_indicator:1; + unsigned transport_error_indicator:1; + unsigned pid_lsb:8; + unsigned continuity_counter:4; + unsigned adaptation_field_control:2; + unsigned transport_scrambling_control:2; +#else +#error "Please fix " +#endif +} __packed; + +/** + * struct ts_adaptation_field - Adaptation field prefix + * as defined in MPEG2 transport stream standard. + */ +struct ts_adaptation_field { +#if defined(__BIG_ENDIAN_BITFIELD) + unsigned adaptation_field_length:8; + unsigned discontinuity_indicator:1; + unsigned random_access_indicator:1; + unsigned elementary_stream_priority_indicator:1; + unsigned PCR_flag:1; + unsigned OPCR_flag:1; + unsigned splicing_point_flag:1; + unsigned transport_private_data_flag:1; + unsigned adaptation_field_extension_flag:1; + unsigned program_clock_reference_base_1:8; + unsigned program_clock_reference_base_2:8; + unsigned program_clock_reference_base_3:8; + unsigned program_clock_reference_base_4:8; + unsigned program_clock_reference_base_5:1; + unsigned reserved:6; + unsigned program_clock_reference_ext_1:1; + unsigned program_clock_reference_ext_2:8; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + unsigned adaptation_field_length:8; + unsigned adaptation_field_extension_flag:1; + unsigned transport_private_data_flag:1; + unsigned splicing_point_flag:1; + unsigned OPCR_flag:1; + unsigned PCR_flag:1; + unsigned elementary_stream_priority_indicator:1; + unsigned random_access_indicator:1; + unsigned discontinuity_indicator:1; + unsigned program_clock_reference_base_1:8; + unsigned program_clock_reference_base_2:8; + unsigned program_clock_reference_base_3:8; + unsigned program_clock_reference_base_4:8; + unsigned program_clock_reference_ext_1:1; + unsigned reserved:6; + unsigned program_clock_reference_base_5:1; + unsigned program_clock_reference_ext_2:8; +#else +#error "Please fix " +#endif +} __packed; + + +/* + * PES packet header containing dts and/or pts values + * as defined in MPEG2 transport stream standard. + */ +struct pes_packet_header { +#if defined(__BIG_ENDIAN_BITFIELD) + unsigned packet_start_code_prefix_1:8; + unsigned packet_start_code_prefix_2:8; + unsigned packet_start_code_prefix_3:8; + unsigned stream_id:8; + unsigned pes_packet_length_msb:8; + unsigned pes_packet_length_lsb:8; + unsigned reserved_bits0:2; + unsigned pes_scrambling_control:2; + unsigned pes_priority:1; + unsigned data_alignment_indicator:1; + unsigned copyright:1; + unsigned original_or_copy:1; + unsigned pts_dts_flag:2; + unsigned escr_flag:1; + unsigned es_rate_flag:1; + unsigned dsm_trick_mode_flag:1; + unsigned additional_copy_info_flag:1; + unsigned pes_crc_flag:1; + unsigned pes_extension_flag:1; + unsigned pes_header_data_length:8; + unsigned reserved_bits1:4; + unsigned pts_1:3; + unsigned marker_bit0:1; + unsigned pts_2:8; + unsigned pts_3:7; + unsigned marker_bit1:1; + unsigned pts_4:8; + unsigned pts_5:7; + unsigned marker_bit2:1; + unsigned reserved_bits2:4; + unsigned dts_1:3; + unsigned marker_bit3:1; + unsigned dts_2:8; + unsigned dts_3:7; + unsigned marker_bit4:1; + unsigned dts_4:8; + unsigned dts_5:7; + unsigned marker_bit5:1; + unsigned reserved_bits3:4; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + unsigned packet_start_code_prefix_1:8; + unsigned packet_start_code_prefix_2:8; + unsigned packet_start_code_prefix_3:8; + unsigned stream_id:8; + unsigned pes_packet_length_lsb:8; + unsigned pes_packet_length_msb:8; + unsigned original_or_copy:1; + unsigned copyright:1; + unsigned data_alignment_indicator:1; + unsigned pes_priority:1; + unsigned pes_scrambling_control:2; + unsigned reserved_bits0:2; + unsigned pes_extension_flag:1; + unsigned pes_crc_flag:1; + unsigned additional_copy_info_flag:1; + unsigned dsm_trick_mode_flag:1; + unsigned es_rate_flag:1; + unsigned escr_flag:1; + unsigned pts_dts_flag:2; + unsigned pes_header_data_length:8; + unsigned marker_bit0:1; + unsigned pts_1:3; + unsigned reserved_bits1:4; + unsigned pts_2:8; + unsigned marker_bit1:1; + unsigned pts_3:7; + unsigned pts_4:8; + unsigned marker_bit2:1; + unsigned pts_5:7; + unsigned marker_bit3:1; + unsigned dts_1:3; + unsigned reserved_bits2:4; + unsigned dts_2:8; + unsigned marker_bit4:1; + unsigned dts_3:7; + unsigned dts_4:8; + unsigned marker_bit5:1; + unsigned dts_5:7; + unsigned reserved_bits3:4; +#else +#error "Please fix " +#endif +} __packed; + +/** + * mpq_decoder_buffers_desc - decoder buffer(s) management information. + * + * @desc: Array of buffer descriptors as they are passed to mpq_streambuffer + * upon its initialization. These descriptors must remain valid as long as + * the mpq_streambuffer object is used. + * @ion_handle: Array of ION handles, one for each decoder buffer, used for + * kernel memory mapping or allocation. Handles are saved in order to release + * resources properly later on. + * @decoder_buffers_num: number of buffers that are managed, either externally + * or internally by the mpq_streambuffer object + * @shared_file: File handle of internally allocated video buffer shared + * with video consumer. + */ +struct mpq_decoder_buffers_desc { + struct mpq_streambuffer_buffer_desc desc[DMX_MAX_DECODER_BUFFER_NUM]; + struct ion_dma_buff_info buff_dma_info[DMX_MAX_DECODER_BUFFER_NUM]; + u32 decoder_buffers_num; + struct file *shared_file; +}; + +/* + * mpq_video_feed_info - private data used for video feed. + * + * @video_buffer: Holds the streamer buffer shared with + * the decoder for feeds having the data going to the decoder. + * @video_buffer_lock: Lock protecting against video output buffer. + * The lock protects against API calls to manipulate the output buffer + * (initialize, free, re-use buffers) and dvb-sw demux parsing the video + * data through mpq_dmx_process_video_packet(). + * @buffer_desc: Holds decoder buffer(s) information used for stream buffer. + * @pes_header: Used for feeds that output data to decoder, + * holds PES header of current processed PES. + * @pes_header_left_bytes: Used for feeds that output data to decoder, + * holds remaining PES header bytes of current processed PES. + * @pes_header_offset: Holds the offset within the current processed + * pes header. + * @fullness_wait_cancel: Flag used to signal to abort waiting for + * decoder's fullness. + * @stream_interface: The ID of the video stream interface registered + * with this stream buffer. + * @patterns: pointer to the framing patterns to look for. + * @patterns_num: number of framing patterns. + * @prev_pattern: holds the trailing data of the last processed video packet. + * @frame_offset: Saves data buffer offset to which a new frame will be written + * @last_pattern_offset: Holds the previous pattern offset + * @pending_pattern_len: Accumulated number of data bytes that will be + * reported for this frame. + * @last_framing_match_type: Used for saving the type of + * the previous pattern match found in this video feed. + * @last_framing_match_stc: Used for saving the STC attached to TS packet + * of the previous pattern match found in this video feed. + * @found_sequence_header_pattern: Flag used to note that an MPEG-2 + * Sequence Header, H.264 SPS or VC-1 Sequence Header pattern + * (whichever is relevant according to the video standard) had already + * been found. + * @prefix_size: a bit mask representing the size(s) of possible prefixes + * to the pattern, already found in the previous buffer. If bit 0 is set, + * a prefix of size 1 was found. If bit 1 is set, a prefix of size 2 was + * found, etc. This supports a prefix size of up to 32, which is more + * than we need. The search function updates prefix_size as needed + * for the next buffer search. + * @first_prefix_size: used to save the prefix size used to find the first + * pattern written to the stream buffer. + * @saved_pts_dts_info: used to save PTS/DTS information until it is written. + * @new_pts_dts_info: used to store PTS/DTS information from current PES header. + * @saved_info_used: indicates if saved PTS/DTS information was used. + * @new_info_exists: indicates if new PTS/DTS information exists in + * new_pts_dts_info that should be saved to saved_pts_dts_info. + * @first_pts_dts_copy: a flag used to indicate if PTS/DTS information needs + * to be copied from the currently parsed PES header to the saved_pts_dts_info. + * @tei_errs: Transport stream Transport Error Indicator (TEI) counter. + * @last_continuity: last continuity counter value found in TS packet header. + * Initialized to -1. + * @continuity_errs: Transport stream continuity error counter. + * @ts_packets_num: TS packets counter. + * @ts_dropped_bytes: counts the number of bytes dropped due to insufficient + * buffer space. + * @prev_stc: STC attached to the previous video TS packet + */ +struct mpq_video_feed_info { + struct mpq_streambuffer *video_buffer; + spinlock_t video_buffer_lock; + struct mpq_decoder_buffers_desc buffer_desc; + struct pes_packet_header pes_header; + u32 pes_header_left_bytes; + u32 pes_header_offset; + int fullness_wait_cancel; + enum mpq_adapter_stream_if stream_interface; +const struct dvb_dmx_video_patterns *patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM]; + int patterns_num; + char prev_pattern[DVB_DMX_MAX_PATTERN_LEN]; + u32 frame_offset; + u32 last_pattern_offset; + u32 pending_pattern_len; + u64 last_framing_match_type; + u64 last_framing_match_stc; + int found_sequence_header_pattern; + struct dvb_dmx_video_prefix_size_masks prefix_size; + u32 first_prefix_size; + struct dmx_pts_dts_info saved_pts_dts_info; + struct dmx_pts_dts_info new_pts_dts_info; + int saved_info_used; + int new_info_exists; + int first_pts_dts_copy; + u32 tei_errs; + int last_continuity; + u32 continuity_errs; + u32 ts_packets_num; + u32 ts_dropped_bytes; + u64 prev_stc; +}; + +/** + * mpq feed object - mpq common plugin feed information + * + * @dvb_demux_feed: Back pointer to dvb demux level feed object + * @mpq_demux: Pointer to common mpq demux object + * @plugin_priv: Plugin specific private data + * @sdmx_filter_handle: Secure demux filter handle. Recording feed may share + * same filter handle + * @secondary_feed: Specifies if this feed shares filter handle with + * other feeds + * @metadata_buf: Ring buffer object for managing the metadata buffer + * @metadata_buf_handle: Allocation handle for the metadata buffer + * @session_id: Counter that is incremented every time feed is initialized + * through mpq_dmx_init_mpq_feed + * @sdmx_buf: Ring buffer object for intermediate output data from the sdmx + * @sdmx_buf_handle: Allocation handle for the sdmx intermediate data buffer + * @video_info: Video feed specific information + */ +struct mpq_feed { + struct dvb_demux_feed *dvb_demux_feed; + struct mpq_demux *mpq_demux; + void *plugin_priv; + + /* Secure demux related */ + int sdmx_filter_handle; + int secondary_feed; + enum sdmx_filter filter_type; + struct dvb_ringbuffer metadata_buf; + struct ion_dma_buff_info metadata_dma_buff; + struct sdmx_buff_descriptor metadata_desc; + + u8 session_id; + struct dvb_ringbuffer sdmx_buf; + struct ion_dma_buff_info sdmx_dma_buff; + struct sdmx_buff_descriptor data_desc; + + struct mpq_video_feed_info video_info; +}; + +/** + * struct mpq_demux - mpq demux information + * @idx: Instance index + * @demux: The dvb_demux instance used by mpq_demux + * @dmxdev: The dmxdev instance used by mpq_demux + * @fe_memory: Handle of front-end memory source to mpq_demux + * @source: The current source connected to the demux + * @is_initialized: Indicates whether this demux device was + * initialized or not. + * @ion_client: ION demux client used to allocate memory from ION. + * @mutex: Lock used to protect against private feed data + * @feeds: mpq common feed object pool + * @num_active_feeds: Number of active mpq feeds + * @num_secure_feeds: Number of secure feeds (have a sdmx filter associated) + * currently allocated. + * Used before each call to sdmx_process() to build up to date state. + * @sdmx_session_handle: Secure demux open session handle + * @sdmx_filter_count: Number of active secure demux filters + * @sdmx_eos: End-of-stream indication flag for current sdmx session + * @sdmx_filters_state: Array holding buffers status for each secure + * demux filter. + * @decoder_alloc_flags: ION flags to be used when allocating internally + * @plugin_priv: Underlying plugin's own private data + * @mpq_dmx_plugin_release: Underlying plugin's release function + * @hw_notification_interval: Notification interval in msec, + * exposed in debugfs. + * @hw_notification_min_interval: Minimum notification internal in msec, + * exposed in debugfs. + * @hw_notification_count: Notification count, exposed in debugfs. + * @hw_notification_size: Notification size in bytes, exposed in debugfs. + * @hw_notification_min_size: Minimum notification size in bytes, + * exposed in debugfs. + * @decoder_stat: Decoder output statistics, exposed in debug-fs. + * @sdmx_process_count: Total number of times sdmx_process is called. + * @sdmx_process_time_sum: Total time sdmx_process takes. + * @sdmx_process_time_average: Average time sdmx_process takes. + * @sdmx_process_time_max: Max time sdmx_process takes. + * @sdmx_process_packets_sum: Total packets number sdmx_process handled. + * @sdmx_process_packets_average: Average packets number sdmx_process handled. + * @sdmx_process_packets_min: Minimum packets number sdmx_process handled. + * @last_notification_time: Time of last HW notification. + */ +struct mpq_demux { + int idx; + struct platform_device *pdev; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend fe_memory; + dmx_source_t source; + int is_initialized; + struct ion_client *ion_client; + struct mutex mutex; + struct mpq_feed feeds[MPQ_MAX_DMX_FILES]; + u32 num_active_feeds; + u32 num_secure_feeds; + int sdmx_session_handle; + int sdmx_session_ref_count; + int sdmx_filter_count; + int sdmx_eos; + struct { + /* SDMX filters status */ + struct sdmx_filter_status status[MPQ_MAX_DMX_FILES]; + + /* Index of the feed respective to SDMX filter */ + u8 mpq_feed_idx[MPQ_MAX_DMX_FILES]; + + /* + * Snapshot of session_id of the feed + * when SDMX process was called. This is used + * to identify whether the feed has been + * restarted when processing SDMX results. + * May happen when demux is stalled in playback + * from memory with PULL mode. + */ + u8 session_id[MPQ_MAX_DMX_FILES]; + } sdmx_filters_state; + + unsigned int decoder_alloc_flags; + + /* HW plugin specific */ + void *plugin_priv; + int (*mpq_dmx_plugin_release)(struct mpq_demux *mpq_demux); + + /* debug-fs */ + u32 hw_notification_interval; + u32 hw_notification_min_interval; + u32 hw_notification_count; + u32 hw_notification_size; + u32 hw_notification_min_size; + + struct { + /* + * Accumulated number of bytes + * dropped due to decoder buffer fullness. + */ + u32 drop_count; + + /* Counter incremeneted for each video frame output by demux */ + u32 out_count; + + /* + * Sum of intervals (msec) holding the time + * between two successive video frames output. + */ + u32 out_interval_sum; + + /* + * Average interval (msec) between two + * successive video frames output. + */ + u32 out_interval_average; + + /* + * Max interval (msec) between two + * successive video frames output. + */ + u32 out_interval_max; + + /* Counter for number of decoder packets with TEI bit set */ + u32 ts_errors; + + /* + * Counter for number of decoder packets + * with continuity counter errors. + */ + u32 cc_errors; + + /* Time of last video frame output */ + ktime_t out_last_time; + } decoder_stat[MPQ_ADAPTER_MAX_NUM_OF_INTERFACES]; + + u32 sdmx_process_count; + u32 sdmx_process_time_sum; + u32 sdmx_process_time_average; + u32 sdmx_process_time_max; + u32 sdmx_process_packets_sum; + u32 sdmx_process_packets_average; + u32 sdmx_process_packets_min; + enum sdmx_log_level sdmx_log_level; + + ktime_t last_notification_time; + int ts_packet_timestamp_source; + /* Disable cache operations on qseecom heap since not supported */ + int disable_cache_ops; +}; + +/** + * mpq_dmx_init - initialization and registration function of + * single MPQ demux device + * + * @adapter: The adapter to register mpq_demux to + * @mpq_demux: The mpq demux to initialize + * + * Every HW plug-in needs to provide implementation of such + * function that will be called for each demux device on the + * module initialization. The function mpq_demux_plugin_init + * should be called during the HW plug-in module initialization. + */ +typedef int (*mpq_dmx_init)(struct dvb_adapter *mpq_adapter, + struct mpq_demux *demux); + +/** + * mpq_demux_plugin_init - Initialize demux devices and register + * them to the dvb adapter. + * + * @dmx_init_func: Pointer to the function to be used + * to initialize demux of the underlying HW plugin. + * + * Return error code + * + * Should be called at the HW plugin module initialization. + */ +int mpq_dmx_plugin_init(mpq_dmx_init dmx_init_func, + struct platform_device *pdev); + +/** + * mpq_demux_plugin_exit - terminate demux devices. + * + * Should be called at the HW plugin module termination. + */ +void mpq_dmx_plugin_exit(void); + +/** + * mpq_dmx_set_source - implmenetation of set_source routine. + * + * @demux: The demux device to set its source. + * @src: The source to be set. + * + * Return error code + * + * Can be used by the underlying plugins to implement kernel + * demux API set_source routine. + */ +int mpq_dmx_set_source(struct dmx_demux *demux, const dmx_source_t *src); + +/** + * mpq_dmx_map_buffer - map user-space buffer into kernel space. + * + * @demux: The demux device. + * @dmx_buffer: The demux buffer from user-space, assumes that + * buffer handle is ION file-handle. + * @priv_handle: Saves ION-handle of the buffer imported by this function. + * @kernel_mem: Saves kernel mapped address of the buffer. + * + * Return error code + * + * The function maps the buffer into kernel memory only if the buffer + * was not allocated with secure flag, otherwise the returned kernel + * memory address is set to NULL. + */ +int mpq_dmx_map_buffer(struct dmx_demux *demux, struct dmx_buffer *dmx_buffer, + struct ion_dma_buff_info *buff_dma_info, void **kernel_mem); + +/** + * mpq_dmx_unmap_buffer - unmap user-space buffer from kernel space memory. + * + * @demux: The demux device. + * @priv_handle: ION-handle of the buffer returned from mpq_dmx_map_buffer. + * + * Return error code + * + * The function unmaps the buffer from kernel memory only if the buffer + * was not allocated with secure flag. + */ +int mpq_dmx_unmap_buffer(struct dmx_demux *demux, + struct ion_dma_buff_info *buff_dma_info); + +/** + * mpq_dmx_decoder_fullness_init - Initialize waiting + * mechanism on decoder's buffer fullness. + * + * @feed: The decoder's feed + * + * Return error code. + */ +int mpq_dmx_decoder_fullness_init(struct dvb_demux_feed *feed); + +/** + * mpq_dmx_decoder_fullness_wait - Checks whether decoder buffer + * have free space as required, if not, wait for it. + * + * @feed: The decoder's feed + * @required_space: the required free space to wait for + * + * Return error code. + */ +int mpq_dmx_decoder_fullness_wait(struct dvb_demux_feed *feed, + size_t required_space); + +/** + * mpq_dmx_decoder_fullness_abort - Aborts waiting + * on decoder's buffer fullness if any waiting is done + * now. After calling this, to wait again the user must + * call mpq_dmx_decoder_fullness_init. + * + * @feed: The decoder's feed + * + * Return error code. + */ +int mpq_dmx_decoder_fullness_abort(struct dvb_demux_feed *feed); + +/** + * mpq_dmx_decoder_buffer_status - Returns the + * status of the decoder's buffer. + * + * @feed: The decoder's feed + * @dmx_buffer_status: Status of decoder's buffer + * + * Return error code. + */ +int mpq_dmx_decoder_buffer_status(struct dvb_demux_feed *feed, + struct dmx_buffer_status *dmx_buffer_status); + +/** + * mpq_dmx_reuse_decoder_buffer - release buffer passed to decoder for reuse + * by the stream-buffer. + * + * @feed: The decoder's feed. + * @cookie: stream-buffer handle of the buffer. + * + * Return error code + * + * The function releases the buffer provided by the stream-buffer + * connected to the decoder back to the stream-buffer for reuse. + */ +int mpq_dmx_reuse_decoder_buffer(struct dvb_demux_feed *feed, int cookie); + +/** + * mpq_dmx_process_video_packet - Assemble PES data and output it + * to the stream-buffer connected to the decoder. + * + * @feed: The feed used for the video TS packets + * @buf: The buffer holding video TS packet. + * + * Return error code. + * + * The function assumes it receives buffer with single TS packet + * of the relevant PID. + * If the output buffer is full while assembly, the function drops + * the packet and does not write them to the output buffer. + * Scrambled packets are bypassed. + */ +int mpq_dmx_process_video_packet(struct dvb_demux_feed *feed, const u8 *buf); + +/** + * mpq_dmx_process_pcr_packet - Extract PCR/STC pairs from + * a 192 bytes packet. + * + * @feed: The feed used for the PCR TS packets + * @buf: The buffer holding pcr/stc packet. + * + * Return error code. + * + * The function assumes it receives buffer with single TS packet + * of the relevant PID, and that it has 4 bytes + * suffix as extra timestamp in the following format: + * + * Byte3: TSIF flags + * Byte0-2: TTS, 0..2^24-1 at 105.47 Khz (27*10^6/256). + * + * The function callbacks dmxdev after extraction of the pcr/stc + * pair. + */ +int mpq_dmx_process_pcr_packet(struct dvb_demux_feed *feed, const u8 *buf); + +/** + * mpq_dmx_extract_pcr_and_dci() - Extract the PCR field and discontinuity + * indicator from a TS packet buffer. + * + * @buf: TS packet buffer + * @pcr: returned PCR value + * @dci: returned discontinuity indicator + * + * Returns 1 if PCR was extracted, 0 otherwise. + */ +int mpq_dmx_extract_pcr_and_dci(const u8 *buf, u64 *pcr, int *dci); + +/** + * mpq_dmx_init_debugfs_entries - + * Extend dvb-demux debugfs with mpq related entries (HW statistics and secure + * demux log level). + * + * @mpq_demux: The mpq_demux device to initialize. + */ +void mpq_dmx_init_debugfs_entries(struct mpq_demux *mpq_demux); + +/** + * mpq_dmx_update_hw_statistics - + * Update dvb-demux debugfs with HW notification statistics. + * + * @mpq_demux: The mpq_demux device to update. + */ +void mpq_dmx_update_hw_statistics(struct mpq_demux *mpq_demux); + +/** + * mpq_dmx_set_cipher_ops - Handles setting of cipher operations + * + * @feed: The feed to set its cipher operations + * @cipher_ops: Cipher operations to be set + * + * This common function handles only the case when working with + * secure-demux. When working with secure demux a single decrypt cipher + * operation is allowed. + * + * Return error code + */ +int mpq_dmx_set_cipher_ops(struct dvb_demux_feed *feed, + struct dmx_cipher_operations *cipher_ops); + +/** + * mpq_dmx_convert_tts - Convert timestamp attached by HW to each TS + * packet to 27MHz. + * + * @feed: The feed with TTS attached + * @timestamp: Buffer holding the timestamp attached by the HW + * @timestampIn27Mhz: Timestamp result in 27MHz + * + * Return error code + */ +void mpq_dmx_convert_tts(struct dvb_demux_feed *feed, + const u8 timestamp[TIMESTAMP_LEN], + u64 *timestampIn27Mhz); + +/** + * mpq_sdmx_open_session - Handle the details of opening a new secure demux + * session for the specified mpq demux instance. Multiple calls to this + * is allowed, reference counting is managed to open it only when needed. + * + * @mpq_demux: mpq demux instance + * + * Return error code + */ +int mpq_sdmx_open_session(struct mpq_demux *mpq_demux); + +/** + * mpq_sdmx_close_session - Closes secure demux session. The session + * is closed only if reference counter of the session reaches 0. + * + * @mpq_demux: mpq demux instance + * + * Return error code + */ +int mpq_sdmx_close_session(struct mpq_demux *mpq_demux); + +/** + * mpq_dmx_init_mpq_feed - Initialize an mpq feed object + * The function allocates mpq_feed object and saves in the dvb_demux_feed + * priv field. + * + * @feed: A dvb demux level feed parent object + * + * Return error code + */ +int mpq_dmx_init_mpq_feed(struct dvb_demux_feed *feed); + +/** + * mpq_dmx_terminate_feed - Destroy an mpq feed object + * + * @feed: A dvb demux level feed parent object + * + * Return error code + */ +int mpq_dmx_terminate_feed(struct dvb_demux_feed *feed); + +/** + * mpq_dmx_init_video_feed() - Initializes video related data structures + * + * @mpq_feed: mpq_feed object to initialize + * + * Return error code + */ +int mpq_dmx_init_video_feed(struct mpq_feed *mpq_feed); + +/** + * mpq_dmx_terminate_video_feed() - Release video related feed resources + * + * @mpq_feed: mpq_feed object to terminate + * + * Return error code + */ +int mpq_dmx_terminate_video_feed(struct mpq_feed *mpq_feed); + +/** + * mpq_dmx_write - demux write() function implementation. + * + * A wrapper function used for writing new data into the demux via DVR. + * It checks where new data should actually go, the secure demux or the normal + * dvb demux software demux. + * + * @demux: demux interface + * @buf: input buffer + * @count: number of data bytes in input buffer + * + * Return number of bytes processed or error code + */ +int mpq_dmx_write(struct dmx_demux *demux, const char *buf, size_t count); + +/** + * mpq_sdmx_process - Perform demuxing process on the specified input buffer + * in the secure demux instance + * + * @mpq_demux: mpq demux instance + * @input: input buffer descriptor + * @fill_count: number of data bytes in input buffer that can be read + * @read_offset: offset in buffer for reading + * @tsp_size: size of single TS packet + * + * Return number of bytes read or error code + */ +int mpq_sdmx_process(struct mpq_demux *mpq_demux, + struct sdmx_buff_descr *input, + u32 fill_count, + u32 read_offset, + size_t tsp_size); + +/** + * mpq_sdmx_loaded - Returns 1 if secure demux application is loaded, + * 0 otherwise. This function should be used to determine whether or not + * processing should take place in the SDMX. + */ +int mpq_sdmx_is_loaded(void); + +/** + * mpq_dmx_oob_command - Handles OOB command from dvb-demux. + * + * OOB marker commands trigger callback to the dmxdev. + * Handling of EOS command may trigger current (last on stream) PES/Frame to + * be reported, in addition to callback to the dmxdev. + * In case secure demux is active for the feed, EOS command is passed to the + * secure demux for handling. + * + * @feed: dvb demux feed object + * @cmd: oob command data + * + * returns 0 on success or error + */ +int mpq_dmx_oob_command(struct dvb_demux_feed *feed, + struct dmx_oob_command *cmd); + +/** + * mpq_dmx_peer_rec_feed() - For a recording filter with multiple feeds objects + * search for a feed object that shares the same filter as the specified feed + * object, and return it. + * This can be used to test whether the specified feed object is the first feed + * allocate for the recording filter - return value is NULL. + * + * @feed: dvb demux feed object + * + * Return the dvb_demux_feed sharing the same filter's buffer or NULL if no + * such is found. + */ +struct dvb_demux_feed *mpq_dmx_peer_rec_feed(struct dvb_demux_feed *feed); + +/** + * mpq_dmx_decoder_eos_cmd() - Report EOS event to the mpq_streambuffer + * + * @mpq_feed: Video mpq_feed object for notification + * @feed_type: Feed type( Video ) + * + * Return error code + */ +int mpq_dmx_decoder_eos_cmd(struct mpq_feed *mpq_feed); + +/** + * mpq_dmx_parse_mandatory_pes_header() - Parse non-optional PES header fields + * from TS packet buffer and save results in the feed object. + * + * @feed: Video dvb demux feed object + * @feed_data: Structure where results will be saved + * @pes_header: Saved PES header + * @buf: Input buffer containing TS packet with the PES header + * @ts_payload_offset: Offset in 'buf' where payload begins + * @bytes_avail: Length of actual payload + * + * Return error code + */ +int mpq_dmx_parse_mandatory_pes_header( + struct dvb_demux_feed *feed, + struct mpq_video_feed_info *feed_data, + struct pes_packet_header *pes_header, + const u8 *buf, + u32 *ts_payload_offset, + int *bytes_avail); + +/** + * mpq_dmx_parse_remaining_pes_header() - Parse optional PES header fields + * from TS packet buffer and save results in the feed object. + * This function depends on mpq_dmx_parse_mandatory_pes_header being called + * first for state to be valid. + * + * @feed: Video dvb demux feed object + * @feed_data: Structure where results will be saved + * @pes_header: Saved PES header + * @buf: Input buffer containing TS packet with the PES header + * @ts_payload_offset: Offset in 'buf' where payload begins + * @bytes_avail: Length of actual payload + * + * Return error code + */ +int mpq_dmx_parse_remaining_pes_header( + struct dvb_demux_feed *feed, + struct mpq_video_feed_info *feed_data, + struct pes_packet_header *pes_header, + const u8 *buf, + u32 *ts_payload_offset, + int *bytes_avail); + +/** + * mpq_dmx_flush_stream_buffer() - Flush video stream buffer object of the + * specific video feed, both meta-data packets and data. + * + * @feed: dvb demux video feed object + * + * Return error code + */ +int mpq_dmx_flush_stream_buffer(struct dvb_demux_feed *feed); + +/** + * mpq_dmx_save_pts_dts() - Save the current PTS/DTS data + * + * @feed_data: Video feed structure where PTS/DTS is saved + */ +static inline void mpq_dmx_save_pts_dts(struct mpq_video_feed_info *feed_data) +{ + if (feed_data->new_info_exists) { + feed_data->saved_pts_dts_info.pts_exist = + feed_data->new_pts_dts_info.pts_exist; + feed_data->saved_pts_dts_info.pts = + feed_data->new_pts_dts_info.pts; + feed_data->saved_pts_dts_info.dts_exist = + feed_data->new_pts_dts_info.dts_exist; + feed_data->saved_pts_dts_info.dts = + feed_data->new_pts_dts_info.dts; + + feed_data->new_info_exists = 0; + feed_data->saved_info_used = 0; + } +} + +/** + * mpq_dmx_write_pts_dts() - Write out the saved PTS/DTS data and mark as used + * + * @feed_data: Video feed structure where PTS/DTS was saved + * @info: PTS/DTS structure to write to + */ +static inline void mpq_dmx_write_pts_dts(struct mpq_video_feed_info *feed_data, + struct dmx_pts_dts_info *info) +{ + if (!feed_data->saved_info_used) { + info->pts_exist = feed_data->saved_pts_dts_info.pts_exist; + info->pts = feed_data->saved_pts_dts_info.pts; + info->dts_exist = feed_data->saved_pts_dts_info.dts_exist; + info->dts = feed_data->saved_pts_dts_info.dts; + + feed_data->saved_info_used = 1; + } else { + info->pts_exist = 0; + info->dts_exist = 0; + } +} + +/* + * mpq_dmx_calc_time_delta - + * Calculate delta in msec between two time snapshots. + * + * @curr_time: value of current time + * @prev_time: value of previous time + * + * Return time-delta in msec + */ +static inline u32 mpq_dmx_calc_time_delta(ktime_t curr_time, ktime_t prev_time) +{ + s64 delta_time_ms = ktime_ms_delta(curr_time, prev_time); + + return (u32)delta_time_ms; +} + +void mpq_dmx_update_decoder_stat(struct mpq_feed *mpq_feed); + +/* Return the common module parameter tsif_mode */ +int mpq_dmx_get_param_tsif_mode(void); + +/* Return the common module parameter clock_inv */ +int mpq_dmx_get_param_clock_inv(void); + +/* Return the common module parameter mpq_sdmx_scramble_odd */ +int mpq_dmx_get_param_scramble_odd(void); + +/* Return the common module parameter mpq_sdmx_scramble_even */ +int mpq_dmx_get_param_scramble_even(void); + +/* Return the common module parameter mpq_sdmx_scramble_default_discard */ +int mpq_dmx_get_param_scramble_default_discard(void); + +#endif /* _MPQ_DMX_PLUGIN_COMMON_H */ diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_sw.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_sw.c new file mode 100644 index 000000000000..a82804aaa2c4 --- /dev/null +++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_sw.c @@ -0,0 +1,318 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include "mpq_dvb_debug.h" +#include "mpq_dmx_plugin_common.h" + + +static int mpq_sw_dmx_start_filtering(struct dvb_demux_feed *feed) +{ + int ret = -EINVAL; + struct mpq_demux *mpq_demux = feed->demux->priv; + + MPQ_DVB_DBG_PRINT("%s(pid=%d) executed\n", __func__, feed->pid); + + if (mpq_demux == NULL) { + MPQ_DVB_ERR_PRINT("%s: invalid mpq_demux handle\n", __func__); + goto out; + } + + if (mpq_demux->source < DMX_SOURCE_DVR0) { + MPQ_DVB_ERR_PRINT("%s: only DVR source is supported (%d)\n", + __func__, mpq_demux->source); + goto out; + } + + /* + * Always feed sections/PES starting from a new one and + * do not partial transfer data from older one + */ + feed->pusi_seen = 0; + + ret = mpq_dmx_init_mpq_feed(feed); + if (ret) + MPQ_DVB_ERR_PRINT("%s: mpq_dmx_init_mpq_feed failed(%d)\n", + __func__, ret); +out: + return ret; +} + +static int mpq_sw_dmx_stop_filtering(struct dvb_demux_feed *feed) +{ + int ret; + + MPQ_DVB_DBG_PRINT("%s: (pid=%d) executed\n", __func__, feed->pid); + + ret = mpq_dmx_terminate_feed(feed); + if (ret) + MPQ_DVB_ERR_PRINT("%s: mpq_dmx_terminate_feed failed(%d)\n", + __func__, ret); + + return ret; +} + +static int mpq_sw_dmx_write_to_decoder(struct dvb_demux_feed *feed, + const u8 *buf, size_t len) +{ + /* + * It is assumed that this function is called once for each + * TS packet of the relevant feed. + */ + if (len > (TIMESTAMP_LEN + TS_PACKET_SIZE)) + MPQ_DVB_DBG_PRINT( + "%s: warnning - len larger than one packet\n", + __func__); + + if (dvb_dmx_is_video_feed(feed)) + return mpq_dmx_process_video_packet(feed, buf); + + if (dvb_dmx_is_pcr_feed(feed)) + return mpq_dmx_process_pcr_packet(feed, buf); + + return 0; +} + +static int mpq_sw_dmx_set_source(struct dmx_demux *demux, + const dmx_source_t *src) +{ + int ret = -EINVAL; + + if (demux == NULL || demux->priv == NULL || src == NULL) { + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + goto out; + } + + if (*src >= DMX_SOURCE_DVR0 && *src <= DMX_SOURCE_DVR3) { + ret = mpq_dmx_set_source(demux, src); + if (ret) + MPQ_DVB_ERR_PRINT( + "%s: mpq_dmx_set_source(%d) failed, ret=%d\n", + __func__, *src, ret); + } else { + MPQ_DVB_ERR_PRINT("%s: not a DVR source\n", __func__); + } + +out: + return ret; +} + +static int mpq_sw_dmx_get_caps(struct dmx_demux *demux, struct dmx_caps *caps) +{ + struct dvb_demux *dvb_demux = demux->priv; + + if (dvb_demux == NULL || caps == NULL) { + MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + caps->caps = DMX_CAP_PULL_MODE | DMX_CAP_VIDEO_DECODER_DATA | + DMX_CAP_TS_INSERTION | DMX_CAP_VIDEO_INDEXING | + DMX_CAP_AUTO_BUFFER_FLUSH; + caps->recording_max_video_pids_indexed = 0; + caps->num_decoders = MPQ_ADAPTER_MAX_NUM_OF_INTERFACES; + caps->num_demux_devices = CONFIG_DVB_MPQ_NUM_DMX_DEVICES; + caps->num_pid_filters = MPQ_MAX_DMX_FILES; + caps->num_section_filters = dvb_demux->filternum; + caps->num_section_filters_per_pid = dvb_demux->filternum; + caps->section_filter_length = DMX_FILTER_SIZE; + caps->num_demod_inputs = 0; + caps->num_memory_inputs = CONFIG_DVB_MPQ_NUM_DMX_DEVICES; + caps->max_bitrate = 192; + caps->demod_input_max_bitrate = 96; + caps->memory_input_max_bitrate = 96; + caps->num_cipher_ops = 1; + + /* No STC support */ + caps->max_stc = 0; + + /* Buffer requirements */ + caps->section.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->section.max_buffer_num = 1; + caps->section.max_size = 0xFFFFFFFF; + caps->section.size_alignment = 0; + caps->pes.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->pes.max_buffer_num = 1; + caps->pes.max_size = 0xFFFFFFFF; + caps->pes.size_alignment = 0; + caps->recording_188_tsp.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->recording_188_tsp.max_buffer_num = 1; + caps->recording_188_tsp.max_size = 0xFFFFFFFF; + caps->recording_188_tsp.size_alignment = 0; + caps->recording_192_tsp.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->recording_192_tsp.max_buffer_num = 1; + caps->recording_192_tsp.max_size = 0xFFFFFFFF; + caps->recording_192_tsp.size_alignment = 0; + caps->playback_188_tsp.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->playback_188_tsp.max_buffer_num = 1; + caps->playback_188_tsp.max_size = 0xFFFFFFFF; + caps->playback_188_tsp.size_alignment = 188; + caps->playback_192_tsp.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->playback_192_tsp.max_buffer_num = 1; + caps->playback_192_tsp.max_size = 0xFFFFFFFF; + caps->playback_192_tsp.size_alignment = 192; + caps->decoder.flags = + DMX_BUFFER_SECURED_IF_DECRYPTED | + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_LINEAR_GROUP_SUPPORT | + DMX_BUFFER_CACHED; + caps->decoder.max_buffer_num = DMX_MAX_DECODER_BUFFER_NUM; + caps->decoder.max_size = 0xFFFFFFFF; + caps->decoder.size_alignment = SZ_4K; + + return 0; +} + +static int mpq_sw_dmx_init(struct dvb_adapter *mpq_adapter, + struct mpq_demux *mpq_demux) +{ + int ret; + struct dvb_demux *dvb_demux = &mpq_demux->demux; + + /* Set the kernel-demux object capabilities */ + mpq_demux->demux.dmx.capabilities = + DMX_TS_FILTERING | + DMX_PES_FILTERING | + DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING | + DMX_CRC_CHECKING | + DMX_TS_DESCRAMBLING; + + /* Set dvb-demux "virtual" function pointers */ + dvb_demux->priv = (void *)mpq_demux; + dvb_demux->filternum = MPQ_MAX_DMX_FILES; + dvb_demux->feednum = MPQ_MAX_DMX_FILES; + dvb_demux->start_feed = mpq_sw_dmx_start_filtering; + dvb_demux->stop_feed = mpq_sw_dmx_stop_filtering; + dvb_demux->write_to_decoder = mpq_sw_dmx_write_to_decoder; + dvb_demux->decoder_fullness_init = mpq_dmx_decoder_fullness_init; + dvb_demux->decoder_fullness_wait = mpq_dmx_decoder_fullness_wait; + dvb_demux->decoder_fullness_abort = mpq_dmx_decoder_fullness_abort; + dvb_demux->decoder_buffer_status = mpq_dmx_decoder_buffer_status; + dvb_demux->reuse_decoder_buffer = mpq_dmx_reuse_decoder_buffer; + dvb_demux->set_cipher_op = mpq_dmx_set_cipher_ops; + dvb_demux->oob_command = mpq_dmx_oob_command; + dvb_demux->convert_ts = mpq_dmx_convert_tts; + dvb_demux->flush_decoder_buffer = NULL; + + /* Initialize dvb_demux object */ + ret = dvb_dmx_init(dvb_demux); + if (ret) { + MPQ_DVB_ERR_PRINT("%s: dvb_dmx_init failed, ret=%d\n", + __func__, ret); + goto init_failed; + } + + /* Now initialize the dmx-dev object */ + mpq_demux->dmxdev.filternum = MPQ_MAX_DMX_FILES; + mpq_demux->dmxdev.demux = &mpq_demux->demux.dmx; + mpq_demux->dmxdev.capabilities = DMXDEV_CAP_DUPLEX; + + mpq_demux->dmxdev.demux->set_source = mpq_sw_dmx_set_source; + mpq_demux->dmxdev.demux->get_stc = NULL; + mpq_demux->dmxdev.demux->get_caps = mpq_sw_dmx_get_caps; + mpq_demux->dmxdev.demux->map_buffer = mpq_dmx_map_buffer; + mpq_demux->dmxdev.demux->unmap_buffer = mpq_dmx_unmap_buffer; + mpq_demux->dmxdev.demux->write = mpq_dmx_write; + ret = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter); + if (ret) { + MPQ_DVB_ERR_PRINT("%s: dvb_dmxdev_init failed, ret=%d\n", + __func__, ret); + goto init_failed_dmx_release; + } + + /* Extend dvb-demux debugfs with mpq demux statistics. */ + mpq_dmx_init_debugfs_entries(mpq_demux); + + return 0; + +init_failed_dmx_release: + dvb_dmx_release(dvb_demux); +init_failed: + return ret; +} + + +static int mpq_dmx_sw_plugin_probe(struct platform_device *pdev) +{ + return mpq_dmx_plugin_init(mpq_sw_dmx_init, pdev); +} + +static int mpq_dmx_sw_plugin_remove(struct platform_device *pdev) +{ + mpq_dmx_plugin_exit(); + return 0; +} + + +/*** power management ***/ +static const struct of_device_id msm_match_table[] = { + {.compatible = "qcom,demux"}, + {} +}; + +static struct platform_driver mpq_dmx_sw_plugin_driver = { + .probe = mpq_dmx_sw_plugin_probe, + .remove = mpq_dmx_sw_plugin_remove, + .driver = { + .name = "demux", + .of_match_table = msm_match_table, + }, +}; + + +static int __init mpq_dmx_sw_plugin_init(void) +{ + int rc; + + /* register the driver, and check hardware */ + rc = platform_driver_register(&mpq_dmx_sw_plugin_driver); + if (rc) + MPQ_DVB_ERR_PRINT( + "%s: mpq_dmx_sw_plugin: platform_driver_register failed: %d\n" + __func__, rc); + + return rc; +} + +static void __exit mpq_dmx_sw_plugin_exit(void) +{ + /* delete low level driver */ + platform_driver_unregister(&mpq_dmx_sw_plugin_driver); +} + + +module_init(mpq_dmx_sw_plugin_init); +module_exit(mpq_dmx_sw_plugin_exit); + +MODULE_DESCRIPTION("Qualcomm Technologies Inc. demux software plugin"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c new file mode 100644 index 000000000000..ea1d1eb27735 --- /dev/null +++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c @@ -0,0 +1,1994 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "mpq_dvb_debug.h" +#include "mpq_dmx_plugin_common.h" + +#define TSIF_COUNT 2 + +/* Max number of PID filters */ +#define TSPP_MAX_PID_FILTER_NUM 128 + +/* Max number of user-defined HW PID filters */ +#define TSPP_MAX_HW_PID_FILTER_NUM 15 + +/* HW index of the last entry in the TSPP HW filter table */ +#define TSPP_LAST_HW_FILTER_INDEX 15 + +/* Number of filters required to accept all packets except NULL packets */ +#define TSPP_BLOCK_NULLS_FILTERS_NUM 13 + +/* Max number of section filters */ +#define TSPP_MAX_SECTION_FILTER_NUM 128 + +/* For each TSIF we use a single pipe holding the data after PID filtering */ +#define TSPP_CHANNEL 0 + +/* the channel_id set to TSPP driver based on TSIF number and channel type */ +#define TSPP_CHANNEL_ID(tsif, ch) ((tsif << 1) + ch) +#define TSPP_GET_TSIF_NUM(ch_id) (ch_id >> 1) + +/* mask that set to care for all bits in pid filter */ +#define TSPP_PID_MASK 0x1FFF + +/* dvb-demux defines pid 0x2000 as full capture pid */ +#define TSPP_PASS_THROUGH_PID 0x2000 + +/* NULL packets pid */ +#define TSPP_NULL_PACKETS_PID 0x1FFF + +#define TSPP_RAW_TTS_SIZE 192 +#define TSPP_RAW_SIZE 188 + +#define MAX_BAM_DESCRIPTOR_SIZE (32 * 1024 - 1) + +#define MAX_BAM_DESCRIPTOR_COUNT (8 * 1024 - 2) + +#define TSPP_BUFFER_SIZE (500 * 1024) /* 500KB */ + +#define TSPP_DEFAULT_DESCRIPTOR_SIZE (TSPP_RAW_TTS_SIZE) + +#define TSPP_BUFFER_COUNT(buffer_size) \ + ((buffer_size) / tspp_desc_size) + +/* When TSPP notifies demux that new packets are received. + * Using max descriptor size (170 packets). + * Assuming 20MBit/sec stream, with 170 packets + * per descriptor there would be about 82 descriptors, + * Meaning about 82 notifications per second. + */ +#define TSPP_NOTIFICATION_SIZE(desc_size) \ + (MAX_BAM_DESCRIPTOR_SIZE / (desc_size)) + +/* Channel timeout in msec */ +#define TSPP_CHANNEL_TIMEOUT 100 + +enum mem_buffer_allocation_mode { + MPQ_DMX_TSPP_INTERNAL_ALLOC = 0, + MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC = 1 +}; + +/* module parameters for load time configuration */ +static int allocation_mode = MPQ_DMX_TSPP_INTERNAL_ALLOC; +static int tspp_out_buffer_size = TSPP_BUFFER_SIZE; +static int tspp_desc_size = TSPP_DEFAULT_DESCRIPTOR_SIZE; +static int tspp_notification_size = + TSPP_NOTIFICATION_SIZE(TSPP_DEFAULT_DESCRIPTOR_SIZE); +static int tspp_channel_timeout = TSPP_CHANNEL_TIMEOUT; +static int tspp_out_ion_heap = ION_QSECOM_HEAP_ID; + +module_param(allocation_mode, int, 0644); +module_param(tspp_out_buffer_size, int, 0644); +module_param(tspp_desc_size, int, 0644); +module_param(tspp_notification_size, int, 0644); +module_param(tspp_channel_timeout, int, 0644); +module_param(tspp_out_ion_heap, int, 0644); + +/* The following structure hold singleton information + * required for dmx implementation on top of TSPP. + */ +static struct +{ + /* Information for each TSIF input processing */ + struct { + /* + * TSPP pipe holding all TS packets after PID filtering. + * The following is reference count for number of feeds + * allocated on that pipe. + */ + int channel_ref; + + /* Counter for data notifications on the pipe */ + atomic_t data_cnt; + + /* flag to indicate control operation is in progress */ + atomic_t control_op; + + /* ION handle used for TSPP data buffer allocation */ + struct ion_handle *ch_mem_heap_handle; + + /* TSPP data buffer heap virtual base address */ + void *ch_mem_heap_virt_base; + + /* TSPP data buffer heap physical base address */ + phys_addr_t ch_mem_heap_phys_base; + + /* Buffer allocation index */ + int buff_index; + + /* Number of buffers */ + u32 buffer_count; + + /* + * Array holding the IDs of the TSPP buffer descriptors in the + * current aggregate, in order to release these descriptors at + * the end of processing. + */ + int *aggregate_ids; + + /* + * Holds PIDs of allocated filters along with + * how many feeds are opened on the same PID. For + * TSPP HW filters, holds also the filter table index. + * When pid == -1, the entry is free. + */ + struct { + int pid; + int ref_count; + int hw_index; + } filters[TSPP_MAX_PID_FILTER_NUM]; + + /* Indicates available/allocated filter table indexes */ + int hw_indexes[TSPP_MAX_HW_PID_FILTER_NUM]; + + /* Number of currently allocated PID filters */ + u16 current_filter_count; + + /* + * Flag to indicate whether the user added a filter to accept + * NULL packets (PID = 0x1FFF) + */ + int pass_nulls_flag; + + /* + * Flag to indicate whether the user added a filter to accept + * all packets (PID = 0x2000) + */ + int pass_all_flag; + + /* + * Flag to indicate whether the filter that accepts + * all packets has already been added and is + * currently enabled + */ + int accept_all_filter_exists_flag; + + /* Thread processing TS packets from TSPP */ + struct task_struct *thread; + wait_queue_head_t wait_queue; + + /* TSIF alias */ + char name[TSIF_NAME_LENGTH]; + + /* Pointer to the demux connected to this TSIF */ + struct mpq_demux *mpq_demux; + + /* Mutex protecting the data-structure */ + struct mutex mutex; + + /* ion dma buffer mapping structure */ + struct tspp_ion_dma_buf_info ch_ion_dma_buf; + + } tsif[TSIF_COUNT]; + + /* ION client used for TSPP data buffer allocation */ + struct ion_client *ion_client; +} mpq_dmx_tspp_info; + +static void *tspp_mem_allocator(int channel_id, u32 size, + phys_addr_t *phys_base, dma_addr_t *dma_base, + void *user) +{ + void *virt_addr = NULL; + int i = TSPP_GET_TSIF_NUM(channel_id); + + if (mpq_dmx_tspp_info.tsif[i].buff_index == + mpq_dmx_tspp_info.tsif[i].buffer_count) + return NULL; + + virt_addr = + (mpq_dmx_tspp_info.tsif[i].ch_mem_heap_virt_base + + (mpq_dmx_tspp_info.tsif[i].buff_index * size)); + + *phys_base = + (mpq_dmx_tspp_info.tsif[i].ch_mem_heap_phys_base + + (mpq_dmx_tspp_info.tsif[i].buff_index * size)); + + mpq_dmx_tspp_info.tsif[i].buff_index++; + + return virt_addr; +} + +static void tspp_mem_free(int channel_id, u32 size, + void *virt_base, phys_addr_t phys_base, void *user) +{ + int i = TSPP_GET_TSIF_NUM(channel_id); + + /* + * actual buffer heap free is done in mpq_dmx_tspp_plugin_exit(). + * we update index here, so if this function is called repetitively + * for all the buffers, then afterwards tspp_mem_allocator() + * can be called again. + * Note: it would be incorrect to call tspp_mem_allocator() + * a few times, then call tspp_mem_free(), then call + * tspp_mem_allocator() again. + */ + if (mpq_dmx_tspp_info.tsif[i].buff_index > 0) + mpq_dmx_tspp_info.tsif[i].buff_index--; +} + +/** + * Returns a free HW filter index that can be used. + * + * @tsif: The TSIF to allocate filter from + * + * Return HW filter index or -ENOMEM if no filters available + */ +static int mpq_tspp_allocate_hw_filter_index(int tsif) +{ + int i; + + for (i = 0; i < TSPP_MAX_HW_PID_FILTER_NUM; i++) { + if (mpq_dmx_tspp_info.tsif[tsif].hw_indexes[i] == 0) { + mpq_dmx_tspp_info.tsif[tsif].hw_indexes[i] = 1; + return i; + } + } + + return -ENOMEM; +} + +/** + * Releases a HW filter index for future reuse. + * + * @tsif: The TSIF from which the filter should be released + * @hw_index: The HW index to release + * + */ +static inline void mpq_tspp_release_hw_filter_index(int tsif, int hw_index) +{ + if ((hw_index >= 0) && (hw_index < TSPP_MAX_HW_PID_FILTER_NUM)) + mpq_dmx_tspp_info.tsif[tsif].hw_indexes[hw_index] = 0; +} + + +/** + * Returns a free filter slot that can be used. + * + * @tsif: The TSIF to allocate filter from + * + * Return filter index or -ENOMEM if no filters available + */ +static int mpq_tspp_get_free_filter_slot(int tsif) +{ + int slot; + + for (slot = 0; slot < TSPP_MAX_PID_FILTER_NUM; slot++) + if (mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid == -1) + return slot; + + return -ENOMEM; +} + +/** + * Returns filter index of specific pid. + * + * @tsif: The TSIF to which the pid is allocated + * @pid: The pid to search for + * + * Return filter index or -1 if no filter available + */ +static int mpq_tspp_get_filter_slot(int tsif, int pid) +{ + int slot; + + for (slot = 0; slot < TSPP_MAX_PID_FILTER_NUM; slot++) + if (mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid == pid) + return slot; + + return -EINVAL; +} + +/** + * mpq_dmx_tspp_swfilter_desc - helper function + * + * Takes a tspp buffer descriptor and send it to the SW filter for demuxing, + * one TS packet at a time. + * + * @mpq_demux - mpq demux object + * @tspp_data_desc - tspp buffer descriptor + */ +static inline void mpq_dmx_tspp_swfilter_desc(struct mpq_demux *mpq_demux, + const struct tspp_data_descriptor *tspp_data_desc) +{ + u32 notif_size; + int i; + + notif_size = tspp_data_desc->size / TSPP_RAW_TTS_SIZE; + for (i = 0; i < notif_size; i++) + dvb_dmx_swfilter_packet(&mpq_demux->demux, + ((u8 *)tspp_data_desc->virt_base) + + i * TSPP_RAW_TTS_SIZE, + ((u8 *)tspp_data_desc->virt_base) + + i * TSPP_RAW_TTS_SIZE + TSPP_RAW_SIZE); +} + +/** + * Demux TS packets from TSPP by secure-demux. + * The function assumes the buffer is physically contiguous + * and that TSPP descriptors are continuous in memory. + * + * @tsif: The TSIF interface to process its packets + * @channel_id: the TSPP output pipe with the TS packets + */ +static void mpq_dmx_tspp_aggregated_process(int tsif, int channel_id) +{ + const struct tspp_data_descriptor *tspp_data_desc; + struct mpq_demux *mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux; + struct sdmx_buff_descr input; + size_t aggregate_len = 0; + size_t aggregate_count = 0; + phys_addr_t buff_start_addr_phys; + phys_addr_t buff_current_addr_phys = 0; + u32 notif_size; + int i; + + while ((tspp_data_desc = tspp_get_buffer(0, channel_id)) != NULL) { + if (aggregate_count == 0) + buff_current_addr_phys = tspp_data_desc->phys_base; + notif_size = tspp_data_desc->size / TSPP_RAW_TTS_SIZE; + mpq_dmx_tspp_info.tsif[tsif].aggregate_ids[aggregate_count] = + tspp_data_desc->id; + aggregate_len += tspp_data_desc->size; + aggregate_count++; + mpq_demux->hw_notification_size += notif_size; + + /* Let SW filter process only if it might be relevant */ + if (mpq_demux->num_active_feeds > mpq_demux->num_secure_feeds) + mpq_dmx_tspp_swfilter_desc(mpq_demux, tspp_data_desc); + + } + + if (!aggregate_count) + return; + + buff_start_addr_phys = + mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_phys_base; + + input.base_addr = (u64)buff_start_addr_phys; + input.size = mpq_dmx_tspp_info.tsif[tsif].buffer_count * tspp_desc_size; + + if (mpq_sdmx_is_loaded() && mpq_demux->sdmx_filter_count) { + MPQ_DVB_DBG_PRINT( + "%s: SDMX Processing %zu descriptors: %zu bytes at start address 0x%llx, read offset %d\n", + __func__, aggregate_count, aggregate_len, + input.base_addr, + (int)(buff_current_addr_phys - buff_start_addr_phys)); + + mpq_sdmx_process(mpq_demux, &input, aggregate_len, + buff_current_addr_phys - buff_start_addr_phys, + TSPP_RAW_TTS_SIZE); + } + + for (i = 0; i < aggregate_count; i++) + tspp_release_buffer(0, channel_id, + mpq_dmx_tspp_info.tsif[tsif].aggregate_ids[i]); +} + + +/** + * Demux thread function handling data from specific TSIF. + * + * @arg: TSIF number + */ +static int mpq_dmx_tspp_thread(void *arg) +{ + int tsif = (int)(uintptr_t)arg; + struct mpq_demux *mpq_demux; + const struct tspp_data_descriptor *tspp_data_desc; + atomic_t *data_cnt; + u32 notif_size; + int channel_id; + int ref_count; + int ret; + + do { + ret = wait_event_interruptible( + mpq_dmx_tspp_info.tsif[tsif].wait_queue, + (atomic_read(&mpq_dmx_tspp_info.tsif[tsif].data_cnt) && + !atomic_read(&mpq_dmx_tspp_info.tsif[tsif].control_op)) + || kthread_should_stop()); + + if ((ret < 0) || kthread_should_stop()) { + MPQ_DVB_ERR_PRINT("%s: exit\n", __func__); + break; + } + + /* Lock against the TSPP filters data-structure */ + if (mutex_lock_interruptible( + &mpq_dmx_tspp_info.tsif[tsif].mutex)) + return -ERESTARTSYS; + + channel_id = TSPP_CHANNEL_ID(tsif, TSPP_CHANNEL); + + ref_count = mpq_dmx_tspp_info.tsif[tsif].channel_ref; + data_cnt = &mpq_dmx_tspp_info.tsif[tsif].data_cnt; + + /* Make sure channel is still active */ + if (ref_count == 0) { + mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex); + continue; + } + + atomic_dec(data_cnt); + + mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux; + mpq_demux->hw_notification_size = 0; + + if (allocation_mode != MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC && + mpq_sdmx_is_loaded()) + pr_err_once( + "%s: TSPP Allocation mode does not support secure demux.\n", + __func__); + + if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC && + mpq_sdmx_is_loaded()) { + mpq_dmx_tspp_aggregated_process(tsif, channel_id); + } else { + /* + * Go through all filled descriptors + * and perform demuxing on them + */ + do { + if (atomic_read( + &mpq_dmx_tspp_info.tsif[tsif].control_op)) { + /* restore for next iteration */ + atomic_inc(data_cnt); + break; + } + tspp_data_desc = tspp_get_buffer(0, channel_id); + if (!tspp_data_desc) + break; + + notif_size = tspp_data_desc->size / + TSPP_RAW_TTS_SIZE; + mpq_demux->hw_notification_size += notif_size; + + mpq_dmx_tspp_swfilter_desc(mpq_demux, + tspp_data_desc); + /* + * Notify TSPP that the buffer + * is no longer needed + */ + tspp_release_buffer(0, channel_id, + tspp_data_desc->id); + } while (1); + } + + if (mpq_demux->hw_notification_size && + (mpq_demux->hw_notification_size < + mpq_demux->hw_notification_min_size)) + mpq_demux->hw_notification_min_size = + mpq_demux->hw_notification_size; + + mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex); + } while (1); + + return 0; +} + +/** + * Callback function from TSPP when new data is ready. + * + * @channel_id: Channel with new TS packets + * @user: user-data holding TSIF number + */ +static void mpq_tspp_callback(int channel_id, void *user) +{ + int tsif = (int)(uintptr_t)user; + struct mpq_demux *mpq_demux; + + /* Save statistics on TSPP notifications */ + mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux; + mpq_dmx_update_hw_statistics(mpq_demux); + + atomic_inc(&mpq_dmx_tspp_info.tsif[tsif].data_cnt); + wake_up(&mpq_dmx_tspp_info.tsif[tsif].wait_queue); +} + +/** + * Free memory of channel output of specific TSIF. + * + * @tsif: The TSIF id to which memory should be freed. + */ +static void mpq_dmx_channel_mem_free(int tsif) +{ + int size = 0; + + size = (mpq_dmx_tspp_info.tsif[tsif].buffer_count * tspp_desc_size); + size = ALIGN(size, SZ_4K); + + + tspp_free_dma_buffer(0, size, + (void *)mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_virt_base, + (dma_addr_t)mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_phys_base); + + mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_phys_base = 0; + mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_virt_base = NULL; + mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_handle = NULL; +} + +/** + * Allocate memory for channel output of specific TSIF. + * + * @tsif: The TSIF id to which memory should be allocated. + * + * Return error status + */ +static int mpq_dmx_channel_mem_alloc(int tsif) +{ + int size = 0; + + size = (mpq_dmx_tspp_info.tsif[tsif].buffer_count * tspp_desc_size); + + size = ALIGN(size, SZ_4K); + + mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_virt_base + = tspp_allocate_dma_buffer(0, size, + &mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_phys_base); + + if (IS_ERR_OR_NULL( + mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_virt_base)) { + MPQ_DVB_ERR_PRINT("%s: ion_map_kernel() failed\n", __func__); + mpq_dmx_channel_mem_free(tsif); + return -ENOMEM; + } + return 0; +} + +/** + * Add a filter to accept all packets as the last entry + * of the TSPP HW filter table. + * + * @channel_id: Channel ID number. + * @source: TSPP source. + * + * Return error status + */ +static int mpq_tspp_add_accept_all_filter(int channel_id, + enum tspp_source source) +{ + struct tspp_filter tspp_filter; + int tsif = TSPP_GET_TSIF_NUM(channel_id); + int ret; + + MPQ_DVB_DBG_PRINT("%s: executed, channel id = %d, source = %d\n", + __func__, channel_id, source); + + if (mpq_dmx_tspp_info.tsif[tsif].accept_all_filter_exists_flag) { + MPQ_DVB_DBG_PRINT("%s: accept all filter already exists\n", + __func__); + return 0; + } + + /* This filter will be the last entry in the table */ + tspp_filter.priority = TSPP_LAST_HW_FILTER_INDEX; + /* Pass all pids - set mask to 0 */ + tspp_filter.pid = 0; + tspp_filter.mask = 0; + /* + * Include TTS in RAW packets, if you change this to + * TSPP_MODE_RAW_NO_SUFFIX you must also change TSPP_RAW_TTS_SIZE + * accordingly. + */ + tspp_filter.mode = TSPP_MODE_RAW; + tspp_filter.source = source; + tspp_filter.decrypt = 0; + + ret = tspp_add_filter(0, channel_id, &tspp_filter); + if (!ret) { + mpq_dmx_tspp_info.tsif[tsif].accept_all_filter_exists_flag = 1; + MPQ_DVB_DBG_PRINT( + "%s: accept all filter added successfully\n", + __func__); + } + + return ret; +} + +/** + * Remove the filter that accepts all packets from the last entry + * of the TSPP HW filter table. + * + * @channel_id: Channel ID number. + * @source: TSPP source. + * + * Return error status + */ +static int mpq_tspp_remove_accept_all_filter(int channel_id, + enum tspp_source source) +{ + struct tspp_filter tspp_filter; + int tsif = TSPP_GET_TSIF_NUM(channel_id); + int ret; + + MPQ_DVB_DBG_PRINT("%s: executed, channel id = %d, source = %d\n", + __func__, channel_id, source); + + if (mpq_dmx_tspp_info.tsif[tsif].accept_all_filter_exists_flag == 0) { + MPQ_DVB_DBG_PRINT("%s: accept all filter doesn't exist\n", + __func__); + return 0; + } + + tspp_filter.priority = TSPP_LAST_HW_FILTER_INDEX; + + ret = tspp_remove_filter(0, channel_id, &tspp_filter); + if (!ret) { + mpq_dmx_tspp_info.tsif[tsif].accept_all_filter_exists_flag = 0; + MPQ_DVB_DBG_PRINT( + "%s: accept all filter removed successfully\n", + __func__); + } + + return ret; +} + +/** + * Add filters designed to accept all packets except NULL packets, i.e. + * packets with PID = 0x1FFF. + * This function is called after user-defined filters were removed, + * so it assumes that the first 13 HW filters in the TSPP filter + * table are free for use. + * + * @channel_id: Channel ID number. + * @source: TSPP source. + * + * Return 0 on success, -1 otherwise + */ +static int mpq_tspp_add_null_blocking_filters(int channel_id, + enum tspp_source source) +{ + struct tspp_filter tspp_filter; + int ret = 0; + int i, j; + u16 full_pid_mask = 0x1FFF; + u8 mask_shift; + u8 pid_shift; + int tsif = TSPP_GET_TSIF_NUM(channel_id); + + MPQ_DVB_DBG_PRINT("%s: executed, channel id = %d, source = %d\n", + __func__, channel_id, source); + + /* + * Add a total of 13 filters that will accept packets with + * every PID other than 0x1FFF, which is the NULL PID. + * + * Filter 0: accept all PIDs with bit 12 clear, i.e. + * PID = 0x0000 .. 0x0FFF (4096 PIDs in total): + * Mask = 0x1000, PID = 0x0000. + * + * Filter 12: Accept PID 0x1FFE: + * Mask = 0x1FFF, PID = 0x1FFE. + * + * In general: For N = 0 .. 12, + * Filter : accept all PIDs with MSBits set and bit clear. + * Filter Mask = N+1 MSBits set, others clear. + * Filter PID = MSBits set, others clear. + */ + + /* + * Include TTS in RAW packets, if you change this to + * TSPP_MODE_RAW_NO_SUFFIX you must also change TSPP_RAW_TTS_SIZE + * accordingly. + */ + tspp_filter.mode = TSPP_MODE_RAW; + tspp_filter.source = source; + tspp_filter.decrypt = 0; + + for (i = 0; i < TSPP_BLOCK_NULLS_FILTERS_NUM; i++) { + tspp_filter.priority = mpq_tspp_allocate_hw_filter_index(tsif); + if (tspp_filter.priority != i) { + MPQ_DVB_ERR_PRINT( + "%s: got unexpected HW index %d, expected %d\n", + __func__, tspp_filter.priority, i); + ret = -1; + break; + } + mask_shift = (TSPP_BLOCK_NULLS_FILTERS_NUM - 1 - i); + pid_shift = (TSPP_BLOCK_NULLS_FILTERS_NUM - i); + tspp_filter.mask = + ((full_pid_mask >> mask_shift) << mask_shift); + tspp_filter.pid = ((full_pid_mask >> pid_shift) << pid_shift); + + if (tspp_add_filter(0, channel_id, &tspp_filter)) { + ret = -1; + break; + } + } + + if (ret) { + /* cleanup on failure */ + for (j = 0; j < i; j++) { + tspp_filter.priority = j; + mpq_tspp_release_hw_filter_index(tsif, j); + tspp_remove_filter(0, channel_id, &tspp_filter); + } + } else { + MPQ_DVB_DBG_PRINT( + "%s: NULL blocking filters added successfully\n", + __func__); + } + + return ret; +} + +/** + * Remove filters designed to accept all packets except NULL packets, i.e. + * packets with PID = 0x1FFF. + * + * @channel_id: Channel ID number. + * + * @source: TSPP source. + * + * Return 0 on success, -1 otherwise + */ +static int mpq_tspp_remove_null_blocking_filters(int channel_id, + enum tspp_source source) +{ + struct tspp_filter tspp_filter; + int tsif = TSPP_GET_TSIF_NUM(channel_id); + int ret = 0; + int i; + + MPQ_DVB_DBG_PRINT("%s: executed, channel id = %d, source = %d\n", + __func__, channel_id, source); + + for (i = 0; i < TSPP_BLOCK_NULLS_FILTERS_NUM; i++) { + tspp_filter.priority = i; + if (tspp_remove_filter(0, channel_id, &tspp_filter)) { + MPQ_DVB_ERR_PRINT("%s: failed to remove filter %d\n", + __func__, i); + ret = -1; + } + + mpq_tspp_release_hw_filter_index(tsif, i); + } + + return ret; +} + +/** + * Add all current user-defined filters (up to 15) as HW filters + * + * @channel_id: Channel ID number. + * + * @source: TSPP source. + * + * Return 0 on success, -1 otherwise + */ +static int mpq_tspp_add_all_user_filters(int channel_id, + enum tspp_source source) +{ + struct tspp_filter tspp_filter; + int tsif = TSPP_GET_TSIF_NUM(channel_id); + int slot; + u16 added_count = 0; + u16 total_filters_count = 0; + + MPQ_DVB_DBG_PRINT("%s: executed\n", __func__); + + /* + * Include TTS in RAW packets, if you change this to + * TSPP_MODE_RAW_NO_SUFFIX you must also change TSPP_RAW_TTS_SIZE + * accordingly. + */ + tspp_filter.mode = TSPP_MODE_RAW; + tspp_filter.source = source; + tspp_filter.decrypt = 0; + + for (slot = 0; slot < TSPP_MAX_PID_FILTER_NUM; slot++) { + if (mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid == -1) + continue; + + /* + * count total number of user filters to verify that it is + * exactly TSPP_MAX_HW_PID_FILTER_NUM as expected. + */ + total_filters_count++; + + if (added_count > TSPP_MAX_HW_PID_FILTER_NUM) + continue; + + tspp_filter.priority = mpq_tspp_allocate_hw_filter_index(tsif); + + if (mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid == + TSPP_PASS_THROUGH_PID) { + /* pass all pids */ + tspp_filter.pid = 0; + tspp_filter.mask = 0; + } else { + tspp_filter.pid = + mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid; + tspp_filter.mask = TSPP_PID_MASK; + } + + MPQ_DVB_DBG_PRINT( + "%s: adding HW filter, PID = %d, mask = 0x%X, index = %d\n", + __func__, tspp_filter.pid, tspp_filter.mask, + tspp_filter.priority); + + if (!tspp_add_filter(0, channel_id, &tspp_filter)) { + mpq_dmx_tspp_info.tsif[tsif].filters[slot].hw_index = + tspp_filter.priority; + added_count++; + } else { + MPQ_DVB_ERR_PRINT("%s: tspp_add_filter failed\n", + __func__); + } + } + + if ((added_count != TSPP_MAX_HW_PID_FILTER_NUM) || + (added_count != total_filters_count)) + return -EINVAL; + + return 0; +} + +/** + * Remove all user-defined HW filters + * + * @channel_id: Channel ID number. + * + * @source: TSPP source. + * + * Return 0 on success, -1 otherwise + */ +static int mpq_tspp_remove_all_user_filters(int channel_id, + enum tspp_source source) +{ + struct tspp_filter tspp_filter; + int ret = 0; + int tsif = TSPP_GET_TSIF_NUM(channel_id); + int i; + + MPQ_DVB_DBG_PRINT("%s: executed\n", __func__); + + for (i = 0; i < TSPP_MAX_HW_PID_FILTER_NUM; i++) { + tspp_filter.priority = i; + MPQ_DVB_DBG_PRINT("%s: Removing HW filter %d\n", + __func__, tspp_filter.priority); + if (tspp_remove_filter(0, channel_id, &tspp_filter)) + ret = -1; + + mpq_tspp_release_hw_filter_index(tsif, i); + mpq_dmx_tspp_info.tsif[tsif].filters[i].hw_index = -1; + } + + return ret; +} + +/** + * Configure TSPP channel to filter the PID of new feed. + * + * @feed: The feed to configure the channel with + * + * Return error status + * + * The function checks if the new PID can be added to an already + * allocated channel, if not, a new channel is allocated and configured. + */ +static int mpq_tspp_dmx_add_channel(struct dvb_demux_feed *feed) +{ + struct mpq_demux *mpq_demux = feed->demux->priv; + struct tspp_select_source tspp_source; + struct tspp_filter tspp_filter; + int tsif; + int tsif_mode = mpq_dmx_get_param_tsif_mode(); + int ret = 0; + int slot; + int channel_id; + int *channel_ref_count; + u32 buffer_size; + int restore_user_filters = 0; + int remove_accept_all_filter = 0; + int remove_null_blocking_filters = 0; + size_t agg_size; + + tspp_source.clk_inverse = mpq_dmx_get_param_clock_inv(); + tspp_source.data_inverse = 0; + tspp_source.sync_inverse = 0; + tspp_source.enable_inverse = 0; + + MPQ_DVB_DBG_PRINT("%s: executed, PID = %d\n", __func__, feed->pid); + + switch (tsif_mode) { + case 1: + tspp_source.mode = TSPP_TSIF_MODE_1; + break; + case 2: + tspp_source.mode = TSPP_TSIF_MODE_2; + break; + default: + tspp_source.mode = TSPP_TSIF_MODE_LOOPBACK; + break; + } + + /* determine the TSIF we are reading from */ + if (mpq_demux->source == DMX_SOURCE_FRONT0) { + tsif = 0; + tspp_source.source = TSPP_SOURCE_TSIF0; + } else if (mpq_demux->source == DMX_SOURCE_FRONT1) { + tsif = 1; + tspp_source.source = TSPP_SOURCE_TSIF1; + } else { + /* invalid source */ + MPQ_DVB_ERR_PRINT( + "%s: invalid input source (%d)\n", + __func__, + mpq_demux->source); + + return -EINVAL; + } + + atomic_inc(&mpq_dmx_tspp_info.tsif[tsif].control_op); + if (mutex_lock_interruptible(&mpq_dmx_tspp_info.tsif[tsif].mutex)) { + atomic_dec(&mpq_dmx_tspp_info.tsif[tsif].control_op); + return -ERESTARTSYS; + } + + /* + * It is possible that this PID was already requested before. + * Can happen if we play and record same PES or PCR + * piggypacked on video packet. + */ + slot = mpq_tspp_get_filter_slot(tsif, feed->pid); + if (slot >= 0) { + /* PID already configured */ + mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count++; + goto out; + } + + + channel_id = TSPP_CHANNEL_ID(tsif, TSPP_CHANNEL); + channel_ref_count = &mpq_dmx_tspp_info.tsif[tsif].channel_ref; + + /* + * Recalculate 'tspp_notification_size' and buffer count in case + * 'tspp_desc_size' or 'tspp_out_buffer_size' parameters have changed. + */ + buffer_size = tspp_desc_size; + tspp_notification_size = TSPP_NOTIFICATION_SIZE(tspp_desc_size); + mpq_dmx_tspp_info.tsif[tsif].buffer_count = + TSPP_BUFFER_COUNT(tspp_out_buffer_size); + if (mpq_dmx_tspp_info.tsif[tsif].buffer_count > + MAX_BAM_DESCRIPTOR_COUNT) + mpq_dmx_tspp_info.tsif[tsif].buffer_count = + MAX_BAM_DESCRIPTOR_COUNT; + + /* check if required TSPP pipe is already allocated or not */ + if (*channel_ref_count == 0) { + if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) { + agg_size = mpq_dmx_tspp_info.tsif[tsif].buffer_count * + sizeof(int); + mpq_dmx_tspp_info.tsif[tsif].aggregate_ids = + vzalloc(agg_size); + if (!mpq_dmx_tspp_info.tsif[tsif].aggregate_ids) { + MPQ_DVB_ERR_PRINT( + "%s: Failed to allocate memory for buffer descriptors aggregation\n", + __func__); + ret = -ENOMEM; + goto out; + } + + ret = mpq_dmx_channel_mem_alloc(tsif); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_dmx_channel_mem_alloc(%d) failed (%d)\n", + __func__, + channel_id, + ret); + + goto add_channel_failed; + } + } + + ret = tspp_open_channel(0, channel_id); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: tspp_open_channel(%d) failed (%d)\n", + __func__, + channel_id, + ret); + + goto add_channel_failed; + } + + /* set TSPP source */ + ret = tspp_open_stream(0, channel_id, &tspp_source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: tspp_select_source(%d,%d) failed (%d)\n", + __func__, + channel_id, + tspp_source.source, + ret); + + goto add_channel_close_ch; + } + + /* register notification on TS packets */ + tspp_register_notification(0, + channel_id, + mpq_tspp_callback, + (void *)(uintptr_t)tsif, + tspp_channel_timeout); + + /* + * Register allocator and provide allocation function + * that allocates from contiguous memory so that we can have + * big notification size, smallest descriptor, and still provide + * TZ with single big buffer based on notification size. + */ + if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) { + ret = tspp_allocate_buffers(0, channel_id, + mpq_dmx_tspp_info.tsif[tsif].buffer_count, + buffer_size, tspp_notification_size, + tspp_mem_allocator, tspp_mem_free, NULL); + } else { + ret = tspp_allocate_buffers(0, channel_id, + mpq_dmx_tspp_info.tsif[tsif].buffer_count, + buffer_size, tspp_notification_size, + NULL, NULL, NULL); + } + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: tspp_allocate_buffers(%d) failed (%d)\n", + __func__, + channel_id, + ret); + + goto add_channel_unregister_notif; + } + + mpq_dmx_tspp_info.tsif[tsif].mpq_demux = mpq_demux; + } + + /* add new PID to the existing pipe */ + slot = mpq_tspp_get_free_filter_slot(tsif); + if (slot < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_get_free_filter_slot(%d) failed\n", + __func__, tsif); + + goto add_channel_unregister_notif; + } + + if (feed->pid == TSPP_PASS_THROUGH_PID) + mpq_dmx_tspp_info.tsif[tsif].pass_all_flag = 1; + else if (feed->pid == TSPP_NULL_PACKETS_PID) + mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag = 1; + + mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid = feed->pid; + mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count++; + + tspp_filter.priority = -1; + + if (mpq_dmx_tspp_info.tsif[tsif].current_filter_count < + TSPP_MAX_HW_PID_FILTER_NUM) { + /* HW filtering mode */ + tspp_filter.priority = mpq_tspp_allocate_hw_filter_index(tsif); + if (tspp_filter.priority < 0) + goto add_channel_free_filter_slot; + + if (feed->pid == TSPP_PASS_THROUGH_PID) { + /* pass all pids */ + tspp_filter.pid = 0; + tspp_filter.mask = 0; + } else { + tspp_filter.pid = feed->pid; + tspp_filter.mask = TSPP_PID_MASK; + } + + /* + * Include TTS in RAW packets, if you change this to + * TSPP_MODE_RAW_NO_SUFFIX you must also change + * TSPP_RAW_TTS_SIZE accordingly. + */ + tspp_filter.mode = TSPP_MODE_RAW; + tspp_filter.source = tspp_source.source; + tspp_filter.decrypt = 0; + ret = tspp_add_filter(0, channel_id, &tspp_filter); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: tspp_add_filter(%d) failed (%d)\n", + __func__, + channel_id, + ret); + + goto add_channel_free_filter_slot; + } + mpq_dmx_tspp_info.tsif[tsif].filters[slot].hw_index = + tspp_filter.priority; + + MPQ_DVB_DBG_PRINT( + "%s: HW filtering mode: added TSPP HW filter, PID = %d, mask = 0x%X, index = %d\n", + __func__, tspp_filter.pid, tspp_filter.mask, + tspp_filter.priority); + } else if (mpq_dmx_tspp_info.tsif[tsif].current_filter_count == + TSPP_MAX_HW_PID_FILTER_NUM) { + /* Crossing the threshold - from HW to SW filtering mode */ + + /* Add a temporary filter to accept all packets */ + ret = mpq_tspp_add_accept_all_filter(channel_id, + tspp_source.source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_add_accept_all_filter(%d, %d) failed\n", + __func__, channel_id, tspp_source.source); + + goto add_channel_free_filter_slot; + } + + /* Remove all existing user filters */ + ret = mpq_tspp_remove_all_user_filters(channel_id, + tspp_source.source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_remove_all_user_filters(%d, %d) failed\n", + __func__, channel_id, tspp_source.source); + + restore_user_filters = 1; + remove_accept_all_filter = 1; + + goto add_channel_free_filter_slot; + } + + /* Add HW filters to block NULL packets */ + ret = mpq_tspp_add_null_blocking_filters(channel_id, + tspp_source.source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_add_null_blocking_filters(%d, %d) failed\n", + __func__, channel_id, tspp_source.source); + + restore_user_filters = 1; + remove_accept_all_filter = 1; + + goto add_channel_free_filter_slot; + } + + /* Remove filters that accepts all packets, if necessary */ + if ((mpq_dmx_tspp_info.tsif[tsif].pass_all_flag == 0) && + (mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag == 0)) { + + ret = mpq_tspp_remove_accept_all_filter(channel_id, + tspp_source.source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_remove_accept_all_filter(%d, %d) failed\n", + __func__, channel_id, + tspp_source.source); + + remove_null_blocking_filters = 1; + restore_user_filters = 1; + remove_accept_all_filter = 1; + + goto add_channel_free_filter_slot; + } + } + } else { + /* Already working in SW filtering mode */ + if (mpq_dmx_tspp_info.tsif[tsif].pass_all_flag || + mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag) { + + ret = mpq_tspp_add_accept_all_filter(channel_id, + tspp_source.source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_add_accept_all_filter(%d, %d) failed\n", + __func__, channel_id, + tspp_source.source); + + goto add_channel_free_filter_slot; + } + } + } + + (*channel_ref_count)++; + mpq_dmx_tspp_info.tsif[tsif].current_filter_count++; + + MPQ_DVB_DBG_PRINT("%s: success, current_filter_count = %d\n", + __func__, mpq_dmx_tspp_info.tsif[tsif].current_filter_count); + + goto out; + +add_channel_free_filter_slot: + /* restore internal database state */ + mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid = -1; + mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count--; + + /* release HW index if we allocated one */ + if (tspp_filter.priority >= 0) { + mpq_dmx_tspp_info.tsif[tsif].filters[slot].hw_index = -1; + mpq_tspp_release_hw_filter_index(tsif, tspp_filter.priority); + } + + /* restore HW filter table state if necessary */ + if (remove_null_blocking_filters) + mpq_tspp_remove_null_blocking_filters(channel_id, + tspp_source.source); + + if (restore_user_filters) + mpq_tspp_add_all_user_filters(channel_id, tspp_source.source); + + if (remove_accept_all_filter) + mpq_tspp_remove_accept_all_filter(channel_id, + tspp_source.source); + + /* restore flags. we can only get here if we changed the flags. */ + if (feed->pid == TSPP_PASS_THROUGH_PID) + mpq_dmx_tspp_info.tsif[tsif].pass_all_flag = 0; + else if (feed->pid == TSPP_NULL_PACKETS_PID) + mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag = 0; + +add_channel_unregister_notif: + if (*channel_ref_count == 0) { + tspp_unregister_notification(0, channel_id); + tspp_close_stream(0, channel_id); + } +add_channel_close_ch: + if (*channel_ref_count == 0) + tspp_close_channel(0, channel_id); +add_channel_failed: + if (*channel_ref_count == 0) + if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) { + vfree(mpq_dmx_tspp_info.tsif[tsif].aggregate_ids); + mpq_dmx_tspp_info.tsif[tsif].aggregate_ids = NULL; + mpq_dmx_channel_mem_free(tsif); + } + +out: + mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex); + atomic_dec(&mpq_dmx_tspp_info.tsif[tsif].control_op); + return ret; +} + +/** + * Removes filter from TSPP. + * + * @feed: The feed to remove + * + * Return error status + * + * The function checks if this is the only PID allocated within + * the channel, if so, the channel is closed as well. + */ +static int mpq_tspp_dmx_remove_channel(struct dvb_demux_feed *feed) +{ + int tsif; + int ret = 0; + int channel_id; + int slot; + atomic_t *data_cnt; + int *channel_ref_count; + enum tspp_source tspp_source; + struct tspp_filter tspp_filter; + struct mpq_demux *mpq_demux = feed->demux->priv; + int restore_null_blocking_filters = 0; + int remove_accept_all_filter = 0; + int remove_user_filters = 0; + int accept_all_filter_existed = 0; + + MPQ_DVB_DBG_PRINT("%s: executed, PID = %d\n", __func__, feed->pid); + + /* determine the TSIF we are reading from */ + if (mpq_demux->source == DMX_SOURCE_FRONT0) { + tsif = 0; + tspp_source = TSPP_SOURCE_TSIF0; + } else if (mpq_demux->source == DMX_SOURCE_FRONT1) { + tsif = 1; + tspp_source = TSPP_SOURCE_TSIF1; + } else { + /* invalid source */ + MPQ_DVB_ERR_PRINT( + "%s: invalid input source (%d)\n", + __func__, + mpq_demux->source); + + return -EINVAL; + } + + atomic_inc(&mpq_dmx_tspp_info.tsif[tsif].control_op); + if (mutex_lock_interruptible(&mpq_dmx_tspp_info.tsif[tsif].mutex)) { + atomic_dec(&mpq_dmx_tspp_info.tsif[tsif].control_op); + return -ERESTARTSYS; + } + + channel_id = TSPP_CHANNEL_ID(tsif, TSPP_CHANNEL); + channel_ref_count = &mpq_dmx_tspp_info.tsif[tsif].channel_ref; + data_cnt = &mpq_dmx_tspp_info.tsif[tsif].data_cnt; + + /* check if required TSPP pipe is already allocated or not */ + if (*channel_ref_count == 0) { + /* invalid feed provided as the channel is not allocated */ + MPQ_DVB_ERR_PRINT( + "%s: invalid feed (%d)\n", + __func__, + channel_id); + + ret = -EINVAL; + goto out; + } + + slot = mpq_tspp_get_filter_slot(tsif, feed->pid); + + if (slot < 0) { + /* invalid feed provided as it has no filter allocated */ + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_get_filter_slot failed (%d,%d)\n", + __func__, + feed->pid, + tsif); + + ret = -EINVAL; + goto out; + } + + /* since filter was found, ref_count > 0 so it's ok to decrement it */ + mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count--; + + if (mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count) { + /* + * there are still references to this pid, do not + * remove the filter yet + */ + goto out; + } + + if (feed->pid == TSPP_PASS_THROUGH_PID) + mpq_dmx_tspp_info.tsif[tsif].pass_all_flag = 0; + else if (feed->pid == TSPP_NULL_PACKETS_PID) + mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag = 0; + + mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid = -1; + + if (mpq_dmx_tspp_info.tsif[tsif].current_filter_count <= + TSPP_MAX_HW_PID_FILTER_NUM) { + /* staying in HW filtering mode */ + tspp_filter.priority = + mpq_dmx_tspp_info.tsif[tsif].filters[slot].hw_index; + ret = tspp_remove_filter(0, channel_id, &tspp_filter); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: tspp_remove_filter failed (%d,%d)\n", + __func__, + channel_id, + tspp_filter.priority); + + goto remove_channel_failed_restore_count; + } + mpq_tspp_release_hw_filter_index(tsif, tspp_filter.priority); + mpq_dmx_tspp_info.tsif[tsif].filters[slot].hw_index = -1; + + MPQ_DVB_DBG_PRINT( + "%s: HW filtering mode: Removed TSPP HW filter, PID = %d, index = %d\n", + __func__, feed->pid, tspp_filter.priority); + } else if (mpq_dmx_tspp_info.tsif[tsif].current_filter_count == + (TSPP_MAX_HW_PID_FILTER_NUM + 1)) { + /* Crossing the threshold - from SW to HW filtering mode */ + + accept_all_filter_existed = + mpq_dmx_tspp_info.tsif[tsif].accept_all_filter_exists_flag; + + /* Add a temporary filter to accept all packets */ + ret = mpq_tspp_add_accept_all_filter(channel_id, + tspp_source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_add_accept_all_filter(%d, %d) failed\n", + __func__, channel_id, tspp_source); + + goto remove_channel_failed_restore_count; + } + + ret = mpq_tspp_remove_null_blocking_filters(channel_id, + tspp_source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_remove_null_blocking_filters(%d, %d) failed\n", + __func__, channel_id, tspp_source); + + restore_null_blocking_filters = 1; + if (!accept_all_filter_existed) + remove_accept_all_filter = 1; + + goto remove_channel_failed_restore_count; + } + + ret = mpq_tspp_add_all_user_filters(channel_id, + tspp_source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_add_all_user_filters(%d, %d) failed\n", + __func__, channel_id, tspp_source); + + remove_user_filters = 1; + restore_null_blocking_filters = 1; + if (!accept_all_filter_existed) + remove_accept_all_filter = 1; + + goto remove_channel_failed_restore_count; + } + + ret = mpq_tspp_remove_accept_all_filter(channel_id, + tspp_source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_remove_accept_all_filter(%d, %d) failed\n", + __func__, channel_id, tspp_source); + + remove_user_filters = 1; + restore_null_blocking_filters = 1; + if (!accept_all_filter_existed) + remove_accept_all_filter = 1; + + goto remove_channel_failed_restore_count; + } + } else { + /* staying in SW filtering mode */ + if ((mpq_dmx_tspp_info.tsif[tsif].pass_all_flag == 0) && + (mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag == 0)) { + + ret = mpq_tspp_remove_accept_all_filter(channel_id, + tspp_source); + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_tspp_remove_accept_all_filter(%d, %d) failed\n", + __func__, channel_id, + tspp_source); + + goto remove_channel_failed_restore_count; + } + } + } + + mpq_dmx_tspp_info.tsif[tsif].current_filter_count--; + (*channel_ref_count)--; + + MPQ_DVB_DBG_PRINT("%s: success, current_filter_count = %d\n", + __func__, mpq_dmx_tspp_info.tsif[tsif].current_filter_count); + + if (*channel_ref_count == 0) { + /* channel is not used any more, release it */ + tspp_unregister_notification(0, channel_id); + tspp_close_stream(0, channel_id); + tspp_close_channel(0, channel_id); + atomic_set(data_cnt, 0); + + if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) { + vfree(mpq_dmx_tspp_info.tsif[tsif].aggregate_ids); + mpq_dmx_tspp_info.tsif[tsif].aggregate_ids = NULL; + mpq_dmx_channel_mem_free(tsif); + } + } + + goto out; + +remove_channel_failed_restore_count: + /* restore internal database state */ + mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid = feed->pid; + mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count++; + + if (remove_user_filters) + mpq_tspp_remove_all_user_filters(channel_id, tspp_source); + + if (restore_null_blocking_filters) + mpq_tspp_add_null_blocking_filters(channel_id, tspp_source); + + if (remove_accept_all_filter) + mpq_tspp_remove_accept_all_filter(channel_id, tspp_source); + + /* restore flags. we can only get here if we changed the flags. */ + if (feed->pid == TSPP_PASS_THROUGH_PID) + mpq_dmx_tspp_info.tsif[tsif].pass_all_flag = 1; + else if (feed->pid == TSPP_NULL_PACKETS_PID) + mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag = 1; + +out: + mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex); + atomic_dec(&mpq_dmx_tspp_info.tsif[tsif].control_op); + return ret; +} + +static int mpq_tspp_dmx_start_filtering(struct dvb_demux_feed *feed) +{ + int ret; + struct mpq_demux *mpq_demux = feed->demux->priv; + + MPQ_DVB_DBG_PRINT( + "%s(pid=%d) executed\n", + __func__, + feed->pid); + + if (mpq_demux == NULL) { + MPQ_DVB_ERR_PRINT( + "%s: invalid mpq_demux handle\n", + __func__); + + return -EINVAL; + } + + if (mpq_demux->source < DMX_SOURCE_DVR0) { + /* source from TSPP, need to configure tspp pipe */ + ret = mpq_tspp_dmx_add_channel(feed); + + if (ret < 0) { + MPQ_DVB_DBG_PRINT( + "%s: mpq_tspp_dmx_add_channel failed(%d)\n", + __func__, + ret); + return ret; + } + } + + /* + * Always feed sections/PES starting from a new one and + * do not partial transfer data from older one + */ + feed->pusi_seen = 0; + + ret = mpq_dmx_init_mpq_feed(feed); + if (ret) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_dmx_init_mpq_feed failed(%d)\n", + __func__, + ret); + if (mpq_demux->source < DMX_SOURCE_DVR0) + mpq_tspp_dmx_remove_channel(feed); + + return ret; + } + + return 0; +} + +static int mpq_tspp_dmx_stop_filtering(struct dvb_demux_feed *feed) +{ + int ret = 0; + struct mpq_demux *mpq_demux = feed->demux->priv; + + MPQ_DVB_DBG_PRINT("%s(%d) executed\n", __func__, feed->pid); + + mpq_dmx_terminate_feed(feed); + + if (mpq_demux->source < DMX_SOURCE_DVR0) { + /* source from TSPP, need to configure tspp pipe */ + ret = mpq_tspp_dmx_remove_channel(feed); + } + + return ret; +} + +static int mpq_tspp_dmx_write_to_decoder( + struct dvb_demux_feed *feed, + const u8 *buf, + size_t len) +{ + /* + * It is assumed that this function is called once for each + * TS packet of the relevant feed. + */ + if (len > TSPP_RAW_TTS_SIZE) + MPQ_DVB_DBG_PRINT( + "%s: warnning - len larger than one packet\n", + __func__); + + if (dvb_dmx_is_video_feed(feed)) + return mpq_dmx_process_video_packet(feed, buf); + + if (dvb_dmx_is_pcr_feed(feed)) + return mpq_dmx_process_pcr_packet(feed, buf); + + return 0; +} + +/** + * Returns demux capabilities of TSPPv1 plugin + * + * @demux: demux device + * @caps: Returned capbabilities + * + * Return error code + */ +static int mpq_tspp_dmx_get_caps(struct dmx_demux *demux, + struct dmx_caps *caps) +{ + struct dvb_demux *dvb_demux = demux->priv; + + if ((dvb_demux == NULL) || (caps == NULL)) { + MPQ_DVB_ERR_PRINT( + "%s: invalid parameters\n", + __func__); + + return -EINVAL; + } + + caps->caps = DMX_CAP_PULL_MODE | DMX_CAP_VIDEO_DECODER_DATA | + DMX_CAP_TS_INSERTION | DMX_CAP_VIDEO_INDEXING | + DMX_CAP_AUTO_BUFFER_FLUSH; + caps->recording_max_video_pids_indexed = 0; + caps->num_decoders = MPQ_ADAPTER_MAX_NUM_OF_INTERFACES; + caps->num_demux_devices = CONFIG_DVB_MPQ_NUM_DMX_DEVICES; + caps->num_pid_filters = TSPP_MAX_PID_FILTER_NUM; + caps->num_section_filters = dvb_demux->filternum; + caps->num_section_filters_per_pid = dvb_demux->filternum; + caps->section_filter_length = DMX_FILTER_SIZE; + caps->num_demod_inputs = TSIF_COUNT; + caps->num_memory_inputs = CONFIG_DVB_MPQ_NUM_DMX_DEVICES; + caps->max_bitrate = 192; + caps->demod_input_max_bitrate = 96; + caps->memory_input_max_bitrate = 96; + caps->num_cipher_ops = 1; + + /* TSIF reports 3 bytes STC at unit of 27MHz/256 */ + caps->max_stc = (u64)0xFFFFFF * 256; + + /* Buffer requirements */ + caps->section.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->section.max_buffer_num = 1; + caps->section.max_size = 0xFFFFFFFF; + caps->section.size_alignment = 0; + caps->pes.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->pes.max_buffer_num = 1; + caps->pes.max_size = 0xFFFFFFFF; + caps->pes.size_alignment = 0; + caps->recording_188_tsp.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->recording_188_tsp.max_buffer_num = 1; + caps->recording_188_tsp.max_size = 0xFFFFFFFF; + caps->recording_188_tsp.size_alignment = 0; + caps->recording_192_tsp.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->recording_192_tsp.max_buffer_num = 1; + caps->recording_192_tsp.max_size = 0xFFFFFFFF; + caps->recording_192_tsp.size_alignment = 0; + caps->playback_188_tsp.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->playback_188_tsp.max_buffer_num = 1; + caps->playback_188_tsp.max_size = 0xFFFFFFFF; + caps->playback_188_tsp.size_alignment = 188; + caps->playback_192_tsp.flags = + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_CACHED; + caps->playback_192_tsp.max_buffer_num = 1; + caps->playback_192_tsp.max_size = 0xFFFFFFFF; + caps->playback_192_tsp.size_alignment = 192; + caps->decoder.flags = + DMX_BUFFER_SECURED_IF_DECRYPTED | + DMX_BUFFER_EXTERNAL_SUPPORT | + DMX_BUFFER_INTERNAL_SUPPORT | + DMX_BUFFER_LINEAR_GROUP_SUPPORT | + DMX_BUFFER_CACHED; + caps->decoder.max_buffer_num = DMX_MAX_DECODER_BUFFER_NUM; + caps->decoder.max_size = 0xFFFFFFFF; + caps->decoder.size_alignment = SZ_4K; + + return 0; +} + + +/** + * Reads TSIF STC from TSPP + * + * @demux: demux device + * @num: STC number. 0 for TSIF0 and 1 for TSIF1. + * @stc: STC value + * @base: divisor to get 90KHz value + * + * Return error code + */ +static int mpq_tspp_dmx_get_stc(struct dmx_demux *demux, unsigned int num, + u64 *stc, unsigned int *base) +{ + enum tspp_source source; + u32 tcr_counter; + u64 avtimer_stc = 0; + int tts_source = 0; + + if (!demux || !stc || !base) + return -EINVAL; + + if (num == 0) + source = TSPP_SOURCE_TSIF0; + else if (num == 1) + source = TSPP_SOURCE_TSIF1; + else + return -EINVAL; + + if (tspp_get_tts_source(0, &tts_source) < 0) + tts_source = TSIF_TTS_TCR; + + if (tts_source != TSIF_TTS_LPASS_TIMER) { + tspp_get_ref_clk_counter(0, source, &tcr_counter); + *stc = ((u64)tcr_counter) * 256; /* conversion to 27MHz */ + *base = 300; /* divisor to get 90KHz clock from stc value */ + } else { + if (tspp_get_lpass_time_counter(0, source, &avtimer_stc) < 0) + return -EINVAL; + *stc = avtimer_stc; + } + return 0; +} + +static int mpq_tspp_dmx_init( + struct dvb_adapter *mpq_adapter, + struct mpq_demux *mpq_demux) +{ + int result; + + MPQ_DVB_DBG_PRINT("%s executed\n", __func__); + + mpq_dmx_tspp_info.ion_client = mpq_demux->ion_client; + + /* Set the kernel-demux object capabilities */ + mpq_demux->demux.dmx.capabilities = + DMX_TS_FILTERING | + DMX_PES_FILTERING | + DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING | + DMX_CRC_CHECKING | + DMX_TS_DESCRAMBLING; + + /* Set dvb-demux "virtual" function pointers */ + mpq_demux->demux.priv = (void *)mpq_demux; + mpq_demux->demux.filternum = TSPP_MAX_SECTION_FILTER_NUM; + mpq_demux->demux.feednum = MPQ_MAX_DMX_FILES; + mpq_demux->demux.start_feed = mpq_tspp_dmx_start_filtering; + mpq_demux->demux.stop_feed = mpq_tspp_dmx_stop_filtering; + mpq_demux->demux.write_to_decoder = mpq_tspp_dmx_write_to_decoder; + mpq_demux->demux.decoder_fullness_init = mpq_dmx_decoder_fullness_init; + mpq_demux->demux.decoder_fullness_wait = mpq_dmx_decoder_fullness_wait; + mpq_demux->demux.decoder_fullness_abort = + mpq_dmx_decoder_fullness_abort; + mpq_demux->demux.decoder_buffer_status = mpq_dmx_decoder_buffer_status; + mpq_demux->demux.reuse_decoder_buffer = mpq_dmx_reuse_decoder_buffer; + mpq_demux->demux.set_cipher_op = mpq_dmx_set_cipher_ops; + mpq_demux->demux.oob_command = mpq_dmx_oob_command; + mpq_demux->demux.convert_ts = mpq_dmx_convert_tts; + mpq_demux->demux.flush_decoder_buffer = NULL; + + /* Initialize dvb_demux object */ + result = dvb_dmx_init(&mpq_demux->demux); + if (result < 0) { + MPQ_DVB_ERR_PRINT("%s: dvb_dmx_init failed\n", __func__); + goto init_failed; + } + + /* Now initailize the dmx-dev object */ + mpq_demux->dmxdev.filternum = MPQ_MAX_DMX_FILES; + mpq_demux->dmxdev.demux = &mpq_demux->demux.dmx; + mpq_demux->dmxdev.capabilities = DMXDEV_CAP_DUPLEX; + + mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source; + mpq_demux->dmxdev.demux->get_stc = mpq_tspp_dmx_get_stc; + mpq_demux->dmxdev.demux->get_caps = mpq_tspp_dmx_get_caps; + mpq_demux->dmxdev.demux->map_buffer = mpq_dmx_map_buffer; + mpq_demux->dmxdev.demux->unmap_buffer = mpq_dmx_unmap_buffer; + mpq_demux->dmxdev.demux->write = mpq_dmx_write; + result = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter); + if (result < 0) { + MPQ_DVB_ERR_PRINT("%s: dvb_dmxdev_init failed (errno=%d)\n", + __func__, + result); + goto init_failed_dmx_release; + } + + /* Extend dvb-demux debugfs with TSPP statistics. */ + mpq_dmx_init_debugfs_entries(mpq_demux); + + /* Get the TSIF TTS info */ + if (tspp_get_tts_source(0, &mpq_demux->ts_packet_timestamp_source) < 0) + mpq_demux->ts_packet_timestamp_source = TSIF_TTS_TCR; + + return 0; + +init_failed_dmx_release: + dvb_dmx_release(&mpq_demux->demux); +init_failed: + return result; +} + +static int mpq_dmx_tspp_plugin_probe(struct platform_device *pdev) +{ + int i; + int j; + int ret; + + MPQ_DVB_DBG_PRINT("%s executed\n", __func__); + + for (i = 0; i < TSIF_COUNT; i++) { + mpq_dmx_tspp_info.tsif[i].aggregate_ids = NULL; + mpq_dmx_tspp_info.tsif[i].channel_ref = 0; + mpq_dmx_tspp_info.tsif[i].buff_index = 0; + mpq_dmx_tspp_info.tsif[i].ch_mem_heap_handle = NULL; + mpq_dmx_tspp_info.tsif[i].ch_mem_heap_virt_base = NULL; + mpq_dmx_tspp_info.tsif[i].ch_mem_heap_phys_base = 0; + atomic_set(&mpq_dmx_tspp_info.tsif[i].data_cnt, 0); + atomic_set(&mpq_dmx_tspp_info.tsif[i].control_op, 0); + + for (j = 0; j < TSPP_MAX_PID_FILTER_NUM; j++) { + mpq_dmx_tspp_info.tsif[i].filters[j].pid = -1; + mpq_dmx_tspp_info.tsif[i].filters[j].ref_count = 0; + mpq_dmx_tspp_info.tsif[i].filters[j].hw_index = -1; + } + + for (j = 0; j < TSPP_MAX_HW_PID_FILTER_NUM; j++) + mpq_dmx_tspp_info.tsif[i].hw_indexes[j] = 0; + + mpq_dmx_tspp_info.tsif[i].current_filter_count = 0; + mpq_dmx_tspp_info.tsif[i].pass_nulls_flag = 0; + mpq_dmx_tspp_info.tsif[i].pass_all_flag = 0; + mpq_dmx_tspp_info.tsif[i].accept_all_filter_exists_flag = 0; + + snprintf(mpq_dmx_tspp_info.tsif[i].name, + TSIF_NAME_LENGTH, + "dmx_tsif%d", + i); + + init_waitqueue_head(&mpq_dmx_tspp_info.tsif[i].wait_queue); + mpq_dmx_tspp_info.tsif[i].thread = + kthread_run( + mpq_dmx_tspp_thread, (void *)(uintptr_t)i, + mpq_dmx_tspp_info.tsif[i].name); + + if (IS_ERR(mpq_dmx_tspp_info.tsif[i].thread)) { + for (j = 0; j < i; j++) { + kthread_stop(mpq_dmx_tspp_info.tsif[j].thread); + mutex_destroy(&mpq_dmx_tspp_info.tsif[j].mutex); + } + + MPQ_DVB_ERR_PRINT( + "%s: kthread_run failed\n", + __func__); + + return -ENOMEM; + } + + mutex_init(&mpq_dmx_tspp_info.tsif[i].mutex); + } + + ret = mpq_dmx_plugin_init(mpq_tspp_dmx_init, pdev); + + if (ret < 0) { + MPQ_DVB_ERR_PRINT( + "%s: mpq_dmx_plugin_init failed (errno=%d)\n", + __func__, + ret); + + for (i = 0; i < TSIF_COUNT; i++) { + kthread_stop(mpq_dmx_tspp_info.tsif[i].thread); + mutex_destroy(&mpq_dmx_tspp_info.tsif[i].mutex); + } + } + + return ret; +} + +static int mpq_dmx_tspp_plugin_remove(struct platform_device *pdev) +{ + int i; + + MPQ_DVB_DBG_PRINT("%s executed\n", __func__); + + for (i = 0; i < TSIF_COUNT; i++) { + mutex_lock(&mpq_dmx_tspp_info.tsif[i].mutex); + + /* + * Note: tspp_close_channel will also free the TSPP buffers + * even if we allocated them ourselves, + * using our free function. + */ + if (mpq_dmx_tspp_info.tsif[i].channel_ref) { + tspp_unregister_notification(0, + TSPP_CHANNEL_ID(i, TSPP_CHANNEL)); + tspp_close_channel(0, + TSPP_CHANNEL_ID(i, TSPP_CHANNEL)); + + if (allocation_mode == + MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) { + vfree(mpq_dmx_tspp_info.tsif[i].aggregate_ids); + mpq_dmx_tspp_info.tsif[i].aggregate_ids = NULL; + mpq_dmx_channel_mem_free(i); + } + } + + mutex_unlock(&mpq_dmx_tspp_info.tsif[i].mutex); + kthread_stop(mpq_dmx_tspp_info.tsif[i].thread); + mutex_destroy(&mpq_dmx_tspp_info.tsif[i].mutex); + } + + mpq_dmx_plugin_exit(); + return 0; +} + +static const struct of_device_id msm_match_table[] = { + {.compatible = "qcom,demux"}, + {} +}; + +static struct platform_driver mpq_dmx_tspp_plugin_driver = { + .probe = mpq_dmx_tspp_plugin_probe, + .remove = mpq_dmx_tspp_plugin_remove, + .driver = { + .name = "demux", + .of_match_table = msm_match_table, + }, +}; + + +static int __init mpq_dmx_tspp_plugin_init(void) +{ + int rc; + + /* register the driver, and check hardware */ + rc = platform_driver_register(&mpq_dmx_tspp_plugin_driver); + if (rc) + pr_err("%s: platform_driver_register failed: %d\n", + __func__, rc); + + return rc; +} + +static void __exit mpq_dmx_tspp_plugin_exit(void) +{ + /* delete low level driver */ + platform_driver_unregister(&mpq_dmx_tspp_plugin_driver); +} + + +module_init(mpq_dmx_tspp_plugin_init); +module_exit(mpq_dmx_tspp_plugin_exit); + +MODULE_DESCRIPTION("Qualcomm Technologies Inc. demux TSPP version 1 HW Plugin"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.c b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.c new file mode 100644 index 000000000000..1cfade7e8a55 --- /dev/null +++ b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.c @@ -0,0 +1,1025 @@ +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include "qseecom_kernel.h" +#include "mpq_sdmx.h" + +static struct qseecom_handle *sdmx_qseecom_handles[SDMX_MAX_SESSIONS]; +static struct mutex sdmx_lock[SDMX_MAX_SESSIONS]; + +#define QSEECOM_SBUFF_SIZE SZ_128K + +enum sdmx_cmd_id { + SDMX_OPEN_SESSION_CMD, + SDMX_CLOSE_SESSION_CMD, + SDMX_SET_SESSION_CFG_CMD, + SDMX_ADD_FILTER_CMD, + SDMX_REMOVE_FILTER_CMD, + SDMX_SET_KL_IDX_CMD, + SDMX_ADD_RAW_PID_CMD, + SDMX_REMOVE_RAW_PID_CMD, + SDMX_PROCESS_CMD, + SDMX_GET_DBG_COUNTERS_CMD, + SDMX_RESET_DBG_COUNTERS_CMD, + SDMX_GET_VERSION_CMD, + SDMX_INVALIDATE_KL_CMD, + SDMX_SET_LOG_LEVEL_CMD +}; + +#pragma pack(push, sdmx, 1) + +struct sdmx_proc_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; + u8 flags; + struct sdmx_buff_descr in_buf_descr; + u32 inp_fill_cnt; + u32 in_rd_offset; + u32 num_filters; + struct sdmx_filter_status filters_status[]; +}; + +struct sdmx_proc_rsp { + enum sdmx_status ret; + u32 inp_fill_cnt; + u32 in_rd_offset; + u32 err_indicators; + u32 status_indicators; +}; + +struct sdmx_open_ses_req { + enum sdmx_cmd_id cmd_id; +}; + +struct sdmx_open_ses_rsp { + enum sdmx_status ret; + u32 session_handle; +}; + +struct sdmx_close_ses_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; +}; + +struct sdmx_close_ses_rsp { + enum sdmx_status ret; +}; + +struct sdmx_ses_cfg_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; + enum sdmx_proc_mode process_mode; + enum sdmx_inp_mode input_mode; + enum sdmx_pkt_format packet_len; + u8 odd_scramble_bits; + u8 even_scramble_bits; +}; + +struct sdmx_ses_cfg_rsp { + enum sdmx_status ret; +}; + +struct sdmx_set_kl_ind_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; + u32 pid; + u32 kl_index; +}; + +struct sdmx_set_kl_ind_rsp { + enum sdmx_status ret; +}; + +struct sdmx_add_filt_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; + u32 pid; + enum sdmx_filter filter_type; + struct sdmx_buff_descr meta_data_buf; + enum sdmx_buf_mode buffer_mode; + enum sdmx_raw_out_format ts_out_format; + u32 flags; + u32 num_data_bufs; + struct sdmx_data_buff_descr data_bufs[]; +}; + +struct sdmx_add_filt_rsp { + enum sdmx_status ret; + u32 filter_handle; +}; + +struct sdmx_rem_filt_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; + u32 filter_handle; +}; + +struct sdmx_rem_filt_rsp { + enum sdmx_status ret; +}; + +struct sdmx_add_raw_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; + u32 filter_handle; + u32 pid; +}; + +struct sdmx_add_raw_rsp { + enum sdmx_status ret; +}; + +struct sdmx_rem_raw_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; + u32 filter_handle; + u32 pid; +}; + +struct sdmx_rem_raw_rsp { + enum sdmx_status ret; +}; + +struct sdmx_get_counters_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; + u32 num_filters; +}; + +struct sdmx_get_counters_rsp { + enum sdmx_status ret; + struct sdmx_session_dbg_counters session_counters; + u32 num_filters; + struct sdmx_filter_dbg_counters filter_counters[]; +}; + +struct sdmx_rst_counters_req { + enum sdmx_cmd_id cmd_id; + u32 session_handle; +}; + +struct sdmx_rst_counters_rsp { + enum sdmx_status ret; +}; + +struct sdmx_get_version_req { + enum sdmx_cmd_id cmd_id; +}; + +struct sdmx_get_version_rsp { + enum sdmx_status ret; + int32_t version; +}; + +struct sdmx_set_log_level_req { + enum sdmx_cmd_id cmd_id; + enum sdmx_log_level level; + u32 session_handle; +}; + +struct sdmx_set_log_level_rsp { + enum sdmx_status ret; +}; + +#pragma pack(pop, sdmx) + +static int get_cmd_rsp_buffers(int handle_index, + void **cmd, + int *cmd_len, + void **rsp, + int *rsp_len) +{ + if (*cmd_len & QSEECOM_ALIGN_MASK) + *cmd_len = QSEECOM_ALIGN(*cmd_len); + + if (*rsp_len & QSEECOM_ALIGN_MASK) + *rsp_len = QSEECOM_ALIGN(*rsp_len); + + if ((*rsp_len + *cmd_len) > QSEECOM_SBUFF_SIZE) { + pr_err("%s: shared buffer too small to hold cmd=%d and rsp=%d\n", + __func__, *cmd_len, *rsp_len); + return SDMX_STATUS_OUT_OF_MEM; + } + + *cmd = sdmx_qseecom_handles[handle_index]->sbuf; + *rsp = sdmx_qseecom_handles[handle_index]->sbuf + *cmd_len; + return SDMX_SUCCESS; +} + +/* + * Returns version of secure-demux app. + * + * @session_handle: Returned instance handle. Must not be NULL. + * Return error code + */ +int sdmx_get_version(int session_handle, int32_t *version) +{ + int res, cmd_len, rsp_len; + struct sdmx_get_version_req *cmd; + struct sdmx_get_version_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) || + (version == NULL)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_get_version_req); + rsp_len = sizeof(struct sdmx_get_version_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_GET_VERSION_CMD; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + ret = rsp->ret; + *version = rsp->version; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; + +} +EXPORT_SYMBOL(sdmx_get_version); + +/* + * Initializes a new secure demux instance and returns a handle of the instance. + * + * @session_handle: handle of a secure demux instance to get its version. + * Return the version if successful or an error code. + */ +int sdmx_open_session(int *session_handle) +{ + int res, cmd_len, rsp_len; + enum sdmx_status ret, version_ret; + struct sdmx_open_ses_req *cmd; + struct sdmx_open_ses_rsp *rsp; + struct qseecom_handle *qseecom_handle = NULL; + int32_t version; + + /* Input validation */ + if (session_handle == NULL) + return SDMX_STATUS_GENERAL_FAILURE; + + /* Start the TZ app */ + res = qseecom_start_app(&qseecom_handle, "securemm", + QSEECOM_SBUFF_SIZE); + + if (res < 0) { + pr_debug("%s: Fail to load securemm app\n", __func__); + return SDMX_STATUS_GENERAL_FAILURE; + } + + cmd_len = sizeof(struct sdmx_open_ses_req); + rsp_len = sizeof(struct sdmx_open_ses_rsp); + + /* Get command and response buffers */ + cmd = (struct sdmx_open_ses_req *)qseecom_handle->sbuf; + + if (cmd_len & QSEECOM_ALIGN_MASK) + cmd_len = QSEECOM_ALIGN(cmd_len); + + rsp = (struct sdmx_open_ses_rsp *)qseecom_handle->sbuf + cmd_len; + + if (rsp_len & QSEECOM_ALIGN_MASK) + rsp_len = QSEECOM_ALIGN(rsp_len); + + /* Will be later overridden by SDMX response */ + *session_handle = SDMX_INVALID_SESSION_HANDLE; + + /* Populate command struct */ + cmd->cmd_id = SDMX_OPEN_SESSION_CMD; + + /* Issue QSEECom command */ + res = qseecom_send_command(qseecom_handle, (void *)cmd, cmd_len, + (void *)rsp, rsp_len); + + if (res < 0) { + qseecom_shutdown_app(&qseecom_handle); + return SDMX_STATUS_GENERAL_FAILURE; + } + + /* Parse response struct */ + *session_handle = rsp->session_handle; + + /* Initialize handle and mutex */ + sdmx_qseecom_handles[*session_handle] = qseecom_handle; + mutex_init(&sdmx_lock[*session_handle]); + ret = rsp->ret; + + /* Get and print the app version */ + version_ret = sdmx_get_version(*session_handle, &version); + if (version_ret == SDMX_SUCCESS) + pr_info("%s: TZ SDMX version is %x.%x\n", version >> 8, + __func__, version & 0xFF); + else + pr_err("%s: Error reading TZ SDMX version\n", __func__); + + return ret; +} +EXPORT_SYMBOL(sdmx_open_session); + +/* + * Closes a secure demux instance. + * + * @session_handle: handle of a secure demux instance to close. + * Return error code + */ +int sdmx_close_session(int session_handle) +{ + int res, cmd_len, rsp_len; + struct sdmx_close_ses_req *cmd; + struct sdmx_close_ses_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_close_ses_req); + rsp_len = sizeof(struct sdmx_close_ses_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_CLOSE_SESSION_CMD; + cmd->session_handle = session_handle; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + ret = rsp->ret; + + /* Shutdown the TZ app (or at least free the current handle) */ + res = qseecom_shutdown_app(&sdmx_qseecom_handles[session_handle]); + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + sdmx_qseecom_handles[session_handle] = NULL; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_close_session); + +/* + * Configures an open secure demux instance. + * + * @session_handle: secure demux instance + * @proc_mode: Defines secure demux's behavior in case of output + * buffer overflow. + * @inp_mode: Defines the input encryption settings. + * @pkt_format: TS packet length in input buffer. + * @odd_scramble_bits: Value of the scramble bits indicating the ODD key. + * @even_scramble_bits: Value of the scramble bits indicating the EVEN key. + * Return error code + */ +int sdmx_set_session_cfg(int session_handle, + enum sdmx_proc_mode proc_mode, + enum sdmx_inp_mode inp_mode, + enum sdmx_pkt_format pkt_format, + u8 odd_scramble_bits, + u8 even_scramble_bits) +{ + int res, cmd_len, rsp_len; + struct sdmx_ses_cfg_req *cmd; + struct sdmx_ses_cfg_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_ses_cfg_req); + rsp_len = sizeof(struct sdmx_ses_cfg_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_SET_SESSION_CFG_CMD; + cmd->session_handle = session_handle; + cmd->process_mode = proc_mode; + cmd->input_mode = inp_mode; + cmd->packet_len = pkt_format; + cmd->odd_scramble_bits = odd_scramble_bits; + cmd->even_scramble_bits = even_scramble_bits; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + ret = rsp->ret; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_set_session_cfg); + +/* + * Creates a new secure demux filter and returns a filter handle + * + * @session_handle: secure demux instance + * @pid: pid to filter + * @filter_type: type of filtering + * @meta_data_buf: meta data buffer descriptor + * @data_buf_mode: data buffer mode (ring/linear) + * @num_data_bufs: number of data buffers (use 1 for a ring buffer) + * @data_bufs: data buffers descriptors array + * @filter_handle: returned filter handle + * @ts_out_format: output format for raw filters + * @flags: optional flags for filter + * (currently only clear section CRC verification is supported) + * + * Return error code + */ +int sdmx_add_filter(int session_handle, + u16 pid, + enum sdmx_filter filterype, + struct sdmx_buff_descr *meta_data_buf, + enum sdmx_buf_mode d_buf_mode, + u32 num_data_bufs, + struct sdmx_data_buff_descr *data_bufs, + int *filter_handle, + enum sdmx_raw_out_format ts_out_format, + u32 flags) +{ + int res, cmd_len, rsp_len; + struct sdmx_add_filt_req *cmd; + struct sdmx_add_filt_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) || + (filter_handle == NULL)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_add_filt_req) + + num_data_bufs * sizeof(struct sdmx_data_buff_descr); + rsp_len = sizeof(struct sdmx_add_filt_rsp); + + /* Will be later overridden by SDMX response */ + *filter_handle = SDMX_INVALID_FILTER_HANDLE; + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_ADD_FILTER_CMD; + cmd->session_handle = session_handle; + cmd->pid = (u32)pid; + cmd->filter_type = filterype; + cmd->ts_out_format = ts_out_format; + cmd->flags = flags; + if (meta_data_buf != NULL) + memcpy(&(cmd->meta_data_buf), meta_data_buf, + sizeof(struct sdmx_buff_descr)); + else + memset(&(cmd->meta_data_buf), 0, sizeof(cmd->meta_data_buf)); + + cmd->buffer_mode = d_buf_mode; + cmd->num_data_bufs = num_data_bufs; + memcpy(cmd->data_bufs, data_bufs, + num_data_bufs * sizeof(struct sdmx_data_buff_descr)); + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + /* Parse response struct */ + *filter_handle = rsp->filter_handle; + ret = rsp->ret; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_add_filter); + +/* + * Removes a secure demux filter + * + * @session_handle: secure demux instance + * @filter_handle: filter handle to remove + * + * Return error code + */ +int sdmx_remove_filter(int session_handle, int filter_handle) +{ + int res, cmd_len, rsp_len; + struct sdmx_rem_filt_req *cmd; + struct sdmx_rem_filt_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_rem_filt_req); + rsp_len = sizeof(struct sdmx_rem_filt_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_REMOVE_FILTER_CMD; + cmd->session_handle = session_handle; + cmd->filter_handle = filter_handle; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + ret = rsp->ret; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_remove_filter); + +/* + * Associates a key ladder index for the specified pid + * + * @session_handle: secure demux instance + * @pid: pid + * @key_ladder_index: key ladder index to associate to the pid + * + * Return error code + * + * Note: if pid already has some key ladder index associated, it will be + * overridden. + */ +int sdmx_set_kl_ind(int session_handle, u16 pid, u32 key_ladder_index) +{ + int res, cmd_len, rsp_len; + struct sdmx_set_kl_ind_req *cmd; + struct sdmx_set_kl_ind_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_set_kl_ind_req); + rsp_len = sizeof(struct sdmx_set_kl_ind_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_SET_KL_IDX_CMD; + cmd->session_handle = session_handle; + cmd->pid = (u32)pid; + cmd->kl_index = key_ladder_index; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + ret = rsp->ret; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_set_kl_ind); + +/* + * Adds the specified pid to an existing raw (recording) filter + * + * @session_handle: secure demux instance + * @filter_handle: raw filter handle + * @pid: pid + * + * Return error code + */ +int sdmx_add_raw_pid(int session_handle, int filter_handle, u16 pid) +{ + int res, cmd_len, rsp_len; + struct sdmx_add_raw_req *cmd; + struct sdmx_add_raw_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_add_raw_req); + rsp_len = sizeof(struct sdmx_add_raw_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_ADD_RAW_PID_CMD; + cmd->session_handle = session_handle; + cmd->filter_handle = filter_handle; + cmd->pid = (u32)pid; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + ret = rsp->ret; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_add_raw_pid); + +/* + * Removes the specified pid from a raw (recording) filter + * + * @session_handle: secure demux instance + * @filter_handle: raw filter handle + * @pid: pid + * + * Return error code + */ +int sdmx_remove_raw_pid(int session_handle, int filter_handle, u16 pid) +{ + int res, cmd_len, rsp_len; + struct sdmx_rem_raw_req *cmd; + struct sdmx_rem_raw_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_rem_raw_req); + rsp_len = sizeof(struct sdmx_rem_raw_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_REMOVE_RAW_PID_CMD; + cmd->session_handle = session_handle; + cmd->filter_handle = filter_handle; + cmd->pid = (u32)pid; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + ret = rsp->ret; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_remove_raw_pid); + +/* + * Call secure demux to perform processing on the specified input buffer + * + * @session_handle: secure demux instance + * @flags: input flags. Currently only EOS marking is supported. + * @input_buf_desc: input buffer descriptor + * @input_fill_count: number of bytes available in input buffer + * @input_read_offset: offset inside input buffer where data starts + * @error_indicators: returned general error indicators + * @status_indicators: returned general status indicators + * @num_filters: number of filters in filter status array + * @filter_status: filter status descriptor array + * + * Return error code + */ +int sdmx_process(int session_handle, u8 flags, + struct sdmx_buff_descr *input_buf_desc, + u32 *input_fill_count, + u32 *input_read_offset, + u32 *error_indicators, + u32 *status_indicators, + u32 num_filters, + struct sdmx_filter_status *filter_status) +{ + int res, cmd_len, rsp_len; + struct sdmx_proc_req *cmd; + struct sdmx_proc_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) || + (input_buf_desc == NULL) || + (input_fill_count == NULL) || (input_read_offset == NULL) || + (error_indicators == NULL) || (status_indicators == NULL) || + (filter_status == NULL)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_proc_req) + + num_filters * sizeof(struct sdmx_filter_status); + rsp_len = sizeof(struct sdmx_proc_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_PROCESS_CMD; + cmd->session_handle = session_handle; + cmd->flags = flags; + cmd->in_buf_descr.base_addr = input_buf_desc->base_addr; + cmd->in_buf_descr.size = input_buf_desc->size; + cmd->inp_fill_cnt = *input_fill_count; + cmd->in_rd_offset = *input_read_offset; + cmd->num_filters = num_filters; + memcpy(cmd->filters_status, filter_status, + num_filters * sizeof(struct sdmx_filter_status)); + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + /* Parse response struct */ + *input_fill_count = rsp->inp_fill_cnt; + *input_read_offset = rsp->in_rd_offset; + *error_indicators = rsp->err_indicators; + *status_indicators = rsp->status_indicators; + memcpy(filter_status, cmd->filters_status, + num_filters * sizeof(struct sdmx_filter_status)); + ret = rsp->ret; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_process); + +/* + * Returns session-level & filter-level debug counters + * + * @session_handle: secure demux instance + * @session_counters: returned session-level debug counters + * @num_filters: returned number of filters reported in filter_counters + * @filter_counters: returned filter-level debug counters array + * + * Return error code + */ +int sdmx_get_dbg_counters(int session_handle, + struct sdmx_session_dbg_counters *session_counters, + u32 *num_filters, + struct sdmx_filter_dbg_counters *filter_counters) +{ + int res, cmd_len, rsp_len; + struct sdmx_get_counters_req *cmd; + struct sdmx_get_counters_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) || + (session_counters == NULL) || (num_filters == NULL) || + (filter_counters == NULL)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_get_counters_req); + rsp_len = sizeof(struct sdmx_get_counters_rsp) + + *num_filters * sizeof(struct sdmx_filter_dbg_counters); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_GET_DBG_COUNTERS_CMD; + cmd->session_handle = session_handle; + cmd->num_filters = *num_filters; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + /* Parse response struct */ + *session_counters = rsp->session_counters; + *num_filters = rsp->num_filters; + memcpy(filter_counters, rsp->filter_counters, + *num_filters * sizeof(struct sdmx_filter_dbg_counters)); + ret = rsp->ret; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_get_dbg_counters); + +/* + * Reset debug counters + * + * @session_handle: secure demux instance + * + * Return error code + */ +int sdmx_reset_dbg_counters(int session_handle) +{ + int res, cmd_len, rsp_len; + struct sdmx_rst_counters_req *cmd; + struct sdmx_rst_counters_rsp *rsp; + enum sdmx_status ret; + + if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS)) + return SDMX_STATUS_INVALID_INPUT_PARAMS; + + cmd_len = sizeof(struct sdmx_rst_counters_req); + rsp_len = sizeof(struct sdmx_rst_counters_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_RESET_DBG_COUNTERS_CMD; + cmd->session_handle = session_handle; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + + ret = rsp->ret; +out: + mutex_unlock(&sdmx_lock[session_handle]); + + return ret; +} +EXPORT_SYMBOL(sdmx_reset_dbg_counters); + +/* + * Set debug log verbosity level + * + * @session_handle: secure demux instance + * @level: requested log level + * + * Return error code + */ +int sdmx_set_log_level(int session_handle, enum sdmx_log_level level) +{ + int res, cmd_len, rsp_len; + struct sdmx_set_log_level_req *cmd; + struct sdmx_set_log_level_rsp *rsp; + enum sdmx_status ret; + + cmd_len = sizeof(struct sdmx_set_log_level_req); + rsp_len = sizeof(struct sdmx_set_log_level_rsp); + + /* Lock shared memory */ + mutex_lock(&sdmx_lock[session_handle]); + + /* Get command and response buffers */ + ret = get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len, + (void **)&rsp, &rsp_len); + if (ret) + goto out; + + /* Populate command struct */ + cmd->cmd_id = SDMX_SET_LOG_LEVEL_CMD; + cmd->session_handle = session_handle; + cmd->level = level; + + /* Issue QSEECom command */ + res = qseecom_send_command(sdmx_qseecom_handles[session_handle], + (void *)cmd, cmd_len, (void *)rsp, rsp_len); + if (res < 0) { + mutex_unlock(&sdmx_lock[session_handle]); + return SDMX_STATUS_GENERAL_FAILURE; + } + ret = rsp->ret; +out: + /* Unlock */ + mutex_unlock(&sdmx_lock[session_handle]); + return ret; +} diff --git a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h new file mode 100644 index 000000000000..08a23a59d425 --- /dev/null +++ b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h @@ -0,0 +1,377 @@ +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MPQ_SDMX_H +#define _MPQ_SDMX_H + +#include + +/* Constant declarations */ +#define SDMX_MAX_SESSIONS (4) +#define SDMX_LOOPBACK_PID (0x2000) + +#define SDMX_MAX_PHYSICAL_CHUNKS (256) + +/* Filter-level error indicators */ +#define SDMX_FILTER_SUCCESS (0) +#define SDMX_FILTER_ERR_MD_BUF_FULL BIT(0) +#define SDMX_FILTER_ERR_D_BUF_FULL BIT(1) +#define SDMX_FILTER_ERR_D_LIN_BUFS_FULL BIT(2) +#define SDMX_FILTER_ERR_INVALID_SCRAMBLE_BITS BIT(3) +#define SDMX_FILTER_ERR_KL_IND_NOT_SET BIT(4) +#define SDMX_FILTER_ERR_CAS_DECRYPT_ERROR BIT(5) +#define SDMX_FILTER_ERR_SEC_VERIF_CRC32_FAIL BIT(6) +#define SDMX_FILTER_ERR_SEC_INTERNAL_MALLOC_FAIL BIT(7) +#define SDMX_FILTER_ERR_SEC_LEN_INVALID BIT(8) +#define SDMX_FILTER_ERR_SEC_PUSI_PTR_INVALID BIT(9) +#define SDMX_FILTER_ERR_TS_SYNC_BYTE_INVALID BIT(10) +#define SDMX_FILTER_ERR_TS_TRANSPORT_ERR BIT(11) +#define SDMX_FILTER_ERR_CONT_CNT_INVALID BIT(12) +#define SDMX_FILTER_ERR_CONT_CNT_DUPLICATE BIT(13) +#define SDMX_FILTER_ERR_INVALID_PES_HDR BIT(14) +#define SDMX_FILTER_ERR_INVALID_PES_LEN BIT(15) +#define SDMX_FILTER_ERR_INVALID_PES_ENCRYPTION BIT(16) +#define SDMX_FILTER_ERR_SECURITY_FAULT BIT(17) +#define SDMX_FILTER_ERR_IN_NS_BUFFER BIT(18) + +/* Filter-level status indicators */ +#define SDMX_FILTER_STATUS_EOS BIT(0) +#define SDMX_FILTER_STATUS_WR_PTR_CHANGED BIT(1) + +/* Filter-level flags */ +#define SDMX_FILTER_FLAG_VERIFY_SECTION_CRC BIT(0) + +#define SDMX_INVALID_SESSION_HANDLE (-1) +#define SDMX_INVALID_FILTER_HANDLE (-1) + +/* Input flags */ +#define SDMX_INPUT_FLAG_EOS BIT(0) +#define SDMX_INPUT_FLAG_DBG_ENABLE BIT(1) + + +enum sdmx_buf_mode { + SDMX_RING_BUF, + SDMX_LINEAR_GROUP_BUF, +}; + +enum sdmx_proc_mode { + SDMX_PUSH_MODE, + SDMX_PULL_MODE, +}; + +enum sdmx_inp_mode { + SDMX_PKT_ENC_MODE, + SDMX_BULK_ENC_MODE, + SDMX_CLEAR_MODE, +}; + +enum sdmx_pkt_format { + SDMX_188_BYTE_PKT = 188, + SDMX_192_BYTE_PKT = 192, + SDMX_195_BYTE_PKT = 195, +}; + +enum sdmx_log_level { + SDMX_LOG_NO_PRINT, + SDMX_LOG_MSG_ERROR, + SDMX_LOG_DEBUG, + SDMX_LOG_VERBOSE +}; + +enum sdmx_status { + SDMX_SUCCESS = 0, + SDMX_STATUS_GENERAL_FAILURE = -1, + SDMX_STATUS_MAX_OPEN_SESSIONS_REACHED = -2, + SDMX_STATUS_INVALID_SESSION_HANDLE = -3, + SDMX_STATUS_INVALID_INPUT_PARAMS = -4, + SDMX_STATUS_UNSUPPORTED_MODE = -5, + SDMX_STATUS_INVALID_PID = -6, + SDMX_STATUS_OUT_OF_MEM = -7, + SDMX_STATUS_FILTER_EXISTS = -8, + SDMX_STATUS_INVALID_FILTER_HANDLE = -9, + SDMX_STATUS_MAX_RAW_PIDS_REACHED = -10, + SDMX_STATUS_SINGLE_PID_RAW_FILTER = -11, + SDMX_STATUS_INP_BUF_INVALID_PARAMS = -12, + SDMX_STATUS_INVALID_FILTER_CFG = -13, + SDMX_STATUS_STALLED_IN_PULL_MODE = -14, + SDMX_STATUS_SECURITY_FAULT = -15, + SDMX_STATUS_NS_BUFFER_ERROR = -16, +}; + +enum sdmx_filter { + SDMX_PES_FILTER, /* Other PES */ + SDMX_SEPARATED_PES_FILTER, /* Separated PES (for decoder) */ + SDMX_SECTION_FILTER, /* Section */ + SDMX_PCR_FILTER, /* PCR */ + SDMX_RAW_FILTER, /* Recording */ +}; + +enum sdmx_raw_out_format { + SDMX_188_OUTPUT, + SDMX_192_HEAD_OUTPUT, + SDMX_192_TAIL_OUTPUT +}; + +struct sdmx_buff_descriptor { + void *virt_base; /* logical address of the actual data */ + phys_addr_t phys_base; /* physical address of the actual data */ + dma_addr_t dma_base; /* DMA address of the actual data */ + u32 size; /* size of buffer in bytes */ + int id; /* unique identifier */ + void *user; /* user-defined data */ +}; + +#pragma pack(push, sdmx, 1) + +struct sdmx_session_dbg_counters { + /* Total number of TS-packets input to SDMX. */ + u32 ts_pkt_in; + + /* Total number of TS-packets filtered out by SDMX. */ + u32 ts_pkt_out; +}; + +struct sdmx_filter_dbg_counters { + int filter_handle; + + /* Number of TS-packets filtered. */ + u32 ts_pkt_count; + + /* Number of TS-packets with adaptation field only (no payload). */ + u32 ts_pkt_no_payload; + + /* Number of TS-packets with the discontinuity indicator set. */ + u32 ts_pkt_discont; + + /* Number of duplicate TS-packets detected. */ + u32 ts_pkt_dup; + + /* Number of packets not decrypted because the key wasn't ready. */ + u32 ts_pkt_key_not_ready; +}; + +struct sdmx_pes_counters { + /* Number of TS packets with the TEI flag set */ + u32 transport_err_count; + + /* Number of TS packets with continuity counter errors */ + u32 continuity_err_count; + + /* Number of TS packets composing this PES frame */ + u32 pes_ts_count; + + /* Number of TS packets dropped due to full buffer */ + u32 drop_count; +}; + +struct sdmx_buff_descr { + /* Physical address where buffer starts */ + u64 base_addr; + + /* Size of buffer */ + u32 size; +}; + +struct sdmx_data_buff_descr { + /* Physical chunks of the buffer */ + struct sdmx_buff_descr buff_chunks[SDMX_MAX_PHYSICAL_CHUNKS]; + + /* Length of buffer */ + u32 length; +}; + +/* + * Data payload residing in the data buffers is described using this meta-data + * header. The meta data header specifies where the payload is located in the + * data buffer and how big it is. + * The meta data header optionally carries additional relevant meta data + * immediately following the meta-data header. + */ +struct sdmx_metadata_header { + /* + * Payload start offset inside data buffer. In case data is managed + * as a linear buffer group, this specifies buffer index. + */ + u32 payload_start; + + /* Payload length */ + u32 payload_length; + + /* Number of meta data bytes immediately following this header */ + u32 metadata_length; +}; + + +struct sdmx_filter_status { + /* Secure demux filter handle */ + int filter_handle; + + /* + * Number of pending bytes in filter's output data buffer. + * For linear buffer mode, this is number of buffers pending. + */ + u32 data_fill_count; + + /* + * Offset in data buffer for next data payload to be written. + * For linear buffer mode, this is a buffer index. + */ + u32 data_write_offset; + + /* Number of pending bytes in filter's output meta data buffer */ + u32 metadata_fill_count; + + /* Offset in meta data buffer for next metadata header to be written */ + u32 metadata_write_offset; + + /* Errors (bitmap) reported by secure demux for this filter */ + u32 error_indicators; + + /* General status (bitmap) reported by secure demux for this filter */ + u32 status_indicators; +}; +#pragma pack(pop, sdmx) + +#ifdef CONFIG_QSEECOM + +int sdmx_open_session(int *session_handle); + +int sdmx_close_session(int session_handle); + +int sdmx_get_version(int session_handle, int32_t *version); + +int sdmx_set_session_cfg(int session_handle, enum sdmx_proc_mode proc_mode, + enum sdmx_inp_mode inp_mode, enum sdmx_pkt_format pkt_format, + u8 odd_scramble_bits, u8 even_scramble_bits); + +int sdmx_add_filter(int session_handle, u16 pid, enum sdmx_filter filter_type, + struct sdmx_buff_descr *meta_data_buf, enum sdmx_buf_mode data_buf_mode, + u32 num_data_bufs, struct sdmx_data_buff_descr *data_bufs, + int *filter_handle, enum sdmx_raw_out_format ts_out_format, u32 flags); + +int sdmx_remove_filter(int session_handle, int filter_handle); + +int sdmx_set_kl_ind(int session_handle, u16 pid, u32 key_ladder_index); + +int sdmx_add_raw_pid(int session_handle, int filter_handle, u16 pid); + +int sdmx_remove_raw_pid(int session_handle, int filter_handle, u16 pid); + +int sdmx_process(int session_handle, u8 flags, + struct sdmx_buff_descr *input_buf_desc, + u32 *input_fill_count, u32 *input_read_offset, + u32 *error_indicators, + u32 *status_indicators, + u32 num_filters, + struct sdmx_filter_status *filter_status); + +int sdmx_get_dbg_counters(int session_handle, + struct sdmx_session_dbg_counters *session_counters, + u32 *num_filters, + struct sdmx_filter_dbg_counters *filter_counters); + +int sdmx_reset_dbg_counters(int session_handle); + +int sdmx_set_log_level(int session_handle, enum sdmx_log_level level); + +#else + +static inline int sdmx_open_session(int *session_handle) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_close_session(int session_handle) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_get_version(int session_handle, int32_t *version) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_set_session_cfg(int session_handle, + enum sdmx_proc_mode proc_mode, + enum sdmx_inp_mode inp_mode, enum sdmx_pkt_format pkt_format, + u8 odd_scramble_bits, u8 even_scramble_bits) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_add_filter(int session_handle, u16 pid, + enum sdmx_filter filter_type, + struct sdmx_buff_descr *meta_data_buf, enum sdmx_buf_mode data_buf_mode, + u32 num_data_bufs, struct sdmx_data_buff_descr *data_bufs, + int *filter_handle, enum sdmx_raw_out_format ts_out_format, u32 flags) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_remove_filter(int session_handle, int filter_handle) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_set_kl_ind(int session_handle, u16 pid, + u32 key_ladder_index) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_add_raw_pid(int session_handle, int filter_handle, + u16 pid) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_remove_raw_pid(int session_handle, int filter_handle, + u16 pid) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_process(int session_handle, u8 flags, + struct sdmx_buff_descr *input_buf_desc, + u32 *input_fill_count, u32 *input_read_offset, + u32 *error_indicators, + u32 *status_indicators, + u32 num_filters, + struct sdmx_filter_status *filter_status) +{ + *status_indicators = 0; + *error_indicators = 0; + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_get_dbg_counters(int session_handle, + struct sdmx_session_dbg_counters *session_counters, + u32 *num_filters, + struct sdmx_filter_dbg_counters *filter_counters) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_reset_dbg_counters(int session_handle) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +static inline int sdmx_set_log_level(int session_handle, + enum sdmx_log_level level) +{ + return SDMX_STATUS_GENERAL_FAILURE; +} + +#endif + +#endif /* _MPQ_SDMX_H */ diff --git a/drivers/media/platform/msm/dvb/include/mpq_adapter.h b/drivers/media/platform/msm/dvb/include/mpq_adapter.h new file mode 100644 index 000000000000..212083a91344 --- /dev/null +++ b/drivers/media/platform/msm/dvb/include/mpq_adapter.h @@ -0,0 +1,222 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MPQ_ADAPTER_H +#define _MPQ_ADAPTER_H + +#include "dvbdev.h" +#include "dvb_demux.h" +#include "mpq_stream_buffer.h" + + + +/** IDs of interfaces holding stream-buffers */ +enum mpq_adapter_stream_if { + /** Interface holding stream-buffer for video0 stream */ + MPQ_ADAPTER_VIDEO0_STREAM_IF = 0, + + /** Interface holding stream-buffer for video1 stream */ + MPQ_ADAPTER_VIDEO1_STREAM_IF = 1, + + /** Interface holding stream-buffer for video2 stream */ + MPQ_ADAPTER_VIDEO2_STREAM_IF = 2, + + /** Interface holding stream-buffer for video3 stream */ + MPQ_ADAPTER_VIDEO3_STREAM_IF = 3, + + /** Interface holding stream-buffer for audio0 stream */ + MPQ_ADAPTER_AUDIO0_STREAM_IF = 4, + + /** Interface holding stream-buffer for audio1 stream */ + MPQ_ADAPTER_AUDIO1_STREAM_IF = 5, + + /** Interface holding stream-buffer for audio2 stream */ + MPQ_ADAPTER_AUDIO2_STREAM_IF = 6, + + /** Interface holding stream-buffer for audio3 stream */ + MPQ_ADAPTER_AUDIO3_STREAM_IF = 7, + + /** Maximum number of interfaces holding stream-buffers */ + MPQ_ADAPTER_MAX_NUM_OF_INTERFACES, +}; + +enum dmx_packet_type { + DMX_PES_PACKET, + DMX_FRAMING_INFO_PACKET, + DMX_EOS_PACKET, + DMX_MARKER_PACKET +}; + +struct dmx_pts_dts_info { + /** Indication whether PTS exist */ + int pts_exist; + + /** Indication whether DTS exist */ + int dts_exist; + + /** PTS value associated with the PES data if any */ + u64 pts; + + /** DTS value associated with the PES data if any */ + u64 dts; +}; + +struct dmx_framing_packet_info { + /** framing pattern type, one of DMX_IDX_* definitions */ + u64 pattern_type; + + /** PTS/DTS information */ + struct dmx_pts_dts_info pts_dts_info; + + /** STC value attached to first TS packet holding the pattern */ + u64 stc; + + /* + * Number of TS packets with Transport Error Indicator (TEI) + * found while constructing the frame. + */ + __u32 transport_error_indicator_counter; + + /* Number of continuity errors found while constructing the frame */ + __u32 continuity_error_counter; + + /* + * Number of dropped bytes due to insufficient buffer space, + * since last reported frame. + */ + __u32 ts_dropped_bytes; + + /* Total number of TS packets holding the frame */ + __u32 ts_packets_num; +}; + +struct dmx_pes_packet_info { + /** PTS/DTS information */ + struct dmx_pts_dts_info pts_dts_info; + + /** STC value attached to first TS packet holding the PES */ + u64 stc; +}; + +struct dmx_marker_info { + /* marker id */ + u64 id; +}; + +/** The meta-data used for video interface */ +struct mpq_adapter_video_meta_data { + /** meta-data packet type */ + enum dmx_packet_type packet_type; + + /** packet-type specific information */ + union { + struct dmx_framing_packet_info framing; + struct dmx_pes_packet_info pes; + struct dmx_marker_info marker; + } info; +} __packed; + +/** The meta-data used for audio interface */ +struct mpq_adapter_audio_meta_data { + /** meta-data packet type */ + enum dmx_packet_type packet_type; + + /** packet-type specific information */ + union { + struct dmx_pes_packet_info pes; + struct dmx_marker_info marker; + } info; +} __packed; + +/** Callback function to notify on registrations of specific interfaces */ +typedef void (*mpq_adapter_stream_if_callback)( + enum mpq_adapter_stream_if interface_id, + void *user_param); + + +/** + * mpq_adapter_get - Returns pointer to Qualcomm Technologies Inc. DVB adapter + * + * Return dvb adapter or NULL if not exist. + */ +struct dvb_adapter *mpq_adapter_get(void); + + +/** + * mpq_adapter_register_stream_if - Register a stream interface. + * + * @interface_id: The interface id + * @stream_buffer: The buffer used for the interface + * + * Return error status + * + * Stream interface used to connect between two units in tunneling + * mode using mpq_streambuffer implementation. + * The producer of the interface should register the new interface, + * consumer may get the interface using mpq_adapter_get_stream_if. + * + * Note that the function holds a pointer to this interface, + * stream_buffer pointer assumed to be valid as long as interface + * is active. + */ +int mpq_adapter_register_stream_if( + enum mpq_adapter_stream_if interface_id, + struct mpq_streambuffer *stream_buffer); + + +/** + * mpq_adapter_unregister_stream_if - Un-register a stream interface. + * + * @interface_id: The interface id + * + * Return error status + */ +int mpq_adapter_unregister_stream_if( + enum mpq_adapter_stream_if interface_id); + + +/** + * mpq_adapter_get_stream_if - Get buffer used for a stream interface. + * + * @interface_id: The interface id + * @stream_buffer: The returned stream buffer + * + * Return error status + */ +int mpq_adapter_get_stream_if( + enum mpq_adapter_stream_if interface_id, + struct mpq_streambuffer **stream_buffer); + + +/** + * mpq_adapter_notify_stream_if - Register notification + * to be triggered when a stream interface is registered. + * + * @interface_id: The interface id + * @callback: The callback to be triggered when the interface is registered + * @user_param: A parameter that is passed back to the callback function + * when triggered. + * + * Return error status + * + * Producer may use this to register notification when desired + * interface registered in the system and query its information + * afterwards using mpq_adapter_get_stream_if. + * To remove the callback, this function should be called with NULL + * value in callback parameter. + */ +int mpq_adapter_notify_stream_if( + enum mpq_adapter_stream_if interface_id, + mpq_adapter_stream_if_callback callback, + void *user_param); + +#endif /* _MPQ_ADAPTER_H */ diff --git a/drivers/media/platform/msm/dvb/include/mpq_dvb_debug.h b/drivers/media/platform/msm/dvb/include/mpq_dvb_debug.h new file mode 100644 index 000000000000..47d2e6ea8ad1 --- /dev/null +++ b/drivers/media/platform/msm/dvb/include/mpq_dvb_debug.h @@ -0,0 +1,41 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MPQ_DVB_DEBUG_H +#define _MPQ_DVB_DEBUG_H + +/* Enable this line if you want to output debug printouts */ +#define MPG_DVB_DEBUG_ENABLE + +#undef MPQ_DVB_DBG_PRINT /* undef it, just in case */ + +#ifdef MPG_DVB_DEBUG_ENABLE +#define MPQ_DVB_ERR_PRINT(fmt, args...) pr_err(fmt, ## args) +#define MPQ_DVB_WARN_PRINT(fmt, args...) pr_warn(fmt, ## args) +#define MPQ_DVB_NOTICE_PRINT(fmt, args...) pr_notice(fmt, ## args) +#define MPQ_DVB_DBG_PRINT(fmt, args...) pr_debug(fmt, ## args) +#else /* MPG_DVB_DEBUG_ENABLE */ +#define MPQ_DVB_ERR_PRINT(fmt, args...) +#define MPQ_DVB_WARN_PRINT(fmt, args...) +#define MPQ_DVB_NOTICE_PRINT(fmt, args...) +#define MPQ_DVB_DBG_PRINT(fmt, args...) +#endif /* MPG_DVB_DEBUG_ENABLE */ + + +/* + * The following can be used to disable specific printout + * by adding a letter to the end of MPQ_DVB_DBG_PRINT + */ +#undef MPQ_DVB_DBG_PRINTT +#define MPQ_DVB_DBG_PRINTT(fmt, args...) + +#endif /* _MPQ_DVB_DEBUG_H */ diff --git a/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h b/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h new file mode 100644 index 000000000000..13d4eb8d975f --- /dev/null +++ b/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h @@ -0,0 +1,494 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MPQ_STREAM_BUFFER_H +#define _MPQ_STREAM_BUFFER_H + +#include "dvb_ringbuffer.h" + +/** + * DOC: MPQ Stream Buffer + * + * A stream buffer implementation is used to transfer data between two units + * such as demux and decoders. The implementation relies on dvb_ringbuffer + * implementation. Refer to dvb_ringbuffer.h for details. + * + * The implementation uses two dvb_ringbuffers, one to pass the + * raw-data (PES payload for example) and the other to pass + * meta-data (information from PES header for example). + * + * The meta-data uses dvb_ringbuffer packet interface. Each meta-data + * packet points to the data buffer, and includes the offset to the data in the + * buffer, the size of raw-data described by the meta-data packet, and also the + * size of user's own parameters if any required. + * + * Data can be managed in two ways: ring-buffer & linear buffers, as specified + * in initialization when calling the mpq_streambuffer_init function. + * For managing data as a ring buffer exactly 1 data buffer descriptor must be + * specified in initialization. For this mode, dvb_ringbuffer is used "as-is". + * For managing data in several linear buffers, an array of buffer descriptors + * must be passed. + * For both modes, data descriptor(s) must be remain valid throughout the life + * span of the mpq_streambuffer object. + * Apart from initialization API remains the same for both modes. + * + * Contrary to dvb_ringbuffer implementation, this API makes sure there's + * enough data to read/write when making read/write operations. + * Users interested to flush/reset specific buffer, check for bytes + * ready or space available for write should use the respective services + * in dvb_ringbuffer (dvb_ringbuffer_avail, dvb_ringbuffer_free, + * dvb_ringbuffer_reset, dvb_ringbuffer_flush, + * dvb_ringbuffer_flush_spinlock_wakeup). + * + * Concurrency protection is handled in the same manner as in + * dvb_ringbuffer implementation. + * + * Typical call flow from producer: + * + * - Start writing the raw-data of new packet, the following call is + * repeated until end of data of the specific packet + * + * mpq_streambuffer_data_write(...) + * + * - Now write a new packet describing the new available raw-data + * mpq_streambuffer_pkt_write(...) + * + * For linear buffer mode, writing a new packet with data size > 0, causes the + * current buffer to be marked as pending for reading, and triggers moving to + * the next available buffer, that shall now be the current write buffer. + * + * Typical call flow from consumer: + * + * - Poll for next available packet: + * mpq_streambuffer_pkt_next(&streambuff,-1,&len) + * + * In different approach, consumer can wait on event for new data and then + * call mpq_streambuffer_pkt_next, waiting for data can be done as follows: + * + * wait_event_interruptible( + * streambuff->packet_data->queue, + * !dvb_ringbuffer_empty(&streambuff->packet_data) || + * (streambuff->packet_data.error != 0); + * + * - Get the new packet information: + * mpq_streambuffer_pkt_read(..) + * + * - Read the raw-data of the new packet. Here you can use two methods: + * + * 1. Read the data to a user supplied buffer: + * mpq_streambuffer_data_read() + * + * In this case memory copy is done, read pointer is updated in the raw + * data buffer, the amount of raw-data is provided part of the + * packet's information. User should then call mpq_streambuffer_pkt_dispose + * with dispose_data set to 0 as the raw-data was already disposed. + * Note that secure buffer cannot be accessed directly and an error will + * occur. + * + * 2. Access the data directly using the raw-data address. The address + * of the raw data is provided part of the packet's information. User + * then should call mpq_streambuffer_pkt_dispose with dispose_data set + * to 1 to dispose the packet along with it's raw-data. + * + * - Disposal of packets: + * mpq_streambuffer_pkt_dispose(...) + * + * For linear buffer mode, disposing of a packet with data size > 0, + * regardless of the 'dispose_data' parameter, causes the current buffer's + * data to be disposed and marked as free for writing, and triggers moving to + * the next available buffer, that shall now be the current read buffer. + */ + +struct mpq_streambuffer; +struct mpq_streambuffer_packet_header; + +typedef void (*mpq_streambuffer_dispose_cb) ( + struct mpq_streambuffer *sbuff, + u32 offset, + size_t len, + void *user_data); + +enum mpq_streambuffer_mode { + MPQ_STREAMBUFFER_BUFFER_MODE_RING, + MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR +}; + +/** + * struct mpq_streambuffer - mpq stream buffer representation + * + * @raw_data: The buffer used to hold raw-data, or linear buffer descriptors + * @packet_data: The buffer user to hold the meta-data + * @buffers: array of buffer descriptor(s) holding buffer initial & dynamic + * buffer information + * @mode: mpq_streambuffer buffer management work mode - Ring-buffer or Linear + * buffers + * @buffers_num: number of data buffers to manage + * @pending_buffers_count: for linear buffer management, counts the number of + * buffer that has been + */ +struct mpq_streambuffer { + struct dvb_ringbuffer raw_data; + struct dvb_ringbuffer packet_data; + struct mpq_streambuffer_buffer_desc *buffers; + enum mpq_streambuffer_mode mode; + u32 buffers_num; + u32 pending_buffers_count; + mpq_streambuffer_dispose_cb cb; + void *cb_user_data; +}; + +/** + * mpq_streambuffer_linear_desc + * @handle: ION handle's file descriptor of buffer + * @base: kernel mapped address to start of buffer. + * Can be NULL for secured buffers + * @size: size of buffer + * @read_ptr: initial read pointer value (should normally be 0) + * @write_ptr: initial write pointer value (should normally be 0) + */ +struct mpq_streambuffer_buffer_desc { + int handle; + void *base; + u32 size; + u32 read_ptr; + u32 write_ptr; +}; + +/** + * struct mpq_streambuffer_packet_header - packet header saved in packet buffer + * @user_data_len: length of private user (meta) data + * @raw_data_handle: ION handle's file descriptor of raw-data buffer + * @raw_data_offset: offset of raw-data from start of buffer (0 for linear) + * @raw_data_len: size of raw-data in the raw-data buffer (can be 0) + * + * The packet structure that is saved in each packet-buffer: + * user_data_len + * raw_data_handle + * raw_data_offset + * raw_data_len + * private user-data bytes + */ +struct mpq_streambuffer_packet_header { + u32 user_data_len; + int raw_data_handle; + u32 raw_data_offset; + u32 raw_data_len; +} __packed; + +/** + * mpq_streambuffer_init - Initialize a new stream buffer + * + * @sbuff: The buffer to initialize + * @data_buffers: array of data buffer descriptor(s). + * Data descriptor(s) must be remain valid throughout the life + * span of the mpq_streambuffer object + * @data_buff_num: number of data buffer in array + * @packet_buff: The buffer holding meta-data + * @packet_buff_size: Size of meta-data buffer + * + * Return Error status, -EINVAL if any of the arguments are invalid + * + * Note: + * for data_buff_num > 1, mpq_streambuffer object manages these buffers as a + * separated set of linear buffers. A linear buffer cannot wrap-around and one + * can only write as many data bytes as the buffer's size. Data will not be + * written to the next free buffer. + */ +int mpq_streambuffer_init( + struct mpq_streambuffer *sbuff, + enum mpq_streambuffer_mode mode, + struct mpq_streambuffer_buffer_desc *data_buffers, + u32 data_buff_num, + void *packet_buff, + size_t packet_buff_size); + +/** + * mpq_streambuffer_terminate - Terminate stream buffer + * + * @sbuff: The buffer to terminate + * + * The function sets the the buffers error flags to ENODEV + * and wakeup any waiting threads on the buffer queues. + * Threads waiting on the buffer queues should check if + * error was set. + */ +void mpq_streambuffer_terminate(struct mpq_streambuffer *sbuff); + +/** + * mpq_streambuffer_packet_next - Returns index of next available packet. + * + * @sbuff: The stream buffer + * @idx: Previous packet index or -1 to return index of the the first + * available packet. + * @pktlen: The length of the ready packet + * + * Return index to the packet-buffer, -1 if buffer is empty + * + * After getting the index, the user of this function can either + * access the packet buffer directly using the returned index + * or ask to read the data back from the buffer using mpq_ringbuffer_pkt_read + */ +ssize_t mpq_streambuffer_pkt_next( + struct mpq_streambuffer *sbuff, + ssize_t idx, size_t *pktlen); + +/** + * mpq_streambuffer_pkt_read - Reads out the packet from the provided index. + * + * @sbuff: The stream buffer + * @idx: The index of the packet to be read + * @packet: The read packet's header + * @user_data: The read private user data + * + * Return The actual number of bytes read, -EINVAL if the packet is + * already disposed or the packet-data is invalid. + * + * The packet is not disposed after this function is called, to dispose it + * along with the raw-data it points to use mpq_streambuffer_pkt_dispose. + * If there are no private user-data, the user-data pointer can be NULL. + * The caller of this function must make sure that the private user-data + * buffer has enough space for the private user-data length + */ +ssize_t mpq_streambuffer_pkt_read( + struct mpq_streambuffer *sbuff, + size_t idx, + struct mpq_streambuffer_packet_header *packet, + u8 *user_data); + +/** + * mpq_streambuffer_pkt_dispose - Disposes a packet from the packet buffer + * + * @sbuff: The stream buffer + * @idx: The index of the packet to be disposed + * @dispose_data: Indicates whether to update the read pointer inside the + * raw-data buffer for the respective data pointed by the packet. + * + * Return error status, -EINVAL if the packet-data is invalid + * + * The function updates the read pointer inside the raw-data buffer + * for the respective data pointed by the packet if dispose_data is set. + */ +int mpq_streambuffer_pkt_dispose( + struct mpq_streambuffer *sbuff, + size_t idx, + int dispose_data); + +/** + * mpq_streambuffer_pkt_write - Write a new packet to the packet buffer. + * + * @sbuff: The stream buffer + * @packet: The packet header to write + * @user_data: The private user-data to be written + * + * Return error status, -ENOSPC if there's no space to write the packet + */ +int mpq_streambuffer_pkt_write( + struct mpq_streambuffer *sbuff, + struct mpq_streambuffer_packet_header *packet, + u8 *user_data); + +/** + * mpq_streambuffer_data_write - Write data to raw-data buffer + * + * @sbuff: The stream buffer + * @buf: The buffer holding the data to be written + * @len: The length of the data buffer + * + * Return The actual number of bytes written or -ENOSPC if + * no space to write the data + */ +ssize_t mpq_streambuffer_data_write( + struct mpq_streambuffer *sbuff, + const u8 *buf, size_t len); + +/** + * mpq_streambuffer_data_write_deposit - Advances the raw-buffer write pointer. + * Assumes the raw-data was written by the user directly + * + * @sbuff: The stream buffer + * @len: The length of the raw-data that was already written + * + * Return error status + */ +int mpq_streambuffer_data_write_deposit( + struct mpq_streambuffer *sbuff, + size_t len); + +/** + * mpq_streambuffer_data_read - Reads out raw-data to the provided buffer. + * + * @sbuff: The stream buffer + * @buf: The buffer to read the raw-data data to + * @len: The length of the buffer that will hold the raw-data + * + * Return The actual number of bytes read or error code + * + * This function copies the data from the ring-buffer to the + * provided buf parameter. The user can save the extra copy by accessing + * the data pointer directly and reading from it, then update the + * read pointer by the amount of data that was read using + * mpq_streambuffer_data_read_dispose + */ +ssize_t mpq_streambuffer_data_read( + struct mpq_streambuffer *sbuff, + u8 *buf, size_t len); + +/** + * mpq_streambuffer_data_read_user + * + * Same as mpq_streambuffer_data_read except data can be copied to user-space + * buffer. + */ +ssize_t mpq_streambuffer_data_read_user( + struct mpq_streambuffer *sbuff, + u8 __user *buf, size_t len); + +/** + * mpq_streambuffer_data_read_dispose - Advances the raw-buffer read pointer. + * Assumes the raw-data was read by the user directly. + * + * @sbuff: The stream buffer + * @len: The length of the raw-data to be disposed + * + * Return error status, -EINVAL if buffer there's no enough data to + * be disposed + * + * The user can instead dispose a packet along with the data in the + * raw-data buffer using mpq_streambuffer_pkt_dispose. + */ +int mpq_streambuffer_data_read_dispose( + struct mpq_streambuffer *sbuff, + size_t len); +/** + * mpq_streambuffer_get_buffer_handle - Returns the current linear buffer + * ION handle. + * @sbuff: The stream buffer + * @read_buffer: specifies if a read buffer handle is requested (when set), + * or a write buffer handle is requested. + * For linear buffer mode read & write buffers may be different + * buffers. For ring buffer mode, the same (single) buffer handle + * is returned. + * buffer handle + * @handle: returned handle + * + * Return error status + * -EINVAL is arguments are invalid. + * -EPERM if stream buffer specified was not initialized with linear support. + */ +int mpq_streambuffer_get_buffer_handle( + struct mpq_streambuffer *sbuff, + int read_buffer, + int *handle); + +/** + * mpq_streambuffer_data_free - Returns number of free bytes in data buffer. + * @sbuff: The stream buffer object + * + * Note: for linear buffer management this return number of free bytes in the + * current write buffer only. + */ +ssize_t mpq_streambuffer_data_free( + struct mpq_streambuffer *sbuff); + +/** + * mpq_streambuffer_data_avail - Returns number of bytes in data buffer that + * can be read. + * @sbuff: The stream buffer object + * + * Note: for linear buffer management this return number of data bytes in the + * current read buffer only. + */ +ssize_t mpq_streambuffer_data_avail( + struct mpq_streambuffer *sbuff); + +/** + * mpq_streambuffer_register_pkt_dispose - Registers a callback to notify on + * packet disposal events. + * can be read. + * @sbuff: The stream buffer object + * @cb_func: user callback function + * @user_data: user data to be passed to callback function. + * + * Returns error status + * -EINVAL if arguments are invalid + */ +int mpq_streambuffer_register_data_dispose( + struct mpq_streambuffer *sbuff, + mpq_streambuffer_dispose_cb cb_func, + void *user_data); + +/** + * mpq_streambuffer_data_rw_offset - returns read/write offsets of current data + * buffer. + * @sbuff: The stream buffer object + * @read_offset: returned read offset + * @write_offset: returned write offset + * + * Note: read offset or write offset may be NULL if not required. + * Returns error status + * -EINVAL if arguments are invalid + */ +int mpq_streambuffer_get_data_rw_offset( + struct mpq_streambuffer *sbuff, + u32 *read_offset, + u32 *write_offset); + +/** + * mpq_streambuffer_metadata_free - returns number of free bytes in the meta + * data buffer, or error status. + * @sbuff: the stream buffer object + */ +ssize_t mpq_streambuffer_metadata_free(struct mpq_streambuffer *sbuff); + +/** + * mpq_streambuffer_flush - flush both pending packets and data in buffer + * + * @sbuff: the stream buffer object + * + * Returns error status + */ +int mpq_streambuffer_flush(struct mpq_streambuffer *sbuff); + +/* + * ------------------------------------------------------ + * Consumer or AV Decoder Stream Interface to Ring Buffer + * ------------------------------------------------------ + * Producer is Demux Driver + * ------------------------ + * + * call from Audio/Video Decoder Driver to find Audio/Video + * streambuffer AV handles, "DMX_PES_AUDIO0 through 3" or + * DMX_PES_VIDEO0 through 3" interfaces corresponding to 4 programs. + */ + +/* call from Audio/Video Decoder Driver via POLLING to consume + * Headers and Compressed data from ring buffer using streambuffer handle. + * hdrdata[] and cdata[] buffers have to be malloc'd by consumer + * + * -------------------------- + * Consumer Calling Sequence + * -------------------------- + * Find the streambuffer corresponding to a DMX TS PES stream instance. + * 1. consumer_audio_streambuffer() or consumer_video_streambuffer() + * Process the packet headers if required. + * 2. mpq_read_new_packet_hdr_data() + * Process the compressed data by forwarding to AV decoder. + * 3. mpq_read_new_packet_compressed_data() + * Dispose the packet. + * 4. mpq_dispose_new_packet_read() + * + * The Audio/Video drivers (or consumers) require the stream_buffer information + * for consuming packet headers and compressed AV data from the + * ring buffer filled by demux driver which is the producer + */ + +#endif /* _MPQ_STREAM_BUFFER_H */ diff --git a/include/linux/qcom_tspp.h b/include/linux/qcom_tspp.h new file mode 100644 index 000000000000..a598c8fb3c3d --- /dev/null +++ b/include/linux/qcom_tspp.h @@ -0,0 +1,124 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MSM_TSPP_H_ +#define _MSM_TSPP_H_ + +struct tspp_data_descriptor { + void *virt_base; /* logical address of the actual data */ + phys_addr_t phys_base; /* physical address of the actual data */ + dma_addr_t dma_base; /* DMA address of the actual data */ + u32 size; /* size of buffer in bytes */ + int id; /* unique identifier */ + void *user; /* user-defined data */ +}; + +enum tspp_key_parity { + TSPP_KEY_PARITY_EVEN, + TSPP_KEY_PARITY_ODD +}; + +struct tspp_key { + enum tspp_key_parity parity; + int lsb; + int msb; +}; + +enum tspp_source { + TSPP_SOURCE_TSIF0, + TSPP_SOURCE_TSIF1, + TSPP_SOURCE_MEM, + TSPP_SOURCE_NONE = -1 +}; + +enum tspp_mode { + TSPP_MODE_DISABLED, + TSPP_MODE_PES, + TSPP_MODE_RAW, + TSPP_MODE_RAW_NO_SUFFIX +}; + +enum tspp_tsif_mode { + TSPP_TSIF_MODE_LOOPBACK, /* loopback mode */ + TSPP_TSIF_MODE_1, /* without sync */ + TSPP_TSIF_MODE_2 /* with sync signal */ +}; + +struct tspp_filter { + int pid; + int mask; + enum tspp_mode mode; + unsigned int priority; /* 0 - 15 */ + int decrypt; + enum tspp_source source; +}; + +struct tspp_select_source { + enum tspp_source source; + enum tspp_tsif_mode mode; + int clk_inverse; + int data_inverse; + int sync_inverse; + int enable_inverse; +}; + +enum tsif_tts_source { + TSIF_TTS_TCR = 0, /* Time stamps from TCR counter */ + TSIF_TTS_LPASS_TIMER /* Time stamps from AV/Qtimer Timer */ +}; + +struct tspp_ion_dma_buf_info { + struct dma_buf *dbuf; + struct dma_buf_attachment *attach; + struct sg_table *table; + bool smmu_map; + void *va; +}; + +typedef void (tspp_notifier)(int channel_id, void *user); +typedef void* (tspp_allocator)(int channel_id, u32 size, + phys_addr_t *phys_base, dma_addr_t *dma_base, void *user); +typedef void (tspp_memfree)(int channel_id, u32 size, + void *virt_base, phys_addr_t phys_base, void *user); + +/* Kernel API functions */ +int tspp_open_stream(u32 dev, u32 channel_id, + struct tspp_select_source *source); +int tspp_close_stream(u32 dev, u32 channel_id); +int tspp_open_channel(u32 dev, u32 channel_id); +int tspp_close_channel(u32 dev, u32 channel_id); +int tspp_get_ref_clk_counter(u32 dev, + enum tspp_source source, u32 *tcr_counter); +int tspp_add_filter(u32 dev, u32 channel_id, struct tspp_filter *filter); +int tspp_remove_filter(u32 dev, u32 channel_id, struct tspp_filter *filter); +int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key); +int tspp_register_notification(u32 dev, u32 channel_id, tspp_notifier *notify, + void *data, u32 timer_ms); +int tspp_unregister_notification(u32 dev, u32 channel_id); +const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id); +int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id); +int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count, + u32 size, u32 int_freq, tspp_allocator *alloc, + tspp_memfree *memfree, void *user); + +int tspp_get_tts_source(u32 dev, int *tts_source); +int tspp_get_lpass_time_counter(u32 dev, enum tspp_source source, + u64 *lpass_time_counter); + +int tspp_attach_ion_dma_buff(u32 dev, + struct tspp_ion_dma_buf_info *ion_dma_buf); + +int tspp_detach_ion_dma_buff(u32 dev, + struct tspp_ion_dma_buf_info *ion_dma_buf); +void *tspp_allocate_dma_buffer(u32 dev, int size, phys_addr_t *paddr); +int tspp_free_dma_buffer(u32 dev, int size, void *vaddr, dma_addr_t paddr); +#endif /* _MSM_TSPP_H_ */ -- GitLab From eb0c342cc23d36be4938b5fd623cdda5326c4a1e Mon Sep 17 00:00:00 2001 From: Monika Singh Date: Wed, 18 Jul 2018 12:01:59 +0530 Subject: [PATCH 0701/1001] RM: dts: msm: add TSPP node for kernel 4.14 Add TSPP device tree node to support TSPP on kernel 4.14, together with the required pinctrl definitions. Change-Id: I0ae67eae0e3d7f6228b431028bd291599c86ac36 Signed-off-by: Monika Singh --- arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi | 60 ++++++++++++++++++++ arch/arm64/boot/dts/qcom/sm8150.dtsi | 59 +++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi index a0fa356d831a..aabfddf66ac0 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi @@ -3927,6 +3927,66 @@ }; }; + tsif0_signals_active: tsif0_signals_active { + tsif1_clk { + pins = "gpio88"; /* TSIF0 CLK */ + function = "tsif1_clk"; + }; + tsif1_en { + pins = "gpio89"; /* TSIF0 Enable */ + function = "tsif1_en"; + }; + tsif1_data { + pins = "gpio90"; /* TSIF0 DATA */ + function = "tsif1_data"; + }; + signals_cfg { + pins = "gpio88", "gpio89", "gpio90"; + drive_strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + + /* sync signal is only used if configured to mode-2 */ + tsif0_sync_active: tsif0_sync_active { + tsif1_sync { + pins = "gpio91"; /* TSIF0 SYNC */ + function = "tsif1_sync"; + drive_strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + + tsif1_signals_active: tsif1_signals_active { + tsif2_clk { + pins = "gpio92"; /* TSIF1 CLK */ + function = "tsif2_clk"; + }; + tsif2_en { + pins = "gpio93"; /* TSIF1 Enable */ + function = "tsif2_en"; + }; + tsif2_data { + pins = "gpio94"; /* TSIF1 DATA */ + function = "tsif2_data"; + }; + signals_cfg { + pins = "gpio92", "gpio93", "gpio94"; + drive_strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + + /* sync signal is only used if configured to mode-2 */ + tsif1_sync_active: tsif1_sync_active { + tsif2_sync { + pins = "gpio95"; /* TSIF1 SYNC */ + function = "tsif2_sync"; + drive_strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + trigout_a: trigout_a { mux { pins = "gpio49"; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index a81e64558c44..6106d1f2a1e4 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -3628,6 +3628,65 @@ qcom,smmu-coherent; status = "disabled"; }; + + tspp: msm_tspp@0x8880000 { + compatible = "qcom,msm_tspp"; + reg = <0x088a7000 0x200>, /* MSM_TSIF0_PHYS */ + <0x088a8000 0x200>, /* MSM_TSIF1_PHYS */ + <0x088a9000 0x1000>, /* MSM_TSPP_PHYS */ + <0x08884000 0x23000>; /* MSM_TSPP_BAM_PHYS */ + reg-names = "MSM_TSIF0_PHYS", + "MSM_TSIF1_PHYS", + "MSM_TSPP_PHYS", + "MSM_TSPP_BAM_PHYS"; + interrupts = <0 121 0>, /* TSIF_TSPP_IRQ */ + <0 119 0>, /* TSIF0_IRQ */ + <0 120 0>, /* TSIF1_IRQ */ + <0 122 0>; /* TSIF_BAM_IRQ */ + interrupt-names = "TSIF_TSPP_IRQ", + "TSIF0_IRQ", + "TSIF1_IRQ", + "TSIF_BAM_IRQ"; + + clock-names = "iface_clk", "ref_clk"; + clocks = <&clock_gcc GCC_TSIF_AHB_CLK>, + <&clock_gcc GCC_TSIF_REF_CLK>; + + qcom,msm-bus,name = "tsif"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <82 512 0 0>, /* No vote */ + <82 512 12288 24576>; + /* Max. bandwidth, 2xTSIF, each max of 96Mbps */ + + pinctrl-names = "disabled", + "tsif0-mode1", "tsif0-mode2", + "tsif1-mode1", "tsif1-mode2", + "dual-tsif-mode1", "dual-tsif-mode2"; + + pinctrl-0 = <>; /* disabled */ + pinctrl-1 = <&tsif0_signals_active>; /* tsif0-mode1 */ + pinctrl-2 = <&tsif0_signals_active + &tsif0_sync_active>; /* tsif0-mode2 */ + pinctrl-3 = <&tsif1_signals_active>; /* tsif1-mode1 */ + pinctrl-4 = <&tsif1_signals_active + &tsif1_sync_active>; /* tsif1-mode2 */ + pinctrl-5 = <&tsif0_signals_active + &tsif1_signals_active>; /* dual-tsif-mode1 */ + pinctrl-6 = <&tsif0_signals_active + &tsif0_sync_active + &tsif1_signals_active + &tsif1_sync_active>; /* dual-tsif-mode2 */ + + memory-region = <&qseecom_mem>; + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x620 0x00>; + }; + + demux { + compatible = "qcom,demux"; + }; }; &emac_gdsc { -- GitLab From 76ba917341c60b7f780349164b4099936b4ce195 Mon Sep 17 00:00:00 2001 From: Monika Singh Date: Wed, 27 Jun 2018 17:21:03 +0530 Subject: [PATCH 0702/1001] Migrate mpq demux driver from kernel 4.9 to 4.14 This change migrates all the relevant files and updates made to the dvb/demux framework, required for mpq demux driver. The snapshot is taken as of msm-4.9, 'commit ba29a3e82c501 ("Migrate mpq demux driver from kernel 4.4 to 4.9")' In addition, introduce a few code changes to fix warnings, typos and other style issues. Change-Id: I1621409bfbdbbec676a6ba29c0583c80574a4945 Signed-off-by: Monika Singh --- drivers/media/dvb-core/demux.h | 214 +- drivers/media/dvb-core/dmxdev.c | 4101 +++++++++++++++++++++-- drivers/media/dvb-core/dmxdev.h | 137 +- drivers/media/dvb-core/dvb_demux.c | 2821 ++++++++++++++-- drivers/media/dvb-core/dvb_demux.h | 274 ++ drivers/media/dvb-core/dvb_net.c | 5 +- drivers/media/dvb-core/dvb_ringbuffer.c | 69 +- drivers/media/dvb-core/dvb_ringbuffer.h | 35 +- drivers/media/tuners/xc5000.c | 4 +- include/uapi/linux/dvb/dmx.h | 770 ++++- 10 files changed, 7817 insertions(+), 613 deletions(-) diff --git a/drivers/media/dvb-core/demux.h b/drivers/media/dvb-core/demux.h index c4df6cee48e6..e14a29c33518 100644 --- a/drivers/media/dvb-core/demux.h +++ b/drivers/media/dvb-core/demux.h @@ -36,6 +36,8 @@ * Common definitions */ +#define DMX_EVENT_QUEUE_SIZE 500 /* number of events */ + /* * DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter. */ @@ -56,6 +58,108 @@ #define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188) #endif +/* + * enum dmx_success: Success codes for the Demux Callback API. + */ +enum dmx_success { + DMX_OK = 0, /* Received Ok */ + DMX_OK_PES_END, /* Received OK, data reached end of PES packet */ + DMX_OK_PCR, /* Received OK, data with new PCR/STC pair */ + DMX_OK_EOS, /* Received OK, reached End-of-Stream (EOS) */ + DMX_OK_MARKER, /* Received OK, reached a data Marker */ + DMX_LENGTH_ERROR, /* Incorrect length */ + DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */ + DMX_CRC_ERROR, /* Incorrect CRC */ + DMX_FRAME_ERROR, /* Frame alignment error */ + DMX_FIFO_ERROR, /* Receiver FIFO overrun */ + DMX_MISSED_ERROR, /* Receiver missed packet */ + DMX_OK_DECODER_BUF, /* Received OK, new ES data in decoder buffer */ + DMX_OK_IDX, /* Received OK, new index event */ + DMX_OK_SCRAMBLING_STATUS, /* Received OK, new scrambling status */ +}; + +struct ion_dma_buff_info { + struct dma_buf *dmabuf; + struct sg_table *sgt; + struct dma_buf_attachment *attach; + phys_addr_t pa; + void *va; + size_t len; +}; + +/* + * struct dmx_data_ready: Parameters for event notification callback. + * Event notification notifies demux device that data is written + * and available in the device's output buffer or provides + * notification on errors and other events. In the latter case + * data_length is zero. + */ +struct dmx_data_ready { + enum dmx_success status; + + /* + * data_length may be 0 in case of DMX_OK_PES_END or DMX_OK_EOS + * and in non-DMX_OK_XXX events. In DMX_OK_PES_END, + * data_length is for data coming after the end of PES. + */ + int data_length; + + union { + struct { + int start_gap; + int actual_length; + int disc_indicator_set; + int pes_length_mismatch; + u64 stc; + u32 tei_counter; + u32 cont_err_counter; + u32 ts_packets_num; + } pes_end; + + struct { + u64 pcr; + u64 stc; + int disc_indicator_set; + } pcr; + + struct { + int handle; + int cookie; + u32 offset; + u32 len; + int pts_exists; + u64 pts; + int dts_exists; + u64 dts; + u32 tei_counter; + u32 cont_err_counter; + u32 ts_packets_num; + u32 ts_dropped_bytes; + u64 stc; + } buf; + + struct { + u64 id; + } marker; + + struct dmx_index_event_info idx_event; + struct dmx_scrambling_status_event_info scrambling_bits; + }; +}; + +/* + * struct data_buffer: Parameters of buffer allocated by + * demux device for input/output. Can be used to directly map the + * demux-device buffer to HW output if HW supports it. + */ +struct data_buffer { + /* dvb_ringbuffer managed by demux-device */ + const struct dvb_ringbuffer *ringbuff; + + /* ion_dma_buff_info managed by demux-device */ + struct ion_dma_buff_info buff_dma_info; + +}; /* * TS packet reception */ @@ -91,17 +195,54 @@ enum ts_filter_type { * Using this API, the client can set the filtering properties to start/stop * filtering TS packets on a particular TS feed. */ +struct dmx_ts_feed; + +typedef int (*dmx_ts_data_ready_cb)( + struct dmx_ts_feed *source, + struct dmx_data_ready *dmx_data_ready); + struct dmx_ts_feed { int is_filtering; struct dmx_demux *parent; + struct data_buffer buffer; void *priv; + struct dmx_decoder_buffers *decoder_buffers; int (*set)(struct dmx_ts_feed *feed, u16 pid, int type, enum dmx_ts_pes pes_type, + size_t circular_buffer_size, ktime_t timeout); int (*start_filtering)(struct dmx_ts_feed *feed); int (*stop_filtering)(struct dmx_ts_feed *feed); + int (*set_video_codec)(struct dmx_ts_feed *feed, + enum dmx_video_codec video_codec); + int (*set_idx_params)(struct dmx_ts_feed *feed, + struct dmx_indexing_params *idx_params); + int (*get_decoder_buff_status)( + struct dmx_ts_feed *feed, + struct dmx_buffer_status *dmx_buffer_status); + int (*reuse_decoder_buffer)( + struct dmx_ts_feed *feed, + int cookie); + int (*data_ready_cb)(struct dmx_ts_feed *feed, + dmx_ts_data_ready_cb callback); + int (*notify_data_read)(struct dmx_ts_feed *feed, + u32 bytes_num); + int (*set_tsp_out_format)(struct dmx_ts_feed *feed, + enum dmx_tsp_format_t tsp_format); + int (*set_secure_mode)(struct dmx_ts_feed *feed, + struct dmx_secure_mode *sec_mode); + int (*set_cipher_ops)(struct dmx_ts_feed *feed, + struct dmx_cipher_operations *cipher_ops); + int (*oob_command)(struct dmx_ts_feed *feed, + struct dmx_oob_command *cmd); + int (*ts_insertion_init)(struct dmx_ts_feed *feed); + int (*ts_insertion_terminate)(struct dmx_ts_feed *feed); + int (*ts_insertion_insert_buffer)(struct dmx_ts_feed *feed, + char *data, size_t size); + int (*get_scrambling_bits)(struct dmx_ts_feed *feed, u8 *value); + int (*flush_buffer)(struct dmx_ts_feed *feed, size_t length); }; /* @@ -126,14 +267,21 @@ struct dmx_ts_feed { * corresponding bits are compared. The filter only accepts sections that are * equal to filter_value in all the tested bit positions. */ + +struct dmx_section_feed; struct dmx_section_filter { u8 filter_value[DMX_MAX_FILTER_SIZE]; u8 filter_mask[DMX_MAX_FILTER_SIZE]; u8 filter_mode[DMX_MAX_FILTER_SIZE]; struct dmx_section_feed *parent; /* Back-pointer */ + struct data_buffer buffer; void *priv; /* Pointer to private data of the API client */ }; +typedef int (*dmx_section_data_ready_cb)( + struct dmx_section_filter *source, + struct dmx_data_ready *dmx_data_ready); + /** * struct dmx_section_feed - Structure that contains a section feed filter * @@ -176,6 +324,7 @@ struct dmx_section_feed { /* public: */ int (*set)(struct dmx_section_feed *feed, u16 pid, + size_t circular_buffer_size, int check_crc); int (*allocate_filter)(struct dmx_section_feed *feed, struct dmx_section_filter **filter); @@ -183,6 +332,18 @@ struct dmx_section_feed { struct dmx_section_filter *filter); int (*start_filtering)(struct dmx_section_feed *feed); int (*stop_filtering)(struct dmx_section_feed *feed); + int (*data_ready_cb)(struct dmx_section_feed *feed, + dmx_section_data_ready_cb callback); + int (*notify_data_read)(struct dmx_section_filter *filter, + u32 bytes_num); + int (*set_secure_mode)(struct dmx_section_feed *feed, + struct dmx_secure_mode *sec_mode); + int (*set_cipher_ops)(struct dmx_section_feed *feed, + struct dmx_cipher_operations *cipher_ops); + int (*oob_command)(struct dmx_section_feed *feed, + struct dmx_oob_command *cmd); + int (*get_scrambling_bits)(struct dmx_section_feed *feed, u8 *value); + int (*flush_buffer)(struct dmx_section_feed *feed, size_t length); }; /** @@ -288,9 +449,19 @@ typedef int (*dmx_section_cb)(const u8 *buffer1, size_t buffer2_len, struct dmx_section_filter *source); -/* - * DVB Front-End - */ +typedef int (*dmx_ts_fullness) ( + struct dmx_ts_feed *source, + int required_space, + int wait); + +typedef int (*dmx_section_fullness) ( + struct dmx_section_filter *source, + int required_space, + int wait); + +/*--------------------------------------------------------------------------*/ +/* DVB Front-End */ +/*--------------------------------------------------------------------------*/ /** * enum dmx_frontend_source - Used to identify the type of frontend @@ -305,6 +476,13 @@ typedef int (*dmx_section_cb)(const u8 *buffer1, enum dmx_frontend_source { DMX_MEMORY_FE, DMX_FRONTEND_0, + DMX_FRONTEND_1, + DMX_FRONTEND_2, + DMX_FRONTEND_3, + DMX_STREAM_0, /* external stream input, e.g. LVDS */ + DMX_STREAM_1, + DMX_STREAM_2, + DMX_STREAM_3 }; /** @@ -338,8 +516,11 @@ struct dmx_frontend { */ enum dmx_demux_caps { DMX_TS_FILTERING = 1, + DMX_PES_FILTERING = 2, DMX_SECTION_FILTERING = 4, DMX_MEMORY_BASED_FILTERING = 8, + DMX_CRC_CHECKING = 16, + DMX_TS_DESCRAMBLING = 32 }; /* @@ -550,6 +731,10 @@ struct dmx_demux { enum dmx_demux_caps capabilities; struct dmx_frontend *frontend; void *priv; + struct data_buffer dvr_input; /* DVR input buffer */ + int dvr_input_protected; + struct dentry *debugfs_demux_dir; /* debugfs dir */ + int (*open)(struct dmx_demux *demux); int (*close)(struct dmx_demux *demux); int (*write)(struct dmx_demux *demux, const char __user *buf, @@ -575,7 +760,19 @@ struct dmx_demux { int (*get_pes_pids)(struct dmx_demux *demux, u16 *pids); - /* private: */ + int (*get_caps)(struct dmx_demux *demux, struct dmx_caps *caps); + + int (*set_source)(struct dmx_demux *demux, const dmx_source_t *src); + + int (*set_tsp_format)(struct dmx_demux *demux, + enum dmx_tsp_format_t tsp_format); + + int (*set_playback_mode)(struct dmx_demux *demux, + enum dmx_playback_mode_t mode, + dmx_ts_fullness ts_fullness_callback, + dmx_section_fullness sec_fullness_callback); + + int (*write_cancel)(struct dmx_demux *demux); /* * Only used at av7110, to read some data from firmware. @@ -584,6 +781,15 @@ struct dmx_demux { */ int (*get_stc)(struct dmx_demux *demux, unsigned int num, u64 *stc, unsigned int *base); + + int (*map_buffer)(struct dmx_demux *demux, + struct dmx_buffer *dmx_buffer, + struct ion_dma_buff_info *dma_buffer, void **mem); + + int (*unmap_buffer)(struct dmx_demux *demux, + struct ion_dma_buff_info *dma_buffer); + + int (*get_tsp_size)(struct dmx_demux *demux); }; #endif /* #ifndef __DEMUX_H */ diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 51009b2718a3..ff6a5cf93eb8 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -27,18 +27,73 @@ #include #include #include +#include +#include +#include +#include #include "dmxdev.h" -static int debug; +static int overflow_auto_flush = 1; +module_param(overflow_auto_flush, int, 0644); +MODULE_PARM_DESC(overflow_auto_flush, + "Automatically flush buffer on overflow (default: on)"); -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); +#define DMX_DEFAULT_DECODER_BUFFER_SIZE (32768) -#define dprintk(fmt, arg...) do { \ - if (debug) \ - printk(KERN_DEBUG pr_fmt("%s: " fmt), \ - __func__, ##arg); \ -} while (0) +static inline int dvb_dmxdev_verify_buffer_size(u32 size, u32 max_size, + u32 size_align) +{ + if (size_align) + return size <= max_size && !(size % size_align); + else + return size <= max_size; +} + +static int dvb_filter_verify_buffer_size(struct dmxdev_filter *filter) +{ + struct dmx_caps caps; + size_t size = filter->buffer.size; + + /* + * For backward compatibility, if no demux capabilities can + * be retrieved assume size is ok. + * Decoder filter buffer size is verified when decoder buffer is set. + */ + if (filter->dev->demux->get_caps) { + filter->dev->demux->get_caps(filter->dev->demux, &caps); + + if (filter->type == DMXDEV_TYPE_SEC) + return dvb_dmxdev_verify_buffer_size( + size, + caps.section.max_size, + caps.section.size_alignment); + + if (filter->params.pes.output == DMX_OUT_TAP) + return dvb_dmxdev_verify_buffer_size( + size, + caps.pes.max_size, + caps.pes.size_alignment); + + size = (filter->params.pes.output == DMX_OUT_TS_TAP) ? + filter->dev->dvr_buffer.size : size; + + if (filter->params.pes.output == DMX_OUT_TSDEMUX_TAP || + filter->params.pes.output == DMX_OUT_TS_TAP) { + if (filter->dmx_tsp_format == DMX_TSP_FORMAT_188) + return dvb_dmxdev_verify_buffer_size( + size, + caps.recording_188_tsp.max_size, + caps.recording_188_tsp.size_alignment); + + return dvb_dmxdev_verify_buffer_size( + size, + caps.recording_192_tsp.max_size, + caps.recording_192_tsp.size_alignment); + } + } + + return 1; +} static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf, const u8 *src, size_t len) @@ -52,16 +107,401 @@ static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf, free = dvb_ringbuffer_free(buf); if (len > free) { - dprintk("buffer overflow\n"); + pr_debug("dmxdev: buffer overflow\n"); return -EOVERFLOW; } return dvb_ringbuffer_write(buf, src, len); } -static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src, - int non_blocking, char __user *buf, - size_t count, loff_t *ppos) +static inline void dvb_dmxdev_notify_data_read(struct dmxdev_filter *filter, + int bytes_read) +{ + if (!filter) + return; + + if (filter->type == DMXDEV_TYPE_SEC) { + if (filter->feed.sec.feed->notify_data_read) + filter->feed.sec.feed->notify_data_read( + filter->filter.sec, + bytes_read); + } else { + struct dmxdev_feed *feed; + + /* + * All feeds of same demux-handle share the same output + * buffer, it is enough to notify on the buffer status + * on one of the feeds + */ + feed = list_first_entry(&filter->feed.ts, + struct dmxdev_feed, next); + + if (feed->ts->notify_data_read) + feed->ts->notify_data_read( + feed->ts, + bytes_read); + } +} + +static inline u32 dvb_dmxdev_advance_event_idx(u32 index) +{ + index++; + if (index >= DMX_EVENT_QUEUE_SIZE) + index = 0; + + return index; +} + +static inline int dvb_dmxdev_events_is_full(struct dmxdev_events_queue *events) +{ + int new_write_index; + + new_write_index = dvb_dmxdev_advance_event_idx(events->write_index); + if (new_write_index == events->read_index) + return 1; + + return 0; + +} + +static inline void dvb_dmxdev_flush_events(struct dmxdev_events_queue *events) +{ + events->read_index = 0; + events->write_index = 0; + events->notified_index = 0; + events->bytes_read_no_event = 0; + events->current_event_data_size = 0; + events->wakeup_events_counter = 0; +} + +static inline void dvb_dmxdev_flush_output(struct dvb_ringbuffer *buffer, + struct dmxdev_events_queue *events) +{ + dvb_dmxdev_flush_events(events); + dvb_ringbuffer_flush(buffer); +} + +static int dvb_dmxdev_update_pes_event(struct dmx_filter_event *event, + int bytes_read) +{ + int start_delta; + + if (event->params.pes.total_length <= bytes_read) + return event->params.pes.total_length; + + /* + * only part of the data relevant to this event was read. + * Update the event's information to reflect the new state. + */ + event->params.pes.total_length -= bytes_read; + + start_delta = event->params.pes.start_offset - + event->params.pes.base_offset; + + if (bytes_read <= start_delta) { + event->params.pes.base_offset += + bytes_read; + } else { + start_delta = + bytes_read - start_delta; + + event->params.pes.start_offset += start_delta; + event->params.pes.actual_length -= start_delta; + + event->params.pes.base_offset = + event->params.pes.start_offset; + } + + return 0; +} + +static int dvb_dmxdev_update_section_event(struct dmx_filter_event *event, + int bytes_read) +{ + int start_delta; + + if (event->params.section.total_length <= bytes_read) + return event->params.section.total_length; + + /* + * only part of the data relevant to this event was read. + * Update the event's information to reflect the new state. + */ + + event->params.section.total_length -= bytes_read; + + start_delta = event->params.section.start_offset - + event->params.section.base_offset; + + if (bytes_read <= start_delta) { + event->params.section.base_offset += + bytes_read; + } else { + start_delta = + bytes_read - start_delta; + + event->params.section.start_offset += start_delta; + event->params.section.actual_length -= start_delta; + + event->params.section.base_offset = + event->params.section.start_offset; + } + + return 0; +} + +static int dvb_dmxdev_update_rec_event(struct dmx_filter_event *event, + int bytes_read) +{ + if (event->params.recording_chunk.size <= bytes_read) + return event->params.recording_chunk.size; + + /* + * only part of the data relevant to this event was read. + * Update the event's information to reflect the new state. + */ + event->params.recording_chunk.size -= bytes_read; + event->params.recording_chunk.offset += bytes_read; + + return 0; +} + +static int dvb_dmxdev_add_event(struct dmxdev_events_queue *events, + struct dmx_filter_event *event) +{ + int res; + int new_write_index; + int data_event; + + /* Check if the event is disabled */ + if (events->event_mask.disable_mask & event->type) + return 0; + + /* Check if we are adding an event that user already read its data */ + if (events->bytes_read_no_event) { + data_event = 1; + + if (event->type == DMX_EVENT_NEW_PES) + res = dvb_dmxdev_update_pes_event(event, + events->bytes_read_no_event); + else if (event->type == DMX_EVENT_NEW_SECTION) + res = dvb_dmxdev_update_section_event(event, + events->bytes_read_no_event); + else if (event->type == DMX_EVENT_NEW_REC_CHUNK) + res = dvb_dmxdev_update_rec_event(event, + events->bytes_read_no_event); + else + data_event = 0; + + if (data_event) { + if (res) { + /* + * Data relevant to this event was fully + * consumed already, discard event. + */ + events->bytes_read_no_event -= res; + return 0; + } + events->bytes_read_no_event = 0; + } else { + /* + * data was read beyond the non-data event, + * making it not relevant anymore + */ + return 0; + } + } + + new_write_index = dvb_dmxdev_advance_event_idx(events->write_index); + if (new_write_index == events->read_index) { + pr_err("dmxdev: events overflow\n"); + return -EOVERFLOW; + } + + events->queue[events->write_index] = *event; + events->write_index = new_write_index; + + if (!(events->event_mask.no_wakeup_mask & event->type)) + events->wakeup_events_counter++; + + return 0; +} + +static int dvb_dmxdev_remove_event(struct dmxdev_events_queue *events, + struct dmx_filter_event *event) +{ + if (events->notified_index == events->write_index) + return -ENODATA; + + *event = events->queue[events->notified_index]; + + events->notified_index = + dvb_dmxdev_advance_event_idx(events->notified_index); + + if (!(events->event_mask.no_wakeup_mask & event->type)) + events->wakeup_events_counter--; + + return 0; +} + +static int dvb_dmxdev_update_events(struct dmxdev_events_queue *events, + int bytes_read) +{ + struct dmx_filter_event *event; + int res; + int data_event; + + /* + * If data events are not enabled on this filter, + * there's nothing to update. + */ + if (events->data_read_event_masked) + return 0; + + /* + * Go through all events that were notified and + * remove them from the events queue if their respective + * data was read. + */ + while ((events->read_index != events->notified_index) && + (bytes_read)) { + event = events->queue + events->read_index; + + data_event = 1; + + if (event->type == DMX_EVENT_NEW_PES) + res = dvb_dmxdev_update_pes_event(event, bytes_read); + else if (event->type == DMX_EVENT_NEW_SECTION) + res = dvb_dmxdev_update_section_event(event, + bytes_read); + else if (event->type == DMX_EVENT_NEW_REC_CHUNK) + res = dvb_dmxdev_update_rec_event(event, bytes_read); + else + data_event = 0; + + if (data_event) { + if (res) { + /* + * Data relevant to this event was + * fully consumed, remove it from the queue. + */ + bytes_read -= res; + events->read_index = + dvb_dmxdev_advance_event_idx( + events->read_index); + } else { + bytes_read = 0; + } + } else { + /* + * non-data event was already notified, + * no need to keep it + */ + events->read_index = dvb_dmxdev_advance_event_idx( + events->read_index); + } + } + + if (!bytes_read) + return 0; + + /* + * If we reached here it means: + * bytes_read != 0 + * events->read_index == events->notified_index + * Check if there are pending events in the queue + * which the user didn't read while their relevant data + * was read. + */ + while ((events->notified_index != events->write_index) && + (bytes_read)) { + event = events->queue + events->notified_index; + + data_event = 1; + + if (event->type == DMX_EVENT_NEW_PES) + res = dvb_dmxdev_update_pes_event(event, bytes_read); + else if (event->type == DMX_EVENT_NEW_SECTION) + res = dvb_dmxdev_update_section_event(event, + bytes_read); + else if (event->type == DMX_EVENT_NEW_REC_CHUNK) + res = dvb_dmxdev_update_rec_event(event, bytes_read); + else + data_event = 0; + + if (data_event) { + if (res) { + /* + * Data relevant to this event was + * fully consumed, remove it from the queue. + */ + bytes_read -= res; + events->notified_index = + dvb_dmxdev_advance_event_idx( + events->notified_index); + if (!(events->event_mask.no_wakeup_mask & + event->type)) + events->wakeup_events_counter--; + } else { + bytes_read = 0; + } + } else { + if (bytes_read) { + /* + * data was read beyond the non-data event, + * making it not relevant anymore + */ + events->notified_index = + dvb_dmxdev_advance_event_idx( + events->notified_index); + if (!(events->event_mask.no_wakeup_mask & + event->type)) + events->wakeup_events_counter--; + } + } + + events->read_index = events->notified_index; + } + + /* + * Check if data was read without having a respective + * event in the events-queue + */ + if (bytes_read) + events->bytes_read_no_event += bytes_read; + + return 0; +} + +static inline int dvb_dmxdev_check_data(struct dmxdev_filter *filter, + struct dvb_ringbuffer *src) +{ + int data_status_change; + + if (filter) + if (mutex_lock_interruptible(&filter->mutex)) + return -ERESTARTSYS; + + if (!src->data || + !dvb_ringbuffer_empty(src) || + src->error || + (filter && + (filter->state != DMXDEV_STATE_GO) && + (filter->state != DMXDEV_STATE_DONE))) + data_status_change = 1; + else + data_status_change = 0; + + if (filter) + mutex_unlock(&filter->mutex); + + return data_status_change; +} + +static ssize_t dvb_dmxdev_buffer_read(struct dmxdev_filter *filter, + struct dvb_ringbuffer *src, + int non_blocking, char __user *buf, + size_t count, loff_t *ppos) { size_t todo; ssize_t avail; @@ -72,7 +512,7 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src, if (src->error) { ret = src->error; - dvb_ringbuffer_flush(src); + src->error = 0; return ret; } @@ -82,15 +522,35 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src, break; } + if (filter) { + if ((filter->state == DMXDEV_STATE_DONE) && + dvb_ringbuffer_empty(src)) + break; + + mutex_unlock(&filter->mutex); + } + ret = wait_event_interruptible(src->queue, - !dvb_ringbuffer_empty(src) || - (src->error != 0)); + dvb_dmxdev_check_data(filter, src)); + + if (filter) { + if (mutex_lock_interruptible(&filter->mutex)) + return -ERESTARTSYS; + + if ((filter->state != DMXDEV_STATE_GO) && + (filter->state != DMXDEV_STATE_DONE)) + return -ENODEV; + } + if (ret < 0) break; + if (!src->data) + return 0; + if (src->error) { ret = src->error; - dvb_ringbuffer_flush(src); + src->error = 0; break; } @@ -105,6 +565,9 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src, buf += ret; } + if (count - todo) /* some data was read? */ + wake_up_all(&src->queue); + return (count - todo) ? (count - todo) : ret; } @@ -122,13 +585,238 @@ static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type) return NULL; } +static void dvb_dvr_oob_cmd(struct dmxdev *dmxdev, struct dmx_oob_command *cmd) +{ + int i; + struct dmxdev_filter *filter; + struct dmxdev_feed *feed; + + for (i = 0; i < dmxdev->filternum; i++) { + filter = &dmxdev->filter[i]; + if (!filter || filter->state != DMXDEV_STATE_GO) + continue; + + switch (filter->type) { + case DMXDEV_TYPE_SEC: + filter->feed.sec.feed->oob_command( + filter->feed.sec.feed, cmd); + break; + case DMXDEV_TYPE_PES: + feed = list_first_entry(&filter->feed.ts, + struct dmxdev_feed, next); + feed->ts->oob_command(feed->ts, cmd); + break; + case DMXDEV_TYPE_NONE: + break; + default: + break; + } + } +} + +static int dvb_dvr_feed_cmd(struct dmxdev *dmxdev, struct dvr_command *dvr_cmd) +{ + int ret = 0; + size_t todo; + int bytes_written = 0; + size_t split; + size_t tsp_size; + u8 *data_start; + struct dvb_ringbuffer *src = &dmxdev->dvr_input_buffer; + + todo = dvr_cmd->cmd.data_feed_count; + + if (dmxdev->demux->get_tsp_size) + tsp_size = dmxdev->demux->get_tsp_size(dmxdev->demux); + else + tsp_size = 188; + + while (todo >= tsp_size) { + /* wait for input */ + ret = wait_event_interruptible( + src->queue, + (dvb_ringbuffer_avail(src) >= tsp_size) || + dmxdev->dvr_in_exit || src->error); + + if (ret < 0) + break; + + spin_lock(&dmxdev->dvr_in_lock); + + if (dmxdev->exit || dmxdev->dvr_in_exit) { + spin_unlock(&dmxdev->dvr_in_lock); + ret = -ENODEV; + break; + } + + if (src->error) { + spin_unlock(&dmxdev->dvr_in_lock); + wake_up_all(&src->queue); + ret = -EINVAL; + break; + } + + dmxdev->dvr_processing_input = 1; + + split = (src->pread + todo > src->size) ? + src->size - src->pread : 0; + + /* + * In DVR PULL mode, write might block. + * Lock on DVR buffer is released before calling to + * write, if DVR was released meanwhile, dvr_in_exit is + * prompted. Lock is acquired when updating the read pointer + * again to preserve read/write pointers consistency. + * + * In protected input mode, DVR input buffer is not mapped + * to kernel memory. Underlying demux implementation + * should trigger HW to read from DVR input buffer + * based on current read offset. + */ + if (split > 0) { + data_start = (dmxdev->demux->dvr_input_protected) ? + NULL : (src->data + src->pread); + + spin_unlock(&dmxdev->dvr_in_lock); + ret = dmxdev->demux->write(dmxdev->demux, + data_start, + split); + + if (ret < 0) { + pr_err("dmxdev: dvr write error %d\n", ret); + continue; + } + + if (dmxdev->dvr_in_exit) { + ret = -ENODEV; + break; + } + + spin_lock(&dmxdev->dvr_in_lock); + + todo -= ret; + bytes_written += ret; + DVB_RINGBUFFER_SKIP(src, ret); + if (ret < split) { + dmxdev->dvr_processing_input = 0; + spin_unlock(&dmxdev->dvr_in_lock); + wake_up_all(&src->queue); + continue; + } + } + + data_start = (dmxdev->demux->dvr_input_protected) ? + NULL : (src->data + src->pread); + + spin_unlock(&dmxdev->dvr_in_lock); + ret = dmxdev->demux->write(dmxdev->demux, + data_start, todo); + + if (ret < 0) { + pr_err("dmxdev: dvr write error %d\n", ret); + continue; + } + + if (dmxdev->dvr_in_exit) { + ret = -ENODEV; + break; + } + + spin_lock(&dmxdev->dvr_in_lock); + + todo -= ret; + bytes_written += ret; + DVB_RINGBUFFER_SKIP(src, ret); + dmxdev->dvr_processing_input = 0; + spin_unlock(&dmxdev->dvr_in_lock); + + wake_up_all(&src->queue); + } + + if (ret < 0) + return ret; + + return bytes_written; +} + +static int dvr_input_thread_entry(void *arg) +{ + struct dmxdev *dmxdev = arg; + struct dvb_ringbuffer *cmdbuf = &dmxdev->dvr_cmd_buffer; + struct dvr_command dvr_cmd; + int leftover = 0; + int ret; + + while (1) { + /* wait for input */ + ret = wait_event_interruptible( + cmdbuf->queue, + (!cmdbuf->data) || + (dvb_ringbuffer_avail(cmdbuf) >= sizeof(dvr_cmd)) || + (dmxdev->dvr_in_exit)); + + if (ret < 0) + break; + + spin_lock(&dmxdev->dvr_in_lock); + + if (!cmdbuf->data || dmxdev->exit || dmxdev->dvr_in_exit) { + spin_unlock(&dmxdev->dvr_in_lock); + break; + } + + dvb_ringbuffer_read(cmdbuf, (u8 *)&dvr_cmd, sizeof(dvr_cmd)); + + spin_unlock(&dmxdev->dvr_in_lock); + + if (dvr_cmd.type == DVR_DATA_FEED_CMD) { + dvr_cmd.cmd.data_feed_count += leftover; + + ret = dvb_dvr_feed_cmd(dmxdev, &dvr_cmd); + if (ret < 0) { + pr_debug("%s: DVR data feed failed, ret=%d\n", + __func__, ret); + continue; + } + + leftover = dvr_cmd.cmd.data_feed_count - ret; + } else { + /* + * For EOS, try to process leftover data in the input + * buffer. + */ + if (dvr_cmd.cmd.oobcmd.type == DMX_OOB_CMD_EOS) { + struct dvr_command feed_cmd; + + feed_cmd.type = DVR_DATA_FEED_CMD; + feed_cmd.cmd.data_feed_count = + dvb_ringbuffer_avail( + &dmxdev->dvr_input_buffer); + dvb_dvr_feed_cmd(dmxdev, &feed_cmd); + } + + dvb_dvr_oob_cmd(dmxdev, &dvr_cmd.cmd.oobcmd); + } + } + + set_current_state(TASK_INTERRUPTIBLE); + while (!kthread_should_stop()) { + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + } + set_current_state(TASK_RUNNING); + + return 0; +} + static int dvb_dvr_open(struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; struct dmx_frontend *front; + void *mem; - dprintk("%s\n", __func__); + pr_debug("function : %s(%X)\n", __func__, (file->f_flags & O_ACCMODE)); if (mutex_lock_interruptible(&dmxdev->mutex)) return -ERESTARTSYS; @@ -146,22 +834,29 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) } if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - void *mem; - if (!dvbdev->readers) { mutex_unlock(&dmxdev->mutex); return -EBUSY; } - mem = vmalloc(DVR_BUFFER_SIZE); + mem = vmalloc_user(DVR_BUFFER_SIZE); if (!mem) { mutex_unlock(&dmxdev->mutex); return -ENOMEM; } dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); - dvbdev->readers--; - } + dvb_dmxdev_flush_events(&dmxdev->dvr_output_events); + dmxdev->dvr_output_events.event_mask.disable_mask = 0; + dmxdev->dvr_output_events.event_mask.no_wakeup_mask = 0; + dmxdev->dvr_output_events.event_mask.wakeup_threshold = 1; + dmxdev->dvr_feeds_count = 0; + dmxdev->dvr_buffer_mode = DMX_BUFFER_MODE_INTERNAL; + memset(&dmxdev->dvr_buff_dma_info, 0, + sizeof(dmxdev->dvr_buff_dma_info)); - if ((file->f_flags & O_ACCMODE) == O_WRONLY) { + dvbdev->readers--; + } else if (!dvbdev->writers) { + dmxdev->dvr_in_exit = 0; + dmxdev->dvr_processing_input = 0; dmxdev->dvr_orig_fe = dmxdev->demux->frontend; if (!dmxdev->demux->write) { @@ -175,9 +870,52 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) mutex_unlock(&dmxdev->mutex); return -EINVAL; } + + mem = vmalloc_user(DVR_BUFFER_SIZE); + if (!mem) { + mutex_unlock(&dmxdev->mutex); + return -ENOMEM; + } + dmxdev->demux->disconnect_frontend(dmxdev->demux); dmxdev->demux->connect_frontend(dmxdev->demux, front); + dmxdev->dvr_input_buffer_mode = DMX_BUFFER_MODE_INTERNAL; + + dvb_ringbuffer_init(&dmxdev->dvr_input_buffer, + mem, + DVR_BUFFER_SIZE); + + memset(&dmxdev->demux->dvr_input.buff_dma_info, 0, + sizeof(struct ion_dma_buff_info)); + dmxdev->demux->dvr_input.ringbuff = &dmxdev->dvr_input_buffer; + dmxdev->demux->dvr_input_protected = 0; + mem = vmalloc(DVR_CMDS_BUFFER_SIZE); + if (!mem) { + vfree(dmxdev->dvr_input_buffer.data); + dmxdev->dvr_input_buffer.data = NULL; + mutex_unlock(&dmxdev->mutex); + return -ENOMEM; + } + dvb_ringbuffer_init(&dmxdev->dvr_cmd_buffer, mem, + DVR_CMDS_BUFFER_SIZE); + dvbdev->writers--; + + dmxdev->dvr_input_thread = + kthread_run( + dvr_input_thread_entry, + (void *)dmxdev, + "dvr_input"); + + if (IS_ERR(dmxdev->dvr_input_thread)) { + vfree(dmxdev->dvr_input_buffer.data); + vfree(dmxdev->dvr_cmd_buffer.data); + dmxdev->dvr_input_buffer.data = NULL; + dmxdev->dvr_cmd_buffer.data = NULL; + mutex_unlock(&dmxdev->mutex); + return -ENOMEM; + } } + dvbdev->users++; mutex_unlock(&dmxdev->mutex); return 0; @@ -190,11 +928,6 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) mutex_lock(&dmxdev->mutex); - if ((file->f_flags & O_ACCMODE) == O_WRONLY) { - dmxdev->demux->disconnect_frontend(dmxdev->demux); - dmxdev->demux->connect_frontend(dmxdev->demux, - dmxdev->dvr_orig_fe); - } if ((file->f_flags & O_ACCMODE) == O_RDONLY) { dvbdev->readers++; if (dmxdev->dvr_buffer.data) { @@ -204,140 +937,1657 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) spin_lock_irq(&dmxdev->lock); dmxdev->dvr_buffer.data = NULL; spin_unlock_irq(&dmxdev->lock); - vfree(mem); + wake_up_all(&dmxdev->dvr_buffer.queue); + + if (dmxdev->dvr_buffer_mode == DMX_BUFFER_MODE_INTERNAL) + vfree(mem); } - } - /* TODO */ - dvbdev->users--; - if (dvbdev->users == 1 && dmxdev->exit == 1) { - mutex_unlock(&dmxdev->mutex); - wake_up(&dvbdev->wait_queue); - } else - mutex_unlock(&dmxdev->mutex); + + if ((dmxdev->dvr_buffer_mode == DMX_BUFFER_MODE_EXTERNAL) && + dmxdev->dvr_buff_dma_info.va) { + dmxdev->demux->unmap_buffer(dmxdev->demux, + &dmxdev->dvr_buff_dma_info); + } + } else { + int i; + + spin_lock(&dmxdev->dvr_in_lock); + dmxdev->dvr_in_exit = 1; + spin_unlock(&dmxdev->dvr_in_lock); + + wake_up_all(&dmxdev->dvr_cmd_buffer.queue); + + /* + * There might be dmx filters reading now from DVR + * device, in PULL mode, they might be also stalled + * on output, signal to them that DVR is exiting. + */ + if (dmxdev->playback_mode == DMX_PB_MODE_PULL) { + wake_up_all(&dmxdev->dvr_buffer.queue); + + for (i = 0; i < dmxdev->filternum; i++) + if (dmxdev->filter[i].state == DMXDEV_STATE_GO) + wake_up_all( + &dmxdev->filter[i].buffer.queue); + } + + /* notify kernel demux that we are canceling */ + if (dmxdev->demux->write_cancel) + dmxdev->demux->write_cancel(dmxdev->demux); + + /* + * Now stop dvr-input thread so that no one + * would process data from dvr input buffer any more + * before it gets freed. + */ + kthread_stop(dmxdev->dvr_input_thread); + + dvbdev->writers++; + dmxdev->demux->disconnect_frontend(dmxdev->demux); + dmxdev->demux->connect_frontend(dmxdev->demux, + dmxdev->dvr_orig_fe); + + if (dmxdev->dvr_input_buffer.data) { + void *mem = dmxdev->dvr_input_buffer.data; + /* + * Ensure all the operations on the DVR input buffer + * are completed before it gets freed. + */ + mb(); + spin_lock_irq(&dmxdev->dvr_in_lock); + dmxdev->dvr_input_buffer.data = NULL; + spin_unlock_irq(&dmxdev->dvr_in_lock); + + if (dmxdev->dvr_input_buffer_mode == + DMX_BUFFER_MODE_INTERNAL) + vfree(mem); + } + + if ((dmxdev->dvr_input_buffer_mode == + DMX_BUFFER_MODE_EXTERNAL) && + (dmxdev->demux->dvr_input.buff_dma_info.va)) { + if (!dmxdev->demux->dvr_input_protected) + dmxdev->demux->unmap_buffer(dmxdev->demux, + &dmxdev->demux->dvr_input.buff_dma_info); + } + + if (dmxdev->dvr_cmd_buffer.data) { + void *mem = dmxdev->dvr_cmd_buffer.data; + /* + * Ensure all the operations on the DVR command buffer + * are completed before it gets freed. + */ + mb(); + spin_lock_irq(&dmxdev->dvr_in_lock); + dmxdev->dvr_cmd_buffer.data = NULL; + spin_unlock_irq(&dmxdev->dvr_in_lock); + vfree(mem); + } + } + /* TODO */ + dvbdev->users--; + if (dvbdev->users == 1 && dmxdev->exit == 1) { + fops_put(file->f_op); + file->f_op = NULL; + mutex_unlock(&dmxdev->mutex); + wake_up(&dvbdev->wait_queue); + } else + mutex_unlock(&dmxdev->mutex); + + return 0; +} + + +static int dvb_dvr_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct dvb_device *dvbdev = filp->private_data; + struct dmxdev *dmxdev = dvbdev->priv; + struct dvb_ringbuffer *buffer; + enum dmx_buffer_mode buffer_mode; + int vma_size; + int buffer_size; + int ret; + + if (((filp->f_flags & O_ACCMODE) == O_RDONLY) && + (vma->vm_flags & VM_WRITE)) + return -EINVAL; + + if (mutex_lock_interruptible(&dmxdev->mutex)) + return -ERESTARTSYS; + + if (dmxdev->exit) { + mutex_unlock(&dmxdev->mutex); + return -ENODEV; + } + + if ((filp->f_flags & O_ACCMODE) == O_RDONLY) { + buffer = &dmxdev->dvr_buffer; + buffer_mode = dmxdev->dvr_buffer_mode; + } else { + buffer = &dmxdev->dvr_input_buffer; + buffer_mode = dmxdev->dvr_input_buffer_mode; + } + + if (buffer_mode == DMX_BUFFER_MODE_EXTERNAL) { + mutex_unlock(&dmxdev->mutex); + return -EINVAL; + } + + vma_size = vma->vm_end - vma->vm_start; + + /* Make sure requested mapping is not larger than buffer size */ + buffer_size = buffer->size + (PAGE_SIZE-1); + buffer_size = buffer_size & ~(PAGE_SIZE-1); + + if (vma_size != buffer_size) { + mutex_unlock(&dmxdev->mutex); + return -EINVAL; + } + + ret = remap_vmalloc_range(vma, buffer->data, 0); + if (ret) { + mutex_unlock(&dmxdev->mutex); + return ret; + } + + vma->vm_flags |= VM_DONTDUMP; + vma->vm_flags |= VM_DONTEXPAND; + + mutex_unlock(&dmxdev->mutex); + return ret; +} + +static void dvb_dvr_queue_data_feed(struct dmxdev *dmxdev, size_t count) +{ + struct dvb_ringbuffer *cmdbuf = &dmxdev->dvr_cmd_buffer; + struct dvr_command *dvr_cmd; + int last_dvr_cmd; + + spin_lock(&dmxdev->dvr_in_lock); + + /* Peek at the last DVR command queued, try to coalesce FEED commands */ + if (dvb_ringbuffer_avail(cmdbuf) >= sizeof(*dvr_cmd)) { + last_dvr_cmd = cmdbuf->pwrite - sizeof(*dvr_cmd); + if (last_dvr_cmd < 0) + last_dvr_cmd += cmdbuf->size; + + dvr_cmd = (struct dvr_command *)&cmdbuf->data[last_dvr_cmd]; + if (dvr_cmd->type == DVR_DATA_FEED_CMD) { + dvr_cmd->cmd.data_feed_count += count; + spin_unlock(&dmxdev->dvr_in_lock); + return; + } + } + + /* + * We assume command buffer is large enough so that overflow should not + * happen. Overflow to the command buffer means data previously written + * to the input buffer is 'orphan' - does not have a matching FEED + * command. Issue a warning if this ever happens. + * Orphan data might still be processed if EOS is issued. + */ + if (dvb_ringbuffer_free(cmdbuf) < sizeof(*dvr_cmd)) { + pr_err("%s: DVR command buffer overflow\n", __func__); + spin_unlock(&dmxdev->dvr_in_lock); + return; + } + + dvr_cmd = (struct dvr_command *)&cmdbuf->data[cmdbuf->pwrite]; + dvr_cmd->type = DVR_DATA_FEED_CMD; + dvr_cmd->cmd.data_feed_count = count; + DVB_RINGBUFFER_PUSH(cmdbuf, sizeof(*dvr_cmd)); + spin_unlock(&dmxdev->dvr_in_lock); + + wake_up_all(&cmdbuf->queue); +} + +static int dvb_dvr_external_input_only(struct dmxdev *dmxdev) +{ + struct dmx_caps caps; + int is_external_only; + int flags; + size_t tsp_size; + + if (dmxdev->demux->get_tsp_size) + tsp_size = dmxdev->demux->get_tsp_size(dmxdev->demux); + else + tsp_size = 188; + + /* + * For backward compatibility, default assumes that + * external only buffers are not supported. + */ + flags = 0; + if (dmxdev->demux->get_caps) { + dmxdev->demux->get_caps(dmxdev->demux, &caps); + + if (tsp_size == 188) + flags = caps.playback_188_tsp.flags; + else + flags = caps.playback_192_tsp.flags; + } + + if (!(flags & DMX_BUFFER_INTERNAL_SUPPORT) && + (flags & DMX_BUFFER_EXTERNAL_SUPPORT)) + is_external_only = 1; + else + is_external_only = 0; + + return is_external_only; +} + +static int dvb_dvr_verify_buffer_size(struct dmxdev *dmxdev, + unsigned int f_flags, + unsigned long size) +{ + struct dmx_caps caps; + int tsp_size; + + if (!dmxdev->demux->get_caps) + return 1; + + if (dmxdev->demux->get_tsp_size) + tsp_size = dmxdev->demux->get_tsp_size(dmxdev->demux); + else + tsp_size = 188; + + dmxdev->demux->get_caps(dmxdev->demux, &caps); + if ((f_flags & O_ACCMODE) == O_RDONLY) + return (tsp_size == 188 && dvb_dmxdev_verify_buffer_size(size, + caps.recording_188_tsp.max_size, + caps.recording_188_tsp.size_alignment)) || + (tsp_size == 192 && dvb_dmxdev_verify_buffer_size(size, + caps.recording_192_tsp.max_size, + caps.recording_192_tsp.size_alignment)); + + return (tsp_size == 188 && dvb_dmxdev_verify_buffer_size(size, + caps.playback_188_tsp.max_size, + caps.playback_188_tsp.size_alignment)) || + (tsp_size == 192 && dvb_dmxdev_verify_buffer_size(size, + caps.playback_192_tsp.max_size, + caps.playback_192_tsp.size_alignment)); +} + +static ssize_t dvb_dvr_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; + struct dvb_ringbuffer *src = &dmxdev->dvr_input_buffer; + struct dvb_ringbuffer *cmdbuf = &dmxdev->dvr_cmd_buffer; + int ret; + size_t todo; + ssize_t free_space; + + if (!dmxdev->demux->write) + return -EOPNOTSUPP; + + if (!dvb_dvr_verify_buffer_size(dmxdev, file->f_flags, src->size) || + ((file->f_flags & O_ACCMODE) == O_RDONLY) || + !src->data || !cmdbuf->data || + (dvb_dvr_external_input_only(dmxdev) && + (dmxdev->dvr_input_buffer_mode == DMX_BUFFER_MODE_INTERNAL))) + return -EINVAL; + + if ((file->f_flags & O_NONBLOCK) && + (dvb_ringbuffer_free(src) == 0)) + return -EWOULDBLOCK; + + ret = 0; + for (todo = count; todo > 0; todo -= ret) { + ret = wait_event_interruptible(src->queue, + (dvb_ringbuffer_free(src)) || + !src->data || !cmdbuf->data || + (src->error != 0) || dmxdev->dvr_in_exit); + + if (ret < 0) + return ret; + + if (mutex_lock_interruptible(&dmxdev->mutex)) + return -ERESTARTSYS; + + if ((!src->data) || (!cmdbuf->data)) { + mutex_unlock(&dmxdev->mutex); + return 0; + } + + if (dmxdev->exit || dmxdev->dvr_in_exit) { + mutex_unlock(&dmxdev->mutex); + return -ENODEV; + } + + if (src->error) { + ret = src->error; + dvb_ringbuffer_flush(src); + mutex_unlock(&dmxdev->mutex); + wake_up_all(&src->queue); + return ret; + } + + free_space = dvb_ringbuffer_free(src); + + if (free_space > todo) + free_space = todo; + + ret = dvb_ringbuffer_write_user(src, buf, free_space); + + if (ret < 0) { + mutex_unlock(&dmxdev->mutex); + return ret; + } + + buf += ret; + + dvb_dvr_queue_data_feed(dmxdev, ret); + + mutex_unlock(&dmxdev->mutex); + } + + return (count - todo) ? (count - todo) : ret; +} + +static int dvb_dmxdev_flush_data(struct dmxdev_filter *filter, size_t length) +{ + int ret = 0; + unsigned long flags; + + struct dvb_ringbuffer *buffer = &filter->buffer; + struct dmxdev_events_queue *events = &filter->events; + + if (filter->type == DMXDEV_TYPE_PES && + filter->params.pes.output == DMX_OUT_TS_TAP) { + buffer = &filter->dev->dvr_buffer; + events = &filter->dev->dvr_output_events; + } + + /* + * Drop 'length' pending data bytes from the ringbuffer and update + * event queue accordingly, similarly to dvb_dmxdev_release_data(). + */ + spin_lock_irqsave(&filter->dev->lock, flags); + DVB_RINGBUFFER_SKIP(buffer, length); + buffer->error = 0; + dvb_dmxdev_flush_events(events); + events->current_event_start_offset = buffer->pwrite; + spin_unlock_irqrestore(&filter->dev->lock, flags); + + if (filter->type == DMXDEV_TYPE_PES) { + struct dmxdev_feed *feed; + + feed = list_first_entry(&filter->feed.ts, + struct dmxdev_feed, next); + + if (feed->ts->flush_buffer) + return feed->ts->flush_buffer(feed->ts, length); + } else if (filter->type == DMXDEV_TYPE_SEC && + filter->feed.sec.feed->flush_buffer) { + return filter->feed.sec.feed->flush_buffer( + filter->feed.sec.feed, length); + } + + return ret; +} + +static inline void dvb_dmxdev_auto_flush_buffer(struct dmxdev_filter *filter, + struct dvb_ringbuffer *buf) +{ + size_t flush_len; + + /* + * When buffer overflowed, demux-dev marked the buffer in + * error state. If auto-flush is enabled discard current + * pending data in buffer. + */ + if (overflow_auto_flush) { + flush_len = dvb_ringbuffer_avail(buf); + dvb_dmxdev_flush_data(filter, flush_len); + } +} + +static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + ssize_t res; + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; + unsigned long flags; + + if (dmxdev->exit) + return -ENODEV; + + if (!dvb_dvr_verify_buffer_size(dmxdev, file->f_flags, + dmxdev->dvr_buffer.size)) + return -EINVAL; + + res = dvb_dmxdev_buffer_read(NULL, &dmxdev->dvr_buffer, + file->f_flags & O_NONBLOCK, + buf, count, ppos); + + if (res > 0) { + dvb_dmxdev_notify_data_read(dmxdev->dvr_feed, res); + spin_lock_irqsave(&dmxdev->lock, flags); + dvb_dmxdev_update_events(&dmxdev->dvr_output_events, res); + spin_unlock_irqrestore(&dmxdev->lock, flags); + + /* + * in PULL mode, we might be stalling on + * event queue, so need to wake-up waiters + */ + if (dmxdev->playback_mode == DMX_PB_MODE_PULL) + wake_up_all(&dmxdev->dvr_buffer.queue); + } else if (res == -EOVERFLOW) { + dvb_dmxdev_auto_flush_buffer(dmxdev->dvr_feed, + &dmxdev->dvr_buffer); + } + + return res; +} + +/* + * dvb_dvr_push_oob_cmd + * + * Note: this function assume dmxdev->mutex was taken, so command buffer cannot + * be released during its operation. + */ +static int dvb_dvr_push_oob_cmd(struct dmxdev *dmxdev, unsigned int f_flags, + struct dmx_oob_command *cmd) +{ + struct dvb_ringbuffer *cmdbuf = &dmxdev->dvr_cmd_buffer; + struct dvr_command *dvr_cmd; + + if ((f_flags & O_ACCMODE) == O_RDONLY || + dmxdev->source < DMX_SOURCE_DVR0) + return -EPERM; + + if (dvb_ringbuffer_free(cmdbuf) < sizeof(*dvr_cmd)) + return -ENOMEM; + + dvr_cmd = (struct dvr_command *)&cmdbuf->data[cmdbuf->pwrite]; + dvr_cmd->type = DVR_OOB_CMD; + dvr_cmd->cmd.oobcmd = *cmd; + DVB_RINGBUFFER_PUSH(cmdbuf, sizeof(*dvr_cmd)); + wake_up_all(&cmdbuf->queue); + + return 0; +} + +static int dvb_dvr_flush_buffer(struct dmxdev *dmxdev, unsigned int f_flags) +{ + size_t flush_len; + int ret; + + if ((f_flags & O_ACCMODE) != O_RDONLY) + return -EINVAL; + + flush_len = dvb_ringbuffer_avail(&dmxdev->dvr_buffer); + ret = dvb_dmxdev_flush_data(dmxdev->dvr_feed, flush_len); + + return ret; +} + +static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev, + unsigned int f_flags, + unsigned long size) +{ + struct dvb_ringbuffer *buf; + void *newmem; + void *oldmem; + spinlock_t *lock; + enum dmx_buffer_mode buffer_mode; + + pr_debug("function : %s\n", __func__); + + if ((f_flags & O_ACCMODE) == O_RDONLY) { + buf = &dmxdev->dvr_buffer; + lock = &dmxdev->lock; + buffer_mode = dmxdev->dvr_buffer_mode; + } else { + buf = &dmxdev->dvr_input_buffer; + lock = &dmxdev->dvr_in_lock; + buffer_mode = dmxdev->dvr_input_buffer_mode; + } + + if (buf->size == size) + return 0; + if (!size || (buffer_mode == DMX_BUFFER_MODE_EXTERNAL)) + return -EINVAL; + + newmem = vmalloc_user(size); + if (!newmem) + return -ENOMEM; + + oldmem = buf->data; + + spin_lock_irq(lock); + + if (((f_flags & O_ACCMODE) != O_RDONLY) && + (dmxdev->dvr_processing_input)) { + spin_unlock_irq(lock); + vfree(oldmem); + return -EBUSY; + } + + buf->data = newmem; + buf->size = size; + + /* reset and not flush in case the buffer shrinks */ + dvb_ringbuffer_reset(buf); + + spin_unlock_irq(lock); + + vfree(oldmem); + + return 0; +} + +static int dvb_dvr_set_buffer_mode(struct dmxdev *dmxdev, + unsigned int f_flags, enum dmx_buffer_mode mode) +{ + struct dvb_ringbuffer *buf; + spinlock_t *lock; + enum dmx_buffer_mode *buffer_mode; + struct ion_dma_buff_info *dma_info; + void *oldmem; + int *is_protected; + + if ((mode != DMX_BUFFER_MODE_INTERNAL) && + (mode != DMX_BUFFER_MODE_EXTERNAL)) + return -EINVAL; + + if ((mode == DMX_BUFFER_MODE_EXTERNAL) && + (!dmxdev->demux->map_buffer || !dmxdev->demux->unmap_buffer)) + return -EINVAL; + + if ((f_flags & O_ACCMODE) == O_RDONLY) { + buf = &dmxdev->dvr_buffer; + lock = &dmxdev->lock; + buffer_mode = &dmxdev->dvr_buffer_mode; + dma_info = &dmxdev->dvr_buff_dma_info; + is_protected = NULL; + } else { + buf = &dmxdev->dvr_input_buffer; + lock = &dmxdev->dvr_in_lock; + buffer_mode = &dmxdev->dvr_input_buffer_mode; + dma_info = &dmxdev->demux->dvr_input.buff_dma_info; + is_protected = &dmxdev->demux->dvr_input_protected; + } + + if (mode == *buffer_mode) + return 0; + + oldmem = buf->data; + spin_lock_irq(lock); + buf->data = NULL; + spin_unlock_irq(lock); + + *buffer_mode = mode; + + if (mode == DMX_BUFFER_MODE_INTERNAL) { + /* switched from external to internal */ + if (dma_info->dmabuf) { + dmxdev->demux->unmap_buffer(dmxdev->demux, + dma_info); + } + + if (is_protected) + *is_protected = 0; + + /* set default internal buffer */ + dvb_dvr_set_buffer_size(dmxdev, f_flags, DVR_BUFFER_SIZE); + } else if (oldmem) { + /* switched from internal to external */ + vfree(oldmem); + } + + return 0; +} + +static int dvb_dvr_set_buffer(struct dmxdev *dmxdev, + unsigned int f_flags, struct dmx_buffer *dmx_buffer) +{ + struct dvb_ringbuffer *buf; + spinlock_t *lock; + enum dmx_buffer_mode buffer_mode; + struct ion_dma_buff_info *dma_info; + void *newmem; + void *oldmem = NULL; + int *is_protected; + struct dmx_caps caps; + + if (dmxdev->demux->get_caps) + dmxdev->demux->get_caps(dmxdev->demux, &caps); + else + caps.caps = 0; + + if ((f_flags & O_ACCMODE) == O_RDONLY) { + buf = &dmxdev->dvr_buffer; + lock = &dmxdev->lock; + buffer_mode = dmxdev->dvr_buffer_mode; + dma_info = &dmxdev->dvr_buff_dma_info; + is_protected = NULL; + } else { + buf = &dmxdev->dvr_input_buffer; + lock = &dmxdev->dvr_in_lock; + buffer_mode = dmxdev->dvr_input_buffer_mode; + dma_info = &dmxdev->demux->dvr_input.buff_dma_info; + is_protected = &dmxdev->demux->dvr_input_protected; + if (!(caps.caps & DMX_CAP_SECURED_INPUT_PLAYBACK) && + dmx_buffer->is_protected) + return -EINVAL; + } + + if (!dmx_buffer->size || + (buffer_mode == DMX_BUFFER_MODE_INTERNAL)) + return -EINVAL; + + if (dmxdev->demux->dvr_input.buff_dma_info.va) + oldmem = dmxdev->demux->dvr_input.buff_dma_info.va; + + /* + * Protected buffer is relevant only for DVR input buffer + * when DVR device is opened for write. In such case, + * buffer is mapped only if the buffer is not protected one. + */ + if (!is_protected || !dmx_buffer->is_protected) { + if (dmxdev->demux->map_buffer(dmxdev->demux, dmx_buffer, + dma_info, &newmem)) + return -ENOMEM; + } else { + newmem = NULL; + } + + spin_lock_irq(lock); + buf->data = newmem; + buf->size = dmx_buffer->size; + if (is_protected) + *is_protected = dmx_buffer->is_protected; + dvb_ringbuffer_reset(buf); + spin_unlock_irq(lock); + + if (oldmem) + dmxdev->demux->unmap_buffer(dmxdev->demux, oldmem); + + return 0; +} + +static int dvb_dvr_get_event(struct dmxdev *dmxdev, + unsigned int f_flags, + struct dmx_filter_event *event) +{ + int res = 0; + + if (!((f_flags & O_ACCMODE) == O_RDONLY)) + return -EINVAL; + + spin_lock_irq(&dmxdev->lock); + + if (dmxdev->dvr_buffer.error == -EOVERFLOW) { + event->type = DMX_EVENT_BUFFER_OVERFLOW; + dmxdev->dvr_buffer.error = 0; + } else { + res = dvb_dmxdev_remove_event(&dmxdev->dvr_output_events, + event); + if (res) { + spin_unlock_irq(&dmxdev->lock); + return res; + } + } + + spin_unlock_irq(&dmxdev->lock); + + if (event->type == DMX_EVENT_BUFFER_OVERFLOW) + dvb_dmxdev_auto_flush_buffer(dmxdev->dvr_feed, + &dmxdev->dvr_buffer); + + /* + * in PULL mode, we might be stalling on + * event queue, so need to wake-up waiters + */ + if (dmxdev->playback_mode == DMX_PB_MODE_PULL) + wake_up_all(&dmxdev->dvr_buffer.queue); + + return res; +} + +static int dvb_dvr_get_buffer_status(struct dmxdev *dmxdev, + unsigned int f_flags, + struct dmx_buffer_status *dmx_buffer_status) +{ + struct dvb_ringbuffer *buf; + spinlock_t *lock; + + if ((f_flags & O_ACCMODE) == O_RDONLY) { + buf = &dmxdev->dvr_buffer; + lock = &dmxdev->lock; + } else { + buf = &dmxdev->dvr_input_buffer; + lock = &dmxdev->dvr_in_lock; + } + + spin_lock_irq(lock); + + dmx_buffer_status->error = buf->error; + dmx_buffer_status->fullness = dvb_ringbuffer_avail(buf); + dmx_buffer_status->free_bytes = dvb_ringbuffer_free(buf); + dmx_buffer_status->read_offset = buf->pread; + dmx_buffer_status->write_offset = buf->pwrite; + dmx_buffer_status->size = buf->size; + buf->error = 0; + + spin_unlock_irq(lock); + + if (dmx_buffer_status->error == -EOVERFLOW) + dvb_dmxdev_auto_flush_buffer(dmxdev->dvr_feed, buf); + + return 0; +} + +static int dvb_dvr_release_data(struct dmxdev *dmxdev, + unsigned int f_flags, + u32 bytes_count) +{ + ssize_t buff_fullness; + + if (!((f_flags & O_ACCMODE) == O_RDONLY)) + return -EINVAL; + + if (!bytes_count) + return 0; + + buff_fullness = dvb_ringbuffer_avail(&dmxdev->dvr_buffer); + + if (bytes_count > buff_fullness) + return -EINVAL; + + DVB_RINGBUFFER_SKIP(&dmxdev->dvr_buffer, bytes_count); + + dvb_dmxdev_notify_data_read(dmxdev->dvr_feed, bytes_count); + spin_lock_irq(&dmxdev->lock); + dvb_dmxdev_update_events(&dmxdev->dvr_output_events, bytes_count); + spin_unlock_irq(&dmxdev->lock); + + wake_up_all(&dmxdev->dvr_buffer.queue); + return 0; +} + +/* + * dvb_dvr_feed_data - Notify new data in DVR input buffer + * + * @dmxdev - demux device instance + * @f_flags - demux device file flag (access mode) + * @bytes_count - how many bytes were written to the input buffer + * + * Note: this function assume dmxdev->mutex was taken, so buffer cannot + * be released during its operation. + */ +static int dvb_dvr_feed_data(struct dmxdev *dmxdev, + unsigned int f_flags, + u32 bytes_count) +{ + ssize_t free_space; + struct dvb_ringbuffer *buffer = &dmxdev->dvr_input_buffer; + + if ((f_flags & O_ACCMODE) == O_RDONLY) + return -EINVAL; + + if (!bytes_count) + return 0; + + free_space = dvb_ringbuffer_free(buffer); + + if (bytes_count > free_space) + return -EINVAL; + + DVB_RINGBUFFER_PUSH(buffer, bytes_count); + + dvb_dvr_queue_data_feed(dmxdev, bytes_count); + + return 0; +} + +static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter + *dmxdevfilter, int state) +{ + spin_lock_irq(&dmxdevfilter->dev->lock); + dmxdevfilter->state = state; + spin_unlock_irq(&dmxdevfilter->dev->lock); +} + +static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, + unsigned long size) +{ + struct dvb_ringbuffer *buf = &dmxdevfilter->buffer; + void *newmem; + void *oldmem; + + if (buf->size == size) + return 0; + if (!size || + (dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL)) + return -EINVAL; + if (dmxdevfilter->state >= DMXDEV_STATE_GO) + return -EBUSY; + + newmem = vmalloc_user(size); + if (!newmem) + return -ENOMEM; + + oldmem = buf->data; + + spin_lock_irq(&dmxdevfilter->dev->lock); + buf->data = newmem; + buf->size = size; + + /* reset and not flush in case the buffer shrinks */ + dvb_ringbuffer_reset(buf); + spin_unlock_irq(&dmxdevfilter->dev->lock); + + vfree(oldmem); + + return 0; +} + +static int dvb_dmxdev_set_buffer_mode(struct dmxdev_filter *dmxdevfilter, + enum dmx_buffer_mode mode) +{ + struct dvb_ringbuffer *buf = &dmxdevfilter->buffer; + struct dmxdev *dmxdev = dmxdevfilter->dev; + void *oldmem; + + if (dmxdevfilter->state >= DMXDEV_STATE_GO) + return -EBUSY; + + if ((mode != DMX_BUFFER_MODE_INTERNAL) && + (mode != DMX_BUFFER_MODE_EXTERNAL)) + return -EINVAL; + + if ((mode == DMX_BUFFER_MODE_EXTERNAL) && + (!dmxdev->demux->map_buffer || !dmxdev->demux->unmap_buffer)) + return -EINVAL; + + if (mode == dmxdevfilter->buffer_mode) + return 0; + + oldmem = buf->data; + spin_lock_irq(&dmxdevfilter->dev->lock); + buf->data = NULL; + spin_unlock_irq(&dmxdevfilter->dev->lock); + + dmxdevfilter->buffer_mode = mode; + + if (mode == DMX_BUFFER_MODE_INTERNAL) { + /* switched from external to internal */ + if (dmxdevfilter->buff_dma_info.va) { + dmxdev->demux->unmap_buffer(dmxdev->demux, + &dmxdevfilter->buff_dma_info); + } + } else if (oldmem) { + /* switched from internal to external */ + vfree(oldmem); + } + + return 0; +} + +static int dvb_dmxdev_set_buffer(struct dmxdev_filter *dmxdevfilter, + struct dmx_buffer *buffer) +{ + struct dvb_ringbuffer *buf = &dmxdevfilter->buffer; + struct dmxdev *dmxdev = dmxdevfilter->dev; + void *newmem; + void *oldmem; + + if (dmxdevfilter->state >= DMXDEV_STATE_GO) + return -EBUSY; + + if ((!buffer->size) || + (dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_INTERNAL)) + return -EINVAL; + + oldmem = dmxdevfilter->buff_dma_info.va; + if (oldmem) { + dmxdev->demux->unmap_buffer(dmxdev->demux, + &dmxdevfilter->buff_dma_info); + } + + + if (dmxdev->demux->map_buffer(dmxdev->demux, buffer, + &dmxdevfilter->buff_dma_info, &newmem)) + return -ENOMEM; + + spin_lock_irq(&dmxdevfilter->dev->lock); + buf->data = newmem; + buf->size = buffer->size; + dvb_ringbuffer_reset(buf); + spin_unlock_irq(&dmxdevfilter->dev->lock); + + return 0; +} + +static int dvb_dmxdev_set_tsp_out_format(struct dmxdev_filter *dmxdevfilter, + enum dmx_tsp_format_t dmx_tsp_format) +{ + if (dmxdevfilter->state >= DMXDEV_STATE_GO) + return -EBUSY; + + if ((dmx_tsp_format > DMX_TSP_FORMAT_192_HEAD) || + (dmx_tsp_format < DMX_TSP_FORMAT_188)) + return -EINVAL; + + dmxdevfilter->dmx_tsp_format = dmx_tsp_format; + + return 0; +} + +static int dvb_dmxdev_set_decoder_buffer_size( + struct dmxdev_filter *dmxdevfilter, + unsigned long size) +{ + struct dmx_caps caps; + struct dmx_demux *demux = dmxdevfilter->dev->demux; + + if (demux->get_caps) { + demux->get_caps(demux, &caps); + if (!dvb_dmxdev_verify_buffer_size(size, caps.decoder.max_size, + caps.decoder.size_alignment)) + return -EINVAL; + } + + if (size == 0) + return -EINVAL; + + if (dmxdevfilter->decoder_buffers.buffers_size == size) + return 0; + + if (dmxdevfilter->state >= DMXDEV_STATE_GO) + return -EBUSY; + + /* + * In case decoder buffers were already set before to some external + * buffers, setting the decoder buffer size alone implies transition + * to internal buffer mode. + */ + dmxdevfilter->decoder_buffers.buffers_size = size; + dmxdevfilter->decoder_buffers.buffers_num = 0; + dmxdevfilter->decoder_buffers.is_linear = 0; + return 0; +} + +static int dvb_dmxdev_set_source(struct dmxdev_filter *dmxdevfilter, + dmx_source_t *source) +{ + int ret = 0; + struct dmxdev *dev; + + if (dmxdevfilter->state == DMXDEV_STATE_GO) + return -EBUSY; + + dev = dmxdevfilter->dev; + if (dev->demux->set_source) + ret = dev->demux->set_source(dev->demux, source); + + if (!ret) + dev->source = *source; + + return ret; +} + +static int dvb_dmxdev_reuse_decoder_buf(struct dmxdev_filter *dmxdevfilter, + int cookie) +{ + struct dmxdev_feed *feed; + + if (dmxdevfilter->state != DMXDEV_STATE_GO || + (dmxdevfilter->type != DMXDEV_TYPE_PES) || + (dmxdevfilter->params.pes.output != DMX_OUT_DECODER) || + (dmxdevfilter->events.event_mask.disable_mask & + DMX_EVENT_NEW_ES_DATA)) + return -EPERM; + + /* Only one feed should be in the list in case of decoder */ + feed = list_first_entry(&dmxdevfilter->feed.ts, + struct dmxdev_feed, next); + if (feed && feed->ts && feed->ts->reuse_decoder_buffer) + return feed->ts->reuse_decoder_buffer(feed->ts, cookie); + + return -ENODEV; +} + +static int dvb_dmxdev_set_event_mask(struct dmxdev_filter *dmxdevfilter, + struct dmx_events_mask *event_mask) +{ + if (!event_mask || + (event_mask->wakeup_threshold >= DMX_EVENT_QUEUE_SIZE)) + return -EINVAL; + + if (dmxdevfilter->state == DMXDEV_STATE_GO) + return -EBUSY; + + /* + * Overflow event is not allowed to be masked. + * This is because if overflow occurs, demux stops outputting data + * until user is notified. If user is using events to read the data, + * the overflow event must be always enabled or otherwise we would + * never recover from overflow state. + */ + event_mask->disable_mask &= ~(u32)DMX_EVENT_BUFFER_OVERFLOW; + event_mask->no_wakeup_mask &= ~(u32)DMX_EVENT_BUFFER_OVERFLOW; + + dmxdevfilter->events.event_mask = *event_mask; + + return 0; +} + +static int dvb_dmxdev_get_event_mask(struct dmxdev_filter *dmxdevfilter, + struct dmx_events_mask *event_mask) +{ + if (!event_mask) + return -EINVAL; + + *event_mask = dmxdevfilter->events.event_mask; return 0; } -static ssize_t dvb_dvr_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) +static int dvb_dmxdev_set_indexing_params(struct dmxdev_filter *dmxdevfilter, + struct dmx_indexing_params *idx_params) +{ + int found_pid; + struct dmxdev_feed *feed; + struct dmxdev_feed *ts_feed = NULL; + struct dmx_caps caps; + int ret = 0; + + if (!dmxdevfilter->dev->demux->get_caps) + return -EINVAL; + + dmxdevfilter->dev->demux->get_caps(dmxdevfilter->dev->demux, &caps); + + if (!idx_params || + !(caps.caps & DMX_CAP_VIDEO_INDEXING) || + (dmxdevfilter->state < DMXDEV_STATE_SET) || + (dmxdevfilter->type != DMXDEV_TYPE_PES) || + ((dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) && + (dmxdevfilter->params.pes.output != DMX_OUT_TSDEMUX_TAP))) + return -EINVAL; + + if (idx_params->enable && !idx_params->types) + return -EINVAL; + + found_pid = 0; + list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) { + if (feed->pid == idx_params->pid) { + found_pid = 1; + ts_feed = feed; + ts_feed->idx_params = *idx_params; + if ((dmxdevfilter->state == DMXDEV_STATE_GO) && + ts_feed->ts->set_idx_params) + ret = ts_feed->ts->set_idx_params( + ts_feed->ts, idx_params); + break; + } + } + + if (!found_pid) + return -EINVAL; + + return ret; +} + +static int dvb_dmxdev_get_scrambling_bits(struct dmxdev_filter *filter, + struct dmx_scrambling_bits *scrambling_bits) +{ + struct dmxdev_feed *feed; + + if (!scrambling_bits || + (filter->state != DMXDEV_STATE_GO)) + return -EINVAL; + + if (filter->type == DMXDEV_TYPE_SEC) { + if (filter->feed.sec.feed->get_scrambling_bits) + return filter->feed.sec.feed->get_scrambling_bits( + filter->feed.sec.feed, + &scrambling_bits->value); + return -EINVAL; + } + + list_for_each_entry(feed, &filter->feed.ts, next) { + if (feed->pid == scrambling_bits->pid) { + if (feed->ts->get_scrambling_bits) + return feed->ts->get_scrambling_bits(feed->ts, + &scrambling_bits->value); + return -EINVAL; + } + } + + return -EINVAL; +} + +static void dvb_dmxdev_ts_insertion_work(struct work_struct *worker) +{ + struct ts_insertion_buffer *ts_buffer = + container_of(to_delayed_work(worker), + struct ts_insertion_buffer, dwork); + struct dmxdev_feed *feed; + size_t free_bytes; + struct dmx_ts_feed *ts; + + mutex_lock(&ts_buffer->dmxdevfilter->mutex); + + if (ts_buffer->abort || + (ts_buffer->dmxdevfilter->state != DMXDEV_STATE_GO)) { + mutex_unlock(&ts_buffer->dmxdevfilter->mutex); + return; + } + + feed = list_first_entry(&ts_buffer->dmxdevfilter->feed.ts, + struct dmxdev_feed, next); + ts = feed->ts; + free_bytes = dvb_ringbuffer_free(&ts_buffer->dmxdevfilter->buffer); + + mutex_unlock(&ts_buffer->dmxdevfilter->mutex); + + if (ts_buffer->size < free_bytes) + ts->ts_insertion_insert_buffer(ts, + ts_buffer->buffer, ts_buffer->size); + + if (ts_buffer->repetition_time && !ts_buffer->abort) + schedule_delayed_work(&ts_buffer->dwork, + msecs_to_jiffies(ts_buffer->repetition_time)); +} + +static void dvb_dmxdev_queue_ts_insertion( + struct ts_insertion_buffer *ts_buffer) +{ + size_t tsp_size; + + if (ts_buffer->dmxdevfilter->dmx_tsp_format == DMX_TSP_FORMAT_188) + tsp_size = 188; + else + tsp_size = 192; + + if (ts_buffer->size % tsp_size) { + pr_err("%s: Wrong buffer alignment, size=%zu, tsp_size=%zu\n", + __func__, ts_buffer->size, tsp_size); + return; + } + + ts_buffer->abort = 0; + schedule_delayed_work(&ts_buffer->dwork, 0); +} + +static void dvb_dmxdev_cancel_ts_insertion( + struct ts_insertion_buffer *ts_buffer) +{ + /* + * This function assumes it is called while mutex + * of demux filter is taken. Since work in workqueue + * captures the filter's mutex to protect against the DB, + * mutex needs to be released before waiting for the work + * to get finished otherwise work in workqueue will + * never be finished. + */ + if (!mutex_is_locked(&ts_buffer->dmxdevfilter->mutex)) { + pr_err("%s: mutex is not locked!\n", __func__); + return; + } + + ts_buffer->abort = 1; + + mutex_unlock(&ts_buffer->dmxdevfilter->mutex); + cancel_delayed_work_sync(&ts_buffer->dwork); + mutex_lock(&ts_buffer->dmxdevfilter->mutex); +} + +static int dvb_dmxdev_set_ts_insertion(struct dmxdev_filter *dmxdevfilter, + struct dmx_set_ts_insertion *params) +{ + int ret = 0; + int first_buffer; + struct dmxdev_feed *feed; + struct ts_insertion_buffer *ts_buffer; + struct dmx_caps caps; + + if (!dmxdevfilter->dev->demux->get_caps) + return -EINVAL; + + dmxdevfilter->dev->demux->get_caps(dmxdevfilter->dev->demux, &caps); + + if (!params || + !params->size || + !(caps.caps & DMX_CAP_TS_INSERTION) || + (dmxdevfilter->state < DMXDEV_STATE_SET) || + (dmxdevfilter->type != DMXDEV_TYPE_PES) || + ((dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) && + (dmxdevfilter->params.pes.output != DMX_OUT_TSDEMUX_TAP))) + return -EINVAL; + + ts_buffer = vmalloc(sizeof(struct ts_insertion_buffer)); + if (!ts_buffer) + return -ENOMEM; + + ts_buffer->buffer = vmalloc(params->size); + if (!ts_buffer->buffer) { + vfree(ts_buffer); + return -ENOMEM; + } + + if (copy_from_user(ts_buffer->buffer, + params->ts_packets, params->size)) { + vfree(ts_buffer->buffer); + vfree(ts_buffer); + return -EFAULT; + } + + if (params->repetition_time && + params->repetition_time < DMX_MIN_INSERTION_REPETITION_TIME) + params->repetition_time = DMX_MIN_INSERTION_REPETITION_TIME; + + ts_buffer->size = params->size; + ts_buffer->identifier = params->identifier; + ts_buffer->repetition_time = params->repetition_time; + ts_buffer->dmxdevfilter = dmxdevfilter; + INIT_DELAYED_WORK(&ts_buffer->dwork, dvb_dmxdev_ts_insertion_work); + + first_buffer = list_empty(&dmxdevfilter->insertion_buffers); + list_add_tail(&ts_buffer->next, &dmxdevfilter->insertion_buffers); + + if (dmxdevfilter->state != DMXDEV_STATE_GO) + return 0; + + feed = list_first_entry(&dmxdevfilter->feed.ts, + struct dmxdev_feed, next); + + if (first_buffer && feed->ts->ts_insertion_init) + ret = feed->ts->ts_insertion_init(feed->ts); + + if (!ret) { + dvb_dmxdev_queue_ts_insertion(ts_buffer); + } else { + list_del(&ts_buffer->next); + vfree(ts_buffer->buffer); + vfree(ts_buffer); + } + + return ret; +} + +static int dvb_dmxdev_abort_ts_insertion(struct dmxdev_filter *dmxdevfilter, + struct dmx_abort_ts_insertion *params) +{ + int ret = 0; + int found_buffer; + struct dmxdev_feed *feed; + struct ts_insertion_buffer *ts_buffer, *tmp; + struct dmx_caps caps; + + if (!dmxdevfilter->dev->demux->get_caps) + return -EINVAL; + + dmxdevfilter->dev->demux->get_caps(dmxdevfilter->dev->demux, &caps); + + if (!params || + !(caps.caps & DMX_CAP_TS_INSERTION) || + (dmxdevfilter->state < DMXDEV_STATE_SET) || + (dmxdevfilter->type != DMXDEV_TYPE_PES) || + ((dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) && + (dmxdevfilter->params.pes.output != DMX_OUT_TSDEMUX_TAP))) + return -EINVAL; + + found_buffer = 0; + list_for_each_entry_safe(ts_buffer, tmp, + &dmxdevfilter->insertion_buffers, next) { + if (ts_buffer->identifier == params->identifier) { + list_del(&ts_buffer->next); + found_buffer = 1; + break; + } + } + + if (!found_buffer) + return -EINVAL; + + if (dmxdevfilter->state == DMXDEV_STATE_GO) { + dvb_dmxdev_cancel_ts_insertion(ts_buffer); + if (list_empty(&dmxdevfilter->insertion_buffers)) { + feed = list_first_entry(&dmxdevfilter->feed.ts, + struct dmxdev_feed, next); + if (feed->ts->ts_insertion_terminate) + ret = feed->ts->ts_insertion_terminate( + feed->ts); + } + } + + vfree(ts_buffer->buffer); + vfree(ts_buffer); + + return ret; +} + +static int dvb_dmxdev_ts_fullness_callback(struct dmx_ts_feed *filter, + int required_space, int wait) +{ + struct dmxdev_filter *dmxdevfilter = filter->priv; + struct dvb_ringbuffer *src; + struct dmxdev_events_queue *events; + int ret; + + if (!dmxdevfilter) { + pr_err("%s: NULL demux filter object!\n", __func__); + return -ENODEV; + } + + if (dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) { + src = &dmxdevfilter->buffer; + events = &dmxdevfilter->events; + } else { + src = &dmxdevfilter->dev->dvr_buffer; + events = &dmxdevfilter->dev->dvr_output_events; + } + + do { + ret = 0; + + if (dmxdevfilter->dev->dvr_in_exit) + return -ENODEV; + + spin_lock(&dmxdevfilter->dev->lock); + + if ((!src->data) || + (dmxdevfilter->state != DMXDEV_STATE_GO)) + ret = -EINVAL; + else if (src->error) + ret = src->error; + + if (ret) { + spin_unlock(&dmxdevfilter->dev->lock); + return ret; + } + + if ((required_space <= dvb_ringbuffer_free(src)) && + (!dvb_dmxdev_events_is_full(events))) { + spin_unlock(&dmxdevfilter->dev->lock); + return 0; + } + + spin_unlock(&dmxdevfilter->dev->lock); + + if (!wait) + return -ENOSPC; + + ret = wait_event_interruptible(src->queue, + (!src->data) || + ((dvb_ringbuffer_free(src) >= required_space) && + (!dvb_dmxdev_events_is_full(events))) || + (src->error != 0) || + (dmxdevfilter->state != DMXDEV_STATE_GO) || + dmxdevfilter->dev->dvr_in_exit); + + if (ret < 0) + return ret; + } while (1); +} + +static int dvb_dmxdev_sec_fullness_callback( + struct dmx_section_filter *filter, + int required_space, int wait) +{ + struct dmxdev_filter *dmxdevfilter = filter->priv; + struct dvb_ringbuffer *src; + struct dmxdev_events_queue *events; + int ret; + + if (!dmxdevfilter) { + pr_err("%s: NULL demux filter object!\n", __func__); + return -ENODEV; + } + + src = &dmxdevfilter->buffer; + events = &dmxdevfilter->events; + + do { + ret = 0; + + if (dmxdevfilter->dev->dvr_in_exit) + return -ENODEV; + + spin_lock(&dmxdevfilter->dev->lock); + + if ((!src->data) || + (dmxdevfilter->state != DMXDEV_STATE_GO)) + ret = -EINVAL; + else if (src->error) + ret = src->error; + + if (ret) { + spin_unlock(&dmxdevfilter->dev->lock); + return ret; + } + + if ((required_space <= dvb_ringbuffer_free(src)) && + (!dvb_dmxdev_events_is_full(events))) { + spin_unlock(&dmxdevfilter->dev->lock); + return 0; + } + + spin_unlock(&dmxdevfilter->dev->lock); + + if (!wait) + return -ENOSPC; + + ret = wait_event_interruptible(src->queue, + (!src->data) || + ((dvb_ringbuffer_free(src) >= required_space) && + (!dvb_dmxdev_events_is_full(events))) || + (src->error != 0) || + (dmxdevfilter->state != DMXDEV_STATE_GO) || + dmxdevfilter->dev->dvr_in_exit); + + if (ret < 0) + return ret; + } while (1); +} + +static int dvb_dmxdev_set_playback_mode(struct dmxdev_filter *dmxdevfilter, + enum dmx_playback_mode_t playback_mode) { - struct dvb_device *dvbdev = file->private_data; - struct dmxdev *dmxdev = dvbdev->priv; - int ret; + struct dmxdev *dmxdev = dmxdevfilter->dev; + struct dmx_caps caps; - if (!dmxdev->demux->write) - return -EOPNOTSUPP; - if ((file->f_flags & O_ACCMODE) != O_WRONLY) + if (dmxdev->demux->get_caps) + dmxdev->demux->get_caps(dmxdev->demux, &caps); + else + caps.caps = 0; + + if ((playback_mode != DMX_PB_MODE_PUSH) && + (playback_mode != DMX_PB_MODE_PULL)) return -EINVAL; - if (mutex_lock_interruptible(&dmxdev->mutex)) - return -ERESTARTSYS; - if (dmxdev->exit) { - mutex_unlock(&dmxdev->mutex); - return -ENODEV; - } - ret = dmxdev->demux->write(dmxdev->demux, buf, count); - mutex_unlock(&dmxdev->mutex); - return ret; + if (dmxdev->demux->set_playback_mode == NULL) + return -EINVAL; + + if (((dmxdev->source < DMX_SOURCE_DVR0) || + !(caps.caps & DMX_CAP_PULL_MODE)) && + (playback_mode == DMX_PB_MODE_PULL)) + return -EPERM; + + if (dmxdevfilter->state == DMXDEV_STATE_GO) + return -EBUSY; + + dmxdev->playback_mode = playback_mode; + + return dmxdev->demux->set_playback_mode( + dmxdev->demux, + dmxdev->playback_mode, + dvb_dmxdev_ts_fullness_callback, + dvb_dmxdev_sec_fullness_callback); } -static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) +static int dvb_dmxdev_flush_buffer(struct dmxdev_filter *filter) { - struct dvb_device *dvbdev = file->private_data; - struct dmxdev *dmxdev = dvbdev->priv; + size_t flush_len; + int ret; - if (dmxdev->exit) - return -ENODEV; + if (filter->state != DMXDEV_STATE_GO) + return -EINVAL; + + flush_len = dvb_ringbuffer_avail(&filter->buffer); + ret = dvb_dmxdev_flush_data(filter, flush_len); - return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, - file->f_flags & O_NONBLOCK, - buf, count, ppos); + return ret; } -static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev, - unsigned long size) +static int dvb_dmxdev_get_buffer_status( + struct dmxdev_filter *dmxdevfilter, + struct dmx_buffer_status *dmx_buffer_status) { - struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer; - void *newmem; - void *oldmem; + struct dvb_ringbuffer *buf = &dmxdevfilter->buffer; - dprintk("%s\n", __func__); + /* + * Note: Taking the dmxdevfilter->dev->lock spinlock is required only + * when getting the status of the Demux-userspace data ringbuffer . + * In case we are getting the status of a decoder buffer, taking this + * spinlock is not required and in fact might lead to a deadlock. + */ + if ((dmxdevfilter->type == DMXDEV_TYPE_PES) && + (dmxdevfilter->params.pes.output == DMX_OUT_DECODER)) { + struct dmxdev_feed *feed; + int ret; + + /* Only one feed should be in the list in case of decoder */ + feed = list_first_entry(&dmxdevfilter->feed.ts, + struct dmxdev_feed, next); + + /* Ask for status of decoder's buffer from underlying HW */ + if (feed->ts->get_decoder_buff_status) + ret = feed->ts->get_decoder_buff_status( + feed->ts, + dmx_buffer_status); + else + ret = -ENODEV; - if (buf->size == size) - return 0; - if (!size) - return -EINVAL; + return ret; + } - newmem = vmalloc(size); - if (!newmem) - return -ENOMEM; + spin_lock_irq(&dmxdevfilter->dev->lock); - oldmem = buf->data; + if (!buf->data) { + spin_unlock_irq(&dmxdevfilter->dev->lock); + return -EINVAL; + } - spin_lock_irq(&dmxdev->lock); - buf->data = newmem; - buf->size = size; + dmx_buffer_status->error = buf->error; + dmx_buffer_status->fullness = dvb_ringbuffer_avail(buf); + dmx_buffer_status->free_bytes = dvb_ringbuffer_free(buf); + dmx_buffer_status->read_offset = buf->pread; + dmx_buffer_status->write_offset = buf->pwrite; + dmx_buffer_status->size = buf->size; + buf->error = 0; - /* reset and not flush in case the buffer shrinks */ - dvb_ringbuffer_reset(buf); - spin_unlock_irq(&dmxdev->lock); + spin_unlock_irq(&dmxdevfilter->dev->lock); - vfree(oldmem); + if (dmx_buffer_status->error == -EOVERFLOW) + dvb_dmxdev_auto_flush_buffer(dmxdevfilter, buf); return 0; } -static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter - *dmxdevfilter, int state) +static int dvb_dmxdev_release_data(struct dmxdev_filter *dmxdevfilter, + u32 bytes_count) { + ssize_t buff_fullness; + + if (!dmxdevfilter->buffer.data) + return -EINVAL; + + if (!bytes_count) + return 0; + + buff_fullness = dvb_ringbuffer_avail(&dmxdevfilter->buffer); + + if (bytes_count > buff_fullness) + return -EINVAL; + + DVB_RINGBUFFER_SKIP(&dmxdevfilter->buffer, bytes_count); + + dvb_dmxdev_notify_data_read(dmxdevfilter, bytes_count); spin_lock_irq(&dmxdevfilter->dev->lock); - dmxdevfilter->state = state; + dvb_dmxdev_update_events(&dmxdevfilter->events, bytes_count); spin_unlock_irq(&dmxdevfilter->dev->lock); + + wake_up_all(&dmxdevfilter->buffer.queue); + + return 0; } -static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, - unsigned long size) +static int dvb_dmxdev_get_event(struct dmxdev_filter *dmxdevfilter, + struct dmx_filter_event *event) { - struct dvb_ringbuffer *buf = &dmxdevfilter->buffer; - void *newmem; - void *oldmem; + int res = 0; - if (buf->size == size) - return 0; - if (!size) - return -EINVAL; - if (dmxdevfilter->state >= DMXDEV_STATE_GO) - return -EBUSY; + spin_lock_irq(&dmxdevfilter->dev->lock); - newmem = vmalloc(size); - if (!newmem) - return -ENOMEM; + /* Check first for filter overflow */ + if (dmxdevfilter->buffer.error == -EOVERFLOW) { + event->type = DMX_EVENT_BUFFER_OVERFLOW; + } else { + res = dvb_dmxdev_remove_event(&dmxdevfilter->events, event); + if (res) { + spin_unlock_irq(&dmxdevfilter->dev->lock); + return res; + } + } - oldmem = buf->data; + /* clear buffer error now that user was notified */ + if (event->type == DMX_EVENT_BUFFER_OVERFLOW || + event->type == DMX_EVENT_SECTION_TIMEOUT) + dmxdevfilter->buffer.error = 0; + + spin_unlock_irq(&dmxdevfilter->dev->lock); + + if (event->type == DMX_EVENT_BUFFER_OVERFLOW) + dvb_dmxdev_auto_flush_buffer(dmxdevfilter, + &dmxdevfilter->buffer); spin_lock_irq(&dmxdevfilter->dev->lock); - buf->data = newmem; - buf->size = size; - /* reset and not flush in case the buffer shrinks */ - dvb_ringbuffer_reset(buf); + /* + * If no-data events are enabled on this filter, + * the events can be removed from the queue when + * user gets them. + * For filters with data events enabled, the event is removed + * from the queue only when the respective data is read. + */ + if (event->type != DMX_EVENT_BUFFER_OVERFLOW && + dmxdevfilter->events.data_read_event_masked) + dmxdevfilter->events.read_index = + dvb_dmxdev_advance_event_idx( + dmxdevfilter->events.read_index); + spin_unlock_irq(&dmxdevfilter->dev->lock); - vfree(oldmem); + /* + * in PULL mode, we might be stalling on + * event queue, so need to wake-up waiters + */ + if (dmxdevfilter->dev->playback_mode == DMX_PB_MODE_PULL) + wake_up_all(&dmxdevfilter->buffer.queue); - return 0; + return res; } static void dvb_dmxdev_filter_timeout(unsigned long data) { struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data; + struct dmx_filter_event event; dmxdevfilter->buffer.error = -ETIMEDOUT; spin_lock_irq(&dmxdevfilter->dev->lock); dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT; + event.type = DMX_EVENT_SECTION_TIMEOUT; + dvb_dmxdev_add_event(&dmxdevfilter->events, &event); spin_unlock_irq(&dmxdevfilter->dev->lock); - wake_up(&dmxdevfilter->buffer.queue); + wake_up_all(&dmxdevfilter->buffer.queue); } static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter) @@ -359,65 +2609,481 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, struct dmx_section_filter *filter) { struct dmxdev_filter *dmxdevfilter = filter->priv; - int ret; + struct dmx_filter_event event; + ssize_t free; - if (dmxdevfilter->buffer.error) { - wake_up(&dmxdevfilter->buffer.queue); - return 0; + + if (!dmxdevfilter) { + pr_err("%s: null filter.\n", __func__); + return -EINVAL; } + spin_lock(&dmxdevfilter->dev->lock); - if (dmxdevfilter->state != DMXDEV_STATE_GO) { + + if (dmxdevfilter->buffer.error || + dmxdevfilter->state != DMXDEV_STATE_GO || + dmxdevfilter->eos_state) { + spin_unlock(&dmxdevfilter->dev->lock); + return 0; + } + + /* Discard section data if event cannot be notified */ + if (!(dmxdevfilter->events.event_mask.disable_mask & + DMX_EVENT_NEW_SECTION) && + dvb_dmxdev_events_is_full(&dmxdevfilter->events)) { spin_unlock(&dmxdevfilter->dev->lock); return 0; } + + if ((buffer1_len + buffer2_len) == 0) { + if (buffer1 == NULL && buffer2 == NULL) { + /* Section was dropped due to CRC error */ + event.type = DMX_EVENT_SECTION_CRC_ERROR; + dvb_dmxdev_add_event(&dmxdevfilter->events, &event); + + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&dmxdevfilter->buffer.queue); + } else { + spin_unlock(&dmxdevfilter->dev->lock); + } + + return 0; + } + + event.params.section.base_offset = dmxdevfilter->buffer.pwrite; + event.params.section.start_offset = dmxdevfilter->buffer.pwrite; + del_timer(&dmxdevfilter->timer); - dprintk("section callback %*ph\n", 6, buffer1); - ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, - buffer1_len); - if (ret == buffer1_len) { - ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, - buffer2_len); + + /* Verify output buffer has sufficient space, or report overflow */ + free = dvb_ringbuffer_free(&dmxdevfilter->buffer); + if (free < (buffer1_len + buffer2_len)) { + pr_debug("%s: section filter overflow (pid=%u)\n", + __func__, dmxdevfilter->params.sec.pid); + dmxdevfilter->buffer.error = -EOVERFLOW; + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&dmxdevfilter->buffer.queue); + return 0; } - if (ret < 0) - dmxdevfilter->buffer.error = ret; + + dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, buffer1_len); + dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, buffer2_len); + + event.type = DMX_EVENT_NEW_SECTION; + event.params.section.total_length = buffer1_len + buffer2_len; + event.params.section.actual_length = + event.params.section.total_length; + + dvb_dmxdev_add_event(&dmxdevfilter->events, &event); + if (dmxdevfilter->params.sec.flags & DMX_ONESHOT) dmxdevfilter->state = DMXDEV_STATE_DONE; spin_unlock(&dmxdevfilter->dev->lock); - wake_up(&dmxdevfilter->buffer.queue); + wake_up_all(&dmxdevfilter->buffer.queue); + return 0; +} + +static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, + const u8 *buffer2, size_t buffer2_len, + struct dmx_ts_feed *feed) +{ + struct dmxdev_filter *dmxdevfilter = feed->priv; + struct dvb_ringbuffer *buffer; + struct dmxdev_events_queue *events; + struct dmx_filter_event event; + ssize_t free; + + if (!dmxdevfilter) { + pr_err("%s: null filter (feed->is_filtering=%d)\n", + __func__, feed->is_filtering); + return -EINVAL; + } + spin_lock(&dmxdevfilter->dev->lock); + + if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER || + dmxdevfilter->state != DMXDEV_STATE_GO || + dmxdevfilter->eos_state) { + spin_unlock(&dmxdevfilter->dev->lock); + return 0; + } + + if (dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) { + buffer = &dmxdevfilter->buffer; + events = &dmxdevfilter->events; + } else { + buffer = &dmxdevfilter->dev->dvr_buffer; + events = &dmxdevfilter->dev->dvr_output_events; + } + + if (buffer->error) { + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + return buffer->error; + } + + if (!events->current_event_data_size) + events->current_event_start_offset = buffer->pwrite; + + /* Verify output buffer has sufficient space, or report overflow */ + free = dvb_ringbuffer_free(buffer); + if (free < (buffer1_len + buffer2_len)) { + pr_debug("%s: buffer overflow error, pid=%u\n", + __func__, dmxdevfilter->params.pes.pid); + buffer->error = -EOVERFLOW; + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + + return -EOVERFLOW; + } + + if (buffer1_len + buffer2_len) { + dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); + dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len); + + events->current_event_data_size += (buffer1_len + buffer2_len); + + if ((dmxdevfilter->params.pes.output == DMX_OUT_TS_TAP || + dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) + && events->current_event_data_size >= + dmxdevfilter->params.pes.rec_chunk_size) { + event.type = DMX_EVENT_NEW_REC_CHUNK; + event.params.recording_chunk.offset = + events->current_event_start_offset; + event.params.recording_chunk.size = + events->current_event_data_size; + + dvb_dmxdev_add_event(events, &event); + events->current_event_data_size = 0; + } + } + + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); return 0; } -static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, - const u8 *buffer2, size_t buffer2_len, - struct dmx_ts_feed *feed) -{ - struct dmxdev_filter *dmxdevfilter = feed->priv; - struct dvb_ringbuffer *buffer; - int ret; +static int dvb_dmxdev_section_event_cb(struct dmx_section_filter *filter, + struct dmx_data_ready *dmx_data_ready) +{ + int res = 0; + struct dmxdev_filter *dmxdevfilter = filter->priv; + struct dmx_filter_event event; + ssize_t free; + + if (!dmxdevfilter) { + pr_err("%s: null filter. event type=%d (length=%d) will be discarded\n", + __func__, dmx_data_ready->status, + dmx_data_ready->data_length); + return -EINVAL; + } + + spin_lock(&dmxdevfilter->dev->lock); + + if (dmxdevfilter->buffer.error == -ETIMEDOUT || + dmxdevfilter->state != DMXDEV_STATE_GO || + dmxdevfilter->eos_state) { + spin_unlock(&dmxdevfilter->dev->lock); + return 0; + } + + if (dmx_data_ready->data_length == 0) { + if (dmx_data_ready->status == DMX_CRC_ERROR) { + /* Section was dropped due to CRC error */ + event.type = DMX_EVENT_SECTION_CRC_ERROR; + dvb_dmxdev_add_event(&dmxdevfilter->events, &event); + + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&dmxdevfilter->buffer.queue); + } else if (dmx_data_ready->status == DMX_OK_EOS) { + event.type = DMX_EVENT_EOS; + dvb_dmxdev_add_event(&dmxdevfilter->events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&dmxdevfilter->buffer.queue); + } else if (dmx_data_ready->status == DMX_OK_MARKER) { + event.type = DMX_EVENT_MARKER; + event.params.marker.id = dmx_data_ready->marker.id; + dvb_dmxdev_add_event(&dmxdevfilter->events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&dmxdevfilter->buffer.queue); + } else if (dmx_data_ready->status == DMX_OK_SCRAMBLING_STATUS) { + event.type = DMX_EVENT_SCRAMBLING_STATUS_CHANGE; + event.params.scrambling_status = + dmx_data_ready->scrambling_bits; + dvb_dmxdev_add_event(&dmxdevfilter->events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&dmxdevfilter->buffer.queue); + } else if (dmx_data_ready->status == DMX_OVERRUN_ERROR) { + pr_debug("dmxdev: section filter overflow (pid=%u)\n", + dmxdevfilter->params.sec.pid); + /* Set buffer error to notify user overflow occurred */ + dmxdevfilter->buffer.error = -EOVERFLOW; + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&dmxdevfilter->buffer.queue); + } else { + spin_unlock(&dmxdevfilter->dev->lock); + } + return 0; + } + + event.type = DMX_EVENT_NEW_SECTION; + event.params.section.base_offset = dmxdevfilter->buffer.pwrite; + event.params.section.start_offset = dmxdevfilter->buffer.pwrite; + event.params.section.total_length = dmx_data_ready->data_length; + event.params.section.actual_length = dmx_data_ready->data_length; + + if (dmx_data_ready->status == DMX_MISSED_ERROR) + event.params.section.flags = DMX_FILTER_CC_ERROR; + else + event.params.section.flags = 0; + + free = dvb_ringbuffer_free(&dmxdevfilter->buffer); + if (free < dmx_data_ready->data_length) { + pr_err("%s: invalid data length: data_length=%d > free=%zd\n", + __func__, dmx_data_ready->data_length, free); + } else { + res = dvb_dmxdev_add_event(&dmxdevfilter->events, &event); + DVB_RINGBUFFER_PUSH(&dmxdevfilter->buffer, + dmx_data_ready->data_length); + } + + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&dmxdevfilter->buffer.queue); + + return res; +} + +static int dvb_dmxdev_ts_event_cb(struct dmx_ts_feed *feed, + struct dmx_data_ready *dmx_data_ready) +{ + struct dmxdev_filter *dmxdevfilter = feed->priv; + struct dvb_ringbuffer *buffer; + struct dmxdev_events_queue *events; + struct dmx_filter_event event; + ssize_t free; + + if (!dmxdevfilter) { + pr_err("%s: null filter (feed->is_filtering=%d) event type=%d (length=%d) will be discarded\n", + __func__, feed->is_filtering, + dmx_data_ready->status, + dmx_data_ready->data_length); + return -EINVAL; + } + + spin_lock(&dmxdevfilter->dev->lock); + + if (dmxdevfilter->state != DMXDEV_STATE_GO || + dmxdevfilter->eos_state) { + spin_unlock(&dmxdevfilter->dev->lock); + return 0; + } + + if (dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) { + buffer = &dmxdevfilter->buffer; + events = &dmxdevfilter->events; + } else { + buffer = &dmxdevfilter->dev->dvr_buffer; + events = &dmxdevfilter->dev->dvr_output_events; + } + + if (!buffer->error && dmx_data_ready->status == DMX_OVERRUN_ERROR) { + pr_debug("dmxdev: %s filter buffer overflow (pid=%u)\n", + dmxdevfilter->params.pes.output == DMX_OUT_DECODER ? + "decoder" : "", + dmxdevfilter->params.pes.pid); + /* Set buffer error to notify user overflow occurred */ + buffer->error = -EOVERFLOW; + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + return 0; + } + + if (dmx_data_ready->status == DMX_OK_EOS) { + /* Report partial recording chunk */ + if ((dmxdevfilter->params.pes.output == DMX_OUT_TS_TAP || + dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) + && events->current_event_data_size) { + event.type = DMX_EVENT_NEW_REC_CHUNK; + event.params.recording_chunk.offset = + events->current_event_start_offset; + event.params.recording_chunk.size = + events->current_event_data_size; + events->current_event_start_offset = + (events->current_event_start_offset + + events->current_event_data_size) % + buffer->size; + events->current_event_data_size = 0; + dvb_dmxdev_add_event(events, &event); + } + + dmxdevfilter->eos_state = 1; + pr_debug("dmxdev: DMX_OK_EOS - entering EOS state\n"); + event.type = DMX_EVENT_EOS; + dvb_dmxdev_add_event(events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + return 0; + } + + if (dmx_data_ready->status == DMX_OK_MARKER) { + pr_debug("dmxdev: DMX_OK_MARKER - id=%llu\n", + dmx_data_ready->marker.id); + event.type = DMX_EVENT_MARKER; + event.params.marker.id = dmx_data_ready->marker.id; + dvb_dmxdev_add_event(events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + return 0; + } + + if (dmx_data_ready->status == DMX_OK_PCR) { + pr_debug("dmxdev: event callback DMX_OK_PCR\n"); + event.type = DMX_EVENT_NEW_PCR; + event.params.pcr.pcr = dmx_data_ready->pcr.pcr; + event.params.pcr.stc = dmx_data_ready->pcr.stc; + if (dmx_data_ready->pcr.disc_indicator_set) + event.params.pcr.flags = + DMX_FILTER_DISCONTINUITY_INDICATOR; + else + event.params.pcr.flags = 0; + + dvb_dmxdev_add_event(events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + return 0; + } + + if (dmx_data_ready->status == DMX_OK_IDX) { + pr_debug("dmxdev: event callback DMX_OK_IDX\n"); + event.type = DMX_EVENT_NEW_INDEX_ENTRY; + event.params.index = dmx_data_ready->idx_event; + + dvb_dmxdev_add_event(events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + return 0; + } + + if (dmx_data_ready->status == DMX_OK_SCRAMBLING_STATUS) { + event.type = DMX_EVENT_SCRAMBLING_STATUS_CHANGE; + event.params.scrambling_status = + dmx_data_ready->scrambling_bits; + dvb_dmxdev_add_event(events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + return 0; + } + + if (dmx_data_ready->status == DMX_OK_DECODER_BUF) { + event.type = DMX_EVENT_NEW_ES_DATA; + event.params.es_data.buf_handle = dmx_data_ready->buf.handle; + event.params.es_data.cookie = dmx_data_ready->buf.cookie; + event.params.es_data.offset = dmx_data_ready->buf.offset; + event.params.es_data.data_len = dmx_data_ready->buf.len; + event.params.es_data.pts_valid = dmx_data_ready->buf.pts_exists; + event.params.es_data.pts = dmx_data_ready->buf.pts; + event.params.es_data.dts_valid = dmx_data_ready->buf.dts_exists; + event.params.es_data.dts = dmx_data_ready->buf.dts; + event.params.es_data.stc = dmx_data_ready->buf.stc; + event.params.es_data.transport_error_indicator_counter = + dmx_data_ready->buf.tei_counter; + event.params.es_data.continuity_error_counter = + dmx_data_ready->buf.cont_err_counter; + event.params.es_data.ts_packets_num = + dmx_data_ready->buf.ts_packets_num; + event.params.es_data.ts_dropped_bytes = + dmx_data_ready->buf.ts_dropped_bytes; + dvb_dmxdev_add_event(events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + return 0; + } - spin_lock(&dmxdevfilter->dev->lock); if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) { spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); return 0; } - if (dmxdevfilter->params.pes.output == DMX_OUT_TAP - || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) - buffer = &dmxdevfilter->buffer; - else - buffer = &dmxdevfilter->dev->dvr_buffer; - if (buffer->error) { + free = dvb_ringbuffer_free(buffer); + if (free < dmx_data_ready->data_length) { + pr_err("%s: invalid data length: data_length=%d > free=%zd\n", + __func__, dmx_data_ready->data_length, free); + spin_unlock(&dmxdevfilter->dev->lock); - wake_up(&buffer->queue); + wake_up_all(&buffer->queue); return 0; } - ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); - if (ret == buffer1_len) - ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len); - if (ret < 0) - buffer->error = ret; + + if (dmxdevfilter->params.pes.output == DMX_OUT_TAP) { + if (dmx_data_ready->status == DMX_OK && + !events->current_event_data_size) { + events->current_event_start_offset = buffer->pwrite; + } else if (dmx_data_ready->status == DMX_OK_PES_END) { + event.type = DMX_EVENT_NEW_PES; + + event.params.pes.base_offset = + events->current_event_start_offset; + event.params.pes.start_offset = + (events->current_event_start_offset + + dmx_data_ready->pes_end.start_gap) % + buffer->size; + + event.params.pes.actual_length = + dmx_data_ready->pes_end.actual_length; + event.params.pes.total_length = + events->current_event_data_size; + + event.params.pes.flags = 0; + if (dmx_data_ready->pes_end.disc_indicator_set) + event.params.pes.flags |= + DMX_FILTER_DISCONTINUITY_INDICATOR; + if (dmx_data_ready->pes_end.pes_length_mismatch) + event.params.pes.flags |= + DMX_FILTER_PES_LENGTH_ERROR; + + event.params.pes.stc = dmx_data_ready->pes_end.stc; + event.params.pes.transport_error_indicator_counter = + dmx_data_ready->pes_end.tei_counter; + event.params.pes.continuity_error_counter = + dmx_data_ready->pes_end.cont_err_counter; + event.params.pes.ts_packets_num = + dmx_data_ready->pes_end.ts_packets_num; + + /* Do not report zero length PES */ + if (event.params.pes.total_length) + dvb_dmxdev_add_event(events, &event); + + events->current_event_data_size = 0; + } + } else if (!events->current_event_data_size) { + events->current_event_start_offset = buffer->pwrite; + } + + events->current_event_data_size += dmx_data_ready->data_length; + DVB_RINGBUFFER_PUSH(buffer, dmx_data_ready->data_length); + + if ((dmxdevfilter->params.pes.output == DMX_OUT_TS_TAP) || + (dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)) { + while (events->current_event_data_size >= + dmxdevfilter->params.pes.rec_chunk_size) { + event.type = DMX_EVENT_NEW_REC_CHUNK; + event.params.recording_chunk.offset = + events->current_event_start_offset; + event.params.recording_chunk.size = + dmxdevfilter->params.pes.rec_chunk_size; + events->current_event_data_size = + events->current_event_data_size - + dmxdevfilter->params.pes.rec_chunk_size; + events->current_event_start_offset = + (events->current_event_start_offset + + dmxdevfilter->params.pes.rec_chunk_size) % + buffer->size; + + dvb_dmxdev_add_event(events, &event); + } + } spin_unlock(&dmxdevfilter->dev->lock); - wake_up(&buffer->queue); + wake_up_all(&buffer->queue); return 0; } @@ -431,11 +3097,18 @@ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter) switch (dmxdevfilter->type) { case DMXDEV_TYPE_SEC: del_timer(&dmxdevfilter->timer); - dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec); + dmxdevfilter->feed.sec.feed->stop_filtering( + dmxdevfilter->feed.sec.feed); break; case DMXDEV_TYPE_PES: - list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) + list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) { + if (dmxdevfilter->params.pes.output == DMX_OUT_TS_TAP) { + dmxdevfilter->dev->dvr_feeds_count--; + if (!dmxdevfilter->dev->dvr_feeds_count) + dmxdevfilter->dev->dvr_feed = NULL; + } feed->ts->stop_filtering(feed->ts); + } break; default: return -EINVAL; @@ -453,7 +3126,8 @@ static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter) switch (filter->type) { case DMXDEV_TYPE_SEC: - return filter->feed.sec->start_filtering(filter->feed.sec); + return filter->feed.sec.feed->start_filtering( + filter->feed.sec.feed); case DMXDEV_TYPE_PES: list_for_each_entry(feed, &filter->feed.ts, next) { ret = feed->ts->start_filtering(feed->ts); @@ -487,7 +3161,7 @@ static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter) } filter->dev->demux->release_section_feed(dmxdev->demux, - filter->feed.sec); + filter->feed.sec.feed); return 0; } @@ -496,25 +3170,38 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) { struct dmxdev_feed *feed; struct dmx_demux *demux; + struct ts_insertion_buffer *ts_buffer; if (dmxdevfilter->state < DMXDEV_STATE_GO) return 0; switch (dmxdevfilter->type) { case DMXDEV_TYPE_SEC: - if (!dmxdevfilter->feed.sec) + if (!dmxdevfilter->feed.sec.feed) break; dvb_dmxdev_feed_stop(dmxdevfilter); if (dmxdevfilter->filter.sec) - dmxdevfilter->feed.sec-> - release_filter(dmxdevfilter->feed.sec, - dmxdevfilter->filter.sec); + dmxdevfilter->feed.sec.feed->release_filter( + dmxdevfilter->feed.sec.feed, + dmxdevfilter->filter.sec); dvb_dmxdev_feed_restart(dmxdevfilter); - dmxdevfilter->feed.sec = NULL; + dmxdevfilter->feed.sec.feed = NULL; break; case DMXDEV_TYPE_PES: dvb_dmxdev_feed_stop(dmxdevfilter); demux = dmxdevfilter->dev->demux; + + if (!list_empty(&dmxdevfilter->insertion_buffers)) { + feed = list_first_entry(&dmxdevfilter->feed.ts, + struct dmxdev_feed, next); + + list_for_each_entry(ts_buffer, + &dmxdevfilter->insertion_buffers, next) + dvb_dmxdev_cancel_ts_insertion(ts_buffer); + if (feed->ts->ts_insertion_terminate) + feed->ts->ts_insertion_terminate(feed->ts); + } + list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) { demux->release_ts_feed(demux, feed->ts); feed->ts = NULL; @@ -526,7 +3213,13 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) return -EINVAL; } - dvb_ringbuffer_flush(&dmxdevfilter->buffer); + spin_lock_irq(&dmxdevfilter->dev->lock); + dvb_dmxdev_flush_output(&dmxdevfilter->buffer, &dmxdevfilter->events); + dvb_ringbuffer_reset(&dmxdevfilter->buffer); + spin_unlock_irq(&dmxdevfilter->dev->lock); + + wake_up_all(&dmxdevfilter->buffer.queue); + return 0; } @@ -560,7 +3253,7 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, struct dmxdev_filter *filter, struct dmxdev_feed *feed) { - ktime_t timeout = 0; + ktime_t timeout = ktime_set(0, 0); struct dmx_pes_filter_params *para = &filter->params.pes; enum dmx_output otype; int ret; @@ -593,12 +3286,84 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, tsfeed = feed->ts; tsfeed->priv = filter; - ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, timeout); + if (filter->params.pes.output == DMX_OUT_TS_TAP) { + tsfeed->buffer.ringbuff = &dmxdev->dvr_buffer; + memcpy(&tsfeed->buffer.buff_dma_info, + &dmxdev->dvr_buff_dma_info, + sizeof(struct ion_dma_buff_info)); + + if (!dmxdev->dvr_feeds_count) + dmxdev->dvr_feed = filter; + dmxdev->dvr_feeds_count++; + } else if (filter->params.pes.output == DMX_OUT_DECODER) { + tsfeed->buffer.ringbuff = &filter->buffer; + tsfeed->decoder_buffers = &filter->decoder_buffers; + memcpy(&tsfeed->buffer.buff_dma_info, + &filter->buff_dma_info, + sizeof(struct ion_dma_buff_info)); + + } else { + tsfeed->buffer.ringbuff = &filter->buffer; + memcpy(&tsfeed->buffer.buff_dma_info, + &filter->buff_dma_info, + sizeof(struct ion_dma_buff_info)); + } + + if (tsfeed->data_ready_cb) { + ret = tsfeed->data_ready_cb(tsfeed, dvb_dmxdev_ts_event_cb); + + if (ret < 0) { + dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); + return ret; + } + } + + ret = tsfeed->set(tsfeed, feed->pid, + ts_type, ts_pes, + filter->decoder_buffers.buffers_size, + timeout); if (ret < 0) { dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); return ret; } + if (tsfeed->set_tsp_out_format) + tsfeed->set_tsp_out_format(tsfeed, filter->dmx_tsp_format); + + if (tsfeed->set_secure_mode) + tsfeed->set_secure_mode(tsfeed, &filter->sec_mode); + + if (tsfeed->set_cipher_ops) + tsfeed->set_cipher_ops(tsfeed, &feed->cipher_ops); + + if ((para->pes_type == DMX_PES_VIDEO0) || + (para->pes_type == DMX_PES_VIDEO1) || + (para->pes_type == DMX_PES_VIDEO2) || + (para->pes_type == DMX_PES_VIDEO3)) { + if (tsfeed->set_video_codec) { + ret = tsfeed->set_video_codec(tsfeed, + para->video_codec); + + if (ret < 0) { + dmxdev->demux->release_ts_feed(dmxdev->demux, + tsfeed); + return ret; + } + } + } + + if ((filter->params.pes.output == DMX_OUT_TS_TAP) || + (filter->params.pes.output == DMX_OUT_TSDEMUX_TAP)) + if (tsfeed->set_idx_params) { + ret = tsfeed->set_idx_params( + tsfeed, &feed->idx_params); + if (ret) { + dmxdev->demux->release_ts_feed(dmxdev->demux, + tsfeed); + return ret; + } + } + ret = tsfeed->start_filtering(tsfeed); if (ret < 0) { dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); @@ -608,12 +3373,50 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, return 0; } +static int dvb_filter_external_buffer_only(struct dmxdev *dmxdev, + struct dmxdev_filter *filter) +{ + struct dmx_caps caps; + int is_external_only; + int flags; + + /* + * For backward compatibility, default assumes that + * external only buffers are not supported. + */ + flags = 0; + if (dmxdev->demux->get_caps) { + dmxdev->demux->get_caps(dmxdev->demux, &caps); + + if (filter->type == DMXDEV_TYPE_SEC) + flags = caps.section.flags; + else if (filter->params.pes.output == DMX_OUT_DECODER) + /* For decoder filters dmxdev buffer is not required */ + flags = 0; + else if (filter->params.pes.output == DMX_OUT_TAP) + flags = caps.pes.flags; + else if (filter->dmx_tsp_format == DMX_TSP_FORMAT_188) + flags = caps.recording_188_tsp.flags; + else + flags = caps.recording_192_tsp.flags; + } + + if (!(flags & DMX_BUFFER_INTERNAL_SUPPORT) && + (flags & DMX_BUFFER_EXTERNAL_SUPPORT)) + is_external_only = 1; + else + is_external_only = 0; + + return is_external_only; +} + static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) { struct dmxdev *dmxdev = filter->dev; struct dmxdev_feed *feed; void *mem; int ret, i; + size_t tsp_size; if (filter->state < DMXDEV_STATE_SET) return -EINVAL; @@ -621,34 +3424,64 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) if (filter->state >= DMXDEV_STATE_GO) dvb_dmxdev_filter_stop(filter); + if (!dvb_filter_verify_buffer_size(filter)) + return -EINVAL; + if (!filter->buffer.data) { - mem = vmalloc(filter->buffer.size); + /* + * dmxdev buffer in decoder filters is not really used + * to exchange data with applications. Decoder buffers + * can be set using DMX_SET_DECODER_BUFFER, which + * would not update the filter->buffer.data at all. + * Therefore we should not treat this filter as + * other regular filters and should not fail here + * even if user sets the buffer in deocder + * filter as external buffer. + */ + if (filter->type == DMXDEV_TYPE_PES && + (filter->params.pes.output == DMX_OUT_DECODER || + filter->params.pes.output == DMX_OUT_TS_TAP)) + filter->buffer_mode = DMX_BUFFER_MODE_INTERNAL; + + if (!(filter->type == DMXDEV_TYPE_PES && + filter->params.pes.output == DMX_OUT_TS_TAP) && + (filter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL || + dvb_filter_external_buffer_only(dmxdev, filter))) + return -ENOMEM; + + mem = vmalloc_user(filter->buffer.size); if (!mem) return -ENOMEM; spin_lock_irq(&filter->dev->lock); filter->buffer.data = mem; spin_unlock_irq(&filter->dev->lock); + } else if ((filter->buffer_mode == DMX_BUFFER_MODE_INTERNAL) && + dvb_filter_external_buffer_only(dmxdev, filter)) { + return -ENOMEM; } - dvb_ringbuffer_flush(&filter->buffer); + filter->eos_state = 0; + + spin_lock_irq(&filter->dev->lock); + dvb_dmxdev_flush_output(&filter->buffer, &filter->events); + spin_unlock_irq(&filter->dev->lock); switch (filter->type) { case DMXDEV_TYPE_SEC: { struct dmx_sct_filter_params *para = &filter->params.sec; struct dmx_section_filter **secfilter = &filter->filter.sec; - struct dmx_section_feed **secfeed = &filter->feed.sec; + struct dmx_section_feed **secfeed = &filter->feed.sec.feed; *secfilter = NULL; *secfeed = NULL; - /* find active filter/feed with same PID */ for (i = 0; i < dmxdev->filternum; i++) { if (dmxdev->filter[i].state >= DMXDEV_STATE_GO && dmxdev->filter[i].type == DMXDEV_TYPE_SEC && dmxdev->filter[i].params.sec.pid == para->pid) { - *secfeed = dmxdev->filter[i].feed.sec; + *secfeed = dmxdev->filter[i].feed.sec.feed; break; } } @@ -656,22 +3489,44 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) /* if no feed found, try to allocate new one */ if (!*secfeed) { ret = dmxdev->demux->allocate_section_feed(dmxdev->demux, - secfeed, - dvb_dmxdev_section_callback); + secfeed, + dvb_dmxdev_section_callback); if (ret < 0) { pr_err("DVB (%s): could not alloc feed\n", __func__); return ret; } - ret = (*secfeed)->set(*secfeed, para->pid, + if ((*secfeed)->data_ready_cb) { + ret = (*secfeed)->data_ready_cb( + *secfeed, + dvb_dmxdev_section_event_cb); + + if (ret < 0) { + pr_err( + "DVB (%s): could not set event cb\n", + __func__); + dvb_dmxdev_feed_restart(filter); + return ret; + } + } + + ret = (*secfeed)->set(*secfeed, para->pid, 32768, (para->flags & DMX_CHECK_CRC) ? 1 : 0); if (ret < 0) { pr_err("DVB (%s): could not set feed\n", - __func__); + __func__); dvb_dmxdev_feed_restart(filter); return ret; } + + if ((*secfeed)->set_secure_mode) + (*secfeed)->set_secure_mode(*secfeed, + &filter->sec_mode); + + if ((*secfeed)->set_cipher_ops) + (*secfeed)->set_cipher_ops(*secfeed, + &filter->feed.sec.cipher_ops); } else { dvb_dmxdev_feed_stop(filter); } @@ -679,12 +3534,15 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) ret = (*secfeed)->allocate_filter(*secfeed, secfilter); if (ret < 0) { dvb_dmxdev_feed_restart(filter); - filter->feed.sec->start_filtering(*secfeed); - dprintk("could not get filter\n"); + filter->feed.sec.feed->start_filtering(*secfeed); + pr_debug("could not get filter\n"); return ret; } (*secfilter)->priv = filter; + (*secfilter)->buffer.ringbuff = &filter->buffer; + memcpy(&(*secfilter)->buffer.buff_dma_info, + &filter->buff_dma_info, sizeof(struct ion_dma_buff_info)); memcpy(&((*secfilter)->filter_value[3]), &(para->filter.filter[1]), DMX_FILTER_SIZE - 1); @@ -700,8 +3558,12 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) (*secfilter)->filter_mask[2] = 0; filter->todo = 0; + filter->events.data_read_event_masked = + filter->events.event_mask.disable_mask & + DMX_EVENT_NEW_SECTION; - ret = filter->feed.sec->start_filtering(filter->feed.sec); + ret = filter->feed.sec.feed->start_filtering( + filter->feed.sec.feed); if (ret < 0) return ret; @@ -709,19 +3571,93 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) break; } case DMXDEV_TYPE_PES: + if (filter->params.pes.rec_chunk_size < + DMX_REC_BUFF_CHUNK_MIN_SIZE) + filter->params.pes.rec_chunk_size = + DMX_REC_BUFF_CHUNK_MIN_SIZE; + + if (filter->params.pes.rec_chunk_size >= + filter->buffer.size) + filter->params.pes.rec_chunk_size = + filter->buffer.size >> 2; + + /* Align rec-chunk based on output format */ + if (filter->dmx_tsp_format == DMX_TSP_FORMAT_188) + tsp_size = 188; + else + tsp_size = 192; + + filter->params.pes.rec_chunk_size /= tsp_size; + filter->params.pes.rec_chunk_size *= tsp_size; + + if (filter->params.pes.output == DMX_OUT_TS_TAP) + dmxdev->dvr_output_events.data_read_event_masked = + dmxdev->dvr_output_events.event_mask.disable_mask & + DMX_EVENT_NEW_REC_CHUNK; + else if (filter->params.pes.output == DMX_OUT_TSDEMUX_TAP) + filter->events.data_read_event_masked = + filter->events.event_mask.disable_mask & + DMX_EVENT_NEW_REC_CHUNK; + else if (filter->params.pes.output == DMX_OUT_TAP) + filter->events.data_read_event_masked = + filter->events.event_mask.disable_mask & + DMX_EVENT_NEW_PES; + else + filter->events.data_read_event_masked = 1; + + ret = 0; list_for_each_entry(feed, &filter->feed.ts, next) { ret = dvb_dmxdev_start_feed(dmxdev, filter, feed); - if (ret < 0) { - dvb_dmxdev_filter_stop(filter); - return ret; + if (ret) + break; + } + + if (!ret) + break; + + /* cleanup feeds that were started before the failure */ + list_for_each_entry(feed, &filter->feed.ts, next) { + if (!feed->ts) + continue; + feed->ts->stop_filtering(feed->ts); + dmxdev->demux->release_ts_feed(dmxdev->demux, feed->ts); + feed->ts = NULL; + + if (filter->params.pes.output == DMX_OUT_TS_TAP) { + filter->dev->dvr_feeds_count--; + if (!filter->dev->dvr_feeds_count) + filter->dev->dvr_feed = NULL; } } - break; + return ret; + default: return -EINVAL; } dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO); + + if ((filter->type == DMXDEV_TYPE_PES) && + !list_empty(&filter->insertion_buffers)) { + struct ts_insertion_buffer *ts_buffer; + + feed = list_first_entry(&filter->feed.ts, + struct dmxdev_feed, next); + + ret = 0; + if (feed->ts->ts_insertion_init) + ret = feed->ts->ts_insertion_init(feed->ts); + if (!ret) { + list_for_each_entry(ts_buffer, + &filter->insertion_buffers, next) + dvb_dmxdev_queue_ts_insertion( + ts_buffer); + } else { + pr_err("%s: ts_insertion_init failed, err %d\n", + __func__, ret); + } + } + return 0; } @@ -751,11 +3687,29 @@ static int dvb_demux_open(struct inode *inode, struct file *file) mutex_init(&dmxdevfilter->mutex); file->private_data = dmxdevfilter; + memset(&dmxdevfilter->decoder_buffers, + 0, + sizeof(dmxdevfilter->decoder_buffers)); + dmxdevfilter->decoder_buffers.buffers_size = + DMX_DEFAULT_DECODER_BUFFER_SIZE; + dmxdevfilter->buffer_mode = DMX_BUFFER_MODE_INTERNAL; + memset(&dmxdevfilter->buff_dma_info, 0, + sizeof(struct ion_dma_buff_info)); dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); + dvb_dmxdev_flush_events(&dmxdevfilter->events); + dmxdevfilter->events.event_mask.disable_mask = DMX_EVENT_NEW_ES_DATA; + dmxdevfilter->events.event_mask.no_wakeup_mask = 0; + dmxdevfilter->events.event_mask.wakeup_threshold = 1; + dmxdevfilter->type = DMXDEV_TYPE_NONE; dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); init_timer(&dmxdevfilter->timer); + dmxdevfilter->sec_mode.is_secured = 0; + + INIT_LIST_HEAD(&dmxdevfilter->insertion_buffers); + + dmxdevfilter->dmx_tsp_format = DMX_TSP_FORMAT_188; dvbdev->users++; mutex_unlock(&dmxdev->mutex); @@ -765,23 +3719,39 @@ static int dvb_demux_open(struct inode *inode, struct file *file) static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter) { + struct ts_insertion_buffer *ts_buffer, *tmp; + mutex_lock(&dmxdev->mutex); mutex_lock(&dmxdevfilter->mutex); dvb_dmxdev_filter_stop(dmxdevfilter); dvb_dmxdev_filter_reset(dmxdevfilter); + list_for_each_entry_safe(ts_buffer, tmp, + &dmxdevfilter->insertion_buffers, next) { + list_del(&ts_buffer->next); + vfree(ts_buffer->buffer); + vfree(ts_buffer); + } + if (dmxdevfilter->buffer.data) { void *mem = dmxdevfilter->buffer.data; spin_lock_irq(&dmxdev->lock); dmxdevfilter->buffer.data = NULL; spin_unlock_irq(&dmxdev->lock); - vfree(mem); + if (dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_INTERNAL) + vfree(mem); + } + + if ((dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL) && + dmxdevfilter->buff_dma_info.va) { + dmxdev->demux->unmap_buffer(dmxdev->demux, + &dmxdevfilter->buff_dma_info); } dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE); - wake_up(&dmxdevfilter->buffer.queue); + wake_up_all(&dmxdevfilter->buffer.queue); mutex_unlock(&dmxdevfilter->mutex); mutex_unlock(&dmxdev->mutex); return 0; @@ -799,6 +3769,7 @@ static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev, struct dmxdev_filter *filter, u16 pid) { struct dmxdev_feed *feed; + int ret = 0; if ((filter->type != DMXDEV_TYPE_PES) || (filter->state < DMXDEV_STATE_SET)) @@ -814,28 +3785,45 @@ static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev, return -ENOMEM; feed->pid = pid; - list_add(&feed->next, &filter->feed.ts); + feed->cipher_ops.operations_count = 0; + feed->idx_params.enable = 0; if (filter->state >= DMXDEV_STATE_GO) - return dvb_dmxdev_start_feed(dmxdev, filter, feed); + ret = dvb_dmxdev_start_feed(dmxdev, filter, feed); - return 0; + if (!ret) + list_add(&feed->next, &filter->feed.ts); + else + kfree(feed); + + return ret; } static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev, struct dmxdev_filter *filter, u16 pid) { + int feed_count; struct dmxdev_feed *feed, *tmp; if ((filter->type != DMXDEV_TYPE_PES) || (filter->state < DMXDEV_STATE_SET)) return -EINVAL; + feed_count = 0; + list_for_each_entry(tmp, &filter->feed.ts, next) + feed_count++; + + if (feed_count <= 1) + return -EINVAL; + list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) { - if ((feed->pid == pid) && (feed->ts != NULL)) { - feed->ts->stop_filtering(feed->ts); - filter->dev->demux->release_ts_feed(filter->dev->demux, - feed->ts); + if (feed->pid == pid) { + if (feed->ts != NULL) { + feed->ts->stop_filtering(feed->ts); + filter->dev->demux->release_ts_feed( + filter->dev->demux, + feed->ts); + } list_del(&feed->next); kfree(feed); } @@ -848,7 +3836,7 @@ static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter, struct dmx_sct_filter_params *params) { - dprintk("%s: PID=0x%04x, flags=%02x, timeout=%d\n", + pr_debug("function : %s, PID=0x%04x, flags=%02x, timeout=%d\n", __func__, params->pid, params->flags, params->timeout); dvb_dmxdev_filter_stop(dmxdevfilter); @@ -857,6 +3845,7 @@ static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, memcpy(&dmxdevfilter->params.sec, params, sizeof(struct dmx_sct_filter_params)); invert_mode(&dmxdevfilter->params.sec.filter); + dmxdevfilter->feed.sec.cipher_ops.operations_count = 0; dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); if (params->flags & DMX_IMMEDIATE_START) @@ -865,6 +3854,99 @@ static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, return 0; } +static int dvb_dmxdev_set_secure_mode( + struct dmxdev *dmxdev, + struct dmxdev_filter *filter, + struct dmx_secure_mode *sec_mode) +{ + if (!dmxdev || !filter || !sec_mode) + return -EINVAL; + + if (filter->state == DMXDEV_STATE_GO) { + pr_err("%s: invalid filter state\n", __func__); + return -EBUSY; + } + + pr_debug("%s: secure=%d\n", __func__, sec_mode->is_secured); + + filter->sec_mode = *sec_mode; + + return 0; +} + +static int dvb_dmxdev_set_cipher(struct dmxdev *dmxdev, + struct dmxdev_filter *filter, + struct dmx_cipher_operations *cipher_ops) +{ + struct dmxdev_feed *feed; + struct dmxdev_feed *ts_feed = NULL; + struct dmxdev_sec_feed *sec_feed = NULL; + struct dmx_caps caps; + + if (!dmxdev || !dmxdev->demux->get_caps) + return -EINVAL; + + dmxdev->demux->get_caps(dmxdev->demux, &caps); + + if (!filter || !cipher_ops || + (cipher_ops->operations_count > caps.num_cipher_ops) || + (cipher_ops->operations_count > + DMX_MAX_CIPHER_OPERATIONS_COUNT)) + return -EINVAL; + + pr_debug("%s: pid=%d, operations=%d\n", __func__, + cipher_ops->pid, cipher_ops->operations_count); + + if (filter->state < DMXDEV_STATE_SET || + filter->state > DMXDEV_STATE_GO) { + pr_err("%s: invalid filter state\n", __func__); + return -EPERM; + } + + if (!filter->sec_mode.is_secured && cipher_ops->operations_count) { + pr_err("%s: secure mode must be enabled to set cipher ops\n", + __func__); + return -EPERM; + } + + switch (filter->type) { + case DMXDEV_TYPE_PES: + list_for_each_entry(feed, &filter->feed.ts, next) { + if (feed->pid == cipher_ops->pid) { + ts_feed = feed; + ts_feed->cipher_ops = *cipher_ops; + if (filter->state == DMXDEV_STATE_GO && + ts_feed->ts->set_cipher_ops) + ts_feed->ts->set_cipher_ops( + ts_feed->ts, cipher_ops); + break; + } + } + break; + case DMXDEV_TYPE_SEC: + if (filter->params.sec.pid == cipher_ops->pid) { + sec_feed = &filter->feed.sec; + sec_feed->cipher_ops = *cipher_ops; + if (filter->state == DMXDEV_STATE_GO && + sec_feed->feed->set_cipher_ops) + sec_feed->feed->set_cipher_ops(sec_feed->feed, + cipher_ops); + } + break; + + default: + return -EINVAL; + } + + if (!ts_feed && !sec_feed) { + pr_err("%s: pid %d is undefined for this filter\n", + __func__, cipher_ops->pid); + return -EINVAL; + } + + return 0; +} + static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter, struct dmx_pes_filter_params *params) @@ -895,6 +3977,55 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev, return 0; } +static int dvb_dmxdev_set_decoder_buffer(struct dmxdev *dmxdev, + struct dmxdev_filter *filter, + struct dmx_decoder_buffers *buffs) +{ + int i; + struct dmx_decoder_buffers *dec_buffs; + struct dmx_caps caps; + + if (!dmxdev || !filter || !buffs) + return -EINVAL; + + dec_buffs = &filter->decoder_buffers; + if (!dmxdev->demux->get_caps) + return -EINVAL; + + dmxdev->demux->get_caps(dmxdev->demux, &caps); + if (!dvb_dmxdev_verify_buffer_size(buffs->buffers_size, + caps.decoder.max_size, caps.decoder.size_alignment)) + return -EINVAL; + + if ((buffs->buffers_size == 0) || + (buffs->is_linear && + ((buffs->buffers_num <= 1) || + (buffs->buffers_num > DMX_MAX_DECODER_BUFFER_NUM)))) + return -EINVAL; + + if (buffs->buffers_num == 0) { + /* Internal mode - linear buffers not supported in this mode */ + if (!(caps.decoder.flags & DMX_BUFFER_INTERNAL_SUPPORT) || + buffs->is_linear) + return -EINVAL; + } else { + /* External buffer(s) mode */ + if ((!(caps.decoder.flags & DMX_BUFFER_LINEAR_GROUP_SUPPORT) && + buffs->buffers_num > 1) || + !(caps.decoder.flags & DMX_BUFFER_EXTERNAL_SUPPORT) || + buffs->buffers_num > caps.decoder.max_buffer_num) + return -EINVAL; + + dec_buffs->is_linear = buffs->is_linear; + dec_buffs->buffers_num = buffs->buffers_num; + dec_buffs->buffers_size = buffs->buffers_size; + for (i = 0; i < dec_buffs->buffers_num; i++) + dec_buffs->handles[i] = buffs->handles[i]; + } + + return 0; +} + static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil, struct file *file, char __user *buf, size_t count, loff_t *ppos) @@ -906,7 +4037,10 @@ static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil, hcount = 3 + dfil->todo; if (hcount > count) hcount = count; - result = dvb_dmxdev_buffer_read(&dfil->buffer, + if (hcount == 0) + return done; + + result = dvb_dmxdev_buffer_read(dfil, &dfil->buffer, file->f_flags & O_NONBLOCK, buf, hcount, ppos); if (result < 0) { @@ -927,7 +4061,7 @@ static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil, } if (count > dfil->todo) count = dfil->todo; - result = dvb_dmxdev_buffer_read(&dfil->buffer, + result = dvb_dmxdev_buffer_read(dfil, &dfil->buffer, file->f_flags & O_NONBLOCK, buf, count, ppos); if (result < 0) @@ -946,12 +4080,36 @@ dvb_demux_read(struct file *file, char __user *buf, size_t count, if (mutex_lock_interruptible(&dmxdevfilter->mutex)) return -ERESTARTSYS; + if (dmxdevfilter->eos_state && + dvb_ringbuffer_empty(&dmxdevfilter->buffer)) { + mutex_unlock(&dmxdevfilter->mutex); + return 0; + } + if (dmxdevfilter->type == DMXDEV_TYPE_SEC) ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos); else - ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer, - file->f_flags & O_NONBLOCK, - buf, count, ppos); + ret = dvb_dmxdev_buffer_read(dmxdevfilter, + &dmxdevfilter->buffer, + file->f_flags & O_NONBLOCK, + buf, count, ppos); + + if (ret > 0) { + dvb_dmxdev_notify_data_read(dmxdevfilter, ret); + spin_lock_irq(&dmxdevfilter->dev->lock); + dvb_dmxdev_update_events(&dmxdevfilter->events, ret); + spin_unlock_irq(&dmxdevfilter->dev->lock); + + /* + * in PULL mode, we might be stalling on + * event queue, so need to wake-up waiters + */ + if (dmxdevfilter->dev->playback_mode == DMX_PB_MODE_PULL) + wake_up_all(&dmxdevfilter->buffer.queue); + } else if (ret == -EOVERFLOW) { + dvb_dmxdev_auto_flush_buffer(dmxdevfilter, + &dmxdevfilter->buffer); + } mutex_unlock(&dmxdevfilter->mutex); return ret; @@ -974,55 +4132,161 @@ static int dvb_demux_do_ioctl(struct file *file, mutex_unlock(&dmxdev->mutex); return -ERESTARTSYS; } - if (dmxdevfilter->state < DMXDEV_STATE_SET) - ret = -EINVAL; - else - ret = dvb_dmxdev_filter_start(dmxdevfilter); + if (dmxdevfilter->state < DMXDEV_STATE_SET) + ret = -EINVAL; + else + ret = dvb_dmxdev_filter_start(dmxdevfilter); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_STOP: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_filter_stop(dmxdevfilter); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_FILTER: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_PES_FILTER: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_BUFFER_SIZE: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_BUFFER_MODE: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_set_buffer_mode(dmxdevfilter, + *(enum dmx_buffer_mode *)parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_BUFFER: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_set_buffer(dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_GET_BUFFER_STATUS: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_get_buffer_status(dmxdevfilter, parg); mutex_unlock(&dmxdevfilter->mutex); break; - case DMX_STOP: + case DMX_RELEASE_DATA: if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { mutex_unlock(&dmxdev->mutex); return -ERESTARTSYS; } - ret = dvb_dmxdev_filter_stop(dmxdevfilter); + ret = dvb_dmxdev_release_data(dmxdevfilter, arg); mutex_unlock(&dmxdevfilter->mutex); break; - case DMX_SET_FILTER: + case DMX_GET_PES_PIDS: + if (!dmxdev->demux->get_pes_pids) { + ret = -EINVAL; + break; + } + dmxdev->demux->get_pes_pids(dmxdev->demux, parg); + break; + + case DMX_GET_CAPS: + if (!dmxdev->demux->get_caps) { + ret = -EINVAL; + break; + } + ret = dmxdev->demux->get_caps(dmxdev->demux, parg); + break; + + case DMX_SET_SOURCE: if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { mutex_unlock(&dmxdev->mutex); return -ERESTARTSYS; } - ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg); + ret = dvb_dmxdev_set_source(dmxdevfilter, parg); mutex_unlock(&dmxdevfilter->mutex); break; - case DMX_SET_PES_FILTER: + case DMX_SET_TS_PACKET_FORMAT: + if (!dmxdev->demux->set_tsp_format) { + ret = -EINVAL; + break; + } + + if (dmxdevfilter->state >= DMXDEV_STATE_GO) { + ret = -EBUSY; + break; + } + ret = dmxdev->demux->set_tsp_format( + dmxdev->demux, + *(enum dmx_tsp_format_t *)parg); + break; + + case DMX_SET_TS_OUT_FORMAT: if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { mutex_unlock(&dmxdev->mutex); return -ERESTARTSYS; } - ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg); + + ret = dvb_dmxdev_set_tsp_out_format(dmxdevfilter, + *(enum dmx_tsp_format_t *)parg); + mutex_unlock(&dmxdevfilter->mutex); break; - case DMX_SET_BUFFER_SIZE: + case DMX_SET_DECODER_BUFFER_SIZE: if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { mutex_unlock(&dmxdev->mutex); return -ERESTARTSYS; } - ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg); + + ret = dvb_dmxdev_set_decoder_buffer_size(dmxdevfilter, arg); mutex_unlock(&dmxdevfilter->mutex); break; - case DMX_GET_PES_PIDS: - if (!dmxdev->demux->get_pes_pids) { - ret = -EINVAL; - break; + case DMX_SET_PLAYBACK_MODE: + ret = dvb_dmxdev_set_playback_mode( + dmxdevfilter, + *(enum dmx_playback_mode_t *)parg); + break; + + case DMX_GET_EVENT: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; } - dmxdev->demux->get_pes_pids(dmxdev->demux, parg); + ret = dvb_dmxdev_get_event(dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); break; case DMX_GET_STC: @@ -1054,8 +4318,109 @@ static int dvb_demux_do_ioctl(struct file *file, mutex_unlock(&dmxdevfilter->mutex); break; + case DMX_SET_DECODER_BUFFER: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + ret = -ERESTARTSYS; + break; + } + ret = dvb_dmxdev_set_decoder_buffer(dmxdev, dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_SECURE_MODE: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + ret = -ERESTARTSYS; + break; + } + ret = dvb_dmxdev_set_secure_mode(dmxdev, dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_CIPHER: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + ret = -ERESTARTSYS; + break; + } + ret = dvb_dmxdev_set_cipher(dmxdev, dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_REUSE_DECODER_BUFFER: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_reuse_decoder_buf(dmxdevfilter, arg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_EVENTS_MASK: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_set_event_mask(dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_GET_EVENTS_MASK: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_get_event_mask(dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_INDEXING_PARAMS: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_set_indexing_params(dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_SET_TS_INSERTION: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_set_ts_insertion(dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_ABORT_TS_INSERTION: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_abort_ts_insertion(dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_GET_SCRAMBLING_BITS: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_get_scrambling_bits(dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_FLUSH_BUFFER: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_flush_buffer(dmxdevfilter); + mutex_unlock(&dmxdevfilter->mutex); + break; + default: - ret = -ENOTTY; + pr_err("%s: unknown ioctl code (0x%x)\n", + __func__, cmd); + ret = -ENOIOCTLCMD; break; } mutex_unlock(&dmxdev->mutex); @@ -1068,13 +4433,78 @@ static long dvb_demux_ioctl(struct file *file, unsigned int cmd, return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl); } +#ifdef CONFIG_COMPAT + +struct dmx_set_ts_insertion32 { + __u32 identifier; + __u32 repetition_time; + compat_uptr_t ts_packets; + compat_size_t size; +}; + +static long dmx_set_ts_insertion32_wrapper(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret; + struct dmx_set_ts_insertion32 dmx_ts_insert32; + struct dmx_set_ts_insertion dmx_ts_insert; + + ret = copy_from_user(&dmx_ts_insert32, (void __user *)arg, + sizeof(dmx_ts_insert32)); + if (ret) { + pr_err( + "%s: copy dmx_set_ts_insertion32 from user failed, ret=%d\n", + __func__, ret); + return -EFAULT; + } + + memset(&dmx_ts_insert, 0, sizeof(dmx_ts_insert)); + dmx_ts_insert.identifier = dmx_ts_insert32.identifier; + dmx_ts_insert.repetition_time = dmx_ts_insert32.repetition_time; + dmx_ts_insert.ts_packets = compat_ptr(dmx_ts_insert32.ts_packets); + dmx_ts_insert.size = dmx_ts_insert32.size; + + ret = dvb_demux_do_ioctl(file, DMX_SET_TS_INSERTION, &dmx_ts_insert); + + return ret; +} + +#define DMX_SET_TS_INSERTION32 _IOW('o', 70, struct dmx_set_ts_insertion32) + +/* + * compat ioctl is called whenever compatibility is required, i.e when a 32bit + * process calls an ioctl for a 64bit kernel. + */ +static long dvb_demux_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + long ret = 0; + + switch (cmd) { + case DMX_SET_TS_INSERTION32: + ret = dmx_set_ts_insertion32_wrapper(file, cmd, arg); + break; + case DMX_SET_TS_INSERTION: + pr_err("%s: 64bit ioctl code (0x%lx) used by 32bit userspace\n", + __func__, DMX_SET_TS_INSERTION); + ret = -ENOIOCTLCMD; + break; + default: + /* use regular ioctl */ + ret = dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl); + } + + return ret; +} +#endif + static unsigned int dvb_demux_poll(struct file *file, poll_table *wait) { struct dmxdev_filter *dmxdevfilter = file->private_data; unsigned int mask = 0; - if ((!dmxdevfilter) || dmxdevfilter->dev->exit) - return POLLERR; + if (!dmxdevfilter) + return -EINVAL; poll_wait(file, &dmxdevfilter->buffer.queue, wait); @@ -1083,20 +4513,80 @@ static unsigned int dvb_demux_poll(struct file *file, poll_table *wait) dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT) return 0; - if (dmxdevfilter->buffer.error) - mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); + if (dmxdevfilter->buffer.error) { + mask |= (POLLIN | POLLRDNORM | POLLERR); + if (dmxdevfilter->buffer.error == -EOVERFLOW) + mask |= POLLPRI; + } if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer)) - mask |= (POLLIN | POLLRDNORM | POLLPRI); + mask |= (POLLIN | POLLRDNORM); + + if (dmxdevfilter->events.wakeup_events_counter >= + dmxdevfilter->events.event_mask.wakeup_threshold) + mask |= POLLPRI; return mask; } +static int dvb_demux_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct dmxdev_filter *dmxdevfilter = filp->private_data; + struct dmxdev *dmxdev = dmxdevfilter->dev; + int ret; + int vma_size; + int buffer_size; + + vma_size = vma->vm_end - vma->vm_start; + + if (vma->vm_flags & VM_WRITE) + return -EINVAL; + + if (mutex_lock_interruptible(&dmxdev->mutex)) + return -ERESTARTSYS; + + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + + if ((!dmxdevfilter->buffer.data) || + (dmxdevfilter->buffer_mode == DMX_BUFFER_MODE_EXTERNAL)) { + mutex_unlock(&dmxdevfilter->mutex); + mutex_unlock(&dmxdev->mutex); + return -EINVAL; + } + + /* Make sure requested mapping is not larger than buffer size */ + buffer_size = dmxdevfilter->buffer.size + (PAGE_SIZE-1); + buffer_size = buffer_size & ~(PAGE_SIZE-1); + + if (vma_size != buffer_size) { + mutex_unlock(&dmxdevfilter->mutex); + mutex_unlock(&dmxdev->mutex); + return -EINVAL; + } + + ret = remap_vmalloc_range(vma, dmxdevfilter->buffer.data, 0); + if (ret) { + mutex_unlock(&dmxdevfilter->mutex); + mutex_unlock(&dmxdev->mutex); + return ret; + } + + vma->vm_flags |= VM_DONTDUMP; + vma->vm_flags |= VM_DONTEXPAND; + + mutex_unlock(&dmxdevfilter->mutex); + mutex_unlock(&dmxdev->mutex); + + return 0; +} + static int dvb_demux_release(struct inode *inode, struct file *file) { struct dmxdev_filter *dmxdevfilter = file->private_data; struct dmxdev *dmxdev = dmxdevfilter->dev; - int ret; ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter); @@ -1104,6 +4594,8 @@ static int dvb_demux_release(struct inode *inode, struct file *file) mutex_lock(&dmxdev->mutex); dmxdev->dvbdev->users--; if (dmxdev->dvbdev->users == 1 && dmxdev->exit == 1) { + fops_put(file->f_op); + file->f_op = NULL; mutex_unlock(&dmxdev->mutex); wake_up(&dmxdev->dvbdev->wait_queue); } else @@ -1120,6 +4612,10 @@ static const struct file_operations dvb_demux_fops = { .release = dvb_demux_release, .poll = dvb_demux_poll, .llseek = default_llseek, + .mmap = dvb_demux_mmap, +#ifdef CONFIG_COMPAT + .compat_ioctl = dvb_demux_compat_ioctl, +#endif }; static const struct dvb_device dvbdev_demux = { @@ -1145,7 +4641,40 @@ static int dvb_dvr_do_ioctl(struct file *file, switch (cmd) { case DMX_SET_BUFFER_SIZE: - ret = dvb_dvr_set_buffer_size(dmxdev, arg); + ret = dvb_dvr_set_buffer_size(dmxdev, file->f_flags, arg); + break; + + case DMX_SET_BUFFER_MODE: + ret = dvb_dvr_set_buffer_mode(dmxdev, file->f_flags, + *(enum dmx_buffer_mode *)parg); + break; + + case DMX_SET_BUFFER: + ret = dvb_dvr_set_buffer(dmxdev, file->f_flags, parg); + break; + + case DMX_GET_BUFFER_STATUS: + ret = dvb_dvr_get_buffer_status(dmxdev, file->f_flags, parg); + break; + + case DMX_RELEASE_DATA: + ret = dvb_dvr_release_data(dmxdev, file->f_flags, arg); + break; + + case DMX_FEED_DATA: + ret = dvb_dvr_feed_data(dmxdev, file->f_flags, arg); + break; + + case DMX_GET_EVENT: + ret = dvb_dvr_get_event(dmxdev, file->f_flags, parg); + break; + + case DMX_PUSH_OOB_COMMAND: + ret = dvb_dvr_push_oob_cmd(dmxdev, file->f_flags, parg); + break; + + case DMX_FLUSH_BUFFER: + ret = dvb_dvr_flush_buffer(dmxdev, file->f_flags); break; default: @@ -1157,10 +4686,18 @@ static int dvb_dvr_do_ioctl(struct file *file, } static long dvb_dvr_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) +{ + return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl); +} + +#ifdef CONFIG_COMPAT +static long dvb_dvr_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl); } +#endif static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) { @@ -1168,21 +4705,29 @@ static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) struct dmxdev *dmxdev = dvbdev->priv; unsigned int mask = 0; - dprintk("%s\n", __func__); - - if (dmxdev->exit) - return POLLERR; - - poll_wait(file, &dmxdev->dvr_buffer.queue, wait); - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - if (dmxdev->dvr_buffer.error) - mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); + poll_wait(file, &dmxdev->dvr_buffer.queue, wait); + + if (dmxdev->dvr_buffer.error) { + mask |= (POLLIN | POLLRDNORM | POLLERR); + if (dmxdev->dvr_buffer.error == -EOVERFLOW) + mask |= POLLPRI; + } if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer)) - mask |= (POLLIN | POLLRDNORM | POLLPRI); - } else - mask |= (POLLOUT | POLLWRNORM | POLLPRI); + mask |= (POLLIN | POLLRDNORM); + + if (dmxdev->dvr_output_events.wakeup_events_counter >= + dmxdev->dvr_output_events.event_mask.wakeup_threshold) + mask |= POLLPRI; + } else { + poll_wait(file, &dmxdev->dvr_input_buffer.queue, wait); + if (dmxdev->dvr_input_buffer.error) + mask |= (POLLOUT | POLLRDNORM | POLLPRI | POLLERR); + + if (dvb_ringbuffer_free(&dmxdev->dvr_input_buffer)) + mask |= (POLLOUT | POLLRDNORM | POLLPRI); + } return mask; } @@ -1191,7 +4736,11 @@ static const struct file_operations dvb_dvr_fops = { .owner = THIS_MODULE, .read = dvb_dvr_read, .write = dvb_dvr_write, + .mmap = dvb_dvr_mmap, .unlocked_ioctl = dvb_dvr_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = dvb_dvr_compat_ioctl, +#endif .open = dvb_dvr_open, .release = dvb_dvr_release, .poll = dvb_dvr_poll, @@ -1207,9 +4756,94 @@ static const struct dvb_device dvbdev_dvr = { #endif .fops = &dvb_dvr_fops }; + + +/** + * debugfs service to print active filters information. + */ +static int dvb_dmxdev_dbgfs_print(struct seq_file *s, void *p) +{ + int i; + struct dmxdev *dmxdev = s->private; + struct dmxdev_filter *filter; + int active_count = 0; + struct dmx_buffer_status buffer_status; + struct dmx_scrambling_bits scrambling_bits; + static const char * const pes_feeds[] = {"DEC", "PES", "DVR", "REC"}; + int ret; + + if (!dmxdev) + return 0; + + for (i = 0; i < dmxdev->filternum; i++) { + filter = &dmxdev->filter[i]; + if (filter->state >= DMXDEV_STATE_GO) { + active_count++; + + seq_printf(s, "filter_%02d - ", i); + + if (filter->type == DMXDEV_TYPE_SEC) { + seq_puts(s, "type: SEC, "); + seq_printf(s, "PID %04d ", + filter->params.sec.pid); + scrambling_bits.pid = filter->params.sec.pid; + } else { + seq_printf(s, "type: %s, ", + pes_feeds[filter->params.pes.output]); + seq_printf(s, "PID: %04d ", + filter->params.pes.pid); + scrambling_bits.pid = filter->params.pes.pid; + } + + dvb_dmxdev_get_scrambling_bits(filter, + &scrambling_bits); + + if (filter->type == DMXDEV_TYPE_PES && + filter->params.pes.output == DMX_OUT_TS_TAP) + ret = dvb_dvr_get_buffer_status(dmxdev, + O_RDONLY, &buffer_status); + else + ret = dvb_dmxdev_get_buffer_status(filter, + &buffer_status); + if (!ret) { + seq_printf(s, "size: %08d, ", + buffer_status.size); + seq_printf(s, "fullness: %08d, ", + buffer_status.fullness); + seq_printf(s, "error: %d, ", + buffer_status.error); + } + + seq_printf(s, "scramble: %d, ", + scrambling_bits.value); + seq_printf(s, "secured: %d\n", + filter->sec_mode.is_secured); + } + } + + if (!active_count) + seq_puts(s, "No active filters\n"); + + return 0; +} + +static int dvb_dmxdev_dbgfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, dvb_dmxdev_dbgfs_print, inode->i_private); +} + +static const struct file_operations dbgfs_filters_fops = { + .open = dvb_dmxdev_dbgfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) { int i; + struct dmx_caps caps; if (dmxdev->demux->open(dmxdev->demux) < 0) return -EUSERS; @@ -1218,8 +4852,12 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) if (!dmxdev->filter) return -ENOMEM; + dmxdev->playback_mode = DMX_PB_MODE_PUSH; + dmxdev->demux->dvr_input_protected = 0; + mutex_init(&dmxdev->mutex); spin_lock_init(&dmxdev->lock); + spin_lock_init(&dmxdev->dvr_in_lock); for (i = 0; i < dmxdev->filternum; i++) { dmxdev->filter[i].dev = dmxdev; dmxdev->filter[i].buffer.data = NULL; @@ -1233,6 +4871,19 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) dmxdev, DVB_DEVICE_DVR, dmxdev->filternum); dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192); + dvb_ringbuffer_init(&dmxdev->dvr_input_buffer, NULL, 8192); + + /* Disable auto buffer flushing if plugin does not allow it */ + if (dmxdev->demux->get_caps) { + dmxdev->demux->get_caps(dmxdev->demux, &caps); + if (!(caps.caps & DMX_CAP_AUTO_BUFFER_FLUSH)) + overflow_auto_flush = 0; + } + + if (dmxdev->demux->debugfs_demux_dir) + debugfs_create_file("filters", 0444, + dmxdev->demux->debugfs_demux_dir, dmxdev, + &dbgfs_filters_fops); return 0; } diff --git a/drivers/media/dvb-core/dmxdev.h b/drivers/media/dvb-core/dmxdev.h index 054fd4eb6192..88d17c2292c3 100644 --- a/drivers/media/dvb-core/dmxdev.h +++ b/drivers/media/dvb-core/dmxdev.h @@ -29,7 +29,7 @@ #include #include #include - +#include #include #include "dvbdev.h" @@ -53,10 +53,87 @@ enum dmxdev_state { struct dmxdev_feed { u16 pid; + struct dmx_indexing_params idx_params; + struct dmx_cipher_operations cipher_ops; struct dmx_ts_feed *ts; struct list_head next; }; +struct dmxdev_sec_feed { + struct dmx_section_feed *feed; + struct dmx_cipher_operations cipher_ops; +}; + +struct dmxdev_events_queue { + /* + * indices used to manage events queue. + * read_index advanced when relevant data is read + * from the buffer. + * notified_index is the index from which next events + * are returned. + * read_index <= notified_index <= write_index + * + * If user reads the data without getting the respective + * event first, the read/notified indices are updated + * automatically to reflect the actual data that exist + * in the buffer. + */ + u32 read_index; + u32 write_index; + u32 notified_index; + + /* Bytes read by user without having respective event in the queue */ + u32 bytes_read_no_event; + + /* internal tracking of PES and recording events */ + u32 current_event_data_size; + u32 current_event_start_offset; + + /* current setting of the events masking */ + struct dmx_events_mask event_mask; + + /* + * indicates if an event used for data-reading from demux + * filter is enabled or not. These are events on which + * user may wait for before calling read() on the demux filter. + */ + int data_read_event_masked; + + /* + * holds the current number of pending events in the + * events queue that are considered as a wake-up source + */ + u32 wakeup_events_counter; + + struct dmx_filter_event queue[DMX_EVENT_QUEUE_SIZE]; +}; + +#define DMX_MIN_INSERTION_REPETITION_TIME 25 /* in msec */ +struct ts_insertion_buffer { + /* work scheduled for insertion of this buffer */ + struct delayed_work dwork; + + struct list_head next; + + /* buffer holding TS packets for insertion */ + char *buffer; + + /* buffer size */ + size_t size; + + /* buffer ID from user */ + u32 identifier; + + /* repetition time for the buffer insertion */ + u32 repetition_time; + + /* the recording filter to which this buffer belongs */ + struct dmxdev_filter *dmxdevfilter; + + /* indication whether insertion should be aborted */ + int abort; +}; + struct dmxdev_filter { union { struct dmx_section_filter *sec; @@ -65,7 +142,7 @@ struct dmxdev_filter { union { /* list of TS and PES feeds (struct dmxdev_feed) */ struct list_head ts; - struct dmx_section_feed *sec; + struct dmxdev_sec_feed sec; } feed; union { @@ -73,19 +150,37 @@ struct dmxdev_filter { struct dmx_pes_filter_params pes; } params; + struct dmxdev_events_queue events; + enum dmxdev_type type; enum dmxdev_state state; struct dmxdev *dev; struct dvb_ringbuffer buffer; + struct ion_dma_buff_info buff_dma_info; + enum dmx_buffer_mode buffer_mode; struct mutex mutex; + /* for recording output */ + enum dmx_tsp_format_t dmx_tsp_format; + u32 rec_chunk_size; + + /* list of buffers used for insertion (struct ts_insertion_buffer) */ + struct list_head insertion_buffers; + + /* End-of-stream indication has been received */ + int eos_state; + /* only for sections */ struct timer_list timer; int todo; u8 secheader[3]; -}; + struct dmx_secure_mode sec_mode; + + /* Decoder buffer(s) related */ + struct dmx_decoder_buffers decoder_buffers; +}; struct dmxdev { struct dvb_device *dvbdev; @@ -96,18 +191,52 @@ struct dmxdev { int filternum; int capabilities; +#define DMXDEV_CAP_DUPLEX 0x01 + + enum dmx_playback_mode_t playback_mode; + dmx_source_t source; unsigned int exit:1; -#define DMXDEV_CAP_DUPLEX 1 + unsigned int dvr_in_exit:1; + unsigned int dvr_processing_input:1; + struct dmx_frontend *dvr_orig_fe; struct dvb_ringbuffer dvr_buffer; + struct ion_dma_buff_info dvr_buff_dma_info; + enum dmx_buffer_mode dvr_buffer_mode; + struct dmxdev_events_queue dvr_output_events; + struct dmxdev_filter *dvr_feed; + int dvr_feeds_count; + + struct dvb_ringbuffer dvr_input_buffer; + enum dmx_buffer_mode dvr_input_buffer_mode; + struct task_struct *dvr_input_thread; + /* DVR commands (data feed / OOB command) queue */ + struct dvb_ringbuffer dvr_cmd_buffer; + #define DVR_BUFFER_SIZE (10*188*1024) struct mutex mutex; spinlock_t lock; + spinlock_t dvr_in_lock; +}; + +enum dvr_cmd { + DVR_DATA_FEED_CMD, + DVR_OOB_CMD }; +struct dvr_command { + enum dvr_cmd type; + union { + struct dmx_oob_command oobcmd; + size_t data_feed_count; + } cmd; +}; + +#define DVR_CMDS_BUFFER_SIZE (sizeof(struct dvr_command)*500) + int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *); void dvb_dmxdev_release(struct dmxdev *dmxdev); diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index 6628f80d184f..48c670bccc99 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -17,8 +17,6 @@ * */ -#define pr_fmt(fmt) "dvb_demux: " fmt - #include #include #include @@ -29,9 +27,16 @@ #include #include #include +#include #include "dvb_demux.h" +#define NOBUFS +/* + * #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog + */ +// #define DVB_DEMUX_SECTION_LOSS_LOG + static int dvb_demux_tscheck; module_param(dvb_demux_tscheck, int, 0644); MODULE_PARM_DESC(dvb_demux_tscheck, @@ -47,13 +52,117 @@ module_param(dvb_demux_feed_err_pkts, int, 0644); MODULE_PARM_DESC(dvb_demux_feed_err_pkts, "when set to 0, drop packets with the TEI bit set (1 by default)"); -#define dprintk(fmt, arg...) \ - printk(KERN_DEBUG pr_fmt("%s: " fmt), __func__, ##arg) +/* counter advancing for each new dvb-demux device */ +static int dvb_demux_index; + +static int dvb_demux_performancecheck; +module_param(dvb_demux_performancecheck, int, 0644); +MODULE_PARM_DESC(dvb_demux_performancecheck, + "enable transport stream performance check, reported through debugfs"); + +#define dprintk_tscheck(x...) do { \ + if (dvb_demux_tscheck) \ + pr_debug_ratelimited(x); \ + } while (0) + +static const struct dvb_dmx_video_patterns mpeg2_seq_hdr = { + {0x00, 0x00, 0x01, 0xB3}, + {0xFF, 0xFF, 0xFF, 0xFF}, + 4, + DMX_IDX_MPEG_SEQ_HEADER +}; + +static const struct dvb_dmx_video_patterns mpeg2_gop = { + {0x00, 0x00, 0x01, 0xB8}, + {0xFF, 0xFF, 0xFF, 0xFF}, + 4, + DMX_IDX_MPEG_GOP +}; + +static const struct dvb_dmx_video_patterns mpeg2_iframe = { + {0x00, 0x00, 0x01, 0x00, 0x00, 0x08}, + {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38}, + 6, + DMX_IDX_MPEG_I_FRAME_START +}; + +static const struct dvb_dmx_video_patterns mpeg2_pframe = { + {0x00, 0x00, 0x01, 0x00, 0x00, 0x10}, + {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38}, + 6, + DMX_IDX_MPEG_P_FRAME_START +}; + +static const struct dvb_dmx_video_patterns mpeg2_bframe = { + {0x00, 0x00, 0x01, 0x00, 0x00, 0x18}, + {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38}, + 6, + DMX_IDX_MPEG_B_FRAME_START +}; + +static const struct dvb_dmx_video_patterns h264_sps = { + {0x00, 0x00, 0x01, 0x07}, + {0xFF, 0xFF, 0xFF, 0x1F}, + 4, + DMX_IDX_H264_SPS +}; + +static const struct dvb_dmx_video_patterns h264_pps = { + {0x00, 0x00, 0x01, 0x08}, + {0xFF, 0xFF, 0xFF, 0x1F}, + 4, + DMX_IDX_H264_PPS +}; + +static const struct dvb_dmx_video_patterns h264_idr = { + {0x00, 0x00, 0x01, 0x05, 0x80}, + {0xFF, 0xFF, 0xFF, 0x1F, 0x80}, + 5, + DMX_IDX_H264_IDR_START +}; + +static const struct dvb_dmx_video_patterns h264_non_idr = { + {0x00, 0x00, 0x01, 0x01, 0x80}, + {0xFF, 0xFF, 0xFF, 0x1F, 0x80}, + 5, + DMX_IDX_H264_NON_IDR_START +}; + +static const struct dvb_dmx_video_patterns h264_non_access_unit_del = { + {0x00, 0x00, 0x01, 0x09}, + {0xFF, 0xFF, 0xFF, 0x1F}, + 4, + DMX_IDX_H264_ACCESS_UNIT_DEL +}; + +static const struct dvb_dmx_video_patterns h264_non_sei = { + {0x00, 0x00, 0x01, 0x06}, + {0xFF, 0xFF, 0xFF, 0x1F}, + 4, + DMX_IDX_H264_SEI +}; + +static const struct dvb_dmx_video_patterns vc1_seq_hdr = { + {0x00, 0x00, 0x01, 0x0F}, + {0xFF, 0xFF, 0xFF, 0xFF}, + 4, + DMX_IDX_VC1_SEQ_HEADER +}; + +static const struct dvb_dmx_video_patterns vc1_entry_point = { + {0x00, 0x00, 0x01, 0x0E}, + {0xFF, 0xFF, 0xFF, 0xFF}, + 4, + DMX_IDX_VC1_ENTRY_POINT +}; + +static const struct dvb_dmx_video_patterns vc1_frame = { + {0x00, 0x00, 0x01, 0x0D}, + {0xFF, 0xFF, 0xFF, 0xFF}, + 4, + DMX_IDX_VC1_FRAME_START +}; -#define dprintk_tscheck(x...) do { \ - if (dvb_demux_tscheck && printk_ratelimit()) \ - dprintk(x); \ -} while (0) /****************************************************************************** * static inlined helper functions @@ -64,9 +173,9 @@ static inline u16 section_length(const u8 *buf) return 3 + ((buf[1] & 0x0f) << 8) + buf[2]; } -static inline u16 ts_pid(const u8 *buf) +static inline u8 ts_scrambling_ctrl(const u8 *buf) { - return ((buf[1] & 0x1f) << 8) + buf[2]; + return (buf[3] >> 6) & 0x3; } static inline u8 payload(const u8 *tsp) @@ -95,39 +204,358 @@ static void dvb_dmx_memcopy(struct dvb_demux_feed *f, u8 *d, const u8 *s, memcpy(d, s, len); } +static u32 dvb_dmx_calc_time_delta(ktime_t past_time) +{ + ktime_t curr_time = ktime_get(); + s64 delta_time_us = ktime_us_delta(curr_time, past_time); + + return (u32)delta_time_us; +} + /****************************************************************************** * Software filter functions ******************************************************************************/ +/* + * Check if two patterns are identical, taking mask into consideration. + * @pattern1: the first byte pattern to compare. + * @pattern2: the second byte pattern to compare. + * @mask: the bit mask to use. + * @pattern_size: the length of both patterns and the mask, in bytes. + * + * Return: 1 if patterns match, 0 otherwise. + */ +static inline int dvb_dmx_patterns_match(const u8 *pattern1, const u8 *pattern2, + const u8 *mask, size_t pattern_size) +{ + int i; + + /* + * Assumption: it is OK to access pattern1, pattern2 and mask. + * This function performs no sanity checks to keep things fast. + */ + + for (i = 0; i < pattern_size; i++) + if ((pattern1[i] & mask[i]) != (pattern2[i] & mask[i])) + return 0; + + return 1; +} + +/* + * dvb_dmx_video_pattern_search - + * search for framing patterns in a given buffer. + * + * Optimized version: first search for a common substring, e.g. 0x00 0x00 0x01. + * If this string is found, go over all the given patterns (all must start + * with this string) and search for their ending in the buffer. + * + * Assumption: the patterns we look for do not spread over more than two + * buffers. + * + * @paterns: the full patterns information to look for. + * @patterns_num: the number of patterns to look for. + * @buf: the buffer to search. + * @buf_size: the size of the buffer to search. we search the entire buffer. + * @prefix_size_masks: a bit mask (per pattern) of possible prefix sizes to use + * when searching for a pattern that started at the last buffer. + * Updated in this function for use in the next lookup. + * @results: lookup results (offset, type, used_prefix_size) per found pattern, + * up to DVB_DMX_MAX_FOUND_PATTERNS. + * + * Return: + * Number of patterns found (up to DVB_DMX_MAX_FOUND_PATTERNS). + * 0 if pattern was not found. + * error value on failure. + */ +int dvb_dmx_video_pattern_search( + const struct dvb_dmx_video_patterns + *patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM], + int patterns_num, + const u8 *buf, + size_t buf_size, + struct dvb_dmx_video_prefix_size_masks *prefix_size_masks, + struct dvb_dmx_video_patterns_results *results) +{ + int i, j; + unsigned int current_size; + u32 prefix; + int found = 0; + int start_offset = 0; + /* the starting common substring to look for */ + u8 string[] = {0x00, 0x00, 0x01}; + /* the mask for the starting string */ + u8 string_mask[] = {0xFF, 0xFF, 0xFF}; + /* the size of the starting string (in bytes) */ + size_t string_size = 3; + + if ((patterns == NULL) || (patterns_num <= 0) || (buf == NULL)) + return -EINVAL; + + memset(results, 0, sizeof(struct dvb_dmx_video_patterns_results)); + + /* + * handle prefix - disregard string, simply check all patterns, + * looking for a matching suffix at the very beginning of the buffer. + */ + for (j = 0; (j < patterns_num) && !found; j++) { + prefix = prefix_size_masks->size_mask[j]; + current_size = 32; + while (prefix) { + if (prefix & (0x1 << (current_size - 1))) { + /* + * check that we don't look further + * than buf_size boundary + */ + if ((int)(patterns[j]->size - current_size) > + buf_size) + break; + + if (current_size >= DVB_DMX_MAX_PATTERN_LEN) + break; + + if (dvb_dmx_patterns_match( + (patterns[j]->pattern + current_size), + buf, (patterns[j]->mask + current_size), + (patterns[j]->size - current_size))) { + + /* + * pattern found using prefix at the + * very beginning of the buffer, so + * offset is 0, but we already zeroed + * everything in the beginning of the + * function. that's why the next line + * is commented. + */ + /* results->info[found].offset = 0; */ + results->info[found].type = + patterns[j]->type; + results->info[found].used_prefix_size = + current_size; + found++; + /* + * save offset to start looking from + * in the buffer, to avoid reusing the + * data of a pattern we already found. + */ + start_offset = (patterns[j]->size - + current_size); + + if (found >= DVB_DMX_MAX_FOUND_PATTERNS) + goto next_prefix_lookup; + /* + * we don't want to search for the same + * pattern with several possible prefix + * sizes if we have already found it, + * so we break from the inner loop. + * since we incremented 'found', we + * will not search for additional + * patterns using a prefix - that would + * imply ambiguous patterns where one + * pattern can be included in another. + * the for loop will exit. + */ + break; + } + } + prefix &= ~(0x1 << (current_size - 1)); + current_size--; + } + } + + /* + * Search buffer for entire pattern, starting with the string. + * Note the external for loop does not execute if buf_size is + * smaller than string_size (the cast to int is required, since + * size_t is unsigned). + */ + for (i = start_offset; i < (int)(buf_size - string_size + 1); i++) { + if (dvb_dmx_patterns_match(string, (buf + i), string_mask, + string_size)) { + /* now search for patterns: */ + for (j = 0; j < patterns_num; j++) { + /* avoid overflow to next buffer */ + if ((i + patterns[j]->size) > buf_size) + continue; + + if (dvb_dmx_patterns_match( + (patterns[j]->pattern + string_size), + (buf + i + string_size), + (patterns[j]->mask + string_size), + (patterns[j]->size - string_size))) { + + results->info[found].offset = i; + results->info[found].type = + patterns[j]->type; + /* + * save offset to start next prefix + * lookup, to avoid reusing the data + * of any pattern we already found. + */ + if ((i + patterns[j]->size) > + start_offset) + start_offset = (i + + patterns[j]->size); + /* + * did not use a prefix to find this + * pattern, but we zeroed everything + * in the beginning of the function. + * So no need to zero used_prefix_size + * for results->info[found] + */ + + found++; + if (found >= DVB_DMX_MAX_FOUND_PATTERNS) + goto next_prefix_lookup; + /* + * theoretically we don't have to break + * here, but we don't want to search + * for the other matching patterns on + * the very same same place in the + * buffer. That would mean the + * (pattern & mask) combinations are + * not unique. So we break from inner + * loop and move on to the next place + * in the buffer. + */ + break; + } + } + } + } + +next_prefix_lookup: + /* check for possible prefix sizes for the next buffer */ + for (j = 0; j < patterns_num; j++) { + prefix_size_masks->size_mask[j] = 0; + for (i = 1; i < patterns[j]->size; i++) { + /* + * avoid looking outside of the buffer + * or reusing previously used data. + */ + if (i > (buf_size - start_offset)) + break; + + if (dvb_dmx_patterns_match(patterns[j]->pattern, + (buf + buf_size - i), + patterns[j]->mask, i)) { + prefix_size_masks->size_mask[j] |= + (1 << (i - 1)); + } + } + } + + return found; +} +EXPORT_SYMBOL(dvb_dmx_video_pattern_search); + +/** + * dvb_dmx_notify_section_event() - Notify demux event for all filters of a + * specified section feed. + * + * @feed: dvb_demux_feed object + * @event: demux event to notify + * @should_lock: specifies whether the function should lock the demux + * + * Caller is responsible for locking the demux properly, either by doing the + * locking itself and setting 'should_lock' to 0, or have the function do it + * by setting 'should_lock' to 1. + */ +int dvb_dmx_notify_section_event(struct dvb_demux_feed *feed, + struct dmx_data_ready *event, int should_lock) +{ + struct dvb_demux_filter *f; + + if (feed == NULL || event == NULL || feed->type != DMX_TYPE_SEC) + return -EINVAL; + + if (!should_lock && !spin_is_locked(&feed->demux->lock)) + return -EINVAL; + + if (should_lock) + spin_lock(&feed->demux->lock); + + f = feed->filter; + while (f && feed->feed.sec.is_filtering) { + feed->data_ready_cb.sec(&f->filter, event); + f = f->next; + } + + if (should_lock) + spin_unlock(&feed->demux->lock); + + return 0; +} +EXPORT_SYMBOL(dvb_dmx_notify_section_event); + +static int dvb_dmx_check_pes_end(struct dvb_demux_feed *feed) +{ + struct dmx_data_ready data; + + if (!feed->pusi_seen) + return 0; + + data.status = DMX_OK_PES_END; + data.data_length = 0; + data.pes_end.start_gap = 0; + data.pes_end.actual_length = feed->peslen; + data.pes_end.disc_indicator_set = 0; + data.pes_end.pes_length_mismatch = 0; + data.pes_end.stc = 0; + data.pes_end.tei_counter = feed->pes_tei_counter; + data.pes_end.cont_err_counter = feed->pes_cont_err_counter; + data.pes_end.ts_packets_num = feed->pes_ts_packets_num; + + return feed->data_ready_cb.ts(&feed->feed.ts, &data); +} + static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed, const u8 *buf) { int count = payload(buf); int p; -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG int ccok; u8 cc; -#endif + int ret; if (count == 0) return -1; p = 188 - count; -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG cc = buf[3] & 0x0f; - ccok = ((feed->cc + 1) & 0x0f) == cc; + if (feed->first_cc) + ccok = 1; + else + ccok = ((feed->cc + 1) & 0x0f) == cc; + + feed->first_cc = 0; feed->cc = cc; - if (!ccok) - dprintk("missed packet!\n"); -#endif - if (buf[1] & 0x40) // PUSI ? - feed->peslen = 0xfffa; + /* PUSI ? */ + if (buf[1] & 0x40) { + dvb_dmx_check_pes_end(feed); + feed->pusi_seen = 1; + feed->peslen = 0; + feed->pes_tei_counter = 0; + feed->pes_cont_err_counter = 0; + feed->pes_ts_packets_num = 0; + } + + if (feed->pusi_seen == 0) + return 0; + + ret = feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts); - feed->peslen += count; + /* Verify TS packet was copied successfully */ + if (!ret) { + feed->pes_cont_err_counter += !ccok; + feed->pes_tei_counter += (buf[1] & 0x80) ? 1 : 0; + feed->pes_ts_packets_num++; + feed->peslen += count; + } - return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts); + return ret; } static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed, @@ -166,10 +594,28 @@ static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed) return 0; if (sec->check_crc) { + ktime_t pre_crc_time = ktime_set(0, 0); + + if (dvb_demux_performancecheck) + pre_crc_time = ktime_get(); + section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0); if (section_syntax_indicator && - demux->check_crc32(feed, sec->secbuf, sec->seclen)) + demux->check_crc32(feed, sec->secbuf, sec->seclen)) { + if (dvb_demux_performancecheck) + demux->total_crc_time += + dvb_dmx_calc_time_delta(pre_crc_time); + + /* Notify on CRC error */ + feed->cb.sec(NULL, 0, NULL, 0, + &f->filter); + return -1; + } + + if (dvb_demux_performancecheck) + demux->total_crc_time += + dvb_dmx_calc_time_delta(pre_crc_time); } do { @@ -186,7 +632,7 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) { struct dmx_section_feed *sec = &feed->feed.sec; -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG +#ifdef DVB_DEMUX_SECTION_LOSS_LOG if (sec->secbufp < sec->tsfeedp) { int i, n = sec->tsfeedp - sec->secbufp; @@ -196,12 +642,12 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) * but just first and last. */ if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) { - dprintk("dvb_demux.c section ts padding loss: %d/%d\n", + pr_debug("dvb_demux.c section ts padding loss: %d/%d\n", n, sec->tsfeedp); - dprintk("dvb_demux.c pad data:"); + pr_debug("dvb_demux.c pad data:"); for (i = 0; i < n; i++) - pr_cont(" %02x", sec->secbuf[i]); - pr_cont("\n"); + pr_debug(" %02x", sec->secbuf[i]); + pr_debug("\n"); } } #endif @@ -239,8 +685,8 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, return 0; if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) { -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG - dprintk("dvb_demux.c section buffer full loss: %d/%d\n", +#ifdef DVB_DEMUX_SECTION_LOSS_LOG + pr_err("dvb_demux.c section buffer full loss: %d/%d\n", sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, DMX_MAX_SECFEED_SIZE); #endif @@ -273,9 +719,9 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, /* dump [secbuf .. secbuf+seclen) */ if (feed->pusi_seen) dvb_dmx_swfilter_section_feed(feed); -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG +#ifdef DVB_DEMUX_SECTION_LOSS_LOG else - dprintk("dvb_demux.c pusi not seen, discarding section data\n"); + pr_err("dvb_demux.c pusi not seen, discarding section data\n"); #endif sec->secbufp += seclen; /* secbufp and secbuf moving together is */ sec->secbuf += seclen; /* redundant but saves pointer arithmetic */ @@ -284,7 +730,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, return 0; } -static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, +static int dvb_dmx_swfilter_section_one_packet(struct dvb_demux_feed *feed, const u8 *buf) { u8 p, count; @@ -299,7 +745,16 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, p = 188 - count; /* payload start */ cc = buf[3] & 0x0f; - ccok = ((feed->cc + 1) & 0x0f) == cc; + if (feed->first_cc) + ccok = 1; + else + ccok = ((feed->cc + 1) & 0x0f) == cc; + + /* discard TS packets holding sections with TEI bit set */ + if (buf[1] & 0x80) + return -EINVAL; + + feed->first_cc = 0; feed->cc = cc; if (buf[3] & 0x20) { @@ -309,9 +764,9 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, } if (!ccok || dc_i) { -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG - dprintk("dvb_demux.c discontinuity detected %d bytes lost\n", - count); +#ifdef DVB_DEMUX_SECTION_LOSS_LOG + pr_err("dvb_demux.c discontinuity detected %d bytes lost\n", + count); /* * those bytes under sume circumstances will again be reported * in the following dvb_dmx_swfilter_section_new @@ -341,10 +796,9 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, dvb_dmx_swfilter_section_copy_dump(feed, after, after_len); } -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG +#ifdef DVB_DEMUX_SECTION_LOSS_LOG else if (count > 0) - dprintk("dvb_demux.c PUSI=1 but %d bytes lost\n", - count); + pr_err("dvb_demux.c PUSI=1 but %d bytes lost\n", count); #endif } else { /* PUSI=0 (is not set), no section boundary */ @@ -354,408 +808,1773 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, return 0; } -static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, - const u8 *buf) +/* + * dvb_dmx_swfilter_section_packet - wrapper for section filtering of single + * TS packet. + * + * @feed: dvb demux feed + * @buf: buffer containing the TS packet + * @should_lock: specifies demux locking semantics: if not set, proper demux + * locking is expected to have been done by the caller. + * + * Return error status + */ +int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, + const u8 *buf, int should_lock) { - switch (feed->type) { - case DMX_TYPE_TS: - if (!feed->feed.ts.is_filtering) - break; - if (feed->ts_type & TS_PACKET) { - if (feed->ts_type & TS_PAYLOAD_ONLY) - dvb_dmx_swfilter_payload(feed, buf); - else - feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts); - } - if (feed->ts_type & TS_DECODER) - if (feed->demux->write_to_decoder) - feed->demux->write_to_decoder(feed, buf, 188); - break; - - case DMX_TYPE_SEC: - if (!feed->feed.sec.is_filtering) - break; - if (dvb_dmx_swfilter_section_packet(feed, buf) < 0) - feed->feed.sec.seclen = feed->feed.sec.secbufp = 0; - break; + int ret; - default: - break; + if (!should_lock && !spin_is_locked(&feed->demux->lock)) { + pr_err("%s: demux spinlock should have been locked\n", + __func__); + return -EINVAL; } -} -#define DVR_FEED(f) \ - (((f)->type == DMX_TYPE_TS) && \ - ((f)->feed.ts.is_filtering) && \ - (((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET)) + if (should_lock) + spin_lock(&feed->demux->lock); -static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) -{ - struct dvb_demux_feed *feed; - u16 pid = ts_pid(buf); - int dvr_done = 0; + ret = dvb_dmx_swfilter_section_one_packet(feed, buf); - if (dvb_demux_speedcheck) { - ktime_t cur_time; - u64 speed_bytes, speed_timedelta; + if (should_lock) + spin_unlock(&feed->demux->lock); - demux->speed_pkts_cnt++; + return ret; +} +EXPORT_SYMBOL(dvb_dmx_swfilter_section_packet); - /* show speed every SPEED_PKTS_INTERVAL packets */ - if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) { - cur_time = ktime_get(); +static int dvb_demux_idx_event_sort(struct dmx_index_event_info *curr, + struct dmx_index_event_info *new) +{ + if (curr->match_tsp_num > new->match_tsp_num) + return 0; - if (ktime_to_ns(demux->speed_last_time) != 0) { - speed_bytes = (u64)demux->speed_pkts_cnt - * 188 * 8; - /* convert to 1024 basis */ - speed_bytes = 1000 * div64_u64(speed_bytes, - 1024); - speed_timedelta = ktime_ms_delta(cur_time, - demux->speed_last_time); - dprintk("TS speed %llu Kbits/sec \n", - div64_u64(speed_bytes, - speed_timedelta)); - } + if (curr->match_tsp_num < new->match_tsp_num) + return 1; + /* + * In case TSP numbers are equal, sort according to event type giving + * priority to PUSI events first, then RAI and finally framing events. + */ + if ((curr->type & DMX_IDX_RAI && new->type & DMX_IDX_PUSI) || + (!(curr->type & DMX_IDX_PUSI) && !(curr->type & DMX_IDX_RAI) && + new->type & (DMX_IDX_PUSI | DMX_IDX_RAI))) + return 0; - demux->speed_last_time = cur_time; - demux->speed_pkts_cnt = 0; - } + return 1; +} + +static int dvb_demux_save_idx_event(struct dvb_demux_feed *feed, + struct dmx_index_event_info *idx_event, + int traverse_from_tail) +{ + struct dmx_index_entry *idx_entry; + struct dmx_index_entry *curr_entry; + struct list_head *pos; + + /* get entry from free list */ + if (list_empty(&feed->rec_info->idx_info.free_list)) { + pr_err("%s: index free list is empty\n", __func__); + return -ENOMEM; } - if (buf[1] & 0x80) { - dprintk_tscheck("TEI detected. PID=0x%x data1=0x%x\n", - pid, buf[1]); - /* data in this packet can't be trusted - drop it unless - * module option dvb_demux_feed_err_pkts is set */ - if (!dvb_demux_feed_err_pkts) - return; - } else /* if TEI bit is set, pid may be wrong- skip pkt counter */ - if (demux->cnt_storage && dvb_demux_tscheck) { - /* check pkt counter */ - if (pid < MAX_PID) { - if (buf[3] & 0x10) - demux->cnt_storage[pid] = - (demux->cnt_storage[pid] + 1) & 0xf; + idx_entry = list_first_entry(&feed->rec_info->idx_info.free_list, + struct dmx_index_entry, next); + list_del(&idx_entry->next); - if ((buf[3] & 0xf) != demux->cnt_storage[pid]) { - dprintk_tscheck("TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n", - pid, demux->cnt_storage[pid], - buf[3] & 0xf); - demux->cnt_storage[pid] = buf[3] & 0xf; - } + idx_entry->event = *idx_event; + + pos = &feed->rec_info->idx_info.ready_list; + if (traverse_from_tail) { + list_for_each_entry_reverse(curr_entry, + &feed->rec_info->idx_info.ready_list, next) { + if (dvb_demux_idx_event_sort(&curr_entry->event, + idx_event)) { + pos = &curr_entry->next; + break; } - /* end check */ } + } else { + list_for_each_entry(curr_entry, + &feed->rec_info->idx_info.ready_list, next) { + if (!dvb_demux_idx_event_sort(&curr_entry->event, + idx_event)) { + pos = &curr_entry->next; + break; + } + } + } - list_for_each_entry(feed, &demux->feed_list, list_head) { - if ((feed->pid != pid) && (feed->pid != 0x2000)) - continue; - - /* copy each packet only once to the dvr device, even - * if a PID is in multiple filters (e.g. video + PCR) */ - if ((DVR_FEED(feed)) && (dvr_done++)) - continue; + if (traverse_from_tail) + list_add(&idx_entry->next, pos); + else + list_add_tail(&idx_entry->next, pos); - if (feed->pid == pid) - dvb_dmx_swfilter_packet_type(feed, buf); - else if (feed->pid == 0x2000) - feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts); - } + return 0; } -void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, - size_t count) +int dvb_demux_push_idx_event(struct dvb_demux_feed *feed, + struct dmx_index_event_info *idx_event, int should_lock) { - unsigned long flags; + int ret; - spin_lock_irqsave(&demux->lock, flags); + if (!should_lock && !spin_is_locked(&feed->demux->lock)) + return -EINVAL; - while (count--) { - if (buf[0] == 0x47) - dvb_dmx_swfilter_packet(demux, buf); - buf += 188; - } + if (should_lock) + spin_lock(&feed->demux->lock); + ret = dvb_demux_save_idx_event(feed, idx_event, 1); + if (should_lock) + spin_unlock(&feed->demux->lock); - spin_unlock_irqrestore(&demux->lock, flags); + return ret; } +EXPORT_SYMBOL(dvb_demux_push_idx_event); -EXPORT_SYMBOL(dvb_dmx_swfilter_packets); - -static inline int find_next_packet(const u8 *buf, int pos, size_t count, - const int pktsize) +static inline void dvb_dmx_notify_indexing(struct dvb_demux_feed *feed) { - int start = pos, lost; - - while (pos < count) { - if (buf[pos] == 0x47 || - (pktsize == 204 && buf[pos] == 0xB8)) - break; - pos++; - } - - lost = pos - start; - if (lost) { - /* This garbage is part of a valid packet? */ - int backtrack = pos - pktsize; - if (backtrack >= 0 && (buf[backtrack] == 0x47 || - (pktsize == 204 && buf[backtrack] == 0xB8))) - return backtrack; + struct dmx_data_ready dmx_data_ready; + struct dmx_index_entry *curr_entry; + struct list_head *n, *pos; + + dmx_data_ready.status = DMX_OK_IDX; + + list_for_each_safe(pos, n, &feed->rec_info->idx_info.ready_list) { + curr_entry = list_entry(pos, struct dmx_index_entry, next); + + if ((feed->rec_info->idx_info.min_pattern_tsp_num == (u64)-1) || + (curr_entry->event.match_tsp_num <= + feed->rec_info->idx_info.min_pattern_tsp_num)) { + dmx_data_ready.idx_event = curr_entry->event; + feed->data_ready_cb.ts(&feed->feed.ts, &dmx_data_ready); + list_del(&curr_entry->next); + list_add_tail(&curr_entry->next, + &feed->rec_info->idx_info.free_list); + } } - - return pos; } -/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */ -static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, - size_t count, const int pktsize) +void dvb_dmx_notify_idx_events(struct dvb_demux_feed *feed, int should_lock) { - int p = 0, i, j; - const u8 *q; - unsigned long flags; + if (!should_lock && !spin_is_locked(&feed->demux->lock)) + return; - spin_lock_irqsave(&demux->lock, flags); + if (should_lock) + spin_lock(&feed->demux->lock); + dvb_dmx_notify_indexing(feed); + if (should_lock) + spin_unlock(&feed->demux->lock); +} +EXPORT_SYMBOL(dvb_dmx_notify_idx_events); - if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */ - i = demux->tsbufp; - j = pktsize - i; - if (count < j) { - memcpy(&demux->tsbuf[i], buf, count); - demux->tsbufp += count; - goto bailout; - } - memcpy(&demux->tsbuf[i], buf, j); - if (demux->tsbuf[0] == 0x47) /* double check */ - dvb_dmx_swfilter_packet(demux, demux->tsbuf); - demux->tsbufp = 0; - p += j; +static void dvb_dmx_process_pattern_result(struct dvb_demux_feed *feed, + struct dvb_dmx_video_patterns_results *patterns, int pattern, + u64 curr_stc, u64 prev_stc, + u64 curr_match_tsp, u64 prev_match_tsp, + u64 curr_pusi_tsp, u64 prev_pusi_tsp) +{ + int mpeg_frame_start; + int h264_frame_start; + int vc1_frame_start; + int seq_start; + u64 frame_end_in_seq; + struct dmx_index_event_info idx_event; + + idx_event.pid = feed->pid; + if (patterns->info[pattern].used_prefix_size) { + idx_event.match_tsp_num = prev_match_tsp; + idx_event.last_pusi_tsp_num = prev_pusi_tsp; + idx_event.stc = prev_stc; + } else { + idx_event.match_tsp_num = curr_match_tsp; + idx_event.last_pusi_tsp_num = curr_pusi_tsp; + idx_event.stc = curr_stc; } - while (1) { - p = find_next_packet(buf, p, count, pktsize); - if (p >= count) - break; - if (count - p < pktsize) - break; + /* notify on frame-end if needed */ + if (feed->prev_frame_valid) { + if (feed->prev_frame_type & DMX_IDX_MPEG_I_FRAME_START) { + idx_event.type = DMX_IDX_MPEG_I_FRAME_END; + frame_end_in_seq = DMX_IDX_MPEG_FIRST_SEQ_FRAME_END; + } else if (feed->prev_frame_type & DMX_IDX_MPEG_P_FRAME_START) { + idx_event.type = DMX_IDX_MPEG_P_FRAME_END; + frame_end_in_seq = DMX_IDX_MPEG_FIRST_SEQ_FRAME_END; + } else if (feed->prev_frame_type & DMX_IDX_MPEG_B_FRAME_START) { + idx_event.type = DMX_IDX_MPEG_B_FRAME_END; + frame_end_in_seq = DMX_IDX_MPEG_FIRST_SEQ_FRAME_END; + } else if (feed->prev_frame_type & DMX_IDX_H264_IDR_START) { + idx_event.type = DMX_IDX_H264_IDR_END; + frame_end_in_seq = DMX_IDX_H264_FIRST_SPS_FRAME_END; + } else if (feed->prev_frame_type & DMX_IDX_H264_NON_IDR_START) { + idx_event.type = DMX_IDX_H264_NON_IDR_END; + frame_end_in_seq = DMX_IDX_H264_FIRST_SPS_FRAME_END; + } else { + idx_event.type = DMX_IDX_VC1_FRAME_END; + frame_end_in_seq = DMX_IDX_VC1_FIRST_SEQ_FRAME_END; + } - q = &buf[p]; + if (feed->idx_params.types & idx_event.type) + dvb_demux_save_idx_event(feed, &idx_event, 1); - if (pktsize == 204 && (*q == 0xB8)) { - memcpy(demux->tsbuf, q, 188); - demux->tsbuf[0] = 0x47; - q = demux->tsbuf; + if (feed->first_frame_in_seq_notified && + feed->idx_params.types & frame_end_in_seq) { + idx_event.type = frame_end_in_seq; + dvb_demux_save_idx_event(feed, &idx_event, 1); + feed->first_frame_in_seq_notified = 0; } - dvb_dmx_swfilter_packet(demux, q); - p += pktsize; } - i = count - p; - if (i) { - memcpy(demux->tsbuf, &buf[p], i); - demux->tsbufp = i; - if (pktsize == 204 && demux->tsbuf[0] == 0xB8) - demux->tsbuf[0] = 0x47; + seq_start = patterns->info[pattern].type & + (DMX_IDX_MPEG_SEQ_HEADER | DMX_IDX_H264_SPS | + DMX_IDX_VC1_SEQ_HEADER); + + /* did we find start of sequence/SPS? */ + if (seq_start) { + feed->first_frame_in_seq = 1; + feed->first_frame_in_seq_notified = 0; + feed->prev_frame_valid = 0; + idx_event.type = patterns->info[pattern].type; + if (feed->idx_params.types & idx_event.type) + dvb_demux_save_idx_event(feed, &idx_event, 1); + return; } -bailout: - spin_unlock_irqrestore(&demux->lock, flags); -} + mpeg_frame_start = patterns->info[pattern].type & + (DMX_IDX_MPEG_I_FRAME_START | + DMX_IDX_MPEG_P_FRAME_START | + DMX_IDX_MPEG_B_FRAME_START); -void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) + h264_frame_start = patterns->info[pattern].type & + (DMX_IDX_H264_IDR_START | DMX_IDX_H264_NON_IDR_START); + + vc1_frame_start = patterns->info[pattern].type & + DMX_IDX_VC1_FRAME_START; + + if (!mpeg_frame_start && !h264_frame_start && !vc1_frame_start) { + /* neither sequence nor frame, notify on the entry if needed */ + idx_event.type = patterns->info[pattern].type; + if (feed->idx_params.types & idx_event.type) + dvb_demux_save_idx_event(feed, &idx_event, 1); + feed->prev_frame_valid = 0; + return; + } + + /* notify on first frame in sequence/sps if needed */ + if (feed->first_frame_in_seq) { + feed->first_frame_in_seq = 0; + feed->first_frame_in_seq_notified = 1; + if (mpeg_frame_start) + idx_event.type = DMX_IDX_MPEG_FIRST_SEQ_FRAME_START; + else if (h264_frame_start) + idx_event.type = DMX_IDX_H264_FIRST_SPS_FRAME_START; + else + idx_event.type = DMX_IDX_VC1_FIRST_SEQ_FRAME_START; + + if (feed->idx_params.types & idx_event.type) + dvb_demux_save_idx_event(feed, &idx_event, 1); + } + + /* notify on frame start if needed */ + idx_event.type = patterns->info[pattern].type; + if (feed->idx_params.types & idx_event.type) + dvb_demux_save_idx_event(feed, &idx_event, 1); + + feed->prev_frame_valid = 1; + feed->prev_frame_type = patterns->info[pattern].type; +} + +void dvb_dmx_process_idx_pattern(struct dvb_demux_feed *feed, + struct dvb_dmx_video_patterns_results *patterns, int pattern, + u64 curr_stc, u64 prev_stc, + u64 curr_match_tsp, u64 prev_match_tsp, + u64 curr_pusi_tsp, u64 prev_pusi_tsp) +{ + spin_lock(&feed->demux->lock); + dvb_dmx_process_pattern_result(feed, + patterns, pattern, + curr_stc, prev_stc, + curr_match_tsp, prev_match_tsp, + curr_pusi_tsp, prev_pusi_tsp); + spin_unlock(&feed->demux->lock); +} +EXPORT_SYMBOL(dvb_dmx_process_idx_pattern); + +static void dvb_dmx_index(struct dvb_demux_feed *feed, + const u8 *buf, + const u8 timestamp[TIMESTAMP_LEN]) +{ + int i; + int p; + u64 stc; + int found_patterns; + int count = payload(buf); + u64 min_pattern_tsp_num; + struct dvb_demux_feed *tmp_feed; + struct dvb_demux *demux = feed->demux; + struct dmx_index_event_info idx_event; + struct dvb_dmx_video_patterns_results patterns; + + if (feed->demux->convert_ts) + feed->demux->convert_ts(feed, timestamp, &stc); + else + stc = 0; + + idx_event.pid = feed->pid; + idx_event.stc = stc; + idx_event.match_tsp_num = feed->rec_info->ts_output_count; + + /* PUSI ? */ + if (buf[1] & 0x40) { + feed->curr_pusi_tsp_num = feed->rec_info->ts_output_count; + if (feed->idx_params.types & DMX_IDX_PUSI) { + idx_event.type = DMX_IDX_PUSI; + idx_event.last_pusi_tsp_num = + feed->curr_pusi_tsp_num; + dvb_demux_save_idx_event(feed, &idx_event, 1); + } + } + + /* + * if we still did not encounter a TS packet with PUSI indication, + * we cannot report index entries yet as we need to provide + * the TS packet number with PUSI indication preceding the TS + * packet pointed by the reported index entry. + */ + if (feed->curr_pusi_tsp_num == (u64)-1) { + dvb_dmx_notify_indexing(feed); + return; + } + + if ((feed->idx_params.types & DMX_IDX_RAI) && /* index RAI? */ + (buf[3] & 0x20) && /* adaptation field exists? */ + (buf[4] > 0) && /* adaptation field len > 0 ? */ + (buf[5] & 0x40)) { /* RAI is set? */ + idx_event.type = DMX_IDX_RAI; + idx_event.last_pusi_tsp_num = + feed->curr_pusi_tsp_num; + dvb_demux_save_idx_event(feed, &idx_event, 1); + } + + /* + * if no pattern search is required, or the TS packet has no payload, + * pattern search is not executed. + */ + if (!feed->pattern_num || !count) { + dvb_dmx_notify_indexing(feed); + return; + } + + p = 188 - count; /* payload start */ + + found_patterns = + dvb_dmx_video_pattern_search(feed->patterns, + feed->pattern_num, &buf[p], count, + &feed->prefix_size, &patterns); + + for (i = 0; i < found_patterns; i++) + dvb_dmx_process_pattern_result(feed, &patterns, i, + stc, feed->prev_stc, + feed->rec_info->ts_output_count, feed->prev_tsp_num, + feed->curr_pusi_tsp_num, feed->prev_pusi_tsp_num); + + feed->prev_tsp_num = feed->rec_info->ts_output_count; + feed->prev_pusi_tsp_num = feed->curr_pusi_tsp_num; + feed->prev_stc = stc; + feed->last_pattern_tsp_num = feed->rec_info->ts_output_count; + + /* + * it is possible to have a TS packet that has a prefix of + * a video pattern but the video pattern is not identified yet + * until we get the next TS packet of that PID. When we get + * the next TS packet of that PID, pattern-search would + * detect that we have a new index entry that starts in the + * previous TS packet. + * In order to notify the user on index entries with match_tsp_num + * in ascending order, index events with match_tsp_num up to + * the last_pattern_tsp_num are notified now to the user, + * the rest can't be notified now as we might hit the above + * scenario and cause the events not to be notified with + * ascending order of match_tsp_num. + */ + if (feed->rec_info->idx_info.pattern_search_feeds_num == 1) { + /* + * optimization for case we have only one PID + * with video pattern search, in this case + * min_pattern_tsp_num is simply updated to the new + * TS packet number of the PID with pattern search. + */ + feed->rec_info->idx_info.min_pattern_tsp_num = + feed->last_pattern_tsp_num; + dvb_dmx_notify_indexing(feed); + return; + } + + /* + * if we have more than one PID with pattern search, + * min_pattern_tsp_num needs to be updated now based on + * last_pattern_tsp_num of all PIDs with pattern search. + */ + min_pattern_tsp_num = (u64)-1; + i = feed->rec_info->idx_info.pattern_search_feeds_num; + list_for_each_entry(tmp_feed, &demux->feed_list, list_head) { + if ((tmp_feed->state != DMX_STATE_GO) || + (tmp_feed->type != DMX_TYPE_TS) || + (tmp_feed->feed.ts.buffer.ringbuff != + feed->feed.ts.buffer.ringbuff)) + continue; + + if ((tmp_feed->last_pattern_tsp_num != (u64)-1) && + ((min_pattern_tsp_num == (u64)-1) || + (tmp_feed->last_pattern_tsp_num < + min_pattern_tsp_num))) + min_pattern_tsp_num = tmp_feed->last_pattern_tsp_num; + + if (tmp_feed->pattern_num) { + i--; + if (i == 0) + break; + } + } + + feed->rec_info->idx_info.min_pattern_tsp_num = min_pattern_tsp_num; + + /* notify all index entries up to min_pattern_tsp_num */ + dvb_dmx_notify_indexing(feed); +} + +static inline void dvb_dmx_swfilter_output_packet( + struct dvb_demux_feed *feed, + const u8 *buf, + const u8 timestamp[TIMESTAMP_LEN]) +{ + /* + * if we output 192 packet with timestamp at head of packet, + * output the timestamp now before the 188 TS packet + */ + if (feed->tsp_out_format == DMX_TSP_FORMAT_192_HEAD) + feed->cb.ts(timestamp, TIMESTAMP_LEN, NULL, + 0, &feed->feed.ts); + + feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts); + + /* + * if we output 192 packet with timestamp at tail of packet, + * output the timestamp now after the 188 TS packet + */ + if (feed->tsp_out_format == DMX_TSP_FORMAT_192_TAIL) + feed->cb.ts(timestamp, TIMESTAMP_LEN, NULL, + 0, &feed->feed.ts); + + if (feed->idx_params.enable) + dvb_dmx_index(feed, buf, timestamp); + + feed->rec_info->ts_output_count++; +} + +static inline void dvb_dmx_configure_decoder_fullness( + struct dvb_demux *demux, + int initialize) +{ + struct dvb_demux_feed *feed; + int j; + + for (j = 0; j < demux->feednum; j++) { + feed = &demux->feed[j]; + + if ((feed->state != DMX_STATE_GO) || + (feed->type != DMX_TYPE_TS) || + !(feed->ts_type & TS_DECODER)) + continue; + + if (initialize) { + if (demux->decoder_fullness_init) + demux->decoder_fullness_init(feed); + } else { + if (demux->decoder_fullness_abort) + demux->decoder_fullness_abort(feed); + } + } +} + +static inline int dvb_dmx_swfilter_buffer_check( + struct dvb_demux *demux, + u16 pid) +{ + int desired_space; + int ret; + struct dmx_ts_feed *ts; + struct dvb_demux_filter *f; + struct dvb_demux_feed *feed; + int was_locked; + int i, j; + + if (likely(spin_is_locked(&demux->lock))) + was_locked = 1; + else + was_locked = 0; + + /* + * Check that there's enough free space for data output. + * If there no space, wait for it (block). + * Since this function is called while spinlock + * is acquired, the lock should be released first. + * Once we get control back, lock is acquired back + * and checks that the filter is still valid. + */ + for (j = 0; j < demux->feednum; j++) { + feed = &demux->feed[j]; + + if (demux->sw_filter_abort) + return -ENODEV; + + if ((feed->state != DMX_STATE_GO) || + ((feed->pid != pid) && (feed->pid != 0x2000))) + continue; + + if (feed->secure_mode.is_secured && + !dvb_dmx_is_rec_feed(feed)) + return 0; + + if (feed->type == DMX_TYPE_TS) { + desired_space = 192; /* upper bound */ + ts = &feed->feed.ts; + + if (feed->ts_type & TS_PACKET) { + if (likely(was_locked)) + spin_unlock(&demux->lock); + + ret = demux->buffer_ctrl.ts(ts, + desired_space, 1); + + if (likely(was_locked)) + spin_lock(&demux->lock); + + if (ret < 0) + continue; + } + + if (demux->sw_filter_abort) + return -ENODEV; + + if (!ts->is_filtering) + continue; + + if ((feed->ts_type & TS_DECODER) && + (demux->decoder_fullness_wait)) { + if (likely(was_locked)) + spin_unlock(&demux->lock); + + ret = demux->decoder_fullness_wait( + feed, + desired_space); + + if (likely(was_locked)) + spin_lock(&demux->lock); + + if (ret < 0) + continue; + } + + continue; + } + + /* else - section case */ + desired_space = feed->feed.sec.tsfeedp + 188; /* upper bound */ + for (i = 0; i < demux->filternum; i++) { + if (demux->sw_filter_abort) + return -EPERM; + + if (!feed->feed.sec.is_filtering) + continue; + + f = &demux->filter[i]; + if (f->feed != feed) + continue; + + if (likely(was_locked)) + spin_unlock(&demux->lock); + + ret = demux->buffer_ctrl.sec(&f->filter, + desired_space, 1); + + if (likely(was_locked)) + spin_lock(&demux->lock); + + if (ret < 0) + break; + } + } + + return 0; +} + +static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, + const u8 *buf, const u8 timestamp[TIMESTAMP_LEN]) +{ + u16 pid = ts_pid(buf); + u8 scrambling_bits = ts_scrambling_ctrl(buf); + struct dmx_data_ready dmx_data_ready; + + /* + * Notify on scrambling status change only when we move + * from clear (0) to non-clear and vise-versa + */ + if ((scrambling_bits && !feed->scrambling_bits) || + (!scrambling_bits && feed->scrambling_bits)) { + dmx_data_ready.status = DMX_OK_SCRAMBLING_STATUS; + dmx_data_ready.data_length = 0; + dmx_data_ready.scrambling_bits.pid = pid; + dmx_data_ready.scrambling_bits.old_value = + feed->scrambling_bits; + dmx_data_ready.scrambling_bits.new_value = scrambling_bits; + + if (feed->type == DMX_TYPE_SEC) + dvb_dmx_notify_section_event(feed, &dmx_data_ready, 0); + else if (feed->feed.ts.is_filtering) + feed->data_ready_cb.ts(&feed->feed.ts, &dmx_data_ready); + } + + feed->scrambling_bits = scrambling_bits; + + switch (feed->type) { + case DMX_TYPE_TS: + if (!feed->feed.ts.is_filtering) + break; + if (feed->ts_type & TS_PACKET) { + if (feed->ts_type & TS_PAYLOAD_ONLY) { + if (!feed->secure_mode.is_secured) + dvb_dmx_swfilter_payload(feed, buf); + } else { + dvb_dmx_swfilter_output_packet(feed, + buf, timestamp); + } + } + if ((feed->ts_type & TS_DECODER) && + !feed->secure_mode.is_secured) + if (feed->demux->write_to_decoder) + feed->demux->write_to_decoder(feed, buf, 188); + break; + + case DMX_TYPE_SEC: + if (!feed->feed.sec.is_filtering || + feed->secure_mode.is_secured) + break; + if (dvb_dmx_swfilter_section_one_packet(feed, buf) < 0) + feed->feed.sec.seclen = feed->feed.sec.secbufp = 0; + break; + + default: + break; + } +} + +#define DVR_FEED(f) \ + (((f)->type == DMX_TYPE_TS) && \ + ((f)->feed.ts.is_filtering) && \ + (((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET)) + +static void dvb_dmx_swfilter_one_packet(struct dvb_demux *demux, const u8 *buf, + const u8 timestamp[TIMESTAMP_LEN]) +{ + struct dvb_demux_feed *feed; + u16 pid = ts_pid(buf); + int dvr_done = 0; + + if (dvb_demux_speedcheck) { + ktime_t cur_time; + u64 speed_bytes, speed_timedelta; + + demux->speed_pkts_cnt++; + + /* show speed every SPEED_PKTS_INTERVAL packets */ + if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) { + cur_time = ktime_get(); + + if (ktime_to_ns(demux->speed_last_time) != 0) { + speed_bytes = (u64)demux->speed_pkts_cnt + * 188 * 8; + /* convert to 1024 basis */ + speed_bytes = 1000 * div64_u64(speed_bytes, + 1024); + speed_timedelta = ktime_ms_delta(cur_time, + demux->speed_last_time); + pr_info("TS speed %llu Kbits/sec\n", + div64_u64(speed_bytes, speed_timedelta)); + } + + demux->speed_last_time = cur_time; + demux->speed_pkts_cnt = 0; + } + } + + if (buf[1] & 0x80) { + dprintk_tscheck("TEI detected. PID=0x%x data1=0x%x\n", pid, + buf[1]); + /* + * data in this packet can't be trusted - drop it unless + * module option dvb_demux_feed_err_pkts is set + */ + if (!dvb_demux_feed_err_pkts) + return; + } else /* if TEI bit is set, pid may be wrong- skip pkt counter */ + if (demux->cnt_storage && dvb_demux_tscheck) { + /* check pkt counter */ + if (pid < MAX_PID) { + if (buf[3] & 0x10) + demux->cnt_storage[pid] = + (demux->cnt_storage[pid] + 1) & + 0xf; + + if ((buf[3] & 0xf) != demux->cnt_storage[pid]) { + dprintk_tscheck( + "TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n", + pid, demux->cnt_storage[pid], + buf[3] & 0xf); + demux->cnt_storage[pid] = buf[3] & 0xf; + } + } + /* end check */ + } + + if (demux->playback_mode == DMX_PB_MODE_PULL) + if (dvb_dmx_swfilter_buffer_check(demux, pid) < 0) + return; + + list_for_each_entry(feed, &demux->feed_list, list_head) { + if ((feed->pid != pid) && (feed->pid != 0x2000)) + continue; + + /* + * copy each packet only once to the dvr device, even + * if a PID is in multiple filters (e.g. video + PCR) + */ + if ((DVR_FEED(feed)) && (dvr_done++)) + continue; + + if (feed->pid == pid) + dvb_dmx_swfilter_packet_type(feed, buf, timestamp); + else if ((feed->pid == 0x2000) && + (feed->feed.ts.is_filtering)) + dvb_dmx_swfilter_output_packet(feed, buf, timestamp); + } +} + +void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf, + const u8 timestamp[TIMESTAMP_LEN]) +{ + spin_lock(&demux->lock); + dvb_dmx_swfilter_one_packet(demux, buf, timestamp); + spin_unlock(&demux->lock); +} +EXPORT_SYMBOL(dvb_dmx_swfilter_packet); + +void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, + size_t count) +{ + ktime_t pre_time = ktime_set(0, 0); + u8 timestamp[TIMESTAMP_LEN] = {0}; + + if (dvb_demux_performancecheck) + pre_time = ktime_get(); + + spin_lock(&demux->lock); + + demux->sw_filter_abort = 0; + dvb_dmx_configure_decoder_fullness(demux, 1); + + while (count--) { + if (buf[0] == 0x47) + dvb_dmx_swfilter_one_packet(demux, buf, timestamp); + buf += 188; + } + + spin_unlock(&demux->lock); + + if (dvb_demux_performancecheck) + demux->total_process_time += dvb_dmx_calc_time_delta(pre_time); +} +EXPORT_SYMBOL(dvb_dmx_swfilter_packets); + +static inline int find_next_packet(const u8 *buf, int pos, size_t count, + const int pktsize, const int leadingbytes) +{ + int start = pos, lost; + + while (pos < count) { + if ((buf[pos] == 0x47 && !leadingbytes) || + (pktsize == 204 && buf[pos] == 0xB8) || + (pktsize == 192 && leadingbytes && + (pos+leadingbytes < count) && + buf[pos+leadingbytes] == 0x47)) + break; + pos++; + } + + lost = pos - start; + if (lost) { + /* This garbage is part of a valid packet? */ + int backtrack = pos - pktsize; + + if (backtrack >= 0 && (buf[backtrack] == 0x47 || + (pktsize == 204 && buf[backtrack] == 0xB8) || + (pktsize == 192 && + buf[backtrack+leadingbytes] == 0x47))) + return backtrack; + } + + return pos; +} + +/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */ +static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, + size_t count, const int pktsize, const int leadingbytes) +{ + int p = 0, i = 0, j = 0; + const u8 *q; + ktime_t pre_time; + u8 timestamp[TIMESTAMP_LEN]; + + if (dvb_demux_performancecheck) + pre_time = ktime_get(); + + spin_lock(&demux->lock); + + demux->sw_filter_abort = 0; + dvb_dmx_configure_decoder_fullness(demux, 1); + + if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */ + i = demux->tsbufp; + j = pktsize - i; + if (count < j) { + memcpy(&demux->tsbuf[i], buf, count); + demux->tsbufp += count; + goto bailout; + } + memcpy(&demux->tsbuf[i], buf, j); + + if (pktsize == 192) { + if (leadingbytes) + memcpy(timestamp, &demux->tsbuf[p], + TIMESTAMP_LEN); + else + memcpy(timestamp, &demux->tsbuf[188], + TIMESTAMP_LEN); + } else { + memset(timestamp, 0, TIMESTAMP_LEN); + } + + if (pktsize == 192 && + leadingbytes && + demux->tsbuf[leadingbytes] == 0x47) /* double check */ + dvb_dmx_swfilter_one_packet(demux, + demux->tsbuf + TIMESTAMP_LEN, timestamp); + else if (demux->tsbuf[0] == 0x47) /* double check */ + dvb_dmx_swfilter_one_packet(demux, + demux->tsbuf, timestamp); + demux->tsbufp = 0; + p += j; + } + + while (1) { + p = find_next_packet(buf, p, count, pktsize, leadingbytes); + + if (demux->sw_filter_abort) + goto bailout; + + if (p >= count) + break; + if (count - p < pktsize) + break; + + q = &buf[p]; + + if (pktsize == 204 && (*q == 0xB8)) { + memcpy(demux->tsbuf, q, 188); + demux->tsbuf[0] = 0x47; + q = demux->tsbuf; + } + + if (pktsize == 192) { + if (leadingbytes) { + q = &buf[p+leadingbytes]; + memcpy(timestamp, &buf[p], TIMESTAMP_LEN); + } else { + memcpy(timestamp, &buf[p+188], TIMESTAMP_LEN); + } + } else { + memset(timestamp, 0, TIMESTAMP_LEN); + } + + dvb_dmx_swfilter_one_packet(demux, q, timestamp); + p += pktsize; + } + + i = count - p; + if (i) { + memcpy(demux->tsbuf, &buf[p], i); + demux->tsbufp = i; + if (pktsize == 204 && demux->tsbuf[0] == 0xB8) + demux->tsbuf[0] = 0x47; + } + +bailout: + spin_unlock(&demux->lock); + + if (dvb_demux_performancecheck) + demux->total_process_time += dvb_dmx_calc_time_delta(pre_time); +} + +void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) +{ + _dvb_dmx_swfilter(demux, buf, count, 188, 0); +} +EXPORT_SYMBOL(dvb_dmx_swfilter); + +void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) +{ + _dvb_dmx_swfilter(demux, buf, count, 204, 0); +} +EXPORT_SYMBOL(dvb_dmx_swfilter_204); + +void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count) +{ + spin_lock(&demux->lock); + + demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts); + + spin_unlock(&demux->lock); +} +EXPORT_SYMBOL(dvb_dmx_swfilter_raw); + +void dvb_dmx_swfilter_format( + struct dvb_demux *demux, + const u8 *buf, + size_t count, + enum dmx_tsp_format_t tsp_format) +{ + switch (tsp_format) { + case DMX_TSP_FORMAT_188: + _dvb_dmx_swfilter(demux, buf, count, 188, 0); + break; + + case DMX_TSP_FORMAT_192_TAIL: + _dvb_dmx_swfilter(demux, buf, count, 192, 0); + break; + + case DMX_TSP_FORMAT_192_HEAD: + _dvb_dmx_swfilter(demux, buf, count, 192, TIMESTAMP_LEN); + break; + + case DMX_TSP_FORMAT_204: + _dvb_dmx_swfilter(demux, buf, count, 204, 0); + break; + + default: + pr_err("%s: invalid TS packet format (format=%d)\n", __func__, + tsp_format); + break; + } +} +EXPORT_SYMBOL(dvb_dmx_swfilter_format); + +static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux) +{ + int i; + + for (i = 0; i < demux->filternum; i++) + if (demux->filter[i].state == DMX_STATE_FREE) + break; + + if (i == demux->filternum) + return NULL; + + demux->filter[i].state = DMX_STATE_ALLOCATED; + + return &demux->filter[i]; +} + +static struct dvb_demux_feed *dvb_dmx_feed_alloc(struct dvb_demux *demux) +{ + int i; + + for (i = 0; i < demux->feednum; i++) + if (demux->feed[i].state == DMX_STATE_FREE) + break; + + if (i == demux->feednum) + return NULL; + + demux->feed[i].state = DMX_STATE_ALLOCATED; + + return &demux->feed[i]; +} + +const struct dvb_dmx_video_patterns *dvb_dmx_get_pattern(u64 dmx_idx_pattern) +{ + switch (dmx_idx_pattern) { + case DMX_IDX_MPEG_SEQ_HEADER: + return &mpeg2_seq_hdr; + + case DMX_IDX_MPEG_GOP: + return &mpeg2_gop; + + case DMX_IDX_MPEG_I_FRAME_START: + return &mpeg2_iframe; + + case DMX_IDX_MPEG_P_FRAME_START: + return &mpeg2_pframe; + + case DMX_IDX_MPEG_B_FRAME_START: + return &mpeg2_bframe; + + case DMX_IDX_H264_SPS: + return &h264_sps; + + case DMX_IDX_H264_PPS: + return &h264_pps; + + case DMX_IDX_H264_IDR_START: + return &h264_idr; + + case DMX_IDX_H264_NON_IDR_START: + return &h264_non_idr; + + case DMX_IDX_H264_ACCESS_UNIT_DEL: + return &h264_non_access_unit_del; + + case DMX_IDX_H264_SEI: + return &h264_non_sei; + + case DMX_IDX_VC1_SEQ_HEADER: + return &vc1_seq_hdr; + + case DMX_IDX_VC1_ENTRY_POINT: + return &vc1_entry_point; + + case DMX_IDX_VC1_FRAME_START: + return &vc1_frame; + + default: + return NULL; + } +} +EXPORT_SYMBOL(dvb_dmx_get_pattern); + +static void dvb_dmx_init_idx_state(struct dvb_demux_feed *feed) +{ + feed->prev_tsp_num = (u64)-1; + feed->curr_pusi_tsp_num = (u64)-1; + feed->prev_pusi_tsp_num = (u64)-1; + feed->prev_frame_valid = 0; + feed->first_frame_in_seq = 0; + feed->first_frame_in_seq_notified = 0; + feed->last_pattern_tsp_num = (u64)-1; + feed->pattern_num = 0; + memset(&feed->prefix_size, 0, + sizeof(struct dvb_dmx_video_prefix_size_masks)); + + if (feed->idx_params.types & + (DMX_IDX_MPEG_SEQ_HEADER | + DMX_IDX_MPEG_FIRST_SEQ_FRAME_START | + DMX_IDX_MPEG_FIRST_SEQ_FRAME_END)) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_MPEG_SEQ_HEADER); + feed->pattern_num++; + } + + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & DMX_IDX_MPEG_GOP)) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_MPEG_GOP); + feed->pattern_num++; + } + + /* MPEG2 I-frame */ + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & + (DMX_IDX_MPEG_I_FRAME_START | DMX_IDX_MPEG_I_FRAME_END | + DMX_IDX_MPEG_P_FRAME_END | DMX_IDX_MPEG_B_FRAME_END | + DMX_IDX_MPEG_FIRST_SEQ_FRAME_START | + DMX_IDX_MPEG_FIRST_SEQ_FRAME_END))) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_MPEG_I_FRAME_START); + feed->pattern_num++; + } + + /* MPEG2 P-frame */ + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & + (DMX_IDX_MPEG_P_FRAME_START | DMX_IDX_MPEG_P_FRAME_END | + DMX_IDX_MPEG_I_FRAME_END | DMX_IDX_MPEG_B_FRAME_END | + DMX_IDX_MPEG_FIRST_SEQ_FRAME_START | + DMX_IDX_MPEG_FIRST_SEQ_FRAME_END))) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_MPEG_P_FRAME_START); + feed->pattern_num++; + } + + /* MPEG2 B-frame */ + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & + (DMX_IDX_MPEG_B_FRAME_START | DMX_IDX_MPEG_B_FRAME_END | + DMX_IDX_MPEG_I_FRAME_END | DMX_IDX_MPEG_P_FRAME_END | + DMX_IDX_MPEG_FIRST_SEQ_FRAME_START | + DMX_IDX_MPEG_FIRST_SEQ_FRAME_END))) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_MPEG_B_FRAME_START); + feed->pattern_num++; + } + + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & + (DMX_IDX_H264_SPS | + DMX_IDX_H264_FIRST_SPS_FRAME_START | + DMX_IDX_H264_FIRST_SPS_FRAME_END))) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_H264_SPS); + feed->pattern_num++; + } + + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & DMX_IDX_H264_PPS)) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_H264_PPS); + feed->pattern_num++; + } + + /* H264 IDR */ + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & + (DMX_IDX_H264_IDR_START | DMX_IDX_H264_IDR_END | + DMX_IDX_H264_NON_IDR_END | + DMX_IDX_H264_FIRST_SPS_FRAME_START | + DMX_IDX_H264_FIRST_SPS_FRAME_END))) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_H264_IDR_START); + feed->pattern_num++; + } + + /* H264 non-IDR */ + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & + (DMX_IDX_H264_NON_IDR_START | DMX_IDX_H264_NON_IDR_END | + DMX_IDX_H264_IDR_END | + DMX_IDX_H264_FIRST_SPS_FRAME_START | + DMX_IDX_H264_FIRST_SPS_FRAME_END))) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_H264_NON_IDR_START); + feed->pattern_num++; + } + + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & DMX_IDX_H264_ACCESS_UNIT_DEL)) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_H264_ACCESS_UNIT_DEL); + feed->pattern_num++; + } + + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & DMX_IDX_H264_SEI)) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_H264_SEI); + feed->pattern_num++; + } + + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & + (DMX_IDX_VC1_SEQ_HEADER | + DMX_IDX_VC1_FIRST_SEQ_FRAME_START | + DMX_IDX_VC1_FIRST_SEQ_FRAME_END))) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_VC1_SEQ_HEADER); + feed->pattern_num++; + } + + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & DMX_IDX_VC1_ENTRY_POINT)) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_VC1_ENTRY_POINT); + feed->pattern_num++; + } + + /* VC1 frame */ + if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) && + (feed->idx_params.types & + (DMX_IDX_VC1_FRAME_START | DMX_IDX_VC1_FRAME_END | + DMX_IDX_VC1_FIRST_SEQ_FRAME_START | + DMX_IDX_VC1_FIRST_SEQ_FRAME_END))) { + feed->patterns[feed->pattern_num] = + dvb_dmx_get_pattern(DMX_IDX_VC1_FRAME_START); + feed->pattern_num++; + } + + if (feed->pattern_num) + feed->rec_info->idx_info.pattern_search_feeds_num++; +} + +static struct dvb_demux_rec_info *dvb_dmx_alloc_rec_info( + struct dmx_ts_feed *ts_feed) +{ + int i; + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; + struct dvb_demux_rec_info *rec_info; + struct dvb_demux_feed *tmp_feed; + + /* check if this feed share recording buffer with other active feeds */ + list_for_each_entry(tmp_feed, &demux->feed_list, list_head) { + if ((tmp_feed->state == DMX_STATE_GO) && + (tmp_feed->type == DMX_TYPE_TS) && + (tmp_feed != feed) && + (tmp_feed->feed.ts.buffer.ringbuff == + ts_feed->buffer.ringbuff)) { + /* indexing information is shared between the feeds */ + tmp_feed->rec_info->ref_count++; + return tmp_feed->rec_info; + } + } + + /* Need to allocate a new indexing info */ + for (i = 0; i < demux->feednum; i++) + if (!demux->rec_info_pool[i].ref_count) + break; + + if (i == demux->feednum) + return NULL; + + rec_info = &demux->rec_info_pool[i]; + rec_info->ref_count++; + INIT_LIST_HEAD(&rec_info->idx_info.free_list); + INIT_LIST_HEAD(&rec_info->idx_info.ready_list); + + for (i = 0; i < DMX_IDX_EVENT_QUEUE_SIZE; i++) + list_add(&rec_info->idx_info.events[i].next, + &rec_info->idx_info.free_list); + + rec_info->ts_output_count = 0; + rec_info->idx_info.min_pattern_tsp_num = (u64)-1; + rec_info->idx_info.pattern_search_feeds_num = 0; + rec_info->idx_info.indexing_feeds_num = 0; + + return rec_info; +} + +static void dvb_dmx_free_rec_info(struct dmx_ts_feed *ts_feed) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + + if (!feed->rec_info || !feed->rec_info->ref_count) { + pr_err("%s: invalid idx info state\n", __func__); + return; + } + + feed->rec_info->ref_count--; +} + +static int dvb_demux_feed_find(struct dvb_demux_feed *feed) +{ + struct dvb_demux_feed *entry; + + list_for_each_entry(entry, &feed->demux->feed_list, list_head) + if (entry == feed) + return 1; + + return 0; +} + +static void dvb_demux_feed_add(struct dvb_demux_feed *feed) +{ + spin_lock_irq(&feed->demux->lock); + if (dvb_demux_feed_find(feed)) { + pr_err("%s: feed already in list (type=%x state=%x pid=%x)\n", + __func__, feed->type, feed->state, feed->pid); + goto out; + } + + list_add(&feed->list_head, &feed->demux->feed_list); +out: + spin_unlock_irq(&feed->demux->lock); +} + +static void dvb_demux_feed_del(struct dvb_demux_feed *feed) +{ + spin_lock_irq(&feed->demux->lock); + if (!(dvb_demux_feed_find(feed))) { + pr_err("%s: feed not in list (type=%x state=%x pid=%x)\n", + __func__, feed->type, feed->state, feed->pid); + goto out; + } + + list_del(&feed->list_head); +out: + spin_unlock_irq(&feed->demux->lock); +} + +static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type, + enum dmx_ts_pes pes_type, + size_t circular_buffer_size, ktime_t timeout) { - _dvb_dmx_swfilter(demux, buf, count, 188); + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; + + if (pid > DMX_MAX_PID) + return -EINVAL; + + if (mutex_lock_interruptible(&demux->mutex)) + return -ERESTARTSYS; + + if (ts_type & TS_DECODER) { + if (pes_type >= DMX_PES_OTHER) { + mutex_unlock(&demux->mutex); + return -EINVAL; + } + + if (demux->pesfilter[pes_type] && + demux->pesfilter[pes_type] != feed) { + mutex_unlock(&demux->mutex); + return -EINVAL; + } + + demux->pesfilter[pes_type] = feed; + demux->pids[pes_type] = pid; + } + + dvb_demux_feed_add(feed); + + feed->pid = pid; + feed->buffer_size = circular_buffer_size; + feed->timeout = timeout; + feed->ts_type = ts_type; + feed->pes_type = pes_type; + + if (feed->buffer_size) { +#ifdef NOBUFS + feed->buffer = NULL; +#else + feed->buffer = vmalloc(feed->buffer_size); + if (!feed->buffer) { + mutex_unlock(&demux->mutex); + return -ENOMEM; + } +#endif + } + + feed->state = DMX_STATE_READY; + mutex_unlock(&demux->mutex); + + return 0; } -EXPORT_SYMBOL(dvb_dmx_swfilter); -void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) +static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed) { - _dvb_dmx_swfilter(demux, buf, count, 204); + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; + int ret; + + if (mutex_lock_interruptible(&demux->mutex)) + return -ERESTARTSYS; + + if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) { + mutex_unlock(&demux->mutex); + return -EINVAL; + } + + if (!demux->start_feed) { + mutex_unlock(&demux->mutex); + return -ENODEV; + } + + feed->first_cc = 1; + feed->scrambling_bits = 0; + + if ((feed->ts_type & TS_PACKET) && + !(feed->ts_type & TS_PAYLOAD_ONLY)) { + feed->rec_info = dvb_dmx_alloc_rec_info(ts_feed); + if (!feed->rec_info) { + mutex_unlock(&demux->mutex); + return -ENOMEM; + } + if (feed->idx_params.enable) { + dvb_dmx_init_idx_state(feed); + feed->rec_info->idx_info.indexing_feeds_num++; + if (demux->set_indexing) + demux->set_indexing(feed); + } + } else { + feed->pattern_num = 0; + feed->rec_info = NULL; + } + + ret = demux->start_feed(feed); + if (ret < 0) { + if ((feed->ts_type & TS_PACKET) && + !(feed->ts_type & TS_PAYLOAD_ONLY)) { + dvb_dmx_free_rec_info(ts_feed); + feed->rec_info = NULL; + } + mutex_unlock(&demux->mutex); + return ret; + } + + spin_lock_irq(&demux->lock); + ts_feed->is_filtering = 1; + feed->state = DMX_STATE_GO; + spin_unlock_irq(&demux->lock); + mutex_unlock(&demux->mutex); + + return 0; } -EXPORT_SYMBOL(dvb_dmx_swfilter_204); -void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count) +static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed) { - unsigned long flags; + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; + int ret; - spin_lock_irqsave(&demux->lock, flags); + mutex_lock(&demux->mutex); - demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts); + if (feed->state < DMX_STATE_GO) { + mutex_unlock(&demux->mutex); + return -EINVAL; + } + + if (!demux->stop_feed) { + mutex_unlock(&demux->mutex); + return -ENODEV; + } + + ret = demux->stop_feed(feed); + + spin_lock_irq(&demux->lock); + ts_feed->is_filtering = 0; + feed->state = DMX_STATE_ALLOCATED; + spin_unlock_irq(&demux->lock); + + if (feed->rec_info) { + if (feed->pattern_num) + feed->rec_info->idx_info.pattern_search_feeds_num--; + if (feed->idx_params.enable) + feed->rec_info->idx_info.indexing_feeds_num--; + dvb_dmx_free_rec_info(ts_feed); + feed->rec_info = NULL; + } - spin_unlock_irqrestore(&demux->lock, flags); + mutex_unlock(&demux->mutex); + + return ret; } -EXPORT_SYMBOL(dvb_dmx_swfilter_raw); -static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux) +static int dmx_ts_feed_decoder_buff_status(struct dmx_ts_feed *ts_feed, + struct dmx_buffer_status *dmx_buffer_status) { - int i; + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; + int ret; - for (i = 0; i < demux->filternum; i++) - if (demux->filter[i].state == DMX_STATE_FREE) - break; + mutex_lock(&demux->mutex); - if (i == demux->filternum) - return NULL; + if (feed->state < DMX_STATE_GO) { + mutex_unlock(&demux->mutex); + return -EINVAL; + } - demux->filter[i].state = DMX_STATE_ALLOCATED; + if (!demux->decoder_buffer_status) { + mutex_unlock(&demux->mutex); + return -ENODEV; + } - return &demux->filter[i]; + ret = demux->decoder_buffer_status(feed, dmx_buffer_status); + + mutex_unlock(&demux->mutex); + + return ret; } -static struct dvb_demux_feed *dvb_dmx_feed_alloc(struct dvb_demux *demux) +static int dmx_ts_feed_reuse_decoder_buffer(struct dmx_ts_feed *ts_feed, + int cookie) { - int i; + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; + int ret; - for (i = 0; i < demux->feednum; i++) - if (demux->feed[i].state == DMX_STATE_FREE) - break; + mutex_lock(&demux->mutex); - if (i == demux->feednum) - return NULL; + if (feed->state < DMX_STATE_GO) { + mutex_unlock(&demux->mutex); + return -EINVAL; + } - demux->feed[i].state = DMX_STATE_ALLOCATED; + if (!demux->reuse_decoder_buffer) { + mutex_unlock(&demux->mutex); + return -ENODEV; + } - return &demux->feed[i]; + ret = demux->reuse_decoder_buffer(feed, cookie); + + mutex_unlock(&demux->mutex); + + return ret; } -static int dvb_demux_feed_find(struct dvb_demux_feed *feed) +static int dmx_ts_feed_data_ready_cb(struct dmx_ts_feed *feed, + dmx_ts_data_ready_cb callback) { - struct dvb_demux_feed *entry; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - list_for_each_entry(entry, &feed->demux->feed_list, list_head) - if (entry == feed) - return 1; + mutex_lock(&dvbdmx->mutex); + + if (dvbdmxfeed->state == DMX_STATE_GO) { + mutex_unlock(&dvbdmx->mutex); + return -EINVAL; + } + dvbdmxfeed->data_ready_cb.ts = callback; + + mutex_unlock(&dvbdmx->mutex); return 0; } -static void dvb_demux_feed_add(struct dvb_demux_feed *feed) +static int dmx_ts_set_secure_mode(struct dmx_ts_feed *feed, + struct dmx_secure_mode *secure_mode) { - spin_lock_irq(&feed->demux->lock); - if (dvb_demux_feed_find(feed)) { - pr_err("%s: feed already in list (type=%x state=%x pid=%x)\n", - __func__, feed->type, feed->state, feed->pid); - goto out; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + + if (mutex_lock_interruptible(&dvbdmx->mutex)) + return -ERESTARTSYS; + + if (dvbdmxfeed->state == DMX_STATE_GO) { + mutex_unlock(&dvbdmx->mutex); + return -EBUSY; } - list_add(&feed->list_head, &feed->demux->feed_list); -out: - spin_unlock_irq(&feed->demux->lock); + dvbdmxfeed->secure_mode = *secure_mode; + mutex_unlock(&dvbdmx->mutex); + return 0; } -static void dvb_demux_feed_del(struct dvb_demux_feed *feed) +static int dmx_ts_set_cipher_ops(struct dmx_ts_feed *feed, + struct dmx_cipher_operations *cipher_ops) { - spin_lock_irq(&feed->demux->lock); - if (!(dvb_demux_feed_find(feed))) { - pr_err("%s: feed not in list (type=%x state=%x pid=%x)\n", - __func__, feed->type, feed->state, feed->pid); - goto out; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + int ret = 0; + + if (mutex_lock_interruptible(&dvbdmx->mutex)) + return -ERESTARTSYS; + + if ((dvbdmxfeed->state == DMX_STATE_GO) && + dvbdmx->set_cipher_op) + ret = dvbdmx->set_cipher_op(dvbdmxfeed, cipher_ops); + + if (!ret) + dvbdmxfeed->cipher_ops = *cipher_ops; + + mutex_unlock(&dvbdmx->mutex); + return ret; +} + +static int dmx_ts_set_video_codec( + struct dmx_ts_feed *ts_feed, + enum dmx_video_codec video_codec) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + + feed->video_codec = video_codec; + + return 0; +} + +static int dmx_ts_set_idx_params(struct dmx_ts_feed *ts_feed, + struct dmx_indexing_params *idx_params) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *dvbdmx = feed->demux; + int idx_enabled; + int ret = 0; + + mutex_lock(&dvbdmx->mutex); + + if ((feed->state == DMX_STATE_GO) && + !feed->rec_info) { + mutex_unlock(&dvbdmx->mutex); + return -EINVAL; + } + + idx_enabled = feed->idx_params.enable; + feed->idx_params = *idx_params; + + if (feed->state == DMX_STATE_GO) { + spin_lock_irq(&dvbdmx->lock); + if (feed->pattern_num) + feed->rec_info->idx_info.pattern_search_feeds_num--; + if (idx_enabled && !idx_params->enable) + feed->rec_info->idx_info.indexing_feeds_num--; + if (!idx_enabled && idx_params->enable) + feed->rec_info->idx_info.indexing_feeds_num++; + dvb_dmx_init_idx_state(feed); + spin_unlock_irq(&dvbdmx->lock); + + if (dvbdmx->set_indexing) + ret = dvbdmx->set_indexing(feed); + } + + mutex_unlock(&dvbdmx->mutex); + + return ret; +} + +static int dvbdmx_ts_feed_oob_cmd(struct dmx_ts_feed *ts_feed, + struct dmx_oob_command *cmd) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dmx_data_ready data; + struct dvb_demux *dvbdmx = feed->demux; + int ret = 0; + int secure_non_rec = feed->secure_mode.is_secured && + !dvb_dmx_is_rec_feed(feed); + + mutex_lock(&dvbdmx->mutex); + + if (feed->state != DMX_STATE_GO) { + mutex_unlock(&dvbdmx->mutex); + return -EINVAL; + } + + /* Decoder & non-recording secure feeds are handled by plug-in */ + if ((feed->ts_type & TS_DECODER) || secure_non_rec) { + if (feed->demux->oob_command) + ret = feed->demux->oob_command(feed, cmd); + } + + if (!(feed->ts_type & (TS_PAYLOAD_ONLY | TS_PACKET)) || + secure_non_rec) { + mutex_unlock(&dvbdmx->mutex); + return ret; + } + + data.data_length = 0; + + switch (cmd->type) { + case DMX_OOB_CMD_EOS: + if (feed->ts_type & TS_PAYLOAD_ONLY) + dvb_dmx_check_pes_end(feed); + + data.status = DMX_OK_EOS; + ret = feed->data_ready_cb.ts(&feed->feed.ts, &data); + break; + + case DMX_OOB_CMD_MARKER: + data.status = DMX_OK_MARKER; + data.marker.id = cmd->params.marker.id; + ret = feed->data_ready_cb.ts(&feed->feed.ts, &data); + break; + + default: + ret = -EINVAL; + break; } - list_del(&feed->list_head); -out: - spin_unlock_irq(&feed->demux->lock); + mutex_unlock(&dvbdmx->mutex); + return ret; } -static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type, - enum dmx_ts_pes pes_type, ktime_t timeout) +static int dvbdmx_ts_get_scrambling_bits(struct dmx_ts_feed *ts_feed, + u8 *value) { struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; struct dvb_demux *demux = feed->demux; - if (pid > DMX_MAX_PID) + spin_lock(&demux->lock); + + if (!ts_feed->is_filtering) { + spin_unlock(&demux->lock); return -EINVAL; + } - if (mutex_lock_interruptible(&demux->mutex)) - return -ERESTARTSYS; + *value = feed->scrambling_bits; + spin_unlock(&demux->lock); - if (ts_type & TS_DECODER) { - if (pes_type >= DMX_PES_OTHER) { - mutex_unlock(&demux->mutex); - return -EINVAL; - } + return 0; +} - if (demux->pesfilter[pes_type] && - demux->pesfilter[pes_type] != feed) { - mutex_unlock(&demux->mutex); - return -EINVAL; - } +static int dvbdmx_ts_insertion_insert_buffer(struct dmx_ts_feed *ts_feed, + char *data, size_t size) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; - demux->pesfilter[pes_type] = feed; - demux->pids[pes_type] = pid; + spin_lock(&demux->lock); + if (!ts_feed->is_filtering) { + spin_unlock(&demux->lock); + return 0; } - dvb_demux_feed_add(feed); - - feed->pid = pid; - feed->timeout = timeout; - feed->ts_type = ts_type; - feed->pes_type = pes_type; + feed->cb.ts(data, size, NULL, 0, ts_feed); - feed->state = DMX_STATE_READY; - mutex_unlock(&demux->mutex); + spin_unlock(&demux->lock); return 0; } -static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed) +static int dmx_ts_set_tsp_out_format( + struct dmx_ts_feed *ts_feed, + enum dmx_tsp_format_t tsp_format) { struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; - struct dvb_demux *demux = feed->demux; - int ret; + struct dvb_demux *dvbdmx = feed->demux; - if (mutex_lock_interruptible(&demux->mutex)) - return -ERESTARTSYS; + mutex_lock(&dvbdmx->mutex); - if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) { - mutex_unlock(&demux->mutex); + if (feed->state == DMX_STATE_GO) { + mutex_unlock(&dvbdmx->mutex); return -EINVAL; } - if (!demux->start_feed) { - mutex_unlock(&demux->mutex); - return -ENODEV; - } + feed->tsp_out_format = tsp_format; + mutex_unlock(&dvbdmx->mutex); + return 0; +} - if ((ret = demux->start_feed(feed)) < 0) { - mutex_unlock(&demux->mutex); - return ret; - } +/** + * dvbdmx_ts_reset_pes_state() - Reset the current PES length and PES counters + * + * @feed: dvb demux feed object + */ +void dvbdmx_ts_reset_pes_state(struct dvb_demux_feed *feed) +{ + unsigned long flags; - spin_lock_irq(&demux->lock); - ts_feed->is_filtering = 1; - feed->state = DMX_STATE_GO; - spin_unlock_irq(&demux->lock); - mutex_unlock(&demux->mutex); + /* + * Reset PES state. + * PUSI seen indication is kept so we can get partial PES. + */ + spin_lock_irqsave(&feed->demux->lock, flags); - return 0; + feed->peslen = 0; + feed->pes_tei_counter = 0; + feed->pes_cont_err_counter = 0; + feed->pes_ts_packets_num = 0; + + spin_unlock_irqrestore(&feed->demux->lock, flags); } +EXPORT_SYMBOL(dvbdmx_ts_reset_pes_state); -static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed) +static int dvbdmx_ts_flush_buffer(struct dmx_ts_feed *ts_feed, size_t length) { struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; struct dvb_demux *demux = feed->demux; - int ret; + int ret = 0; - mutex_lock(&demux->mutex); - - if (feed->state < DMX_STATE_GO) { - mutex_unlock(&demux->mutex); - return -EINVAL; - } + if (mutex_lock_interruptible(&demux->mutex)) + return -ERESTARTSYS; - if (!demux->stop_feed) { - mutex_unlock(&demux->mutex); - return -ENODEV; - } + dvbdmx_ts_reset_pes_state(feed); - ret = demux->stop_feed(feed); + if ((feed->ts_type & TS_DECODER) && demux->flush_decoder_buffer) + /* Call decoder specific flushing if one exists */ + ret = demux->flush_decoder_buffer(feed, length); - spin_lock_irq(&demux->lock); - ts_feed->is_filtering = 0; - feed->state = DMX_STATE_ALLOCATED; - spin_unlock_irq(&demux->lock); mutex_unlock(&demux->mutex); - return ret; } @@ -778,7 +2597,21 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx, feed->cb.ts = callback; feed->demux = demux; feed->pid = 0xffff; - feed->peslen = 0xfffa; + feed->peslen = 0; + feed->pes_tei_counter = 0; + feed->pes_ts_packets_num = 0; + feed->pes_cont_err_counter = 0; + feed->secure_mode.is_secured = 0; + feed->buffer = NULL; + feed->tsp_out_format = DMX_TSP_FORMAT_188; + feed->idx_params.enable = 0; + + /* default behaviour - pass first PES data even if it is + * partial PES data from previous PES that we didn't receive its header. + * Override this to 0 in your start_feed function in order to handle + * first PES differently. + */ + feed->pusi_seen = 1; (*ts_feed) = &feed->feed.ts; (*ts_feed)->parent = dmx; @@ -787,6 +2620,22 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx, (*ts_feed)->start_filtering = dmx_ts_feed_start_filtering; (*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering; (*ts_feed)->set = dmx_ts_feed_set; + (*ts_feed)->set_video_codec = dmx_ts_set_video_codec; + (*ts_feed)->set_idx_params = dmx_ts_set_idx_params; + (*ts_feed)->set_tsp_out_format = dmx_ts_set_tsp_out_format; + (*ts_feed)->get_decoder_buff_status = dmx_ts_feed_decoder_buff_status; + (*ts_feed)->reuse_decoder_buffer = dmx_ts_feed_reuse_decoder_buffer; + (*ts_feed)->data_ready_cb = dmx_ts_feed_data_ready_cb; + (*ts_feed)->notify_data_read = NULL; + (*ts_feed)->set_secure_mode = dmx_ts_set_secure_mode; + (*ts_feed)->set_cipher_ops = dmx_ts_set_cipher_ops; + (*ts_feed)->oob_command = dvbdmx_ts_feed_oob_cmd; + (*ts_feed)->get_scrambling_bits = dvbdmx_ts_get_scrambling_bits; + (*ts_feed)->ts_insertion_init = NULL; + (*ts_feed)->ts_insertion_terminate = NULL; + (*ts_feed)->ts_insertion_insert_buffer = + dvbdmx_ts_insertion_insert_buffer; + (*ts_feed)->flush_buffer = dvbdmx_ts_flush_buffer; if (!(feed->filter = dvb_dmx_filter_alloc(demux))) { feed->state = DMX_STATE_FREE; @@ -815,10 +2664,14 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, mutex_unlock(&demux->mutex); return -EINVAL; } +#ifndef NOBUFS + vfree(feed->buffer); + feed->buffer = NULL; +#endif feed->state = DMX_STATE_FREE; feed->filter->state = DMX_STATE_FREE; - + ts_feed->priv = NULL; dvb_demux_feed_del(feed); feed->pid = 0xffff; @@ -866,7 +2719,8 @@ static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed, } static int dmx_section_feed_set(struct dmx_section_feed *feed, - u16 pid, int check_crc) + u16 pid, size_t circular_buffer_size, + int check_crc) { struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; struct dvb_demux *dvbdmx = dvbdmxfeed->demux; @@ -880,8 +2734,19 @@ static int dmx_section_feed_set(struct dmx_section_feed *feed, dvb_demux_feed_add(dvbdmxfeed); dvbdmxfeed->pid = pid; + dvbdmxfeed->buffer_size = circular_buffer_size; dvbdmxfeed->feed.sec.check_crc = check_crc; +#ifdef NOBUFS + dvbdmxfeed->buffer = NULL; +#else + dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size); + if (!dvbdmxfeed->buffer) { + mutex_unlock(&dvbdmx->mutex); + return -ENOMEM; + } +#endif + dvbdmxfeed->state = DMX_STATE_READY; mutex_unlock(&dvbdmx->mutex); return 0; @@ -932,6 +2797,8 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed) dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; dvbdmxfeed->feed.sec.secbufp = 0; dvbdmxfeed->feed.sec.seclen = 0; + dvbdmxfeed->first_cc = 1; + dvbdmxfeed->scrambling_bits = 0; if (!dvbdmx->start_feed) { mutex_unlock(&dvbdmx->mutex); @@ -962,6 +2829,11 @@ static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed) mutex_lock(&dvbdmx->mutex); + if (dvbdmxfeed->state < DMX_STATE_GO) { + mutex_unlock(&dvbdmx->mutex); + return -EINVAL; + } + if (!dvbdmx->stop_feed) { mutex_unlock(&dvbdmx->mutex); return -ENODEV; @@ -978,6 +2850,66 @@ static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed) return ret; } + +static int dmx_section_feed_data_ready_cb(struct dmx_section_feed *feed, + dmx_section_data_ready_cb callback) +{ + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + + mutex_lock(&dvbdmx->mutex); + + if (dvbdmxfeed->state == DMX_STATE_GO) { + mutex_unlock(&dvbdmx->mutex); + return -EINVAL; + } + + dvbdmxfeed->data_ready_cb.sec = callback; + + mutex_unlock(&dvbdmx->mutex); + return 0; +} + +static int dmx_section_set_secure_mode(struct dmx_section_feed *feed, + struct dmx_secure_mode *secure_mode) +{ + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + + mutex_lock(&dvbdmx->mutex); + + if (dvbdmxfeed->state == DMX_STATE_GO) { + mutex_unlock(&dvbdmx->mutex); + return -EBUSY; + } + + dvbdmxfeed->secure_mode = *secure_mode; + mutex_unlock(&dvbdmx->mutex); + return 0; +} + +static int dmx_section_set_cipher_ops(struct dmx_section_feed *feed, + struct dmx_cipher_operations *cipher_ops) +{ + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + int ret = 0; + + if (mutex_lock_interruptible(&dvbdmx->mutex)) + return -ERESTARTSYS; + + if ((dvbdmxfeed->state == DMX_STATE_GO) && + dvbdmx->set_cipher_op) { + ret = dvbdmx->set_cipher_op(dvbdmxfeed, cipher_ops); + } + + if (!ret) + dvbdmxfeed->cipher_ops = *cipher_ops; + + mutex_unlock(&dvbdmx->mutex); + return ret; +} + static int dmx_section_feed_release_filter(struct dmx_section_feed *feed, struct dmx_section_filter *filter) { @@ -1011,12 +2943,82 @@ static int dmx_section_feed_release_filter(struct dmx_section_feed *feed, f->next = f->next->next; } + filter->priv = NULL; dvbdmxfilter->state = DMX_STATE_FREE; spin_unlock_irq(&dvbdmx->lock); mutex_unlock(&dvbdmx->mutex); return 0; } +static int dvbdmx_section_feed_oob_cmd(struct dmx_section_feed *section_feed, + struct dmx_oob_command *cmd) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)section_feed; + struct dvb_demux *dvbdmx = feed->demux; + struct dmx_data_ready data; + int ret = 0; + + data.data_length = 0; + + mutex_lock(&dvbdmx->mutex); + + if (feed->state != DMX_STATE_GO) { + mutex_unlock(&dvbdmx->mutex); + return -EINVAL; + } + + /* Secure section feeds are handled by the plug-in */ + if (feed->secure_mode.is_secured) { + if (feed->demux->oob_command) + ret = feed->demux->oob_command(feed, cmd); + else + ret = 0; + + mutex_unlock(&dvbdmx->mutex); + return ret; + } + + switch (cmd->type) { + case DMX_OOB_CMD_EOS: + data.status = DMX_OK_EOS; + break; + + case DMX_OOB_CMD_MARKER: + data.status = DMX_OK_MARKER; + data.marker.id = cmd->params.marker.id; + break; + + default: + ret = -EINVAL; + break; + } + + if (!ret) + ret = dvb_dmx_notify_section_event(feed, &data, 1); + + mutex_unlock(&dvbdmx->mutex); + return ret; +} + +static int dvbdmx_section_get_scrambling_bits( + struct dmx_section_feed *section_feed, u8 *value) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)section_feed; + struct dvb_demux *demux = feed->demux; + + spin_lock(&demux->lock); + + if (!section_feed->is_filtering) { + spin_unlock(&demux->lock); + return -EINVAL; + } + + *value = feed->scrambling_bits; + spin_unlock(&demux->lock); + + return 0; +} + static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, struct dmx_section_feed **feed, dmx_section_cb callback) @@ -1036,10 +3038,14 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, dvbdmxfeed->cb.sec = callback; dvbdmxfeed->demux = dvbdmx; dvbdmxfeed->pid = 0xffff; + dvbdmxfeed->secure_mode.is_secured = 0; + dvbdmxfeed->tsp_out_format = DMX_TSP_FORMAT_188; dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0; dvbdmxfeed->feed.sec.tsfeedp = 0; dvbdmxfeed->filter = NULL; + dvbdmxfeed->buffer = NULL; + dvbdmxfeed->idx_params.enable = 0; (*feed) = &dvbdmxfeed->feed.sec; (*feed)->is_filtering = 0; @@ -1051,6 +3057,13 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, (*feed)->start_filtering = dmx_section_feed_start_filtering; (*feed)->stop_filtering = dmx_section_feed_stop_filtering; (*feed)->release_filter = dmx_section_feed_release_filter; + (*feed)->data_ready_cb = dmx_section_feed_data_ready_cb; + (*feed)->notify_data_read = NULL; + (*feed)->set_secure_mode = dmx_section_set_secure_mode; + (*feed)->set_cipher_ops = dmx_section_set_cipher_ops; + (*feed)->oob_command = dvbdmx_section_feed_oob_cmd; + (*feed)->get_scrambling_bits = dvbdmx_section_get_scrambling_bits; + (*feed)->flush_buffer = NULL; mutex_unlock(&dvbdmx->mutex); return 0; @@ -1068,8 +3081,12 @@ static int dvbdmx_release_section_feed(struct dmx_demux *demux, mutex_unlock(&dvbdmx->mutex); return -EINVAL; } +#ifndef NOBUFS + vfree(dvbdmxfeed->buffer); + dvbdmxfeed->buffer = NULL; +#endif dvbdmxfeed->state = DMX_STATE_FREE; - + feed->priv = NULL; dvb_demux_feed_del(dvbdmxfeed); dvbdmxfeed->pid = 0xffff; @@ -1105,23 +3122,18 @@ static int dvbdmx_close(struct dmx_demux *demux) return 0; } -static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count) +static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count) { struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - void *p; - if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE)) + if (!demux->frontend || !buf || demux->dvr_input_protected || + (demux->frontend->source != DMX_MEMORY_FE)) return -EINVAL; - - p = memdup_user(buf, count); - if (IS_ERR(p)) - return PTR_ERR(p); - if (mutex_lock_interruptible(&dvbdemux->mutex)) { - kfree(p); + if (mutex_lock_interruptible(&dvbdemux->mutex)) return -ERESTARTSYS; - } - dvb_dmx_swfilter(dvbdemux, p, count); - kfree(p); + + dvb_dmx_swfilter_format(dvbdemux, buf, count, dvbdemux->tsp_format); + mutex_unlock(&dvbdemux->mutex); if (signal_pending(current)) @@ -1129,6 +3141,40 @@ static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t return count; } +static int dvbdmx_write_cancel(struct dmx_demux *demux) +{ + struct dvb_demux *dvbdmx = (struct dvb_demux *)demux; + + spin_lock_irq(&dvbdmx->lock); + + /* cancel any pending wait for decoder's buffers */ + dvbdmx->sw_filter_abort = 1; + dvbdmx->tsbufp = 0; + dvb_dmx_configure_decoder_fullness(dvbdmx, 0); + + spin_unlock_irq(&dvbdmx->lock); + + return 0; +} + +static int dvbdmx_set_playback_mode(struct dmx_demux *demux, + enum dmx_playback_mode_t mode, + dmx_ts_fullness ts_fullness_callback, + dmx_section_fullness sec_fullness_callback) +{ + struct dvb_demux *dvbdmx = (struct dvb_demux *)demux; + + mutex_lock(&dvbdmx->mutex); + + dvbdmx->playback_mode = mode; + dvbdmx->buffer_ctrl.ts = ts_fullness_callback; + dvbdmx->buffer_ctrl.sec = sec_fullness_callback; + + mutex_unlock(&dvbdmx->mutex); + + return 0; +} + static int dvbdmx_add_frontend(struct dmx_demux *demux, struct dmx_frontend *frontend) { @@ -1186,7 +3232,7 @@ static int dvbdmx_disconnect_frontend(struct dmx_demux *demux) struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; mutex_lock(&dvbdemux->mutex); - + dvbdemux->sw_filter_abort = 0; demux->frontend = NULL; mutex_unlock(&dvbdemux->mutex); return 0; @@ -1196,7 +3242,50 @@ static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 * pids) { struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - memcpy(pids, dvbdemux->pids, 5 * sizeof(u16)); + /* 4 Demux Instances each with group of 5 pids */ + memcpy(pids, dvbdemux->pids, DMX_PES_OTHER*sizeof(u16)); + return 0; +} + +static int dvbdmx_get_tsp_size(struct dmx_demux *demux) +{ + int tsp_size; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; + + mutex_lock(&dvbdemux->mutex); + tsp_size = dvbdemux->ts_packet_size; + mutex_unlock(&dvbdemux->mutex); + + return tsp_size; +} + +static int dvbdmx_set_tsp_format( + struct dmx_demux *demux, + enum dmx_tsp_format_t tsp_format) +{ + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; + + if ((tsp_format > DMX_TSP_FORMAT_204) || + (tsp_format < DMX_TSP_FORMAT_188)) + return -EINVAL; + + mutex_lock(&dvbdemux->mutex); + + dvbdemux->tsp_format = tsp_format; + switch (tsp_format) { + case DMX_TSP_FORMAT_188: + dvbdemux->ts_packet_size = 188; + break; + case DMX_TSP_FORMAT_192_TAIL: + case DMX_TSP_FORMAT_192_HEAD: + dvbdemux->ts_packet_size = 192; + break; + case DMX_TSP_FORMAT_204: + dvbdemux->ts_packet_size = 204; + break; + } + + mutex_unlock(&dvbdemux->mutex); return 0; } @@ -1218,18 +3307,53 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) dvbdemux->filter = NULL; return -ENOMEM; } + + dvbdemux->rec_info_pool = vmalloc(dvbdemux->feednum * + sizeof(struct dvb_demux_rec_info)); + if (!dvbdemux->rec_info_pool) { + vfree(dvbdemux->feed); + vfree(dvbdemux->filter); + dvbdemux->feed = NULL; + dvbdemux->filter = NULL; + return -ENOMEM; + } + + dvbdemux->sw_filter_abort = 0; + dvbdemux->total_process_time = 0; + dvbdemux->total_crc_time = 0; + snprintf(dvbdemux->alias, + MAX_DVB_DEMUX_NAME_LEN, + "demux%d", + dvb_demux_index++); + + dvbdemux->dmx.debugfs_demux_dir = + debugfs_create_dir(dvbdemux->alias, NULL); + + if (dvbdemux->dmx.debugfs_demux_dir != NULL) { + debugfs_create_u32( + "total_processing_time", 0664, + dvbdemux->dmx.debugfs_demux_dir, + &dvbdemux->total_process_time); + + debugfs_create_u32( + "total_crc_time", 0664, + dvbdemux->dmx.debugfs_demux_dir, + &dvbdemux->total_crc_time); + } + for (i = 0; i < dvbdemux->filternum; i++) { dvbdemux->filter[i].state = DMX_STATE_FREE; dvbdemux->filter[i].index = i; } + for (i = 0; i < dvbdemux->feednum; i++) { dvbdemux->feed[i].state = DMX_STATE_FREE; dvbdemux->feed[i].index = i; + + dvbdemux->rec_info_pool[i].ref_count = 0; } dvbdemux->cnt_storage = vmalloc(MAX_PID + 1); - if (!dvbdemux->cnt_storage) - pr_warn("Couldn't allocate memory for TS/TEI check. Disabling it\n"); INIT_LIST_HEAD(&dvbdemux->frontend_list); @@ -1244,6 +3368,9 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) dvbdemux->recording = 0; dvbdemux->tsbufp = 0; + dvbdemux->tsp_format = DMX_TSP_FORMAT_188; + dvbdemux->ts_packet_size = 188; + if (!dvbdemux->check_crc32) dvbdemux->check_crc32 = dvb_dmx_crc32; @@ -1255,10 +3382,14 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) dmx->open = dvbdmx_open; dmx->close = dvbdmx_close; dmx->write = dvbdmx_write; + dmx->write_cancel = dvbdmx_write_cancel; + dmx->set_playback_mode = dvbdmx_set_playback_mode; dmx->allocate_ts_feed = dvbdmx_allocate_ts_feed; dmx->release_ts_feed = dvbdmx_release_ts_feed; dmx->allocate_section_feed = dvbdmx_allocate_section_feed; dmx->release_section_feed = dvbdmx_release_section_feed; + dmx->map_buffer = NULL; + dmx->unmap_buffer = NULL; dmx->add_frontend = dvbdmx_add_frontend; dmx->remove_frontend = dvbdmx_remove_frontend; @@ -1267,6 +3398,9 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) dmx->disconnect_frontend = dvbdmx_disconnect_frontend; dmx->get_pes_pids = dvbdmx_get_pes_pids; + dmx->set_tsp_format = dvbdmx_set_tsp_format; + dmx->get_tsp_size = dvbdmx_get_tsp_size; + mutex_init(&dvbdemux->mutex); spin_lock_init(&dvbdemux->lock); @@ -1277,9 +3411,14 @@ EXPORT_SYMBOL(dvb_dmx_init); void dvb_dmx_release(struct dvb_demux *dvbdemux) { + if (dvbdemux->dmx.debugfs_demux_dir != NULL) + debugfs_remove_recursive(dvbdemux->dmx.debugfs_demux_dir); + + dvb_demux_index--; vfree(dvbdemux->cnt_storage); vfree(dvbdemux->filter); vfree(dvbdemux->feed); + vfree(dvbdemux->rec_info_pool); } EXPORT_SYMBOL(dvb_dmx_release); diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h index 6f572ca8d339..4faa4cd77738 100644 --- a/drivers/media/dvb-core/dvb_demux.h +++ b/drivers/media/dvb-core/dvb_demux.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "demux.h" @@ -40,6 +41,8 @@ #define MAX_PID 0x1fff +#define TIMESTAMP_LEN 4 + #define SPEED_PKTS_INTERVAL 50000 struct dvb_demux_filter { @@ -60,6 +63,92 @@ struct dvb_demux_filter { #define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head) + +struct dmx_index_entry { + struct dmx_index_event_info event; + struct list_head next; +}; + +#define DMX_IDX_EVENT_QUEUE_SIZE DMX_EVENT_QUEUE_SIZE + +struct dvb_demux_rec_info { + /* Reference counter for number of feeds using this information */ + int ref_count; + + /* Counter for number of TS packets output to recording buffer */ + u64 ts_output_count; + + /* Indexing information */ + struct { + /* + * Minimum TS packet number encountered in recording filter + * among all feeds that search for video patterns + */ + u64 min_pattern_tsp_num; + + /* Number of indexing-enabled feeds */ + u8 indexing_feeds_num; + + /* Number of feeds with video pattern search request */ + u8 pattern_search_feeds_num; + + /* Index entries pool */ + struct dmx_index_entry events[DMX_IDX_EVENT_QUEUE_SIZE]; + + /* List of free entries that can be used for new index events */ + struct list_head free_list; + + /* List holding ready index entries not notified to user yet */ + struct list_head ready_list; + } idx_info; +}; + +#define DVB_DMX_MAX_PATTERN_LEN 6 +struct dvb_dmx_video_patterns { + /* the byte pattern to look for */ + u8 pattern[DVB_DMX_MAX_PATTERN_LEN]; + + /* the byte mask to use (same length as pattern) */ + u8 mask[DVB_DMX_MAX_PATTERN_LEN]; + + /* the length of the pattern, in bytes */ + size_t size; + + /* the type of the pattern. One of DMX_IDX_* definitions */ + u64 type; +}; + +#define DVB_DMX_MAX_FOUND_PATTERNS 20 +#define DVB_DMX_MAX_SEARCH_PATTERN_NUM 20 +struct dvb_dmx_video_prefix_size_masks { + /* + * a bit mask (per pattern) of possible prefix sizes to use + * when searching for a pattern that started in the previous TS packet. + * Updated by dvb_dmx_video_pattern_search for use in the next lookup. + */ + u32 size_mask[DVB_DMX_MAX_FOUND_PATTERNS]; +}; + +struct dvb_dmx_video_patterns_results { + struct { + /* + * The offset in the buffer where the pattern was found. + * If a pattern is found using a prefix (i.e. started on the + * previous buffer), offset is zero. + */ + u32 offset; + + /* + * The type of the pattern found. + * One of DMX_IDX_* definitions. + */ + u64 type; + + /* The prefix size that was used to find this pattern */ + u32 used_prefix_size; + } info[DVB_DMX_MAX_FOUND_PATTERNS]; +}; + struct dvb_demux_feed { union { struct dmx_ts_feed ts; @@ -71,11 +160,21 @@ struct dvb_demux_feed { dmx_section_cb sec; } cb; + union { + dmx_ts_data_ready_cb ts; + dmx_section_data_ready_cb sec; + } data_ready_cb; + struct dvb_demux *demux; void *priv; int type; int state; u16 pid; + u8 *buffer; + int buffer_size; + enum dmx_tsp_format_t tsp_out_format; + struct dmx_secure_mode secure_mode; + struct dmx_cipher_operations cipher_ops; ktime_t timeout; struct dvb_demux_filter *filter; @@ -84,12 +183,34 @@ struct dvb_demux_feed { enum dmx_ts_pes pes_type; int cc; + int first_cc; int pusi_seen; /* prevents feeding of garbage from previous section */ + u8 scrambling_bits; + + struct dvb_demux_rec_info *rec_info; + u64 prev_tsp_num; + u64 prev_stc; + u64 curr_pusi_tsp_num; + u64 prev_pusi_tsp_num; + int prev_frame_valid; + u64 prev_frame_type; + int first_frame_in_seq; + int first_frame_in_seq_notified; + u64 last_pattern_tsp_num; + int pattern_num; +const struct dvb_dmx_video_patterns *patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM]; + struct dvb_dmx_video_prefix_size_masks prefix_size; u16 peslen; + u32 pes_tei_counter; + u32 pes_cont_err_counter; + u32 pes_ts_packets_num; struct list_head list_head; unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */ + + enum dmx_video_codec video_codec; + struct dmx_indexing_params idx_params; }; struct dvb_demux { @@ -101,10 +222,27 @@ struct dvb_demux { int (*stop_feed)(struct dvb_demux_feed *feed); int (*write_to_decoder)(struct dvb_demux_feed *feed, const u8 *buf, size_t len); + int (*decoder_fullness_init)(struct dvb_demux_feed *feed); + int (*decoder_fullness_wait)(struct dvb_demux_feed *feed, + size_t required_space); + int (*decoder_fullness_abort)(struct dvb_demux_feed *feed); + int (*decoder_buffer_status)(struct dvb_demux_feed *feed, + struct dmx_buffer_status *dmx_buffer_status); + int (*reuse_decoder_buffer)(struct dvb_demux_feed *feed, + int cookie); + int (*set_cipher_op)(struct dvb_demux_feed *feed, + struct dmx_cipher_operations *cipher_ops); u32 (*check_crc32)(struct dvb_demux_feed *feed, const u8 *buf, size_t len); void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst, const u8 *src, size_t len); + int (*oob_command)(struct dvb_demux_feed *feed, + struct dmx_oob_command *cmd); + void (*convert_ts)(struct dvb_demux_feed *feed, + const u8 timestamp[TIMESTAMP_LEN], + u64 *timestampIn27Mhz); + int (*set_indexing)(struct dvb_demux_feed *feed); + int (*flush_decoder_buffer)(struct dvb_demux_feed *feed, size_t length); int users; #define MAX_DVB_DEMUX_USERS 10 @@ -130,10 +268,35 @@ struct dvb_demux { ktime_t speed_last_time; /* for TS speed check */ uint32_t speed_pkts_cnt; /* for TS speed check */ + + enum dmx_tsp_format_t tsp_format; + size_t ts_packet_size; + + enum dmx_playback_mode_t playback_mode; + int sw_filter_abort; + + struct { + dmx_ts_fullness ts; + dmx_section_fullness sec; + } buffer_ctrl; + + struct dvb_demux_rec_info *rec_info_pool; + + /* + * the following is used for debugfs exposing info + * about dvb demux performance. + */ +#define MAX_DVB_DEMUX_NAME_LEN 10 + char alias[MAX_DVB_DEMUX_NAME_LEN]; + + u32 total_process_time; + u32 total_crc_time; }; int dvb_dmx_init(struct dvb_demux *dvbdemux); void dvb_dmx_release(struct dvb_demux *dvbdemux); +int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf, + int should_lock); void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, size_t count); void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count); @@ -141,5 +304,116 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count); void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count); +void dvb_dmx_swfilter_format( + struct dvb_demux *demux, const u8 *buf, + size_t count, + enum dmx_tsp_format_t tsp_format); +void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf, + const u8 timestamp[TIMESTAMP_LEN]); +const struct dvb_dmx_video_patterns *dvb_dmx_get_pattern(u64 dmx_idx_pattern); +int dvb_dmx_video_pattern_search( + const struct dvb_dmx_video_patterns + *patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM], + int patterns_num, + const u8 *buf, size_t buf_size, + struct dvb_dmx_video_prefix_size_masks *prefix_size_masks, + struct dvb_dmx_video_patterns_results *results); +int dvb_demux_push_idx_event(struct dvb_demux_feed *feed, + struct dmx_index_event_info *idx_event, int should_lock); +void dvb_dmx_process_idx_pattern(struct dvb_demux_feed *feed, + struct dvb_dmx_video_patterns_results *patterns, int pattern, + u64 curr_stc, u64 prev_stc, + u64 curr_match_tsp, u64 prev_match_tsp, + u64 curr_pusi_tsp, u64 prev_pusi_tsp); +void dvb_dmx_notify_idx_events(struct dvb_demux_feed *feed, int should_lock); +int dvb_dmx_notify_section_event(struct dvb_demux_feed *feed, + struct dmx_data_ready *event, int should_lock); +void dvbdmx_ts_reset_pes_state(struct dvb_demux_feed *feed); + +/** + * dvb_dmx_is_video_feed - Returns whether the PES feed + * is video one. + * + * @feed: The feed to be checked. + * + * Return 1 if feed is video feed, 0 otherwise. + */ +static inline int dvb_dmx_is_video_feed(struct dvb_demux_feed *feed) +{ + if (feed->type != DMX_TYPE_TS) + return 0; + + if (feed->ts_type & (~TS_DECODER)) + return 0; + + if ((feed->pes_type == DMX_PES_VIDEO0) || + (feed->pes_type == DMX_PES_VIDEO1) || + (feed->pes_type == DMX_PES_VIDEO2) || + (feed->pes_type == DMX_PES_VIDEO3)) + return 1; + + return 0; +} + +/** + * dvb_dmx_is_pcr_feed - Returns whether the PES feed + * is PCR one. + * + * @feed: The feed to be checked. + * + * Return 1 if feed is PCR feed, 0 otherwise. + */ +static inline int dvb_dmx_is_pcr_feed(struct dvb_demux_feed *feed) +{ + if (feed->type != DMX_TYPE_TS) + return 0; + + if (feed->ts_type & (~TS_DECODER)) + return 0; + + if ((feed->pes_type == DMX_PES_PCR0) || + (feed->pes_type == DMX_PES_PCR1) || + (feed->pes_type == DMX_PES_PCR2) || + (feed->pes_type == DMX_PES_PCR3)) + return 1; + + return 0; +} + +/** + * dvb_dmx_is_sec_feed - Returns whether this is a section feed + * + * @feed: The feed to be checked. + * + * Return 1 if feed is a section feed, 0 otherwise. + */ +static inline int dvb_dmx_is_sec_feed(struct dvb_demux_feed *feed) +{ + return (feed->type == DMX_TYPE_SEC); +} + +/** + * dvb_dmx_is_rec_feed - Returns whether this is a recording feed + * + * @feed: The feed to be checked. + * + * Return 1 if feed is recording feed, 0 otherwise. + */ +static inline int dvb_dmx_is_rec_feed(struct dvb_demux_feed *feed) +{ + if (feed->type != DMX_TYPE_TS) + return 0; + + if (feed->ts_type & (TS_DECODER | TS_PAYLOAD_ONLY)) + return 0; + + return 1; +} + +static inline u16 ts_pid(const u8 *buf) +{ + return ((buf[1] & 0x1f) << 8) + buf[2]; +} + #endif /* _DVB_DEMUX_H_ */ diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index 06b0dcc13695..28dea0402530 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -1091,7 +1091,7 @@ static int dvb_net_feed_start(struct net_device *dev) goto error; } - ret = priv->secfeed->set(priv->secfeed, priv->pid, 1); + ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1); if (ret<0) { pr_err("%s: could not set section feed\n", dev->name); @@ -1129,7 +1129,7 @@ static int dvb_net_feed_start(struct net_device *dev) netdev_dbg(dev, "start filtering\n"); priv->secfeed->start_filtering(priv->secfeed); } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) { - ktime_t timeout = ns_to_ktime(10 * NSEC_PER_MSEC); + ktime_t timeout = ktime_set(0, 10*NSEC_PER_MSEC); // 10 msec /* we have payloads encapsulated in TS */ netdev_dbg(dev, "alloc tsfeed\n"); @@ -1145,6 +1145,7 @@ static int dvb_net_feed_start(struct net_device *dev) priv->pid, /* pid */ TS_PACKET, /* type */ DMX_PES_OTHER, /* pes type */ + 32768, /* circular buffer size */ timeout /* timeout */ ); diff --git a/drivers/media/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb-core/dvb_ringbuffer.c index 2322af1b8742..ea4fed0dfece 100644 --- a/drivers/media/dvb-core/dvb_ringbuffer.c +++ b/drivers/media/dvb-core/dvb_ringbuffer.c @@ -33,6 +33,8 @@ #define PKT_READY 0 #define PKT_DISPOSED 1 +#define PKT_PENDING 2 + void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len) @@ -205,18 +207,19 @@ ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t } ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, - const u8 __user *buf, size_t len) + const u8 __user *buf, size_t len) { - int status; size_t todo = len; size_t split; + ssize_t oldpwrite = rbuf->pwrite; - split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0; + split = (rbuf->pwrite + len > rbuf->size) ? + rbuf->size - rbuf->pwrite : + 0; if (split > 0) { - status = copy_from_user(rbuf->data+rbuf->pwrite, buf, split); - if (status) - return len - todo; + if (copy_from_user(rbuf->data + rbuf->pwrite, buf, split)) + return -EFAULT; buf += split; todo -= split; /* smp_store_release() for write pointer update to ensure that @@ -226,9 +229,12 @@ ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, */ smp_store_release(&rbuf->pwrite, 0); } - status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo); - if (status) - return len - todo; + + if (copy_from_user(rbuf->data + rbuf->pwrite, buf, todo)) { + /* smp_store_release() for write pointer update */ + smp_store_release(&rbuf->pwrite, oldpwrite); + return -EFAULT; + } /* smp_store_release() for write pointer update, see above */ smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size); @@ -249,6 +255,31 @@ ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t le return status; } +ssize_t dvb_ringbuffer_pkt_start(struct dvb_ringbuffer *rbuf, size_t len) +{ + ssize_t oldpwrite = rbuf->pwrite; + + DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8); + DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff); + DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_PENDING); + + return oldpwrite; +} +EXPORT_SYMBOL(dvb_ringbuffer_pkt_start); + +int dvb_ringbuffer_pkt_close(struct dvb_ringbuffer *rbuf, ssize_t idx) +{ + idx = (idx + 2) % rbuf->size; + + if (rbuf->data[idx] != PKT_PENDING) + return -EINVAL; + + rbuf->data[idx] = PKT_READY; + + return 0; +} +EXPORT_SYMBOL(dvb_ringbuffer_pkt_close); + ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx, int offset, u8 __user *buf, size_t len) { @@ -256,6 +287,9 @@ ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx, size_t split; size_t pktlen; + if (DVB_RINGBUFFER_PEEK(rbuf, (idx+2)) != PKT_READY) + return -EINVAL; + pktlen = rbuf->data[idx] << 8; pktlen |= rbuf->data[(idx + 1) % rbuf->size]; if (offset > pktlen) return -EINVAL; @@ -276,6 +310,7 @@ ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx, return len; } +EXPORT_SYMBOL(dvb_ringbuffer_pkt_read_user); ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, int offset, u8* buf, size_t len) @@ -284,6 +319,9 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, size_t split; size_t pktlen; + if (rbuf->data[(idx + 2) % rbuf->size] != PKT_READY) + return -EINVAL; + pktlen = rbuf->data[idx] << 8; pktlen |= rbuf->data[(idx + 1) % rbuf->size]; if (offset > pktlen) return -EINVAL; @@ -301,6 +339,7 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, memcpy(buf, rbuf->data+idx, todo); return len; } +EXPORT_SYMBOL(dvb_ringbuffer_pkt_read); void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx) { @@ -320,6 +359,7 @@ void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx) } } } +EXPORT_SYMBOL(dvb_ringbuffer_pkt_dispose); ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen) { @@ -335,7 +375,10 @@ ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size; } - consumed = (idx - rbuf->pread) % rbuf->size; + if (idx >= rbuf->pread) + consumed = idx - rbuf->pread; + else + consumed = rbuf->size - (rbuf->pread - idx); while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) { @@ -348,6 +391,9 @@ ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* return idx; } + if (curpktstatus == PKT_PENDING) + return -EFAULT; + consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE; idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size; } @@ -355,8 +401,7 @@ ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* // no packets available return -1; } - - +EXPORT_SYMBOL(dvb_ringbuffer_pkt_next); EXPORT_SYMBOL(dvb_ringbuffer_init); EXPORT_SYMBOL(dvb_ringbuffer_empty); diff --git a/drivers/media/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb-core/dvb_ringbuffer.h index 8ed6bcc3a56e..e2196f4ab6e4 100644 --- a/drivers/media/dvb-core/dvb_ringbuffer.h +++ b/drivers/media/dvb-core/dvb_ringbuffer.h @@ -124,6 +124,9 @@ extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf); */ #define DVB_RINGBUFFER_PEEK(rbuf, offs) \ ((rbuf)->data[((rbuf)->pread + (offs)) % (rbuf)->size]) +#define DVB_RINGBUFFER_PUSH(rbuf, num) \ + ((rbuf)->pwrite = (((rbuf)->pwrite+(num))%(rbuf)->size)) + /** * DVB_RINGBUFFER_SKIP - advance read ptr by @num bytes @@ -274,7 +277,35 @@ extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx); * in bytes. * returns Packet index (if >=0), or -1 if no packets available. */ -extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, - size_t idx, size_t *pktlen); +extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, + size_t *pktlen); + + +/** + * Start a new packet that will be written directly by the user to the packet + * buffer. + * The function only writes the header of the packet into the packet buffer, + * and the packet is in pending state (can't be read by the reader) until it is + * closed using dvb_ringbuffer_pkt_close. You must write the data into the + * packet buffer using dvb_ringbuffer_write followed by + * dvb_ringbuffer_pkt_close. + * + * @rbuf: Ringbuffer concerned. + * @len: Size of the packet's data + * returns Index of the packet's header that was started. + */ +extern ssize_t dvb_ringbuffer_pkt_start(struct dvb_ringbuffer *rbuf, + size_t len); + +/** + * Close a packet that was started using dvb_ringbuffer_pkt_start. + * The packet will be marked as ready to be ready. + * + * @rbuf: Ringbuffer concerned. + * @idx: Packet index that was returned by dvb_ringbuffer_pkt_start + * returns error status, -EINVAL if the provided index is invalid + */ +extern int dvb_ringbuffer_pkt_close(struct dvb_ringbuffer *rbuf, ssize_t idx); + #endif /* _DVB_RINGBUFFER_H_ */ diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index 0e7e4fdf9e50..05701240b5d1 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -906,7 +906,7 @@ static void xc5000_config_tv(struct dvb_frontend *fe, static int xc5000_set_tv_freq(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; - u16 pll_lock_status; + u16 pll_lock_status = 0; int ret; tune_channel: @@ -1108,7 +1108,7 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force) const struct xc5000_fw_cfg *desired_fw = xc5000_assign_firmware(priv->chip_id); const struct firmware *fw; int ret, i; - u16 pll_lock_status; + u16 pll_lock_status = 0; u16 fw_ck; cancel_delayed_work(&priv->timer_sleep); diff --git a/include/uapi/linux/dvb/dmx.h b/include/uapi/linux/dvb/dmx.h index c10f1324b4ca..0a1af707ad58 100644 --- a/include/uapi/linux/dvb/dmx.h +++ b/include/uapi/linux/dvb/dmx.h @@ -33,6 +33,11 @@ #define DMX_FILTER_SIZE 16 +/* Min recording chunk upon which event is generated */ +#define DMX_REC_BUFF_CHUNK_MIN_SIZE (100*188) + +#define DMX_MAX_DECODER_BUFFER_NUM (32) + /** * enum dmx_output - Output for the demux. * @@ -178,37 +183,736 @@ struct dmx_sct_filter_params { #define DMX_CHECK_CRC 1 #define DMX_ONESHOT 2 #define DMX_IMMEDIATE_START 4 +#define DMX_KERNEL_CLIENT 0x8000 }; -/** - * struct dmx_pes_filter_params - Specifies Packetized Elementary Stream (PES) - * filter parameters. - * - * @pid: PID to be filtered. - * @input: Demux input, as specified by &enum dmx_input. - * @output: Demux output, as specified by &enum dmx_output. - * @pes_type: Type of the pes filter, as specified by &enum dmx_pes_type. - * @flags: Demux PES flags. - */ +enum dmx_video_codec { + DMX_VIDEO_CODEC_MPEG2, + DMX_VIDEO_CODEC_H264, + DMX_VIDEO_CODEC_VC1 +}; + +/* Index entries types */ +#define DMX_IDX_RAI 0x00000001 +#define DMX_IDX_PUSI 0x00000002 +#define DMX_IDX_MPEG_SEQ_HEADER 0x00000004 +#define DMX_IDX_MPEG_GOP 0x00000008 +#define DMX_IDX_MPEG_FIRST_SEQ_FRAME_START 0x00000010 +#define DMX_IDX_MPEG_FIRST_SEQ_FRAME_END 0x00000020 +#define DMX_IDX_MPEG_I_FRAME_START 0x00000040 +#define DMX_IDX_MPEG_I_FRAME_END 0x00000080 +#define DMX_IDX_MPEG_P_FRAME_START 0x00000100 +#define DMX_IDX_MPEG_P_FRAME_END 0x00000200 +#define DMX_IDX_MPEG_B_FRAME_START 0x00000400 +#define DMX_IDX_MPEG_B_FRAME_END 0x00000800 +#define DMX_IDX_H264_SPS 0x00001000 +#define DMX_IDX_H264_PPS 0x00002000 +#define DMX_IDX_H264_FIRST_SPS_FRAME_START 0x00004000 +#define DMX_IDX_H264_FIRST_SPS_FRAME_END 0x00008000 +#define DMX_IDX_H264_IDR_START 0x00010000 +#define DMX_IDX_H264_IDR_END 0x00020000 +#define DMX_IDX_H264_NON_IDR_START 0x00040000 +#define DMX_IDX_H264_NON_IDR_END 0x00080000 +#define DMX_IDX_VC1_SEQ_HEADER 0x00100000 +#define DMX_IDX_VC1_ENTRY_POINT 0x00200000 +#define DMX_IDX_VC1_FIRST_SEQ_FRAME_START 0x00400000 +#define DMX_IDX_VC1_FIRST_SEQ_FRAME_END 0x00800000 +#define DMX_IDX_VC1_FRAME_START 0x01000000 +#define DMX_IDX_VC1_FRAME_END 0x02000000 +#define DMX_IDX_H264_ACCESS_UNIT_DEL 0x04000000 +#define DMX_IDX_H264_SEI 0x08000000 + struct dmx_pes_filter_params { - __u16 pid; - enum dmx_input input; + __u16 pid; + enum dmx_input input; enum dmx_output output; enum dmx_ts_pes pes_type; + __u32 flags; + + /* + * The following configures when the event + * DMX_EVENT_NEW_REC_CHUNK will be triggered. + * When new recorded data is received with size + * equal or larger than this value a new event + * will be triggered. This is relevant when + * output is DMX_OUT_TS_TAP or DMX_OUT_TSDEMUX_TAP, + * size must be at least DMX_REC_BUFF_CHUNK_MIN_SIZE + * and smaller than buffer size. + */ + __u32 rec_chunk_size; + + enum dmx_video_codec video_codec; +}; + +struct dmx_buffer_status { + /* size of buffer in bytes */ + unsigned int size; + + /* fullness of buffer in bytes */ + unsigned int fullness; + + /* + * How many bytes are free + * It's the same as: size-fullness-1 + */ + unsigned int free_bytes; + + /* read pointer offset in bytes */ + unsigned int read_offset; + + /* write pointer offset in bytes */ + unsigned int write_offset; + + /* non-zero if data error occurred */ + int error; +}; + +/* Events associated with each demux filter */ +enum dmx_event { + /* New PES packet is ready to be consumed */ + DMX_EVENT_NEW_PES = 0x00000001, + + /* New section is ready to be consumed */ + DMX_EVENT_NEW_SECTION = 0x00000002, + + /* New recording chunk is ready to be consumed */ + DMX_EVENT_NEW_REC_CHUNK = 0x00000004, + + /* New PCR value is ready */ + DMX_EVENT_NEW_PCR = 0x00000008, + + /* Overflow */ + DMX_EVENT_BUFFER_OVERFLOW = 0x00000010, + + /* Section was dropped due to CRC error */ + DMX_EVENT_SECTION_CRC_ERROR = 0x00000020, + + /* End-of-stream, no more data from this filter */ + DMX_EVENT_EOS = 0x00000040, + + /* New Elementary Stream data is ready */ + DMX_EVENT_NEW_ES_DATA = 0x00000080, + + /* Data markers */ + DMX_EVENT_MARKER = 0x00000100, + + /* New indexing entry is ready */ + DMX_EVENT_NEW_INDEX_ENTRY = 0x00000200, + + /* + * Section filter timer expired. This is notified + * when timeout is configured to section filter + * (dmx_sct_filter_params) and no sections were + * received for the given time. + */ + DMX_EVENT_SECTION_TIMEOUT = 0x00000400, + + /* Scrambling bits change between clear and scrambled */ + DMX_EVENT_SCRAMBLING_STATUS_CHANGE = 0x00000800 +}; + +enum dmx_oob_cmd { + /* End-of-stream, no more data from this filter */ + DMX_OOB_CMD_EOS, + + /* Data markers */ + DMX_OOB_CMD_MARKER, +}; + +/* Flags passed in filter events */ + +/* Continuity counter error was detected */ +#define DMX_FILTER_CC_ERROR 0x01 + +/* Discontinuity indicator was set */ +#define DMX_FILTER_DISCONTINUITY_INDICATOR 0x02 + +/* PES length in PES header is not correct */ +#define DMX_FILTER_PES_LENGTH_ERROR 0x04 + + +/* PES info associated with DMX_EVENT_NEW_PES event */ +struct dmx_pes_event_info { + /* Offset at which PES information starts */ + __u32 base_offset; + + /* + * Start offset at which PES data + * from the stream starts. + * Equal to base_offset if PES data + * starts from the beginning. + */ + __u32 start_offset; + + /* Total length holding the PES information */ + __u32 total_length; + + /* Actual length holding the PES data */ + __u32 actual_length; + + /* Local receiver timestamp in 27MHz */ + __u64 stc; + + /* Flags passed in filter events */ + __u32 flags; + + /* + * Number of TS packets with Transport Error Indicator (TEI) + * found while constructing the PES. + */ + __u32 transport_error_indicator_counter; + + /* Number of continuity errors found while constructing the PES */ + __u32 continuity_error_counter; + + /* Total number of TS packets holding the PES */ + __u32 ts_packets_num; +}; + +/* Section info associated with DMX_EVENT_NEW_SECTION event */ +struct dmx_section_event_info { + /* Offset at which section information starts */ + __u32 base_offset; + + /* + * Start offset at which section data + * from the stream starts. + * Equal to base_offset if section data + * starts from the beginning. + */ + __u32 start_offset; + + /* Total length holding the section information */ + __u32 total_length; + + /* Actual length holding the section data */ + __u32 actual_length; + + /* Flags passed in filter events */ + __u32 flags; +}; + +/* Recording info associated with DMX_EVENT_NEW_REC_CHUNK event */ +struct dmx_rec_chunk_event_info { + /* Offset at which recording chunk starts */ + __u32 offset; + + /* Size of recording chunk in bytes */ + __u32 size; +}; + +/* PCR info associated with DMX_EVENT_NEW_PCR event */ +struct dmx_pcr_event_info { + /* Local timestamp in 27MHz + * when PCR packet was received + */ + __u64 stc; + + /* PCR value in 27MHz */ + __u64 pcr; + + /* Flags passed in filter events */ + __u32 flags; +}; + +/* + * Elementary stream data information associated + * with DMX_EVENT_NEW_ES_DATA event + */ +struct dmx_es_data_event_info { + /* Buffer user-space handle */ + int buf_handle; + + /* + * Cookie to provide when releasing the buffer + * using the DMX_RELEASE_DECODER_BUFFER ioctl command + */ + int cookie; + + /* Offset of data from the beginning of the buffer */ + __u32 offset; + + /* Length of data in buffer (in bytes) */ + __u32 data_len; + + /* Indication whether PTS value is valid */ + int pts_valid; + + /* PTS value associated with the buffer */ + __u64 pts; + + /* Indication whether DTS value is valid */ + int dts_valid; + + /* DTS value associated with the buffer */ + __u64 dts; + + /* STC value associated with the buffer in 27MHz */ + __u64 stc; + + /* + * Number of TS packets with Transport Error Indicator (TEI) set + * in the TS packet header since last reported event + */ + __u32 transport_error_indicator_counter; + + /* Number of continuity errors since last reported event */ + __u32 continuity_error_counter; + + /* Total number of TS packets processed since last reported event */ + __u32 ts_packets_num; + + /* + * Number of dropped bytes due to insufficient buffer space, + * since last reported event + */ + __u32 ts_dropped_bytes; +}; + +/* Marker details associated with DMX_EVENT_MARKER event */ +struct dmx_marker_event_info { + /* Marker id */ + __u64 id; +}; + +/* Indexing information associated with DMX_EVENT_NEW_INDEX_ENTRY event */ +struct dmx_index_event_info { + /* Index entry type, one of DMX_IDX_* */ + __u64 type; + + /* + * The PID the index entry belongs to. + * In case of recording filter, multiple PIDs may exist in the same + * filter through DMX_ADD_PID ioctl and each can be indexed separately. + */ + __u16 pid; + + /* + * The TS packet number in the recorded data at which + * the indexing event is found. + */ + __u64 match_tsp_num; + + /* + * The TS packet number in the recorded data preceding + * match_tsp_num and has PUSI set. + */ + __u64 last_pusi_tsp_num; + + /* STC associated with match_tsp_num, in 27MHz */ + __u64 stc; +}; + +/* Scrambling information associated with DMX_EVENT_SCRAMBLING_STATUS_CHANGE */ +struct dmx_scrambling_status_event_info { + /* + * The PID which its scrambling bit status changed. + * In case of recording filter, multiple PIDs may exist in the same + * filter through DMX_ADD_PID ioctl, each may have + * different scrambling bits status. + */ + __u16 pid; + + /* old value of scrambling bits */ + __u8 old_value; + + /* new value of scrambling bits */ + __u8 new_value; +}; + +/* + * Filter's event returned through DMX_GET_EVENT. + * poll with POLLPRI would block until events are available. + */ +struct dmx_filter_event { + enum dmx_event type; + + union { + struct dmx_pes_event_info pes; + struct dmx_section_event_info section; + struct dmx_rec_chunk_event_info recording_chunk; + struct dmx_pcr_event_info pcr; + struct dmx_es_data_event_info es_data; + struct dmx_marker_event_info marker; + struct dmx_index_event_info index; + struct dmx_scrambling_status_event_info scrambling_status; + } params; +}; + +/* Filter's buffer requirement returned in dmx_caps */ +struct dmx_buffer_requirement { + /* Buffer size alignment, 0 means no special requirement */ + __u32 size_alignment; + + /* Maximum buffer size allowed */ + __u32 max_size; + + /* Maximum number of linear buffers handled by demux */ + __u32 max_buffer_num; + + /* Feature support bitmap as detailed below */ __u32 flags; + +/* Buffer must be allocated as physically contiguous memory */ +#define DMX_BUFFER_CONTIGUOUS_MEM 0x1 + +/* If the filter's data is decrypted, the buffer should be secured one */ +#define DMX_BUFFER_SECURED_IF_DECRYPTED 0x2 + +/* Buffer can be allocated externally */ +#define DMX_BUFFER_EXTERNAL_SUPPORT 0x4 + +/* Buffer can be allocated internally */ +#define DMX_BUFFER_INTERNAL_SUPPORT 0x8 + +/* Filter output can be output to a linear buffer group */ +#define DMX_BUFFER_LINEAR_GROUP_SUPPORT 0x10 + +/* Buffer may be allocated as cached buffer */ +#define DMX_BUFFER_CACHED 0x20 }; -/** - * struct dmx_stc - Stores System Time Counter (STC) information. - * - * @num: input data: number of the STC, from 0 to N. - * @base: output: divisor for STC to get 90 kHz clock. - * @stc: output: stc in @base * 90 kHz units. +/* Out-of-band (OOB) command */ +struct dmx_oob_command { + enum dmx_oob_cmd type; + + union { + struct dmx_marker_event_info marker; + } params; +}; + +typedef struct dmx_caps { + __u32 caps; + +/* Indicates whether demux support playback from memory in pull mode */ +#define DMX_CAP_PULL_MODE 0x01 + +/* Indicates whether demux support indexing of recorded video stream */ +#define DMX_CAP_VIDEO_INDEXING 0x02 + +/* Indicates whether demux support sending data directly to video decoder */ +#define DMX_CAP_VIDEO_DECODER_DATA 0x04 + +/* Indicates whether demux support sending data directly to audio decoder */ +#define DMX_CAP_AUDIO_DECODER_DATA 0x08 + +/* Indicates whether demux support sending data directly to subtitle decoder */ +#define DMX_CAP_SUBTITLE_DECODER_DATA 0x10 + +/* Indicates whether TS insertion is supported */ +#define DMX_CAP_TS_INSERTION 0x20 + +/* Indicates whether playback from secured input is supported */ +#define DMX_CAP_SECURED_INPUT_PLAYBACK 0x40 + +/* Indicates whether automatic buffer flush upon overflow is allowed */ +#define DMX_CAP_AUTO_BUFFER_FLUSH 0x80 + + /* Number of decoders demux can output data to */ + int num_decoders; + + /* Number of demux devices */ + int num_demux_devices; + + /* Max number of PID filters */ + int num_pid_filters; + + /* Max number of section filters */ + int num_section_filters; + + /* + * Max number of section filters using same PID, + * 0 if not supported + */ + int num_section_filters_per_pid; + + /* + * Length of section filter, not including section + * length field (2 bytes). + */ + int section_filter_length; + + /* Max number of demod based input */ + int num_demod_inputs; + + /* Max number of memory based input */ + int num_memory_inputs; + + /* Overall bitrate from all inputs concurrently. Mbit/sec */ + int max_bitrate; + + /* Max bitrate from single demod input. Mbit/sec */ + int demod_input_max_bitrate; + + /* Max bitrate from single memory input. Mbit/sec */ + int memory_input_max_bitrate; + + /* Max number of supported cipher operations per PID */ + int num_cipher_ops; + + /* Max possible value of STC reported by demux, in 27MHz */ + __u64 max_stc; + + /* + * For indexing support (DMX_CAP_VIDEO_INDEXING capability) this is + * the max number of video pids that can be indexed for a single + * recording filter. If 0, means there is not limitation. */ + int recording_max_video_pids_indexed; + + struct dmx_buffer_requirement section; + + /* For PES not sent to decoder */ + struct dmx_buffer_requirement pes; + + /* For PES sent to decoder */ + struct dmx_buffer_requirement decoder; + + /* Recording buffer for recording of 188 bytes packets */ + struct dmx_buffer_requirement recording_188_tsp; + + /* Recording buffer for recording of 192 bytes packets */ + struct dmx_buffer_requirement recording_192_tsp; + + /* DVR input buffer for playback of 188 bytes packets */ + struct dmx_buffer_requirement playback_188_tsp; + + /* DVR input buffer for playback of 192 bytes packets */ + struct dmx_buffer_requirement playback_192_tsp; +} dmx_caps_t; + +typedef enum dmx_source { + DMX_SOURCE_FRONT0 = 0, + DMX_SOURCE_FRONT1, + DMX_SOURCE_FRONT2, + DMX_SOURCE_FRONT3, + DMX_SOURCE_DVR0 = 16, + DMX_SOURCE_DVR1, + DMX_SOURCE_DVR2, + DMX_SOURCE_DVR3 +} dmx_source_t; + +enum dmx_tsp_format_t { + DMX_TSP_FORMAT_188 = 0, + DMX_TSP_FORMAT_192_TAIL, + DMX_TSP_FORMAT_192_HEAD, + DMX_TSP_FORMAT_204, +}; + +enum dmx_playback_mode_t { + /* + * In push mode, if one of output buffers + * is full, the buffer would overflow + * and demux continue processing incoming stream. + * This is the default mode. When playing from frontend, + * this is the only mode that is allowed. + */ + DMX_PB_MODE_PUSH = 0, + + /* + * In pull mode, if one of output buffers + * is full, demux stalls waiting for free space, + * this would cause DVR input buffer fullness + * to accumulate. + * This mode is possible only when playing + * from DVR. + */ + DMX_PB_MODE_PULL, +}; + struct dmx_stc { - unsigned int num; - unsigned int base; - __u64 stc; + unsigned int num; /* input : which STC? 0..N */ + unsigned int base; /* output: divisor for stc to get 90 kHz clock */ + __u64 stc; /* output: stc in 'base'*90 kHz units */ +}; + +enum dmx_buffer_mode { + /* + * demux buffers are allocated internally + * by the demux driver. This is the default mode. + * DMX_SET_BUFFER_SIZE can be used to set the size of + * this buffer. + */ + DMX_BUFFER_MODE_INTERNAL, + + /* + * demux buffers are allocated externally and provided + * to demux through DMX_SET_BUFFER. + * When this mode is used DMX_SET_BUFFER_SIZE and + * mmap are prohibited. + */ + DMX_BUFFER_MODE_EXTERNAL, +}; + +struct dmx_buffer { + unsigned int size; + int handle; + + /* + * The following indication is relevant only when setting + * DVR input buffer. It indicates whether the input buffer + * being set is secured one or not. Secured (locked) buffers + * are required for playback from secured input. In such case + * write() syscall is not allowed. + */ + int is_protected; +}; + +struct dmx_decoder_buffers { + /* + * Specify if linear buffer support is requested. If set, buffers_num + * must be greater than 1 + */ + int is_linear; + + /* + * Specify number of external buffers allocated by user. + * If set to 0 means internal buffer allocation is requested + */ + __u32 buffers_num; + + /* Specify buffer size, either external or internal */ + __u32 buffers_size; + + /* Array of externally allocated buffer handles */ + int handles[DMX_MAX_DECODER_BUFFER_NUM]; +}; + +struct dmx_secure_mode { + /* + * Specifies whether the filter is secure or not. + * Filter should be set as secured if the filter's data *may* include + * encrypted data that would require decryption configured through + * DMX_SET_CIPHER ioctl. The setting may be done while + * filter is in idle state only. + */ + int is_secured; +}; + +struct dmx_cipher_operation { + /* Indication whether the operation is encryption or decryption */ + int encrypt; + + /* The ID of the key used for decryption or encryption */ + __u32 key_ladder_id; +}; + +#define DMX_MAX_CIPHER_OPERATIONS_COUNT 5 +struct dmx_cipher_operations { + /* + * The PID to perform the cipher operations on. + * In case of recording filter, multiple PIDs may exist in the same + * filter through DMX_ADD_PID ioctl, each may have different + * cipher operations. + */ + __u16 pid; + + /* Total number of operations */ + __u8 operations_count; + + /* + * Cipher operation to perform on the given PID. + * The operations are performed in the order they are given. + */ + struct dmx_cipher_operation operations[DMX_MAX_CIPHER_OPERATIONS_COUNT]; +}; + +struct dmx_events_mask { + /* + * Bitmask of events to be disabled (dmx_event). + * Disabled events will not be notified to the user. + * By default all events are enabled except for + * DMX_EVENT_NEW_ES_DATA. + * Overflow event can't be disabled. + */ + __u32 disable_mask; + + /* + * Bitmask of events that will not wake-up the user + * when user calls poll with POLLPRI flag. + * Events that are used as wake-up source should not be + * disabled in disable_mask or they would not be used + * as a wake-up source. + * By default all enabled events are set as wake-up events. + * Overflow event can't be disabled as a wake-up source. + */ + __u32 no_wakeup_mask; + + /* + * Number of ready wake-up events which will trigger + * a wake-up when user calls poll with POLLPRI flag. + * Default is set to 1. + */ + __u32 wakeup_threshold; +}; + +struct dmx_indexing_params { + /* + * PID to index. In case of recording filter, multiple PIDs + * may exist in the same filter through DMX_ADD_PID ioctl. + * It is assumed that the PID was already added using DMX_ADD_PID + * or an error will be reported. + */ + __u16 pid; + + /* enable or disable indexing, default is disabled */ + int enable; + + /* combination of DMX_IDX_* bits */ + __u64 types; +}; + +struct dmx_set_ts_insertion { + /* + * Unique identifier managed by the caller. + * This identifier can be used later to remove the + * insertion using DMX_ABORT_TS_INSERTION ioctl. + */ + __u32 identifier; + + /* + * Repetition time in msec, minimum allowed value is 25msec. + * 0 repetition time means one-shot insertion is done. + * Insertion done based on wall-clock. + */ + __u32 repetition_time; + + /* + * TS packets buffer to be inserted. + * The buffer is inserted as-is to the recording buffer + * without any modification. + * It is advised to set discontinuity flag in the very + * first TS packet in the buffer. + */ + const __u8 *ts_packets; + + /* + * Size in bytes of the TS packets buffer to be inserted. + * Should be in multiples of 188 or 192 bytes + * depending on recording filter output format. + */ + size_t size; +}; + +struct dmx_abort_ts_insertion { + /* + * Identifier of the insertion buffer previously set + * using DMX_SET_TS_INSERTION. + */ + __u32 identifier; +}; + +struct dmx_scrambling_bits { + /* + * The PID to return its scrambling bit value. + * In case of recording filter, multiple PIDs may exist in the same + * filter through DMX_ADD_PID ioctl, each may have different + * scrambling bits status. + */ + __u16 pid; + + /* Current value of scrambling bits: 0, 1, 2 or 3 */ + __u8 value; }; #define DMX_START _IO('o', 41) @@ -217,9 +921,33 @@ struct dmx_stc { #define DMX_SET_PES_FILTER _IOW('o', 44, struct dmx_pes_filter_params) #define DMX_SET_BUFFER_SIZE _IO('o', 45) #define DMX_GET_PES_PIDS _IOR('o', 47, __u16[5]) +#define DMX_GET_CAPS _IOR('o', 48, dmx_caps_t) +#define DMX_SET_SOURCE _IOW('o', 49, dmx_source_t) #define DMX_GET_STC _IOWR('o', 50, struct dmx_stc) #define DMX_ADD_PID _IOW('o', 51, __u16) #define DMX_REMOVE_PID _IOW('o', 52, __u16) +#define DMX_SET_TS_PACKET_FORMAT _IOW('o', 53, enum dmx_tsp_format_t) +#define DMX_SET_TS_OUT_FORMAT _IOW('o', 54, enum dmx_tsp_format_t) +#define DMX_SET_DECODER_BUFFER_SIZE _IO('o', 55) +#define DMX_GET_BUFFER_STATUS _IOR('o', 56, struct dmx_buffer_status) +#define DMX_RELEASE_DATA _IO('o', 57) +#define DMX_FEED_DATA _IO('o', 58) +#define DMX_SET_PLAYBACK_MODE _IOW('o', 59, enum dmx_playback_mode_t) +#define DMX_GET_EVENT _IOR('o', 60, struct dmx_filter_event) +#define DMX_SET_BUFFER_MODE _IOW('o', 61, enum dmx_buffer_mode) +#define DMX_SET_BUFFER _IOW('o', 62, struct dmx_buffer) +#define DMX_SET_DECODER_BUFFER _IOW('o', 63, struct dmx_decoder_buffers) +#define DMX_REUSE_DECODER_BUFFER _IO('o', 64) +#define DMX_SET_SECURE_MODE _IOW('o', 65, struct dmx_secure_mode) +#define DMX_SET_EVENTS_MASK _IOW('o', 66, struct dmx_events_mask) +#define DMX_GET_EVENTS_MASK _IOR('o', 67, struct dmx_events_mask) +#define DMX_PUSH_OOB_COMMAND _IOW('o', 68, struct dmx_oob_command) +#define DMX_SET_INDEXING_PARAMS _IOW('o', 69, struct dmx_indexing_params) +#define DMX_SET_TS_INSERTION _IOW('o', 70, struct dmx_set_ts_insertion) +#define DMX_ABORT_TS_INSERTION _IOW('o', 71, struct dmx_abort_ts_insertion) +#define DMX_GET_SCRAMBLING_BITS _IOWR('o', 72, struct dmx_scrambling_bits) +#define DMX_SET_CIPHER _IOW('o', 73, struct dmx_cipher_operations) +#define DMX_FLUSH_BUFFER _IO('o', 74) #if !defined(__KERNEL__) -- GitLab From 426f385db9239359bf3d9cdd1103951158095c4a Mon Sep 17 00:00:00 2001 From: Monika Singh Date: Thu, 19 Jul 2018 13:04:51 +0530 Subject: [PATCH 0703/1001] defconfig: msm: enable dvb demux modules compilation Enable dvb_core, mpq demux plugin, TSPP modules compilation. Change-Id: If1ac983799e8b8a3b1637cd6aad29a86e705372a Signed-off-by: Monika Singh --- arch/arm64/configs/vendor/sm8150-perf_defconfig | 5 +++++ arch/arm64/configs/vendor/sm8150_defconfig | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/arch/arm64/configs/vendor/sm8150-perf_defconfig b/arch/arm64/configs/vendor/sm8150-perf_defconfig index 85331abeccf4..0738fba1a1a3 100644 --- a/arch/arm64/configs/vendor/sm8150-perf_defconfig +++ b/arch/arm64/configs/vendor/sm8150-perf_defconfig @@ -368,6 +368,7 @@ CONFIG_REGULATOR_RPMH=y CONFIG_REGULATOR_STUB=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_VIDEO_ADV_DEBUG=y @@ -381,6 +382,10 @@ CONFIG_MSM_VIDC_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y CONFIG_MSM_NPU=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m +CONFIG_DVB_MPQ_TSPP1=y +CONFIG_TSPP=m CONFIG_DRM=y CONFIG_DRM_MSM_REGISTER_LOGGING=y CONFIG_DRM_SDE_EVTLOG_DEBUG=y diff --git a/arch/arm64/configs/vendor/sm8150_defconfig b/arch/arm64/configs/vendor/sm8150_defconfig index 9d4e63b5918c..bf1637e16a3f 100644 --- a/arch/arm64/configs/vendor/sm8150_defconfig +++ b/arch/arm64/configs/vendor/sm8150_defconfig @@ -383,6 +383,7 @@ CONFIG_REGULATOR_RPMH=y CONFIG_REGULATOR_STUB=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_VIDEO_ADV_DEBUG=y @@ -396,6 +397,10 @@ CONFIG_MSM_VIDC_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y CONFIG_MSM_NPU=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m +CONFIG_DVB_MPQ_TSPP1=y +CONFIG_TSPP=m CONFIG_DRM=y CONFIG_DRM_MSM_REGISTER_LOGGING=y CONFIG_DRM_SDE_EVTLOG_DEBUG=y -- GitLab From b7d52b1381856961902f78cdf25ea4d28d238997 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Sun, 12 Aug 2018 20:08:52 +0530 Subject: [PATCH 0704/1001] i2c-qcom-geni: Set DMA mask to support 64 bit DMA Set DMA mask to 64 bit to support DMA address of range 64 bit. Change-Id: I7e703044b8020f3c31431ff8782032a5d5357988 Signed-off-by: Shrey Vijay Signed-off-by: Alok Chauhan --- drivers/i2c/busses/i2c-qcom-geni.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index db708ea669d1..b3b3f8e97c69 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -845,6 +845,15 @@ static int geni_i2c_probe(struct platform_device *pdev) return ret; } + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (ret) { + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "could not set DMA mask\n"); + return ret; + } + } + gi2c->adap.algo = &geni_i2c_algo; init_completion(&gi2c->xfer); platform_set_drvdata(pdev, gi2c); -- GitLab From b81771958662764808bf2e6e789275183df5106a Mon Sep 17 00:00:00 2001 From: Sriharsha Allenki Date: Thu, 9 Aug 2018 19:05:31 +0530 Subject: [PATCH 0705/1001] usb: dwc3: Start the core in host mode only if there is no extcon The current driver starts the core in host mode even if there is extcon available for that core. This causes the id_state to be overwritten to ID_GROUND irrespective of the current extcon state. Fix this starting the core in host mode by default only if there is no extcon present. Change-Id: Idd0885942e5e854f0aafc4a26a6eb27033f00935 Signed-off-by: Sriharsha Allenki --- drivers/usb/dwc3/dwc3-msm.c | 39 +++++++++++++++---------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index f471fe93e9b9..16363c0d8ef7 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -2974,17 +2974,6 @@ static int dwc3_msm_extcon_register(struct dwc3_msm *mdwc) struct extcon_dev *edev; int idx, extcon_cnt, ret = 0; bool check_vbus_state, check_id_state, phandle_found = false; - struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); - - if (!of_property_read_bool(node, "extcon")) { - if (dwc->dr_mode == USB_DR_MODE_OTG) { - dev_dbg(mdwc->dev, "%s: no extcon, simulate vbus connect\n", - __func__); - mdwc->vbus_active = true; - queue_work(mdwc->dwc3_wq, &mdwc->resume_work); - } - return 0; - } extcon_cnt = of_count_phandle_with_args(node, "extcon", NULL); if (extcon_cnt < 0) { @@ -3278,7 +3267,6 @@ static int dwc3_msm_probe(struct platform_device *pdev) struct dwc3_msm *mdwc; struct dwc3 *dwc; struct resource *res; - bool host_mode; int ret = 0, i; u32 val; unsigned long irq_type; @@ -3526,24 +3514,29 @@ static int dwc3_msm_probe(struct platform_device *pdev) mutex_init(&mdwc->suspend_resume_mutex); - ret = dwc3_msm_extcon_register(mdwc); - if (ret) - goto put_dwc3; + if (of_property_read_bool(node, "extcon")) { + ret = dwc3_msm_extcon_register(mdwc); + if (ret) + goto put_dwc3; + } else { + if (dwc->dr_mode == USB_DR_MODE_OTG || + dwc->dr_mode == USB_DR_MODE_PERIPHERAL) { + dev_dbg(mdwc->dev, "%s: no extcon, simulate vbus connect\n", + __func__); + mdwc->vbus_active = true; + } else if (dwc->dr_mode == USB_DR_MODE_HOST) { + dev_dbg(mdwc->dev, "DWC3 in host only mode\n"); + mdwc->id_state = DWC3_ID_GROUND; + } - schedule_delayed_work(&mdwc->sm_work, 0); + dwc3_ext_event_notify(mdwc); + } device_create_file(&pdev->dev, &dev_attr_mode); device_create_file(&pdev->dev, &dev_attr_speed); device_create_file(&pdev->dev, &dev_attr_usb_compliance_mode); device_create_file(&pdev->dev, &dev_attr_bus_vote); - host_mode = usb_get_dr_mode(&mdwc->dwc3->dev) == USB_DR_MODE_HOST; - if (host_mode) { - dev_dbg(&pdev->dev, "DWC3 in host only mode\n"); - mdwc->id_state = DWC3_ID_GROUND; - dwc3_ext_event_notify(mdwc); - } - return 0; put_dwc3: -- GitLab From 7354f1c218b02ec35bdf06b8e59b28bd8cf85cbb Mon Sep 17 00:00:00 2001 From: Sriharsha Allenki Date: Thu, 9 Aug 2018 21:57:25 +0530 Subject: [PATCH 0706/1001] usb: dwc3: Use pwr_event_irq to wakeup if there is no ss_phy_irq On platforms where there is no support for ss_phy_irq, pwr_event_irq is used for wakeup events from SS PHY. Add the proper programming to enable the Superspeed wakeup events and do not suspend SS PHY to get these wakeup events. Change-Id: I812fb13f6b59cfab07532d6e42baa9fe46568c03 Signed-off-by: Sriharsha Allenki --- drivers/usb/dwc3/dwc3-msm.c | 59 ++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 16363c0d8ef7..4f48541f12c6 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -83,6 +83,7 @@ #define PWR_EVNT_POWERDOWN_OUT_P3_MASK BIT(3) #define PWR_EVNT_LPM_IN_L2_MASK BIT(4) #define PWR_EVNT_LPM_OUT_L2_MASK BIT(5) +#define PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK BIT(12) #define PWR_EVNT_LPM_OUT_L1_MASK BIT(13) /* QSCRATCH_GENERAL_CFG register bit offset */ @@ -245,6 +246,7 @@ struct dwc3_msm { bool suspend; bool use_pdc_interrupts; enum dwc3_id_state id_state; + bool use_pwr_event_for_wakeup; unsigned long lpm_flags; #define MDWC3_SS_PHY_SUSPEND BIT(0) #define MDWC3_ASYNC_IRQ_WAKE_CAPABILITY BIT(1) @@ -2189,6 +2191,27 @@ static void configure_nonpdc_usb_interrupt(struct dwc3_msm *mdwc, } } +static void dwc3_msm_set_ss_pwr_events(struct dwc3_msm *mdwc, bool on) +{ + u32 irq_mask, irq_stat; + + irq_stat = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG); + + /* clear pending interrupts */ + dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG, irq_stat); + + irq_mask = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_MASK_REG); + + if (on) + irq_mask |= (PWR_EVNT_POWERDOWN_OUT_P3_MASK | + PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK); + else + irq_mask &= ~(PWR_EVNT_POWERDOWN_OUT_P3_MASK | + PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK); + + dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_MASK_REG, irq_mask); +} + static int dwc3_msm_update_bus_bw(struct dwc3_msm *mdwc, enum bus_vote bv) { int ret = 0; @@ -2228,6 +2251,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); struct dwc3_event_buffer *evt; struct usb_irq *uirq; + bool can_suspend_ssphy, no_active_ss; mutex_lock(&mdwc->suspend_resume_mutex); if (atomic_read(&dwc->in_lpm)) { @@ -2303,13 +2327,28 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) /* Suspend HS PHY */ usb_phy_set_suspend(mdwc->hs_phy, 1); + /* + * Synopsys Superspeed PHY does not support ss_phy_irq, so to detect + * any wakeup events in host mode PHY cannot be suspended. + * This Superspeed PHY can be suspended only in the following cases: + * 1. The core is not in host mode + * 2. A Highspeed device is connected but not a Superspeed device + */ + no_active_ss = (!mdwc->in_host_mode) || (mdwc->in_host_mode && + ((mdwc->hs_phy->flags & (PHY_HSFS_MODE | PHY_LS_MODE)) && + !dwc3_msm_is_superspeed(mdwc))); + can_suspend_ssphy = dwc->maximum_speed >= USB_SPEED_SUPER && + (!mdwc->use_pwr_event_for_wakeup || no_active_ss); /* Suspend SS PHY */ - if (dwc->maximum_speed >= USB_SPEED_SUPER) { + if (can_suspend_ssphy) { /* indicate phy about SS mode */ if (dwc3_msm_is_superspeed(mdwc)) mdwc->ss_phy->flags |= DEVICE_IN_SS_MODE; usb_phy_set_suspend(mdwc->ss_phy, 1); mdwc->lpm_flags |= MDWC3_SS_PHY_SUSPEND; + } else if (mdwc->use_pwr_event_for_wakeup) { + dwc3_msm_set_ss_pwr_events(mdwc, true); + enable_irq(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq); } /* make sure above writes are completed before turning off clocks */ @@ -2465,6 +2504,16 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) if (mdwc->bus_aggr_clk) clk_prepare_enable(mdwc->bus_aggr_clk); + /* + * Disable any wakeup events that were enabled if pwr_event_irq + * is used as wakeup interrupt. + */ + if (mdwc->use_pwr_event_for_wakeup && + !(mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND)) { + disable_irq_nosync(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq); + dwc3_msm_set_ss_pwr_events(mdwc, false); + } + /* Resume SS PHY */ if (dwc->maximum_speed >= USB_SPEED_SUPER && mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND) { @@ -3487,6 +3536,14 @@ static int dwc3_msm_probe(struct platform_device *pdev) goto put_dwc3; } + /* + * On platforms with SS PHY that do not support ss_phy_irq for wakeup + * events, use pwr_event_irq for wakeup events in superspeed mode. + */ + mdwc->use_pwr_event_for_wakeup = dwc->maximum_speed >= USB_SPEED_SUPER + && !mdwc->wakeup_irq[SS_PHY_IRQ].irq; + + /* IOMMU will be reattached upon each resume/connect */ if (mdwc->iommu_map) arm_iommu_detach_device(mdwc->dev); -- GitLab From e3abf4d059c2274a7a1f48e7215d8d4cb14e062b Mon Sep 17 00:00:00 2001 From: shubham Date: Mon, 13 Aug 2018 14:53:03 +0530 Subject: [PATCH 0707/1001] msm: vidc: EOS not reached for specific AV content Changing the minimum required buffers for firmware to minimum count instead of client buffer count. Change-Id: Ib6a488d37b446fe5c7da1af325ad0801f9776e84 Signed-off-by: Shubham Gupta --- drivers/media/platform/msm/vidc/msm_vdec.c | 2 +- drivers/media/platform/msm/vidc/msm_vidc.c | 4 ++-- drivers/media/platform/msm/vidc/msm_vidc_common.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 965ef037f284..f91ed9e7bb93 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -1192,7 +1192,7 @@ int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) break; rc = msm_comm_set_buffer_count(inst, - bufreq_out2->buffer_count_min_host, + bufreq_out2->buffer_count_min, bufreq_out2->buffer_count_actual, HAL_BUFFER_OUTPUT2); if (rc) { diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index b00d7ee75f33..df48ac63d301 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -777,7 +777,7 @@ static int msm_vidc_queue_setup(struct vb2_queue *q, bufreq->buffer_count_actual = *num_buffers; rc = msm_comm_set_buffer_count(inst, - bufreq->buffer_count_min_host, + bufreq->buffer_count_min, bufreq->buffer_count_actual, HAL_BUFFER_INPUT); } break; @@ -811,7 +811,7 @@ static int msm_vidc_queue_setup(struct vb2_queue *q, bufreq->buffer_count_actual = *num_buffers; rc = msm_comm_set_buffer_count(inst, - bufreq->buffer_count_min_host, + bufreq->buffer_count_min, bufreq->buffer_count_actual, buffer_type); } break; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index cbfeea486d65..40b98427ebdc 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -3196,7 +3196,7 @@ static int msm_comm_init_buffer_count(struct msm_vidc_inst *inst) bufreq->buffer_count_actual); rc = msm_comm_set_buffer_count(inst, - bufreq->buffer_count_min_host, + bufreq->buffer_count_min, bufreq->buffer_count_actual, HAL_BUFFER_INPUT); if (rc) { dprintk(VIDC_ERR, @@ -3230,7 +3230,7 @@ static int msm_comm_init_buffer_count(struct msm_vidc_inst *inst) bufreq->buffer_count_actual); rc = msm_comm_set_buffer_count(inst, - bufreq->buffer_count_min_host, + bufreq->buffer_count_min, bufreq->buffer_count_actual, HAL_BUFFER_OUTPUT); if (rc) { dprintk(VIDC_ERR, -- GitLab From 556ffff37c504edfe754a9598a164bc45866801b Mon Sep 17 00:00:00 2001 From: Om Parkash Date: Sat, 11 Aug 2018 18:20:12 +0530 Subject: [PATCH 0708/1001] ARM: dts: msm: Add src-clock-name in csiphy node Add src-clock-name property in csiphy nodes in camera dtsi for sm6150. Change-Id: I4e0d735f21c07112b860b84a9ddedb9ff9dbc0e1 Signed-off-by: Om Parkash --- arch/arm64/boot/dts/qcom/sm6150-camera.dtsi | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi b/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi index b26b1ed6d4db..50506ac40038 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-camera.dtsi @@ -45,6 +45,7 @@ "csiphy0_clk", "csi0phytimer_clk_src", "csi0phytimer_clk"; + src-clock-name = "csi0phytimer_clk_src"; clock-cntl-level = "turbo"; clock-rates = <0 0 0 0 384000000 0 269333333 0>; @@ -79,6 +80,7 @@ "csiphy1_clk", "csi1phytimer_clk_src", "csi1phytimer_clk"; + src-clock-name = "csi1phytimer_clk_src"; clock-cntl-level = "turbo"; clock-rates = <0 0 0 0 384000000 0 269333333 0>; @@ -114,6 +116,7 @@ "csiphy2_clk", "csi2phytimer_clk_src", "csi2phytimer_clk"; + src-clock-name = "csi2phytimer_clk_src"; clock-cntl-level = "turbo"; clock-rates = <0 0 0 0 384000000 0 269333333 0>; @@ -451,7 +454,7 @@ "csid0", "csid1", "csid2", "ife0", "ife1", "ife2", "ipe0", "ipe1", "cam-cdm-intf0", "cpas-cdm0", "bps0", - "icp0", "jpeg-dma0", "jpeg-enc0", "lrmecpas"; + "icp0", "jpeg-dma0", "jpeg-enc0", "lrmecpas0"; client-axi-port-names = "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", "cam_hf_1", "cam_hf_2", "cam_hf_2", -- GitLab From 9243d3c6f674b8a22ad1d6b34f2c4a40d87b72de Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Mon, 16 Jul 2018 22:45:07 +0530 Subject: [PATCH 0709/1001] ARM: dts: msm: Enable the OSM clock controller for sm6150 Update the cpucc clock node to use the real OSM clock controller for sm6150. Also add the measurement support for CPU clocks. Change-Id: I6c4ed45418f07f24fc53215a1994e826381717ad Signed-off-by: Odelu Kukatla --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 20 +++++++++--- drivers/clk/qcom/debugcc-sm6150.c | 15 ++++++++- include/dt-bindings/clock/qcom,cpucc-sm6150.h | 32 ------------------- 3 files changed, 30 insertions(+), 37 deletions(-) delete mode 100644 include/dt-bindings/clock/qcom,cpucc-sm6150.h diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index ce1117cba29a..babdfe876830 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -1069,9 +1069,20 @@ #reset-cells = <1>; }; - clock_cpucc: qcom,cpucc { - compatible = "qcom,dummycc"; - clock-output-names = "cpucc_clocks"; + cpucc_debug: syscon@182a0018 { + compatible = "syscon"; + reg = <0x182a0018 0x4>; + }; + + clock_cpucc: qcom,cpucc@18321000 { + compatible = "qcom,clk-cpu-osm-sm6150"; + reg = <0x18321000 0x1400>, + <0x18323000 0x1400>, + <0x18325800 0x1400>; + reg-names = "osm_l3_base", "osm_pwrcl_base", + "osm_perfcl_base"; + l3-devs = <&cpu0_cpu_l3_lat &cpu6_cpu_l3_lat + &cdsp_cdsp_l3_lat &msm_gpu>; #clock-cells = <1>; }; @@ -1082,6 +1093,7 @@ qcom,camcc = <&clock_camcc>; qcom,dispcc = <&clock_dispcc>; qcom,gpucc = <&clock_gpucc>; + qcom,cpucc = <&cpucc_debug>; clock-names = "cxo"; clocks = <&clock_rpmh RPMH_CXO_CLK>; #clock-cells = <1>; diff --git a/drivers/clk/qcom/debugcc-sm6150.c b/drivers/clk/qcom/debugcc-sm6150.c index d9625fc6e9e0..31a32b5a98d1 100644 --- a/drivers/clk/qcom/debugcc-sm6150.c +++ b/drivers/clk/qcom/debugcc-sm6150.c @@ -255,6 +255,9 @@ static const char *const debug_mux_parent_names[] = { "video_cc_venus_ctl_axi_clk", "video_cc_venus_ctl_core_clk", "video_cc_xo_clk", + "l3_clk", + "pwrcl_clk", + "perfcl_clk", }; static struct clk_debug_mux gcc_debug_mux = { @@ -682,7 +685,7 @@ static struct clk_debug_mux gcc_debug_mux = { { "gpu_cc_sleep_clk", 0x144, 1, GPU_CC, 0x16, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, { "measure_only_bimc_clk", 0xC2, 1, GCC, - 0xC2, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, + 0xBF, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "measure_only_cnoc_clk", 0x15, 1, GCC, 0x15, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "measure_only_ipa_2x_clk", 0x128, 1, GCC, @@ -711,6 +714,12 @@ static struct clk_debug_mux gcc_debug_mux = { 0x1, 0x3F, 0, 0x7, 0, 5, 0xA4C, 0xA30, 0xA38 }, { "video_cc_xo_clk", 0x48, 1, VIDEO_CC, 0xC, 0x3F, 0, 0x7, 0, 5, 0xA4C, 0xA30, 0xA38 }, + { "l3_clk", 0xD6, 4, CPU_CC, + 0x46, 0x7F, 4, 0xf, 11, 1, 0x0, 0x0, U32_MAX, 16 }, + { "pwrcl_clk", 0xD6, 4, CPU_CC, + 0x44, 0x7F, 4, 0xf, 11, 1, 0x0, 0x0, U32_MAX, 16 }, + { "perfcl_clk", 0xD6, 4, CPU_CC, + 0x45, 0x7F, 4, 0xf, 11, 1, 0x0, 0x0, U32_MAX, 16 }, ), .hw.init = &(struct clk_init_data){ .name = "gcc_debug_mux", @@ -784,6 +793,10 @@ static int clk_debug_sm6150_probe(struct platform_device *pdev) if (ret) return ret; + ret = map_debug_bases(pdev, "qcom,cpucc", CPU_CC); + if (ret) + return ret; + clk = devm_clk_register(&pdev->dev, &gcc_debug_mux.hw); if (IS_ERR(clk)) { dev_err(&pdev->dev, "Unable to register GCC debug mux\n"); diff --git a/include/dt-bindings/clock/qcom,cpucc-sm6150.h b/include/dt-bindings/clock/qcom,cpucc-sm6150.h deleted file mode 100644 index 2a60ef821775..000000000000 --- a/include/dt-bindings/clock/qcom,cpucc-sm6150.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _DT_BINDINGS_CLK_QCOM_CPU_CC_SM6150_H -#define _DT_BINDINGS_CLK_QCOM_CPU_CC_SM6150_H - -#define PWRCL_CLK 0 -#define PERFCL_CLK 1 -#define L3_CLK 2 -#define L3_CLUSTER0_VOTE_CLK 3 -#define L3_CLUSTER1_VOTE_CLK 4 -#define CPU0_PWRCL_CLK 5 -#define CPU1_PWRCL_CLK 6 -#define CPU2_PWRCL_CLK 7 -#define CPU3_PWRCL_CLK 8 -#define CPU4_PWRCL_CLK 9 -#define CPU5_PWRCL_CLK 10 -#define CPU6_PERFCL_CLK 11 -#define CPU7_PERFCL_CLK 12 -#define L3_MISC_VOTE_CLK 13 - -#endif -- GitLab From 8142924f24af6b74c9da8df4d38fad5d52eb444e Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Sat, 11 Aug 2018 23:38:01 +0530 Subject: [PATCH 0710/1001] ARM: dts: msm: fix phy parameters for hx83112a panel on sm6150 Fix PHY supply and timing parameters for hx83112a truly video mode panel on sm6150 platform. Change-Id: I7aa98d4ba7f0a275e66817102fac898cbfaac257 Signed-off-by: Sandeep Panda --- arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi | 4 ++-- arch/arm64/boot/dts/qcom/sm6150-sde.dtsi | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi index 18802d41d15c..bf6ddb3cb46f 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi @@ -211,9 +211,9 @@ }; &dsi_hx83112a_truly_video { + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x31>; qcom,mdss-dsi-display-timings { - qcom,mdss-dsi-t-clk-post = <0x0e>; - qcom,mdss-dsi-t-clk-pre = <0x31>; timing@0{ qcom,mdss-dsi-panel-phy-timings = [24 1f 08 09 05 02 04 a0 diff --git a/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi index 89183060f29f..7804c58b579b 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi @@ -449,7 +449,7 @@ reg = <0>; qcom,supply-name = "vdda-0p9"; qcom,supply-min-voltage = <880000>; - qcom,supply-max-voltage = <880000>; + qcom,supply-max-voltage = <975000>; qcom,supply-enable-load = <36000>; qcom,supply-disable-load = <0>; }; -- GitLab From ecad1b0eae7408df78c84fe95beda143966a0a84 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Mon, 13 Aug 2018 16:49:52 +0530 Subject: [PATCH 0711/1001] ARM: dts: msm: Update sm7150 DT entires for fastrpc usecases Add CDSP loader DT entry to load CDSP image, add adsprpc mem region DT entry for remote heap usecase, configure SMMU context banks for fastRPC sessions and remove adsp ion heap 22 as it is specifically used for adsp remote heap. Change-Id: I901e717b378608639ac2095704eb21941b9b51c5 Acked-by: Vishnu Karthik D Signed-off-by: Tharun Kumar Merugu --- arch/arm64/boot/dts/qcom/sdmmagpie-ion.dtsi | 6 -- arch/arm64/boot/dts/qcom/sdmmagpie.dtsi | 112 ++++++++++++++++++++ 2 files changed, 112 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-ion.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-ion.dtsi index a8bfab8603ec..f89f20ef5c37 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-ion.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-ion.dtsi @@ -21,12 +21,6 @@ qcom,ion-heap-type = "SYSTEM"; }; - qcom,ion-heap@22 { /* ADSP HEAP */ - reg = <22>; - memory-region = <&adsp_mem>; - qcom,ion-heap-type = "DMA"; - }; - qcom,ion-heap@27 { /* QSEECOM HEAP */ reg = <27>; memory-region = <&qseecom_mem>; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index bd56ac97bac0..add315ceb386 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -1131,6 +1131,118 @@ #mbox-cells = <1>; }; + qcom,msm-cdsp-loader { + compatible = "qcom,cdsp-loader"; + qcom,proc-img-to-load = "cdsp"; + }; + + qcom,msm-adsprpc-mem { + compatible = "qcom,msm-adsprpc-mem-region"; + memory-region = <&adsp_mem>; + restrict-access; + }; + + qcom,msm_fastrpc { + compatible = "qcom,msm-fastrpc-compute"; + qcom,rpc-latency-us = <611>; + qcom,adsp-remoteheap-vmid = <22 37>; + qcom,fastrpc-adsp-audio-pdr; + qcom,fastrpc-adsp-sensors-pdr; + + qcom,msm_fastrpc_compute_cb1 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1441 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb2 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1442 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb3 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1443 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb4 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1444 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb5 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1445 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb6 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1446 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb9 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + qcom,secure-context-bank; + iommus = <&apps_smmu 0x1449 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb10 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1B23 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb11 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1B24 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb12 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1B25 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb13 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1B26 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb14 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1B27 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb15 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1B28 0x0>; + shared-cb = <3>; + dma-coherent; + }; + }; + qcom,glink { compatible = "qcom,glink"; #address-cells = <1>; -- GitLab From 34bce88d8cb56edb62a11151470adf41e63afa96 Mon Sep 17 00:00:00 2001 From: Kiran Gunda Date: Mon, 13 Aug 2018 18:10:26 +0530 Subject: [PATCH 0712/1001] ARM: dts: msm: Correct the spmi core size for SM6150 Currently spmi core size is defined as 0x2300, which can lead to the buffer overflow if the desired APID is not found. Fix it for SM6150 and sdmmagpie. Change-Id: I58e5f0786ab61550ef1e7a97219b4e9fe1ef0e99 Signed-off-by: Kiran Gunda --- arch/arm64/boot/dts/qcom/sdmmagpie.dtsi | 2 +- arch/arm64/boot/dts/qcom/sm6150.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index bd56ac97bac0..df56fc18dd07 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -1520,7 +1520,7 @@ spmi_bus: qcom,spmi@c440000 { compatible = "qcom,spmi-pmic-arb"; - reg = <0xc440000 0x2300>, + reg = <0xc440000 0x1100>, <0xc600000 0x2000000>, <0xe600000 0x100000>, <0xe700000 0xa0000>, diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index ce1117cba29a..3795a20bddeb 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -1694,7 +1694,7 @@ spmi_bus: qcom,spmi@c440000 { compatible = "qcom,spmi-pmic-arb"; - reg = <0xc440000 0x2300>, + reg = <0xc440000 0x1100>, <0xc600000 0x2000000>, <0xe600000 0x100000>, <0xe700000 0xa0000>, -- GitLab From 86b4123d2802ff46f98d10da92664d86f57094b9 Mon Sep 17 00:00:00 2001 From: Ram Prakash Gupta Date: Fri, 10 Aug 2018 19:21:07 +0530 Subject: [PATCH 0713/1001] ARM: defconfig: Enable CONFIG_MMC_CQ_HCI for sm6150 Enable emmc command queue interface support for sm6150. Change-Id: Id8897e1734089fe14625f2b2259f427cf84c1c70 Signed-off-by: Ram Prakash Gupta --- arch/arm64/configs/vendor/sdmsteppe-perf_defconfig | 1 + arch/arm64/configs/vendor/sdmsteppe_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig index afcb03ddfed3..aaad4dd149fb 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig @@ -423,6 +423,7 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP_FLASH_V2=y diff --git a/arch/arm64/configs/vendor/sdmsteppe_defconfig b/arch/arm64/configs/vendor/sdmsteppe_defconfig index 04247ca6e677..97059819f3b1 100644 --- a/arch/arm64/configs/vendor/sdmsteppe_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe_defconfig @@ -436,6 +436,7 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP_FLASH_V2=y -- GitLab From 31d843bde1e4b4f6642eaed5ceb6092666aac3ed Mon Sep 17 00:00:00 2001 From: Kiran Gunda Date: Thu, 9 Aug 2018 17:16:24 +0530 Subject: [PATCH 0714/1001] ARM: dts: msm: Update the max voltage of the SMPSC2 for SM6150 Update the SMPSC2 max voltage from 1200mv to 648mv to match the regulator spec. Change-Id: I7b6a39f8c9c948bd4c1472b0c7750856d77cf980 Signed-off-by: Kiran Gunda --- arch/arm64/boot/dts/qcom/sm6150-regulator.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150-regulator.dtsi b/arch/arm64/boot/dts/qcom/sm6150-regulator.dtsi index c77682c57ea6..8b540cf96627 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-regulator.dtsi @@ -117,7 +117,7 @@ regulator-name = "pm6150l_s2"; qcom,set = ; regulator-min-microvolt = <348000>; - regulator-max-microvolt = <1200000>; + regulator-max-microvolt = <648000>; qcom,init-voltage = <348000>; }; }; -- GitLab From ed5be30b154601488bcec69ee7880fa9c5da3d5f Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 31 Oct 2017 00:15:47 +0100 Subject: [PATCH 0715/1001] debugfs: add support for more elaborate ->d_fsdata Currently, the user provided fops, "real_fops", are stored directly into ->d_fsdata. In order to be able to store more per-file state and thus prepare for more granular file removal protection, wrap the real_fops into a dynamically allocated container struct, debugfs_fsdata. A struct debugfs_fsdata gets allocated at file creation and freed from the newly intoduced ->d_release(). Finally, move the implementation of debugfs_real_fops() out of the public debugfs header such that struct debugfs_fsdata's declaration can be kept private. Change-Id: I3517697b316d5ed1bbc9e5b24b66463479c6fd4d Signed-off-by: Nicolai Stange Signed-off-by: Greg Kroah-Hartman Git-commit: 7c8d469877b16d2c1cecf101a0abb7b218db85bc Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Raghavendra Rao Ananta --- fs/debugfs/file.c | 12 ++++++++++++ fs/debugfs/inode.c | 22 +++++++++++++++++++--- fs/debugfs/internal.h | 4 ++++ include/linux/debugfs.h | 20 +++----------------- 4 files changed, 38 insertions(+), 20 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 6dabc4a10396..b6f5ddab66bf 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -97,6 +97,18 @@ EXPORT_SYMBOL_GPL(debugfs_use_file_finish); #define F_DENTRY(filp) ((filp)->f_path.dentry) +const struct file_operations *debugfs_real_fops(const struct file *filp) + __must_hold(&debugfs_srcu) +{ + struct debugfs_fsdata *fsd = F_DENTRY(filp)->d_fsdata; + /* + * Neither the pointer to the struct file_operations, nor its + * contents ever change -- srcu_dereference() is not needed here. + */ + return fsd->real_fops; +} +EXPORT_SYMBOL_GPL(debugfs_real_fops); + static int open_proxy_open(struct inode *inode, struct file *filp) { const struct dentry *dentry = F_DENTRY(filp); diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index c59f015f386e..a9c3d3e9af39 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -185,6 +185,11 @@ static const struct super_operations debugfs_super_operations = { .evict_inode = debugfs_evict_inode, }; +static void debugfs_release_dentry(struct dentry *dentry) +{ + kfree(dentry->d_fsdata); +} + static struct vfsmount *debugfs_automount(struct path *path) { debugfs_automount_t f; @@ -194,6 +199,7 @@ static struct vfsmount *debugfs_automount(struct path *path) static const struct dentry_operations debugfs_dops = { .d_delete = always_delete_dentry, + .d_release = debugfs_release_dentry, .d_automount = debugfs_automount, }; @@ -341,24 +347,34 @@ static struct dentry *__debugfs_create_file(const char *name, umode_t mode, { struct dentry *dentry; struct inode *inode; + struct debugfs_fsdata *fsd; + + fsd = kmalloc(sizeof(*fsd), GFP_KERNEL); + if (!fsd) + return NULL; if (!(mode & S_IFMT)) mode |= S_IFREG; BUG_ON(!S_ISREG(mode)); dentry = start_creating(name, parent); - if (IS_ERR(dentry)) + if (IS_ERR(dentry)) { + kfree(fsd); return NULL; + } inode = debugfs_get_inode(dentry->d_sb); - if (unlikely(!inode)) + if (unlikely(!inode)) { + kfree(fsd); return failed_creating(dentry); + } inode->i_mode = mode; inode->i_private = data; inode->i_fop = proxy_fops; - dentry->d_fsdata = (void *)real_fops; + fsd->real_fops = real_fops; + dentry->d_fsdata = fsd; d_instantiate(dentry, inode); fsnotify_create(d_inode(dentry->d_parent), dentry); diff --git a/fs/debugfs/internal.h b/fs/debugfs/internal.h index b3e8443a1f47..512601eed3ce 100644 --- a/fs/debugfs/internal.h +++ b/fs/debugfs/internal.h @@ -19,4 +19,8 @@ extern const struct file_operations debugfs_noop_file_operations; extern const struct file_operations debugfs_open_proxy_file_operations; extern const struct file_operations debugfs_full_proxy_file_operations; +struct debugfs_fsdata { + const struct file_operations *real_fops; +}; + #endif /* _DEBUGFS_INTERNAL_H_ */ diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index b93efc8feecd..cbee5f4a02a3 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -45,23 +45,6 @@ extern struct dentry *arch_debugfs_dir; extern struct srcu_struct debugfs_srcu; -/** - * debugfs_real_fops - getter for the real file operation - * @filp: a pointer to a struct file - * - * Must only be called under the protection established by - * debugfs_use_file_start(). - */ -static inline const struct file_operations *debugfs_real_fops(const struct file *filp) - __must_hold(&debugfs_srcu) -{ - /* - * Neither the pointer to the struct file_operations, nor its - * contents ever change -- srcu_dereference() is not needed here. - */ - return filp->f_path.dentry->d_fsdata; -} - #define DEFINE_DEBUGFS_ATTRIBUTE(__fops, __get, __set, __fmt) \ static int __fops ## _open(struct inode *inode, struct file *file) \ { \ @@ -112,6 +95,9 @@ int debugfs_use_file_start(const struct dentry *dentry, int *srcu_idx) void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu); +const struct file_operations *debugfs_real_fops(const struct file *filp) + __must_hold(&debugfs_srcu); + ssize_t debugfs_attr_read(struct file *file, char __user *buf, size_t len, loff_t *ppos); ssize_t debugfs_attr_write(struct file *file, const char __user *buf, -- GitLab From 9d70524d0ad367e721c8977f1b63ca2fb4a6bab0 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 31 Oct 2017 00:15:48 +0100 Subject: [PATCH 0716/1001] debugfs: implement per-file removal protection Since commit 49d200deaa68 ("debugfs: prevent access to removed files' private data"), accesses to a file's private data are protected from concurrent removal by covering all file_operations with a SRCU read section and sychronizing with those before returning from debugfs_remove() by means of synchronize_srcu(). As pointed out by Johannes Berg, there are debugfs files with forever blocking file_operations. Their corresponding SRCU read side sections would block any debugfs_remove() forever as well, even unrelated ones. This results in a livelock. Because a remover can't cancel any indefinite blocking within foreign files, this is a problem. Resolve this by introducing support for more granular protection on a per-file basis. This is implemented by introducing an 'active_users' refcount_t to the per-file struct debugfs_fsdata state. At file creation time, it is set to one and a debugfs_remove() will drop that initial reference. The new debugfs_file_get() and debugfs_file_put(), intended to be used in place of former debugfs_use_file_start() and debugfs_use_file_finish(), increment and decrement it respectively. Once the count drops to zero, debugfs_file_put() will signal a completion which is possibly being waited for from debugfs_remove(). Thus, as long as there is a debugfs_file_get() not yet matched by a corresponding debugfs_file_put() around, debugfs_remove() will block. Actual users of debugfs_use_file_start() and -finish() will get converted to the new debugfs_file_get() and debugfs_file_put() by followup patches. Change-Id: Icfde769b8604854a2e6f91d1070ac72dc2a8f7fc Fixes: 49d200deaa68 ("debugfs: prevent access to removed files' private data") Reported-by: Johannes Berg Signed-off-by: Nicolai Stange Signed-off-by: Greg Kroah-Hartman Git-commit: e9117a5a4bf65d8e99f060d356a04d27a60b436d Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Raghavendra Rao Ananta --- fs/debugfs/file.c | 48 +++++++++++++++++++++++++++++++++++++++++ fs/debugfs/inode.c | 29 +++++++++++++++++++------ fs/debugfs/internal.h | 2 ++ include/linux/debugfs.h | 11 ++++++++++ 4 files changed, 84 insertions(+), 6 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index b6f5ddab66bf..6644bfdea2f8 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -109,6 +109,54 @@ const struct file_operations *debugfs_real_fops(const struct file *filp) } EXPORT_SYMBOL_GPL(debugfs_real_fops); +/** + * debugfs_file_get - mark the beginning of file data access + * @dentry: the dentry object whose data is being accessed. + * + * Up to a matching call to debugfs_file_put(), any successive call + * into the file removing functions debugfs_remove() and + * debugfs_remove_recursive() will block. Since associated private + * file data may only get freed after a successful return of any of + * the removal functions, you may safely access it after a successful + * call to debugfs_file_get() without worrying about lifetime issues. + * + * If -%EIO is returned, the file has already been removed and thus, + * it is not safe to access any of its data. If, on the other hand, + * it is allowed to access the file data, zero is returned. + */ +int debugfs_file_get(struct dentry *dentry) +{ + struct debugfs_fsdata *fsd = dentry->d_fsdata; + + /* Avoid starvation of removers. */ + if (d_unlinked(dentry)) + return -EIO; + + if (!refcount_inc_not_zero(&fsd->active_users)) + return -EIO; + + return 0; +} +EXPORT_SYMBOL_GPL(debugfs_file_get); + +/** + * debugfs_file_put - mark the end of file data access + * @dentry: the dentry object formerly passed to + * debugfs_file_get(). + * + * Allow any ongoing concurrent call into debugfs_remove() or + * debugfs_remove_recursive() blocked by a former call to + * debugfs_file_get() to proceed and return to its caller. + */ +void debugfs_file_put(struct dentry *dentry) +{ + struct debugfs_fsdata *fsd = dentry->d_fsdata; + + if (refcount_dec_and_test(&fsd->active_users)) + complete(&fsd->active_users_drained); +} +EXPORT_SYMBOL_GPL(debugfs_file_put); + static int open_proxy_open(struct inode *inode, struct file *filp) { const struct dentry *dentry = F_DENTRY(filp); diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index a9c3d3e9af39..6449eb935540 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -374,6 +374,7 @@ static struct dentry *__debugfs_create_file(const char *name, umode_t mode, inode->i_fop = proxy_fops; fsd->real_fops = real_fops; + refcount_set(&fsd->active_users, 1); dentry->d_fsdata = fsd; d_instantiate(dentry, inode); @@ -631,18 +632,34 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent, } EXPORT_SYMBOL_GPL(debugfs_create_symlink); +static void __debugfs_remove_file(struct dentry *dentry, struct dentry *parent) +{ + struct debugfs_fsdata *fsd; + + simple_unlink(d_inode(parent), dentry); + d_delete(dentry); + fsd = dentry->d_fsdata; + init_completion(&fsd->active_users_drained); + if (!refcount_dec_and_test(&fsd->active_users)) + wait_for_completion(&fsd->active_users_drained); +} + static int __debugfs_remove(struct dentry *dentry, struct dentry *parent) { int ret = 0; if (simple_positive(dentry)) { dget(dentry); - if (d_is_dir(dentry)) - ret = simple_rmdir(d_inode(parent), dentry); - else - simple_unlink(d_inode(parent), dentry); - if (!ret) - d_delete(dentry); + if (!d_is_reg(dentry)) { + if (d_is_dir(dentry)) + ret = simple_rmdir(d_inode(parent), dentry); + else + simple_unlink(d_inode(parent), dentry); + if (!ret) + d_delete(dentry); + } else { + __debugfs_remove_file(dentry, parent); + } dput(dentry); } return ret; diff --git a/fs/debugfs/internal.h b/fs/debugfs/internal.h index 512601eed3ce..0eea99432840 100644 --- a/fs/debugfs/internal.h +++ b/fs/debugfs/internal.h @@ -21,6 +21,8 @@ extern const struct file_operations debugfs_full_proxy_file_operations; struct debugfs_fsdata { const struct file_operations *real_fops; + refcount_t active_users; + struct completion active_users_drained; }; #endif /* _DEBUGFS_INTERNAL_H_ */ diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index cbee5f4a02a3..3b914d588148 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -98,6 +98,9 @@ void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu); const struct file_operations *debugfs_real_fops(const struct file *filp) __must_hold(&debugfs_srcu); +int debugfs_file_get(struct dentry *dentry); +void debugfs_file_put(struct dentry *dentry); + ssize_t debugfs_attr_read(struct file *file, char __user *buf, size_t len, loff_t *ppos); ssize_t debugfs_attr_write(struct file *file, const char __user *buf, @@ -236,6 +239,14 @@ static inline void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu) { } +static inline int debugfs_file_get(struct dentry *dentry) +{ + return 0; +} + +static inline void debugfs_file_put(struct dentry *dentry) +{ } + static inline ssize_t debugfs_attr_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) { -- GitLab From d7a077d779a31883e5aa9f7683d4327aadaa19a5 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 31 Oct 2017 00:15:49 +0100 Subject: [PATCH 0717/1001] debugfs: debugfs_real_fops(): drop __must_hold sparse annotation Currently, debugfs_real_fops() is annotated with a __must_hold(&debugfs_srcu) sparse annotation. With the conversion of the SRCU based protection of users against concurrent file removals to a per-file refcount based scheme, this becomes wrong. Drop this annotation. Change-Id: I261ad90f4af2fe28379be1256ec86a8b41f1dd08 Signed-off-by: Nicolai Stange Signed-off-by: Greg Kroah-Hartman Git-commit: 055ab8e3e3d52e005d2047b14ce63551b3a8b8b5 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Raghavendra Rao Ananta --- fs/debugfs/file.c | 6 +----- include/linux/debugfs.h | 3 +-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 6644bfdea2f8..08511678b782 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -98,13 +98,9 @@ EXPORT_SYMBOL_GPL(debugfs_use_file_finish); #define F_DENTRY(filp) ((filp)->f_path.dentry) const struct file_operations *debugfs_real_fops(const struct file *filp) - __must_hold(&debugfs_srcu) { struct debugfs_fsdata *fsd = F_DENTRY(filp)->d_fsdata; - /* - * Neither the pointer to the struct file_operations, nor its - * contents ever change -- srcu_dereference() is not needed here. - */ + return fsd->real_fops; } EXPORT_SYMBOL_GPL(debugfs_real_fops); diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index 3b914d588148..c5eda259b9d6 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -95,8 +95,7 @@ int debugfs_use_file_start(const struct dentry *dentry, int *srcu_idx) void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu); -const struct file_operations *debugfs_real_fops(const struct file *filp) - __must_hold(&debugfs_srcu); +const struct file_operations *debugfs_real_fops(const struct file *filp); int debugfs_file_get(struct dentry *dentry); void debugfs_file_put(struct dentry *dentry); -- GitLab From 2556cfd8c0de270af27f5b633d93d62764c50590 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 31 Oct 2017 00:15:50 +0100 Subject: [PATCH 0718/1001] debugfs: convert to debugfs_file_get() and -put() Convert all calls to the now obsolete debugfs_use_file_start() and debugfs_use_file_finish() from the debugfs core itself to the new debugfs_file_get() and debugfs_file_put() API. Change-Id: Ib0f291b138c7b9eacbe80678c283051f799f5042 Fixes: 49d200deaa68 ("debugfs: prevent access to removed files' private data") Signed-off-by: Nicolai Stange Signed-off-by: Greg Kroah-Hartman Git-commit: 69d29f9e6a53559895e6f785f6cf72daa738f132 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Raghavendra Rao Ananta --- fs/debugfs/file.c | 106 ++++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 56 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 08511678b782..d3a972b45ff0 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -155,15 +155,12 @@ EXPORT_SYMBOL_GPL(debugfs_file_put); static int open_proxy_open(struct inode *inode, struct file *filp) { - const struct dentry *dentry = F_DENTRY(filp); + struct dentry *dentry = F_DENTRY(filp); const struct file_operations *real_fops = NULL; - int srcu_idx, r; + int r = 0; - r = debugfs_use_file_start(dentry, &srcu_idx); - if (r) { - r = -ENOENT; - goto out; - } + if (debugfs_file_get(dentry)) + return -ENOENT; real_fops = debugfs_real_fops(filp); real_fops = fops_get(real_fops); @@ -180,7 +177,7 @@ static int open_proxy_open(struct inode *inode, struct file *filp) r = real_fops->open(inode, filp); out: - debugfs_use_file_finish(srcu_idx); + debugfs_file_put(dentry); return r; } @@ -194,16 +191,16 @@ const struct file_operations debugfs_open_proxy_file_operations = { #define FULL_PROXY_FUNC(name, ret_type, filp, proto, args) \ static ret_type full_proxy_ ## name(proto) \ { \ - const struct dentry *dentry = F_DENTRY(filp); \ + struct dentry *dentry = F_DENTRY(filp); \ const struct file_operations *real_fops = \ debugfs_real_fops(filp); \ - int srcu_idx; \ ret_type r; \ \ - r = debugfs_use_file_start(dentry, &srcu_idx); \ - if (likely(!r)) \ - r = real_fops->name(args); \ - debugfs_use_file_finish(srcu_idx); \ + r = debugfs_file_get(dentry); \ + if (unlikely(r)) \ + return r; \ + r = real_fops->name(args); \ + debugfs_file_put(dentry); \ return r; \ } @@ -228,18 +225,15 @@ FULL_PROXY_FUNC(unlocked_ioctl, long, filp, static unsigned int full_proxy_poll(struct file *filp, struct poll_table_struct *wait) { - const struct dentry *dentry = F_DENTRY(filp); const struct file_operations *real_fops = debugfs_real_fops(filp); - int srcu_idx; + struct dentry *dentry = F_DENTRY(filp); unsigned int r = 0; - if (debugfs_use_file_start(dentry, &srcu_idx)) { - debugfs_use_file_finish(srcu_idx); + if (debugfs_file_get(dentry)) return POLLHUP; - } r = real_fops->poll(filp, wait); - debugfs_use_file_finish(srcu_idx); + debugfs_file_put(dentry); return r; } @@ -283,16 +277,13 @@ static void __full_proxy_fops_init(struct file_operations *proxy_fops, static int full_proxy_open(struct inode *inode, struct file *filp) { - const struct dentry *dentry = F_DENTRY(filp); + struct dentry *dentry = F_DENTRY(filp); const struct file_operations *real_fops = NULL; struct file_operations *proxy_fops = NULL; - int srcu_idx, r; + int r = 0; - r = debugfs_use_file_start(dentry, &srcu_idx); - if (r) { - r = -ENOENT; - goto out; - } + if (debugfs_file_get(dentry)) + return -ENOENT; real_fops = debugfs_real_fops(filp); real_fops = fops_get(real_fops); @@ -330,7 +321,7 @@ static int full_proxy_open(struct inode *inode, struct file *filp) kfree(proxy_fops); fops_put(real_fops); out: - debugfs_use_file_finish(srcu_idx); + debugfs_file_put(dentry); return r; } @@ -341,13 +332,14 @@ const struct file_operations debugfs_full_proxy_file_operations = { ssize_t debugfs_attr_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) { + struct dentry *dentry = F_DENTRY(file); ssize_t ret; - int srcu_idx; - ret = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); - if (likely(!ret)) - ret = simple_attr_read(file, buf, len, ppos); - debugfs_use_file_finish(srcu_idx); + ret = debugfs_file_get(dentry); + if (unlikely(ret)) + return ret; + ret = simple_attr_read(file, buf, len, ppos); + debugfs_file_put(dentry); return ret; } EXPORT_SYMBOL_GPL(debugfs_attr_read); @@ -355,13 +347,14 @@ EXPORT_SYMBOL_GPL(debugfs_attr_read); ssize_t debugfs_attr_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { + struct dentry *dentry = F_DENTRY(file); ssize_t ret; - int srcu_idx; - ret = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); - if (likely(!ret)) - ret = simple_attr_write(file, buf, len, ppos); - debugfs_use_file_finish(srcu_idx); + ret = debugfs_file_get(dentry); + if (unlikely(ret)) + return ret; + ret = simple_attr_write(file, buf, len, ppos); + debugfs_file_put(dentry); return ret; } EXPORT_SYMBOL_GPL(debugfs_attr_write); @@ -795,14 +788,14 @@ ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf, { char buf[3]; bool val; - int r, srcu_idx; + int r; + struct dentry *dentry = F_DENTRY(file); - r = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); - if (likely(!r)) - val = *(bool *)file->private_data; - debugfs_use_file_finish(srcu_idx); - if (r) + r = debugfs_file_get(dentry); + if (unlikely(r)) return r; + val = *(bool *)file->private_data; + debugfs_file_put(dentry); if (val) buf[0] = 'Y'; @@ -820,8 +813,9 @@ ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf, char buf[32]; size_t buf_size; bool bv; - int r, srcu_idx; + int r; bool *val = file->private_data; + struct dentry *dentry = F_DENTRY(file); buf_size = min(count, (sizeof(buf)-1)); if (copy_from_user(buf, user_buf, buf_size)) @@ -829,12 +823,11 @@ ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf, buf[buf_size] = '\0'; if (strtobool(buf, &bv) == 0) { - r = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); - if (likely(!r)) - *val = bv; - debugfs_use_file_finish(srcu_idx); - if (r) + r = debugfs_file_get(dentry); + if (unlikely(r)) return r; + *val = bv; + debugfs_file_put(dentry); } return count; @@ -896,14 +889,15 @@ static ssize_t read_file_blob(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct debugfs_blob_wrapper *blob = file->private_data; + struct dentry *dentry = F_DENTRY(file); ssize_t r; - int srcu_idx; - r = debugfs_use_file_start(F_DENTRY(file), &srcu_idx); - if (likely(!r)) - r = simple_read_from_buffer(user_buf, count, ppos, blob->data, - blob->size); - debugfs_use_file_finish(srcu_idx); + r = debugfs_file_get(dentry); + if (unlikely(r)) + return r; + r = simple_read_from_buffer(user_buf, count, ppos, blob->data, + blob->size); + debugfs_file_put(dentry); return r; } -- GitLab From a19fc3cddfcb4fda58e6d4c6f1bd527ff10365fc Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 31 Oct 2017 00:15:51 +0100 Subject: [PATCH 0719/1001] IB/hfi1: convert to debugfs_file_get() and -put() Convert all calls to the now obsolete debugfs_use_file_start() and debugfs_use_file_finish() to the new debugfs_file_get() and debugfs_file_put() API. Change-Id: Id8129d3c28135ad24efea95de956ecbdea81addc Fixes: 49d200deaa68 ("debugfs: prevent access to removed files' private data") Signed-off-by: Nicolai Stange Reviewed-by: Dennis Dalessandro Signed-off-by: Greg Kroah-Hartman Git-commit: 7cda7b8f97da9382bb945d541a85cde58d5dac27 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Raghavendra Rao Ananta --- drivers/infiniband/hw/hfi1/debugfs.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/debugfs.c b/drivers/infiniband/hw/hfi1/debugfs.c index f661b387e916..8ab2c40b13b2 100644 --- a/drivers/infiniband/hw/hfi1/debugfs.c +++ b/drivers/infiniband/hw/hfi1/debugfs.c @@ -71,13 +71,13 @@ static ssize_t hfi1_seq_read( loff_t *ppos) { struct dentry *d = file->f_path.dentry; - int srcu_idx; ssize_t r; - r = debugfs_use_file_start(d, &srcu_idx); - if (likely(!r)) - r = seq_read(file, buf, size, ppos); - debugfs_use_file_finish(srcu_idx); + r = debugfs_file_get(d); + if (unlikely(r)) + return r; + r = seq_read(file, buf, size, ppos); + debugfs_file_put(d); return r; } @@ -87,13 +87,13 @@ static loff_t hfi1_seq_lseek( int whence) { struct dentry *d = file->f_path.dentry; - int srcu_idx; loff_t r; - r = debugfs_use_file_start(d, &srcu_idx); - if (likely(!r)) - r = seq_lseek(file, offset, whence); - debugfs_use_file_finish(srcu_idx); + r = debugfs_file_get(d); + if (unlikely(r)) + return r; + r = seq_lseek(file, offset, whence); + debugfs_file_put(d); return r; } -- GitLab From 8832b80a655f691ad1ef8442951eb379674d625f Mon Sep 17 00:00:00 2001 From: Satya Durga Srinivasu Prabhala Date: Tue, 7 Aug 2018 11:38:51 -0700 Subject: [PATCH 0720/1001] sched/fair: Do load balancing of misfit task only when dst_cpu is idle 'commit 53adc803f95a ("FROMLIST: sched/fair: Consider misfit tasks when load-balancing")' introduces a change where a higher capacity CPUs could pull a misfit task from lower capacity via active load balancing. However it fails to take in to account if the dst cpu is already busy, we want to avoid overcrowding the dst cpu and further causing migrations away from it. Add a check to ensure that misfit tasks are pulled via active load balancing only if the dst cpu is idle. Change-Id: Iceee1c36dba445a45aaee5e380a729dac68e56c8 Signed-off-by: Satya Durga Srinivasu Prabhala --- kernel/sched/fair.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index d886396ba4c8..c7bd86920d6d 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -10697,7 +10697,8 @@ static int need_active_balance(struct lb_env *env) return 1; } - if (env->src_grp_type == group_misfit_task) + if (env->idle != CPU_NOT_IDLE && + env->src_grp_type == group_misfit_task) return 1; if (env->src_grp_type == group_overloaded && -- GitLab From 95bed8c6058b1ee353b182a0c4a69fe7cdb62b2e Mon Sep 17 00:00:00 2001 From: Kyle Piefer Date: Thu, 2 Aug 2018 13:05:43 -0700 Subject: [PATCH 0721/1001] msm: kgsl: Enable IFPC on A640 v2 The IFPC feature saves power between frames. Enable it on Adreno 640 v2 GPUs because it is now supported. Change-Id: Ie770eabc0aef295ede68d01650bed908f6ddc052 Signed-off-by: Kyle Piefer --- drivers/gpu/msm/adreno-gpulist.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h index 2547794bd78f..0cd3869ec4cd 100644 --- a/drivers/gpu/msm/adreno-gpulist.h +++ b/drivers/gpu/msm/adreno-gpulist.h @@ -408,7 +408,8 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .minor = 0, .patchid = ANY_ID, .features = ADRENO_64BIT | ADRENO_RPMH | ADRENO_GPMU | - ADRENO_CONTENT_PROTECTION | ADRENO_IOCOHERENT, + ADRENO_CONTENT_PROTECTION | ADRENO_IOCOHERENT | + ADRENO_IFPC, .sqefw_name = "a630_sqe.fw", .zap_name = "a640_zap", .gpudev = &adreno_a6xx_gpudev, -- GitLab From bd83235fe4895c58566c157d466db30884d77de5 Mon Sep 17 00:00:00 2001 From: Bharathraj Nagaraju Date: Wed, 25 Jul 2018 11:05:42 -0700 Subject: [PATCH 0722/1001] ARM: dts: msm: Add support for SA8155 V2 Add Initial DTS files to support SA8155 V2 chipset Change-Id: Ia76fb05d5d6e62dae4e23d65384c8d89b5134450 Signed-off-by: Bharathraj Nagaraju --- arch/arm64/boot/dts/qcom/Makefile | 6 +++-- arch/arm64/boot/dts/qcom/sa8155-adp-star.dts | 2 +- arch/arm64/boot/dts/qcom/sa8155-v1.dtsi | 21 ++++++++++++++++++ .../boot/dts/qcom/sa8155-v2-adp-star.dts | 22 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sa8155-v2.dts | 22 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sa8155-v2.dtsi | 20 +++++++++++++++++ arch/arm64/boot/dts/qcom/sa8155.dts | 2 +- arch/arm64/boot/dts/qcom/sa8155.dtsi | 9 -------- .../boot/dts/qcom/sa8155p-v2-adp-star.dts | 22 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sa8155p-v2.dts | 22 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sa8155p-v2.dtsi | 19 ++++++++++++++++ arch/arm64/boot/dts/qcom/sa8155p.dtsi | 4 ++-- 12 files changed, 156 insertions(+), 15 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/sa8155-v1.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sa8155-v2-adp-star.dts create mode 100644 arch/arm64/boot/dts/qcom/sa8155-v2.dts create mode 100644 arch/arm64/boot/dts/qcom/sa8155-v2.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sa8155p-v2-adp-star.dts create mode 100644 arch/arm64/boot/dts/qcom/sa8155p-v2.dts create mode 100644 arch/arm64/boot/dts/qcom/sa8155p-v2.dtsi diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index b1b5fcacab79..07f4e8043d8c 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -38,8 +38,8 @@ sm8150-mtp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2. sm8150-rumi-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb sm8150-qrd-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb sm8150-qrd-dvt-overlay.dtbo-base := sm8150-v2.dtb sm8150p-v2.dtb -sa8155-adp-star-overlay.dtbo-base := sa8155.dtb -sa8155p-adp-star-overlay.dtbo-base := sa8155p.dtb +sa8155-adp-star-overlay.dtbo-base := sa8155.dtb sa8155-v2.dtb +sa8155p-adp-star-overlay.dtbo-base := sa8155p.dtb sa8155p-v2.dtb sm8150-sdx50m-cdp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb sm8150-sdx50m-mtp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb sm8150-sdx50m-mtp-2.5k-panel-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb @@ -51,6 +51,8 @@ dtb-$(CONFIG_ARCH_SM8150) += sm8150-rumi.dtb \ sm8150-qrd.dtb \ sa8155-adp-star.dtb \ sa8155p-adp-star.dtb \ + sa8155-v2-adp-star.dtb \ + sa8155p-v2-adp-star.dtb \ sm8150-v2-rumi.dtb \ sm8150-v2-mtp.dtb \ sm8150-v2-cdp.dtb \ diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-star.dts b/arch/arm64/boot/dts/qcom/sa8155-adp-star.dts index d4322630a3a0..351ce2b1a19f 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-adp-star.dts +++ b/arch/arm64/boot/dts/qcom/sa8155-adp-star.dts @@ -11,7 +11,7 @@ */ /dts-v1/; -#include "sa8155.dtsi" +#include "sa8155-v1.dtsi" #include "sa8155-adp-star.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sa8155-v1.dtsi b/arch/arm64/boot/dts/qcom/sa8155-v1.dtsi new file mode 100644 index 000000000000..24b43228ab9c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155-v1.dtsi @@ -0,0 +1,21 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sm8150.dtsi" +#include "sa8155.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155"; + compatible = "qcom,sa8155"; + qcom,msm-name = "SA8155 V1"; + qcom,msm-id = <362 0x10000>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155-v2-adp-star.dts b/arch/arm64/boot/dts/qcom/sa8155-v2-adp-star.dts new file mode 100644 index 000000000000..7f411ed1e62e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155-v2-adp-star.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sa8155-v2.dtsi" +#include "sa8155-adp-star.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155 V2 ADP STAR"; + compatible = "qcom,sa8155-adp-star", "qcom,sa8155", "qcom,adp-star"; + qcom,board-id = <25 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155-v2.dts b/arch/arm64/boot/dts/qcom/sa8155-v2.dts new file mode 100644 index 000000000000..4e3838fc5e3c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155-v2.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sa8155-v2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155 v2 SoC"; + compatible = "qcom,sa8155"; + qcom,pmic-name = "PM8150"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155-v2.dtsi b/arch/arm64/boot/dts/qcom/sa8155-v2.dtsi new file mode 100644 index 000000000000..3f14c5915341 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155-v2.dtsi @@ -0,0 +1,20 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sm8150-v2.dtsi" +#include "sa8155.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155 V2"; + qcom,msm-name = "SA8155 V2"; + qcom,msm-id = <362 0x20000>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155.dts b/arch/arm64/boot/dts/qcom/sa8155.dts index 0fbb4769485b..6309bd7a211d 100644 --- a/arch/arm64/boot/dts/qcom/sa8155.dts +++ b/arch/arm64/boot/dts/qcom/sa8155.dts @@ -12,7 +12,7 @@ /dts-v1/; -#include "sa8155.dtsi" +#include "sa8155-v1.dtsi" / { model = "Qualcomm Technologies, Inc. SA8155 SoC"; diff --git a/arch/arm64/boot/dts/qcom/sa8155.dtsi b/arch/arm64/boot/dts/qcom/sa8155.dtsi index ce073c9f8920..b3c27a827699 100644 --- a/arch/arm64/boot/dts/qcom/sa8155.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155.dtsi @@ -10,15 +10,6 @@ * GNU General Public License for more details. */ -#include "sm8150.dtsi" - -/ { - model = "Qualcomm Technologies, Inc. SA8155"; - compatible = "qcom,sa8155"; - qcom,msm-name = "SA8155"; - qcom,msm-id = <362 0x10000>; -}; - /* Remove regulator nodes specific to SA8155 */ &soc { /delete-node/ regulator-pm8150-s4; diff --git a/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-star.dts b/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-star.dts new file mode 100644 index 000000000000..838d96387275 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-star.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sa8155p-v2.dtsi" +#include "sa8155-adp-star.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155P V2 ADP STAR"; + compatible = "qcom,sa8155p-adp-star", "qcom,sa8155p", "qcom,adp-star"; + qcom,board-id = <25 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155p-v2.dts b/arch/arm64/boot/dts/qcom/sa8155p-v2.dts new file mode 100644 index 000000000000..62889ab921c6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155p-v2.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sa8155p-v2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155P v2 SoC"; + compatible = "qcom,sa8155p"; + qcom,pmic-name = "PM8150"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155p-v2.dtsi b/arch/arm64/boot/dts/qcom/sa8155p-v2.dtsi new file mode 100644 index 000000000000..ac6ec4a18d72 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155p-v2.dtsi @@ -0,0 +1,19 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sa8155-v2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155P v2"; + qcom,msm-name = "SA8155P v2"; + qcom,msm-id = <367 0x20000>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155p.dtsi b/arch/arm64/boot/dts/qcom/sa8155p.dtsi index 9b49c4fbd11b..7d70bb52ed77 100644 --- a/arch/arm64/boot/dts/qcom/sa8155p.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155p.dtsi @@ -10,11 +10,11 @@ * GNU General Public License for more details. */ -#include "sa8155.dtsi" +#include "sa8155-v1.dtsi" / { model = "Qualcomm Technologies, Inc. SA8155P "; - qcom,msm-name = "SA8155P"; + qcom,msm-name = "SA8155P V1"; compatible = "qcom,sa8155p"; qcom,msm-id = <367 0x10000>; }; -- GitLab From 8e44f6c0cdcbea0dee8a13818ad5b7bc6e6d95e3 Mon Sep 17 00:00:00 2001 From: Bharathraj Nagaraju Date: Wed, 1 Aug 2018 12:10:43 -0700 Subject: [PATCH 0723/1001] ARM: dts: msm: update UFS regulator for SA8155 V2 The VDDA_UFS_2LN_CORE supply has been changed from L18C on SA8155 V1 to L5A on SA8155 V2. Override this UFS regulator with the new mapping. Change-Id: I5353111448d70a5a574f72cca16a490a93c78809 Signed-off-by: Bharathraj Nagaraju --- arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi | 1 - arch/arm64/boot/dts/qcom/sa8155-v2.dtsi | 4 ++++ arch/arm64/boot/dts/qcom/sa8155.dtsi | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi index a300ec8e5b60..0ece526b4a45 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi @@ -138,7 +138,6 @@ &ufsphy_mem { compatible = "qcom,ufs-phy-qmp-v4"; - vdda-phy-supply = <&pm8150_2_l18>; vdda-pll-supply = <&pm8150_2_l8>; vdda-phy-max-microamp = <87100>; vdda-pll-max-microamp = <18300>; diff --git a/arch/arm64/boot/dts/qcom/sa8155-v2.dtsi b/arch/arm64/boot/dts/qcom/sa8155-v2.dtsi index 3f14c5915341..5f13249b2f5c 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-v2.dtsi @@ -18,3 +18,7 @@ qcom,msm-name = "SA8155 V2"; qcom,msm-id = <362 0x20000>; }; + +&ufsphy_mem { + vdda-phy-supply = <&pm8150_1_l5>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155.dtsi b/arch/arm64/boot/dts/qcom/sa8155.dtsi index b3c27a827699..e232fdf7892b 100644 --- a/arch/arm64/boot/dts/qcom/sa8155.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155.dtsi @@ -171,6 +171,10 @@ vdd_parent-supply = <&pm8150_2_s3_level>; }; +&ufsphy_mem { + vdda-phy-supply = <&pm8150_2_l18>; +}; + &thermal_zones { aoss0-lowf { cooling-maps { -- GitLab From 9d7f74f9da216cbd51200b4ab627ea75b8bf57ae Mon Sep 17 00:00:00 2001 From: Srinivas Ramana Date: Mon, 13 Aug 2018 23:04:14 +0530 Subject: [PATCH 0724/1001] pinctrl: sm6150: fix SDC and UFS reset pin groups offsets SDC and UFS_RESET pin groups are having a wrong offset. Fix it. Change-Id: Ieb25fefc9960fb59f2ecac583f508515d3a5e18d Signed-off-by: Srinivas Ramana --- drivers/pinctrl/qcom/pinctrl-sm6150.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-sm6150.c b/drivers/pinctrl/qcom/pinctrl-sm6150.c index 937ffde55963..39448b33c79f 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm6150.c +++ b/drivers/pinctrl/qcom/pinctrl-sm6150.c @@ -1548,14 +1548,14 @@ static const struct msm_pingroup sm6150_groups[] = { NA, NA, NA, NA), [121] = PINGROUP(121, SOUTH, mclk1, NA, NA, NA, NA, NA, NA, NA, NA), [122] = PINGROUP(122, SOUTH, mclk2, NA, NA, NA, NA, NA, NA, NA, NA), - [123] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x9a000, 15, 0), - [124] = SDC_QDSD_PINGROUP(sdc1_clk, 0x9a000, 13, 6), - [125] = SDC_QDSD_PINGROUP(sdc1_cmd, 0x9a000, 11, 3), - [126] = SDC_QDSD_PINGROUP(sdc1_data, 0x9a000, 9, 0), - [127] = SDC_QDSD_PINGROUP(sdc2_clk, 0x98000, 14, 6), - [128] = SDC_QDSD_PINGROUP(sdc2_cmd, 0x98000, 11, 3), - [129] = SDC_QDSD_PINGROUP(sdc2_data, 0x98000, 9, 0), - [130] = UFS_RESET(ufs_reset, 0x9f000), + [123] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x59a000, 15, 0), + [124] = SDC_QDSD_PINGROUP(sdc1_clk, 0x59a000, 13, 6), + [125] = SDC_QDSD_PINGROUP(sdc1_cmd, 0x59a000, 11, 3), + [126] = SDC_QDSD_PINGROUP(sdc1_data, 0x59a000, 9, 0), + [127] = SDC_QDSD_PINGROUP(sdc2_clk, 0xd98000, 14, 6), + [128] = SDC_QDSD_PINGROUP(sdc2_cmd, 0xd98000, 11, 3), + [129] = SDC_QDSD_PINGROUP(sdc2_data, 0xd98000, 9, 0), + [130] = UFS_RESET(ufs_reset, 0x59f000), }; static struct msm_dir_conn sm6150_dir_conn[] = { -- GitLab From 72915668f77dbca53084e7bf7cde2b481eff20ca Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Fri, 3 Aug 2018 13:48:20 -0700 Subject: [PATCH 0725/1001] arm: dts: msm: Update USB QMP DP PHY settings for sm8150 v2 Add override for SM8150 V2 for USB QMP DP PHY initialization settings based on V2 version 2.1. These provide V2 specific tuning for improved USB Gen2 performance. Change-Id: I7fc838848598bfa155d77b47a74cb62e345bb4c2 Signed-off-by: Jack Pham --- arch/arm64/boot/dts/qcom/sm8150-v2.dtsi | 144 ++++++++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi b/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi index 4e620b8c2997..9780dc4f0cfc 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi @@ -669,3 +669,147 @@ < 2649600 MHZ_TO_MBPS( 933, 16) >, < 3000000 MHZ_TO_MBPS(1000, 16) >; }; + +&usb_qmp_dp_phy { + qcom,qmp-phy-init-seq = + ; +}; -- GitLab From 158117e9d62c967da1da50ba28672c3d3ccc04ee Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Fri, 10 Aug 2018 11:16:19 -0700 Subject: [PATCH 0726/1001] msm: camera: isp: Report bubble on request in wait list We need to report error on the request in wait list instead of pending list. Also, if bubble report flag is enabled then this request will be reapplied, hence move it back to pending list. Change-Id: I6283c223f2e6232f811407487d86b6b7872ff011 Signed-off-by: Karthik Anantha Ram --- .../media/platform/msm/camera/cam_isp/cam_isp_context.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c index d14718c27c40..3fcfefe54e36 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c @@ -723,9 +723,9 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, struct cam_context *ctx = ctx_isp->base; uint64_t request_id = 0; - if (list_empty(&ctx->pending_req_list)) { + if (list_empty(&ctx->wait_req_list)) { /* - * If no pending req in epoch, this is an error case. + * If no wait req in epoch, this is an error case. * The recovery is to go back to sof state */ CAM_ERR(CAM_ISP, "No pending request"); @@ -738,7 +738,7 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, goto end; } - req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request, + req = list_first_entry(&ctx->wait_req_list, struct cam_ctx_request, list); req_isp = (struct cam_isp_ctx_req *)req->req_priv; @@ -747,6 +747,9 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, ctx->ctx_crm_intf->notify_err) { struct cam_req_mgr_error_notify notify; + list_del_init(&req->list); + list_add(&req->list, &ctx->pending_req_list); + notify.link_hdl = ctx->link_hdl; notify.dev_hdl = ctx->dev_hdl; notify.req_id = req->request_id; -- GitLab From 68a68b27ce8fe80f5a994adc9a2921506727194f Mon Sep 17 00:00:00 2001 From: Alok Pandey Date: Tue, 3 Jul 2018 14:34:22 +0530 Subject: [PATCH 0727/1001] msm: camera: isp: Add active list request flush support If umd send flush all, isp driver flushes only pending list requests. Currently, the expectation is that the active list and wait request will be cleared upon receiving buf done from hardware. In corner cases due to IRQ scheduling delay, sometimes the active list will get stuck with one request without clearing it. This is causing flush wait timeout at application level. This change adds stop HW and flush active adn wait list to prevent these timeouts. Change-Id: Ifdb318cd21859cde5d2c318e39d9a71aa0e227b3 Signed-off-by: Alok Pandey Signed-off-by: Junzhe Zou Signed-off-by: Harsh Shah --- .../msm/camera/cam_isp/cam_isp_context.c | 91 ++++++- .../cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 231 +++++++++++------- .../cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 2 + .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 20 +- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 5 +- 5 files changed, 250 insertions(+), 99 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c index d14718c27c40..57e92bead0de 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c @@ -1365,12 +1365,56 @@ static int __cam_isp_ctx_flush_req_in_top_state( struct cam_context *ctx, struct cam_req_mgr_flush_request *flush_req) { + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + struct cam_isp_stop_args stop_isp; + struct cam_hw_stop_args stop_args; + struct cam_isp_start_args start_isp; int rc = 0; CAM_DBG(CAM_ISP, "try to flush pending list"); spin_lock_bh(&ctx->lock); rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); spin_unlock_bh(&ctx->lock); + + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + /* if active and wait list are empty, return */ + spin_lock_bh(&ctx->lock); + if ((list_empty(&ctx->wait_req_list)) && + (list_empty(&ctx->active_req_list))) { + spin_unlock_bh(&ctx->lock); + CAM_DBG(CAM_ISP, "active and wait list are empty"); + goto end; + } + spin_unlock_bh(&ctx->lock); + + /* Stop hw first before active list flush */ + stop_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY; + stop_isp.stop_only = true; + stop_args.args = (void *)&stop_isp; + ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv, + &stop_args); + + spin_lock_bh(&ctx->lock); + CAM_DBG(CAM_ISP, "try to flush wait list"); + rc = __cam_isp_ctx_flush_req(ctx, &ctx->wait_req_list, + flush_req); + CAM_DBG(CAM_ISP, "try to flush active list"); + rc = __cam_isp_ctx_flush_req(ctx, &ctx->active_req_list, + flush_req); + spin_unlock_bh(&ctx->lock); + + /* Start hw */ + start_isp.hw_config.ctxt_to_hw_map = ctx_isp->hw_ctx; + start_isp.start_only = true; + start_isp.hw_config.priv = NULL; + + rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, + &start_isp); + } + +end: CAM_DBG(CAM_ISP, "Flush request in top state %d", ctx->state); return rc; @@ -1386,7 +1430,7 @@ static int __cam_isp_ctx_flush_req_in_ready( spin_lock_bh(&ctx->lock); rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); - /* if nothing is in pending req list, change state to acquire*/ + /* if nothing is in pending req list, change state to acquire */ if (list_empty(&ctx->pending_req_list)) ctx->state = CAM_CTX_ACQUIRED; spin_unlock_bh(&ctx->lock); @@ -2291,7 +2335,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd) { int rc = 0; - struct cam_hw_config_args arg; + struct cam_isp_start_args start_isp; struct cam_ctx_request *req; struct cam_isp_ctx_req *req_isp; struct cam_isp_context *ctx_isp = @@ -2320,12 +2364,13 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, goto end; } - arg.ctxt_to_hw_map = ctx_isp->hw_ctx; - arg.request_id = req->request_id; - arg.hw_update_entries = req_isp->cfg; - arg.num_hw_update_entries = req_isp->num_cfg; - arg.priv = &req_isp->hw_update_data; - arg.init_packet = 1; + start_isp.hw_config.ctxt_to_hw_map = ctx_isp->hw_ctx; + start_isp.hw_config.request_id = req->request_id; + start_isp.hw_config.hw_update_entries = req_isp->cfg; + start_isp.hw_config.num_hw_update_entries = req_isp->num_cfg; + start_isp.hw_config.priv = &req_isp->hw_update_data; + start_isp.hw_config.init_packet = 1; + start_isp.start_only = false; ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; @@ -2342,7 +2387,8 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, */ ctx->state = CAM_CTX_ACTIVATED; trace_cam_context_state("ISP", ctx); - rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, &arg); + rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, + &start_isp); if (rc) { /* HW failure. user need to clean up the resource */ CAM_ERR(CAM_ISP, "Start HW failed"); @@ -2383,6 +2429,7 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( struct cam_isp_ctx_req *req_isp; struct cam_isp_context *ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + struct cam_isp_stop_args stop_isp; /* Mask off all the incoming hardware events */ spin_lock_bh(&ctx->lock); @@ -2393,7 +2440,15 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( /* stop hw first */ if (ctx_isp->hw_ctx) { stop.ctxt_to_hw_map = ctx_isp->hw_ctx; - stop.args = stop_cmd; + + if (stop_cmd) + stop_isp.hw_stop_cmd = + CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY; + else + stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY; + + stop_isp.stop_only = false; + stop.args = (void *) &stop_isp; ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv, &stop); } @@ -2414,6 +2469,22 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( list_add_tail(&req->list, &ctx->free_req_list); } + while (!list_empty(&ctx->wait_req_list)) { + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + CAM_DBG(CAM_ISP, "signal fence in wait list. fence num %d", + req_isp->num_fence_map_out); + for (i = 0; i < req_isp->num_fence_map_out; i++) + if (req_isp->fence_map_out[i].sync_id != -1) { + cam_sync_signal( + req_isp->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + } + list_add_tail(&req->list, &ctx->free_req_list); + } + while (!list_empty(&ctx->active_req_list)) { req = list_first_entry(&ctx->active_req_list, struct cam_ctx_request, list); diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index a4b1d457e6f7..c4c16f07b337 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -284,6 +284,100 @@ static void cam_ife_hw_mgr_deinit_hw_res( } } +static int cam_ife_hw_mgr_init_hw( + struct cam_ife_hw_mgr_ctx *ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + int rc = 0, i; + + CAM_DBG(CAM_ISP, "INIT IFE CID ... in ctx id:%d", + ctx->ctx_index); + /* INIT IFE CID */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) { + rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT IFE CID(id :%d)", + hw_mgr_res->res_id); + return rc; + } + } + + CAM_DBG(CAM_ISP, "INIT IFE csid ... in ctx id:%d", + ctx->ctx_index); + + /* INIT IFE csid */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT IFE CSID(id :%d)", + hw_mgr_res->res_id); + return rc; + } + } + + /* INIT IFE SRC */ + CAM_DBG(CAM_ISP, "INIT IFE SRC in ctx id:%d", + ctx->ctx_index); + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT IFE SRC (%d)", + hw_mgr_res->res_id); + return rc; + } + } + + /* INIT IFE OUT */ + CAM_DBG(CAM_ISP, "INIT IFE OUT RESOURCES in ctx id:%d", + ctx->ctx_index); + + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) { + rc = cam_ife_hw_mgr_init_hw_res(&ctx->res_list_ife_out[i]); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT IFE OUT (%d)", + ctx->res_list_ife_out[i].res_id); + return rc; + } + } + + return rc; +} + +static void cam_ife_hw_mgr_deinit_hw( + struct cam_ife_hw_mgr_ctx *ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + int i = 0; + + if (!ctx->init_done) { + CAM_WARN(CAM_ISP, "ctx is not in init state"); + return; + } + + /* Deinit IFE CID */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) { + CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CID\n", __func__); + cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); + } + + /* Deinit IFE CSID */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CSID\n", __func__); + cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); + } + + /* Deint IFE MUX(SRC) */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); + } + + /* Deinit IFE OUT */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) + cam_ife_hw_mgr_deinit_hw_res(&ctx->res_list_ife_out[i]); + + ctx->init_done = false; +} + static int cam_ife_hw_mgr_put_res( struct list_head *src_list, struct cam_ife_hw_mgr_res **res) @@ -1917,6 +2011,7 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) { int rc = 0; struct cam_hw_stop_args *stop_args = stop_hw_args; + struct cam_isp_stop_args *stop_isp; struct cam_ife_hw_mgr_res *hw_mgr_res; struct cam_ife_hw_mgr_ctx *ctx; enum cam_ife_csid_halt_cmd csid_halt_type; @@ -1926,6 +2021,7 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) CAM_ERR(CAM_ISP, "Invalid arguments"); return -EINVAL; } + ctx = (struct cam_ife_hw_mgr_ctx *)stop_args->ctxt_to_hw_map; if (!ctx || !ctx->ctx_in_use) { CAM_ERR(CAM_ISP, "Invalid context is used"); @@ -1933,12 +2029,20 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) } CAM_DBG(CAM_ISP, " Enter...ctx id:%d", ctx->ctx_index); + stop_isp = (struct cam_isp_stop_args *)stop_args->args; + + if ((stop_isp->hw_stop_cmd == CAM_ISP_HW_STOP_IMMEDIATELY) && + (stop_isp->stop_only)) { + CAM_ERR(CAM_ISP, "Invalid params hw_stop_cmd:%d stop_only:%d", + stop_isp->hw_stop_cmd, stop_isp->stop_only); + return -EPERM; + } /* Set the csid halt command */ - if (!stop_args->args) - csid_halt_type = CAM_CSID_HALT_IMMEDIATELY; - else + if (stop_isp->hw_stop_cmd == CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY) csid_halt_type = CAM_CSID_HALT_AT_FRAME_BOUNDARY; + else + csid_halt_type = CAM_CSID_HALT_IMMEDIATELY; /* Note:stop resource will remove the irq mask from the hardware */ @@ -2014,30 +2118,15 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) ctx->base[i].idx, csid_halt_type); } - /* Deinit IFE CID */ - list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) { - CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CID\n", __func__); - cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); - } - - /* Deinit IFE CSID */ - list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { - CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CSID\n", __func__); - cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); - } - - /* Deint IFE MUX(SRC) */ - list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { - cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); - } - - /* Deinit IFE OUT */ - for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) - cam_ife_hw_mgr_deinit_hw_res(&ctx->res_list_ife_out[i]); + if (stop_isp->stop_only) + goto end; + cam_ife_hw_mgr_deinit_hw(ctx); CAM_DBG(CAM_ISP, "Stop success for ctx id:%d rc :%d", ctx->ctx_index, rc); +end: + mutex_lock(&g_ife_hw_mgr.ctx_mutex); if (!atomic_dec_return(&g_ife_hw_mgr.active_ctx_cnt)) { rc = cam_ife_notify_safe_lut_scm(CAM_IFE_SAFE_DISABLE); @@ -2149,19 +2238,20 @@ static int cam_ife_mgr_restart_hw(void *start_hw_args) static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) { int rc = -1; - struct cam_hw_config_args *start_args = start_hw_args; + struct cam_isp_start_args *start_isp = start_hw_args; struct cam_hw_stop_args stop_args; - struct cam_isp_stop_hw_method stop_hw_method; + struct cam_isp_stop_args stop_isp; struct cam_ife_hw_mgr_ctx *ctx; struct cam_ife_hw_mgr_res *hw_mgr_res; uint32_t i; - if (!hw_mgr_priv || !start_hw_args) { + if (!hw_mgr_priv || !start_isp) { CAM_ERR(CAM_ISP, "Invalid arguments"); return -EINVAL; } - ctx = (struct cam_ife_hw_mgr_ctx *)start_args->ctxt_to_hw_map; + ctx = (struct cam_ife_hw_mgr_ctx *) + start_isp->hw_config.ctxt_to_hw_map; if (!ctx || !ctx->ctx_in_use) { CAM_ERR(CAM_ISP, "Invalid context is used"); return -EPERM; @@ -2174,6 +2264,9 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) cam_tasklet_start(ctx->common.tasklet_info); + if (ctx->init_done && start_isp->start_only) + goto start_only; + /* set current csid debug information to CSID HW */ for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { if (g_ife_hw_mgr.csid_devices[i]) @@ -2184,58 +2277,13 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) sizeof(g_ife_hw_mgr.debug_cfg.csid_debug)); } - /* INIT IFE Root: do nothing */ - - CAM_DBG(CAM_ISP, "INIT IFE CID ... in ctx id:%d", - ctx->ctx_index); - /* INIT IFE CID */ - list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) { - rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); - if (rc) { - CAM_ERR(CAM_ISP, "Can not INIT IFE CID(id :%d)", - hw_mgr_res->res_id); - goto err; - } - } - - - CAM_DBG(CAM_ISP, "INIT IFE csid ... in ctx id:%d", - ctx->ctx_index); - - /* INIT IFE csid */ - list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { - rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); - if (rc) { - CAM_ERR(CAM_ISP, "Can not INIT IFE CSID(id :%d)", - hw_mgr_res->res_id); - goto err; - } - } - - /* INIT IFE SRC */ - CAM_DBG(CAM_ISP, "INIT IFE SRC in ctx id:%d", - ctx->ctx_index); - list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { - rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); - if (rc) { - CAM_ERR(CAM_ISP, "Can not INIT IFE SRC (%d)", - hw_mgr_res->res_id); - goto err; - } + rc = cam_ife_hw_mgr_init_hw(ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Init failed"); + goto err; } - /* INIT IFE OUT */ - CAM_DBG(CAM_ISP, "INIT IFE OUT RESOURCES in ctx id:%d", - ctx->ctx_index); - - for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) { - rc = cam_ife_hw_mgr_init_hw_res(&ctx->res_list_ife_out[i]); - if (rc) { - CAM_ERR(CAM_ISP, "Can not INIT IFE OUT (%d)", - ctx->res_list_ife_out[i].res_id); - goto err; - } - } +start_only: mutex_lock(&g_ife_hw_mgr.ctx_mutex); if (!atomic_fetch_inc(&g_ife_hw_mgr.active_ctx_cnt)) { @@ -2256,12 +2304,15 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) goto err; } - /* Apply initial configuration */ - CAM_DBG(CAM_ISP, "Config HW"); - rc = cam_ife_mgr_config_hw(hw_mgr_priv, start_hw_args); - if (rc) { - CAM_ERR(CAM_ISP, "Config HW failed"); - goto err; + if (!start_isp->start_only) { + /* Apply initial configuration */ + CAM_DBG(CAM_ISP, "Config HW"); + rc = cam_ife_mgr_config_hw(hw_mgr_priv, + &start_isp->hw_config); + if (rc) { + CAM_ERR(CAM_ISP, "Config HW failed"); + goto err; + } } CAM_DBG(CAM_ISP, "START IFE OUT ... in ctx id:%d", @@ -2313,13 +2364,18 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) } } + ctx->init_done = true; /* Start IFE root node: do nothing */ CAM_DBG(CAM_ISP, "Start success for ctx id:%d", ctx->ctx_index); + return 0; + err: - stop_hw_method.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY; - stop_args.ctxt_to_hw_map = start_args->ctxt_to_hw_map; - stop_args.args = (void *)(&stop_hw_method); + stop_isp.stop_only = false; + stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY; + stop_args.ctxt_to_hw_map = start_isp->hw_config.ctxt_to_hw_map; + stop_args.args = (void *)(&stop_isp); + cam_ife_mgr_stop_hw(hw_mgr_priv, &stop_args); CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc); return rc; @@ -2358,6 +2414,9 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv, CAM_DBG(CAM_ISP, "Enter...ctx id:%d", ctx->ctx_index); + if (ctx->init_done) + cam_ife_hw_mgr_deinit_hw(ctx); + /* we should called the stop hw before this already */ cam_ife_hw_mgr_release_hw_for_ctx(ctx); diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 0e678b4584cd..0198f3d62e9c 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -123,6 +123,7 @@ struct cam_ife_hw_mgr_debug { * context * @is_rdi_only_context flag to specify the context has only rdi resource * @config_done_complete indicator for configuration complete + * @init_done indicate whether init hw is done */ struct cam_ife_hw_mgr_ctx { struct list_head list; @@ -156,6 +157,7 @@ struct cam_ife_hw_mgr_ctx { atomic_t overflow_pending; uint32_t is_rdi_only_context; struct completion config_done_complete; + bool init_done; }; /** diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index 8f1911edf2c9..fd71c37c8fa1 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -60,13 +60,29 @@ enum cam_isp_hw_stop_cmd { }; /** - * struct cam_isp_stop_hw_method - hardware stop method + * struct cam_isp_stop_args - hardware stop arguments * * @hw_stop_cmd: Hardware stop command type information + * @stop_only Send stop only to hw drivers. No Deinit to be + * done. * */ -struct cam_isp_stop_hw_method { +struct cam_isp_stop_args { enum cam_isp_hw_stop_cmd hw_stop_cmd; + bool stop_only; +}; + +/** + * struct cam_isp_start_args - isp hardware start arguments + * + * @config_args: Hardware configuration commands. + * @start_only Send start only to hw drivers. No init to + * be done. + * + */ +struct cam_isp_start_args { + struct cam_hw_config_args hw_config; + bool start_only; }; /** diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 09e092bf726d..654f274f8079 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -1250,7 +1250,10 @@ static int cam_vfe_bus_stop_wm(struct cam_isp_resource_node *wm_res) struct cam_vfe_bus_ver2_common_data *common_data = rsrc_data->common_data; - /* disable WM */ + /* Disable WM */ + cam_io_w_mb(0x0, + common_data->mem_base + rsrc_data->hw_regs->cfg); + /* Disable all register access, reply on global reset */ CAM_DBG(CAM_ISP, "WM res %d irq_enabled %d", rsrc_data->index, rsrc_data->irq_enabled); -- GitLab From 60ba85937c98314403d5d0bbfc0d036df2f58b41 Mon Sep 17 00:00:00 2001 From: Kyle Yan Date: Wed, 27 Sep 2017 17:30:11 -0700 Subject: [PATCH 0728/1001] defconfig: Disable DEVPORT on sm8150 Disable DEVPORT on sm8150 as selinux policy requires this node to not be accessible to userspace. Change-Id: Ie68c7dbb20c1d56329df25f782dbde162dbd35aa Signed-off-by: Kyle Yan Signed-off-by: Isaac J. Manjarres --- arch/arm64/configs/vendor/sm8150-perf_defconfig | 1 + arch/arm64/configs/vendor/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/vendor/sm8150-perf_defconfig b/arch/arm64/configs/vendor/sm8150-perf_defconfig index 6c0a268effe0..6434a1572729 100644 --- a/arch/arm64/configs/vendor/sm8150-perf_defconfig +++ b/arch/arm64/configs/vendor/sm8150-perf_defconfig @@ -317,6 +317,7 @@ CONFIG_INPUT_UINPUT=y CONFIG_SERIAL_MSM_GENI=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y +# CONFIG_DEVPORT is not set CONFIG_DIAG_CHAR=y CONFIG_MSM_FASTCVPD=y CONFIG_MSM_ADSPRPC=y diff --git a/arch/arm64/configs/vendor/sm8150_defconfig b/arch/arm64/configs/vendor/sm8150_defconfig index 08e2ad9c884b..dc787b84480a 100644 --- a/arch/arm64/configs/vendor/sm8150_defconfig +++ b/arch/arm64/configs/vendor/sm8150_defconfig @@ -332,6 +332,7 @@ CONFIG_SERIAL_DEV_BUS=y CONFIG_TTY_PRINTK=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y +# CONFIG_DEVPORT is not set CONFIG_DIAG_CHAR=y CONFIG_MSM_FASTCVPD=y CONFIG_MSM_ADSPRPC=y -- GitLab From 81899be227df1cedca1103b4189dcce5d309539f Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Mon, 13 Aug 2018 14:31:54 -0700 Subject: [PATCH 0729/1001] power: qpnp-fg-gen4: Fix ESR timer initialization Currently, while parsing the ESR charging and discharging timers from the device tree, they're initialized to -EINVAL only if the parsing function returns an error. Since the default values for ESR timers are set to 0, fg_set_esr_timer() when called can set the timers to 0 when it is not supposed to. Fix it. CRs-Fixed: 2280822 Change-Id: I59bcc627fa836adfef210890e9019dc6c04bb614 Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qcom/qpnp-fg-gen4.c | 32 ++++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index fd260825570e..138aa4fc3e6b 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -3882,35 +3882,35 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) else chip->dt.delta_soc_thr = temp; + chip->dt.esr_timer_chg_fast[TIMER_RETRY] = -EINVAL; + chip->dt.esr_timer_chg_fast[TIMER_MAX] = -EINVAL; rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-chg-fast", chip->dt.esr_timer_chg_fast, NUM_ESR_TIMERS); - if (rc < 0) { - chip->dt.esr_timer_chg_fast[TIMER_RETRY] = -EINVAL; - chip->dt.esr_timer_chg_fast[TIMER_MAX] = -EINVAL; - } + if (rc < 0) + return rc; + chip->dt.esr_timer_dischg_fast[TIMER_RETRY] = -EINVAL; + chip->dt.esr_timer_dischg_fast[TIMER_MAX] = -EINVAL; rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-dischg-fast", chip->dt.esr_timer_dischg_fast, NUM_ESR_TIMERS); - if (rc < 0) { - chip->dt.esr_timer_dischg_fast[TIMER_RETRY] = -EINVAL; - chip->dt.esr_timer_dischg_fast[TIMER_MAX] = -EINVAL; - } + if (rc < 0) + return rc; + chip->dt.esr_timer_chg_slow[TIMER_RETRY] = -EINVAL; + chip->dt.esr_timer_chg_slow[TIMER_MAX] = -EINVAL; rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-chg-slow", chip->dt.esr_timer_chg_slow, NUM_ESR_TIMERS); - if (rc < 0) { - chip->dt.esr_timer_chg_slow[TIMER_RETRY] = -EINVAL; - chip->dt.esr_timer_chg_slow[TIMER_MAX] = -EINVAL; - } + if (rc < 0) + return rc; + chip->dt.esr_timer_dischg_slow[TIMER_RETRY] = -EINVAL; + chip->dt.esr_timer_dischg_slow[TIMER_MAX] = -EINVAL; rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-dischg-slow", chip->dt.esr_timer_dischg_slow, NUM_ESR_TIMERS); - if (rc < 0) { - chip->dt.esr_timer_dischg_slow[TIMER_RETRY] = -EINVAL; - chip->dt.esr_timer_dischg_slow[TIMER_MAX] = -EINVAL; - } + if (rc < 0) + return rc; chip->dt.force_load_profile = of_property_read_bool(node, "qcom,fg-force-load-profile"); -- GitLab From 2cf5b8f5b9448cddd7ffc9533679f58f979de54d Mon Sep 17 00:00:00 2001 From: Jilai Wang Date: Mon, 13 Aug 2018 17:54:33 -0400 Subject: [PATCH 0730/1001] ARM: dts: msm: update iommu info of npu node for sm8150 v2 Update iommu stream IDs and SMR masks for npu context banks for sm8150 v2. Change-Id: I8ce5f11d7690fb87d7a0efbc52090d9ee8fd9fc4 Signed-off-by: Jilai Wang --- arch/arm64/boot/dts/qcom/sm8150-v2.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi b/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi index 1c13601e4496..39415481a54c 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi @@ -406,6 +406,7 @@ /* NPU overrides */ &msm_npu { + iommus = <&apps_smmu 0x1081 0x400>; qcom,npu-pwrlevels { #address-cells = <1>; #size-cells = <0>; -- GitLab From 86e5c0bf4a1169c1ce927a448a18559cbbc5af6d Mon Sep 17 00:00:00 2001 From: Vijaykumar Badiger Date: Mon, 13 Aug 2018 14:54:23 -0700 Subject: [PATCH 0731/1001] defconfig: msm: Disable config EXT2_FS and EXT3_FS for sa8155 This change disables the unspported fs configs. Change-Id: I3816971be0718e52978bda6615f7f0abde0ad286 Signed-off-by: Vijaykumar Badiger --- arch/arm64/configs/vendor/sa8155-perf_defconfig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/arm64/configs/vendor/sa8155-perf_defconfig b/arch/arm64/configs/vendor/sa8155-perf_defconfig index 66e46fbf98e3..ce000b891c56 100644 --- a/arch/arm64/configs/vendor/sa8155-perf_defconfig +++ b/arch/arm64/configs/vendor/sa8155-perf_defconfig @@ -573,9 +573,7 @@ CONFIG_ESOC_MDM_4x=y CONFIG_ESOC_MDM_DRV=y CONFIG_ESOC_MDM_DBG_ENG=y CONFIG_MSM_TZ_LOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y CONFIG_EXT4_FS_ENCRYPTION=y -- GitLab From e6cb8268dc6e744b38bbb4bc6cc3842fc1fd36ee Mon Sep 17 00:00:00 2001 From: Vijaykumar Badiger Date: Mon, 13 Aug 2018 15:16:43 -0700 Subject: [PATCH 0732/1001] defconfig: msm: Update display configs for sa8155 Update perf configs for display. Change-Id: I2dabb2ca1d0e7b45951052f59039e8c2bae79dd5 Signed-off-by: Vijaykumar Badiger --- arch/arm64/configs/vendor/sa8155-perf_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/configs/vendor/sa8155-perf_defconfig b/arch/arm64/configs/vendor/sa8155-perf_defconfig index 66e46fbf98e3..7f951e081031 100644 --- a/arch/arm64/configs/vendor/sa8155-perf_defconfig +++ b/arch/arm64/configs/vendor/sa8155-perf_defconfig @@ -315,6 +315,7 @@ CONFIG_DIAG_CHAR=y CONFIG_MSM_FASTCVPD=y CONFIG_MSM_ADSPRPC=y CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX_PCA954x=y CONFIG_I2C_QCOM_GENI=y CONFIG_SPI=y CONFIG_SPI_QCOM_GENI=y @@ -326,6 +327,7 @@ CONFIG_PM8150B_PMIC_SIMULATOR=y CONFIG_PM8150L_PMIC_SIMULATOR=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PTP_1588_CLOCK=y +CONFIG_PINCTRL_SX150X=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_PINCTRL_SM8150=y CONFIG_GPIO_SYSFS=y @@ -379,6 +381,7 @@ CONFIG_DRM=y CONFIG_DRM_MSM_REGISTER_LOGGING=y CONFIG_DRM_SDE_EVTLOG_DEBUG=y CONFIG_DRM_SDE_RSC=y +CONFIG_DRM_ANALOGIX_ANX7625=y CONFIG_FB_ARMCLCD=y CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y CONFIG_LOGO=y -- GitLab From 1d00e9c9c642bad5bae1f081bffb58615af06c7f Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Mon, 30 Jul 2018 18:48:16 -0700 Subject: [PATCH 0733/1001] mhi: core: add multi-EE support for MHI channels Same MHI channel could support multiple execution environments, adding support for such channels. CRs-Fixed: 2289334 Change-Id: Ib6de0753238714fda40dfbd2d1220b809b88585d Signed-off-by: Sujeev Dias --- Documentation/devicetree/bindings/bus/mhi.txt | 16 ++- arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi | 120 +++++++++--------- drivers/bus/mhi/core/mhi_init.c | 4 +- drivers/bus/mhi/core/mhi_internal.h | 12 +- drivers/bus/mhi/core/mhi_main.c | 10 +- 5 files changed, 89 insertions(+), 73 deletions(-) diff --git a/Documentation/devicetree/bindings/bus/mhi.txt b/Documentation/devicetree/bindings/bus/mhi.txt index efb9510595e5..c6417eade80c 100644 --- a/Documentation/devicetree/bindings/bus/mhi.txt +++ b/Documentation/devicetree/bindings/bus/mhi.txt @@ -76,9 +76,15 @@ mhi channel node properties: - mhi,ee Usage: required Value type: - Definition: Channel execution enviornment as defined by enum MHI_EE - 1 = Bootloader stage - 2 = AMSS mode + Definition: Channel execution enviornment (EE) mask as defined by enum + mhi_ch_ee_mask + BIT(0) = Channel supported in PBL EE + BIT(1) = Channel supported in SBL EE + BIT(2) = Channel supported in AMSS EE + BIT(3) = Channel supported in BHIe EE + BIT(4) = Channel supported in RDDM EE + BIT(5) = Channel supported in PTHRU EE + BIT(6) = Channel supported in EDL EE - mhi,pollcfg Usage: optional @@ -223,7 +229,7 @@ mhi_controller { mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@1 { @@ -234,7 +240,7 @@ mhi_controller { mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_event@0 { diff --git a/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi b/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi index dd96699d55a3..e240b35a8dda 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi @@ -42,7 +42,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@1 { @@ -53,7 +53,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@2 { @@ -64,7 +64,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <1>; + mhi,ee = <0x2>; }; mhi_chan@3 { @@ -75,7 +75,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <1>; + mhi,ee = <0x2>; }; mhi_chan@4 { @@ -86,7 +86,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@5 { @@ -97,7 +97,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@8 { @@ -108,7 +108,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@9 { @@ -119,7 +119,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@10 { @@ -130,7 +130,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@11 { @@ -141,7 +141,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@14 { @@ -152,7 +152,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@15 { @@ -163,7 +163,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@16 { @@ -174,7 +174,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@17 { @@ -185,7 +185,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@18 { @@ -196,7 +196,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@19 { @@ -207,7 +207,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; mhi,auto-queue; }; @@ -219,7 +219,7 @@ mhi,chan-dir = <1>; mhi,data-type = <1>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; mhi,auto-start; }; @@ -231,7 +231,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; mhi,auto-queue; mhi,auto-start; }; @@ -244,7 +244,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@23 { @@ -255,7 +255,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@24 { @@ -266,7 +266,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <1>; + mhi,ee = <0x2>; }; mhi_chan@25 { @@ -277,7 +277,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <1>; + mhi,ee = <0x2>; }; mhi_chan@26 { @@ -288,7 +288,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@27 { @@ -299,7 +299,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@32 { @@ -310,7 +310,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@33 { @@ -321,7 +321,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@100 { @@ -332,7 +332,7 @@ mhi,chan-dir = <1>; mhi,data-type = <1>; mhi,doorbell-mode = <3>; - mhi,ee = <2>; + mhi,ee = <0x4>; mhi,db-mode-switch; }; @@ -344,7 +344,7 @@ mhi,chan-dir = <2>; mhi,data-type = <1>; mhi,doorbell-mode = <3>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@104 { @@ -353,7 +353,7 @@ mhi,event-ring = <4>; mhi,chan-dir = <1>; mhi,data-type = <3>; - mhi,ee = <2>; + mhi,ee = <0x4>; mhi,offload-chan; }; @@ -363,7 +363,7 @@ mhi,event-ring = <5>; mhi,chan-dir = <2>; mhi,data-type = <3>; - mhi,ee = <2>; + mhi,ee = <0x4>; mhi,offload-chan; mhi,lpm-notify; }; @@ -470,7 +470,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@1 { @@ -481,7 +481,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@2 { @@ -492,7 +492,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <1>; + mhi,ee = <0x2>; }; mhi_chan@3 { @@ -503,7 +503,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <1>; + mhi,ee = <0x2>; }; mhi_chan@4 { @@ -514,7 +514,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@5 { @@ -525,7 +525,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@8 { @@ -536,7 +536,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@9 { @@ -547,7 +547,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@10 { @@ -558,7 +558,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@11 { @@ -569,7 +569,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@14 { @@ -580,7 +580,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@15 { @@ -591,7 +591,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@16 { @@ -602,7 +602,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@17 { @@ -613,7 +613,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@18 { @@ -624,7 +624,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@19 { @@ -635,7 +635,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; mhi,auto-queue; }; @@ -647,7 +647,7 @@ mhi,chan-dir = <1>; mhi,data-type = <1>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; mhi,auto-start; }; @@ -659,7 +659,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; mhi,auto-queue; mhi,auto-start; }; @@ -672,7 +672,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@23 { @@ -683,7 +683,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@24 { @@ -694,7 +694,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <1>; + mhi,ee = <0x2>; }; mhi_chan@25 { @@ -705,7 +705,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <1>; + mhi,ee = <0x2>; }; mhi_chan@26 { @@ -716,7 +716,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@27 { @@ -727,7 +727,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@32 { @@ -738,7 +738,7 @@ mhi,chan-dir = <1>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@33 { @@ -749,7 +749,7 @@ mhi,chan-dir = <2>; mhi,data-type = <0>; mhi,doorbell-mode = <2>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@100 { @@ -760,7 +760,7 @@ mhi,chan-dir = <1>; mhi,data-type = <1>; mhi,doorbell-mode = <3>; - mhi,ee = <2>; + mhi,ee = <0x4>; mhi,db-mode-switch; }; @@ -772,7 +772,7 @@ mhi,chan-dir = <2>; mhi,data-type = <1>; mhi,doorbell-mode = <3>; - mhi,ee = <2>; + mhi,ee = <0x4>; }; mhi_chan@104 { @@ -781,7 +781,7 @@ mhi,event-ring = <4>; mhi,chan-dir = <1>; mhi,data-type = <3>; - mhi,ee = <2>; + mhi,ee = <0x4>; mhi,offload-chan; }; @@ -791,7 +791,7 @@ mhi,event-ring = <5>; mhi,chan-dir = <2>; mhi,data-type = <3>; - mhi,ee = <2>; + mhi,ee = <0x4>; mhi,offload-chan; mhi,lpm-notify; }; diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index 048c85b9b634..59592fb17cf8 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -900,8 +900,8 @@ static int of_parse_ch_cfg(struct mhi_controller *mhi_cntrl, if (ret) goto error_chan_cfg; - ret = of_property_read_u32(child, "mhi,ee", &mhi_chan->ee); - if (ret || mhi_chan->ee >= MHI_EE_MAX_SUPPORTED) + ret = of_property_read_u32(child, "mhi,ee", &mhi_chan->ee_mask); + if (ret) goto error_chan_cfg; of_property_read_u32(child, "mhi,pollcfg", diff --git a/drivers/bus/mhi/core/mhi_internal.h b/drivers/bus/mhi/core/mhi_internal.h index 988894b34e6b..c7ff92747e1a 100644 --- a/drivers/bus/mhi/core/mhi_internal.h +++ b/drivers/bus/mhi/core/mhi_internal.h @@ -476,6 +476,16 @@ enum mhi_er_data_type { MHI_ER_DATA_TYPE_MAX = MHI_ER_TSYNC_ELEMENT_TYPE, }; +enum mhi_ch_ee_mask { + MHI_CH_EE_PBL = BIT(MHI_EE_PBL), + MHI_CH_EE_SBL = BIT(MHI_EE_SBL), + MHI_CH_EE_AMSS = BIT(MHI_EE_AMSS), + MHI_CH_EE_BHIE = BIT(MHI_EE_BHIE), + MHI_CH_EE_RDDM = BIT(MHI_EE_RDDM), + MHI_CH_EE_PTHRU = BIT(MHI_EE_PTHRU), + MHI_CH_EE_EDL = BIT(MHI_EE_EDL), +}; + struct db_cfg { bool reset_req; bool db_mode; @@ -571,7 +581,7 @@ struct mhi_chan { u32 intmod; enum dma_data_direction dir; struct db_cfg db_cfg; - enum mhi_ee ee; + u32 ee_mask; enum MHI_XFER_TYPE xfer_type; enum MHI_CH_STATE ch_state; enum MHI_EV_CCS ccs; diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index 79749fc60a55..0eef26eaeac7 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -657,7 +657,8 @@ void mhi_create_devices(struct mhi_controller *mhi_cntrl) mhi_chan = mhi_cntrl->mhi_chan; for (i = 0; i < mhi_cntrl->max_chan; i++, mhi_chan++) { - if (!mhi_chan->configured || mhi_chan->ee != mhi_cntrl->ee) + if (!mhi_chan->configured || mhi_chan->mhi_dev || + !(mhi_chan->ee_mask & BIT(mhi_cntrl->ee))) continue; mhi_dev = mhi_alloc_device(mhi_cntrl); if (!mhi_dev) @@ -1320,10 +1321,9 @@ static int __mhi_prepare_channel(struct mhi_controller *mhi_cntrl, MHI_LOG("Entered: preparing channel:%d\n", mhi_chan->chan); - if (mhi_cntrl->ee != mhi_chan->ee) { - MHI_ERR("Current EE:%s Required EE:%s for chan:%s\n", - TO_MHI_EXEC_STR(mhi_cntrl->ee), - TO_MHI_EXEC_STR(mhi_chan->ee), + if (!(BIT(mhi_cntrl->ee) & mhi_chan->ee_mask)) { + MHI_ERR("Current EE:%s Required EE Mask:0x%x for chan:%s\n", + TO_MHI_EXEC_STR(mhi_cntrl->ee), mhi_chan->ee_mask, mhi_chan->name); return -ENOTCONN; } -- GitLab From fde38e47282388465cdc3455f00deea037c1043f Mon Sep 17 00:00:00 2001 From: Prashanth Vadde Date: Thu, 9 Aug 2018 23:21:15 +0530 Subject: [PATCH 0734/1001] defconfig: msm: Enable PCA9956B LED Driver on QCS405 Enable PCA9956B LED Driver on QCS405. Change-Id: I49eb7c69c25b71069de40c2d98869a5c6af650f3 Signed-off-by: Prashanth Vadde --- arch/arm64/configs/vendor/qcs405-perf_defconfig | 1 + arch/arm64/configs/vendor/qcs405_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/vendor/qcs405-perf_defconfig b/arch/arm64/configs/vendor/qcs405-perf_defconfig index b59bd3c4cdfa..5f8f1d9159bd 100644 --- a/arch/arm64/configs/vendor/qcs405-perf_defconfig +++ b/arch/arm64/configs/vendor/qcs405-perf_defconfig @@ -370,6 +370,7 @@ CONFIG_MMC_SDHCI_MSM=y CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y +CONFIG_LEDS_PCA9956B=y CONFIG_LEDS_TRIGGERS=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y diff --git a/arch/arm64/configs/vendor/qcs405_defconfig b/arch/arm64/configs/vendor/qcs405_defconfig index 176e2138eb0d..1065afba523c 100644 --- a/arch/arm64/configs/vendor/qcs405_defconfig +++ b/arch/arm64/configs/vendor/qcs405_defconfig @@ -384,6 +384,7 @@ CONFIG_MMC_SDHCI_MSM=y CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y +CONFIG_LEDS_PCA9956B=y CONFIG_LEDS_TRIGGERS=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y -- GitLab From 584987cdcaeb4c172e83cb24df6ba635433d8787 Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Mon, 16 Jul 2018 14:46:30 -0700 Subject: [PATCH 0735/1001] trace: convert to debugfs_file_get() and -put() Convert the depreciated calls, debugfs_use_file_start() and debugfs_use_file_finish() to debugfs_file_get() and debugfs_file_put() respectively. Change-Id: Ifdf214d4274a4062d7a077fdc94a9528d960eed6 Signed-off-by: Raghavendra Rao Ananta --- kernel/trace/ipc_logging_debug.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/kernel/trace/ipc_logging_debug.c b/kernel/trace/ipc_logging_debug.c index d7337249fa75..576afd71c45d 100644 --- a/kernel/trace/ipc_logging_debug.c +++ b/kernel/trace/ipc_logging_debug.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -78,18 +78,19 @@ static ssize_t debug_read_helper(struct file *file, char __user *buff, struct dentry *d = file->f_path.dentry; char *buffer; int bsize; - int srcu_idx; int r; - r = debugfs_use_file_start(d, &srcu_idx); - if (!r) { - ilctxt = file->private_data; - r = kref_get_unless_zero(&ilctxt->refcount) ? 0 : -EIO; - } - debugfs_use_file_finish(srcu_idx); + r = debugfs_file_get(d); if (r) return r; + ilctxt = file->private_data; + r = kref_get_unless_zero(&ilctxt->refcount) ? 0 : -EIO; + if (r) { + debugfs_file_put(d); + return r; + } + buffer = kmalloc(count, GFP_KERNEL); if (!buffer) { bsize = -ENOMEM; @@ -110,6 +111,7 @@ static ssize_t debug_read_helper(struct file *file, char __user *buff, done: ipc_log_context_put(ilctxt); + debugfs_file_put(d); return bsize; } -- GitLab From a3b031d13a4cc09f007deb1ded515ecbeb004d18 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 31 Oct 2017 00:15:52 +0100 Subject: [PATCH 0736/1001] debugfs: purge obsolete SRCU based removal protection Purge the SRCU based file removal race protection in favour of the new, refcount based debugfs_file_get()/debugfs_file_put() API. Change-Id: If1f40752474e55773aae756fdcc9c5c64891c009 Fixes: 49d200deaa68 ("debugfs: prevent access to removed files' private data") Signed-off-by: Nicolai Stange Signed-off-by: Greg Kroah-Hartman Git-commit: c9afbec27089cd6b4e621b639f41c7fc726c3bf1 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Raghavendra Rao Ananta --- fs/debugfs/file.c | 48 ----------------------------------------- fs/debugfs/inode.c | 7 ------ include/linux/debugfs.h | 19 ---------------- lib/Kconfig.debug | 1 - 4 files changed, 75 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index d3a972b45ff0..53f5c9a2af88 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include "internal.h" @@ -48,53 +47,6 @@ const struct file_operations debugfs_noop_file_operations = { .llseek = noop_llseek, }; -/** - * debugfs_use_file_start - mark the beginning of file data access - * @dentry: the dentry object whose data is being accessed. - * @srcu_idx: a pointer to some memory to store a SRCU index in. - * - * Up to a matching call to debugfs_use_file_finish(), any - * successive call into the file removing functions debugfs_remove() - * and debugfs_remove_recursive() will block. Since associated private - * file data may only get freed after a successful return of any of - * the removal functions, you may safely access it after a successful - * call to debugfs_use_file_start() without worrying about - * lifetime issues. - * - * If -%EIO is returned, the file has already been removed and thus, - * it is not safe to access any of its data. If, on the other hand, - * it is allowed to access the file data, zero is returned. - * - * Regardless of the return code, any call to - * debugfs_use_file_start() must be followed by a matching call - * to debugfs_use_file_finish(). - */ -int debugfs_use_file_start(const struct dentry *dentry, int *srcu_idx) - __acquires(&debugfs_srcu) -{ - *srcu_idx = srcu_read_lock(&debugfs_srcu); - barrier(); - if (d_unlinked(dentry)) - return -EIO; - return 0; -} -EXPORT_SYMBOL_GPL(debugfs_use_file_start); - -/** - * debugfs_use_file_finish - mark the end of file data access - * @srcu_idx: the SRCU index "created" by a former call to - * debugfs_use_file_start(). - * - * Allow any ongoing concurrent call into debugfs_remove() or - * debugfs_remove_recursive() blocked by a former call to - * debugfs_use_file_start() to proceed and return to its caller. - */ -void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu) -{ - srcu_read_unlock(&debugfs_srcu, srcu_idx); -} -EXPORT_SYMBOL_GPL(debugfs_use_file_finish); - #define F_DENTRY(filp) ((filp)->f_path.dentry) const struct file_operations *debugfs_real_fops(const struct file *filp) diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 6449eb935540..f587aded46b5 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -27,14 +27,11 @@ #include #include #include -#include #include "internal.h" #define DEBUGFS_DEFAULT_MODE 0700 -DEFINE_SRCU(debugfs_srcu); - static struct vfsmount *debugfs_mount; static int debugfs_mount_count; static bool debugfs_registered; @@ -693,8 +690,6 @@ void debugfs_remove(struct dentry *dentry) inode_unlock(d_inode(parent)); if (!ret) simple_release_fs(&debugfs_mount, &debugfs_mount_count); - - synchronize_srcu(&debugfs_srcu); } EXPORT_SYMBOL_GPL(debugfs_remove); @@ -768,8 +763,6 @@ void debugfs_remove_recursive(struct dentry *dentry) if (!__debugfs_remove(child, parent)) simple_release_fs(&debugfs_mount, &debugfs_mount_count); inode_unlock(d_inode(parent)); - - synchronize_srcu(&debugfs_srcu); } EXPORT_SYMBOL_GPL(debugfs_remove_recursive); diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index c5eda259b9d6..9f821a43bb0d 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -23,7 +23,6 @@ struct device; struct file_operations; -struct srcu_struct; struct debugfs_blob_wrapper { void *data; @@ -43,8 +42,6 @@ struct debugfs_regset32 { extern struct dentry *arch_debugfs_dir; -extern struct srcu_struct debugfs_srcu; - #define DEFINE_DEBUGFS_ATTRIBUTE(__fops, __get, __set, __fmt) \ static int __fops ## _open(struct inode *inode, struct file *file) \ { \ @@ -90,11 +87,6 @@ struct dentry *debugfs_create_automount(const char *name, void debugfs_remove(struct dentry *dentry); void debugfs_remove_recursive(struct dentry *dentry); -int debugfs_use_file_start(const struct dentry *dentry, int *srcu_idx) - __acquires(&debugfs_srcu); - -void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu); - const struct file_operations *debugfs_real_fops(const struct file *filp); int debugfs_file_get(struct dentry *dentry); @@ -227,17 +219,6 @@ static inline void debugfs_remove(struct dentry *dentry) static inline void debugfs_remove_recursive(struct dentry *dentry) { } -static inline int debugfs_use_file_start(const struct dentry *dentry, - int *srcu_idx) - __acquires(&debugfs_srcu) -{ - return 0; -} - -static inline void debugfs_use_file_finish(int srcu_idx) - __releases(&debugfs_srcu) -{ } - static inline int debugfs_file_get(struct dentry *dentry) { return 0; diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 74506964a517..40f399a8eda3 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -291,7 +291,6 @@ config PAGE_OWNER_ENABLE_DEFAULT config DEBUG_FS bool "Debug Filesystem" - select SRCU help debugfs is a virtual file system that kernel developers use to put debugging files into. Enable this option to be able to read and -- GitLab From a9b3a6147243448c9e5193d5ca5d3125a74bac46 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 31 Oct 2017 00:15:53 +0100 Subject: [PATCH 0737/1001] debugfs: call debugfs_real_fops() only after debugfs_file_get() The current implementation of debugfs_real_fops() relies on a debugfs_fsdata instance to be installed at ->d_fsdata. With future patches introducing lazy allocation of these, this requirement will be guaranteed to be fullfilled only inbetween a debugfs_file_get()/debugfs_file_put() pair. The full proxies' fops implemented by debugfs happen to be the only offenders. Fix them up by moving their debugfs_real_fops() calls past those to debugfs_file_get(). full_proxy_release() is special as it doesn't invoke debugfs_file_get() at all. Leave it alone for now. Change-Id: I418a5aea3e5b086a719a780e1b77e966b6034d43 Signed-off-by: Nicolai Stange Signed-off-by: Greg Kroah-Hartman Git-commit: 154b9d7512ae012aca7b4e90af67a72419ad1941 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Raghavendra Rao Ananta --- fs/debugfs/file.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 53f5c9a2af88..bc3549c95574 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -144,13 +144,13 @@ const struct file_operations debugfs_open_proxy_file_operations = { static ret_type full_proxy_ ## name(proto) \ { \ struct dentry *dentry = F_DENTRY(filp); \ - const struct file_operations *real_fops = \ - debugfs_real_fops(filp); \ + const struct file_operations *real_fops; \ ret_type r; \ \ r = debugfs_file_get(dentry); \ if (unlikely(r)) \ return r; \ + real_fops = debugfs_real_fops(filp); \ r = real_fops->name(args); \ debugfs_file_put(dentry); \ return r; \ @@ -177,13 +177,14 @@ FULL_PROXY_FUNC(unlocked_ioctl, long, filp, static unsigned int full_proxy_poll(struct file *filp, struct poll_table_struct *wait) { - const struct file_operations *real_fops = debugfs_real_fops(filp); struct dentry *dentry = F_DENTRY(filp); unsigned int r = 0; + const struct file_operations *real_fops; if (debugfs_file_get(dentry)) return POLLHUP; + real_fops = debugfs_real_fops(filp); r = real_fops->poll(filp, wait); debugfs_file_put(dentry); return r; -- GitLab From 56fa9fd7d0c59a884af639d1d5eced2421c1a6cc Mon Sep 17 00:00:00 2001 From: Tingwei Zhang Date: Tue, 24 Jul 2018 16:24:18 +0800 Subject: [PATCH 0738/1001] coresight: tmc: Add USB BAM SMMU support Add SMMU support to TMC ETR USB BAM. Enable SMMU flag in SPS connection and send IOVA to SPS driver to program BAM. Disable scatter-list mode when SMMU is enabled since SMMU has better support on allocate large memory for ETR. Change-Id: I04f481db3c92008213f4112e69380c07b794b299 Signed-off-by: Tingwei Zhang --- .../hwtracing/coresight/coresight-tmc-etr.c | 74 +++++++++++++++++-- drivers/hwtracing/coresight/coresight-tmc.c | 13 +++- 2 files changed, 79 insertions(+), 8 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 0df879000532..af9e51754d19 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -587,9 +587,10 @@ static void tmc_etr_free_mem(struct tmc_drvdata *drvdata) } } -static void tmc_etr_fill_usb_bam_data(struct tmc_drvdata *drvdata) +static int tmc_etr_fill_usb_bam_data(struct tmc_drvdata *drvdata) { struct tmc_etr_bam_data *bamdata = drvdata->bamdata; + dma_addr_t data_fifo_iova, desc_fifo_iova; get_qdss_bam_connection_info(&bamdata->dest, &bamdata->dest_pipe_idx, @@ -597,6 +598,28 @@ static void tmc_etr_fill_usb_bam_data(struct tmc_drvdata *drvdata) &bamdata->desc_fifo, &bamdata->data_fifo, NULL); + + if (bamdata->props.options & SPS_BAM_SMMU_EN) { + data_fifo_iova = dma_map_resource(drvdata->dev, + bamdata->data_fifo.phys_base, bamdata->data_fifo.size, + DMA_BIDIRECTIONAL, 0); + if (!data_fifo_iova) + return -ENOMEM; + dev_dbg(drvdata->dev, "%s:data p_addr:%pa,iova:%pad,size:%x\n", + __func__, &(bamdata->data_fifo.phys_base), + &data_fifo_iova, bamdata->data_fifo.size); + bamdata->data_fifo.iova = data_fifo_iova; + desc_fifo_iova = dma_map_resource(drvdata->dev, + bamdata->desc_fifo.phys_base, bamdata->desc_fifo.size, + DMA_BIDIRECTIONAL, 0); + if (!desc_fifo_iova) + return -ENOMEM; + dev_dbg(drvdata->dev, "%s:desc p_addr:%pa,iova:%pad,size:%x\n", + __func__, &(bamdata->desc_fifo.phys_base), + &desc_fifo_iova, bamdata->desc_fifo.size); + bamdata->desc_fifo.iova = desc_fifo_iova; + } + return 0; } static void __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata) @@ -625,10 +648,17 @@ static void __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata) axictl = (axictl & ~0x3) | 0x2; writel_relaxed(axictl, drvdata->base + TMC_AXICTL); - writel_relaxed((uint32_t)bamdata->data_fifo.phys_base, + if (bamdata->props.options & SPS_BAM_SMMU_EN) { + writel_relaxed((uint32_t)bamdata->data_fifo.iova, drvdata->base + TMC_DBALO); - writel_relaxed((((uint64_t)bamdata->data_fifo.phys_base) >> 32) & 0xFF, - drvdata->base + TMC_DBAHI); + writel_relaxed((((uint64_t)bamdata->data_fifo.iova) >> 32) + & 0xFF, drvdata->base + TMC_DBAHI); + } else { + writel_relaxed((uint32_t)bamdata->data_fifo.phys_base, + drvdata->base + TMC_DBALO); + writel_relaxed((((uint64_t)bamdata->data_fifo.phys_base) >> 32) + & 0xFF, drvdata->base + TMC_DBAHI); + } /* Set FOnFlIn for periodic flush */ writel_relaxed(0x133, drvdata->base + TMC_FFCR); writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG); @@ -639,9 +669,29 @@ static void __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata) drvdata->enable_to_bam = true; } +static int get_usb_bam_iova(struct device *dev, unsigned long usb_bam_handle, + unsigned long *iova) +{ + int ret = 0; + phys_addr_t p_addr; + u32 bam_size; + + ret = sps_get_bam_addr(usb_bam_handle, &p_addr, &bam_size); + if (ret) { + dev_err(dev, "sps_get_bam_addr failed at handle:%lx, err:%d\n", + usb_bam_handle, ret); + return ret; + } + *iova = dma_map_resource(dev, p_addr, bam_size, DMA_BIDIRECTIONAL, 0); + if (!(*iova)) + return -ENOMEM; + return 0; +} + static int tmc_etr_bam_enable(struct tmc_drvdata *drvdata) { struct tmc_etr_bam_data *bamdata = drvdata->bamdata; + unsigned long iova; int ret; if (bamdata->enable) @@ -673,6 +723,12 @@ static int tmc_etr_bam_enable(struct tmc_drvdata *drvdata) bamdata->connect.desc = bamdata->desc_fifo; bamdata->connect.data = bamdata->data_fifo; + if (bamdata->props.options & SPS_BAM_SMMU_EN) { + ret = get_usb_bam_iova(drvdata->dev, bamdata->dest, &iova); + if (ret) + goto err1; + bamdata->connect.dest_iova = iova; + } ret = sps_connect(bamdata->pipe, &bamdata->connect); if (ret) goto err1; @@ -739,7 +795,9 @@ void usb_notifier(void *priv, unsigned int event, struct qdss_request *d_req, mutex_lock(&drvdata->mem_lock); if (event == USB_QDSS_CONNECT) { - tmc_etr_fill_usb_bam_data(drvdata); + ret = tmc_etr_fill_usb_bam_data(drvdata); + if (ret) + dev_err(drvdata->dev, "ETR get usb bam data failed\n"); ret = tmc_etr_bam_enable(drvdata); if (ret) dev_err(drvdata->dev, "ETR BAM enable failed\n"); @@ -784,6 +842,12 @@ int tmc_etr_bam_init(struct amba_device *adev, bamdata->props.summing_threshold = 0x10; /* BAM event threshold */ bamdata->props.irq = 0; bamdata->props.num_pipes = TMC_ETR_BAM_NR_PIPES; + if (device_property_present(dev, "iommus") + && !device_property_present(dev, "qcom,smmu-s1-bypass")) { + pr_info("%s: setting SPS_BAM_SMMU_EN flag with (%s)\n", + __func__, dev_name(dev)); + bamdata->props.options |= SPS_BAM_SMMU_EN; + } return sps_register_bam_device(&bamdata->props, &bamdata->handle); } diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index e9fe00d0438c..8ed08a9c129f 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -544,10 +544,17 @@ static ssize_t mem_type_store(struct device *dev, } if (!strcmp(str, str_tmc_etr_mem_type[TMC_ETR_MEM_TYPE_CONTIG])) drvdata->mem_type = TMC_ETR_MEM_TYPE_CONTIG; - else if (!strcmp(str, str_tmc_etr_mem_type[TMC_ETR_MEM_TYPE_SG])) + else if (!strcmp(str, str_tmc_etr_mem_type[TMC_ETR_MEM_TYPE_SG])) { + if (device_property_present(dev->parent, "iommus") && + !device_property_present(dev->parent, "qcom,smmu-s1-bypass")) { + mutex_unlock(&drvdata->mem_lock); + pr_err("SMMU is enabled. Sg mode is not supported\n"); + return -EINVAL; + } drvdata->mem_type = TMC_ETR_MEM_TYPE_SG; - else + } else { size = -EINVAL; + } mutex_unlock(&drvdata->mem_lock); @@ -606,7 +613,7 @@ static int tmc_iommu_init(struct tmc_drvdata *drvdata) return 0; drvdata->iommu_mapping = arm_iommu_create_mapping(&amba_bustype, - 0, (SZ_1G * 4ULL)); + 0, (SZ_1G * 2ULL)); if (IS_ERR(drvdata->iommu_mapping)) { dev_err(drvdata->dev, "Create mapping failed, err = %d\n", ret); ret = PTR_ERR(drvdata->iommu_mapping); -- GitLab From 67f3a8892dd888484d8aee5b32ab6100cfbe6944 Mon Sep 17 00:00:00 2001 From: Tingwei Zhang Date: Mon, 30 Jul 2018 23:41:04 -0700 Subject: [PATCH 0739/1001] ARM: dts: msm: Add SMMU support on QDSS for SM8150 v2 Remove s1-bypass flag and enable SMMU function on QDSS. Add SID for QDSS BAM. Change-Id: I8a307adcd930a4a38a16883f1ec9d37a2905af86 Signed-off-by: Tingwei Zhang --- arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi | 7 ++++++- arch/arm64/boot/dts/qcom/sm8150-v2.dtsi | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi b/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi index e20e54f343da..3a6441e486d3 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi @@ -321,7 +321,12 @@ reg-names = "tmc-base", "bam-base"; qcom,smmu-s1-bypass; - iommus = <&apps_smmu 0x05e0 0>; + iommus = <&apps_smmu 0x05e0 0>, + <&apps_smmu 0x04a0 0>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + arm,buffer-size = <0x400000>; coresight-name = "coresight-tmc-etr"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi b/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi index 1c13601e4496..04fa04c76745 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi @@ -40,6 +40,10 @@ }; }; +&tmc_etr { + /delete-property/ qcom,smmu-s1-bypass; +}; + &spss_utils { qcom,spss-dev-firmware-name = "spss2d"; /* 8 chars max */ qcom,spss-test-firmware-name = "spss2t"; /* 8 chars max */ -- GitLab From 6d23a99c6eb7132789c7315091ecc4ba1a50ebc4 Mon Sep 17 00:00:00 2001 From: Hardik Kantilal Patel Date: Fri, 10 Aug 2018 15:53:46 +0530 Subject: [PATCH 0740/1001] icnss: Remove WARN_ON during self recovery trigger Remove WARN_ON during self recovery trigger to avoid false positive while doing stress testing of self recovery feature. CRs-Fixed: 2296234 Change-Id: Ibe858f74ccb78565c98ba249a244f6bceb0ca1e5 Signed-off-by: Hardik Kantilal Patel --- drivers/soc/qcom/icnss.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 9a68853ffd6c..4749ffe6c9ce 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -2004,7 +2004,6 @@ int icnss_trigger_recovery(struct device *dev) goto out; } - WARN_ON(1); icnss_pr_warn("Initiate PD restart at WLAN FW, state: 0x%lx\n", priv->state); -- GitLab From acdc902f9f3c4ea66af43de56b00fd20b6e0910f Mon Sep 17 00:00:00 2001 From: Sayali Lokhande Date: Tue, 14 Aug 2018 11:24:17 +0530 Subject: [PATCH 0741/1001] ARM : dts: msm: Update UFS Unipro clock frequency for sm6150 Update UFS Unipro clock frequency and UFS Phy axi clock frequency as per sm6150 clock frequency plan. Change-Id: I52fc2de2f26d8f36472de218361afa749f3e89d4 Signed-off-by: Sayali Lokhande --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index ce1117cba29a..8a3d96df65c8 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -1634,10 +1634,10 @@ <&clock_gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, <&clock_gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>; freq-table-hz = - <37500000 300000000>, + <50000000 240000000>, <0 0>, <0 0>, - <37500000 300000000>, + <37500000 150000000>, <75000000 300000000>, <0 0>, <0 0>, -- GitLab From d9ae5404496978d97df890131e24f7b664fc554c Mon Sep 17 00:00:00 2001 From: Sayali Lokhande Date: Sun, 12 Aug 2018 19:13:53 +0530 Subject: [PATCH 0742/1001] drivers: phy: ufs: Use correct UFS PHY version suffix for sm6150 For sm6150 target, UFS PHY version suffix is updated to 0x2. This change updates the check condition to callibrate UFS Phy based on correct version suffix. Change-Id: Icdadd4a43cd2adaba2a36005d5539c28a1241a31 Signed-off-by: Sayali Lokhande --- drivers/phy/qualcomm/phy-qcom-ufs-qmp-v3-660.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v3-660.c b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v3-660.c index 7203405b19b7..12507a0af0f0 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v3-660.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v3-660.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -30,7 +30,7 @@ int ufs_qcom_phy_qmp_v3_660_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B); tbl_B = phy_cal_table_rate_B; - if ((major == 0x3) && (minor == 0x001) && (step == 0x001)) { + if ((major == 0x3) && (minor == 0x001) && (step >= 0x001)) { tbl_A = phy_cal_table_rate_A_3_1_1; tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_3_1_1); } else { -- GitLab From 421f436fc8089312a759ec8dd0d2dd69f4d9e03d Mon Sep 17 00:00:00 2001 From: Dinesh K Garg Date: Fri, 20 Jul 2018 11:15:52 -0700 Subject: [PATCH 0743/1001] crypto: ice: Add support for new FDE design ICE driver provides storage driver info whether IO request requires crypto operation. ICE driver tags all requests with BIO_INLINECRYPT flag as needing crypto operation. Per new design all requests of userdata partition would be tagged as needing crypto operation if userspace has informed ICE driver about enabling FDE. Change-Id: I97b18ae76601592900e6f9118ac7b1851e74b6ed Signed-off-by: Dinesh K Garg --- drivers/crypto/msm/ice.c | 54 +++++++++++++++++++++++++++++++++++++--- include/crypto/ice.h | 4 ++- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index e342d2af1109..7bfc73aff5cc 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -57,6 +57,14 @@ #define QCOM_ICE_UFS 10 #define QCOM_ICE_SDCC 20 +#define QCOM_ICE_ENCRYPT 0x1 +#define QCOM_ICE_DECRYPT 0x2 +#define QCOM_SECT_LEN_IN_BYTE 512 +#define QCOM_UD_FOOTER_SIZE 0x4000 +#define QCOM_UD_FOOTER_SECS (QCOM_UD_FOOTER_SIZE / QCOM_SECT_LEN_IN_BYTE) + +static int ice_fde_flag; + struct ice_clk_info { struct list_head list; struct clk *clk; @@ -130,13 +138,14 @@ static int qti_ice_setting_config(struct request *req, return -EINVAL; if ((short)(crypto_data->key_index) >= 0) { - memcpy(&setting->crypto_data, crypto_data, sizeof(setting->crypto_data)); - if (rq_data_dir(req) == WRITE) + if (rq_data_dir(req) == WRITE && + (ice_fde_flag & QCOM_ICE_ENCRYPT)) setting->encr_bypass = false; - else if (rq_data_dir(req) == READ) + else if (rq_data_dir(req) == READ && + (ice_fde_flag & QCOM_ICE_DECRYPT)) setting->decr_bypass = false; else { /* Should I say BUG_ON */ @@ -147,6 +156,12 @@ static int qti_ice_setting_config(struct request *req, return 0; } +void qcom_ice_set_fde_flag(int flag) +{ + ice_fde_flag = flag; + pr_debug("%s read_write setting %d\n", __func__, ice_fde_flag); +} +EXPORT_SYMBOL(qcom_ice_set_fde_flag); static int qcom_ice_enable_clocks(struct ice_device *, bool); @@ -1431,8 +1446,11 @@ static int qcom_ice_config_start(struct platform_device *pdev, struct ice_data_setting *setting, bool async) { struct ice_crypto_setting pfk_crypto_data = {0}; + struct ice_crypto_setting ice_data = {0}; int ret = 0; bool is_pfe = false; + unsigned long sec_end = 0; + sector_t data_size; if (!pdev || !req) { pr_err("%s: Invalid params passed\n", __func__); @@ -1467,6 +1485,36 @@ static int qcom_ice_config_start(struct platform_device *pdev, &pfk_crypto_data, setting); } + if (ice_fde_flag && req->part && req->part->info + && req->part->info->volname[0]) { + if (!strcmp(req->part->info->volname, "userdata")) { + sec_end = req->part->start_sect + req->part->nr_sects - + QCOM_UD_FOOTER_SECS; + if ((req->__sector >= req->part->start_sect) && + (req->__sector < sec_end)) { + /* + * Ugly hack to address non-block-size aligned + * userdata end address in eMMC based devices. + * for eMMC based devices, since sector and + * block sizes are not same i.e. 4K, it is + * possible that partition is not a multiple of + * block size. For UFS based devices sector + * size and block size are same. Hence ensure + * that data is within userdata partition using + * sector based calculation + */ + data_size = req->__data_len / + QCOM_SECT_LEN_IN_BYTE; + + if ((req->__sector + data_size) > sec_end) + return 0; + else + return qti_ice_setting_config(req, pdev, + &ice_data, setting); + } + } + } + /* * It is not an error. If target is not req-crypt based, all request * from storage driver would come here to check if there is any ICE diff --git a/include/crypto/ice.h b/include/crypto/ice.h index 558d1366a789..5407e5106243 100644 --- a/include/crypto/ice.h +++ b/include/crypto/ice.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -56,11 +56,13 @@ struct platform_device *qcom_ice_get_pdevice(struct device_node *node); #ifdef CONFIG_CRYPTO_DEV_QCOM_ICE int qcom_ice_setup_ice_hw(const char *storage_type, int enable); +void qcom_ice_set_fde_flag(int flag); #else static inline int qcom_ice_setup_ice_hw(const char *storage_type, int enable) { return 0; } +static inline void qcom_ice_set_fde_flag(int flag) {} #endif struct qcom_ice_variant_ops { -- GitLab From deca1043dcced663b61d49c8ca01a1eb33ab29d5 Mon Sep 17 00:00:00 2001 From: Dinesh K Garg Date: Fri, 20 Jul 2018 11:27:14 -0700 Subject: [PATCH 0744/1001] qseecom: expose a new IOCTL for new FDE design Adding a new IOCTL QSEECOM_IOCTL_SET_ICE_INFO so that userspace can provide information to kernel whenever FDE is enabled. Change-Id: I03b5571effc07fe5b6b261fae98a0bd2d2958744 Signed-off-by: Dinesh K Garg --- drivers/misc/qseecom.c | 11 +++++++++++ include/uapi/linux/qseecom.h | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index c7001596f025..ed878c1ed667 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -7648,6 +7648,17 @@ static inline long qseecom_ioctl(struct file *file, atomic_dec(&data->ioctl_count); break; } + case QSEECOM_IOCTL_SET_ICE_INFO: { + struct qseecom_ice_data_t ice_data; + + ret = copy_from_user(&ice_data, argp, sizeof(ice_data)); + if (ret) { + pr_err("copy_from_user failed\n"); + return -EFAULT; + } + qcom_ice_set_fde_flag(ice_data.flag); + break; + } default: pr_err("Invalid IOCTL: 0x%x\n", cmd); return -EINVAL; diff --git a/include/uapi/linux/qseecom.h b/include/uapi/linux/qseecom.h index 55c71ddc7d20..961316839280 100644 --- a/include/uapi/linux/qseecom.h +++ b/include/uapi/linux/qseecom.h @@ -268,6 +268,10 @@ struct qseecom_ce_pipe_entry { unsigned int ce_pipe_pair; }; +struct qseecom_ice_data_t { + int flag; +}; + #define MAX_CE_INFO_HANDLE_SIZE 32 struct qseecom_ce_info_req { unsigned char handle[MAX_CE_INFO_HANDLE_SIZE]; @@ -385,5 +389,7 @@ struct file; #define QSEECOM_IOCTL_QUERY_CE_PIPE_INFO \ _IOWR(QSEECOM_IOC_MAGIC, 42, struct qseecom_ce_info_req) +#define QSEECOM_IOCTL_SET_ICE_INFO \ + _IOWR(QSEECOM_IOC_MAGIC, 43, struct qseecom_ice_data_t) #endif /* _UAPI_QSEECOM_H_ */ -- GitLab From ed720829ca37af38ee4a901026a837cddb54cbd8 Mon Sep 17 00:00:00 2001 From: Ghanim Fodi Date: Mon, 13 Aug 2018 14:28:38 +0300 Subject: [PATCH 0745/1001] msm: gsi: Support GSI register version 2 GSI core Registers S/W interface has many non backward compatible changes on sdxprairie. E.g. registers offsets inside the GSI block. This change adds support for version 2 of the SWI. CRs-Fixed: 2295428 Change-Id: I3075683d2effe0d3a0d50d7ffd9d8798763b2387 Signed-off-by: Ghanim Fodi --- drivers/platform/msm/Kconfig | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig index 219112d04f12..34ffbe2f626c 100644 --- a/drivers/platform/msm/Kconfig +++ b/drivers/platform/msm/Kconfig @@ -74,6 +74,15 @@ config GSI and CPUs over various types of interfaces such as MHI, xDCI, xHCI, GPI, WDI, Ethernet, etc. +config GSI_REGISTER_VERSION_2 + bool "GSI core Version 2 Registers SWI Support" + depends on GSI + help + GSI core registers Software interface version 2 has updated + registers interface to communicate with GSI. This includes + new registers offsets, new registers fields structure and + new registers. + config IPA3 tristate "IPA3 support" select GSI -- GitLab From 1066dc5c36a0e298e43a0bda3630eca07c7b088d Mon Sep 17 00:00:00 2001 From: Ghanim Fodi Date: Mon, 13 Aug 2018 17:47:07 +0300 Subject: [PATCH 0746/1001] msm: ipa: Enable GSI Register interface version 2 sdxprairie should use GSI register s/w interface version 2. This change enables it. CRs-Fixed: 2295428 Change-Id: I1a2b23f08b7ffeb904bafee8efea68f142283c50 Signed-off-by: Ghanim Fodi --- arch/arm/configs/vendor/sdxprairie-perf_defconfig | 1 + arch/arm/configs/vendor/sdxprairie_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/vendor/sdxprairie-perf_defconfig b/arch/arm/configs/vendor/sdxprairie-perf_defconfig index 69881b3407e4..b4ef2bd487e4 100644 --- a/arch/arm/configs/vendor/sdxprairie-perf_defconfig +++ b/arch/arm/configs/vendor/sdxprairie-perf_defconfig @@ -258,6 +258,7 @@ CONFIG_STAGING=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_USB_BAM=y +CONFIG_GSI_REGISTER_VERSION_2=y CONFIG_IPA3=y CONFIG_IPA_WDI_UNIFIED_API=y CONFIG_RMNET_IPA3=y diff --git a/arch/arm/configs/vendor/sdxprairie_defconfig b/arch/arm/configs/vendor/sdxprairie_defconfig index 0b8de0c0489b..1b8fdfc6f1ad 100644 --- a/arch/arm/configs/vendor/sdxprairie_defconfig +++ b/arch/arm/configs/vendor/sdxprairie_defconfig @@ -248,6 +248,7 @@ CONFIG_UIO=y CONFIG_STAGING=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_GSI_REGISTER_VERSION_2=y CONFIG_IPA3=y CONFIG_IPA_WDI_UNIFIED_API=y CONFIG_RMNET_IPA3=y -- GitLab From 68e779005f58c92cf12a5e088653c05da36dcfcc Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Fri, 10 Aug 2018 22:37:04 +0530 Subject: [PATCH 0747/1001] power: qpnp-smb5: Add FORCE_RECHARGE power-supply property Disable/re-enable charging to force a recharge. Change-Id: I417d46cc07f455792906a18f4b6dc8e5ca8ca3da Signed-off-by: Anirudh Ghayal --- drivers/power/supply/qcom/qpnp-smb5.c | 13 +++++++++++++ drivers/power/supply/qcom/smb5-lib.h | 1 + 2 files changed, 14 insertions(+) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 0b5cfbd6ede9..66169ba65778 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -1173,6 +1173,7 @@ static enum power_supply_property smb5_batt_props[] = { POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_RECHARGE_SOC, POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_FORCE_RECHARGE, }; static int smb5_batt_get_prop(struct power_supply *psy, @@ -1288,6 +1289,9 @@ static int smb5_batt_get_prop(struct power_supply *psy, rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_CHARGE_FULL, val); break; + case POWER_SUPPLY_PROP_FORCE_RECHARGE: + val->intval = 0; + break; default: pr_err("batt power supply prop %d not supported\n", psp); return -EINVAL; @@ -1367,6 +1371,15 @@ static int smb5_batt_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_RECHARGE_SOC: rc = smblib_set_prop_rechg_soc_thresh(chg, val); break; + case POWER_SUPPLY_PROP_FORCE_RECHARGE: + /* toggle charging to force recharge */ + vote(chg->chg_disable_votable, FORCE_RECHARGE_VOTER, + true, 0); + /* charge disable delay */ + msleep(50); + vote(chg->chg_disable_votable, FORCE_RECHARGE_VOTER, + false, 0); + break; default: rc = -EINVAL; } diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index f29667ad3e61..0018145dda7f 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -59,6 +59,7 @@ enum print_reason { #define WBC_VOTER "WBC_VOTER" #define HW_LIMIT_VOTER "HW_LIMIT_VOTER" #define PL_SMB_EN_VOTER "PL_SMB_EN_VOTER" +#define FORCE_RECHARGE_VOTER "FORCE_RECHARGE_VOTER" #define BOOST_BACK_STORM_COUNT 3 #define WEAK_CHG_STORM_COUNT 8 -- GitLab From ecf6f1272c10b17b535e7fdb4151dad1daf2f743 Mon Sep 17 00:00:00 2001 From: Ghanim Fodi Date: Sun, 27 May 2018 01:17:12 +0300 Subject: [PATCH 0748/1001] msm: gsi: Update GSI 2.5 registers offset This change updates the gsi registers offset to be appropriate for GSI 2.5. For backward compatibility, added new version for the registers s/w interface. CRs-Fixed: 2295428 Change-Id: I24c52ec17ff71d3bd20f7e30ffeb6568c6b6bf10 Signed-off-by: Ghanim Fodi --- drivers/platform/msm/gsi/gsi.c | 27 + drivers/platform/msm/gsi/gsi_reg.h | 1060 +----------------------- drivers/platform/msm/gsi/gsi_reg_v1.h | 1063 +++++++++++++++++++++++++ drivers/platform/msm/gsi/gsi_reg_v2.h | 1063 +++++++++++++++++++++++++ 4 files changed, 2166 insertions(+), 1047 deletions(-) create mode 100644 drivers/platform/msm/gsi/gsi_reg_v1.h create mode 100644 drivers/platform/msm/gsi/gsi_reg_v2.h diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 19cd98f9c44e..f22bcb78ddb7 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -937,6 +937,7 @@ int gsi_register_device(struct gsi_per_props *props, unsigned long *dev_hdl) { int res; uint32_t val; + int needed_reg_ver; if (!gsi_ctx) { pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__); @@ -968,6 +969,32 @@ int gsi_register_device(struct gsi_per_props *props, unsigned long *dev_hdl) return -GSI_STATUS_UNSUPPORTED_OP; } + switch (props->ver) { + case GSI_VER_1_0: + case GSI_VER_1_2: + case GSI_VER_1_3: + case GSI_VER_2_0: + case GSI_VER_2_2: + needed_reg_ver = GSI_REGISTER_VER_1; + break; + case GSI_VER_2_5: + needed_reg_ver = GSI_REGISTER_VER_2; + break; + case GSI_VER_ERR: + case GSI_VER_MAX: + default: + GSIERR("GSI version is not supported %d\n", props->ver); + return -GSI_STATUS_INVALID_PARAMS; + } + + if (needed_reg_ver != GSI_REGISTER_VER_CURRENT) { + GSIERR("Invalid register version. current=%d, needed=%d\n", + GSI_REGISTER_VER_CURRENT, needed_reg_ver); + return -GSI_STATUS_UNSUPPORTED_OP; + } + GSIDBG("gsi ver %d register ver %d needed register ver %d\n", + props->ver, GSI_REGISTER_VER_CURRENT, needed_reg_ver); + spin_lock_init(&gsi_ctx->slock); if (props->intr == GSI_INTR_IRQ) { if (!props->irq) { diff --git a/drivers/platform/msm/gsi/gsi_reg.h b/drivers/platform/msm/gsi/gsi_reg.h index ec2e886fb2d7..8a5719282335 100644 --- a/drivers/platform/msm/gsi/gsi_reg.h +++ b/drivers/platform/msm/gsi/gsi_reg.h @@ -12,1052 +12,18 @@ #ifndef __GSI_REG_H__ #define __GSI_REG_H__ -#define GSI_GSI_REG_BASE_OFFS 0 - -#define GSI_GSI_CFG_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000000) -#define GSI_V2_5_GSI_CFG_SLEEP_CLK_DIV_BMSK 0xf00 -#define GSI_V2_5_GSI_CFG_SLEEP_CLK_DIV_SHFT 0x8 -#define GSI_GSI_CFG_BP_MTRIX_DISABLE_BMSK 0x20 -#define GSI_GSI_CFG_BP_MTRIX_DISABLE_SHFT 0x5 -#define GSI_GSI_CFG_GSI_PWR_CLPS_BMSK 0x10 -#define GSI_GSI_CFG_GSI_PWR_CLPS_SHFT 0x4 -#define GSI_GSI_CFG_UC_IS_MCS_BMSK 0x8 -#define GSI_GSI_CFG_UC_IS_MCS_SHFT 0x3 -#define GSI_GSI_CFG_DOUBLE_MCS_CLK_FREQ_BMSK 0x4 -#define GSI_GSI_CFG_DOUBLE_MCS_CLK_FREQ_SHFT 0x2 -#define GSI_GSI_CFG_MCS_ENABLE_BMSK 0x2 -#define GSI_GSI_CFG_MCS_ENABLE_SHFT 0x1 -#define GSI_GSI_CFG_GSI_ENABLE_BMSK 0x1 -#define GSI_GSI_CFG_GSI_ENABLE_SHFT 0x0 - -#define GSI_GSI_MCS_CFG_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x0000B000) -#define GSI_GSI_MCS_CFG_MCS_ENABLE_BMSK 0x1 -#define GSI_GSI_MCS_CFG_MCS_ENABLE_SHFT 0x0 - -#define GSI_GSI_PERIPH_BASE_ADDR_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000018) -#define GSI_GSI_PERIPH_BASE_ADDR_LSB_RMSK 0xffffffff -#define GSI_GSI_PERIPH_BASE_ADDR_LSB_BASE_ADDR_BMSK 0xffffffff -#define GSI_GSI_PERIPH_BASE_ADDR_LSB_BASE_ADDR_SHFT 0x0 - -#define GSI_GSI_PERIPH_BASE_ADDR_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x0000001c) -#define GSI_GSI_PERIPH_BASE_ADDR_MSB_RMSK 0xffffffff -#define GSI_GSI_PERIPH_BASE_ADDR_MSB_BASE_ADDR_BMSK 0xffffffff -#define GSI_GSI_PERIPH_BASE_ADDR_MSB_BASE_ADDR_SHFT 0x0 - -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000a0) -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000a4) -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000a8) -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000ac) -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_GEN_INT_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000b0) -#define GSI_IC_GEN_INT_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_GEN_INT_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_GEN_INT_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_GEN_INT_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_GEN_INT_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_GEN_INT_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_GEN_INT_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_GEN_INT_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_GEN_INT_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_GEN_INT_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_GEN_INT_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_GEN_INT_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000b4) -#define GSI_IC_GEN_INT_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_GEN_INT_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_GEN_INT_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_GEN_INT_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_GEN_INT_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_GEN_INT_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_GEN_INT_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_GEN_INT_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_GEN_INT_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000b8) -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000bc) -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000c0) -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000c4) -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000c8) -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_TLV_STOP_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000cc) -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_TLV_STOP_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000d0) -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_TLV_RESET_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000d4) -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_TLV_RESET_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000d8) -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000dc) -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_READ_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000e0) -#define GSI_IC_READ_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_READ_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_READ_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_READ_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_READ_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_READ_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_READ_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_READ_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_READ_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_READ_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_READ_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_READ_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000e4) -#define GSI_IC_READ_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_READ_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_READ_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_READ_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_READ_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_READ_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_READ_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_READ_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_READ_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_WRITE_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000e8) -#define GSI_IC_WRITE_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_WRITE_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_WRITE_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_WRITE_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_WRITE_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_WRITE_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_WRITE_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_WRITE_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_WRITE_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_WRITE_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_WRITE_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_WRITE_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000ec) -#define GSI_IC_WRITE_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_WRITE_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_WRITE_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_WRITE_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_WRITE_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_WRITE_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_WRITE_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_WRITE_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_WRITE_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000f0) -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_RMSK 0x3ffc1047 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_TLV_INT_SHFT 0x18 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_CSR_INT_SHFT 0x12 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_INT_END_INT_SHFT 0xc -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_REE_INT_BMSK 0x7 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_REE_INT_SHFT 0x0 - -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x000000f4) -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_RMSK 0xfc3041 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 -#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_CH_CMD_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000400) -#define GSI_GSI_IRAM_PTR_CH_CMD_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_CH_CMD_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_CH_CMD_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000404) -#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_IRAM_PTR_SHFT 0x0 - -#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000408) -#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_RMSK 0xfff -#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_IRAM_PTR_BMSK 0xfff -#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_CH_DB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000418) -#define GSI_GSI_IRAM_PTR_CH_DB_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_CH_DB_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_CH_DB_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_EV_DB_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x0000041c) -#define GSI_GSI_IRAM_PTR_EV_DB_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_EV_DB_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_EV_DB_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_NEW_RE_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000420) -#define GSI_GSI_IRAM_PTR_NEW_RE_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_NEW_RE_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_NEW_RE_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000424) -#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_CH_EMPTY_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000428) -#define GSI_GSI_IRAM_PTR_CH_EMPTY_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_CH_EMPTY_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_CH_EMPTY_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x0000042c) -#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000430) -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000434) -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000438) -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x0000043c) -#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000440) -#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000444) -#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_UC_GP_INT_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x00000448) -#define GSI_GSI_IRAM_PTR_UC_GP_INT_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_UC_GP_INT_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_UC_GP_INT_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_OFFS \ - (GSI_GSI_REG_BASE_OFFS + 0x0000044c) -#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_RMSK 0xfff -#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_IRAM_PTR_BMSK 0xfff -#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_IRAM_PTR_SHFT 0x0 - -#define GSI_GSI_INST_RAM_n_WORD_SZ 0x4 -#define GSI_GSI_INST_RAM_n_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x00004000 + GSI_GSI_INST_RAM_n_WORD_SZ * (n)) -#define GSI_V2_5_GSI_INST_RAM_n_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001b000 + GSI_GSI_INST_RAM_n_WORD_SZ * (n)) -#define GSI_GSI_INST_RAM_n_RMSK 0xffffffff -#define GSI_GSI_INST_RAM_n_MAXn 4095 -#define GSI_V2_0_GSI_INST_RAM_n_MAXn 6143 -#define GSI_V2_2_GSI_INST_RAM_n_MAXn 4095 -#define GSI_V2_5_GSI_INST_RAM_n_MAXn 8191 -#define GSI_GSI_INST_RAM_n_INST_BYTE_3_BMSK 0xff000000 -#define GSI_GSI_INST_RAM_n_INST_BYTE_3_SHFT 0x18 -#define GSI_GSI_INST_RAM_n_INST_BYTE_2_BMSK 0xff0000 -#define GSI_GSI_INST_RAM_n_INST_BYTE_2_SHFT 0x10 -#define GSI_GSI_INST_RAM_n_INST_BYTE_1_BMSK 0xff00 -#define GSI_GSI_INST_RAM_n_INST_BYTE_1_SHFT 0x8 -#define GSI_GSI_INST_RAM_n_INST_BYTE_0_BMSK 0xff -#define GSI_GSI_INST_RAM_n_INST_BYTE_0_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_CNTXT_0_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c000 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_CNTXT_0_ELEMENT_SIZE_BMSK 0xff000000 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_ELEMENT_SIZE_SHFT 0x18 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_BMSK 0xf00000 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_SHFT 0x14 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_ERINDEX_BMSK 0x7c000 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_ERINDEX_SHFT 0xe -#define GSI_V2_5_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_MSB_BMSK 0x2000 -#define GSI_V2_5_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_MSB_SHFT 0xd -#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHID_BMSK 0x1f00 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHID_SHFT 0x8 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_EE_BMSK 0xf0 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_EE_SHFT 0x4 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_DIR_BMSK 0x8 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_DIR_SHFT 0x3 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_BMSK 0x7 -#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_CNTXT_1_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c004 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_CNTXT_1_R_LENGTH_BMSK 0xffff -#define GSI_EE_n_GSI_CH_k_CNTXT_1_R_LENGTH_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_CNTXT_2_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c008 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_CNTXT_3_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c00c + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_CNTXT_4_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c010 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_CNTXT_4_READ_PTR_LSB_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_CNTXT_4_READ_PTR_LSB_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_CNTXT_5_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c014 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_CNTXT_5_READ_PTR_MSB_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_CNTXT_5_READ_PTR_MSB_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_CNTXT_6_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c018 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_CNTXT_6_WRITE_PTR_LSB_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_CNTXT_6_WRITE_PTR_LSB_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_CNTXT_7_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c01c + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_CNTXT_7_WRITE_PTR_MSB_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_CNTXT_7_WRITE_PTR_MSB_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c054 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_RMSK 0xffff -#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_MAXk 30 -#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_MAXn 3 -#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_READ_PTR_BMSK 0xffff -#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_READ_PTR_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c058 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_RMSK 0xffff -#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_MAXk 30 -#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_MAXn 3 -#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_RE_INTR_DB_BMSK 0xffff -#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_RE_INTR_DB_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_QOS_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c05c + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_QOS_RMSK 0x303 -#define GSI_EE_n_GSI_CH_k_QOS_MAXk 30 -#define GSI_EE_n_GSI_CH_k_QOS_MAXn 3 -#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_BMSK 0x400 -#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_SHFT 0xa -#define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK 0x200 -#define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT 0x9 -#define GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK 0x100 -#define GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_SHFT 0x8 -#define GSI_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_BMSK 0xf -#define GSI_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_SHFT 0x0 - -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0000f05c + 0x4000 * (n) + 0x80 * (k)) -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_EMPTY_LVL_THRSHOLD_BMSK 0xff0000 -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_EMPTY_LVL_THRSHOLD_SHFT 0x10 -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_PREFETCH_MODE_BMSK 0x3c00 -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_PREFETCH_MODE_SHFT 0xa -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK 0x200 -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT 0x9 -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK 0x100 -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_SHFT 0x8 -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_BMSK 0xf -#define GSI_V2_5_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_SHFT 0x0 - - -#define GSI_EE_n_GSI_CH_k_SCRATCH_0_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c060 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_SCRATCH_0_SCRATCH_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_SCRATCH_0_SCRATCH_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_SCRATCH_1_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c064 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_SCRATCH_1_SCRATCH_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_SCRATCH_1_SCRATCH_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_SCRATCH_2_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c068 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_SCRATCH_2_SCRATCH_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_SCRATCH_2_SCRATCH_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_SCRATCH_3_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001c06c + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_0_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d000 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_0_ELEMENT_SIZE_BMSK 0xff000000 -#define GSI_EE_n_EV_CH_k_CNTXT_0_ELEMENT_SIZE_SHFT 0x18 -#define GSI_EE_n_EV_CH_k_CNTXT_0_CHSTATE_BMSK 0xf00000 -#define GSI_EE_n_EV_CH_k_CNTXT_0_CHSTATE_SHFT 0x14 -#define GSI_EE_n_EV_CH_k_CNTXT_0_INTYPE_BMSK 0x10000 -#define GSI_EE_n_EV_CH_k_CNTXT_0_INTYPE_SHFT 0x10 -#define GSI_EE_n_EV_CH_k_CNTXT_0_EVCHID_BMSK 0xff00 -#define GSI_EE_n_EV_CH_k_CNTXT_0_EVCHID_SHFT 0x8 -#define GSI_EE_n_EV_CH_k_CNTXT_0_EE_BMSK 0xf0 -#define GSI_EE_n_EV_CH_k_CNTXT_0_EE_SHFT 0x4 -#define GSI_EE_n_EV_CH_k_CNTXT_0_CHTYPE_BMSK 0xf -#define GSI_EE_n_EV_CH_k_CNTXT_0_CHTYPE_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_1_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d004 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_1_R_LENGTH_BMSK 0xffff -#define GSI_EE_n_EV_CH_k_CNTXT_1_R_LENGTH_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_2_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d008 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_3_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d00c + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_4_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d010 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_4_READ_PTR_LSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_4_READ_PTR_LSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_5_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d014 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_5_READ_PTR_MSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_5_READ_PTR_MSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_6_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d018 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_6_WRITE_PTR_LSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_6_WRITE_PTR_LSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_7_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d01c + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_7_WRITE_PTR_MSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_7_WRITE_PTR_MSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_8_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d020 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MOD_CNT_BMSK 0xff000000 -#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MOD_CNT_SHFT 0x18 -#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODC_BMSK 0xff0000 -#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODC_SHFT 0x10 -#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODT_BMSK 0xffff -#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODT_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_9_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d024 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_9_INTVEC_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_9_INTVEC_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_10_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d028 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_10_MSI_ADDR_LSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_10_MSI_ADDR_LSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_11_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d02c + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_11_MSI_ADDR_MSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_11_MSI_ADDR_MSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_12_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d030 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_12_RP_UPDATE_ADDR_LSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_12_RP_UPDATE_ADDR_LSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_CNTXT_13_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d034 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_CNTXT_13_RP_UPDATE_ADDR_MSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_CNTXT_13_RP_UPDATE_ADDR_MSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_SCRATCH_0_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d048 + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_SCRATCH_0_SCRATCH_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_SCRATCH_0_SCRATCH_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_SCRATCH_1_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001d04c + 0x4000 * (n) + 0x80 * (k)) -#define GSI_EE_n_EV_CH_k_SCRATCH_1_SCRATCH_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_SCRATCH_1_SCRATCH_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_DOORBELL_0_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001e000 + 0x4000 * (n) + 0x8 * (k)) -#define GSI_EE_n_GSI_CH_k_DOORBELL_0_WRITE_PTR_LSB_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_DOORBELL_0_WRITE_PTR_LSB_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_k_DOORBELL_1_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001e004 + 0x4000 * (n) + 0x8 * (k)) -#define GSI_EE_n_GSI_CH_k_DOORBELL_1_WRITE_PTR_MSB_BMSK 0xffffffff -#define GSI_EE_n_GSI_CH_k_DOORBELL_1_WRITE_PTR_MSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_DOORBELL_0_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001e100 + 0x4000 * (n) + 0x8 * (k)) -#define GSI_EE_n_EV_CH_k_DOORBELL_0_WRITE_PTR_LSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_DOORBELL_0_WRITE_PTR_LSB_SHFT 0x0 - -#define GSI_EE_n_EV_CH_k_DOORBELL_1_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001e104 + 0x4000 * (n) + 0x8 * (k)) -#define GSI_EE_n_EV_CH_k_DOORBELL_1_WRITE_PTR_MSB_BMSK 0xffffffff -#define GSI_EE_n_EV_CH_k_DOORBELL_1_WRITE_PTR_MSB_SHFT 0x0 - -#define GSI_EE_n_GSI_STATUS_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f000 + 0x4000 * (n)) -#define GSI_EE_n_GSI_STATUS_ENABLED_BMSK 0x1 -#define GSI_EE_n_GSI_STATUS_ENABLED_SHFT 0x0 - -#define GSI_EE_n_GSI_CH_CMD_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f008 + 0x4000 * (n)) -#define GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK 0xff000000 -#define GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT 0x18 -#define GSI_EE_n_GSI_CH_CMD_CHID_BMSK 0xff -#define GSI_EE_n_GSI_CH_CMD_CHID_SHFT 0x0 - -#define GSI_EE_n_EV_CH_CMD_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f010 + 0x4000 * (n)) -#define GSI_EE_n_EV_CH_CMD_OPCODE_BMSK 0xff000000 -#define GSI_EE_n_EV_CH_CMD_OPCODE_SHFT 0x18 -#define GSI_EE_n_EV_CH_CMD_CHID_BMSK 0xff -#define GSI_EE_n_EV_CH_CMD_CHID_SHFT 0x0 - -#define GSI_EE_n_GSI_EE_GENERIC_CMD_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f018 + 0x4000 * (n)) -#define GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_BMSK 0x1f -#define GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_SHFT 0x0 -#define GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_BMSK 0x3e0 -#define GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_SHFT 0x5 -#define GSI_EE_n_GSI_EE_GENERIC_CMD_EE_BMSK 0x3c00 -#define GSI_EE_n_GSI_EE_GENERIC_CMD_EE_SHFT 0xa - -#define GSI_V1_0_EE_n_GSI_HW_PARAM_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) -#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_SEC_GRP_BMSK 0x7c000000 -#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_SEC_GRP_SHFT 0x1a -#define GSI_V1_0_EE_n_GSI_HW_PARAM_USE_AXI_M_BMSK 0x2000000 -#define GSI_V1_0_EE_n_GSI_HW_PARAM_USE_AXI_M_SHFT 0x19 -#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_CONF_ADDR_BUS_W_BMSK 0x1f00000 -#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_CONF_ADDR_BUS_W_SHFT 0x14 -#define GSI_V1_0_EE_n_GSI_HW_PARAM_NUM_EES_BMSK 0xf0000 -#define GSI_V1_0_EE_n_GSI_HW_PARAM_NUM_EES_SHFT 0x10 -#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_CH_NUM_BMSK 0xff00 -#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_CH_NUM_SHFT 0x8 -#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_EV_CH_NUM_BMSK 0xff -#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_EV_CH_NUM_SHFT 0x0 - -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f038 + 0x4000 * (n)) -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_USE_AXI_M_BMSK 0x80000000 -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_USE_AXI_M_SHFT 0x1f -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_SEC_GRP_BMSK 0x7c000000 -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_SEC_GRP_SHFT 0x1a -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_CONF_ADDR_BUS_W_BMSK 0x3e00000 -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_CONF_ADDR_BUS_W_SHFT 0x15 -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_NUM_EES_BMSK 0x1f0000 -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_NUM_EES_SHFT 0x10 -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_CH_NUM_BMSK 0xff00 -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_CH_NUM_SHFT 0x8 -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_EV_CH_NUM_BMSK 0xff -#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_EV_CH_NUM_SHFT 0x0 - -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_MAXn 2 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 -#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 - -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_MAXn 2 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2 -#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3 - -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_BMSK 0x8000 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_SHFT 0xf -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_BMSK 0x4000 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_SHFT 0xE -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_MAXn 2 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2 -#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3 - -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x00012040 + 0x4000 * (n)) -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_BMSK 0x8000 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_SHFT 0xf -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_BMSK 0x4000 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_SHFT 0xE -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_MAXn 2 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_N_HALF_KB_FVAL 0x4 -#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_FOUR_KB_FVAL 0x5 - -#define GSI_EE_n_GSI_SW_VERSION_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f044 + 0x4000 * (n)) -#define GSI_EE_n_GSI_SW_VERSION_MAJOR_BMSK 0xf0000000 -#define GSI_EE_n_GSI_SW_VERSION_MAJOR_SHFT 0x1c -#define GSI_EE_n_GSI_SW_VERSION_MINOR_BMSK 0xfff0000 -#define GSI_EE_n_GSI_SW_VERSION_MINOR_SHFT 0x10 -#define GSI_EE_n_GSI_SW_VERSION_STEP_BMSK 0xffff -#define GSI_EE_n_GSI_SW_VERSION_STEP_SHFT 0x0 - -#define GSI_EE_n_CNTXT_TYPE_IRQ_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f080 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_TYPE_IRQ_GENERAL_BMSK 0x40 -#define GSI_EE_n_CNTXT_TYPE_IRQ_GENERAL_SHFT 0x6 -#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_EV_CTRL_BMSK 0x20 -#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_EV_CTRL_SHFT 0x5 -#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_CH_CTRL_BMSK 0x10 -#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_CH_CTRL_SHFT 0x4 -#define GSI_EE_n_CNTXT_TYPE_IRQ_IEOB_BMSK 0x8 -#define GSI_EE_n_CNTXT_TYPE_IRQ_IEOB_SHFT 0x3 -#define GSI_EE_n_CNTXT_TYPE_IRQ_GLOB_EE_BMSK 0x4 -#define GSI_EE_n_CNTXT_TYPE_IRQ_GLOB_EE_SHFT 0x2 -#define GSI_EE_n_CNTXT_TYPE_IRQ_EV_CTRL_BMSK 0x2 -#define GSI_EE_n_CNTXT_TYPE_IRQ_EV_CTRL_SHFT 0x1 -#define GSI_EE_n_CNTXT_TYPE_IRQ_CH_CTRL_BMSK 0x1 -#define GSI_EE_n_CNTXT_TYPE_IRQ_CH_CTRL_SHFT 0x0 - -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f088 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GENERAL_BMSK 0x40 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GENERAL_SHFT 0x6 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_EV_CTRL_BMSK 0x20 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_EV_CTRL_SHFT 0x5 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_CH_CTRL_BMSK 0x10 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_CH_CTRL_SHFT 0x4 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_IEOB_BMSK 0x8 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_IEOB_SHFT 0x3 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GLOB_EE_BMSK 0x4 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GLOB_EE_SHFT 0x2 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_EV_CTRL_BMSK 0x2 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_EV_CTRL_SHFT 0x1 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_CH_CTRL_BMSK 0x1 -#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_CH_CTRL_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f090 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f094 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f098 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_BMSK 0x1ffff -#define GSI_V2_5_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_BMSK 0x7fffff -#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_SHFT 0x0 -#define GSI_V2_5_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f09c + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfff -#define GSI_V2_5_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfffff -#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 -#define GSI_V2_5_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f0a0 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f0a4 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f0b0 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_EV_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_EV_CH_BIT_MAP_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f0b8 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfff -#define GSI_V2_5_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfffff -#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 -#define GSI_V2_5_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f0c0 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 - -#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f100 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT3_BMSK 0x8 -#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT3_SHFT 0x3 -#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT2_BMSK 0x4 -#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT2_SHFT 0x2 -#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT1_BMSK 0x2 -#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT1_SHFT 0x1 -#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_ERROR_INT_BMSK 0x1 -#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_ERROR_INT_SHFT 0x0 - -#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f108 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT3_BMSK 0x8 -#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT3_SHFT 0x3 -#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT2_BMSK 0x4 -#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT2_SHFT 0x2 -#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT1_BMSK 0x2 -#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT1_SHFT 0x1 -#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_ERROR_INT_BMSK 0x1 -#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_ERROR_INT_SHFT 0x0 - -#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f110 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT3_BMSK 0x8 -#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT3_SHFT 0x3 -#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT2_BMSK 0x4 -#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT2_SHFT 0x2 -#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT1_BMSK 0x2 -#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT1_SHFT 0x1 -#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_ERROR_INT_BMSK 0x1 -#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_ERROR_INT_SHFT 0x0 - -#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f118 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_MCS_STACK_OVRFLOW_BMSK 0x8 -#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_MCS_STACK_OVRFLOW_SHFT 0x3 -#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_CMD_FIFO_OVRFLOW_BMSK 0x4 -#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_CMD_FIFO_OVRFLOW_SHFT 0x2 -#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BUS_ERROR_BMSK 0x2 -#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BUS_ERROR_SHFT 0x1 -#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BREAK_POINT_BMSK 0x1 -#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BREAK_POINT_SHFT 0x0 - -#define GSI_EE_n_CNTXT_GSI_IRQ_EN_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f120 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_MCS_STACK_OVRFLOW_BMSK 0x8 -#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_MCS_STACK_OVRFLOW_SHFT 0x3 -#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_CMD_FIFO_OVRFLOW_BMSK 0x4 -#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_CMD_FIFO_OVRFLOW_SHFT 0x2 -#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BUS_ERROR_BMSK 0x2 -#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BUS_ERROR_SHFT 0x1 -#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BREAK_POINT_BMSK 0x1 -#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BREAK_POINT_SHFT 0x0 - -#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f128 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_MCS_STACK_OVRFLOW_BMSK 0x8 -#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_MCS_STACK_OVRFLOW_SHFT 0x3 -#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_CMD_FIFO_OVRFLOW_BMSK 0x4 -#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_CMD_FIFO_OVRFLOW_SHFT 0x2 -#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BUS_ERROR_BMSK 0x2 -#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BUS_ERROR_SHFT 0x1 -#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BREAK_POINT_BMSK 0x1 -#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BREAK_POINT_SHFT 0x0 - -#define GSI_EE_n_CNTXT_INTSET_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f180 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_INTSET_INTYPE_BMSK 0x1 -#define GSI_EE_n_CNTXT_INTSET_INTYPE_SHFT 0x0 - -#define GSI_EE_n_ERROR_LOG_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f200 + 0x4000 * (n)) -#define GSI_EE_n_ERROR_LOG_TODO_BMSK 0xffffffff -#define GSI_EE_n_ERROR_LOG_TODO_SHFT 0x0 - -#define GSI_EE_n_ERROR_LOG_CLR_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f210 + 0x4000 * (n)) -#define GSI_EE_n_ERROR_LOG_CLR_TODO_BMSK 0xffffffff -#define GSI_EE_n_ERROR_LOG_CLR_TODO_SHFT 0x0 - -#define GSI_EE_n_CNTXT_SCRATCH_0_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0001f400 + 0x4000 * (n)) -#define GSI_EE_n_CNTXT_SCRATCH_0_SCRATCH_BMSK 0xffffffff -#define GSI_EE_n_CNTXT_SCRATCH_0_SCRATCH_SHFT 0x0 - -#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0000c018 + 0x1000 * (n)) -#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_SHFT 0x0 - -#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0000c01c + 0x1000 * (n)) -#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_SHFT 0x0 - -#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0000c028 + 0x1000 * (n)) -#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_SHFT 0x0 - -#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_OFFS(n) \ - (GSI_GSI_REG_BASE_OFFS + 0x0000c02c + 0x1000 * (n)) -#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff -#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 - -#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_OFFS(k, n) \ - (GSI_GSI_REG_BASE_OFFS + 0x00003800 + 0x80 * (n) + 0x4 * (k)) -#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_VALID_BMSK 0x20 -#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_VALID_SHFT 0x5 -#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_PHY_CH_BMSK 0x1f -#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_PHY_CH_SHFT 0x0 +enum gsi_register_ver { + GSI_REGISTER_VER_1 = 0, + GSI_REGISTER_VER_2 = 1, + GSI_REGISTER_MAX, +}; + +#ifdef CONFIG_GSI_REGISTER_VERSION_2 +#include "gsi_reg_v2.h" +#define GSI_REGISTER_VER_CURRENT GSI_REGISTER_VER_2 +#else +#include "gsi_reg_v1.h" +#define GSI_REGISTER_VER_CURRENT GSI_REGISTER_VER_1 +#endif #endif /* __GSI_REG_H__ */ diff --git a/drivers/platform/msm/gsi/gsi_reg_v1.h b/drivers/platform/msm/gsi/gsi_reg_v1.h new file mode 100644 index 000000000000..7dbe649cdb0a --- /dev/null +++ b/drivers/platform/msm/gsi/gsi_reg_v1.h @@ -0,0 +1,1063 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __GSI_REG_V1_H__ +#define __GSI_REG_V1_H__ + +#define GSI_GSI_REG_BASE_OFFS 0 + +#define GSI_GSI_CFG_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000000) +#define GSI_V2_5_GSI_CFG_SLEEP_CLK_DIV_BMSK 0xf00 +#define GSI_V2_5_GSI_CFG_SLEEP_CLK_DIV_SHFT 0x8 +#define GSI_GSI_CFG_BP_MTRIX_DISABLE_BMSK 0x20 +#define GSI_GSI_CFG_BP_MTRIX_DISABLE_SHFT 0x5 +#define GSI_GSI_CFG_GSI_PWR_CLPS_BMSK 0x10 +#define GSI_GSI_CFG_GSI_PWR_CLPS_SHFT 0x4 +#define GSI_GSI_CFG_UC_IS_MCS_BMSK 0x8 +#define GSI_GSI_CFG_UC_IS_MCS_SHFT 0x3 +#define GSI_GSI_CFG_DOUBLE_MCS_CLK_FREQ_BMSK 0x4 +#define GSI_GSI_CFG_DOUBLE_MCS_CLK_FREQ_SHFT 0x2 +#define GSI_GSI_CFG_MCS_ENABLE_BMSK 0x2 +#define GSI_GSI_CFG_MCS_ENABLE_SHFT 0x1 +#define GSI_GSI_CFG_GSI_ENABLE_BMSK 0x1 +#define GSI_GSI_CFG_GSI_ENABLE_SHFT 0x0 + +#define GSI_GSI_MCS_CFG_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000B000) +#define GSI_GSI_MCS_CFG_MCS_ENABLE_BMSK 0x1 +#define GSI_GSI_MCS_CFG_MCS_ENABLE_SHFT 0x0 + +#define GSI_GSI_PERIPH_BASE_ADDR_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000018) +#define GSI_GSI_PERIPH_BASE_ADDR_LSB_RMSK 0xffffffff +#define GSI_GSI_PERIPH_BASE_ADDR_LSB_BASE_ADDR_BMSK 0xffffffff +#define GSI_GSI_PERIPH_BASE_ADDR_LSB_BASE_ADDR_SHFT 0x0 + +#define GSI_GSI_PERIPH_BASE_ADDR_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000001c) +#define GSI_GSI_PERIPH_BASE_ADDR_MSB_RMSK 0xffffffff +#define GSI_GSI_PERIPH_BASE_ADDR_MSB_BASE_ADDR_BMSK 0xffffffff +#define GSI_GSI_PERIPH_BASE_ADDR_MSB_BASE_ADDR_SHFT 0x0 + +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000a0) +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000a4) +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000a8) +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000ac) +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_GEN_INT_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000b0) +#define GSI_IC_GEN_INT_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_GEN_INT_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_GEN_INT_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000b4) +#define GSI_IC_GEN_INT_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_GEN_INT_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000b8) +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000bc) +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000c0) +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000c4) +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000c8) +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000cc) +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000d0) +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000d4) +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000d8) +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000dc) +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_READ_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000e0) +#define GSI_IC_READ_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_READ_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_READ_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_READ_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_READ_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_READ_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_READ_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_READ_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_READ_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_READ_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_READ_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_READ_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000e4) +#define GSI_IC_READ_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_READ_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_READ_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_READ_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_READ_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_READ_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_READ_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_READ_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_READ_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_WRITE_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000e8) +#define GSI_IC_WRITE_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_WRITE_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_WRITE_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_WRITE_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_WRITE_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_WRITE_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_WRITE_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_WRITE_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_WRITE_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_WRITE_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_WRITE_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_WRITE_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000ec) +#define GSI_IC_WRITE_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_WRITE_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_WRITE_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_WRITE_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_WRITE_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_WRITE_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_WRITE_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_WRITE_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_WRITE_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000f0) +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000f4) +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_CH_CMD_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000400) +#define GSI_GSI_IRAM_PTR_CH_CMD_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_CMD_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_CMD_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000404) +#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_IRAM_PTR_SHFT 0x0 + +#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000408) +#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_RMSK 0xfff +#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_IRAM_PTR_BMSK 0xfff +#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_CH_DB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000418) +#define GSI_GSI_IRAM_PTR_CH_DB_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_DB_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_DB_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_EV_DB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000041c) +#define GSI_GSI_IRAM_PTR_EV_DB_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_EV_DB_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_EV_DB_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_NEW_RE_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000420) +#define GSI_GSI_IRAM_PTR_NEW_RE_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_NEW_RE_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_NEW_RE_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000424) +#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_CH_EMPTY_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000428) +#define GSI_GSI_IRAM_PTR_CH_EMPTY_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_EMPTY_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_EMPTY_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000042c) +#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000430) +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000434) +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000438) +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000043c) +#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000440) +#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000444) +#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_UC_GP_INT_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000448) +#define GSI_GSI_IRAM_PTR_UC_GP_INT_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_UC_GP_INT_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_UC_GP_INT_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000044c) +#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_INST_RAM_n_WORD_SZ 0x4 +#define GSI_GSI_INST_RAM_n_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00004000 + GSI_GSI_INST_RAM_n_WORD_SZ * (n)) +#define GSI_V2_5_GSI_INST_RAM_n_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001b000 + GSI_GSI_INST_RAM_n_WORD_SZ * (n)) +#define GSI_GSI_INST_RAM_n_RMSK 0xffffffff +#define GSI_GSI_INST_RAM_n_MAXn 4095 +#define GSI_V2_0_GSI_INST_RAM_n_MAXn 6143 +#define GSI_V2_2_GSI_INST_RAM_n_MAXn 4095 +#define GSI_V2_5_GSI_INST_RAM_n_MAXn 8191 +#define GSI_GSI_INST_RAM_n_INST_BYTE_3_BMSK 0xff000000 +#define GSI_GSI_INST_RAM_n_INST_BYTE_3_SHFT 0x18 +#define GSI_GSI_INST_RAM_n_INST_BYTE_2_BMSK 0xff0000 +#define GSI_GSI_INST_RAM_n_INST_BYTE_2_SHFT 0x10 +#define GSI_GSI_INST_RAM_n_INST_BYTE_1_BMSK 0xff00 +#define GSI_GSI_INST_RAM_n_INST_BYTE_1_SHFT 0x8 +#define GSI_GSI_INST_RAM_n_INST_BYTE_0_BMSK 0xff +#define GSI_GSI_INST_RAM_n_INST_BYTE_0_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c000 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_0_ELEMENT_SIZE_BMSK 0xff000000 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_ELEMENT_SIZE_SHFT 0x18 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_BMSK 0xf00000 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_SHFT 0x14 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_ERINDEX_BMSK 0x7c000 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_ERINDEX_SHFT 0xe +#define GSI_V2_5_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_MSB_BMSK 0x2000 +#define GSI_V2_5_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_MSB_SHFT 0xd +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHID_BMSK 0x1f00 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHID_SHFT 0x8 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_EE_BMSK 0xf0 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_EE_SHFT 0x4 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_DIR_BMSK 0x8 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_DIR_SHFT 0x3 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_BMSK 0x7 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c004 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_1_R_LENGTH_BMSK 0xffff +#define GSI_EE_n_GSI_CH_k_CNTXT_1_R_LENGTH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_2_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c008 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_3_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c00c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_4_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c010 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_4_READ_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_4_READ_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_5_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c014 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_5_READ_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_5_READ_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_6_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c018 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_6_WRITE_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_6_WRITE_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_7_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c01c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_7_WRITE_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_7_WRITE_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c054 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_RMSK 0xffff +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_MAXk 30 +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_MAXn 3 +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_READ_PTR_BMSK 0xffff +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_READ_PTR_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c058 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_RMSK 0xffff +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_MAXk 30 +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_MAXn 3 +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_RE_INTR_DB_BMSK 0xffff +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_RE_INTR_DB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_QOS_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c05c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_QOS_RMSK 0x303 +#define GSI_EE_n_GSI_CH_k_QOS_MAXk 30 +#define GSI_EE_n_GSI_CH_k_QOS_MAXn 3 +#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_BMSK 0x400 +#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_SHFT 0xa +#define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK 0x200 +#define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT 0x9 +#define GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK 0x100 +#define GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_SHFT 0x8 +#define GSI_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_BMSK 0xf +#define GSI_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_SHFT 0x0 + +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f05c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_EMPTY_LVL_THRSHOLD_BMSK 0xff0000 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_EMPTY_LVL_THRSHOLD_SHFT 0x10 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_PREFETCH_MODE_BMSK 0x3c00 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_PREFETCH_MODE_SHFT 0xa +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK 0x200 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT 0x9 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK 0x100 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_SHFT 0x8 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_BMSK 0xf +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_SHFT 0x0 + + +#define GSI_EE_n_GSI_CH_k_SCRATCH_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c060 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_SCRATCH_0_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_SCRATCH_0_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_SCRATCH_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c064 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_SCRATCH_1_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_SCRATCH_1_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_SCRATCH_2_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c068 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_SCRATCH_2_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_SCRATCH_2_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_SCRATCH_3_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c06c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d000 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_0_ELEMENT_SIZE_BMSK 0xff000000 +#define GSI_EE_n_EV_CH_k_CNTXT_0_ELEMENT_SIZE_SHFT 0x18 +#define GSI_EE_n_EV_CH_k_CNTXT_0_CHSTATE_BMSK 0xf00000 +#define GSI_EE_n_EV_CH_k_CNTXT_0_CHSTATE_SHFT 0x14 +#define GSI_EE_n_EV_CH_k_CNTXT_0_INTYPE_BMSK 0x10000 +#define GSI_EE_n_EV_CH_k_CNTXT_0_INTYPE_SHFT 0x10 +#define GSI_EE_n_EV_CH_k_CNTXT_0_EVCHID_BMSK 0xff00 +#define GSI_EE_n_EV_CH_k_CNTXT_0_EVCHID_SHFT 0x8 +#define GSI_EE_n_EV_CH_k_CNTXT_0_EE_BMSK 0xf0 +#define GSI_EE_n_EV_CH_k_CNTXT_0_EE_SHFT 0x4 +#define GSI_EE_n_EV_CH_k_CNTXT_0_CHTYPE_BMSK 0xf +#define GSI_EE_n_EV_CH_k_CNTXT_0_CHTYPE_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d004 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_1_R_LENGTH_BMSK 0xffff +#define GSI_EE_n_EV_CH_k_CNTXT_1_R_LENGTH_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_2_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d008 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_3_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d00c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_4_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d010 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_4_READ_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_4_READ_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_5_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d014 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_5_READ_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_5_READ_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_6_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d018 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_6_WRITE_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_6_WRITE_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_7_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d01c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_7_WRITE_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_7_WRITE_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_8_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d020 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MOD_CNT_BMSK 0xff000000 +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MOD_CNT_SHFT 0x18 +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODC_BMSK 0xff0000 +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODC_SHFT 0x10 +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODT_BMSK 0xffff +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODT_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_9_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d024 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_9_INTVEC_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_9_INTVEC_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_10_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d028 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_10_MSI_ADDR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_10_MSI_ADDR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_11_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d02c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_11_MSI_ADDR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_11_MSI_ADDR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_12_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d030 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_12_RP_UPDATE_ADDR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_12_RP_UPDATE_ADDR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_13_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d034 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_13_RP_UPDATE_ADDR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_13_RP_UPDATE_ADDR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_SCRATCH_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d048 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_SCRATCH_0_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_SCRATCH_0_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_SCRATCH_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001d04c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_SCRATCH_1_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_SCRATCH_1_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_DOORBELL_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001e000 + 0x4000 * (n) + 0x8 * (k)) +#define GSI_EE_n_GSI_CH_k_DOORBELL_0_WRITE_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_DOORBELL_0_WRITE_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_DOORBELL_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001e004 + 0x4000 * (n) + 0x8 * (k)) +#define GSI_EE_n_GSI_CH_k_DOORBELL_1_WRITE_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_DOORBELL_1_WRITE_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_DOORBELL_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001e100 + 0x4000 * (n) + 0x8 * (k)) +#define GSI_EE_n_EV_CH_k_DOORBELL_0_WRITE_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_DOORBELL_0_WRITE_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_DOORBELL_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001e104 + 0x4000 * (n) + 0x8 * (k)) +#define GSI_EE_n_EV_CH_k_DOORBELL_1_WRITE_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_DOORBELL_1_WRITE_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_GSI_STATUS_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f000 + 0x4000 * (n)) +#define GSI_EE_n_GSI_STATUS_ENABLED_BMSK 0x1 +#define GSI_EE_n_GSI_STATUS_ENABLED_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_CMD_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f008 + 0x4000 * (n)) +#define GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK 0xff000000 +#define GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT 0x18 +#define GSI_EE_n_GSI_CH_CMD_CHID_BMSK 0xff +#define GSI_EE_n_GSI_CH_CMD_CHID_SHFT 0x0 + +#define GSI_EE_n_EV_CH_CMD_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f010 + 0x4000 * (n)) +#define GSI_EE_n_EV_CH_CMD_OPCODE_BMSK 0xff000000 +#define GSI_EE_n_EV_CH_CMD_OPCODE_SHFT 0x18 +#define GSI_EE_n_EV_CH_CMD_CHID_BMSK 0xff +#define GSI_EE_n_EV_CH_CMD_CHID_SHFT 0x0 + +#define GSI_EE_n_GSI_EE_GENERIC_CMD_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f018 + 0x4000 * (n)) +#define GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_BMSK 0x1f +#define GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_SHFT 0x0 +#define GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_BMSK 0x3e0 +#define GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_SHFT 0x5 +#define GSI_EE_n_GSI_EE_GENERIC_CMD_EE_BMSK 0x3c00 +#define GSI_EE_n_GSI_EE_GENERIC_CMD_EE_SHFT 0xa + +#define GSI_V1_0_EE_n_GSI_HW_PARAM_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) +#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_SEC_GRP_BMSK 0x7c000000 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_SEC_GRP_SHFT 0x1a +#define GSI_V1_0_EE_n_GSI_HW_PARAM_USE_AXI_M_BMSK 0x2000000 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_USE_AXI_M_SHFT 0x19 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_CONF_ADDR_BUS_W_BMSK 0x1f00000 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_CONF_ADDR_BUS_W_SHFT 0x14 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_NUM_EES_BMSK 0xf0000 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_NUM_EES_SHFT 0x10 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_CH_NUM_BMSK 0xff00 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_CH_NUM_SHFT 0x8 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_EV_CH_NUM_BMSK 0xff +#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_EV_CH_NUM_SHFT 0x0 + +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f038 + 0x4000 * (n)) +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_USE_AXI_M_BMSK 0x80000000 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_USE_AXI_M_SHFT 0x1f +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_SEC_GRP_BMSK 0x7c000000 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_SEC_GRP_SHFT 0x1a +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_CONF_ADDR_BUS_W_BMSK 0x3e00000 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_CONF_ADDR_BUS_W_SHFT 0x15 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_NUM_EES_BMSK 0x1f0000 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_NUM_EES_SHFT 0x10 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_CH_NUM_BMSK 0xff00 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_CH_NUM_SHFT 0x8 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_EV_CH_NUM_BMSK 0xff +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_EV_CH_NUM_SHFT 0x0 + +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_MAXn 2 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 + +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_MAXn 2 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3 + +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_BMSK 0x8000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_SHFT 0xf +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_BMSK 0x4000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_SHFT 0xE +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_MAXn 2 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3 + +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012040 + 0x4000 * (n)) +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_BMSK 0x8000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_SHFT 0xf +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_BMSK 0x4000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_SHFT 0xE +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_MAXn 2 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_N_HALF_KB_FVAL 0x4 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_FOUR_KB_FVAL 0x5 + +#define GSI_EE_n_GSI_SW_VERSION_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f044 + 0x4000 * (n)) +#define GSI_EE_n_GSI_SW_VERSION_MAJOR_BMSK 0xf0000000 +#define GSI_EE_n_GSI_SW_VERSION_MAJOR_SHFT 0x1c +#define GSI_EE_n_GSI_SW_VERSION_MINOR_BMSK 0xfff0000 +#define GSI_EE_n_GSI_SW_VERSION_MINOR_SHFT 0x10 +#define GSI_EE_n_GSI_SW_VERSION_STEP_BMSK 0xffff +#define GSI_EE_n_GSI_SW_VERSION_STEP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_TYPE_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f080 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_TYPE_IRQ_GENERAL_BMSK 0x40 +#define GSI_EE_n_CNTXT_TYPE_IRQ_GENERAL_SHFT 0x6 +#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_EV_CTRL_BMSK 0x20 +#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_EV_CTRL_SHFT 0x5 +#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_CH_CTRL_BMSK 0x10 +#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_CH_CTRL_SHFT 0x4 +#define GSI_EE_n_CNTXT_TYPE_IRQ_IEOB_BMSK 0x8 +#define GSI_EE_n_CNTXT_TYPE_IRQ_IEOB_SHFT 0x3 +#define GSI_EE_n_CNTXT_TYPE_IRQ_GLOB_EE_BMSK 0x4 +#define GSI_EE_n_CNTXT_TYPE_IRQ_GLOB_EE_SHFT 0x2 +#define GSI_EE_n_CNTXT_TYPE_IRQ_EV_CTRL_BMSK 0x2 +#define GSI_EE_n_CNTXT_TYPE_IRQ_EV_CTRL_SHFT 0x1 +#define GSI_EE_n_CNTXT_TYPE_IRQ_CH_CTRL_BMSK 0x1 +#define GSI_EE_n_CNTXT_TYPE_IRQ_CH_CTRL_SHFT 0x0 + +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f088 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GENERAL_BMSK 0x40 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GENERAL_SHFT 0x6 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_EV_CTRL_BMSK 0x20 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_EV_CTRL_SHFT 0x5 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_CH_CTRL_BMSK 0x10 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_CH_CTRL_SHFT 0x4 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_IEOB_BMSK 0x8 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_IEOB_SHFT 0x3 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GLOB_EE_BMSK 0x4 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GLOB_EE_SHFT 0x2 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_EV_CTRL_BMSK 0x2 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_EV_CTRL_SHFT 0x1 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_CH_CTRL_BMSK 0x1 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_CH_CTRL_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f090 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f094 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f098 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_BMSK 0x1ffff +#define GSI_V2_5_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_BMSK 0x7fffff +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_SHFT 0x0 +#define GSI_V2_5_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f09c + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfff +#define GSI_V2_5_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfffff +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 +#define GSI_V2_5_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f0a0 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f0a4 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f0b0 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f0b8 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfff +#define GSI_V2_5_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfffff +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 +#define GSI_V2_5_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f0c0 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f100 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT3_BMSK 0x8 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT3_SHFT 0x3 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT2_BMSK 0x4 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT2_SHFT 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT1_BMSK 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT1_SHFT 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_ERROR_INT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_ERROR_INT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f108 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT3_BMSK 0x8 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT3_SHFT 0x3 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT2_BMSK 0x4 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT2_SHFT 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT1_BMSK 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT1_SHFT 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_ERROR_INT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_ERROR_INT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f110 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT3_BMSK 0x8 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT3_SHFT 0x3 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT2_BMSK 0x4 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT2_SHFT 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT1_BMSK 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT1_SHFT 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_ERROR_INT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_ERROR_INT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f118 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_MCS_STACK_OVRFLOW_BMSK 0x8 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_MCS_STACK_OVRFLOW_SHFT 0x3 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_CMD_FIFO_OVRFLOW_BMSK 0x4 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_CMD_FIFO_OVRFLOW_SHFT 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BUS_ERROR_BMSK 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BUS_ERROR_SHFT 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BREAK_POINT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BREAK_POINT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f120 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_MCS_STACK_OVRFLOW_BMSK 0x8 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_MCS_STACK_OVRFLOW_SHFT 0x3 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_CMD_FIFO_OVRFLOW_BMSK 0x4 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_CMD_FIFO_OVRFLOW_SHFT 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BUS_ERROR_BMSK 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BUS_ERROR_SHFT 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BREAK_POINT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BREAK_POINT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f128 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_MCS_STACK_OVRFLOW_BMSK 0x8 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_MCS_STACK_OVRFLOW_SHFT 0x3 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_CMD_FIFO_OVRFLOW_BMSK 0x4 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_CMD_FIFO_OVRFLOW_SHFT 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BUS_ERROR_BMSK 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BUS_ERROR_SHFT 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BREAK_POINT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BREAK_POINT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_INTSET_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f180 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_INTSET_INTYPE_BMSK 0x1 +#define GSI_EE_n_CNTXT_INTSET_INTYPE_SHFT 0x0 + +#define GSI_EE_n_ERROR_LOG_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f200 + 0x4000 * (n)) +#define GSI_EE_n_ERROR_LOG_TODO_BMSK 0xffffffff +#define GSI_EE_n_ERROR_LOG_TODO_SHFT 0x0 + +#define GSI_EE_n_ERROR_LOG_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f210 + 0x4000 * (n)) +#define GSI_EE_n_ERROR_LOG_CLR_TODO_BMSK 0xffffffff +#define GSI_EE_n_ERROR_LOG_CLR_TODO_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SCRATCH_0_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f400 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SCRATCH_0_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SCRATCH_0_SCRATCH_SHFT 0x0 + +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000c018 + 0x1000 * (n)) +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_SHFT 0x0 + +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000c01c + 0x1000 * (n)) +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000c028 + 0x1000 * (n)) +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_SHFT 0x0 + +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000c02c + 0x1000 * (n)) +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00003800 + 0x80 * (n) + 0x4 * (k)) +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_VALID_BMSK 0x20 +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_VALID_SHFT 0x5 +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_PHY_CH_BMSK 0x1f +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_PHY_CH_SHFT 0x0 + +#endif /* __GSI_REG_V1_H__ */ diff --git a/drivers/platform/msm/gsi/gsi_reg_v2.h b/drivers/platform/msm/gsi/gsi_reg_v2.h new file mode 100644 index 000000000000..e31730d08b38 --- /dev/null +++ b/drivers/platform/msm/gsi/gsi_reg_v2.h @@ -0,0 +1,1063 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __GSI_REG_V2_H__ +#define __GSI_REG_V2_H__ + +#define GSI_GSI_REG_BASE_OFFS 0 + +#define GSI_GSI_CFG_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000000) +#define GSI_V2_5_GSI_CFG_SLEEP_CLK_DIV_BMSK 0xf00 +#define GSI_V2_5_GSI_CFG_SLEEP_CLK_DIV_SHFT 0x8 +#define GSI_GSI_CFG_BP_MTRIX_DISABLE_BMSK 0x20 +#define GSI_GSI_CFG_BP_MTRIX_DISABLE_SHFT 0x5 +#define GSI_GSI_CFG_GSI_PWR_CLPS_BMSK 0x10 +#define GSI_GSI_CFG_GSI_PWR_CLPS_SHFT 0x4 +#define GSI_GSI_CFG_UC_IS_MCS_BMSK 0x8 +#define GSI_GSI_CFG_UC_IS_MCS_SHFT 0x3 +#define GSI_GSI_CFG_DOUBLE_MCS_CLK_FREQ_BMSK 0x4 +#define GSI_GSI_CFG_DOUBLE_MCS_CLK_FREQ_SHFT 0x2 +#define GSI_GSI_CFG_MCS_ENABLE_BMSK 0x2 +#define GSI_GSI_CFG_MCS_ENABLE_SHFT 0x1 +#define GSI_GSI_CFG_GSI_ENABLE_BMSK 0x1 +#define GSI_GSI_CFG_GSI_ENABLE_SHFT 0x0 + +#define GSI_GSI_MCS_CFG_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000B000) +#define GSI_GSI_MCS_CFG_MCS_ENABLE_BMSK 0x1 +#define GSI_GSI_MCS_CFG_MCS_ENABLE_SHFT 0x0 + +#define GSI_GSI_PERIPH_BASE_ADDR_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000018) +#define GSI_GSI_PERIPH_BASE_ADDR_LSB_RMSK 0xffffffff +#define GSI_GSI_PERIPH_BASE_ADDR_LSB_BASE_ADDR_BMSK 0xffffffff +#define GSI_GSI_PERIPH_BASE_ADDR_LSB_BASE_ADDR_SHFT 0x0 + +#define GSI_GSI_PERIPH_BASE_ADDR_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000001c) +#define GSI_GSI_PERIPH_BASE_ADDR_MSB_RMSK 0xffffffff +#define GSI_GSI_PERIPH_BASE_ADDR_MSB_BASE_ADDR_BMSK 0xffffffff +#define GSI_GSI_PERIPH_BASE_ADDR_MSB_BASE_ADDR_SHFT 0x0 + +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000a0) +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000a4) +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_DISABLE_CHNL_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000a8) +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_GEN_EVNT_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000ac) +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_GEN_EVNT_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_GEN_INT_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000b0) +#define GSI_IC_GEN_INT_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_GEN_INT_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_GEN_INT_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_GEN_INT_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000b4) +#define GSI_IC_GEN_INT_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_GEN_INT_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_GEN_INT_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000b8) +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000bc) +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_STOP_INT_MOD_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000c0) +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_PROCESS_DESC_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000c4) +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_PROCESS_DESC_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000c8) +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_TLV_STOP_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000cc) +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_TLV_STOP_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000d0) +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_TLV_RESET_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000d4) +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_TLV_RESET_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000d8) +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000dc) +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_RGSTR_TIMER_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_READ_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000e0) +#define GSI_IC_READ_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_READ_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_READ_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_READ_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_READ_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_READ_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_READ_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_READ_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_READ_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_READ_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_READ_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_READ_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000e4) +#define GSI_IC_READ_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_READ_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_READ_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_READ_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_READ_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_READ_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_READ_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_READ_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_READ_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_WRITE_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000e8) +#define GSI_IC_WRITE_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_WRITE_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_WRITE_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_WRITE_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_WRITE_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_WRITE_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_WRITE_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_WRITE_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_WRITE_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_WRITE_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_WRITE_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_WRITE_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000ec) +#define GSI_IC_WRITE_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_WRITE_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_WRITE_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_WRITE_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_WRITE_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_WRITE_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_WRITE_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_WRITE_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_WRITE_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000f0) +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_RMSK 0x3ffc1047 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_TLV_INT_BMSK 0x3f000000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_TLV_INT_SHFT 0x18 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_CSR_INT_BMSK 0xfc0000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_CSR_INT_SHFT 0x12 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_INT_END_INT_BMSK 0x1000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_INT_END_INT_SHFT 0xc +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_EV_ENG_INT_BMSK 0x40 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_EV_ENG_INT_SHFT 0x6 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_REE_INT_BMSK 0x7 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_LSB_REE_INT_SHFT 0x0 + +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x000000f4) +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_RMSK 0xfc3041 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_UCONTROLLER_INT_BMSK 0xfc0000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_UCONTROLLER_INT_SHFT 0x12 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_RD_WR_INT_BMSK 0x3000 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_RD_WR_INT_SHFT 0xc +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_DB_ENG_INT_BMSK 0x40 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_DB_ENG_INT_SHFT 0x6 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_TIMER_INT_BMSK 0x1 +#define GSI_IC_UCONTROLLER_GPR_BCK_PRS_MSB_TIMER_INT_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_CH_CMD_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000400) +#define GSI_GSI_IRAM_PTR_CH_CMD_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_CMD_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_CMD_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000404) +#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_EE_GENERIC_CMD_IRAM_PTR_SHFT 0x0 + +#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000408) +#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_RMSK 0xfff +#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_IRAM_PTR_BMSK 0xfff +#define GSI_V2_5_GSI_IRAM_PTR_TLV_CH_NOT_FULL_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_CH_DB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000418) +#define GSI_GSI_IRAM_PTR_CH_DB_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_DB_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_DB_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_EV_DB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000041c) +#define GSI_GSI_IRAM_PTR_EV_DB_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_EV_DB_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_EV_DB_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_NEW_RE_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000420) +#define GSI_GSI_IRAM_PTR_NEW_RE_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_NEW_RE_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_NEW_RE_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000424) +#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_DIS_COMP_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_CH_EMPTY_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000428) +#define GSI_GSI_IRAM_PTR_CH_EMPTY_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_EMPTY_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_CH_EMPTY_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000042c) +#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_EVENT_GEN_COMP_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000430) +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_0_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000434) +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_2_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000438) +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_PERIPH_IF_TLV_IN_1_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000043c) +#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_TIMER_EXPIRED_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000440) +#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_WRITE_ENG_COMP_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000444) +#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_READ_ENG_COMP_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_UC_GP_INT_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00000448) +#define GSI_GSI_IRAM_PTR_UC_GP_INT_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_UC_GP_INT_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_UC_GP_INT_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000044c) +#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_RMSK 0xfff +#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_IRAM_PTR_BMSK 0xfff +#define GSI_GSI_IRAM_PTR_INT_MOD_STOPED_IRAM_PTR_SHFT 0x0 + +#define GSI_GSI_INST_RAM_n_WORD_SZ 0x4 +#define GSI_GSI_INST_RAM_n_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00004000 + GSI_GSI_INST_RAM_n_WORD_SZ * (n)) +#define GSI_V2_5_GSI_INST_RAM_n_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001b000 + GSI_GSI_INST_RAM_n_WORD_SZ * (n)) +#define GSI_GSI_INST_RAM_n_RMSK 0xffffffff +#define GSI_GSI_INST_RAM_n_MAXn 4095 +#define GSI_V2_0_GSI_INST_RAM_n_MAXn 6143 +#define GSI_V2_2_GSI_INST_RAM_n_MAXn 4095 +#define GSI_V2_5_GSI_INST_RAM_n_MAXn 8191 +#define GSI_GSI_INST_RAM_n_INST_BYTE_3_BMSK 0xff000000 +#define GSI_GSI_INST_RAM_n_INST_BYTE_3_SHFT 0x18 +#define GSI_GSI_INST_RAM_n_INST_BYTE_2_BMSK 0xff0000 +#define GSI_GSI_INST_RAM_n_INST_BYTE_2_SHFT 0x10 +#define GSI_GSI_INST_RAM_n_INST_BYTE_1_BMSK 0xff00 +#define GSI_GSI_INST_RAM_n_INST_BYTE_1_SHFT 0x8 +#define GSI_GSI_INST_RAM_n_INST_BYTE_0_BMSK 0xff +#define GSI_GSI_INST_RAM_n_INST_BYTE_0_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f000 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_0_ELEMENT_SIZE_BMSK 0xff000000 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_ELEMENT_SIZE_SHFT 0x18 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_BMSK 0xf00000 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_SHFT 0x14 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_ERINDEX_BMSK 0x7c000 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_ERINDEX_SHFT 0xe +#define GSI_V2_5_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_MSB_BMSK 0x2000 +#define GSI_V2_5_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_MSB_SHFT 0xd +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHID_BMSK 0x1f00 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHID_SHFT 0x8 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_EE_BMSK 0xf0 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_EE_SHFT 0x4 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_DIR_BMSK 0x8 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_DIR_SHFT 0x3 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_BMSK 0x7 +#define GSI_EE_n_GSI_CH_k_CNTXT_0_CHTYPE_PROTOCOL_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f004 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_1_R_LENGTH_BMSK 0xffff +#define GSI_EE_n_GSI_CH_k_CNTXT_1_R_LENGTH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_2_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f008 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_3_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f00c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_4_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f010 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_4_READ_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_4_READ_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_5_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f014 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_5_READ_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_5_READ_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_6_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f018 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_6_WRITE_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_6_WRITE_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_CNTXT_7_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f01c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_CNTXT_7_WRITE_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_CNTXT_7_WRITE_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f054 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_RMSK 0xffff +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_MAXk 30 +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_MAXn 3 +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_READ_PTR_BMSK 0xffff +#define GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_READ_PTR_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f058 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_RMSK 0xffff +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_MAXk 30 +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_MAXn 3 +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_RE_INTR_DB_BMSK 0xffff +#define GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_RE_INTR_DB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_QOS_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001c05c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_QOS_RMSK 0x303 +#define GSI_EE_n_GSI_CH_k_QOS_MAXk 30 +#define GSI_EE_n_GSI_CH_k_QOS_MAXn 3 +#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_BMSK 0x400 +#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_SHFT 0xa +#define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK 0x200 +#define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT 0x9 +#define GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK 0x100 +#define GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_SHFT 0x8 +#define GSI_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_BMSK 0xf +#define GSI_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_SHFT 0x0 + +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f05c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_EMPTY_LVL_THRSHOLD_BMSK 0xff0000 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_EMPTY_LVL_THRSHOLD_SHFT 0x10 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_PREFETCH_MODE_BMSK 0x3c00 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_PREFETCH_MODE_SHFT 0xa +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK 0x200 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT 0x9 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK 0x100 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_SHFT 0x8 +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_BMSK 0xf +#define GSI_V2_5_EE_n_GSI_CH_k_QOS_WRR_WEIGHT_SHFT 0x0 + + +#define GSI_EE_n_GSI_CH_k_SCRATCH_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f060 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_SCRATCH_0_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_SCRATCH_0_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_SCRATCH_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f064 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_SCRATCH_1_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_SCRATCH_1_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_SCRATCH_2_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f068 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_SCRATCH_2_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_SCRATCH_2_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_SCRATCH_3_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f06c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010000 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_0_ELEMENT_SIZE_BMSK 0xff000000 +#define GSI_EE_n_EV_CH_k_CNTXT_0_ELEMENT_SIZE_SHFT 0x18 +#define GSI_EE_n_EV_CH_k_CNTXT_0_CHSTATE_BMSK 0xf00000 +#define GSI_EE_n_EV_CH_k_CNTXT_0_CHSTATE_SHFT 0x14 +#define GSI_EE_n_EV_CH_k_CNTXT_0_INTYPE_BMSK 0x10000 +#define GSI_EE_n_EV_CH_k_CNTXT_0_INTYPE_SHFT 0x10 +#define GSI_EE_n_EV_CH_k_CNTXT_0_EVCHID_BMSK 0xff00 +#define GSI_EE_n_EV_CH_k_CNTXT_0_EVCHID_SHFT 0x8 +#define GSI_EE_n_EV_CH_k_CNTXT_0_EE_BMSK 0xf0 +#define GSI_EE_n_EV_CH_k_CNTXT_0_EE_SHFT 0x4 +#define GSI_EE_n_EV_CH_k_CNTXT_0_CHTYPE_BMSK 0xf +#define GSI_EE_n_EV_CH_k_CNTXT_0_CHTYPE_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010004 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_1_R_LENGTH_BMSK 0xffff +#define GSI_EE_n_EV_CH_k_CNTXT_1_R_LENGTH_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_2_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010008 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_2_R_BASE_ADDR_LSBS_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_3_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001000c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_3_R_BASE_ADDR_MSBS_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_4_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010010 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_4_READ_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_4_READ_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_5_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010014 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_5_READ_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_5_READ_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_6_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010018 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_6_WRITE_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_6_WRITE_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_7_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001001c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_7_WRITE_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_7_WRITE_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_8_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010020 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MOD_CNT_BMSK 0xff000000 +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MOD_CNT_SHFT 0x18 +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODC_BMSK 0xff0000 +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODC_SHFT 0x10 +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODT_BMSK 0xffff +#define GSI_EE_n_EV_CH_k_CNTXT_8_INT_MODT_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_9_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010024 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_9_INTVEC_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_9_INTVEC_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_10_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010028 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_10_MSI_ADDR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_10_MSI_ADDR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_11_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001002c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_11_MSI_ADDR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_11_MSI_ADDR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_12_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010030 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_12_RP_UPDATE_ADDR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_12_RP_UPDATE_ADDR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_CNTXT_13_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010034 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_CNTXT_13_RP_UPDATE_ADDR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_CNTXT_13_RP_UPDATE_ADDR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_SCRATCH_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00010048 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_SCRATCH_0_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_SCRATCH_0_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_SCRATCH_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001004c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_EV_CH_k_SCRATCH_1_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_SCRATCH_1_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_DOORBELL_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00011000 + 0x4000 * (n) + 0x8 * (k)) +#define GSI_EE_n_GSI_CH_k_DOORBELL_0_WRITE_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_DOORBELL_0_WRITE_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_DOORBELL_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00011004 + 0x4000 * (n) + 0x8 * (k)) +#define GSI_EE_n_GSI_CH_k_DOORBELL_1_WRITE_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_DOORBELL_1_WRITE_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_DOORBELL_0_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00011100 + 0x4000 * (n) + 0x8 * (k)) +#define GSI_EE_n_EV_CH_k_DOORBELL_0_WRITE_PTR_LSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_DOORBELL_0_WRITE_PTR_LSB_SHFT 0x0 + +#define GSI_EE_n_EV_CH_k_DOORBELL_1_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00011104 + 0x4000 * (n) + 0x8 * (k)) +#define GSI_EE_n_EV_CH_k_DOORBELL_1_WRITE_PTR_MSB_BMSK 0xffffffff +#define GSI_EE_n_EV_CH_k_DOORBELL_1_WRITE_PTR_MSB_SHFT 0x0 + +#define GSI_EE_n_GSI_STATUS_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012000 + 0x4000 * (n)) +#define GSI_EE_n_GSI_STATUS_ENABLED_BMSK 0x1 +#define GSI_EE_n_GSI_STATUS_ENABLED_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_CMD_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012008 + 0x4000 * (n)) +#define GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK 0xff000000 +#define GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT 0x18 +#define GSI_EE_n_GSI_CH_CMD_CHID_BMSK 0xff +#define GSI_EE_n_GSI_CH_CMD_CHID_SHFT 0x0 + +#define GSI_EE_n_EV_CH_CMD_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012010 + 0x4000 * (n)) +#define GSI_EE_n_EV_CH_CMD_OPCODE_BMSK 0xff000000 +#define GSI_EE_n_EV_CH_CMD_OPCODE_SHFT 0x18 +#define GSI_EE_n_EV_CH_CMD_CHID_BMSK 0xff +#define GSI_EE_n_EV_CH_CMD_CHID_SHFT 0x0 + +#define GSI_EE_n_GSI_EE_GENERIC_CMD_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012018 + 0x4000 * (n)) +#define GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_BMSK 0x1f +#define GSI_EE_n_GSI_EE_GENERIC_CMD_OPCODE_SHFT 0x0 +#define GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_BMSK 0x3e0 +#define GSI_EE_n_GSI_EE_GENERIC_CMD_VIRT_CHAN_IDX_SHFT 0x5 +#define GSI_EE_n_GSI_EE_GENERIC_CMD_EE_BMSK 0x3c00 +#define GSI_EE_n_GSI_EE_GENERIC_CMD_EE_SHFT 0xa + +#define GSI_V1_0_EE_n_GSI_HW_PARAM_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) +#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_SEC_GRP_BMSK 0x7c000000 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_SEC_GRP_SHFT 0x1a +#define GSI_V1_0_EE_n_GSI_HW_PARAM_USE_AXI_M_BMSK 0x2000000 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_USE_AXI_M_SHFT 0x19 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_CONF_ADDR_BUS_W_BMSK 0x1f00000 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_PERIPH_CONF_ADDR_BUS_W_SHFT 0x14 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_NUM_EES_BMSK 0xf0000 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_NUM_EES_SHFT 0x10 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_CH_NUM_BMSK 0xff00 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_CH_NUM_SHFT 0x8 +#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_EV_CH_NUM_BMSK 0xff +#define GSI_V1_0_EE_n_GSI_HW_PARAM_GSI_EV_CH_NUM_SHFT 0x0 + +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f038 + 0x4000 * (n)) +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_USE_AXI_M_BMSK 0x80000000 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_USE_AXI_M_SHFT 0x1f +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_SEC_GRP_BMSK 0x7c000000 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_SEC_GRP_SHFT 0x1a +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_CONF_ADDR_BUS_W_BMSK 0x3e00000 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_PERIPH_CONF_ADDR_BUS_W_SHFT 0x15 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_NUM_EES_BMSK 0x1f0000 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_NUM_EES_SHFT 0x10 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_CH_NUM_BMSK 0xff00 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_CH_NUM_SHFT 0x8 +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_EV_CH_NUM_BMSK 0xff +#define GSI_V1_2_EE_n_GSI_HW_PARAM_0_GSI_EV_CH_NUM_SHFT 0x0 + +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_MAXn 2 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 +#define GSI_V1_3_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 + +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_MAXn 2 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2 +#define GSI_V2_0_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3 + +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001f040 + 0x4000 * (n)) +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_BMSK 0x8000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_SHFT 0xf +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_BMSK 0x4000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_SHFT 0xE +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_MAXn 2 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2 +#define GSI_V2_2_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3 + +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012040 + 0x4000 * (n)) +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_BMSK 0x8000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_INTER_EE_SHFT 0xf +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_BMSK 0x4000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_RD_WR_ENG_SHFT 0xE +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_RMSK 0x7fff +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_MAXn 2 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_BMSK 0x38000000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_IOVEC_SHFT 0x1b +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_BMSK 0x7F80000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_MAX_BURST_SHFT 0x13 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_BMSK 0x70000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_SDMA_N_INT_SHFT 0x10 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_BMSK 0x8000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_USE_SDMA_SHFT 0xf +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_BMSK 0x4000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_FULL_LOGIC_SHFT 0xe +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_BMSK 0x2000 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_CH_PEND_TRANSLATE_SHFT 0xd +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_BMSK 0x1f00 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_EV_PER_EE_SHFT 0x8 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_BMSK 0xf8 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_NUM_CH_PER_EE_SHFT 0x3 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_BMSK 0x7 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_SHFT 0x0 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_ONE_KB_FVAL 0x0 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_KB_FVAL 0x1 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_TWO_N_HALF_KB_FVAL 0x2 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_KB_FVAL 0x3 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_THREE_N_HALF_KB_FVAL 0x4 +#define GSI_V2_5_EE_n_GSI_HW_PARAM_2_GSI_IRAM_SIZE_FOUR_KB_FVAL 0x5 + +#define GSI_EE_n_GSI_SW_VERSION_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012044 + 0x4000 * (n)) +#define GSI_EE_n_GSI_SW_VERSION_MAJOR_BMSK 0xf0000000 +#define GSI_EE_n_GSI_SW_VERSION_MAJOR_SHFT 0x1c +#define GSI_EE_n_GSI_SW_VERSION_MINOR_BMSK 0xfff0000 +#define GSI_EE_n_GSI_SW_VERSION_MINOR_SHFT 0x10 +#define GSI_EE_n_GSI_SW_VERSION_STEP_BMSK 0xffff +#define GSI_EE_n_GSI_SW_VERSION_STEP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_TYPE_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012080 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_TYPE_IRQ_GENERAL_BMSK 0x40 +#define GSI_EE_n_CNTXT_TYPE_IRQ_GENERAL_SHFT 0x6 +#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_EV_CTRL_BMSK 0x20 +#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_EV_CTRL_SHFT 0x5 +#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_CH_CTRL_BMSK 0x10 +#define GSI_EE_n_CNTXT_TYPE_IRQ_INTER_EE_CH_CTRL_SHFT 0x4 +#define GSI_EE_n_CNTXT_TYPE_IRQ_IEOB_BMSK 0x8 +#define GSI_EE_n_CNTXT_TYPE_IRQ_IEOB_SHFT 0x3 +#define GSI_EE_n_CNTXT_TYPE_IRQ_GLOB_EE_BMSK 0x4 +#define GSI_EE_n_CNTXT_TYPE_IRQ_GLOB_EE_SHFT 0x2 +#define GSI_EE_n_CNTXT_TYPE_IRQ_EV_CTRL_BMSK 0x2 +#define GSI_EE_n_CNTXT_TYPE_IRQ_EV_CTRL_SHFT 0x1 +#define GSI_EE_n_CNTXT_TYPE_IRQ_CH_CTRL_BMSK 0x1 +#define GSI_EE_n_CNTXT_TYPE_IRQ_CH_CTRL_SHFT 0x0 + +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012088 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GENERAL_BMSK 0x40 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GENERAL_SHFT 0x6 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_EV_CTRL_BMSK 0x20 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_EV_CTRL_SHFT 0x5 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_CH_CTRL_BMSK 0x10 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_INTER_EE_CH_CTRL_SHFT 0x4 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_IEOB_BMSK 0x8 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_IEOB_SHFT 0x3 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GLOB_EE_BMSK 0x4 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_GLOB_EE_SHFT 0x2 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_EV_CTRL_BMSK 0x2 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_EV_CTRL_SHFT 0x1 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_CH_CTRL_BMSK 0x1 +#define GSI_EE_n_CNTXT_TYPE_IRQ_MSK_CH_CTRL_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012090 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012094 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012098 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_BMSK 0x1ffff +#define GSI_V2_5_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_BMSK 0x7fffff +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_SHFT 0x0 +#define GSI_V2_5_EE_n_CNTXT_SRC_GSI_CH_IRQ_MSK_GSI_CH_BIT_MAP_MSK_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0001209c + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfff +#define GSI_V2_5_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfffff +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 +#define GSI_V2_5_EE_n_CNTXT_SRC_EV_CH_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x000120a0 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x000120a4 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x000120b0 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x000120b8 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfff +#define GSI_V2_5_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_BMSK 0xfffff +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 +#define GSI_V2_5_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_EV_CH_BIT_MAP_MSK_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x000120c0 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012100 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT3_BMSK 0x8 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT3_SHFT 0x3 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT2_BMSK 0x4 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT2_SHFT 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT1_BMSK 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_GP_INT1_SHFT 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_ERROR_INT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_STTS_ERROR_INT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012108 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT3_BMSK 0x8 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT3_SHFT 0x3 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT2_BMSK 0x4 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT2_SHFT 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT1_BMSK 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_GP_INT1_SHFT 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_ERROR_INT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_EN_ERROR_INT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012110 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT3_BMSK 0x8 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT3_SHFT 0x3 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT2_BMSK 0x4 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT2_SHFT 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT1_BMSK 0x2 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_GP_INT1_SHFT 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_ERROR_INT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GLOB_IRQ_CLR_ERROR_INT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012118 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_MCS_STACK_OVRFLOW_BMSK 0x8 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_MCS_STACK_OVRFLOW_SHFT 0x3 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_CMD_FIFO_OVRFLOW_BMSK 0x4 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_CMD_FIFO_OVRFLOW_SHFT 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BUS_ERROR_BMSK 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BUS_ERROR_SHFT 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BREAK_POINT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_STTS_GSI_BREAK_POINT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012120 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_MCS_STACK_OVRFLOW_BMSK 0x8 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_MCS_STACK_OVRFLOW_SHFT 0x3 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_CMD_FIFO_OVRFLOW_BMSK 0x4 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_CMD_FIFO_OVRFLOW_SHFT 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BUS_ERROR_BMSK 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BUS_ERROR_SHFT 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BREAK_POINT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_EN_GSI_BREAK_POINT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012128 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_MCS_STACK_OVRFLOW_BMSK 0x8 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_MCS_STACK_OVRFLOW_SHFT 0x3 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_CMD_FIFO_OVRFLOW_BMSK 0x4 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_CMD_FIFO_OVRFLOW_SHFT 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BUS_ERROR_BMSK 0x2 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BUS_ERROR_SHFT 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BREAK_POINT_BMSK 0x1 +#define GSI_EE_n_CNTXT_GSI_IRQ_CLR_GSI_BREAK_POINT_SHFT 0x0 + +#define GSI_EE_n_CNTXT_INTSET_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012180 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_INTSET_INTYPE_BMSK 0x1 +#define GSI_EE_n_CNTXT_INTSET_INTYPE_SHFT 0x0 + +#define GSI_EE_n_ERROR_LOG_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012200 + 0x4000 * (n)) +#define GSI_EE_n_ERROR_LOG_TODO_BMSK 0xffffffff +#define GSI_EE_n_ERROR_LOG_TODO_SHFT 0x0 + +#define GSI_EE_n_ERROR_LOG_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012210 + 0x4000 * (n)) +#define GSI_EE_n_ERROR_LOG_CLR_TODO_BMSK 0xffffffff +#define GSI_EE_n_ERROR_LOG_CLR_TODO_SHFT 0x0 + +#define GSI_EE_n_CNTXT_SCRATCH_0_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00012400 + 0x4000 * (n)) +#define GSI_EE_n_CNTXT_SCRATCH_0_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_CNTXT_SCRATCH_0_SCRATCH_SHFT 0x0 + +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000c018 + 0x1000 * (n)) +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_GSI_CH_BIT_MAP_SHFT 0x0 + +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000c01c + 0x1000 * (n)) +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000c028 + 0x1000 * (n)) +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_GSI_CH_BIT_MAP_SHFT 0x0 + +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_OFFS(n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000c02c + 0x1000 * (n)) +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_BMSK 0xffffffff +#define GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_EV_CH_BIT_MAP_SHFT 0x0 + +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x00003800 + 0x80 * (n) + 0x4 * (k)) +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_VALID_BMSK 0x20 +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_VALID_SHFT 0x5 +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_PHY_CH_BMSK 0x1f +#define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_PHY_CH_SHFT 0x0 + +#endif /* __GSI_REG_V2_H__ */ -- GitLab From 4203378101c91862dfe59fd3adba954e52274661 Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Fri, 10 Aug 2018 22:54:18 +0530 Subject: [PATCH 0749/1001] power: qpnp-qg: Update the property to force-recharge RECHARGE_SOC psy property is no more used to force a recharge. Use the FORCE_RECHARGE property. Change-Id: I417d46cc07f455792906a18f4b6dc8e5ca8ca3db Signed-off-by: Anirudh Ghayal --- drivers/power/supply/qcom/qpnp-qg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 4d6101f97993..47818ca011fe 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -1890,7 +1890,7 @@ static int qg_charge_full_update(struct qpnp_qg *chip) /* Force recharge */ prop.intval = 0; rc = power_supply_set_property(chip->batt_psy, - POWER_SUPPLY_PROP_RECHARGE_SOC, &prop); + POWER_SUPPLY_PROP_FORCE_RECHARGE, &prop); if (rc < 0) pr_err("Failed to force recharge rc=%d\n", rc); else -- GitLab From 390ebfdec4162038524b130d7d20575baed40a82 Mon Sep 17 00:00:00 2001 From: Devi Sandeep Endluri V V Date: Mon, 13 Aug 2018 23:56:44 +0530 Subject: [PATCH 0750/1001] sdmsteppe: defconfig: Enable CONFIG_NETFILTER_XT_MATCH_BPF - Enable bpf match support so that iptable command from netd (userspace module) with bpf match option doesn't fail. - Enable Quota related defconfigs Change-Id: I5c146fdf2fb5f8966263774a858278c3626073a3 Signed-off-by: Devi Sandeep Endluri V V --- arch/arm64/configs/vendor/sdmsteppe-perf_defconfig | 3 +++ arch/arm64/configs/vendor/sdmsteppe_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig index 42a8d1d619d4..591a526a801c 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig @@ -140,6 +140,7 @@ CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y @@ -157,8 +158,10 @@ CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y diff --git a/arch/arm64/configs/vendor/sdmsteppe_defconfig b/arch/arm64/configs/vendor/sdmsteppe_defconfig index 4643b314fabf..69d5587c8e84 100644 --- a/arch/arm64/configs/vendor/sdmsteppe_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe_defconfig @@ -144,6 +144,7 @@ CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y @@ -161,8 +162,10 @@ CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y -- GitLab From 70856d4fba794f5bce47885984cefb4ff3c82094 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Wed, 8 Aug 2018 15:58:02 +0530 Subject: [PATCH 0751/1001] adsprpc: Initialize VA of fastrpc dynamic heap buffer to Zero As fastrpc dynamic heap buffer is allocated with DMA_ATTR_NO_KERNEL_MAPPING there is no virtual mapping for this buffer, so initialize VA with Zero. Change-Id: Id0fd62baa2a9a6510b909bdec69d02d0e4c8f9ab Acked-by: Chenna Kesava Raju Signed-off-by: Tharun Kumar Merugu --- drivers/char/adsprpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 1316dd5212b8..fd86e1ba09f6 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -790,7 +790,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, goto bail; map->phys = (uintptr_t)region_phys; map->size = len; - map->va = (uintptr_t)region_vaddr; + map->va = 0; } else if (mflags == FASTRPC_DMAHANDLE_NOMAP) { VERIFY(err, !IS_ERR_OR_NULL(map->buf = dma_buf_get(fd))); if (err) -- GitLab From c99d68ba6d3740df382c995ec203626eb32c4d92 Mon Sep 17 00:00:00 2001 From: Yuan Zhao Date: Tue, 14 Aug 2018 15:04:20 +0800 Subject: [PATCH 0752/1001] ARM: dts: msm: Add display panel support for QRD SM6150 QRD SM6150 uses this HX83112A panel, add this panel configuration. Change-Id: I1032084ad2c9c41859fe123a840ed29337591554 Signed-off-by: Yuan Zhao --- .../boot/dts/qcom/sm6150-qrd-overlay.dts | 4 ++++ arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts index 2854d1471c99..5a1ded43ba61 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts @@ -22,3 +22,7 @@ compatible = "qcom,sm6150-qrd", "qcom,sm6150", "qcom,qrd"; qcom,board-id = <11 0>; }; + +&dsi_hx83112a_truly_vid_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi index 893c4f96e6d1..63355b0fc6e8 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi @@ -12,10 +12,20 @@ #include "sm6150-thermal-overlay.dtsi" #include +#include "sm6150-sde-display.dtsi" &soc { }; +&pm6150l_wled { + qcom,string-cfg= <3>; + status = "ok"; +}; + +&pm6150l_lcdb { + status = "ok"; +}; + &ufsphy_mem { compatible = "qcom,ufs-phy-qmp-v3-660"; @@ -59,3 +69,12 @@ qcom,step-charging-enable; qcom,sw-jeita-enable; }; + +&dsi_hx83112a_truly_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 90 0>; + qcom,platform-reset-gpio = <&tlmm 91 0>; +}; -- GitLab From 7e0837e767ab3202d997e6628f0eef5dd1b1ff81 Mon Sep 17 00:00:00 2001 From: Vatsal Bucha Date: Tue, 14 Aug 2018 00:25:36 +0530 Subject: [PATCH 0753/1001] ARM: dts: msm: Fix label names for sm6150 wcd Correct sequence of inclusion of dtsi files and fix label names for sm6150 wcd934x. Change-Id: I71af78e90c105113475578408e66f48ccfef5b24 Signed-off-by: Vatsal Bucha --- arch/arm64/boot/dts/qcom/pm6150.dtsi | 2 +- .../boot/dts/qcom/sm6150-audio-overlay.dtsi | 17 +++++++++-------- arch/arm64/boot/dts/qcom/sm6150-audio.dtsi | 2 +- .../qcom/sm6150-ext-codec-audio-overlay.dtsi | 4 ++-- .../boot/dts/qcom/sm6150-external-codec-idp.dts | 2 ++ 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/pm6150.dtsi b/arch/arm64/boot/dts/qcom/pm6150.dtsi index 45fdc3687f4c..bf4e90043c63 100644 --- a/arch/arm64/boot/dts/qcom/pm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/pm6150.dtsi @@ -476,7 +476,7 @@ clocks = <&clock_rpmh RPMH_CXO_CLK>; clock-names = "xo"; assigned-clocks = <&pm6150_clkdiv 1>; - assigned-clock-rates = <9600000>; + assigned-clock-rates = <19200000>; }; pm6150_gpios: pinctrl@c000 { diff --git a/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi index 8c4d761bfc59..5e171c008a4d 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi @@ -81,13 +81,13 @@ qcom,audio-routing = "AMIC2", "MIC BIAS2", "MIC BIAS2", "Analog Mic2", - "DMIC0", "MIC BIAS1", + "TX DMIC0", "MIC BIAS1", "MIC BIAS1", "Digital Mic0", - "DMIC1", "MIC BIAS1", + "TX DMIC1", "MIC BIAS1", "MIC BIAS1", "Digital Mic1", - "DMIC2", "MIC BIAS3", + "TX DMIC2", "MIC BIAS3", "MIC BIAS3", "Digital Mic2", - "DMIC3", "MIC BIAS3", + "TX DMIC3", "MIC BIAS3", "MIC BIAS3", "Digital Mic3", "TX_AIF1 CAP", "VA_MCLK", "TX_AIF2 CAP", "VA_MCLK", @@ -147,9 +147,9 @@ qcom,cdc-vdd-mic-bias-current = <25000>; qcom,cdc-static-supplies = "cdc-vdd-ldo-rxtx", - "cdc-vddpx-1"; - qcom,cdc-on-demand-supplies = "cdc-vdd-buck", - "cdc-vdd-mic-bias"; + "cdc-vddpx-1", + "cdc-vdd-buck", + "cdc-vdd-mic-bias"; }; cdc_dmic01_gpios: cdc_dmic01_pinctrl { @@ -236,7 +236,7 @@ qcom,lpi-gpios; }; - qcom,wcd-dsp-glink { + tavil_glink: qcom,wcd-dsp-glink { status = "disabled"; compatible = "qcom,wcd-dsp-glink"; qcom,wdsp-channels = "g_glink_ctrl", @@ -312,6 +312,7 @@ clock_audio: audio_ext_clk { status = "disabled"; + qcom,codec-ext-clk-src = <0>; compatible = "qcom,audio-ref-clk"; pinctrl-names = "active", "sleep"; pinctrl-0 = <&wcd934x_mclk_default>; diff --git a/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi b/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi index 625b5531be48..60b61ee71905 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi @@ -125,7 +125,7 @@ &slim_aud { status = "disabled"; - msm_dai_slim { + dai_slim: msm_dai_slim { status = "disabled"; compatible = "qcom,msm-dai-slim"; elemental-addr = [ff ff ff fe 17 02]; diff --git a/arch/arm64/boot/dts/qcom/sm6150-ext-codec-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm6150-ext-codec-audio-overlay.dtsi index 275faf437eb4..3e2ebda7bd64 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-ext-codec-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-ext-codec-audio-overlay.dtsi @@ -56,11 +56,11 @@ status = "okay"; }; -&wdsp_mgr { +&tavil_wdsp { status = "okay"; }; -&wdsp_glink { +&tavil_glink { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp.dts b/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp.dts index 4c852ccb490b..d86f77e2e1a7 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp.dts @@ -14,6 +14,8 @@ #include "sm6150.dtsi" #include "sm6150-idp.dtsi" +#include "sm6150-ext-codec-audio-overlay.dtsi" +#include "sm6150-external-codec.dtsi" / { model = "Qualcomm Technologies, Inc. SM6150 External Audio Codec IDP"; -- GitLab From e10f1282bd0e9cfba29f3af07aa24a69cff44874 Mon Sep 17 00:00:00 2001 From: shubham Date: Wed, 20 Jun 2018 17:37:06 +0530 Subject: [PATCH 0754/1001] msm: vidc: Register CVP node conditionally Conditional check is put to check if CVP node exists. Added a new API to remove redundant part in code. Unregistered CVP node in case of the cores_exceeded error. Change-Id: Ife58a748b71a35398b8eeac6782c8d4ad616f31d Signed-off-by: Shubham Gupta --- .../media/platform/msm/vidc/msm_v4l2_vidc.c | 124 ++++++++---------- 1 file changed, 53 insertions(+), 71 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c index 376f204815cc..e25689f79f36 100644 --- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c @@ -496,7 +496,34 @@ static const struct of_device_id msm_vidc_dt_match[] = { {.compatible = "qcom,msm-vidc,mem-cdsp"}, {} }; +static int msm_vidc_register_video_device(enum session_type sess_type, + int nr, struct msm_vidc_core *core, struct device *dev) +{ + int rc = 0; + core->vdev[sess_type].vdev.release = + msm_vidc_release_video_device; + core->vdev[sess_type].vdev.fops = &msm_v4l2_vidc_fops; + core->vdev[sess_type].vdev.ioctl_ops = &msm_v4l2_ioctl_ops; + core->vdev[sess_type].vdev.vfl_dir = VFL_DIR_M2M; + core->vdev[sess_type].type = sess_type; + core->vdev[sess_type].vdev.v4l2_dev = &core->v4l2_dev; + rc = video_register_device(&core->vdev[sess_type].vdev, + VFL_TYPE_GRABBER, nr); + if (rc) { + dprintk(VIDC_ERR, "Failed to register the video device\n"); + return rc; + } + video_set_drvdata(&core->vdev[sess_type].vdev, core); + dev = &core->vdev[sess_type].vdev.dev; + rc = device_create_file(dev, &dev_attr_link_name); + if (rc) { + dprintk(VIDC_ERR, "Failed to create video device file\n"); + video_unregister_device(&core->vdev[sess_type].vdev); + return rc; + } + return 0; +} static int msm_vidc_probe_vidc_device(struct platform_device *pdev) { int rc = 0; @@ -536,75 +563,29 @@ static int msm_vidc_probe_vidc_device(struct platform_device *pdev) } /* setup the decoder device */ - core->vdev[MSM_VIDC_DECODER].vdev.release = - msm_vidc_release_video_device; - core->vdev[MSM_VIDC_DECODER].vdev.fops = &msm_v4l2_vidc_fops; - core->vdev[MSM_VIDC_DECODER].vdev.ioctl_ops = &msm_v4l2_ioctl_ops; - core->vdev[MSM_VIDC_DECODER].vdev.vfl_dir = VFL_DIR_M2M; - core->vdev[MSM_VIDC_DECODER].type = MSM_VIDC_DECODER; - core->vdev[MSM_VIDC_DECODER].vdev.v4l2_dev = &core->v4l2_dev; - rc = video_register_device(&core->vdev[MSM_VIDC_DECODER].vdev, - VFL_TYPE_GRABBER, nr); + rc = msm_vidc_register_video_device(MSM_VIDC_DECODER, + nr, core, dev); if (rc) { - dprintk(VIDC_ERR, "Failed to register video decoder device"); - goto err_dec_register; - } - - video_set_drvdata(&core->vdev[MSM_VIDC_DECODER].vdev, core); - dev = &core->vdev[MSM_VIDC_DECODER].vdev.dev; - rc = device_create_file(dev, &dev_attr_link_name); - if (rc) { - dprintk(VIDC_ERR, - "Failed to create link name sysfs for decoder"); - goto err_dec_attr_link_name; + dprintk(VIDC_ERR, "Failed to register video decoder\n"); + goto err_dec; } /* setup the encoder device */ - core->vdev[MSM_VIDC_ENCODER].vdev.release = - msm_vidc_release_video_device; - core->vdev[MSM_VIDC_ENCODER].vdev.fops = &msm_v4l2_vidc_fops; - core->vdev[MSM_VIDC_ENCODER].vdev.ioctl_ops = &msm_v4l2_ioctl_ops; - core->vdev[MSM_VIDC_ENCODER].vdev.vfl_dir = VFL_DIR_M2M; - core->vdev[MSM_VIDC_ENCODER].type = MSM_VIDC_ENCODER; - core->vdev[MSM_VIDC_ENCODER].vdev.v4l2_dev = &core->v4l2_dev; - rc = video_register_device(&core->vdev[MSM_VIDC_ENCODER].vdev, - VFL_TYPE_GRABBER, nr + 1); + rc = msm_vidc_register_video_device(MSM_VIDC_ENCODER, + nr + 1, core, dev); if (rc) { - dprintk(VIDC_ERR, "Failed to register video encoder device"); - goto err_enc_register; - } - - video_set_drvdata(&core->vdev[MSM_VIDC_ENCODER].vdev, core); - dev = &core->vdev[MSM_VIDC_ENCODER].vdev.dev; - rc = device_create_file(dev, &dev_attr_link_name); - if (rc) { - dprintk(VIDC_ERR, - "Failed to create link name sysfs for encoder"); - goto err_enc_attr_link_name; + dprintk(VIDC_ERR, "Failed to register video encoder\n"); + goto err_enc; } /* setup the cvp device */ - core->vdev[MSM_VIDC_CVP].vdev.release = - msm_vidc_release_video_device; - core->vdev[MSM_VIDC_CVP].vdev.fops = &msm_v4l2_vidc_fops; - core->vdev[MSM_VIDC_CVP].vdev.ioctl_ops = &msm_v4l2_ioctl_ops; - core->vdev[MSM_VIDC_CVP].vdev.vfl_dir = VFL_DIR_M2M; - core->vdev[MSM_VIDC_CVP].type = MSM_VIDC_CVP; - core->vdev[MSM_VIDC_CVP].vdev.v4l2_dev = &core->v4l2_dev; - rc = video_register_device(&core->vdev[MSM_VIDC_CVP].vdev, - VFL_TYPE_GRABBER, nr + 2); - if (rc) { - dprintk(VIDC_ERR, "Failed to register video cvp device"); - goto err_cvp_register; - } - - video_set_drvdata(&core->vdev[MSM_VIDC_CVP].vdev, core); - dev = &core->vdev[MSM_VIDC_CVP].vdev.dev; - rc = device_create_file(dev, &dev_attr_link_name); - if (rc) { - dprintk(VIDC_ERR, - "Failed to create link name sysfs for cvp"); - goto err_cvp_attr_link_name; + if (core->resources.domain_cvp) { + rc = msm_vidc_register_video_device(MSM_VIDC_CVP, + nr + 2, core, dev); + if (rc) { + dprintk(VIDC_ERR, "Failed to register video CVP\n"); + goto err_cvp; + } } /* finish setting up the 'core' */ @@ -661,21 +642,20 @@ static int msm_vidc_probe_vidc_device(struct platform_device *pdev) err_fail_sub_device_probe: vidc_hfi_deinitialize(core->hfi_type, core->device); err_cores_exceeded: - device_remove_file(&core->vdev[MSM_VIDC_CVP].vdev.dev, + if (core->resources.domain_cvp) { + device_remove_file(&core->vdev[MSM_VIDC_CVP].vdev.dev, &dev_attr_link_name); -err_cvp_attr_link_name: - video_unregister_device(&core->vdev[MSM_VIDC_CVP].vdev); -err_cvp_register: + video_unregister_device(&core->vdev[MSM_VIDC_CVP].vdev); + } +err_cvp: device_remove_file(&core->vdev[MSM_VIDC_ENCODER].vdev.dev, &dev_attr_link_name); -err_enc_attr_link_name: video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev); -err_enc_register: +err_enc: device_remove_file(&core->vdev[MSM_VIDC_DECODER].vdev.dev, &dev_attr_link_name); -err_dec_attr_link_name: video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev); -err_dec_register: +err_dec: v4l2_device_unregister(&core->v4l2_dev); err_v4l2_register: sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group); @@ -745,9 +725,11 @@ static int msm_vidc_remove(struct platform_device *pdev) venus_boot_deinit(); vidc_hfi_deinitialize(core->hfi_type, core->device); - device_remove_file(&core->vdev[MSM_VIDC_CVP].vdev.dev, + if (core->resources.domain_cvp) { + device_remove_file(&core->vdev[MSM_VIDC_CVP].vdev.dev, &dev_attr_link_name); - video_unregister_device(&core->vdev[MSM_VIDC_CVP].vdev); + video_unregister_device(&core->vdev[MSM_VIDC_CVP].vdev); + } device_remove_file(&core->vdev[MSM_VIDC_ENCODER].vdev.dev, &dev_attr_link_name); video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev); -- GitLab From 4a1a5b55df8c1c5e39023defa8bcdccf9b64b8b7 Mon Sep 17 00:00:00 2001 From: Devi Sandeep Endluri V V Date: Tue, 14 Aug 2018 19:51:14 +0530 Subject: [PATCH 0755/1001] defconfig: msmsteppe: Enable VTI config for v4 and v6 Enable VTI to give userspace (netd) the ability to create and update virtual interfaces. CRs-Fixed: 2214527 Change-Id: I4f3da9bca47ff083cfdc06ea1d11f5d68b4cddfc Signed-off-by: Devi Sandeep Endluri V V --- arch/arm64/configs/vendor/sdmsteppe-perf_defconfig | 2 ++ arch/arm64/configs/vendor/sdmsteppe_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig index 42a8d1d619d4..ebcfe3aabc85 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig @@ -99,6 +99,7 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -110,6 +111,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y diff --git a/arch/arm64/configs/vendor/sdmsteppe_defconfig b/arch/arm64/configs/vendor/sdmsteppe_defconfig index 4643b314fabf..6b6c70123a02 100644 --- a/arch/arm64/configs/vendor/sdmsteppe_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe_defconfig @@ -103,6 +103,7 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -114,6 +115,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y -- GitLab From c1ba697dccabba9af973441ae260aae0f4c58bfb Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Tue, 31 Oct 2017 00:15:54 +0100 Subject: [PATCH 0756/1001] debugfs: defer debugfs_fsdata allocation to first usage Currently, __debugfs_create_file allocates one struct debugfs_fsdata instance for every file created. However, there are potentially many debugfs file around, most of which are never touched by userspace. Thus, defer the allocations to the first usage, i.e. to the first debugfs_file_get(). A dentry's ->d_fsdata starts out to point to the "real", user provided fops. After a debugfs_fsdata instance has been allocated (and the real fops pointer has been moved over into its ->real_fops member), ->d_fsdata is changed to point to it from then on. The two cases are distinguished by setting BIT(0) for the real fops case. struct debugfs_fsdata's foremost purpose is to track active users and to make debugfs_remove() block until they are done. Since no debugfs_fsdata instance means no active users, make debugfs_remove() return immediately in this case. Take care of possible races between debugfs_file_get() and debugfs_remove(): either debugfs_remove() must see a debugfs_fsdata instance and thus wait for possible active users or debugfs_file_get() must see a dead dentry and return immediately. Make a dentry's ->d_release(), i.e. debugfs_release_dentry(), check whether ->d_fsdata is actually a debugfs_fsdata instance before kfree()ing it. Similarly, make debugfs_real_fops() check whether ->d_fsdata is actually a debugfs_fsdata instance before returning it, otherwise emit a warning. The set of possible error codes returned from debugfs_file_get() has grown from -EIO to -EIO and -ENOMEM. Make open_proxy_open() and full_proxy_open() pass the -ENOMEM onwards to their callers. Change-Id: I22d1f399ced795620cb7a887407465293317d43f Signed-off-by: Nicolai Stange Signed-off-by: Greg Kroah-Hartman Git-commit: 7d39bc50c47b3f8ed0e1a9d671ecb9ec02f10a2d Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Raghavendra Rao Ananta --- fs/debugfs/file.c | 55 ++++++++++++++++++++++++++++++++++++------- fs/debugfs/inode.c | 36 +++++++++++++++------------- fs/debugfs/internal.h | 8 +++++++ 3 files changed, 73 insertions(+), 26 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index bc3549c95574..65872340e301 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -53,6 +53,15 @@ const struct file_operations *debugfs_real_fops(const struct file *filp) { struct debugfs_fsdata *fsd = F_DENTRY(filp)->d_fsdata; + if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT) { + /* + * Urgh, we've been called w/o a protecting + * debugfs_file_get(). + */ + WARN_ON(1); + return NULL; + } + return fsd->real_fops; } EXPORT_SYMBOL_GPL(debugfs_real_fops); @@ -74,9 +83,35 @@ EXPORT_SYMBOL_GPL(debugfs_real_fops); */ int debugfs_file_get(struct dentry *dentry) { - struct debugfs_fsdata *fsd = dentry->d_fsdata; + struct debugfs_fsdata *fsd; + void *d_fsd; + + d_fsd = READ_ONCE(dentry->d_fsdata); + if (!((unsigned long)d_fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)) { + fsd = d_fsd; + } else { + fsd = kmalloc(sizeof(*fsd), GFP_KERNEL); + if (!fsd) + return -ENOMEM; + + fsd->real_fops = (void *)((unsigned long)d_fsd & + ~DEBUGFS_FSDATA_IS_REAL_FOPS_BIT); + refcount_set(&fsd->active_users, 1); + init_completion(&fsd->active_users_drained); + if (cmpxchg(&dentry->d_fsdata, d_fsd, fsd) != d_fsd) { + kfree(fsd); + fsd = READ_ONCE(dentry->d_fsdata); + } + } - /* Avoid starvation of removers. */ + /* + * In case of a successful cmpxchg() above, this check is + * strictly necessary and must follow it, see the comment in + * __debugfs_remove_file(). + * OTOH, if the cmpxchg() hasn't been executed or wasn't + * successful, this serves the purpose of not starving + * removers. + */ if (d_unlinked(dentry)) return -EIO; @@ -98,7 +133,7 @@ EXPORT_SYMBOL_GPL(debugfs_file_get); */ void debugfs_file_put(struct dentry *dentry) { - struct debugfs_fsdata *fsd = dentry->d_fsdata; + struct debugfs_fsdata *fsd = READ_ONCE(dentry->d_fsdata); if (refcount_dec_and_test(&fsd->active_users)) complete(&fsd->active_users_drained); @@ -109,10 +144,11 @@ static int open_proxy_open(struct inode *inode, struct file *filp) { struct dentry *dentry = F_DENTRY(filp); const struct file_operations *real_fops = NULL; - int r = 0; + int r; - if (debugfs_file_get(dentry)) - return -ENOENT; + r = debugfs_file_get(dentry); + if (r) + return r == -EIO ? -ENOENT : r; real_fops = debugfs_real_fops(filp); real_fops = fops_get(real_fops); @@ -233,10 +269,11 @@ static int full_proxy_open(struct inode *inode, struct file *filp) struct dentry *dentry = F_DENTRY(filp); const struct file_operations *real_fops = NULL; struct file_operations *proxy_fops = NULL; - int r = 0; + int r; - if (debugfs_file_get(dentry)) - return -ENOENT; + r = debugfs_file_get(dentry); + if (r) + return r == -EIO ? -ENOENT : r; real_fops = debugfs_real_fops(filp); real_fops = fops_get(real_fops); diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index f587aded46b5..9dca4da059b3 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -184,7 +184,10 @@ static const struct super_operations debugfs_super_operations = { static void debugfs_release_dentry(struct dentry *dentry) { - kfree(dentry->d_fsdata); + void *fsd = dentry->d_fsdata; + + if (!((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)) + kfree(dentry->d_fsdata); } static struct vfsmount *debugfs_automount(struct path *path) @@ -344,35 +347,25 @@ static struct dentry *__debugfs_create_file(const char *name, umode_t mode, { struct dentry *dentry; struct inode *inode; - struct debugfs_fsdata *fsd; - - fsd = kmalloc(sizeof(*fsd), GFP_KERNEL); - if (!fsd) - return NULL; if (!(mode & S_IFMT)) mode |= S_IFREG; BUG_ON(!S_ISREG(mode)); dentry = start_creating(name, parent); - if (IS_ERR(dentry)) { - kfree(fsd); + if (IS_ERR(dentry)) return NULL; - } inode = debugfs_get_inode(dentry->d_sb); - if (unlikely(!inode)) { - kfree(fsd); + if (unlikely(!inode)) return failed_creating(dentry); - } inode->i_mode = mode; inode->i_private = data; inode->i_fop = proxy_fops; - fsd->real_fops = real_fops; - refcount_set(&fsd->active_users, 1); - dentry->d_fsdata = fsd; + dentry->d_fsdata = (void *)((unsigned long)real_fops | + DEBUGFS_FSDATA_IS_REAL_FOPS_BIT); d_instantiate(dentry, inode); fsnotify_create(d_inode(dentry->d_parent), dentry); @@ -635,8 +628,17 @@ static void __debugfs_remove_file(struct dentry *dentry, struct dentry *parent) simple_unlink(d_inode(parent), dentry); d_delete(dentry); - fsd = dentry->d_fsdata; - init_completion(&fsd->active_users_drained); + + /* + * Paired with the closing smp_mb() implied by a successful + * cmpxchg() in debugfs_file_get(): either + * debugfs_file_get() must see a dead dentry or we must see a + * debugfs_fsdata instance at ->d_fsdata here (or both). + */ + smp_mb(); + fsd = READ_ONCE(dentry->d_fsdata); + if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT) + return; if (!refcount_dec_and_test(&fsd->active_users)) wait_for_completion(&fsd->active_users_drained); } diff --git a/fs/debugfs/internal.h b/fs/debugfs/internal.h index 0eea99432840..cb1e8139c398 100644 --- a/fs/debugfs/internal.h +++ b/fs/debugfs/internal.h @@ -25,4 +25,12 @@ struct debugfs_fsdata { struct completion active_users_drained; }; +/* + * A dentry's ->d_fsdata either points to the real fops or to a + * dynamically allocated debugfs_fsdata instance. + * In order to distinguish between these two cases, a real fops + * pointer gets its lowest bit set. + */ +#define DEBUGFS_FSDATA_IS_REAL_FOPS_BIT BIT(0) + #endif /* _DEBUGFS_INTERNAL_H_ */ -- GitLab From a804faa38b4ba3d049208667658de97936c13353 Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Tue, 14 Aug 2018 23:44:09 +0530 Subject: [PATCH 0757/1001] ARM: dts: msm: Update proper clock domain address for LMH DCVS for SM6150 Update correct OSM clock domain register address for LMH DCVS hardware to get aggregated throttling request for each cluster for SM6150. Change-Id: I383d235b1ebc4336303490fc3927374f00b50aa2 Signed-off-by: Manaf Meethalavalappu Pallikunhi --- arch/arm64/boot/dts/qcom/sm6150-thermal.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150-thermal.dtsi b/arch/arm64/boot/dts/qcom/sm6150-thermal.dtsi index 87c52ad023a3..bcc831e3c16d 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-thermal.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-thermal.dtsi @@ -21,7 +21,7 @@ interrupts = ; qcom,affinity = <0>; reg = <0x18358800 0x1000>, - <0x18321000 0x1000>; + <0x18323000 0x1000>; #thermal-sensor-cells = <0>; }; @@ -30,7 +30,7 @@ interrupts = ; qcom,affinity = <1>; reg = <0x18350800 0x1000>, - <0x18323000 0x1000>; + <0x18325800 0x1000>; #thermal-sensor-cells = <0>; }; }; -- GitLab From 2c4ddc1c006f980165b9a56a266393adba815b93 Mon Sep 17 00:00:00 2001 From: Vaibhav Deshu Venkatesh Date: Tue, 14 Aug 2018 11:43:56 -0700 Subject: [PATCH 0758/1001] msm: vidc: Use correct flag to propagate data corruption Use proper flags to propagate data corruption to userspace. CRs-Fixed: 2278442 Change-Id: Ia53b5b262a22edcdc1109ad393ca860a1851776a Signed-off-by: Vaibhav Deshu Venkatesh --- drivers/media/platform/msm/vidc/msm_vidc_common.c | 4 ++-- include/uapi/linux/videodev2.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index cbfeea486d65..55ae2a8c61e2 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -2501,7 +2501,7 @@ static void handle_ebd(enum hal_command_response cmd, void *data) } if (empty_buf_done->status == VIDC_ERR_BITSTREAM_ERR) { dprintk(VIDC_INFO, "Failed : Corrupted input stream\n"); - mbuf->vvb.flags |= V4L2_QCOM_BUF_DATA_CORRUPT; + mbuf->vvb.flags |= V4L2_BUF_FLAG_DATA_CORRUPT; } if (empty_buf_done->flags & HAL_BUFFERFLAG_SYNCFRAME) mbuf->vvb.flags |= V4L2_BUF_FLAG_KEYFRAME; @@ -2681,7 +2681,7 @@ static void handle_fbd(enum hal_command_response cmd, void *data) if (fill_buf_done->flags1 & HAL_BUFFERFLAG_SYNCFRAME) mbuf->vvb.flags |= V4L2_BUF_FLAG_KEYFRAME; if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DATACORRUPT) - mbuf->vvb.flags |= V4L2_QCOM_BUF_DATA_CORRUPT; + mbuf->vvb.flags |= V4L2_BUF_FLAG_DATA_CORRUPT; switch (fill_buf_done->picture_type) { case HAL_PICTURE_IDR: case HAL_PICTURE_I: diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index f7de29626600..fe37ad3ab1b0 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1054,6 +1054,7 @@ struct v4l2_buffer { /* Vendor extensions */ #define V4L2_QCOM_BUF_FLAG_CODECCONFIG 0x00020000 #define V4L2_QCOM_BUF_DATA_CORRUPT 0x00400000 +#define V4L2_BUF_FLAG_DATA_CORRUPT 0x00400000 #define V4L2_QCOM_BUF_INPUT_UNSUPPORTED 0x01000000 #define V4L2_QCOM_BUF_FLAG_EOS 0x02000000 #define V4L2_QCOM_BUF_FLAG_READONLY 0x04000000 -- GitLab From dc1331373599fd04265129264f96502e1a723940 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Tue, 14 Aug 2018 11:50:23 -0700 Subject: [PATCH 0759/1001] defconfig: arm64: Enable USB Electrical and Link test support on sm8150 Enable EHSET Test fixture driver to perform the high speed electrical testing procedure for USB-IF compliance. Also enable the Link Layer Test driver to allow for SuperSpeed link layer testing. Change-Id: I46f205326b0d680bc9d885bc0121445c527c907f Signed-off-by: Jack Pham --- arch/arm64/configs/vendor/sm8150-perf_defconfig | 2 ++ arch/arm64/configs/vendor/sm8150_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm64/configs/vendor/sm8150-perf_defconfig b/arch/arm64/configs/vendor/sm8150-perf_defconfig index 1947d8da3553..19cc87fda4ea 100644 --- a/arch/arm64/configs/vendor/sm8150-perf_defconfig +++ b/arch/arm64/configs/vendor/sm8150-perf_defconfig @@ -424,6 +424,8 @@ CONFIG_USB_DWC3=y CONFIG_USB_DWC3_MSM=y CONFIG_USB_ISP1760=y CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y CONFIG_USB_REDRIVER_NB7VPQ904M=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_QCOM_EMU_PHY=y diff --git a/arch/arm64/configs/vendor/sm8150_defconfig b/arch/arm64/configs/vendor/sm8150_defconfig index 6efc451579e7..0aa1fbe9b52d 100644 --- a/arch/arm64/configs/vendor/sm8150_defconfig +++ b/arch/arm64/configs/vendor/sm8150_defconfig @@ -441,6 +441,8 @@ CONFIG_USB_DWC3=y CONFIG_USB_DWC3_MSM=y CONFIG_USB_ISP1760=y CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y CONFIG_USB_REDRIVER_NB7VPQ904M=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_QCOM_EMU_PHY=y -- GitLab From 8656384f67f8b8b9ebdd097a1acec94d06c3a7ac Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Thu, 20 Jun 2013 13:31:37 -0700 Subject: [PATCH 0760/1001] usb: xhci: Add support for SINGLE_STEP_SET_FEATURE test of EHSET The Embedded High-speed Host Electrical Test (EHSET) procedure defines the SINGLE_STEP_SET_FEATURE test for an embedded USB Host port. Upon activating this test mode, the SETUP stage of a GetDescriptor request is sent and followed by a delay of 15 seconds before finishing with the DATA and STATUS stages. The idea is that this delay will give the test operator sufficient time to configure the oscilloscope to perform a measurement of the response time delay between the latter two stages. This test is not implemented by the EHCI/xHCI host controller itself but can be implemented in software. Similar to commit 9841f37a1cca ("usb: ehci: Add support for SINGLE_STEP_SET_FEATURE test of EHSET"), this patch adds such support to the xHCI driver. Change-Id: I638ca552f6dae735147378f3e6f6068e0003094b Signed-off-by: Jack Pham --- drivers/usb/host/xhci-hub.c | 154 ++++++++++++++++++++++++++++++++++- drivers/usb/host/xhci-ring.c | 144 ++++++++++++++++++++++++++++++++ drivers/usb/host/xhci.h | 4 + 3 files changed, 301 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index b540f00c85df..02b9054e9a41 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -20,7 +20,7 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - +#include #include #include @@ -1029,6 +1029,151 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, return status; } +static void xhci_single_step_completion(struct urb *urb) +{ + struct completion *done = urb->context; + + complete(done); +} + +/* + * Allocate a URB and initialize the various fields of it. + * This API is used by the single_step_set_feature test of + * EHSET where IN packet of the GetDescriptor request is + * sent 15secs after the SETUP packet. + * Return NULL if failed. + */ +static struct urb *xhci_request_single_step_set_feature_urb( + struct usb_device *udev, + void *dr, + void *buf, + struct completion *done) +{ + struct urb *urb; + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + struct usb_host_endpoint *ep; + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return NULL; + + urb->pipe = usb_rcvctrlpipe(udev, 0); + ep = udev->ep_in[usb_pipeendpoint(urb->pipe)]; + if (!ep) { + usb_free_urb(urb); + return NULL; + } + + /* + * Initialize the various URB fields as these are used by the HCD + * driver to queue it and as well as when completion happens. + */ + urb->ep = ep; + urb->dev = udev; + urb->setup_packet = dr; + urb->transfer_buffer = buf; + urb->transfer_buffer_length = USB_DT_DEVICE_SIZE; + urb->complete = xhci_single_step_completion; + urb->status = -EINPROGRESS; + urb->actual_length = 0; + urb->transfer_flags = URB_DIR_IN; + usb_get_urb(urb); + atomic_inc(&urb->use_count); + atomic_inc(&urb->dev->urbnum); + usb_hcd_map_urb_for_dma(hcd, urb, GFP_KERNEL); + urb->context = done; + return urb; +} + +/* + * This function implements the USB_PORT_FEAT_TEST handling of the + * SINGLE_STEP_SET_FEATURE test mode as defined in the Embedded + * High-Speed Electrical Test (EHSET) specification. This simply + * issues a GetDescriptor control transfer, with an inserted 15-second + * delay after the end of the SETUP stage and before the IN token of + * the DATA stage is set. The idea is that this gives the test operator + * enough time to configure the oscilloscope to perform a measurement + * of the response time between the DATA and ACK packets that follow. + */ +static int xhci_ehset_single_step_set_feature(struct usb_hcd *hcd, int port) +{ + int retval; + struct usb_ctrlrequest *dr; + struct urb *urb; + struct usb_device *udev; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct usb_device_descriptor *buf; + unsigned long flags; + DECLARE_COMPLETION_ONSTACK(done); + + /* Obtain udev of the rhub's child port */ + udev = usb_hub_find_child(hcd->self.root_hub, port); + if (!udev) { + xhci_err(xhci, "No device attached to the RootHub\n"); + return -ENODEV; + } + buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!dr) { + kfree(buf); + return -ENOMEM; + } + + /* Fill Setup packet for GetDescriptor */ + dr->bRequestType = USB_DIR_IN; + dr->bRequest = USB_REQ_GET_DESCRIPTOR; + dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8); + dr->wIndex = 0; + dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE); + urb = xhci_request_single_step_set_feature_urb(udev, dr, buf, &done); + if (!urb) { + retval = -ENOMEM; + goto cleanup; + } + + /* Now complete just the SETUP stage */ + spin_lock_irqsave(&xhci->lock, flags); + retval = xhci_submit_single_step_set_feature(hcd, urb, 1); + spin_unlock_irqrestore(&xhci->lock, flags); + if (retval) + goto out1; + + if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) { + usb_kill_urb(urb); + retval = -ETIMEDOUT; + xhci_err(xhci, "%s SETUP stage timed out on ep0\n", __func__); + goto out1; + } + + /* Sleep for 15 seconds; HC will send SOFs during this period */ + msleep(15 * 1000); + + /* Complete remaining DATA and status stages. Re-use same URB */ + urb->status = -EINPROGRESS; + usb_get_urb(urb); + atomic_inc(&urb->use_count); + atomic_inc(&urb->dev->urbnum); + + spin_lock_irqsave(&xhci->lock, flags); + retval = xhci_submit_single_step_set_feature(hcd, urb, 0); + spin_unlock_irqrestore(&xhci->lock, flags); + if (!retval && !wait_for_completion_timeout(&done, + msecs_to_jiffies(2000))) { + usb_kill_urb(urb); + retval = -ETIMEDOUT; + xhci_err(xhci, "%s IN stage timed out on ep0\n", __func__); + } +out1: + usb_free_urb(urb); +cleanup: + kfree(dr); + kfree(buf); + return retval; +} + int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { @@ -1321,6 +1466,13 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /* 4.19.6 Port Test Modes (USB2 Test Mode) */ if (hcd->speed != HCD_USB2) goto error; + if (test_mode == 6) { /* TEST_SINGLE_STEP_SET_FEATURE */ + spin_unlock_irqrestore(&xhci->lock, flags); + retval = xhci_ehset_single_step_set_feature(hcd, + wIndex); + spin_lock_irqsave(&xhci->lock, flags); + break; + } if (test_mode > TEST_FORCE_EN || test_mode < TEST_J) goto error; retval = xhci_enter_test_mode(xhci, test_mode, wIndex, diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 08b464b03ddc..5d76b81bdcbe 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3477,6 +3477,150 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, return 0; } +/* + * Variant of xhci_queue_ctrl_tx() used to implement EHSET + * SINGLE_STEP_SET_FEATURE test mode. It differs in that the control + * transfer is broken up so that the SETUP stage can happen and call + * the URB's completion handler before the DATA/STATUS stages are + * executed by the xHC hardware. This assumes the control transfer is a + * GetDescriptor, with a DATA stage in the IN direction, and an OUT + * STATUS stage. + * + * This function is called twice, usually with a 15-second delay in between. + * - with is_setup==true, the SETUP stage for the control request + * (GetDescriptor) is queued in the TRB ring and sent to HW immediately + * - with is_setup==false, the DATA and STATUS TRBs are queued and exceuted + * + * Caller must have locked xhci->lock + */ +int xhci_submit_single_step_set_feature(struct usb_hcd *hcd, struct urb *urb, + int is_setup) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct xhci_ring *ep_ring; + int num_trbs; + int ret; + unsigned int slot_id, ep_index; + struct usb_ctrlrequest *setup; + struct xhci_generic_trb *start_trb; + int start_cycle; + u32 field, length_field, remainder; + struct urb_priv *urb_priv; + struct xhci_td *td; + + ep_ring = xhci_urb_to_transfer_ring(xhci, urb); + if (!ep_ring) + return -EINVAL; + + /* Need buffer for data stage */ + if (urb->transfer_buffer_length <= 0) + return -EINVAL; + + /* + * Need to copy setup packet into setup TRB, so we can't use the setup + * DMA address. + */ + if (!urb->setup_packet) + return -EINVAL; + setup = (struct usb_ctrlrequest *) urb->setup_packet; + + slot_id = urb->dev->slot_id; + ep_index = xhci_get_endpoint_index(&urb->ep->desc); + + urb_priv = kzalloc(sizeof(struct urb_priv) + + sizeof(struct xhci_td *), GFP_ATOMIC); + if (!urb_priv) + return -ENOMEM; + + td = &urb_priv->td[0]; + urb_priv->num_tds = 1; + urb_priv->num_tds_done = 0; + urb->hcpriv = urb_priv; + + num_trbs = is_setup ? 1 : 2; + + ret = prepare_transfer(xhci, xhci->devs[slot_id], + ep_index, urb->stream_id, + num_trbs, urb, 0, GFP_ATOMIC); + if (ret < 0) { + kfree(urb_priv); + return ret; + } + + /* + * Don't give the first TRB to the hardware (by toggling the cycle bit) + * until we've finished creating all the other TRBs. The ring's cycle + * state may change as we enqueue the other TRBs, so save it too. + */ + start_trb = &ep_ring->enqueue->generic; + start_cycle = ep_ring->cycle_state; + + if (is_setup) { + /* Queue only the setup TRB */ + field = TRB_IDT | TRB_IOC | TRB_TYPE(TRB_SETUP); + if (start_cycle == 0) + field |= 0x1; + + /* xHCI 1.0/1.1 6.4.1.2.1: Transfer Type field */ + if (xhci->hci_version >= 0x100) { + if (setup->bRequestType & USB_DIR_IN) + field |= TRB_TX_TYPE(TRB_DATA_IN); + else + field |= TRB_TX_TYPE(TRB_DATA_OUT); + } + + /* Save the DMA address of the last TRB in the TD */ + td->last_trb = ep_ring->enqueue; + + queue_trb(xhci, ep_ring, false, + setup->bRequestType | setup->bRequest << 8 | + le16_to_cpu(setup->wValue) << 16, + le16_to_cpu(setup->wIndex) | + le16_to_cpu(setup->wLength) << 16, + TRB_LEN(8) | TRB_INTR_TARGET(0), + field); + } else { + /* Queue data TRB */ + field = TRB_ISP | TRB_TYPE(TRB_DATA); + if (start_cycle == 0) + field |= 0x1; + if (setup->bRequestType & USB_DIR_IN) + field |= TRB_DIR_IN; + + remainder = xhci_td_remainder(xhci, 0, + urb->transfer_buffer_length, + urb->transfer_buffer_length, + urb, 1); + + length_field = TRB_LEN(urb->transfer_buffer_length) | + TRB_TD_SIZE(remainder) | + TRB_INTR_TARGET(0); + + queue_trb(xhci, ep_ring, true, + lower_32_bits(urb->transfer_dma), + upper_32_bits(urb->transfer_dma), + length_field, + field); + + /* Save the DMA address of the last TRB in the TD */ + td->last_trb = ep_ring->enqueue; + + /* Queue status TRB */ + field = TRB_IOC | TRB_TYPE(TRB_STATUS); + if (!(setup->bRequestType & USB_DIR_IN)) + field |= TRB_DIR_IN; + + queue_trb(xhci, ep_ring, false, + 0, + 0, + TRB_INTR_TARGET(0), + field | ep_ring->cycle_state); + } + + giveback_first_trb(xhci, slot_id, ep_index, 0, start_cycle, start_trb); + return 0; +} + /* * The transfer burst count field of the isochronous TRB defines the number of * bursts that are required to move all packets in this TD. Only SuperSpeed diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index f4e046001a26..c068371c106f 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2589,4 +2589,8 @@ static inline const char *xhci_decode_ep_context(u32 info, u32 info2, u64 deq, return str; } +/* EHSET */ +int xhci_submit_single_step_set_feature(struct usb_hcd *hcd, struct urb *urb, + int is_setup); + #endif /* __LINUX_XHCI_HCD_H */ -- GitLab From c90727620e85f93d4977c55a7efc84de5aeb543e Mon Sep 17 00:00:00 2001 From: Vaibhav Deshu Venkatesh Date: Tue, 14 Aug 2018 12:24:13 -0700 Subject: [PATCH 0761/1001] msm: vidc: Remove duplicate flag Currently we have duplicate flags to propagate data corruption. Remove the duplicate flag. CRs-Fixed: 2278442 Change-Id: Ief89f88590f04d33e6371b7b31c45c77f519246f Signed-off-by: Vaibhav Deshu Venkatesh --- include/uapi/linux/videodev2.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index fe37ad3ab1b0..f4f6d8423ae3 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1053,7 +1053,6 @@ struct v4l2_buffer { #define V4L2_BUF_FLAG_LAST 0x00100000 /* Vendor extensions */ #define V4L2_QCOM_BUF_FLAG_CODECCONFIG 0x00020000 -#define V4L2_QCOM_BUF_DATA_CORRUPT 0x00400000 #define V4L2_BUF_FLAG_DATA_CORRUPT 0x00400000 #define V4L2_QCOM_BUF_INPUT_UNSUPPORTED 0x01000000 #define V4L2_QCOM_BUF_FLAG_EOS 0x02000000 -- GitLab From 59e635fb51a2e1bc389fbd1663153be89ca69425 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Wed, 8 Aug 2018 15:00:06 +0530 Subject: [PATCH 0762/1001] sched: Improve the scheduler This change is for general scheduler improvement. Change-Id: Iea8e3a6f6b2d83a755b51674e08a1cadcc0247ba Signed-off-by: Pavankumar Kondeti --- kernel/sched/walt.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index dfc8b3252111..b1804c966a10 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -313,6 +313,11 @@ void clear_ed_task(struct task_struct *p, struct rq *rq) rq->ed_task = NULL; } +static inline bool is_ed_task(struct task_struct *p, u64 wallclock) +{ + return (wallclock - p->last_wake_ts >= EARLY_DETECTION_DURATION); +} + bool early_detection_notify(struct rq *rq, u64 wallclock) { struct task_struct *p; @@ -327,7 +332,7 @@ bool early_detection_notify(struct rq *rq, u64 wallclock) if (!loop_max) break; - if (wallclock - p->last_wake_ts >= EARLY_DETECTION_DURATION) { + if (is_ed_task(p, wallclock)) { rq->ed_task = p; return 1; } @@ -828,6 +833,8 @@ void fixup_busy_time(struct task_struct *p, int new_cpu) if (p == src_rq->ed_task) { src_rq->ed_task = NULL; dest_rq->ed_task = p; + } else if (is_ed_task(p, wallclock)) { + dest_rq->ed_task = p; } done: -- GitLab From 0484d2d1a09e92694724fa7a49cb9eed046e3512 Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Thu, 2 Aug 2018 14:21:03 +0530 Subject: [PATCH 0763/1001] timers: Clear timer_base::must_forward_clk with timer_base::lock held timer_base::must_forward_clock is indicating that the base clock might be stale due to a long idle sleep. The forwarding of the base clock takes place in the timer softirq or when a timer is enqueued to a base which is idle. If the enqueue of timer to an idle base happens from a remote CPU, then the following race can happen: CPU0 CPU1 run_timer_softirq mod_timer base = lock_timer_base(timer); base->must_forward_clk = false if (base->must_forward_clk) forward(base); -> skipped enqueue_timer(base, timer, idx); -> idx is calculated high due to stale base unlock_timer_base(timer); base = lock_timer_base(timer); forward(base); The root cause is that timer_base::must_forward_clk is cleared outside the timer_base::lock held region, so the remote queuing CPU observes it as cleared, but the base clock is still stale. This can cause large granularity values for timers, i.e. the accuracy of the expiry time suffers. Prevent this by clearing the flag with timer_base::lock held, so that the forwarding takes place before the cleared flag is observable by a remote CPU. Change-Id: Ia1d8eb0807861a2a520ea2fee0df00daeeccb675 Signed-off-by: Gaurav Kohli Signed-off-by: Thomas Gleixner Cc: john.stultz@linaro.org Cc: sboyd@kernel.org Cc: linux-arm-msm@vger.kernel.org Link: https://lkml.kernel.org/r/1533199863-22748-1-git-send-email-gkohli@codeaurora.org Git-commit: 363e934d8811d799c88faffc5bfca782fd728334 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ Signed-off-by: Isaac J. Manjarres --- kernel/time/timer.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 55447b2a9560..8f9d95f9cb50 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1660,6 +1660,22 @@ static inline void __run_timers(struct timer_base *base) raw_spin_lock_irq(&base->lock); + /* + * timer_base::must_forward_clk must be cleared before running + * timers so that any timer functions that call mod_timer() will + * not try to forward the base. Idle tracking / clock forwarding + * logic is only used with BASE_STD timers. + * + * The must_forward_clk flag is cleared unconditionally also for + * the deferrable base. The deferrable base is not affected by idle + * tracking and never forwarded, so clearing the flag is a NOOP. + * + * The fact that the deferrable base is never forwarded can cause + * large variations in granularity for deferrable timers, but they + * can be deferred for long periods due to idle anyway. + */ + base->must_forward_clk = false; + while (time_after_eq(jiffies, base->clk)) { levels = collect_expired_timers(base, heads); @@ -1679,19 +1695,6 @@ static __latent_entropy void run_timer_softirq(struct softirq_action *h) { struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); - /* - * must_forward_clk must be cleared before running timers so that any - * timer functions that call mod_timer will not try to forward the - * base. idle trcking / clock forwarding logic is only used with - * BASE_STD timers. - * - * The deferrable base does not do idle tracking at all, so we do - * not forward it. This can result in very large variations in - * granularity for deferrable timers, but they can be deferred for - * long periods due to idle. - */ - base->must_forward_clk = false; - __run_timers(base); if (IS_ENABLED(CONFIG_NO_HZ_COMMON)) { __run_timers(this_cpu_ptr(&timer_bases[BASE_DEF])); -- GitLab From 4dfac456ce0bd6c5662f9be591597e6a2a791712 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Wed, 8 Aug 2018 15:22:52 +0530 Subject: [PATCH 0764/1001] sched: Improve the scheduler This change is for general scheduler improvement. Change-Id: Ib93a77c1d12574354213a37b1171a462b7cab685 Signed-off-by: Pavankumar Kondeti --- kernel/sched/core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index b08d42b6185b..1023a34598f9 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -783,6 +783,10 @@ static inline void dequeue_task(struct rq *rq, struct task_struct *p, int flags) sched_info_dequeued(rq, p); p->sched_class->dequeue_task(rq, p, flags); +#ifdef CONFIG_SCHED_WALT + if (p == rq->ed_task) + early_detection_notify(rq, ktime_get_ns()); +#endif trace_sched_enq_deq_task(p, 0, cpumask_bits(&p->cpus_allowed)[0]); } -- GitLab From 7a7f4931e481857b674a84fa56f380d60fb53864 Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Fri, 20 Jul 2018 17:33:32 -0700 Subject: [PATCH 0765/1001] defconfig: Enable /dev/mem virtual device support on sm8150 Enable support for the /dev/mem device for access to areas of physical memory. Change-Id: Ia9ce958978d2594310043d25d3c1d71be4d420c9 Signed-off-by: Isaac J. Manjarres --- arch/arm64/configs/vendor/sm8150_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/configs/vendor/sm8150_defconfig b/arch/arm64/configs/vendor/sm8150_defconfig index 6efc451579e7..51093fc2f419 100644 --- a/arch/arm64/configs/vendor/sm8150_defconfig +++ b/arch/arm64/configs/vendor/sm8150_defconfig @@ -325,7 +325,6 @@ CONFIG_INPUT_UINPUT=y # CONFIG_SERIO_SERPORT is not set # CONFIG_VT is not set # CONFIG_LEGACY_PTYS is not set -# CONFIG_DEVMEM is not set CONFIG_SERIAL_MSM_GENI=y CONFIG_SERIAL_MSM_GENI_CONSOLE=y CONFIG_SERIAL_DEV_BUS=y -- GitLab From 408f54d0f46513cb1416441eb21037e0235da46e Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Tue, 14 Aug 2018 14:26:26 -0700 Subject: [PATCH 0766/1001] defconfig: Disable panic when EDAC encounters single bit errors Disable kernel panic option when single bit errors are encountered by the EDAC framework, so that instead, recovery from these types of errors can be performed. Change-Id: I886c833dc9b37c9d061a219796c2a22ba41b0c30 Signed-off-by: Isaac J. Manjarres --- arch/arm64/configs/vendor/sm8150-perf_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/configs/vendor/sm8150-perf_defconfig b/arch/arm64/configs/vendor/sm8150-perf_defconfig index 1947d8da3553..6c033df559ed 100644 --- a/arch/arm64/configs/vendor/sm8150-perf_defconfig +++ b/arch/arm64/configs/vendor/sm8150-perf_defconfig @@ -469,7 +469,6 @@ CONFIG_LEDS_QTI_TRI_LED=y CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_EDAC=y CONFIG_EDAC_KRYO_ARM64=y -CONFIG_EDAC_KRYO_ARM64_PANIC_ON_CE=y CONFIG_EDAC_KRYO_ARM64_PANIC_ON_UE=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y -- GitLab From ab61c2e28cc99016ca42940edc73fda36b13569f Mon Sep 17 00:00:00 2001 From: Prabhakar Reddy Krishnappa Date: Wed, 8 Aug 2018 14:39:31 -0700 Subject: [PATCH 0767/1001] msm: vidc: Limit the max secure instances to 3 Limit the secure instances to 2 in platform data, but as per the design driver allows 3rd instance as well since the secure flags were updated later for the current instance. Hence total no of concurrent secure sessions support will be max-secure-instances + 1. Change-Id: Iaf91f321a40c590936babb703d58b06dd6eccc25 Signed-off-by: Prabhakar Reddy Krishnappa --- drivers/media/platform/msm/vidc/msm_vidc_platform.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c index e40622acba82..5d9e7698ebc6 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c @@ -192,7 +192,14 @@ static struct msm_vidc_common_data sm8150_common_data[] = { }, { .key = "qcom,max-secure-instances", - .value = 5, + .value = 2, /* + * As per design driver allows 3rd + * instance as well since the secure + * flags were updated later for the + * current instance. Hence total + * secure sessions would be + * max-secure-instances + 1. + */ }, { .key = "qcom,max-hw-load", -- GitLab From 3f94ee692b609d849ebbe4e14e5d38cd66d51e1e Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Mon, 13 Aug 2018 15:35:21 -0700 Subject: [PATCH 0768/1001] msm: ipa: handle modem ssr in imp When modem SSR happens IPA MHI Proxy module needs to be aware of that and perform required cleanup. Change-Id: I01e3bbbbba3f871fa7b49c1175acafed375ab7b4 Acked-by: Ady Abraham Signed-off-by: Skylar Chang --- drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c | 3 +-- drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.h | 7 +++++++ drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c index 86b235bf071f..9001b38cc5ec 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c @@ -923,9 +923,8 @@ static int imp_probe(struct platform_device *pdev) static int imp_remove(struct platform_device *pdev) { IMP_FUNC_ENTRY(); - mutex_lock(&imp_ctx->mutex); mhi_driver_unregister(&mhi_driver); - + mutex_lock(&imp_ctx->mutex); if (!imp_ctx->in_lpm) IPA_ACTIVE_CLIENTS_DEC_SPECIAL("IMP"); imp_ctx->in_lpm = false; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.h b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.h index 3a1d97d188c8..c0e5ef6b47e3 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.h @@ -24,6 +24,8 @@ struct ipa_mhi_alloc_channel_resp_msg_v01 *imp_handle_allocate_channel_req( int imp_handle_vote_req(bool vote); +void imp_handle_modem_shutdown(void); + #else /* CONFIG_IPA3_MHI_PROXY */ static inline void imp_handle_modem_ready(void) @@ -43,6 +45,11 @@ static inline int imp_handle_vote_req(bool vote) return -EPERM; } +static inline void imp_handle_modem_shutdown(void) +{ + +} + #endif /* CONFIG_IPA3_MHI_PROXY */ #endif /* __IMP_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index c835e8ea7bee..e62d7f89ad4f 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -2698,7 +2698,7 @@ static int ipa3_ssr_notifier_cb(struct notifier_block *this, ipa_stop_polling_stats(); if (atomic_read(&rmnet_ipa3_ctx->is_initialized)) platform_driver_unregister(&rmnet_ipa_driver); - + imp_handle_modem_shutdown(); if (atomic_read(&rmnet_ipa3_ctx->is_ssr) && ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) ipa3_q6_post_shutdown_cleanup(); -- GitLab From 13a8238356c07bc01b0a031912a7fef0b8b82ed7 Mon Sep 17 00:00:00 2001 From: Prabhakar Reddy Krishnappa Date: Wed, 8 Aug 2018 14:24:20 -0700 Subject: [PATCH 0769/1001] msm: vidc: skip cache operations for secure session For secure use-case, CPU can't access secure buffers. Hence there is no need to do cache operations. Change-Id: Ia9ea706efbba7efed17d930c3060ef402749c050 Signed-off-by: Prabhakar Reddy Krishnappa --- drivers/media/platform/msm/vidc/msm_smem.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c index 94a79ad672d3..0f2dd3af7949 100644 --- a/drivers/media/platform/msm/vidc/msm_smem.c +++ b/drivers/media/platform/msm/vidc/msm_smem.c @@ -522,12 +522,22 @@ int msm_smem_cache_operations(struct dma_buf *dbuf, enum smem_cache_ops cache_op, unsigned long offset, unsigned long size) { int rc = 0; + unsigned long flags = 0; if (!dbuf) { dprintk(VIDC_ERR, "%s: Invalid params\n", __func__); return -EINVAL; } + /* Return if buffer doesn't support caching */ + rc = dma_buf_get_flags(dbuf, &flags); + if (rc) { + dprintk(VIDC_ERR, "%s: dma_buf_get_flags failed, err %d\n", rc); + return rc; + } else if (!(flags & ION_FLAG_CACHED)) { + return rc; + } + switch (cache_op) { case SMEM_CACHE_CLEAN: case SMEM_CACHE_CLEAN_INVALIDATE: -- GitLab From d040128a869d6e8009b68b941255962d014287e8 Mon Sep 17 00:00:00 2001 From: Tingwei Zhang Date: Sat, 11 Aug 2018 14:03:30 +0800 Subject: [PATCH 0770/1001] ARM: dts: msm: Enable UART on QRD6150 Enable UART on QRD6150 device. It helps debug issues. Change-Id: Ie9edbfab0c3598465a2c02046342fb0db8833616 Signed-off-by: Tingwei Zhang Signed-off-by: Teng Fei Fan --- arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi index 63355b0fc6e8..cebedcbc864a 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi @@ -26,6 +26,10 @@ status = "ok"; }; +&qupv3_se0_2uart { + status = "ok"; +}; + &ufsphy_mem { compatible = "qcom,ufs-phy-qmp-v3-660"; -- GitLab From 6b2236d704439119dbb9b9ed61920916937daf18 Mon Sep 17 00:00:00 2001 From: Yuan Zhao Date: Fri, 10 Aug 2018 17:48:22 +0800 Subject: [PATCH 0771/1001] ARM: dts: msm: Modify the DP PHY power for QRD SM8150 DVT DVT device changes the power supply of DP PHY from L5A to L18A, so set the right config. Change-Id: I63ed0a68b15e7f2308c93c9e6333f139fcdbc2de Signed-off-by: Yuan Zhao --- arch/arm64/boot/dts/qcom/sm8150-qrd-dvt.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd-dvt.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd-dvt.dtsi index a737d8ff24fd..c525073ac2af 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd-dvt.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd-dvt.dtsi @@ -16,3 +16,14 @@ vdd-supply = <&pm8150_l18>; qcom,vdd-voltage-level = <0 912000 912000>; }; + +&sde_dp { + vdda-0p9-supply = <&pm8150_l18>; + qcom,phy-supply-entries { + qcom,phy-supply-entry@0 { + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <912000>; + }; + }; + +}; -- GitLab From 5d28fb16abd0a871bcce4b0590c65d91eef81144 Mon Sep 17 00:00:00 2001 From: Fei Mao Date: Mon, 13 Aug 2018 19:16:06 +0800 Subject: [PATCH 0772/1001] ARM: dts: msm: add Himax Touch panel support for QRD6150 Add Himax touch controller driver support for QRD6150. Change-Id: Iad48b938750188e6c2fb2462fdbcab66151be146 Signed-off-by: Fei Mao --- arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi index 63355b0fc6e8..166effdee064 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi @@ -70,6 +70,28 @@ qcom,sw-jeita-enable; }; +&qupv3_se1_i2c { + status = "okay"; + himax_ts@48 { + compatible = "himax,hxcommon"; + reg = <0x48>; + interrupt-parent = <&tlmm>; + interrupts = <125 0x2008>; + vdd-supply = <&pm6150_l10>; + avdd-supply = <&pm6150l_l7>; + 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>; + himax,panel-coords = <0 1080 0 2160>; + himax,display-coords = <0 1080 0 2160>; + himax,irq-gpio = <&tlmm 89 0x00>; + himax,rst-gpio = <&tlmm 88 0x00>; + report_type = <1>; + }; +}; + &dsi_hx83112a_truly_video { qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; -- GitLab From 6ccb33a2f4fa02299996ede4cb8bd87ec30f7bd7 Mon Sep 17 00:00:00 2001 From: Vevek Venkatesan Date: Wed, 1 Aug 2018 12:53:52 +0530 Subject: [PATCH 0773/1001] input: touchscreen: hxchipset: set rst pin to low during suspend Set the TS_RESET PIN to LOW to avoid leakage, during suspend. Change-Id: Ib2587a6282af2abe15b81ef2aded7e4a8f674723 Signed-off-by: Vevek Venkatesan --- drivers/input/touchscreen/hxchipset/himax_ic_incell_core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/hxchipset/himax_ic_incell_core.c b/drivers/input/touchscreen/hxchipset/himax_ic_incell_core.c index a95fb26a3bc2..b720826e59e2 100644 --- a/drivers/input/touchscreen/hxchipset/himax_ic_incell_core.c +++ b/drivers/input/touchscreen/hxchipset/himax_ic_incell_core.c @@ -464,7 +464,10 @@ static void himax_mcu_resume_ic_action(void) static void himax_mcu_suspend_ic_action(void) { - /* Nothing to do */ + /* Keep TS_RESET PIN to LOW, to avoid leakage during suspend */ +#ifdef HX_RST_PIN_FUNC + himax_rst_gpio_set(private_ts->rst_gpio, 0); +#endif } static void himax_mcu_power_on_init(void) -- GitLab From 16d940015605d09fdade1c38f2c7e0bd6aab1b20 Mon Sep 17 00:00:00 2001 From: Jitendra Sharma Date: Mon, 13 Aug 2018 21:09:24 +0530 Subject: [PATCH 0774/1001] soc: qcom: Update QMI response max buffer length Increase the size of response buffer to MAX_LENGTH, otherwise, decoding of QMI response could fail, if received response is of large size. Change-Id: I49bbfbca36707fde1293e72d38cf597e3c963269 Signed-off-by: Jitendra Sharma --- drivers/soc/qcom/service-locator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c index ecd53bd54ea9..faf3a2218836 100644 --- a/drivers/soc/qcom/service-locator.c +++ b/drivers/soc/qcom/service-locator.c @@ -267,7 +267,7 @@ static int init_service_locator(void) service_locator.connected = false; rc = qmi_handle_init(&service_locator.clnt_handle, - QMI_SERVREG_LOC_GET_DOMAIN_LIST_REQ_MSG_V01_MAX_MSG_LEN, + QMI_SERVREG_LOC_GET_DOMAIN_LIST_RESP_MSG_V01_MAX_MSG_LEN, &server_ops, NULL); if (rc < 0) { pr_err("Service locator QMI handle init failed rc:%d\n", rc); -- GitLab From 4ae8bdf7ccce90f71205772427b108a50d8a6fd6 Mon Sep 17 00:00:00 2001 From: Tingwei Zhang Date: Wed, 15 Aug 2018 18:38:30 +0800 Subject: [PATCH 0775/1001] coresight: tmc: Clear CacheCtrlBit2 and CacheCtrlBit3 TMC ETR should be set to non-cachable and bufferable. CacheCtrlBit2 and CacheCtrlBit3 should be set 0. Change-Id: I4d45fa1dccb4c4a33b725e5ecac80679902451a7 Signed-off-by: Tingwei Zhang --- drivers/hwtracing/coresight/coresight-tmc-etr.c | 3 ++- drivers/hwtracing/coresight/coresight-tmc.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 0df879000532..e002d8050068 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -447,7 +447,8 @@ void tmc_etr_enable_hw(struct tmc_drvdata *drvdata) } axictl = (axictl & - ~(TMC_AXICTL_CACHE_CTL_B0 | TMC_AXICTL_CACHE_CTL_B1)) | + ~(TMC_AXICTL_CACHE_CTL_B0 | TMC_AXICTL_CACHE_CTL_B1 | + TMC_AXICTL_CACHE_CTL_B2 | TMC_AXICTL_CACHE_CTL_B3)) | TMC_AXICTL_CACHE_CTL_B0; writel_relaxed(axictl, drvdata->base + TMC_AXICTL); tmc_write_dba(drvdata, drvdata->paddr); diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index ffe2fde6d193..05b730676f20 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -86,6 +86,8 @@ #define TMC_AXICTL_PROT_CTL_B1 BIT(1) #define TMC_AXICTL_CACHE_CTL_B0 BIT(2) #define TMC_AXICTL_CACHE_CTL_B1 BIT(3) +#define TMC_AXICTL_CACHE_CTL_B2 BIT(4) +#define TMC_AXICTL_CACHE_CTL_B3 BIT(5) #define TMC_AXICTL_SCT_GAT_MODE BIT(7) #define TMC_AXICTL_WR_BURST_16 0xF00 /* Write-back Read and Write-allocate */ -- GitLab From b1497a295f2d116405b59404a830da7d8a7f2fe3 Mon Sep 17 00:00:00 2001 From: Jitendra Sharma Date: Wed, 15 Aug 2018 16:25:42 +0530 Subject: [PATCH 0776/1001] ARM: dts: msm: Enable dload_type selection on SM6150 Add dload_type device tree node to allow support for selecting whether a full ramdump, minidump, or both should be collected from a target. Change-Id: Ie4b970f31ffdc2b1609ef32d8b973b4381edf037 Signed-off-by: Jitendra Sharma --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 4bfae896f4b0..9b1c155b86b5 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -1129,6 +1129,11 @@ reg = <0x65c 4>; }; + dload_type@1c { + compatible = "qcom,msm-imem-dload-type"; + reg = <0x1c 0x4>; + }; + boot_stats@6b0 { compatible = "qcom,msm-imem-boot_stats"; reg = <0x6b0 32>; -- GitLab From 8ad12ed3b1738be72035990e94de9d98d72d764a Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Mon, 30 Jul 2018 21:45:14 -0700 Subject: [PATCH 0777/1001] mhi: core: update MHI host support for WLAN FW execution environment MHI based WLAN devices sends WFW execution environment to indicate device up notification. Adding host support to handle such event. CRs-Fixed: 2289352 Change-Id: I4be4766e46495b542a965a33242c16b498cca1da Signed-off-by: Sujeev Dias --- Documentation/devicetree/bindings/bus/mhi.txt | 4 ++-- drivers/bus/mhi/core/mhi_boot.c | 4 ++-- drivers/bus/mhi/core/mhi_init.c | 5 ++-- drivers/bus/mhi/core/mhi_internal.h | 7 +++--- drivers/bus/mhi/core/mhi_main.c | 7 +++--- drivers/bus/mhi/core/mhi_pm.c | 24 ++++++++++++------- include/linux/mhi.h | 6 ++--- 7 files changed, 31 insertions(+), 26 deletions(-) diff --git a/Documentation/devicetree/bindings/bus/mhi.txt b/Documentation/devicetree/bindings/bus/mhi.txt index c6417eade80c..837c33cd0748 100644 --- a/Documentation/devicetree/bindings/bus/mhi.txt +++ b/Documentation/devicetree/bindings/bus/mhi.txt @@ -81,8 +81,8 @@ mhi channel node properties: BIT(0) = Channel supported in PBL EE BIT(1) = Channel supported in SBL EE BIT(2) = Channel supported in AMSS EE - BIT(3) = Channel supported in BHIe EE - BIT(4) = Channel supported in RDDM EE + BIT(3) = Channel supported in RDDM EE + BIT(4) = Channel supported in WFW EE BIT(5) = Channel supported in PTHRU EE BIT(6) = Channel supported in EDL EE diff --git a/drivers/bus/mhi/core/mhi_boot.c b/drivers/bus/mhi/core/mhi_boot.c index 334a09ff8932..8fa1d037c3df 100644 --- a/drivers/bus/mhi/core/mhi_boot.c +++ b/drivers/bus/mhi/core/mhi_boot.c @@ -556,9 +556,9 @@ void mhi_fw_load_worker(struct work_struct *work) goto error_read; } - /* wait for BHIE event */ + /* wait for SBL event */ ret = wait_event_timeout(mhi_cntrl->state_event, - mhi_cntrl->ee == MHI_EE_BHIE || + mhi_cntrl->ee == MHI_EE_SBL || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state), msecs_to_jiffies(mhi_cntrl->timeout_ms)); diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index 59592fb17cf8..76960cef1a70 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -27,8 +27,8 @@ const char * const mhi_ee_str[MHI_EE_MAX] = { [MHI_EE_PBL] = "PBL", [MHI_EE_SBL] = "SBL", [MHI_EE_AMSS] = "AMSS", - [MHI_EE_BHIE] = "BHIE", [MHI_EE_RDDM] = "RDDM", + [MHI_EE_WFW] = "WFW", [MHI_EE_PTHRU] = "PASS THRU", [MHI_EE_EDL] = "EDL", [MHI_EE_DISABLE_TRANSITION] = "DISABLE", @@ -38,8 +38,7 @@ const char * const mhi_state_tran_str[MHI_ST_TRANSITION_MAX] = { [MHI_ST_TRANSITION_PBL] = "PBL", [MHI_ST_TRANSITION_READY] = "READY", [MHI_ST_TRANSITION_SBL] = "SBL", - [MHI_ST_TRANSITION_AMSS] = "AMSS", - [MHI_ST_TRANSITION_BHIE] = "BHIE", + [MHI_ST_TRANSITION_MISSION_MODE] = "MISSION MODE", }; const char * const mhi_state_str[MHI_STATE_MAX] = { diff --git a/drivers/bus/mhi/core/mhi_internal.h b/drivers/bus/mhi/core/mhi_internal.h index c7ff92747e1a..aa1e043033fb 100644 --- a/drivers/bus/mhi/core/mhi_internal.h +++ b/drivers/bus/mhi/core/mhi_internal.h @@ -382,12 +382,13 @@ extern const char * const mhi_ee_str[MHI_EE_MAX]; #define MHI_IN_PBL(ee) (ee == MHI_EE_PBL || ee == MHI_EE_PTHRU || \ ee == MHI_EE_EDL) +#define MHI_IN_MISSION_MODE(ee) (ee == MHI_EE_AMSS || ee == MHI_EE_WFW) + enum MHI_ST_TRANSITION { MHI_ST_TRANSITION_PBL, MHI_ST_TRANSITION_READY, MHI_ST_TRANSITION_SBL, - MHI_ST_TRANSITION_AMSS, - MHI_ST_TRANSITION_BHIE, + MHI_ST_TRANSITION_MISSION_MODE, MHI_ST_TRANSITION_MAX, }; @@ -480,9 +481,9 @@ enum mhi_ch_ee_mask { MHI_CH_EE_PBL = BIT(MHI_EE_PBL), MHI_CH_EE_SBL = BIT(MHI_EE_SBL), MHI_CH_EE_AMSS = BIT(MHI_EE_AMSS), - MHI_CH_EE_BHIE = BIT(MHI_EE_BHIE), MHI_CH_EE_RDDM = BIT(MHI_EE_RDDM), MHI_CH_EE_PTHRU = BIT(MHI_EE_PTHRU), + MHI_CH_EE_WFW = BIT(MHI_EE_WFW), MHI_CH_EE_EDL = BIT(MHI_EE_EDL), }; diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index 0eef26eaeac7..c22b474678b2 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -613,7 +613,7 @@ static void mhi_create_time_sync_dev(struct mhi_controller *mhi_cntrl) if (!mhi_tsync || !mhi_tsync->db) return; - if (mhi_cntrl->ee != MHI_EE_AMSS) + if (!MHI_IN_MISSION_MODE(mhi_cntrl->ee)) return; mhi_dev = mhi_alloc_device(mhi_cntrl); @@ -973,15 +973,14 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, case MHI_EE_SBL: st = MHI_ST_TRANSITION_SBL; break; + case MHI_EE_WFW: case MHI_EE_AMSS: - st = MHI_ST_TRANSITION_AMSS; + st = MHI_ST_TRANSITION_MISSION_MODE; break; case MHI_EE_RDDM: mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data, MHI_CB_EE_RDDM); - /* fall thru to wake up the event */ - case MHI_EE_BHIE: write_lock_irq(&mhi_cntrl->pm_lock); mhi_cntrl->ee = event; write_unlock_irq(&mhi_cntrl->pm_lock); diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c index cbae02a8dc64..132fb705323f 100644 --- a/drivers/bus/mhi/core/mhi_pm.c +++ b/drivers/bus/mhi/core/mhi_pm.c @@ -319,8 +319,8 @@ int mhi_pm_m0_transition(struct mhi_controller *mhi_cntrl) read_lock_bh(&mhi_cntrl->pm_lock); mhi_cntrl->wake_get(mhi_cntrl, false); - /* ring all event rings and CMD ring only if we're in AMSS */ - if (mhi_cntrl->ee == MHI_EE_AMSS) { + /* ring all event rings and CMD ring only if we're in mission mode */ + if (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) { struct mhi_event *mhi_event = mhi_cntrl->mhi_event; struct mhi_cmd *mhi_cmd = &mhi_cntrl->mhi_cmd[PRIMARY_CMD_RING]; @@ -420,16 +420,21 @@ int mhi_pm_m3_transition(struct mhi_controller *mhi_cntrl) return 0; } -static int mhi_pm_amss_transition(struct mhi_controller *mhi_cntrl) +static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl) { int i; struct mhi_event *mhi_event; - MHI_LOG("Processing AMSS Transition\n"); + MHI_LOG("Processing Mission Mode Transition\n"); write_lock_irq(&mhi_cntrl->pm_lock); - mhi_cntrl->ee = MHI_EE_AMSS; + if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) + mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl); write_unlock_irq(&mhi_cntrl->pm_lock); + + if (!MHI_IN_MISSION_MODE(mhi_cntrl->ee)) + return -EIO; + wake_up_all(&mhi_cntrl->state_event); /* add elements to all HW event rings */ @@ -708,10 +713,11 @@ void mhi_pm_st_worker(struct work_struct *work) write_lock_irq(&mhi_cntrl->pm_lock); mhi_cntrl->ee = MHI_EE_SBL; write_unlock_irq(&mhi_cntrl->pm_lock); + wake_up_all(&mhi_cntrl->state_event); mhi_create_devices(mhi_cntrl); break; - case MHI_ST_TRANSITION_AMSS: - mhi_pm_amss_transition(mhi_cntrl); + case MHI_ST_TRANSITION_MISSION_MODE: + mhi_pm_mission_mode_transition(mhi_cntrl); break; case MHI_ST_TRANSITION_READY: mhi_ready_state_transition(mhi_cntrl); @@ -871,11 +877,11 @@ int mhi_sync_power_up(struct mhi_controller *mhi_cntrl) return ret; wait_event_timeout(mhi_cntrl->state_event, - mhi_cntrl->ee == MHI_EE_AMSS || + MHI_IN_MISSION_MODE(mhi_cntrl->ee) || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state), msecs_to_jiffies(mhi_cntrl->timeout_ms)); - return (mhi_cntrl->ee == MHI_EE_AMSS) ? 0 : -EIO; + return (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) ? 0 : -EIO; } EXPORT_SYMBOL(mhi_sync_power_up); diff --git a/include/linux/mhi.h b/include/linux/mhi.h index ced8dd1a769e..b6b313944e61 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -77,8 +77,8 @@ enum mhi_device_type { * @MHI_EE_PBL - device in PBL * @MHI_EE_SBL - device in SBL * @MHI_EE_AMSS - device in mission mode (firmware fully loaded) - * @MHI_EE_BHIE - device in special SBL that support BHI/e protocol * @MHI_EE_RDDM - device in ram dump collection mode + * @MHI_EE_WFW - device in WLAN firmware mode * @MHI_EE_PTHRU - device in PBL but configured in pass thru mode * @MHI_EE_EDL - device in emergency download mode */ @@ -86,8 +86,8 @@ enum mhi_ee { MHI_EE_PBL = 0x0, MHI_EE_SBL = 0x1, MHI_EE_AMSS = 0x2, - MHI_EE_BHIE = 0x3, - MHI_EE_RDDM = 0x4, + MHI_EE_RDDM = 0x3, + MHI_EE_WFW = 0x4, MHI_EE_PTHRU = 0x5, MHI_EE_EDL = 0x6, MHI_EE_MAX_SUPPORTED = MHI_EE_EDL, -- GitLab From 5e7a0625a706c0a43f7cedd2f1f25a31c0a2b054 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Tue, 7 Aug 2018 19:26:31 +0530 Subject: [PATCH 0778/1001] ARM: dts: msm: add smp2p and smmu ipa support for sm6150 Add smp2p entries for ipa-driver to support smp2p session with modem. Add SMMU entries for ipa-driver to support AP, WALN and uC SMMU mapping. Change-Id: Id3636c2acfd15ad3040e00e2a75ca4a95f0a5597 Acked-by: Ashok Vuyyuru Signed-off-by: Mohammed Javid --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 51 +++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index c0a9a4d58612..7a67b2963958 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -2106,6 +2106,18 @@ interrupt-controller; #interrupt-cells = <2>; }; + + smp2p_ipa_1_out: qcom,smp2p-ipa-1-out { + qcom,entry-name = "ipa"; + #qcom,smem-state-cells = <1>; + }; + + /* ipa - inbound entry from mss */ + smp2p_ipa_1_in: qcom,smp2p-ipa-1-in { + qcom,entry-name = "ipa"; + interrupt-controller; + #interrupt-cells = <2>; + }; }; qcom,smp2p-adsp { @@ -2342,7 +2354,7 @@ interrupts = <0 311 0>, <0 432 0>; interrupt-names = "ipa-irq", "gsi-irq"; qcom,ipa-hw-ver = <16>; /* IPA core version = IPAv4.2 */ - qcom,ipa-hw-mode = <1>; + qcom,ipa-hw-mode = <0>; qcom,ee = <0>; qcom,use-ipa-tethering-bridge; qcom,modem-cfg-emb-pipe-flt; @@ -2351,6 +2363,7 @@ qcom,ipa-fltrt-not-hashable; qcom,use-64-bit-dma-mask; qcom,arm-smmu; + qcom,smmu-fast-map; qcom,bandwidth-vote-for-ipa; qcom,msm-bus,name = "ipa"; qcom,msm-bus,num-cases = <5>; @@ -2384,6 +2397,42 @@ qcom,bus-vector-names = "MIN", "SVS2", "SVS", "NOMINAL", "TURBO"; + /* smp2p information */ + qcom,smp2p_map_ipa_1_out { + compatible = "qcom,smp2p-map-ipa-1-out"; + qcom,smem-states = <&smp2p_ipa_1_out 0>; + qcom,smem-state-names = "ipa-smp2p-out"; + }; + + qcom,smp2p_map_ipa_1_in { + compatible = "qcom,smp2p-map-ipa-1-in"; + interrupts-extended = <&smp2p_ipa_1_in 0 0>; + interrupt-names = "ipa-smp2p-in"; + }; + }; + + ipa_smmu_ap: ipa_smmu_ap { + compatible = "qcom,ipa-smmu-ap-cb"; + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x1520 0x0>; + qcom,iova-mapping = <0x20000000 0x40000000>; + /* modem tables in IMEM */ + qcom,additional-mapping = <0x146bd000 0x146bd000 0x2000>; + }; + + ipa_smmu_wlan: ipa_smmu_wlan { + compatible = "qcom,ipa-smmu-wlan-cb"; + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x1521 0x0>; + /* ipa-uc ram */ + qcom,additional-mapping = <0x1e60000 0x1e60000 0x80000>; + }; + + ipa_smmu_uc: ipa_smmu_uc { + compatible = "qcom,ipa-smmu-uc-cb"; + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x1522 0x0>; + qcom,iova-mapping = <0x40400000 0x1fc00000>; }; qcom,ipa_fws { -- GitLab From cab6a69281fd30eecb169df85d63d465cd81b75f Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Tue, 10 Oct 2017 14:13:12 -0700 Subject: [PATCH 0779/1001] iommu: arm-smmu: Remove unnecessary power_on call arm_smmu_map_sg() calls arm_smmu_unmap() on error, and the later already enables the clocks it requires. No other part of arm_smmu_map_sg() requires accessing hardware registers. Change-Id: Ifaee2224548097c9ebed6d616269ede8e24e4fd3 Signed-off-by: Patrick Daly Signed-off-by: Sudarshan Rajagopalan --- drivers/iommu/arm-smmu.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 4181c15cc938..4ec97c6af695 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -2706,10 +2706,6 @@ static size_t arm_smmu_map_sg(struct iommu_domain *domain, unsigned long iova, if (arm_smmu_is_slave_side_secure(smmu_domain)) return msm_secure_smmu_map_sg(domain, iova, sg, nents, prot); - ret = arm_smmu_domain_power_on(domain, smmu_domain->smmu); - if (ret) - return ret; - arm_smmu_prealloc_memory_sg(smmu_domain, sg, nents, &nonsecure_pool); arm_smmu_secure_domain_lock(smmu_domain); @@ -2754,7 +2750,6 @@ static size_t arm_smmu_map_sg(struct iommu_domain *domain, unsigned long iova, iova = __saved_iova_start; } arm_smmu_secure_domain_unlock(smmu_domain); - arm_smmu_domain_power_off(domain, smmu_domain->smmu); arm_smmu_release_prealloc_memory(smmu_domain, &nonsecure_pool); return iova - __saved_iova_start; } -- GitLab From 4606db83525e970f4d4bb52315f9fa8ee9b5e1e0 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Wed, 15 Aug 2018 12:29:34 -0700 Subject: [PATCH 0780/1001] backlight: qcom-spmi-wled: Change the default FSC for WLED5 to 25 mA As per the hardware recommendation, change the default setting for full scale current for WLED5 peripheral to 25 mA. Change-Id: Ibad2cd4ade504cc6d361e71e5263c09806365649 Signed-off-by: Subbaraman Narayanamurthy --- drivers/video/backlight/qcom-spmi-wled.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/backlight/qcom-spmi-wled.c b/drivers/video/backlight/qcom-spmi-wled.c index b5123b7c7c32..de6c31564f92 100644 --- a/drivers/video/backlight/qcom-spmi-wled.c +++ b/drivers/video/backlight/qcom-spmi-wled.c @@ -1330,7 +1330,7 @@ static const struct wled_config wled4_config_defaults = { static const struct wled_config wled5_config_defaults = { .boost_i_limit = 5, - .fs_current = 12, + .fs_current = 10, /* 25 mA */ .ovp = 4, .switch_freq = -EINVAL, .string_cfg = 0xf, -- GitLab From 7b0e551d5a5056fdd5d2ee30d00f0228d0c9521f Mon Sep 17 00:00:00 2001 From: Oleg Perelet Date: Fri, 10 Aug 2018 12:46:24 -0700 Subject: [PATCH 0781/1001] msm: kgsl: Place GMU in reset before entering slumber Force GMU CM3 core in reset before entering slumber state. Change-Id: I8d88242ef7f9f42993d9bd495bfa4686c8c14847 Signed-off-by: Oleg Perelet --- drivers/gpu/msm/adreno_a6xx_gmu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 6b50fe1756af..dc2f992dc71a 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -421,6 +421,10 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) if (test_bit(GMU_RSCC_SLEEP_SEQ_DONE, &device->gmu_core.flags)) return 0; + gmu_core_regwrite(device, A6XX_GMU_CM3_SYSRESET, 1); + /* Make sure M3 is in reset before going on */ + wmb(); + /* RSC sleep sequence is different on v1 */ if (adreno_is_a630v1(adreno_dev)) gmu_core_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1); @@ -922,10 +926,6 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, int ret; unsigned int chipid = 0; - gmu_core_regwrite(device, A6XX_GMU_CM3_SYSRESET, 1); - /* Make sure M3 is in reset before going on */ - wmb(); - switch (boot_state) { case GMU_COLD_BOOT: /* Turn on TCM retention */ -- GitLab From e1dd9f2a3c5bf7c2f09af6bcd0f62ca856f4d663 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Fri, 3 Aug 2018 15:27:34 -0700 Subject: [PATCH 0782/1001] sound: usb: Add QMI bye callback On unexpected SSRs, a del client notification may not be sent. In order to receive client removal notifications in this situation, usb should register for the bye callback. Perform client disconnect cleanup in the bye callback. Change-Id: Id99195994a828f80e8acff8c21d1cf69e9ad1e49 Signed-off-by: Chris Lew --- sound/usb/usb_audio_qmi_svc.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c index 9c3e49b12800..6254b5b84501 100644 --- a/sound/usb/usb_audio_qmi_svc.c +++ b/sound/usb/usb_audio_qmi_svc.c @@ -1184,6 +1184,25 @@ static void uaudio_qmi_disconnect_work(struct work_struct *w) } } +static void uaudio_qmi_bye_cb(struct qmi_handle *handle, unsigned int node) +{ + struct uaudio_qmi_svc *svc = uaudio_svc; + + pr_debug("%s: node:\n", __func__, node); + if (svc->uaudio_svc_hdl != handle) { + pr_err("%s: handle mismatch\n", __func__); + return; + } + + if (svc->client_connected && svc->client_sq.sq_node == node) { + queue_work(svc->uaudio_wq, &svc->qmi_disconnect_work); + svc->client_sq.sq_node = 0; + svc->client_sq.sq_port = 0; + svc->client_sq.sq_family = 0; + svc->client_connected = false; + } +} + static void uaudio_qmi_svc_disconnect_cb(struct qmi_handle *handle, unsigned int node, unsigned int port) { @@ -1206,6 +1225,7 @@ static void uaudio_qmi_svc_disconnect_cb(struct qmi_handle *handle, } static struct qmi_ops uaudio_svc_ops_options = { + .bye = uaudio_qmi_bye_cb, .del_client = uaudio_qmi_svc_disconnect_cb, }; -- GitLab From 37d6a3be2033dad43c9329cd01dfa2a4ce14e276 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Fri, 10 Aug 2018 15:43:15 -0600 Subject: [PATCH 0783/1001] soc: qcom: Fix recursive spinlock in rmnet TX context rtnl_lock() should not be called from TX context even if rtnl_trylock() is used since TX path may operate in softirq NET_TX context. This patch fixes the recursive spinlock which could occur with the following call stack. A new worker thread is spawned if the grant is 0. The bearer is also passed along to this work queue so that the exact queue operation is performed depending on the instantaneous limits rather than explicitly disabling the flow. The workqueue is also converted to type high priority. 000|arch_counter_get_cntvct(inline) -000|__delay(cycles = 19200) -001|__const_udelay(?) -002|msm_trigger_wdog_bite() -003|spin_dump(inline) -003|spin_bug(lock, msg) -004|debug_spin_lock_before(inline) -004|do_raw_spin_lock(lock) -005|raw_spin_lock(?) -006|__mutex_unlock_slowpath(?) -007|mutex_unlock(lock) -008|__rtnl_unlock() -009|__read_once_size(inline) -009|list_empty(inline) -009|netdev_run_todo() -010|rtnl_unlock() -011|dfc_qmi_burst_check(dev, qos, skb) -012|qmi_rmnet_burst_fc_check(dev, skb) -013|rmnet_vnd_start_xmit(skb, dev) -014|__netdev_start_xmit(inline) -014|netdev_start_xmit(inline) -014|xmit_one(inline) -014|dev_hard_start_xmit(first, dev, txq) -015|sch_direct_xmit(skb, q, dev, txq) -016|__qdisc_run(q) -017|__dev_xmit_skb(inline) -017|__dev_queue_xmit(skb, ?) -018|dev_queue_xmit(?) -019|neigh_direct_output(?, ?) -020|neigh_output(inline) -020|ip6_finish_output2(net, ?, skb) -021|ip6_finish_output(net, sk, skb) -022|NF_HOOK_COND(inline) -022|ip6_output(net, sk, skb) -023|dst_output(inline) -023|NF_HOOK(inline) -023|mld_sendpack(skb) -024|mld_ifc_timer_expire(data) -025|__read_once_size(inline) -025|static_key_count(inline) -025|static_key_false(inline) -025|trace_timer_expire_exit(inline) -025|call_timer_fn() -026|expire_timers(inline) -026|__run_timers(inline) -026|run_timer_softirq(?) -027|__read_once_size(inline) -027|static_key_count(inline) -027|static_key_false(inline) -027|trace_softirq_exit(inline) -027|__softirqentry_text_start() -028|do_softirq_own_stack(inline) -028|invoke_softirq(inline) -028|irq_exit() -029|set_irq_regs(inline) -029|__handle_domain_irq(domain, ?, lookup, regs) -030|gic_handle_irq() -031|el1_irq(asm) -->|exception -032|__mutex_unlock_slowpath(?) -033|mutex_unlock(lock) -034|__rtnl_unlock() -035|__read_once_size(inline) -035|list_empty(inline) -035|netdev_run_todo() -036|rtnl_unlock(inline) -036|rtnetlink_rcv_msg(sk, ?, extack) -037|netlink_rcv_skb(skb, cb) -038|rtnetlink_rcv(?) -039|netlink_unicast_kernel(inline) -039|netlink_unicast(ssk, skb, portid, ?) -040|netlink_sendmsg(?, msg, ?) -041|sock_sendmsg_nosec(inline) -041|sock_sendmsg(sock, msg) -042|SYSC_sendto(inline) -042|sys_sendto(?, buff, ?, flags, ?, ?) -043|el0_svc_naked(asm) -->|exception -044|NUX:0x759BCC4AAC(asm) ---|end of frame CRs-Fixed: 2292152 Change-Id: I340aa3989e085338cb768785f1f632c0a9ea11e0 Signed-off-by: Subash Abhinov Kasiviswanathan --- drivers/soc/qcom/dfc_qmi.c | 120 ++++++++++++++++++++++++++------- drivers/soc/qcom/qmi_rmnet.c | 13 ++-- drivers/soc/qcom/qmi_rmnet_i.h | 17 +++-- include/trace/events/dfc.h | 18 ++++- 4 files changed, 133 insertions(+), 35 deletions(-) diff --git a/drivers/soc/qcom/dfc_qmi.c b/drivers/soc/qcom/dfc_qmi.c index 9cfa7f71a008..0d8be8ff87ce 100644 --- a/drivers/soc/qcom/dfc_qmi.c +++ b/drivers/soc/qcom/dfc_qmi.c @@ -40,6 +40,14 @@ struct dfc_svc_ind { void *dfc_info; }; +struct dfc_burst_ind { + struct work_struct work; + struct net_device *dev; + struct qos_info *qos; + struct rmnet_bearer_map *bearer; + struct dfc_qmi_data *data; +}; + static void dfc_svc_init(struct work_struct *work); static void dfc_do_burst_flow_control(struct work_struct *work); @@ -660,6 +668,57 @@ static void dfc_do_burst_flow_control(struct work_struct *work) local_bh_enable(); } +static void dfc_bearer_limit_work(struct work_struct *work) +{ + struct dfc_burst_ind *dfc_ind = (struct dfc_burst_ind *)work; + struct rmnet_flow_map *itm; + struct list_head *p; + int qlen, fc; + + local_bh_disable(); + + /* enable transmit on device so that the other + * flows which transmit proceed normally. + * do it here under bh disabled so that the TX softirq + * may not run here + */ + netif_start_queue(dfc_ind->dev); + + while (!rtnl_trylock()) { + if (!dfc_ind->data->restart_state) { + cond_resched_softirq(); + } else { + kfree(dfc_ind); + local_bh_enable(); + return; + } + } + + fc = dfc_ind->bearer->grant_size ? 1 : 0; + /* if grant size is non zero here, we must have already + * got an updated grant. do nothing in that case + */ + if (fc) + goto done; + + list_for_each(p, &dfc_ind->qos->flow_head) { + itm = list_entry(p, struct rmnet_flow_map, list); + + if (itm->bearer_id == dfc_ind->bearer->bearer_id) { + qlen = tc_qdisc_flow_control(dfc_ind->dev, + itm->tcm_handle, fc); + trace_dfc_qmi_tc_limit(itm->bearer_id, itm->flow_id, + dfc_ind->bearer->grant_size, + qlen, itm->tcm_handle, fc); + } + } + +done: + kfree(dfc_ind); + rtnl_unlock(); + local_bh_enable(); +} + static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, struct qmi_txn *txn, const void *data) { @@ -780,7 +839,7 @@ int dfc_qmi_client_init(void *port, int index, struct qmi_info *qmi) data->index = index; data->restart_state = 0; - data->dfc_wq = create_singlethread_workqueue("dfc_wq"); + data->dfc_wq = alloc_workqueue("dfc_wq", WQ_HIGHPRI, 1); if (!data->dfc_wq) { pr_err("%s Could not create workqueue\n", __func__); goto err0; @@ -833,39 +892,54 @@ void dfc_qmi_client_exit(void *dfc_data) } void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, - struct sk_buff *skb) + struct sk_buff *skb, struct qmi_info *qmi) { struct rmnet_bearer_map *bearer; + struct dfc_burst_ind *dfc_ind; struct rmnet_flow_map *itm; + struct dfc_qmi_data *data; int ip_type; - if (!qos) - return; + ip_type = (ip_hdr(skb)->version == IP_VER_6) ? AF_INET6 : AF_INET; - if (!rtnl_trylock()) + itm = qmi_rmnet_get_flow_map(qos, skb->mark, ip_type); + if (!itm) return; - ip_type = (ip_hdr(skb)->version == IP_VER_6) ? AF_INET6 : AF_INET; + bearer = qmi_rmnet_get_bearer_map(qos, itm->bearer_id); + if (unlikely(!bearer)) + return; - itm = qmi_rmnet_get_flow_map(qos, skb->mark, ip_type); - if (itm) { - bearer = qmi_rmnet_get_bearer_map(qos, itm->bearer_id); - if (unlikely(!bearer)) { - rtnl_unlock(); - return; - } + trace_dfc_flow_check(bearer->bearer_id, skb->len, bearer->grant_size); - trace_dfc_flow_check(bearer->bearer_id, - skb->len, bearer->grant_size); + if (!bearer->grant_size) + return; - if (skb->len >= bearer->grant_size) { - bearer->grant_size = 0; - dfc_bearer_flow_ctl(dev, qos, bearer->bearer_id, - bearer->grant_size, 0); - } else { - bearer->grant_size -= skb->len; - } + if (skb->len < bearer->grant_size) { + bearer->grant_size -= skb->len; + return; } - rtnl_unlock(); + data = (struct dfc_qmi_data *)qmi_rmnet_has_dfc_client(qmi); + if (!data) + return; + + dfc_ind = kzalloc(sizeof(*dfc_ind), GFP_ATOMIC); + if (!dfc_ind) + return; + + INIT_WORK((struct work_struct *)dfc_ind, dfc_bearer_limit_work); + + dfc_ind->dev = dev; + dfc_ind->qos = qos; + dfc_ind->bearer = bearer; + dfc_ind->data = data; + + bearer->grant_size = 0; + + /* stop the flow in hope that the worker thread is + * immediately scheduled beyond this point of time + */ + netif_stop_queue(dev); + queue_work(data->dfc_wq, (struct work_struct *)dfc_ind); } diff --git a/drivers/soc/qcom/qmi_rmnet.c b/drivers/soc/qcom/qmi_rmnet.c index 2fa51bf85ed1..cb23b80c462d 100644 --- a/drivers/soc/qcom/qmi_rmnet.c +++ b/drivers/soc/qcom/qmi_rmnet.c @@ -75,20 +75,19 @@ static struct qmi_info *qmi_rmnet_qmi_init(void) return qmi_info; } -static inline int -qmi_rmnet_has_dfc_client(struct qmi_info *qmi) +void *qmi_rmnet_has_dfc_client(struct qmi_info *qmi) { int i; if (!qmi || !(qmi->flag & FLAG_DFC_MASK)) - return 0; + return NULL; for (i = 0; i < MAX_CLIENT_NUM; i++) { if (qmi->fc_info[i].dfc_client) - return 1; + return qmi->fc_info[i].dfc_client; } - return 0; + return NULL; } static inline int @@ -97,7 +96,7 @@ qmi_rmnet_has_client(struct qmi_info *qmi) if (qmi->wda_client) return 1; - return qmi_rmnet_has_dfc_client(qmi); + return qmi_rmnet_has_dfc_client(qmi) ? 1 : 0; } #ifdef CONFIG_QCOM_QMI_DFC @@ -528,7 +527,7 @@ void qmi_rmnet_burst_fc_check(struct net_device *dev, struct sk_buff *skb) if (!qmi || !qos) return; - dfc_qmi_burst_check(dev, qos, skb); + dfc_qmi_burst_check(dev, qos, skb, qmi); } EXPORT_SYMBOL(qmi_rmnet_burst_fc_check); diff --git a/drivers/soc/qcom/qmi_rmnet_i.h b/drivers/soc/qcom/qmi_rmnet_i.h index 17b1e6802f4a..770cb2b3d65e 100644 --- a/drivers/soc/qcom/qmi_rmnet_i.h +++ b/drivers/soc/qcom/qmi_rmnet_i.h @@ -106,7 +106,10 @@ int dfc_qmi_client_init(void *port, int index, struct qmi_info *qmi); void dfc_qmi_client_exit(void *dfc_data); void dfc_qmi_burst_check(struct net_device *dev, - struct qos_info *qos, struct sk_buff *skb); + struct qos_info *qos, struct sk_buff *skb, + struct qmi_info *qmi); + +void *qmi_rmnet_has_dfc_client(struct qmi_info *qmi); #else static inline struct rmnet_flow_map * qmi_rmnet_get_flow_map(struct qos_info *qos_info, @@ -131,11 +134,17 @@ static inline void dfc_qmi_client_exit(void *dfc_data) { } -static inline void dfc_qmi_burst_check(struct net_device *dev, - struct qos_info *qos, - struct sk_buff *skb) +static inline void +dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, + struct sk_buff *skb, struct qmi_info *qmi) { } + +static inline +void *qmi_rmnet_has_dfc_client(struct qmi_info *qmi) +{ + return NULL; +} #endif #ifdef CONFIG_QCOM_QMI_POWER_COLLAPSE diff --git a/include/trace/events/dfc.h b/include/trace/events/dfc.h index dc8dd5ae23b9..6b6a8a214014 100644 --- a/include/trace/events/dfc.h +++ b/include/trace/events/dfc.h @@ -18,7 +18,7 @@ #include -TRACE_EVENT(dfc_qmi_tc, +DECLARE_EVENT_CLASS(dfc_tc, TP_PROTO(u8 bearer_id, u32 flow_id, u32 grant, int qlen, u32 tcm_handle, int enable), @@ -50,6 +50,22 @@ TRACE_EVENT(dfc_qmi_tc, __entry->enable ? "enable" : "disable") ); +DEFINE_EVENT(dfc_tc, dfc_qmi_tc, + + TP_PROTO(u8 bearer_id, u32 flow_id, u32 grant, int qlen, + u32 tcm_handle, int enable), + + TP_ARGS(bearer_id, flow_id, grant, qlen, tcm_handle, enable) +); + +DEFINE_EVENT(dfc_tc, dfc_qmi_tc_limit, + + TP_PROTO(u8 bearer_id, u32 flow_id, u32 grant, int qlen, + u32 tcm_handle, int enable), + + TP_ARGS(bearer_id, flow_id, grant, qlen, tcm_handle, enable) +); + TRACE_EVENT(dfc_flow_ind, TP_PROTO(int src, int idx, u8 mux_id, u8 bearer_id, u32 grant, -- GitLab From be0ba9e91d80fd7404dbec9d26aed2a7224e359e Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Thu, 9 Aug 2018 16:54:11 -0700 Subject: [PATCH 0784/1001] power: qpnp-fg-gen4: Configure ESR FCC dynamically Currently, ESR FCC is configured to be HW autonomous always. When parallel charging is enabled, the battery charging current gets split up between main and parallel chargers. For ESR pulse, FG can request for a decrement in FCC whereas the main charger can end up increasing it because of the aforementioned current split. Fix this by moving to SW controlled mode with a fixed ESR FCC decrement of 300 mA when parallel charging is enabled. While at it, check for the presence of Qnovo enable status and charge pump presence as those are also potential cases where this can happen. Switch back to HW autonomous mode: - When the device is charging but only through main charger and not through parallel charger or charge pump and Qnovo is not enabled. - When the device is not charging. Change-Id: I6ea912bd10691e1a175f982dda83ca59ea42409b Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qcom/fg-reg.h | 1 + drivers/power/supply/qcom/qpnp-fg-gen4.c | 86 ++++++++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/drivers/power/supply/qcom/fg-reg.h b/drivers/power/supply/qcom/fg-reg.h index 931af0b2ed8f..0889fdf16a59 100644 --- a/drivers/power/supply/qcom/fg-reg.h +++ b/drivers/power/supply/qcom/fg-reg.h @@ -176,6 +176,7 @@ /* GEN4 bit definitions */ #define GEN4_ESR_FAST_CRG_IVAL_MASK GENMASK(7, 4) +#define GEN4_ESR_FAST_CRG_IVAL_SHIFT 4 #define GEN4_ESR_FCC_300MA 0x0 #define GEN4_ESR_FCC_600MA 0x1 #define GEN4_ESR_FCC_1A 0x2 diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index 138aa4fc3e6b..89fb5d0d897e 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -228,6 +228,7 @@ struct fg_gen4_chip { bool esr_fast_calib; bool esr_fast_calib_done; bool esr_fast_cal_timer_expired; + bool esr_fcc_ctrl_en; bool rslow_low; }; @@ -1974,6 +1975,87 @@ static int fg_gen4_charge_full_update(struct fg_dev *fg) return rc; } +static int fg_gen4_esr_fcc_config(struct fg_gen4_chip *chip) +{ + struct fg_dev *fg = &chip->fg; + union power_supply_propval prop = {0, }; + int rc; + bool parallel_en = false, cp_en = false, qnovo_en, esr_fcc_ctrl_en; + u8 val, mask; + + if (is_parallel_charger_available(fg)) { + rc = power_supply_get_property(fg->parallel_psy, + POWER_SUPPLY_PROP_CHARGING_ENABLED, &prop); + if (rc < 0) + pr_err_ratelimited("Error in reading charging_enabled from parallel_psy, rc=%d\n", + rc); + else + parallel_en = prop.intval; + } + + if (usb_psy_initialized(fg)) { + rc = power_supply_get_property(fg->usb_psy, + POWER_SUPPLY_PROP_SMB_EN_MODE, &prop); + if (rc < 0) { + pr_err("Couldn't read usb SMB_EN_MODE rc=%d\n", rc); + return rc; + } + + /* + * If SMB_EN_MODE is 1, then charge pump can get enabled for + * the charger inserted. However, whether the charge pump + * switching happens only if the conditions are met. + */ + cp_en = (prop.intval == 1); + } + + qnovo_en = is_qnovo_en(fg); + + fg_dbg(fg, FG_POWER_SUPPLY, "chg_sts: %d par_en: %d cp_en: %d qnov_en: %d esr_fcc_ctrl_en: %d\n", + fg->charge_status, parallel_en, cp_en, qnovo_en, + chip->esr_fcc_ctrl_en); + + if (fg->charge_status == POWER_SUPPLY_STATUS_CHARGING && + (parallel_en || qnovo_en || cp_en)) { + if (chip->esr_fcc_ctrl_en) + return 0; + + /* + * When parallel charging or Qnovo or Charge pump is enabled, + * configure ESR FCC to 300mA to trigger an ESR pulse. Without + * this, FG can request the main charger to increase FCC when it + * is supposed to decrease it. + */ + val = GEN4_ESR_FCC_300MA << GEN4_ESR_FAST_CRG_IVAL_SHIFT | + ESR_FAST_CRG_CTL_EN_BIT; + esr_fcc_ctrl_en = true; + } else { + if (!chip->esr_fcc_ctrl_en) + return 0; + + /* + * If we're here, then it means either the device is not in + * charging state or parallel charging / Qnovo / Charge pump is + * disabled. Disable ESR fast charge current control in SW. + */ + val = GEN4_ESR_FCC_1A << GEN4_ESR_FAST_CRG_IVAL_SHIFT; + esr_fcc_ctrl_en = false; + } + + mask = GEN4_ESR_FAST_CRG_IVAL_MASK | ESR_FAST_CRG_CTL_EN_BIT; + rc = fg_masked_write(fg, BATT_INFO_ESR_FAST_CRG_CFG(fg), mask, val); + if (rc < 0) { + pr_err("Error in writing to %04x, rc=%d\n", + BATT_INFO_ESR_FAST_CRG_CFG(fg), rc); + return rc; + } + + chip->esr_fcc_ctrl_en = esr_fcc_ctrl_en; + fg_dbg(fg, FG_STATUS, "esr_fcc_ctrl_en set to %d\n", + chip->esr_fcc_ctrl_en); + return 0; +} + /* All irq handlers below this */ static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data) @@ -2699,6 +2781,10 @@ static void status_change_work(struct work_struct *work) if (rc < 0) pr_err("Error in adjusting recharge SOC, rc=%d\n", rc); + rc = fg_gen4_esr_fcc_config(chip); + if (rc < 0) + pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc); + ttf_update(chip->ttf, input_present); fg->prev_charge_status = fg->charge_status; out: -- GitLab From 911916c5862630422a860e18821722ec3c3b247c Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Wed, 15 Aug 2018 16:05:20 -0700 Subject: [PATCH 0785/1001] Revert "ashmem: switch to ->read_iter" This reverts commit 8a2af06415ef ("ashmem: switch to ->read_iter") This change resulted in ashmem file descriptors now getting labeled as system_server_tmpfs instead of ashmem_device. SELinux is rejecting access to file descriptors labeled as system_server_tmpfs and this is causing the battery settings app to crash. It does not look feasible to get SELinux to accept system_server_tmpfs labeled file descriptors as it is used too broadly. So for now revert this change until we can find a clean way to fix this. Change-Id: I5710c37f1204a296736b0e22bdaf12fe292d9c62 Signed-off-by: Liam Mark --- drivers/staging/android/ashmem.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 69df278e9aa4..9dc534f677d1 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -294,9 +294,19 @@ static int ashmem_release(struct inode *ignored, struct file *file) return 0; } -static ssize_t ashmem_read_iter(struct kiocb *iocb, struct iov_iter *iter) +/** + * ashmem_read() - Reads a set of bytes from an Ashmem-enabled file + * @file: The associated backing file. + * @buf: The buffer of data being written to + * @len: The number of bytes being read + * @pos: The position of the first byte to read. + * + * Return: 0 if successful, or another return code if not. + */ +static ssize_t ashmem_read(struct file *file, char __user *buf, + size_t len, loff_t *pos) { - struct ashmem_area *asma = iocb->ki_filp->private_data; + struct ashmem_area *asma = file->private_data; int ret = 0; mutex_lock(&ashmem_mutex); @@ -310,17 +320,20 @@ static ssize_t ashmem_read_iter(struct kiocb *iocb, struct iov_iter *iter) goto out_unlock; } + mutex_unlock(&ashmem_mutex); + /* * asma and asma->file are used outside the lock here. We assume * once asma->file is set it will never be changed, and will not * be destroyed until all references to the file are dropped and * ashmem_release is called. */ - mutex_unlock(&ashmem_mutex); - ret = vfs_iter_read(asma->file, iter, &iocb->ki_pos, 0); - mutex_lock(&ashmem_mutex); - if (ret > 0) - asma->file->f_pos = iocb->ki_pos; + ret = __vfs_read(asma->file, buf, len, pos); + if (ret >= 0) + /** Update backing file pos, since f_ops->read() doesn't */ + asma->file->f_pos = *pos; + return ret; + out_unlock: mutex_unlock(&ashmem_mutex); return ret; @@ -815,7 +828,7 @@ static const struct file_operations ashmem_fops = { .owner = THIS_MODULE, .open = ashmem_open, .release = ashmem_release, - .read_iter = ashmem_read_iter, + .read = ashmem_read, .llseek = ashmem_llseek, .mmap = ashmem_mmap, .unlocked_ioctl = ashmem_ioctl, -- GitLab From 8b8cab8b08909d54120784ef50dac02fd3b64a6e Mon Sep 17 00:00:00 2001 From: Ziqi Chen Date: Wed, 8 Aug 2018 13:57:12 +0800 Subject: [PATCH 0786/1001] ARM: dts: msm: Enable sdhc1 and sdhc2 for QRD SM6150 SoD Add entried for sdhc1 and sdhc2 on QRD SM6150 platform. Change-Id: Ic9798be616240d6b9fee003ccf57526523ce0dbd Signed-off-by: Ziqi Chen --- arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi index 63355b0fc6e8..d74edc056a05 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi @@ -78,3 +78,39 @@ qcom,platform-te-gpio = <&tlmm 90 0>; qcom,platform-reset-gpio = <&tlmm 91 0>; }; + +&sdhc_1 { + vdd-supply = <&pm6150l_l11>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&pm6150_l12>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pm6150l_l9>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&pm6150l_l6>; + qcom,vdd-io-voltage-level = <1800000 3100000>; + qcom,vdd-io-current-level = <0 22000>; + + 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>; + + cd-gpios = <&tlmm 99 0>; + + status = "ok"; +}; -- GitLab From aac95e5c0e0b403bafecd93daf7973ad557add7b Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Tue, 13 Feb 2018 20:42:16 -0800 Subject: [PATCH 0787/1001] msm: camera: req_mgr: Populate dev_hdl to notify events to RT devices When sending a specific request to a particular connected device fails, we need to notify other devices for which the same request was already sent. While doing this notification dev_hdl needs to be populated correctly. Change-Id: Ib04e600ee96689fa70e471864b6ea14244768007 Signed-off-by: Karthik Anantha Ram --- drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c index edeecdbb6712..3311f29fba1e 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c @@ -502,6 +502,7 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, for (; i >= 0; i--) { dev = &link->l_dev[i]; evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_ERR; + evt_data.dev_hdl = dev->dev_hdl; evt_data.link_hdl = link->link_hdl; evt_data.req_id = apply_req.request_id; evt_data.u.error = CRM_KMD_ERR_BUBBLE; -- GitLab From 197d32af7b67b7f740d1f1c3a8830890a6a0a0b0 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Mon, 13 Aug 2018 11:55:00 -0700 Subject: [PATCH 0788/1001] power: smb5-lib: exclusive typec mode operation In USB Type-C mode, TRY_SINK/TRY_SRC and SRC_ONLY/SNK_ONLY are mutually exlusive. To make force sink/src operation successful, clear both TRY_SINK and TRY_SRC settings beforehand, and restore the settings after switching back to DRP mode. Change-Id: I7d2b7ea8ed41baef37ec2289ec7c43159cba9a55 Signed-off-by: Harry Yang --- drivers/power/supply/qcom/qpnp-smb5.c | 2 ++ drivers/power/supply/qcom/smb5-lib.c | 5 +++-- drivers/power/supply/qcom/smb5-lib.h | 1 + drivers/power/supply/qcom/smb5-reg.h | 4 +++- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 66169ba65778..99b926df7f2a 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -1563,6 +1563,8 @@ static int smb5_configure_typec(struct smb_charger *chg) dev_err(chg->dev, "Couldn't enable try.snk rc=%d\n", rc); return rc; + } else { + chg->typec_try_mode |= EN_TRY_SNK_BIT; } /* configure VCONN for software control */ diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 9c260fd9b4b1..57888f139822 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -2729,7 +2729,7 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg, power_role = TYPEC_DISABLE_CMD_BIT; break; case POWER_SUPPLY_TYPEC_PR_DUAL: - power_role = 0; + power_role = chg->typec_try_mode; break; case POWER_SUPPLY_TYPEC_PR_SINK: power_role = EN_SNK_ONLY_BIT; @@ -2743,7 +2743,8 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg, } rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, - TYPEC_POWER_ROLE_CMD_MASK, power_role); + TYPEC_POWER_ROLE_CMD_MASK | TYPEC_TRY_MODE_MASK, + power_role); if (rc < 0) { smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n", power_role, rc); diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 612b554d98d4..62781c76f9d9 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -375,6 +375,7 @@ struct smb_charger { bool jeita_configured; int charger_temp_max; int smb_temp_max; + u8 typec_try_mode; /* workaround flag */ u32 wa_flags; diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index b2958c337036..8218b9ec4017 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -322,8 +322,10 @@ enum { #define U_USB_GROUND_BIT BIT(4) #define TYPE_C_MODE_CFG_REG (TYPEC_BASE + 0x44) -#define TYPEC_POWER_ROLE_CMD_MASK GENMASK(2, 1) +#define TYPEC_TRY_MODE_MASK GENMASK(4, 3) #define EN_TRY_SNK_BIT BIT(4) +#define EN_TRY_SRC_BIT BIT(3) +#define TYPEC_POWER_ROLE_CMD_MASK GENMASK(2, 0) #define EN_SRC_ONLY_BIT BIT(2) #define EN_SNK_ONLY_BIT BIT(1) #define TYPEC_DISABLE_CMD_BIT BIT(0) -- GitLab From 88df92aece4abb1d0de2166e1f90b6e3e395e5d0 Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Mon, 13 Aug 2018 15:47:07 +0530 Subject: [PATCH 0789/1001] ARM: dts: qcom: Update QUP_1 master id for SM6150 QUP_1 bus master id requires to be updated on SM6150, so update the same. Change-Id: Id01e3432dec0a7694e24578eede8ddc431ecabb1 Signed-off-by: Odelu Kukatla --- arch/arm64/boot/dts/qcom/sm6150-bus.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi b/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi index 0b71cd5e14f4..797f89e181bb 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi @@ -501,7 +501,7 @@ }; mas_qhm_qup1: mas-qhm-qup1 { - cell-id = ; + cell-id = ; label = "mas-qhm-qup1"; qcom,buswidth = <4>; qcom,agg-ports = <1>; -- GitLab From ee4ee46bf464e2d566ad254a2780862853575c25 Mon Sep 17 00:00:00 2001 From: Mukesh Kumar Savaliya Date: Mon, 13 Aug 2018 16:53:29 +0530 Subject: [PATCH 0790/1001] ARM: dts: qcom: Update QUPv3 core master bus id for SM6150 Bus ID got changed for SM6150, hence incorporate the same changes for QUPV3_0 and QUPV3_1 wrapper cores. Change-Id: I0a4504a7835415529be97265c5649c5ea41b84fa Signed-off-by: Mukesh Kumar Savaliya --- arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi index 1ab49b81d108..1b57e796d5d6 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi @@ -29,7 +29,7 @@ qupv3_0: qcom,qupv3_0_geni_se@8c0000 { compatible = "qcom,qupv3-geni-se"; reg = <0x8c0000 0x6000>; - qcom,bus-mas-id = ; + qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; @@ -144,7 +144,7 @@ qupv3_1: qcom,qupv3_1_geni_se@ac0000 { compatible = "qcom,qupv3-geni-se"; reg = <0xac0000 0x6000>; - qcom,bus-mas-id = ; + qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; -- GitLab From 961608640a78d381ea8073e8b4b3de93ec547de3 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Wed, 15 Aug 2018 23:04:39 -0700 Subject: [PATCH 0791/1001] ARM: dts: msm: Update SM8150 QRD USB redriver settings Update redriver tuning settings based on most recent USB 3.1 Gen2 RX compliance testing. These values allow for the best margins for short and long channel jitter tolerance. Change-Id: Iddcf093c3acb5ad7577bb634cb4a8b398edd3f5b Signed-off-by: Jack Pham --- arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index eaaa3edb63ba..dda31252fa51 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -187,10 +187,10 @@ compatible = "onnn,redriver"; reg = <0x19>; extcon = <&pm8150b_pdphy>, <&pm8150b_pdphy>; - eq = /bits/ 8 <0x5 0x4 0x4 0x5>; + eq = /bits/ 8 <0x4 0x4 0x4 0x4>; flat-gain = /bits/ 8 <0x3 0x1 0x1 0x3>; output-comp = /bits/ 8 <0x2 0x2 0x2 0x2>; - loss-match = /bits/ 8 <0x0 0x3 0x3 0x0>; + loss-match = /bits/ 8 <0x1 0x3 0x3 0x1>; }; }; -- GitLab From b218d6b14c2a80a3bd0f85ac7eb7a2bc28c2b7b5 Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Tue, 14 Aug 2018 10:26:54 +0530 Subject: [PATCH 0792/1001] clk: qcom: gcc: Add a fixed factor clock for SDMMAGPIE There is a fixed hardware divider which sits in between the gpll0 and the gpll0 sources which are fed to the various other subsystems(e.g NPU). Add the clock to represent the clock tree correctly. Change-Id: Icc0265849af702714dbf2cbcd73fd49c104c6ecb Signed-off-by: Shefali Jain Signed-off-by: Taniya Das --- drivers/clk/qcom/gcc-sdmmagpie.c | 21 +++++++++++++++---- .../dt-bindings/clock/qcom,gcc-sdmmagpie.h | 1 + 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/clk/qcom/gcc-sdmmagpie.c b/drivers/clk/qcom/gcc-sdmmagpie.c index 79d533789c98..81a05f4c00e6 100644 --- a/drivers/clk/qcom/gcc-sdmmagpie.c +++ b/drivers/clk/qcom/gcc-sdmmagpie.c @@ -238,6 +238,17 @@ static struct clk_alpha_pll_postdiv gpll0_out_even = { }, }; +static struct clk_fixed_factor gcc_pll0_main_div_cdiv = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "gcc_pll0_main_div_cdiv", + .parent_names = (const char *[]){ "gpll0" }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + static struct clk_alpha_pll gpll6 = { .offset = 0x13000, .vco_table = fabia_vco, @@ -1493,7 +1504,7 @@ static struct clk_branch gcc_disp_gpll0_div_clk_src = { .hw.init = &(struct clk_init_data){ .name = "gcc_disp_gpll0_div_clk_src", .parent_names = (const char *[]){ - "gpll0", + "gcc_gpll0_main_div_cdiv", }, .num_parents = 1, .ops = &clk_branch2_ops, @@ -1635,7 +1646,7 @@ static struct clk_branch gcc_gpu_gpll0_div_clk_src = { .hw.init = &(struct clk_init_data){ .name = "gcc_gpu_gpll0_div_clk_src", .parent_names = (const char *[]){ - "gpll0", + "gcc_gpll0_main_div_cdiv", }, .num_parents = 1, .ops = &clk_branch2_ops, @@ -1723,7 +1734,7 @@ static struct clk_branch gcc_mss_gpll0_div_clk_src = { .hw.init = &(struct clk_init_data){ .name = "gcc_mss_gpll0_div_clk_src", .parent_names = (const char *[]){ - "gpll0", + "gcc_pll0_main_div_cdiv", }, .num_parents = 1, .ops = &clk_branch2_ops, @@ -1843,7 +1854,7 @@ static struct clk_branch gcc_npu_gpll0_div_clk_src = { .hw.init = &(struct clk_init_data){ .name = "gcc_npu_gpll0_div_clk_src", .parent_names = (const char *[]){ - "gpll0", + "gcc_pll0_main_div_cdiv", }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -3141,6 +3152,8 @@ struct clk_hw *gcc_sdmmagpie_hws[] = { [MEASURE_ONLY_CNOC_CLK] = &measure_only_cnoc_clk.hw, [MEASURE_ONLY_IPA_2X_CLK] = &measure_only_ipa_2x_clk.hw, [MEASURE_ONLY_SNOC_CLK] = &measure_only_snoc_clk.hw, + [GCC_GPLL0_MAIN_DIV_CDIV] = &gcc_pll0_main_div_cdiv.hw, + }; static struct clk_regmap *gcc_sdmmagpie_clocks[] = { diff --git a/include/dt-bindings/clock/qcom,gcc-sdmmagpie.h b/include/dt-bindings/clock/qcom,gcc-sdmmagpie.h index cde774dceb42..1159fbbffd53 100644 --- a/include/dt-bindings/clock/qcom,gcc-sdmmagpie.h +++ b/include/dt-bindings/clock/qcom,gcc-sdmmagpie.h @@ -183,6 +183,7 @@ #define GCC_VS_CTRL_CLK 163 #define GCC_VS_CTRL_CLK_SRC 164 #define GCC_VSENSOR_CLK_SRC 165 +#define GCC_GPLL0_MAIN_DIV_CDIV 167 /* GCC Resets */ #define GCC_PCIE_0_BCR 0 -- GitLab From 82c5fa13d102a038cdaffd898c37b38323796b58 Mon Sep 17 00:00:00 2001 From: Mukesh Kumar Savaliya Date: Tue, 28 Nov 2017 21:34:17 +0530 Subject: [PATCH 0793/1001] tty: serial: msm_geni_serial : Change AB voting for console used SE This patch is to change the AB value of the core clocks for console use case. Console doesn't need to run at higher AB vote, it causes power regression when system is running at SVS. Change-Id: I5bfdb5966da12b9473f437ee75cea361db330f0c Signed-off-by: Mukesh Kumar Savaliya --- drivers/tty/serial/msm_geni_serial.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index 0b98669a09ca..837ef891ec23 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -112,6 +112,7 @@ #define DEF_TX_WM (2) #define DEF_FIFO_WIDTH_BITS (32) #define UART_CORE2X_VOTE (10000) +#define UART_CONSOLE_CORE2X_VOTE (960) #define WAKEBYTE_TIMEOUT_MSEC (2000) #define WAIT_XFER_MAX_ITER (50) @@ -2386,8 +2387,16 @@ static int msm_geni_serial_probe(struct platform_device *pdev) } dev_port->wrapper_dev = &wrapper_pdev->dev; dev_port->serial_rsc.wrapper_dev = &wrapper_pdev->dev; - ret = geni_se_resources_init(&dev_port->serial_rsc, UART_CORE2X_VOTE, - (DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH)); + + if (is_console) + ret = geni_se_resources_init(&dev_port->serial_rsc, + UART_CONSOLE_CORE2X_VOTE, + (DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH)); + else + ret = geni_se_resources_init(&dev_port->serial_rsc, + UART_CORE2X_VOTE, + (DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH)); + if (ret) goto exit_geni_serial_probe; -- GitLab From 583f0c517b7bee6d794b48f744452440eba71986 Mon Sep 17 00:00:00 2001 From: Mohamed Sunfeer Date: Thu, 19 Jul 2018 13:00:51 +0530 Subject: [PATCH 0794/1001] ARM: dts: msm: Add Qseecom node and Qrng node for sm6150 Add qseecom driver node on Device tree include file to enable the qseecom driver to communicate with TZ and add QRNG device node on include file to enable the QRNG driver to communicate with /dev/random. Change-Id: Ia73855b740ff965eb198877e4dafa670f586239b Signed-off-by: Mohamed Sunfeer --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 9b1c155b86b5..ef2da0ebabf6 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -1604,6 +1604,38 @@ status = "disabled"; }; + qcom_seecom: qseecom@86d00000 { + compatible = "qcom,qseecom"; + reg = <0x86d00000 0xe00000>; + reg-names = "secapp-region"; + memory-region = <&qseecom_mem>; + qcom,hlos-num-ce-hw-instances = <1>; + qcom,hlos-ce-hw-instance = <0>; + qcom,qsee-ce-hw-instance = <0>; + qcom,disk-encrypt-pipe-pair = <2>; + qcom,support-fde; + qcom,no-clock-support; + qcom,fde-key-size; + qcom,appsbl-qseecom-support; + qcom,commonlib64-loaded-by-uefi; + qcom,qsee-reentrancy-support = <2>; + }; + + qcom_rng: qrng@793000 { + compatible = "qcom,msm-rng"; + reg = <0x793000 0x1000>; + qcom,msm-rng-iface-clk; + qcom,no-qrng-config; + qcom,msm-bus,name = "msm-rng-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 618 0 0>, /* No vote */ + <1 618 0 300000>; /* 75 MHz */ + clocks = <&clock_gcc GCC_PRNG_AHB_CLK>; + clock-names = "iface_clk"; + }; + ufsphy_mem: ufsphy_mem@1d87000 { reg = <0x1d87000 0xdb8>; /* PHY regs */ reg-names = "phy_mem"; -- GitLab From acd7b5b3108f8e4af5fe94d928a3ae8bbfa98747 Mon Sep 17 00:00:00 2001 From: Mohamed Sunfeer Date: Thu, 19 Jul 2018 14:06:07 +0530 Subject: [PATCH 0795/1001] ARM: dts: msm: Add crypto devices for sm6150 Add qcedev and qcrypto device node for sm6150 to enable HW crypto CE operations. Change-Id: Ib3f365868e5d68c01fff257516a929cd0405866b Signed-off-by: Mohamed Sunfeer --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 53 ++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index ef2da0ebabf6..231e5a727cfe 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -1741,6 +1741,59 @@ status = "disabled"; }; + qcom_cedev: qcedev@1de0000 { + compatible = "qcom,qcedev"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 272 0>; + qcom,bam-pipe-pair = <3>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,ce-hw-shared; + qcom,bam-ee = <0>; + qcom,msm-bus,name = "qcedev-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <125 512 0 0>, + <125 512 393600 393600>; + qcom,smmu-s1-enable; + qcom,no-clock-support; + iommus = <&apps_smmu 0x0106 0x0011>, + <&apps_smmu 0x0116 0x0011>; + }; + + qcom_crypto: qcrypto@1de0000 { + compatible = "qcom,qcrypto"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 272 0>; + qcom,bam-pipe-pair = <2>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,bam-ee = <0>; + qcom,ce-hw-shared; + qcom,clk-mgmt-sus-res; + qcom,msm-bus,name = "qcrypto-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <125 512 0 0>, + <125 512 393600 393600>; + qcom,use-sw-aes-cbc-ecb-ctr-algo; + qcom,use-sw-aes-xts-algo; + qcom,use-sw-aes-ccm-algo; + qcom,use-sw-ahash-algo; + qcom,use-sw-aead-algo; + qcom,use-sw-hmac-algo; + qcom,smmu-s1-enable; + qcom,no-clock-support; + iommus = <&apps_smmu 0x0104 0x0011>, + <&apps_smmu 0x0114 0x0011>; + }; + spmi_bus: qcom,spmi@c440000 { compatible = "qcom,spmi-pmic-arb"; reg = <0xc440000 0x1100>, -- GitLab From e23638c9cd809324cd5edf3e0c46e2f41895176f Mon Sep 17 00:00:00 2001 From: Mohamed Sunfeer Date: Thu, 19 Jul 2018 15:01:59 +0530 Subject: [PATCH 0796/1001] ARM: dts: msm: Enable TZ-log driver for SM6150 Enable TZ-log device node on include file to enable the TZ-log driver on sdm450 to access TZ diag area. Change-Id: I043a5c3d9c0f8e96f936200d803a7f8f9feb57d3 Signed-off-by: Mohamed Sunfeer --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 231e5a727cfe..bcaf7b870202 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -1794,6 +1794,14 @@ <&apps_smmu 0x0114 0x0011>; }; + qcom_tzlog: tz-log@146aa720 { + compatible = "qcom,tz-log"; + reg = <0x146aa720 0x3000>; + qcom,hyplog-enabled; + hyplog-address-offset = <0x410>; + hyplog-size-offset = <0x414>; + }; + spmi_bus: qcom,spmi@c440000 { compatible = "qcom,spmi-pmic-arb"; reg = <0xc440000 0x1100>, -- GitLab From bb422e13f3a2ae126e0da9996d0eee03148f7d76 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Sat, 11 Aug 2018 23:48:58 +0530 Subject: [PATCH 0797/1001] clk: qcom: update dsi 14nm PLL clock names This change updates the name strings for various DSI 14nm PLL clocks, so that it can work with corresponding upstream clock driver. Change-Id: I8a3c7549ccb13b88ba301a7a72411f4d32817b66 Signed-off-by: Sandeep Panda --- drivers/clk/qcom/dispcc-sm6150.c | 2 +- drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.c | 12 ++++++------ drivers/clk/qcom/mdss/mdss-pll.c | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/clk/qcom/dispcc-sm6150.c b/drivers/clk/qcom/dispcc-sm6150.c index 4338b833faea..1f84e3add24d 100644 --- a/drivers/clk/qcom/dispcc-sm6150.c +++ b/drivers/clk/qcom/dispcc-sm6150.c @@ -472,7 +472,7 @@ static struct clk_branch disp_cc_mdss_byte0_intf_clk = { "disp_cc_mdss_byte0_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .flags = CLK_GET_RATE_NOCACHE, .ops = &clk_branch2_ops, }, }, diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.c index f42ec5504621..473a4fd6eec3 100644 --- a/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.c +++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-14nm.c @@ -78,7 +78,7 @@ static struct dsi_pll_vco_clk dsi0pll_vco_clk = { .pll_enable_seqs[0] = dsi_pll_enable_seq_14nm, .hw.init = &(struct clk_init_data){ .name = "dsi0pll_vco_clk_14nm", - .parent_names = (const char *[]){ "xo_board" }, + .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, .ops = &clk_ops_dsi_vco, }, @@ -90,7 +90,7 @@ static struct dsi_pll_vco_clk dsi0pll_shadow_vco_clk = { .max_rate = 2600000000u, .hw.init = &(struct clk_init_data){ .name = "dsi0pll_shadow_vco_clk_14nm", - .parent_names = (const char *[]){ "xo_board" }, + .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, .ops = &clk_ops_shadow_dsi_vco, }, @@ -104,7 +104,7 @@ static struct dsi_pll_vco_clk dsi1pll_vco_clk = { .pll_enable_seqs[0] = dsi_pll_enable_seq_14nm, .hw.init = &(struct clk_init_data){ .name = "dsi1pll_vco_clk_14nm", - .parent_names = (const char *[]){ "xo_board" }, + .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, .ops = &clk_ops_dsi_vco, }, @@ -118,7 +118,7 @@ static struct dsi_pll_vco_clk dsi1pll_shadow_vco_clk = { .pll_enable_seqs[0] = dsi_pll_enable_seq_14nm, .hw.init = &(struct clk_init_data){ .name = "dsi1pll_shadow_vco_clk_14nm", - .parent_names = (const char *[]){ "xo_board" }, + .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, .ops = &clk_ops_shadow_dsi_vco, }, @@ -319,7 +319,7 @@ static struct clk_regmap_mux dsi0pll_pixel_clk_mux = { .clkr = { .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_pixel_clk_mux", + .name = "dsi0_phy_pll_out_dsiclk", .parent_names = (const char *[]){ "dsi0pll_pixel_clk_src", "dsi0pll_shadow_pixel_clk_src"}, @@ -409,7 +409,7 @@ static struct clk_regmap_mux dsi0pll_byte_clk_mux = { .clkr = { .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_byte_clk_mux", + .name = "dsi0_phy_pll_out_byteclk", .parent_names = (const char *[]){"dsi0pll_byte_clk_src", "dsi0pll_shadow_byte_clk_src"}, diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c index 7de354a4de68..3710a08f12bf 100644 --- a/drivers/clk/qcom/mdss/mdss-pll.c +++ b/drivers/clk/qcom/mdss/mdss-pll.c @@ -408,6 +408,7 @@ static const struct of_device_id mdss_pll_dt_match[] = { {.compatible = "qcom,mdss_dsi_pll_7nm"}, {.compatible = "qcom,mdss_dp_pll_7nm"}, {.compatible = "qcom,mdss_dsi_pll_28lpm"}, + {.compatible = "qcom,mdss_dsi_pll_14nm"}, {} }; -- GitLab From 7d42028b99d32ad6ec82aa429378fba0280a1c4a Mon Sep 17 00:00:00 2001 From: Tingwei Zhang Date: Thu, 16 Aug 2018 15:32:48 +0800 Subject: [PATCH 0798/1001] coresight: byte-cntr: Read 64bit rwp TMC RWP has two 32bit registers which combine to one 64bit register. Read correct RWP register in byte counter driver. Change-Id: If4a204110e0cc97d65e8a6af37ca764ffb38a150 Signed-off-by: Tingwei Zhang --- drivers/hwtracing/coresight/coresight-byte-cntr.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-byte-cntr.c b/drivers/hwtracing/coresight/coresight-byte-cntr.c index 24796b026f55..1a4c74191789 100644 --- a/drivers/hwtracing/coresight/coresight-byte-cntr.c +++ b/drivers/hwtracing/coresight/coresight-byte-cntr.c @@ -47,7 +47,8 @@ static void tmc_etr_sg_read_pos(loff_t *ppos, size_t bytes, bool noirq, size_t *len, char **bufpp) { - uint32_t rwp, i = 0; + uint32_t i = 0; + u64 rwp; uint32_t blk_num, sg_tbl_num, blk_num_loc, read_off; uint32_t *virt_pte, *virt_st_tbl; void *virt_blk; @@ -86,7 +87,7 @@ static void tmc_etr_sg_read_pos(loff_t *ppos, *bufpp = (char *)(virt_blk + read_off); if (noirq) { - rwp = readl_relaxed(tmcdrvdata->base + TMC_RWP); + rwp = tmc_read_rwp(tmcdrvdata); tmc_etr_sg_rwp_pos(tmcdrvdata, rwp); if (tmcdrvdata->sg_blk_num == blk_num && rwp >= (phys_pte + read_off)) -- GitLab From 44c59545270ad7133b21d665104662ea9e58ca64 Mon Sep 17 00:00:00 2001 From: Umang Agrawal Date: Wed, 15 Aug 2018 00:02:10 +0530 Subject: [PATCH 0799/1001] power: smb5: Add DC power supply support to PM6150 Modify logic required to enable support of DC power supply and enable dc power supply for PM6150. Change-Id: I1292b0ca8813d13accb66c77ef685efa56ddaca6 Signed-off-by: Umang Agrawal --- drivers/power/supply/qcom/qpnp-smb5.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 66169ba65778..c83cef17a3cc 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -2641,12 +2641,17 @@ static int smb5_probe(struct platform_device *pdev) goto cleanup; } - if (chg->smb_version == PM8150B_SUBTYPE) { + switch (chg->smb_version) { + case PM8150B_SUBTYPE: + case PM6150_SUBTYPE: rc = smb5_init_dc_psy(chip); if (rc < 0) { pr_err("Couldn't initialize dc psy rc=%d\n", rc); goto cleanup; } + break; + default: + break; } rc = smb5_init_usb_psy(chip); -- GitLab From 31fae71a7be05be720ffe7c17f236a40f3c5d274 Mon Sep 17 00:00:00 2001 From: Vevek Venkatesan Date: Mon, 13 Aug 2018 17:47:10 +0530 Subject: [PATCH 0800/1001] defconfig: add Himax and Synaptics touch driver for SM6150 Add Himax and Synaptics touch kernel driver and remove HBTP input driver support for SM6150. Change-Id: Ib89dd3a426ac4eaa9ee0d80d894ce5057824db49 Signed-off-by: Vevek Venkatesan --- arch/arm64/configs/vendor/sdmsteppe-perf_defconfig | 11 ++++++++++- arch/arm64/configs/vendor/sdmsteppe_defconfig | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig index 6e14473cbaf5..07d72a730f9b 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig @@ -286,8 +286,17 @@ CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y +CONFIG_TOUCHSCREEN_HIMAX_I2C=y +CONFIG_TOUCHSCREEN_HIMAX_INCELL=y +CONFIG_TOUCHSCREEN_HIMAX_IC_HX83112=y +CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING=y CONFIG_INPUT_MISC=y -CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y # CONFIG_SERIO_SERPORT is not set diff --git a/arch/arm64/configs/vendor/sdmsteppe_defconfig b/arch/arm64/configs/vendor/sdmsteppe_defconfig index a2202f3aafe4..9de205387285 100644 --- a/arch/arm64/configs/vendor/sdmsteppe_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe_defconfig @@ -294,8 +294,17 @@ CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y +CONFIG_TOUCHSCREEN_HIMAX_I2C=y +CONFIG_TOUCHSCREEN_HIMAX_INCELL=y +CONFIG_TOUCHSCREEN_HIMAX_IC_HX83112=y +CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING=y CONFIG_INPUT_MISC=y -CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y # CONFIG_SERIO_SERPORT is not set -- GitLab From f46dbe634b7f74254d1ad73e0d0f7f8c02a9031b Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Thu, 16 Aug 2018 13:13:14 +0530 Subject: [PATCH 0801/1001] msm: sps: Correct markings year format Correct markings year format for last change. Change-Id: I925766b96b04eea04a35a46d5904ddd2c5f0a673 Signed-off-by: Jishnu Prakash --- drivers/platform/msm/sps/sps_rm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/msm/sps/sps_rm.c b/drivers/platform/msm/sps/sps_rm.c index 013017c581e2..643f7412d429 100644 --- a/drivers/platform/msm/sps/sps_rm.c +++ b/drivers/platform/msm/sps/sps_rm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, 2017, 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2015, 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and -- GitLab From f85c1532025fe49b5bd8e755c106e710000f6e94 Mon Sep 17 00:00:00 2001 From: Umang Agrawal Date: Thu, 16 Aug 2018 13:21:30 +0530 Subject: [PATCH 0802/1001] ARM: dts: msm: Suspend USB input on debug battery for sm6150 Add support to suspend USB input if debug battery is detected for sm6150 target. Change-Id: Ic7483eb09bb6e8eb22df9a6833fb2e88f3f4bb53 Signed-off-by: Umang Agrawal --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index b40d15341b4d..26c1d8be69a3 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -2526,6 +2526,7 @@ &pm6150_charger { dpdm-supply = <&qusb_phy0>; + qcom,suspend-input-on-debug-batt; }; &usb0 { -- GitLab From baf1f2aef46d09bba1ef82da453330a463f9883b Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Tue, 3 Apr 2018 16:32:26 +0530 Subject: [PATCH 0803/1001] zram: allow zram to allocate CMA pages Though zram pages are movable, they aren't allowed to enter MIGRATE_CMA pageblocks. zram is not seen to pin pages for long which can cause an issue. Moreover allowing zram to pick CMA pages can be helpful in cases seen where zram order 0 alloc fails when there are lots of free cma pages, resulting in kswapd or direct reclaim not making enough progress. Change-Id: Id27d1a31b6cd869ebb025b49b76d2b62ba666ccf Signed-off-by: Vinayak Menon --- drivers/block/zram/zram_drv.c | 5 +++-- mm/zsmalloc.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 88564222f473..036c9a37b226 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -998,13 +998,14 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec, __GFP_KSWAPD_RECLAIM | __GFP_NOWARN | __GFP_HIGHMEM | - __GFP_MOVABLE); + __GFP_MOVABLE | + __GFP_CMA); if (!handle) { zcomp_stream_put(zram->comp); atomic64_inc(&zram->stats.writestall); handle = zs_malloc(zram->mem_pool, comp_len, GFP_NOIO | __GFP_HIGHMEM | - __GFP_MOVABLE); + __GFP_MOVABLE | __GFP_CMA); if (handle) goto compress_again; return -ENOMEM; diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 685049a9048d..9bfea0171c5a 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -345,7 +345,7 @@ static void destroy_cache(struct zs_pool *pool) static unsigned long cache_alloc_handle(struct zs_pool *pool, gfp_t gfp) { return (unsigned long)kmem_cache_alloc(pool->handle_cachep, - gfp & ~(__GFP_HIGHMEM|__GFP_MOVABLE)); + gfp & ~(__GFP_HIGHMEM|__GFP_MOVABLE|__GFP_CMA)); } static void cache_free_handle(struct zs_pool *pool, unsigned long handle) @@ -356,7 +356,7 @@ static void cache_free_handle(struct zs_pool *pool, unsigned long handle) static struct zspage *cache_alloc_zspage(struct zs_pool *pool, gfp_t flags) { return kmem_cache_alloc(pool->zspage_cachep, - flags & ~(__GFP_HIGHMEM|__GFP_MOVABLE)); + flags & ~(__GFP_HIGHMEM|__GFP_MOVABLE|__GFP_CMA)); } static void cache_free_zspage(struct zs_pool *pool, struct zspage *zspage) -- GitLab From b27bf074a135612542050fce2ba5d2b3e1cab980 Mon Sep 17 00:00:00 2001 From: Prateek Sood Date: Thu, 19 Jul 2018 14:53:26 +0530 Subject: [PATCH 0804/1001] ARM: dts: msm: Add sleep counter node for sdmmagpie Add sleep counter device tree node so that boot stats driver can read the counter time stamps. Change-Id: I3f669bbbb99805d7b58848bbbeb77b1cd0f626dc Signed-off-by: Prateek Sood --- arch/arm64/boot/dts/qcom/sdmmagpie.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index 73d6e6ead97d..44668a240c46 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -741,6 +741,12 @@ reg-names = "pshold-base", "tcsr-boot-misc-detect"; }; + qcom,mpm2-sleep-counter@0xc221000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0xc221000 0x1000>; + clock-frequency = <32768>; + }; + qcom,msm-rtb { compatible = "qcom,msm-rtb"; qcom,rtb-size = <0x100000>; -- GitLab From 223c28d53d733e2b1949341fa9ec6cdef29bfd1e Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Thu, 16 Aug 2018 14:22:24 +0530 Subject: [PATCH 0805/1001] mm: fix the use of ALLOC_CMA Movable allocations are allowed to allocate from CMA areas only when __GFP_CMA is set in the gfp mask of the request. But ALLOC_CMA is set in alloc_flags for all movable requests. This can make zone_watermark_ok take incorrect decision. Fix this by adding ALLOC_CMA only when request is of type __GFP_CMA. Change-Id: I15531968021c71cfbedd01d12307a203f0b408ca Signed-off-by: Vinayak Menon --- mm/page_alloc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index c2a871a5661b..c4db6573db78 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -3798,7 +3798,8 @@ gfp_to_alloc_flags(gfp_t gfp_mask) alloc_flags |= ALLOC_HARDER; #ifdef CONFIG_CMA - if (gfpflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE) + if ((gfpflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE) && + (gfp_mask & __GFP_CMA)) alloc_flags |= ALLOC_CMA; #endif return alloc_flags; @@ -4278,7 +4279,8 @@ static inline bool prepare_alloc_pages(gfp_t gfp_mask, unsigned int order, if (should_fail_alloc_page(gfp_mask, order)) return false; - if (IS_ENABLED(CONFIG_CMA) && ac->migratetype == MIGRATE_MOVABLE) + if (IS_ENABLED(CONFIG_CMA) && ac->migratetype == MIGRATE_MOVABLE && + (gfp_mask & __GFP_CMA)) *alloc_flags |= ALLOC_CMA; return true; -- GitLab From 71d59b4ca3077ae24abdd254c497a417bbde5930 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Mon, 6 Nov 2017 13:12:46 -0800 Subject: [PATCH 0806/1001] smb1355: Use comparator for die temperature The current code relies on presence of an external thermistor for reading 1355 die temperature. Instead stepwise increment the threshold. The threshold where the status changes indicates the die temp. Note that we will need to enable die temp comparator source for us to read the status bits. This will cause us to trigger two interrupts every time the sweeping procedure is run. This makes reading the temp_chan from adc unnecessary. Remove that code. Note that the stepwise increment of the threshold is run in a work every 10 seconds and the latest is returned in charger_temp property. It is run only when the parallel charging is enabled. Until any results are available a value of -EINVAL is returned. Change-Id: I22cda1f91b7dfa37970d4a6092f0c8696abd72b5 Signed-off-by: Abhijeet Dharmapurikar Signed-off-by: Umang Agrawal --- drivers/power/supply/qcom/smb1355-charger.c | 140 ++++++++++++-------- 1 file changed, 87 insertions(+), 53 deletions(-) diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c index 2dbba634f6c3..5b81e4f817ee 100644 --- a/drivers/power/supply/qcom/smb1355-charger.c +++ b/drivers/power/supply/qcom/smb1355-charger.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -26,10 +26,9 @@ #include #include #include +#include #include -#define SMB1355_DEFAULT_FCC_UA 1000000 - /* SMB1355 registers, different than mentioned in smb-reg.h */ #define I2C_SS_DIG_BASE 0x0E00 @@ -77,8 +76,12 @@ #define BATIF_CFG_SMISC_BATID_REG (BATIF_BASE + 0x73) #define CFG_SMISC_RBIAS_EXT_CTRL_BIT BIT(2) +#define SMB2CHGS_BATIF_ENG_SMISC_DIETEMP (BATIF_BASE + 0xC0) +#define TDIE_COMPARATOR_THRESHOLD GENMASK(5, 0) + #define BATIF_ENG_SCMISC_SPARE1_REG (BATIF_BASE + 0xC2) #define EXT_BIAS_PIN_BIT BIT(2) +#define DIE_TEMP_COMP_HYST_BIT BIT(1) #define TEMP_COMP_STATUS_REG (MISC_BASE + 0x07) #define SKIN_TEMP_RST_HOT_BIT BIT(6) @@ -151,11 +154,6 @@ struct smb_irq_info { int irq; }; -struct smb_iio { - struct iio_channel *temp_chan; - struct iio_channel *temp_max_chan; -}; - struct smb_dt_props { bool disable_ctm; }; @@ -167,7 +165,6 @@ struct smb1355 { struct smb_dt_props dt; struct smb_params param; - struct smb_iio iio; struct mutex write_lock; @@ -176,6 +173,10 @@ struct smb1355 { int c_health; int c_charger_temp_max; + int die_temp_deciDegC; + bool exit_die_temp; + struct delayed_work die_temp_work; + bool disabled; }; static bool is_secure(struct smb1355 *chip, int addr) @@ -275,6 +276,48 @@ static int smb1355_get_charge_param(struct smb1355 *chip, return rc; } +#define UB_COMP_OFFSET_DEGC 34 +#define DIE_TEMP_MEAS_PERIOD_MS 10000 +static void die_temp_work(struct work_struct *work) +{ + struct smb1355 *chip = container_of(work, struct smb1355, + die_temp_work.work); + int rc, i; + u8 temp_stat; + + for (i = 0; i < BIT(5); i++) { + rc = smb1355_masked_write(chip, + SMB2CHGS_BATIF_ENG_SMISC_DIETEMP, + TDIE_COMPARATOR_THRESHOLD, i); + if (rc < 0) { + pr_err("Couldn't set temp comp threshold rc=%d\n", rc); + continue; + } + + if (chip->exit_die_temp) + return; + + /* wait for the comparator output to deglitch */ + msleep(100); + + rc = smb1355_read(chip, TEMP_COMP_STATUS_REG, &temp_stat); + if (rc < 0) { + pr_err("Couldn't read temp comp status rc=%d\n", rc); + continue; + } + + if (!(temp_stat & DIE_TEMP_UB_HOT_BIT)) { + /* found the temp */ + break; + } + } + + chip->die_temp_deciDegC = 10 * (i + UB_COMP_OFFSET_DEGC); + + schedule_delayed_work(&chip->die_temp_work, + msecs_to_jiffies(DIE_TEMP_MEAS_PERIOD_MS)); +} + static irqreturn_t smb1355_handle_chg_state_change(int irq, void *data) { struct smb1355 *chip = data; @@ -372,25 +415,6 @@ static int smb1355_get_prop_batt_charge_type(struct smb1355 *chip, return rc; } -static int smb1355_get_parallel_charging(struct smb1355 *chip, int *disabled) -{ - int rc; - u8 cfg2; - - rc = smb1355_read(chip, CHGR_CFG2_REG, &cfg2); - if (rc < 0) { - pr_err("Couldn't read en_cmg_reg rc=%d\n", rc); - return rc; - } - - if (cfg2 & CHG_EN_SRC_BIT) - *disabled = 0; - else - *disabled = 1; - - return 0; -} - static int smb1355_get_prop_connector_health(struct smb1355 *chip) { u8 temp; @@ -414,25 +438,6 @@ static int smb1355_get_prop_connector_health(struct smb1355 *chip) return POWER_SUPPLY_HEALTH_COOL; } - -static int smb1355_get_prop_charger_temp(struct smb1355 *chip, - union power_supply_propval *val) -{ - int rc; - - if (!chip->iio.temp_chan || - PTR_ERR(chip->iio.temp_chan) == -EPROBE_DEFER) - chip->iio.temp_chan = devm_iio_channel_get(chip->dev, - "charger_temp"); - - if (IS_ERR(chip->iio.temp_chan)) - return PTR_ERR(chip->iio.temp_chan); - - rc = iio_read_channel_processed(chip->iio.temp_chan, &val->intval); - val->intval /= 100; - return rc; -} - static int smb1355_parallel_get_prop(struct power_supply *psy, enum power_supply_property prop, union power_supply_propval *val) @@ -456,13 +461,13 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, val->intval = !(stat & DISABLE_CHARGING_BIT); break; case POWER_SUPPLY_PROP_CHARGER_TEMP: - rc = smb1355_get_prop_charger_temp(chip, val); + val->intval = chip->die_temp_deciDegC; break; case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: val->intval = chip->c_charger_temp_max; break; case POWER_SUPPLY_PROP_INPUT_SUSPEND: - rc = smb1355_get_parallel_charging(chip, &val->intval); + val->intval = chip->disabled; break; case POWER_SUPPLY_PROP_VOLTAGE_MAX: rc = smb1355_get_charge_param(chip, &chip->param.ov, @@ -502,6 +507,9 @@ static int smb1355_set_parallel_charging(struct smb1355 *chip, bool disable) { int rc; + if (chip->disabled == disable) + return 0; + rc = smb1355_masked_write(chip, WD_CFG_REG, WDOG_TIMER_EN_BIT, disable ? 0 : WDOG_TIMER_EN_BIT); if (rc < 0) { @@ -520,9 +528,21 @@ static int smb1355_set_parallel_charging(struct smb1355 *chip, bool disable) disable ? 0 : CHG_EN_SRC_BIT); if (rc < 0) { pr_err("Couldn't configure charge enable source rc=%d\n", rc); - return rc; + disable = true; } + chip->die_temp_deciDegC = -EINVAL; + if (disable) { + chip->exit_die_temp = true; + cancel_delayed_work_sync(&chip->die_temp_work); + } else { + /* start the work to measure temperature */ + chip->exit_die_temp = false; + schedule_delayed_work(&chip->die_temp_work, 0); + } + + chip->disabled = disable; + return 0; } @@ -770,18 +790,29 @@ static int smb1355_init_hw(struct smb1355 *chip) } /* - * Disable thermal Die temperature comparator source and hw mitigation - * for skin/die + * Enable thermal Die temperature comparator source and disable hw + * mitigation for skin/die */ rc = smb1355_masked_write(chip, MISC_THERMREG_SRC_CFG_REG, THERMREG_DIE_CMP_SRC_EN_BIT | BYP_THERM_CHG_CURR_ADJUST_BIT, - BYP_THERM_CHG_CURR_ADJUST_BIT); + THERMREG_DIE_CMP_SRC_EN_BIT | BYP_THERM_CHG_CURR_ADJUST_BIT); if (rc < 0) { pr_err("Couldn't set Skin temperature comparator src rc=%d\n", rc); return rc; } + /* + * Disable hysterisis for die temperature. This is so that sw can run + * stepping scheme quickly + */ + rc = smb1355_masked_write(chip, BATIF_ENG_SCMISC_SPARE1_REG, + DIE_TEMP_COMP_HYST_BIT, 0); + if (rc < 0) { + pr_err("Couldn't disable hyst. for die rc=%d\n", rc); + return rc; + } + rc = smb1355_tskin_sensor_config(chip); if (rc < 0) { pr_err("Couldn't configure tskin regs rc=%d\n", rc); @@ -907,6 +938,9 @@ static int smb1355_probe(struct platform_device *pdev) chip->c_charger_temp_max = -EINVAL; chip->name = "smb1355"; mutex_init(&chip->write_lock); + INIT_DELAYED_WORK(&chip->die_temp_work, die_temp_work); + chip->disabled = true; + chip->die_temp_deciDegC = -EINVAL; chip->regmap = dev_get_regmap(chip->dev->parent, NULL); if (!chip->regmap) { -- GitLab From c0808dbe83c1e122c94632e5021cde3704215d45 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Thu, 2 Nov 2017 10:01:50 +0530 Subject: [PATCH 0807/1001] qcom: smb1355: support usbin-usbin parallel configuration Currently smb1355 only support usbmid-usbmid parallel architecture, add support for usbin-usbin parallel configuration which allows ICL split between main and parallel charger. While at it, add hardware configuration to improve ICL accuracy and DAC offset/gain. Change-Id: I71aa05114a735346d45af9d64f42de6da91857e9 Signed-off-by: Ashay Jaiswal Signed-off-by: Umang Agrawal --- .../power/supply/qcom/smb1355-charger.txt | 15 ++ drivers/power/supply/qcom/smb1355-charger.c | 206 +++++++++++++++++- 2 files changed, 218 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb1355-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb1355-charger.txt index abbb9816cf98..4f12ec09e1f1 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/smb1355-charger.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/smb1355-charger.txt @@ -36,6 +36,21 @@ Charger specific properties: connected to AUX. Set this flag to indicate the thermistor doesn't exist. +- qcom,parallel-mode + Usage: optional + Value type: + Definition: Specifies parallel charging mode. If not specified, MID-MID + option is selected by default. + +- qcom,stacked-batfet + Usage: optional + Value type: + Definition: boolean flag. Specifies if parallel charger has stacked BATFET + configuration. + In stacked batfet the main and parallel charger's batfet are + stacked one after the other and thus all the charge current + (FCC) flows through main. In a non-stacked configuration each + charger controls the charge current (FCC) separately. ================================================ Second Level Nodes - SMB1355 Charger Peripherals ================================================ diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c index 5b81e4f817ee..1a502262e276 100644 --- a/drivers/power/supply/qcom/smb1355-charger.c +++ b/drivers/power/supply/qcom/smb1355-charger.c @@ -33,6 +33,7 @@ #define I2C_SS_DIG_BASE 0x0E00 #define CHGR_BASE 0x1000 +#define ANA2_BASE 0x1100 #define BATIF_BASE 0x1200 #define USBIN_BASE 0x1300 #define MISC_BASE 0x1600 @@ -69,6 +70,9 @@ #define CHGR_PRE_TO_FAST_THRESHOLD_CFG_REG (CHGR_BASE + 0x74) #define PRE_TO_FAST_CHARGE_THRESHOLD_MASK GENMASK(2, 0) +#define ANA2_TR_SBQ_ICL_1X_REF_OFFSET_REG (ANA2_BASE + 0xF5) +#define TR_SBQ_ICL_1X_REF_OFFSET GENMASK(4, 0) + #define POWER_MODE_HICCUP_CFG (BATIF_BASE + 0x72) #define MAX_HICCUP_DUETO_BATDIS_MASK GENMASK(5, 2) #define HICCUP_TIMEOUT_CFG_MASK GENMASK(1, 0) @@ -92,6 +96,9 @@ #define DIE_TEMP_UB_HOT_BIT BIT(1) #define DIE_TEMP_LB_HOT_BIT BIT(0) +#define MISC_RT_STS_REG (MISC_BASE + 0x10) +#define HARD_ILIMIT_RT_STS_BIT BIT(5) + #define BARK_BITE_WDOG_PET_REG (MISC_BASE + 0x43) #define BARK_BITE_WDOG_PET_BIT BIT(0) @@ -103,6 +110,9 @@ #define WDOG_TIMER_EN_ON_PLUGIN_BIT BIT(1) #define WDOG_TIMER_EN_BIT BIT(0) +#define MISC_CUST_SDCDC_CLK_CFG_REG (MISC_BASE + 0xA0) +#define SWITCHER_CLK_FREQ_MASK GENMASK(3, 0) + #define SNARL_BARK_BITE_WD_CFG_REG (MISC_BASE + 0x53) #define BITE_WDOG_DISABLE_CHARGING_CFG_BIT BIT(7) #define SNARL_WDOG_TIMEOUT_MASK GENMASK(6, 4) @@ -117,6 +127,34 @@ #define MISC_CHGR_TRIM_OPTIONS_REG (MISC_BASE + 0x55) #define CMD_RBIAS_EN_BIT BIT(2) +#define MISC_ENG_SDCDC_INPUT_CURRENT_CFG1_REG (MISC_BASE + 0xC8) +#define PROLONG_ISENSE_MASK GENMASK(7, 6) +#define PROLONG_ISENSEM_SHIFT 6 +#define SAMPLE_HOLD_DELAY_MASK GENMASK(5, 2) +#define SAMPLE_HOLD_DELAY_SHIFT 2 +#define DISABLE_ILIMIT_BIT BIT(0) + +#define MISC_ENG_SDCDC_INPUT_CURRENT_CFG2_REG (MISC_BASE + 0xC9) +#define INPUT_CURRENT_LIMIT_SOURCE_BIT BIT(7) +#define TC_ISENSE_AMPLIFIER_MASK GENMASK(6, 4) +#define TC_ISENSE_AMPLIFIER_SHIFT 4 +#define HS_II_CORRECTION_MASK GENMASK(3, 0) + +#define MISC_ENG_SDCDC_RESERVE3_REG (MISC_BASE + 0xCB) +#define VDDCAP_SHORT_DISABLE_TRISTATE_BIT BIT(7) +#define PCL_SHUTDOWN_BUCK_BIT BIT(6) +#define ISENSE_TC_CORRECTION_BIT BIT(5) +#define II_SOURCE_BIT BIT(4) +#define SCALE_SLOPE_COMP_MASK GENMASK(3, 0) + +#define USBIN_CURRENT_LIMIT_CFG_REG (USBIN_BASE + 0x70) +#define USB_TR_SCPATH_ICL_1X_GAIN_REG (USBIN_BASE + 0xF2) +#define TR_SCPATH_ICL_1X_GAIN_MASK GENMASK(5, 0) + +#define IS_USBIN(mode) \ + ((mode == POWER_SUPPLY_PL_USBIN_USBIN) \ + || (mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) + struct smb_chg_param { const char *name; u16 reg; @@ -128,6 +166,7 @@ struct smb_chg_param { struct smb_params { struct smb_chg_param fcc; struct smb_chg_param ov; + struct smb_chg_param usb_icl; }; static struct smb_params v1_params = { @@ -145,6 +184,13 @@ static struct smb_params v1_params = { .max_u = 5000000, .step_u = 10000, }, + .usb_icl = { + .name = "usb input current limit", + .reg = USBIN_CURRENT_LIMIT_CFG_REG, + .min_u = 100000, + .max_u = 5000000, + .step_u = 30000, + }, }; struct smb_irq_info { @@ -156,6 +202,8 @@ struct smb_irq_info { struct smb_dt_props { bool disable_ctm; + int pl_mode; + int pl_batfet_mode; }; struct smb1355 { @@ -318,6 +366,21 @@ static void die_temp_work(struct work_struct *work) msecs_to_jiffies(DIE_TEMP_MEAS_PERIOD_MS)); } +static int smb1355_get_prop_input_current_limited(struct smb1355 *chip, + union power_supply_propval *pval) +{ + int rc; + u8 stat = 0; + + rc = smb1355_read(chip, MISC_RT_STS_REG, &stat); + if (rc < 0) + pr_err("Couldn't read SMB1355_BATTERY_STATUS_3 rc=%d\n", rc); + + pval->intval = !!(stat & HARD_ILIMIT_RT_STS_BIT); + + return 0; +} + static irqreturn_t smb1355_handle_chg_state_change(int irq, void *data) { struct smb1355 *chip = data; @@ -370,7 +433,24 @@ static int smb1355_parse_dt(struct smb1355 *chip) chip->dt.disable_ctm = of_property_read_bool(node, "qcom,disable-ctm"); - return rc; + /* + * If parallel-mode property is not present default + * parallel configuration is USBMID-USBMID. + */ + rc = of_property_read_u32(node, + "qcom,parallel-mode", &chip->dt.pl_mode); + if (rc < 0) + chip->dt.pl_mode = POWER_SUPPLY_PL_USBMID_USBMID; + + /* + * If stacked-batfet property is not present default + * configuration is NON-STACKED-BATFET. + */ + chip->dt.pl_batfet_mode = POWER_SUPPLY_PL_NON_STACKED_BATFET; + if (of_property_read_bool(node, "qcom,stacked-batfet")) + chip->dt.pl_batfet_mode = POWER_SUPPLY_PL_STACKED_BATFET; + + return 0; } /***************************** @@ -389,6 +469,10 @@ static enum power_supply_property smb1355_parallel_props[] = { POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_PARALLEL_MODE, POWER_SUPPLY_PROP_CONNECTOR_HEALTH, + POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, + POWER_SUPPLY_PROP_MIN_ICL, + POWER_SUPPLY_PROP_CURRENT_MAX, }; static int smb1355_get_prop_batt_charge_type(struct smb1355 *chip, @@ -438,6 +522,7 @@ static int smb1355_get_prop_connector_health(struct smb1355 *chip) return POWER_SUPPLY_HEALTH_COOL; } +#define MIN_PARALLEL_ICL_UA 250000 static int smb1355_parallel_get_prop(struct power_supply *psy, enum power_supply_property prop, union power_supply_propval *val) @@ -481,7 +566,7 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, val->strval = chip->name; break; case POWER_SUPPLY_PROP_PARALLEL_MODE: - val->intval = POWER_SUPPLY_PL_USBMID_USBMID; + val->intval = chip->dt.pl_mode; break; case POWER_SUPPLY_PROP_CONNECTOR_HEALTH: if (chip->c_health == -EINVAL) @@ -489,6 +574,25 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, else val->intval = chip->c_health; break; + case POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE: + val->intval = chip->dt.pl_batfet_mode; + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED: + if (IS_USBIN(chip->dt.pl_mode)) + rc = smb1355_get_prop_input_current_limited(chip, val); + else + val->intval = 0; + break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + if (IS_USBIN(chip->dt.pl_mode)) + rc = smb1355_get_charge_param(chip, + &chip->param.usb_icl, &val->intval); + else + val->intval = 0; + break; + case POWER_SUPPLY_PROP_MIN_ICL: + val->intval = MIN_PARALLEL_ICL_UA; + break; default: pr_err_ratelimited("parallel psy get prop %d not supported\n", prop); @@ -546,6 +650,28 @@ static int smb1355_set_parallel_charging(struct smb1355 *chip, bool disable) return 0; } +static int smb1355_set_current_max(struct smb1355 *chip, int curr) +{ + int rc = 0; + + if (!IS_USBIN(chip->dt.pl_mode)) + return 0; + + if ((curr / 1000) < 100) { + /* disable parallel path (ICL < 100mA) */ + rc = smb1355_set_parallel_charging(chip, true); + } else { + rc = smb1355_set_parallel_charging(chip, false); + if (rc < 0) + return rc; + + rc = smb1355_set_charge_param(chip, + &chip->param.usb_icl, curr); + } + + return rc; +} + static int smb1355_parallel_set_prop(struct power_supply *psy, enum power_supply_property prop, const union power_supply_propval *val) @@ -557,6 +683,9 @@ static int smb1355_parallel_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_INPUT_SUSPEND: rc = smb1355_set_parallel_charging(chip, (bool)val->intval); break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + rc = smb1355_set_current_max(chip, val->intval); + break; case POWER_SUPPLY_PROP_VOLTAGE_MAX: rc = smb1355_set_charge_param(chip, &chip->param.ov, val->intval); @@ -819,6 +948,73 @@ static int smb1355_init_hw(struct smb1355 *chip) return rc; } + /* USBIN-USBIN configuration */ + if (IS_USBIN(chip->dt.pl_mode)) { + /* set swicther clock frequency to 700kHz */ + rc = smb1355_masked_write(chip, MISC_CUST_SDCDC_CLK_CFG_REG, + SWITCHER_CLK_FREQ_MASK, 0x03); + if (rc < 0) { + pr_err("Couldn't set MISC_CUST_SDCDC_CLK_CFG rc=%d\n", + rc); + return rc; + } + + /* + * configure compensation for input current limit (ICL) loop + * accuracy, scale slope compensation using 30k resistor. + */ + rc = smb1355_masked_write(chip, MISC_ENG_SDCDC_RESERVE3_REG, + II_SOURCE_BIT | SCALE_SLOPE_COMP_MASK, + II_SOURCE_BIT); + if (rc < 0) { + pr_err("Couldn't set MISC_ENG_SDCDC_RESERVE3_REG rc=%d\n", + rc); + return rc; + } + + /* configuration to improve ICL accuracy */ + rc = smb1355_masked_write(chip, + MISC_ENG_SDCDC_INPUT_CURRENT_CFG1_REG, + PROLONG_ISENSE_MASK | SAMPLE_HOLD_DELAY_MASK, + ((uint8_t)0x0C << SAMPLE_HOLD_DELAY_SHIFT)); + if (rc < 0) { + pr_err("Couldn't set MISC_ENG_SDCDC_INPUT_CURRENT_CFG1_REG rc=%d\n", + rc); + return rc; + } + + rc = smb1355_masked_write(chip, + MISC_ENG_SDCDC_INPUT_CURRENT_CFG2_REG, + INPUT_CURRENT_LIMIT_SOURCE_BIT + | HS_II_CORRECTION_MASK, + INPUT_CURRENT_LIMIT_SOURCE_BIT | 0xC); + + if (rc < 0) { + pr_err("Couldn't set MISC_ENG_SDCDC_INPUT_CURRENT_CFG2_REG rc=%d\n", + rc); + return rc; + } + + /* configure DAC offset */ + rc = smb1355_masked_write(chip, + ANA2_TR_SBQ_ICL_1X_REF_OFFSET_REG, + TR_SBQ_ICL_1X_REF_OFFSET, 0x00); + if (rc < 0) { + pr_err("Couldn't set ANA2_TR_SBQ_ICL_1X_REF_OFFSET_REG rc=%d\n", + rc); + return rc; + } + + /* configure DAC gain */ + rc = smb1355_masked_write(chip, USB_TR_SCPATH_ICL_1X_GAIN_REG, + TR_SCPATH_ICL_1X_GAIN_MASK, 0x22); + if (rc < 0) { + pr_err("Couldn't set USB_TR_SCPATH_ICL_1X_GAIN_REG rc=%d\n", + rc); + return rc; + } + } + return 0; } @@ -987,7 +1183,11 @@ static int smb1355_probe(struct platform_device *pdev) goto cleanup; } - pr_info("%s probed successfully\n", chip->name); + pr_info("%s probed successfully pl_mode=%s batfet_mode=%s\n", + chip->name, + IS_USBIN(chip->dt.pl_mode) ? "USBIN-USBIN" : "USBMID-USBMID", + (chip->dt.pl_batfet_mode == POWER_SUPPLY_PL_STACKED_BATFET) + ? "STACKED_BATFET" : "NON-STACKED_BATFET"); return rc; cleanup: -- GitLab From 906f7bd8d3b3b6b70a5c72243ea73b53c86936cc Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Mon, 18 Dec 2017 13:37:46 -0800 Subject: [PATCH 0808/1001] power: smb1355: Enable valley current all the time Enable LS valley current all the time for PCL protection. LS_Valley threshold is set to 85%. CRs-Fixed: 2156200 Change-Id: I835eaaabaf6b5f8a4a0f8dddb04eb2b7699d63a3 Signed-off-by: Guru Das Srinagesh --- drivers/power/supply/qcom/smb1355-charger.c | 23 +++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c index 1a502262e276..c13be3bc9f8c 100644 --- a/drivers/power/supply/qcom/smb1355-charger.c +++ b/drivers/power/supply/qcom/smb1355-charger.c @@ -36,6 +36,7 @@ #define ANA2_BASE 0x1100 #define BATIF_BASE 0x1200 #define USBIN_BASE 0x1300 +#define ANA1_BASE 0x1400 #define MISC_BASE 0x1600 #define I2C_SS_DIG_PMIC_SID_REG (I2C_SS_DIG_BASE + 0x45) @@ -87,6 +88,9 @@ #define EXT_BIAS_PIN_BIT BIT(2) #define DIE_TEMP_COMP_HYST_BIT BIT(1) +#define ANA1_ENG_SREFGEN_CFG2_REG (ANA1_BASE + 0xC1) +#define VALLEY_COMPARATOR_EN_BIT BIT(0) + #define TEMP_COMP_STATUS_REG (MISC_BASE + 0x07) #define SKIN_TEMP_RST_HOT_BIT BIT(6) #define SKIN_TEMP_UB_HOT_BIT BIT(5) @@ -113,6 +117,9 @@ #define MISC_CUST_SDCDC_CLK_CFG_REG (MISC_BASE + 0xA0) #define SWITCHER_CLK_FREQ_MASK GENMASK(3, 0) +#define MISC_CUST_SDCDC_ILIMIT_CFG_REG (MISC_BASE + 0xA1) +#define LS_VALLEY_THRESH_PCT_BIT BIT(3) + #define SNARL_BARK_BITE_WD_CFG_REG (MISC_BASE + 0x53) #define BITE_WDOG_DISABLE_CHARGING_CFG_BIT BIT(7) #define SNARL_WDOG_TIMEOUT_MASK GENMASK(6, 4) @@ -942,6 +949,22 @@ static int smb1355_init_hw(struct smb1355 *chip) return rc; } + /* Enable valley current comparator all the time */ + rc = smb1355_masked_write(chip, ANA1_ENG_SREFGEN_CFG2_REG, + VALLEY_COMPARATOR_EN_BIT, VALLEY_COMPARATOR_EN_BIT); + if (rc < 0) { + pr_err("Couldn't enable valley current comparator rc=%d\n", rc); + return rc; + } + + /* Set LS_VALLEY threshold to 85% */ + rc = smb1355_masked_write(chip, MISC_CUST_SDCDC_ILIMIT_CFG_REG, + LS_VALLEY_THRESH_PCT_BIT, LS_VALLEY_THRESH_PCT_BIT); + if (rc < 0) { + pr_err("Couldn't set LS valley threshold to 85pc rc=%d\n", rc); + return rc; + } + rc = smb1355_tskin_sensor_config(chip); if (rc < 0) { pr_err("Couldn't configure tskin regs rc=%d\n", rc); -- GitLab From df1b56ff3c4408f8a96c0ae56856165fb2862d23 Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Mon, 8 Jan 2018 22:11:00 +0530 Subject: [PATCH 0809/1001] power: smb1355: Force enable Bandgap while charging is active To optimize on power the SMB hardware disables the Bandgap when the charger is removed. When this happens, the SMB1355 IRQ line stays stuck in its last known state. I.e. if there was an interrupt pending (the IRQ line is low) and if the Bandgap gets disabled, the line stays stuck low forever causing a storm of interrupts. Fix this by forcing the Bandgap on as long as the parallel charger is enabled. Also, disable the registered SMB IRQs before the Bandgap is disabled by software. CRs-Fixed: 2160392 Change-Id: I237f438da439f4cf3c45ff812e6121e83bd050c1 Signed-off-by: Anirudh Ghayal --- drivers/power/supply/qcom/smb1355-charger.c | 44 +++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c index c13be3bc9f8c..15a33492d36c 100644 --- a/drivers/power/supply/qcom/smb1355-charger.c +++ b/drivers/power/supply/qcom/smb1355-charger.c @@ -103,6 +103,9 @@ #define MISC_RT_STS_REG (MISC_BASE + 0x10) #define HARD_ILIMIT_RT_STS_BIT BIT(5) +#define BANDGAP_ENABLE_REG (MISC_BASE + 0x42) +#define BANDGAP_ENABLE_CMD_BIT BIT(0) + #define BARK_BITE_WDOG_PET_REG (MISC_BASE + 0x43) #define BARK_BITE_WDOG_PET_BIT BIT(0) @@ -162,6 +165,8 @@ ((mode == POWER_SUPPLY_PL_USBIN_USBIN) \ || (mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) +#define PARALLEL_ENABLE_VOTER "PARALLEL_ENABLE_VOTER" + struct smb_chg_param { const char *name; u16 reg; @@ -232,6 +237,8 @@ struct smb1355 { bool exit_die_temp; struct delayed_work die_temp_work; bool disabled; + + struct votable *irq_disable_votable; }; static bool is_secure(struct smb1355 *chip, int addr) @@ -652,6 +659,18 @@ static int smb1355_set_parallel_charging(struct smb1355 *chip, bool disable) schedule_delayed_work(&chip->die_temp_work, 0); } + if (chip->irq_disable_votable) + vote(chip->irq_disable_votable, PARALLEL_ENABLE_VOTER, + disable, 0); + + rc = smb1355_masked_write(chip, BANDGAP_ENABLE_REG, + BANDGAP_ENABLE_CMD_BIT, + disable ? 0 : BANDGAP_ENABLE_CMD_BIT); + if (rc < 0) { + pr_err("Couldn't configure bandgap enable rc=%d\n", rc); + return rc; + } + chip->disabled = disable; return 0; @@ -1102,6 +1121,7 @@ static int smb1355_request_interrupt(struct smb1355 *chip, return rc; } + smb1355_irqs[irq_index].irq = irq; if (smb1355_irqs[irq_index].wake) enable_irq_wake(irq); @@ -1130,6 +1150,23 @@ static int smb1355_request_interrupts(struct smb1355 *chip) return rc; } +static int smb1355_irq_disable_callback(struct votable *votable, void *data, + int disable, const char *client) + +{ + int i; + + for (i = 0; i < ARRAY_SIZE(smb1355_irqs); i++) { + if (smb1355_irqs[i].irq) { + if (disable) + disable_irq(smb1355_irqs[i].irq); + else + enable_irq(smb1355_irqs[i].irq); + } + } + + return 0; +} /********* * PROBE * @@ -1206,6 +1243,13 @@ static int smb1355_probe(struct platform_device *pdev) goto cleanup; } + chip->irq_disable_votable = create_votable("SMB1355_IRQ_DISABLE", + VOTE_SET_ANY, smb1355_irq_disable_callback, chip); + if (IS_ERR(chip->irq_disable_votable)) { + rc = PTR_ERR(chip->irq_disable_votable); + goto cleanup; + } + pr_info("%s probed successfully pl_mode=%s batfet_mode=%s\n", chip->name, IS_USBIN(chip->dt.pl_mode) ? "USBIN-USBIN" : "USBMID-USBMID", -- GitLab From fe4fe7b934a6375aa8edc97757eac42958aa79e3 Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Fri, 12 Jan 2018 11:09:36 +0530 Subject: [PATCH 0810/1001] power: smb1355-charger: Vote to keep the IRQs disabled initially Add an initial vote to keep the IRQs disabled to avoid an unbalanced IRQ. Change-Id: Iaa19d25d0ee94f32928fe937c16263e3fffddd92 Signed-off-by: Anirudh Ghayal --- drivers/power/supply/qcom/smb1355-charger.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c index 15a33492d36c..4390464b68c4 100644 --- a/drivers/power/supply/qcom/smb1355-charger.c +++ b/drivers/power/supply/qcom/smb1355-charger.c @@ -1249,6 +1249,8 @@ static int smb1355_probe(struct platform_device *pdev) rc = PTR_ERR(chip->irq_disable_votable); goto cleanup; } + /* keep IRQ's disabled until parallel is enabled */ + vote(chip->irq_disable_votable, PARALLEL_ENABLE_VOTER, true, 0); pr_info("%s probed successfully pl_mode=%s batfet_mode=%s\n", chip->name, -- GitLab From 01f4b260bc099d36df7d239db6816cacae4651d9 Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Tue, 23 Jan 2018 15:14:37 -0800 Subject: [PATCH 0811/1001] power: smb1355: Detect SMB1354 Add support for detecting whether the chip is SMB1355 or SMB1354 (a variant of SMB1355). This is accomplished by reading the contents of the REVID_MFG_ID_SPARE_REG. CRs-Fixed: 2170280 Change-Id: I7799bfbdbda44f250ebec266ecf5adc0035398bf Signed-off-by: Guru Das Srinagesh Signed-off-by: Umang Agrawal --- drivers/power/supply/qcom/smb1355-charger.c | 44 ++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c index 4390464b68c4..78c36c660b95 100644 --- a/drivers/power/supply/qcom/smb1355-charger.c +++ b/drivers/power/supply/qcom/smb1355-charger.c @@ -31,6 +31,7 @@ /* SMB1355 registers, different than mentioned in smb-reg.h */ +#define REVID_BASE 0x0100 #define I2C_SS_DIG_BASE 0x0E00 #define CHGR_BASE 0x1000 #define ANA2_BASE 0x1100 @@ -39,6 +40,8 @@ #define ANA1_BASE 0x1400 #define MISC_BASE 0x1600 +#define REVID_MFG_ID_SPARE_REG (REVID_BASE + 0xFF) + #define I2C_SS_DIG_PMIC_SID_REG (I2C_SS_DIG_BASE + 0x45) #define PMIC_SID_MASK GENMASK(3, 0) #define PMIC_SID0_BIT BIT(0) @@ -223,6 +226,8 @@ struct smb1355 { char *name; struct regmap *regmap; + int max_fcc; + struct smb_dt_props dt; struct smb_params param; @@ -784,6 +789,38 @@ static int smb1355_init_parallel_psy(struct smb1355 *chip) * HARDWARE INITIALIZATION * ***************************/ +#define MFG_ID_SMB1354 0x01 +#define MFG_ID_SMB1355 0xFF +#define SMB1354_MAX_PARALLEL_FCC_UA 2500000 +#define SMB1355_MAX_PARALLEL_FCC_UA 6000000 +static int smb1355_detect_version(struct smb1355 *chip) +{ + int rc; + u8 val; + + rc = smb1355_read(chip, REVID_MFG_ID_SPARE_REG, &val); + if (rc < 0) { + pr_err("Unable to read REVID rc=%d\n", rc); + return rc; + } + + switch (val) { + case MFG_ID_SMB1354: + chip->name = "smb1354"; + chip->max_fcc = SMB1354_MAX_PARALLEL_FCC_UA; + break; + case MFG_ID_SMB1355: + chip->name = "smb1355"; + chip->max_fcc = SMB1355_MAX_PARALLEL_FCC_UA; + break; + default: + pr_err("Invalid value of REVID val=%d", val); + return -EINVAL; + } + + return rc; +} + static int smb1355_tskin_sensor_config(struct smb1355 *chip) { int rc; @@ -1192,7 +1229,6 @@ static int smb1355_probe(struct platform_device *pdev) chip->param = v1_params; chip->c_health = -EINVAL; chip->c_charger_temp_max = -EINVAL; - chip->name = "smb1355"; mutex_init(&chip->write_lock); INIT_DELAYED_WORK(&chip->die_temp_work, die_temp_work); chip->disabled = true; @@ -1210,6 +1246,12 @@ static int smb1355_probe(struct platform_device *pdev) return -ENODEV; } + rc = smb1355_detect_version(chip); + if (rc < 0) { + pr_err("Couldn't detect SMB1355/1354 chip type rc=%d\n", rc); + goto cleanup; + } + platform_set_drvdata(pdev, chip); rc = smb1355_parse_dt(chip); -- GitLab From a2e53991cc37c4a600bb4c4b589c791052e6d0f6 Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Mon, 22 Jan 2018 16:51:35 -0800 Subject: [PATCH 0812/1001] power: smb1355: Define max FCC limit using property For SMB1354, return the value of max parallel FCC limit via the power supply framework. This limit is 2.5 A. SMB1354 is a variant of SMB1355 with lower FCC limit. CRs-Fixed: 2170280 Change-Id: Iac609de606ad0781cb3141de2e50455e25fb1275 Signed-off-by: Guru Das Srinagesh --- drivers/power/supply/qcom/smb1355-charger.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c index 78c36c660b95..578590c88a24 100644 --- a/drivers/power/supply/qcom/smb1355-charger.c +++ b/drivers/power/supply/qcom/smb1355-charger.c @@ -489,6 +489,7 @@ static enum power_supply_property smb1355_parallel_props[] = { POWER_SUPPLY_PROP_PARALLEL_MODE, POWER_SUPPLY_PROP_CONNECTOR_HEALTH, POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE, + POWER_SUPPLY_PROP_PARALLEL_FCC_MAX, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, POWER_SUPPLY_PROP_MIN_ICL, POWER_SUPPLY_PROP_CURRENT_MAX, @@ -612,6 +613,9 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_MIN_ICL: val->intval = MIN_PARALLEL_ICL_UA; break; + case POWER_SUPPLY_PROP_PARALLEL_FCC_MAX: + val->intval = chip->max_fcc; + break; default: pr_err_ratelimited("parallel psy get prop %d not supported\n", prop); -- GitLab From b523954d2509a33aaa1ed5f96cc02c6b2dab2cdb Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Thu, 29 Mar 2018 17:05:38 -0700 Subject: [PATCH 0813/1001] power: smb1355: Raise PCL value for SMB1354 For SMB1354, set peak current limit to 8.6A as the previous limit, 5.6 A was found to be too low during testing. The previous limit was set in CSIR. CRs-Fixed: 2215592 Change-Id: I9ab18b0b7756e751cd003ae15ffb8e0b464d515c Signed-off-by: Guru Das Srinagesh --- drivers/power/supply/qcom/smb1355-charger.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c index 578590c88a24..ad3748df0755 100644 --- a/drivers/power/supply/qcom/smb1355-charger.c +++ b/drivers/power/supply/qcom/smb1355-charger.c @@ -28,6 +28,7 @@ #include #include #include +#include /* SMB1355 registers, different than mentioned in smb-reg.h */ @@ -125,6 +126,7 @@ #define MISC_CUST_SDCDC_ILIMIT_CFG_REG (MISC_BASE + 0xA1) #define LS_VALLEY_THRESH_PCT_BIT BIT(3) +#define PCL_LIMIT_MASK GENMASK(1, 0) #define SNARL_BARK_BITE_WD_CFG_REG (MISC_BASE + 0x53) #define BITE_WDOG_DISABLE_CHARGING_CFG_BIT BIT(7) @@ -1025,6 +1027,16 @@ static int smb1355_init_hw(struct smb1355 *chip) return rc; } + /* For SMB1354, set PCL to 8.6 A */ + if (!strcmp(chip->name, "smb1354")) { + rc = smb1355_masked_write(chip, MISC_CUST_SDCDC_ILIMIT_CFG_REG, + PCL_LIMIT_MASK, PCL_LIMIT_MASK); + if (rc < 0) { + pr_err("Couldn't set PCL limit to 8.6A rc=%d\n", rc); + return rc; + } + } + rc = smb1355_tskin_sensor_config(chip); if (rc < 0) { pr_err("Couldn't configure tskin regs rc=%d\n", rc); -- GitLab From d836ead79561ed6c853ffaf6948623499c380638 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Fri, 23 Mar 2018 10:23:58 +0530 Subject: [PATCH 0814/1001] power: smb1355: force enable clock while device is active To optimize on power the SMB hardware disables the Bandgap/clock when the charger is removed. When this happens, the SMB1355 IRQ line stays stuck in its last known state. I.e. if there was an interrupt pending (the IRQ line is low) and if the Bandgap/clock gets disabled, the line stays stuck low forever causing a storm of interrupts. Fix this by forcing SMB1355 clock "on" as long as device is up and and running and turn off the clock in ship-mode and shutdown path. Change-Id: If01e07c63119b6af555ffd064d1055417c6b3e46 Signed-off-by: Ashay Jaiswal Signed-off-by: Umang Agrawal --- drivers/power/supply/qcom/smb1355-charger.c | 55 +++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c index ad3748df0755..d5c6aeb33e63 100644 --- a/drivers/power/supply/qcom/smb1355-charger.c +++ b/drivers/power/supply/qcom/smb1355-charger.c @@ -113,6 +113,9 @@ #define BARK_BITE_WDOG_PET_REG (MISC_BASE + 0x43) #define BARK_BITE_WDOG_PET_BIT BIT(0) +#define CLOCK_REQUEST_REG (MISC_BASE + 0x44) +#define CLOCK_REQUEST_CMD_BIT BIT(0) + #define WD_CFG_REG (MISC_BASE + 0x51) #define WATCHDOG_TRIGGER_AFP_EN_BIT BIT(7) #define BARK_WDOG_INT_EN_BIT BIT(6) @@ -250,6 +253,9 @@ struct smb1355 { static bool is_secure(struct smb1355 *chip, int addr) { + if (addr == CLOCK_REQUEST_REG) + return true; + /* assume everything above 0xA0 is secure */ return (addr & 0xFF) >= 0xA0; } @@ -266,6 +272,25 @@ static int smb1355_read(struct smb1355 *chip, u16 addr, u8 *val) return rc; } +static int smb1355_masked_force_write(struct smb1355 *chip, u16 addr, u8 mask, + u8 val) +{ + int rc; + + mutex_lock(&chip->write_lock); + if (is_secure(chip, addr)) { + rc = regmap_write(chip->regmap, (addr & 0xFF00) | 0xD0, 0xA5); + if (rc < 0) + goto unlock; + } + + rc = regmap_write_bits(chip->regmap, addr, mask, val); + +unlock: + mutex_unlock(&chip->write_lock); + return rc; +} + static int smb1355_masked_write(struct smb1355 *chip, u16 addr, u8 mask, u8 val) { int rc; @@ -495,6 +520,7 @@ static enum power_supply_property smb1355_parallel_props[] = { POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, POWER_SUPPLY_PROP_MIN_ICL, POWER_SUPPLY_PROP_CURRENT_MAX, + POWER_SUPPLY_PROP_SET_SHIP_MODE, }; static int smb1355_get_prop_batt_charge_type(struct smb1355 *chip, @@ -618,6 +644,10 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_PARALLEL_FCC_MAX: val->intval = chip->max_fcc; break; + case POWER_SUPPLY_PROP_SET_SHIP_MODE: + /* Not in ship mode as long as device is active */ + val->intval = 0; + break; default: pr_err_ratelimited("parallel psy get prop %d not supported\n", prop); @@ -709,6 +739,20 @@ static int smb1355_set_current_max(struct smb1355 *chip, int curr) return rc; } +static int smb1355_clk_request(struct smb1355 *chip, bool enable) +{ + int rc; + + rc = smb1355_masked_force_write(chip, CLOCK_REQUEST_REG, + CLOCK_REQUEST_CMD_BIT, + enable ? CLOCK_REQUEST_CMD_BIT : 0); + if (rc < 0) + pr_err("Couldn't %s clock rc=%d\n", + enable ? "enable" : "disable", rc); + + return rc; +} + static int smb1355_parallel_set_prop(struct power_supply *psy, enum power_supply_property prop, const union power_supply_propval *val) @@ -737,6 +781,10 @@ static int smb1355_parallel_set_prop(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: chip->c_charger_temp_max = val->intval; + case POWER_SUPPLY_PROP_SET_SHIP_MODE: + if (!val->intval) + break; + rc = smb1355_clk_request(chip, false); break; default: pr_debug("parallel power supply set prop %d not supported\n", @@ -917,6 +965,11 @@ static int smb1355_init_hw(struct smb1355 *chip) { int rc; + /* request clock always on */ + rc = smb1355_clk_request(chip, true); + if (rc < 0) + return rc; + /* Change to let SMB1355 only respond to address 0x0C */ rc = smb1355_masked_write(chip, I2C_SS_DIG_PMIC_SID_REG, PMIC_SID_MASK, PMIC_SID0_BIT); @@ -1337,6 +1390,8 @@ static void smb1355_shutdown(struct platform_device *pdev) rc = smb1355_set_parallel_charging(chip, true); if (rc < 0) pr_err("Couldn't disable parallel path rc=%d\n", rc); + + smb1355_clk_request(chip, false); } static struct platform_driver smb1355_driver = { -- GitLab From 9bc8edebc88c404caa964e8c00cd25d23316ea8a Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Wed, 13 Jun 2018 18:19:04 +0530 Subject: [PATCH 0815/1001] power: smb1355: add support for die-temp based mitigation Add support to configure/enable hardware controlled mitigation based on DIE temperature. H/W controlled scheme manipulates charge current(FCC) going though the charger whenever die temperature crosses configured threshold. Change-Id: Icc7ed6d0f5464ba6223745db440087d9aa4909eb Signed-off-by: Ashay Jaiswal Signed-off-by: Umang Agrawal --- .../power/supply/qcom/smb1355-charger.txt | 12 ++ drivers/power/supply/qcom/smb1355-charger.c | 120 +++++++++++++----- 2 files changed, 103 insertions(+), 29 deletions(-) diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb1355-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb1355-charger.txt index 4f12ec09e1f1..528c285a9361 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/smb1355-charger.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/smb1355-charger.txt @@ -51,6 +51,18 @@ Charger specific properties: stacked one after the other and thus all the charge current (FCC) flows through main. In a non-stacked configuration each charger controls the charge current (FCC) separately. + +- qcom,die-temp-threshold-degc + Usage: optional + Value type: + Definition: Specifies DIE temp threshold beyond which h/w starts mitigation. + If not sepcified, 90 degrees centigrade is used. + +- qcom,hw-die-temp-mitigation + Usage: optional + Value type: bool + Definition: Boolean property to enable h/w controlled die temp mitigation. + ================================================ Second Level Nodes - SMB1355 Charger Peripherals ================================================ diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c index d5c6aeb33e63..39a8ea5b8f3c 100644 --- a/drivers/power/supply/qcom/smb1355-charger.c +++ b/drivers/power/supply/qcom/smb1355-charger.c @@ -85,8 +85,12 @@ #define BATIF_CFG_SMISC_BATID_REG (BATIF_BASE + 0x73) #define CFG_SMISC_RBIAS_EXT_CTRL_BIT BIT(2) -#define SMB2CHGS_BATIF_ENG_SMISC_DIETEMP (BATIF_BASE + 0xC0) +#define SMB2CHG_BATIF_ENG_SMISC_DIETEMP (BATIF_BASE + 0xC0) #define TDIE_COMPARATOR_THRESHOLD GENMASK(5, 0) +#define DIE_LOW_RANGE_BASE_DEGC 34 +#define DIE_LOW_RANGE_DELTA 16 +#define DIE_LOW_RANGE_MAX_DEGC 97 +#define DIE_LOW_RANGE_SHIFT 4 #define BATIF_ENG_SCMISC_SPARE1_REG (BATIF_BASE + 0xC2) #define EXT_BIAS_PIN_BIT BIT(2) @@ -96,13 +100,10 @@ #define VALLEY_COMPARATOR_EN_BIT BIT(0) #define TEMP_COMP_STATUS_REG (MISC_BASE + 0x07) -#define SKIN_TEMP_RST_HOT_BIT BIT(6) -#define SKIN_TEMP_UB_HOT_BIT BIT(5) -#define SKIN_TEMP_LB_HOT_BIT BIT(4) -#define DIE_TEMP_TSD_HOT_BIT BIT(3) -#define DIE_TEMP_RST_HOT_BIT BIT(2) -#define DIE_TEMP_UB_HOT_BIT BIT(1) -#define DIE_TEMP_LB_HOT_BIT BIT(0) +#define TEMP_RST_HOT_BIT BIT(2) +#define TEMP_UB_HOT_BIT BIT(1) +#define TEMP_LB_HOT_BIT BIT(0) +#define SKIN_TEMP_SHIFT 4 #define MISC_RT_STS_REG (MISC_BASE + 0x10) #define HARD_ILIMIT_RT_STS_BIT BIT(5) @@ -224,6 +225,8 @@ struct smb_dt_props { bool disable_ctm; int pl_mode; int pl_batfet_mode; + bool hw_die_temp_mitigation; + u32 die_temp_threshold; }; struct smb1355 { @@ -251,6 +254,11 @@ struct smb1355 { struct votable *irq_disable_votable; }; +enum { + CONNECTOR_TEMP = 0, + DIE_TEMP, +}; + static bool is_secure(struct smb1355 *chip, int addr) { if (addr == CLOCK_REQUEST_REG) @@ -380,8 +388,7 @@ static void die_temp_work(struct work_struct *work) u8 temp_stat; for (i = 0; i < BIT(5); i++) { - rc = smb1355_masked_write(chip, - SMB2CHGS_BATIF_ENG_SMISC_DIETEMP, + rc = smb1355_masked_write(chip, SMB2CHG_BATIF_ENG_SMISC_DIETEMP, TDIE_COMPARATOR_THRESHOLD, i); if (rc < 0) { pr_err("Couldn't set temp comp threshold rc=%d\n", rc); @@ -400,7 +407,7 @@ static void die_temp_work(struct work_struct *work) continue; } - if (!(temp_stat & DIE_TEMP_UB_HOT_BIT)) { + if (!(temp_stat & TEMP_UB_HOT_BIT)) { /* found the temp */ break; } @@ -466,6 +473,7 @@ static int smb1355_determine_initial_status(struct smb1355 *chip) return 0; } +#define DEFAULT_DIE_TEMP_LOW_THRESHOLD 90 static int smb1355_parse_dt(struct smb1355 *chip) { struct device_node *node = chip->dev->of_node; @@ -496,6 +504,15 @@ static int smb1355_parse_dt(struct smb1355 *chip) if (of_property_read_bool(node, "qcom,stacked-batfet")) chip->dt.pl_batfet_mode = POWER_SUPPLY_PL_STACKED_BATFET; + chip->dt.hw_die_temp_mitigation = of_property_read_bool(node, + "qcom,hw-die-temp-mitigation"); + + chip->dt.die_temp_threshold = DEFAULT_DIE_TEMP_LOW_THRESHOLD; + of_property_read_u32(node, "qcom,die-temp-threshold-degc", + &chip->dt.die_temp_threshold); + if (chip->dt.die_temp_threshold > DIE_LOW_RANGE_MAX_DEGC) + chip->dt.die_temp_threshold = DIE_LOW_RANGE_MAX_DEGC; + return 0; } @@ -521,6 +538,7 @@ static enum power_supply_property smb1355_parallel_props[] = { POWER_SUPPLY_PROP_MIN_ICL, POWER_SUPPLY_PROP_CURRENT_MAX, POWER_SUPPLY_PROP_SET_SHIP_MODE, + POWER_SUPPLY_PROP_DIE_HEALTH, }; static int smb1355_get_prop_batt_charge_type(struct smb1355 *chip, @@ -547,10 +565,13 @@ static int smb1355_get_prop_batt_charge_type(struct smb1355 *chip, return rc; } -static int smb1355_get_prop_connector_health(struct smb1355 *chip) +static int smb1355_get_prop_health(struct smb1355 *chip, int type) { u8 temp; - int rc; + int rc, shift; + + /* Connector-temp uses skin-temp configuration */ + shift = (type == CONNECTOR_TEMP) ? SKIN_TEMP_SHIFT : 0; rc = smb1355_read(chip, TEMP_COMP_STATUS_REG, &temp); if (rc < 0) { @@ -558,13 +579,13 @@ static int smb1355_get_prop_connector_health(struct smb1355 *chip) return POWER_SUPPLY_HEALTH_UNKNOWN; } - if (temp & SKIN_TEMP_RST_HOT_BIT) + if (temp & (TEMP_RST_HOT_BIT << shift)) return POWER_SUPPLY_HEALTH_OVERHEAT; - if (temp & SKIN_TEMP_UB_HOT_BIT) + if (temp & (TEMP_UB_HOT_BIT << shift)) return POWER_SUPPLY_HEALTH_HOT; - if (temp & SKIN_TEMP_LB_HOT_BIT) + if (temp & (TEMP_LB_HOT_BIT << shift)) return POWER_SUPPLY_HEALTH_WARM; return POWER_SUPPLY_HEALTH_COOL; @@ -597,7 +618,17 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, val->intval = chip->die_temp_deciDegC; break; case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: - val->intval = chip->c_charger_temp_max; + /* + * In case of h/w controlled die_temp mitigation, + * die_temp/die_temp_max can not be reported as this + * requires run time manipulation of DIE_TEMP low + * threshold which will interfere with h/w mitigation + * scheme. + */ + if (chip->dt.hw_die_temp_mitigation) + val->intval = -EINVAL; + else + val->intval = chip->c_charger_temp_max; break; case POWER_SUPPLY_PROP_INPUT_SUSPEND: val->intval = chip->disabled; @@ -618,10 +649,14 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CONNECTOR_HEALTH: if (chip->c_health == -EINVAL) - val->intval = smb1355_get_prop_connector_health(chip); + val->intval = smb1355_get_prop_health(chip, + CONNECTOR_TEMP); else val->intval = chip->c_health; break; + case POWER_SUPPLY_PROP_DIE_HEALTH: + val->intval = smb1355_get_prop_health(chip, DIE_TEMP); + break; case POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE: val->intval = chip->dt.pl_batfet_mode; break; @@ -691,13 +726,16 @@ static int smb1355_set_parallel_charging(struct smb1355 *chip, bool disable) } chip->die_temp_deciDegC = -EINVAL; - if (disable) { - chip->exit_die_temp = true; - cancel_delayed_work_sync(&chip->die_temp_work); - } else { - /* start the work to measure temperature */ - chip->exit_die_temp = false; - schedule_delayed_work(&chip->die_temp_work, 0); + /* Only enable temperature measurement for s/w based mitigation */ + if (!chip->dt.hw_die_temp_mitigation) { + if (disable) { + chip->exit_die_temp = true; + cancel_delayed_work_sync(&chip->die_temp_work); + } else { + /* start the work to measure temperature */ + chip->exit_die_temp = false; + schedule_delayed_work(&chip->die_temp_work, 0); + } } if (chip->irq_disable_votable) @@ -964,6 +1002,7 @@ static int smb1355_tskin_sensor_config(struct smb1355 *chip) static int smb1355_init_hw(struct smb1355 *chip) { int rc; + u8 val, range; /* request clock always on */ rc = smb1355_clk_request(chip, true); @@ -1040,13 +1079,35 @@ static int smb1355_init_hw(struct smb1355 *chip) return rc; } + /* Configure DIE temp Low threshold */ + if (chip->dt.hw_die_temp_mitigation) { + range = (chip->dt.die_temp_threshold - DIE_LOW_RANGE_BASE_DEGC) + / (DIE_LOW_RANGE_DELTA); + val = (chip->dt.die_temp_threshold + - ((range * DIE_LOW_RANGE_DELTA) + + DIE_LOW_RANGE_BASE_DEGC)) + % DIE_LOW_RANGE_DELTA; + + rc = smb1355_masked_write(chip, SMB2CHG_BATIF_ENG_SMISC_DIETEMP, + TDIE_COMPARATOR_THRESHOLD, + (range << DIE_LOW_RANGE_SHIFT) | val); + if (rc < 0) { + pr_err("Couldn't set temp comp threshold rc=%d\n", rc); + return rc; + } + } + /* - * Enable thermal Die temperature comparator source and disable hw - * mitigation for skin/die + * Enable thermal Die temperature comparator source and + * enable hardware controlled current adjustment for die temp + * if charger is configured in h/w controlled die temp mitigation. */ + val = THERMREG_DIE_CMP_SRC_EN_BIT; + if (!chip->dt.hw_die_temp_mitigation) + val |= BYP_THERM_CHG_CURR_ADJUST_BIT; rc = smb1355_masked_write(chip, MISC_THERMREG_SRC_CFG_REG, THERMREG_DIE_CMP_SRC_EN_BIT | BYP_THERM_CHG_CURR_ADJUST_BIT, - THERMREG_DIE_CMP_SRC_EN_BIT | BYP_THERM_CHG_CURR_ADJUST_BIT); + val); if (rc < 0) { pr_err("Couldn't set Skin temperature comparator src rc=%d\n", rc); @@ -1057,8 +1118,9 @@ static int smb1355_init_hw(struct smb1355 *chip) * Disable hysterisis for die temperature. This is so that sw can run * stepping scheme quickly */ + val = chip->dt.hw_die_temp_mitigation ? DIE_TEMP_COMP_HYST_BIT : 0; rc = smb1355_masked_write(chip, BATIF_ENG_SCMISC_SPARE1_REG, - DIE_TEMP_COMP_HYST_BIT, 0); + DIE_TEMP_COMP_HYST_BIT, val); if (rc < 0) { pr_err("Couldn't disable hyst. for die rc=%d\n", rc); return rc; -- GitLab From 330bd0997f73704695f91f1d4e6ba4f132e5783d Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Mon, 27 Nov 2017 15:46:26 +0530 Subject: [PATCH 0816/1001] battery: fix ordering of ICL/FCC configuration Current parallel design has fixed order of configuring ICL/FCC between main and parallel charger, this could lead to a situation where total(main + parallel) ICL/FCC goes beyond maximum configured value. Fix this by dynamic ordering of ICL/FCC between main and parallel based on AICL change. CRs-Fixed: 2148379 Change-Id: Ia1ff7093d1de9205ce8072760c80ba0a58638462 Signed-off-by: Ashay Jaiswal Signed-off-by: Umang Agrawal --- drivers/power/supply/qcom/battery.c | 116 +++++++++++++++++++++------- 1 file changed, 89 insertions(+), 27 deletions(-) diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index f72ade2f2ece..5b9da48edb55 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -155,22 +155,52 @@ static void split_settled(struct pl_data *chip) total_current_ua = pval.intval; } - pval.intval = total_current_ua - slave_ua; - /* Set ICL on main charger */ - rc = power_supply_set_property(chip->main_psy, + /* + * If there is an increase in slave share + * (Also handles parallel enable case) + * Set Main ICL then slave ICL + * else + * (Also handles parallel disable case) + * Set slave ICL then main ICL. + */ + if (slave_ua > chip->pl_settled_ua) { + pval.intval = total_current_ua - slave_ua; + /* Set ICL on main charger */ + rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); - if (rc < 0) { - pr_err("Couldn't change slave suspend state rc=%d\n", rc); - return; - } + if (rc < 0) { + pr_err("Couldn't change slave suspend state rc=%d\n", + rc); + return; + } - /* set parallel's ICL could be 0mA when pl is disabled */ - pval.intval = slave_ua; - rc = power_supply_set_property(chip->pl_psy, - POWER_SUPPLY_PROP_CURRENT_MAX, &pval); - if (rc < 0) { - pr_err("Couldn't set parallel icl, rc=%d\n", rc); - return; + /* set parallel's ICL could be 0mA when pl is disabled */ + pval.intval = slave_ua; + rc = power_supply_set_property(chip->pl_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, &pval); + if (rc < 0) { + pr_err("Couldn't set parallel icl, rc=%d\n", rc); + return; + } + } else { + /* set parallel's ICL could be 0mA when pl is disabled */ + pval.intval = slave_ua; + rc = power_supply_set_property(chip->pl_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, &pval); + if (rc < 0) { + pr_err("Couldn't set parallel icl, rc=%d\n", rc); + return; + } + + pval.intval = total_current_ua - slave_ua; + /* Set ICL on main charger */ + rc = power_supply_set_property(chip->main_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, &pval); + if (rc < 0) { + pr_err("Couldn't change slave suspend state rc=%d\n", + rc); + return; + } } chip->total_settled_ua = total_settled_ua; @@ -634,24 +664,56 @@ static int pl_disable_vote_callback(struct votable *votable, get_fcc_split(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua); - chip->slave_fcc_ua = slave_fcc_ua; + /* + * If there is an increase in slave share + * (Also handles parallel enable case) + * Set Main ICL then slave FCC + * else + * (Also handles parallel disable case) + * Set slave ICL then main FCC. + */ + if (slave_fcc_ua > chip->slave_fcc_ua) { + pval.intval = master_fcc_ua; + rc = power_supply_set_property(chip->main_psy, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, + &pval); + if (rc < 0) { + pr_err("Could not set main fcc, rc=%d\n", rc); + return rc; + } - pval.intval = master_fcc_ua; - rc = power_supply_set_property(chip->main_psy, + pval.intval = slave_fcc_ua; + rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); - if (rc < 0) { - pr_err("Could not set main fcc, rc=%d\n", rc); - return rc; - } + if (rc < 0) { + pr_err("Couldn't set parallel fcc, rc=%d\n", + rc); + return rc; + } - pval.intval = slave_fcc_ua; - rc = power_supply_set_property(chip->pl_psy, + chip->slave_fcc_ua = slave_fcc_ua; + } else { + pval.intval = slave_fcc_ua; + rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); - if (rc < 0) { - pr_err("Couldn't set parallel fcc, rc=%d\n", rc); - return rc; + if (rc < 0) { + pr_err("Couldn't set parallel fcc, rc=%d\n", + rc); + return rc; + } + + chip->slave_fcc_ua = slave_fcc_ua; + + pval.intval = master_fcc_ua; + rc = power_supply_set_property(chip->main_psy, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, + &pval); + if (rc < 0) { + pr_err("Could not set main fcc, rc=%d\n", rc); + return rc; + } } /* -- GitLab From b4d329253099619c41e0188c0e506addb0b41e72 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Thu, 2 Nov 2017 10:09:14 +0530 Subject: [PATCH 0817/1001] qcom: battery: update FCC split policy Use BATFET configuration exposed by parallel charger for FCC split. In case of Stacked-BATFET main charger configured to full FCC and parallel charger configured to 50% FCC and in case of Non-Stacked-BATFET main charger configured to 50% FCC and parallel charger configured to 50% FCC. Change-Id: Ic75dd883a24fc4f87ecbd40c1d33249c18250fee Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/battery.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 5b9da48edb55..817f9c18c812 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -47,6 +47,7 @@ struct pl_data { int pl_mode; + int pl_batfet_mode; int slave_pct; int slave_fcc_ua; int restricted_current; @@ -375,11 +376,11 @@ static void get_fcc_split(struct pl_data *chip, int total_ua, *slave_ua = (slave_limited_ua * chip->slave_pct) / 100; /* - * In USBIN_USBIN configuration with internal rsense parallel - * charger's current goes through main charger's BATFET, keep - * the main charger's FCC to the votable result. + * In stacked BATFET configuration charger's current goes + * through main charger's BATFET, keep the main charger's FCC + * to the votable result. */ - if (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) + if (chip->pl_batfet_mode == POWER_SUPPLY_PL_STACKED_BATFET) *master_ua = max(0, total_ua); else *master_ua = max(0, total_ua - *slave_ua); @@ -868,6 +869,15 @@ static bool is_parallel_available(struct pl_data *chip) return false; } + rc = power_supply_get_property(chip->pl_psy, + POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE, &pval); + if (rc < 0) { + pr_err("Couldn't get parallel batfet mode rc=%d\n", + rc); + return false; + } + chip->pl_batfet_mode = pval.intval; + vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0); return true; -- GitLab From bfaea1852eafa501ba9536dd9efe36f0efb9cf6c Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Mon, 13 Nov 2017 18:35:28 +0530 Subject: [PATCH 0818/1001] qcom: battery: update ICL split logic Add support to read minimum input current limit (ICL) supported by parallel charger. Disable parallel charging if the parallel's ICL share does not meet this criteria. Change-Id: I2ac442aa090245b8f9d68ac555e26fcdfb26bc8b Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/battery.c | 148 +++++++++++++++++++++------- 1 file changed, 110 insertions(+), 38 deletions(-) diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 817f9c18c812..45baa2217f9a 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -44,10 +44,12 @@ #define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER" #define USBIN_I_VOTER "USBIN_I_VOTER" #define PL_FCC_LOW_VOTER "PL_FCC_LOW_VOTER" +#define ICL_LIMIT_VOTER "ICL_LIMIT_VOTER" struct pl_data { int pl_mode; int pl_batfet_mode; + int pl_min_icl_ua; int slave_pct; int slave_fcc_ua; int restricted_current; @@ -98,6 +100,8 @@ module_param_named(debug_mask, debug_mask, int, 0600); pr_debug(fmt, ##__VA_ARGS__); \ } while (0) +#define IS_USBIN(mode) ((mode == POWER_SUPPLY_PL_USBIN_USBIN) \ + || (mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) enum { VER = 0, SLAVE_PCT, @@ -108,19 +112,19 @@ enum { /******* * ICL * ********/ -static void split_settled(struct pl_data *chip) +static int get_settled_split(struct pl_data *chip, int *main_icl_ua, + int *slave_icl_ua, int *total_settled_icl_ua) { int slave_icl_pct, total_current_ua; int slave_ua = 0, main_settled_ua = 0; union power_supply_propval pval = {0, }; int rc, total_settled_ua = 0; - if ((chip->pl_mode != POWER_SUPPLY_PL_USBIN_USBIN) - && (chip->pl_mode != POWER_SUPPLY_PL_USBIN_USBIN_EXT)) - return; + if (!IS_USBIN(chip->pl_mode)) + return -EINVAL; if (!chip->main_psy) - return; + return -EINVAL; if (!get_effective_result_locked(chip->pl_disable_votable)) { /* read the aicl settled value */ @@ -128,11 +132,10 @@ static void split_settled(struct pl_data *chip) POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval); if (rc < 0) { pr_err("Couldn't get aicl settled value rc=%d\n", rc); - return; + return rc; } main_settled_ua = pval.intval; - /* slave gets 10 percent points less for ICL */ - slave_icl_pct = max(0, chip->slave_pct - 10); + slave_icl_pct = max(0, chip->slave_pct); slave_ua = ((main_settled_ua + chip->pl_settled_ua) * slave_icl_pct) / 100; total_settled_ua = main_settled_ua + chip->pl_settled_ua; @@ -144,18 +147,63 @@ static void split_settled(struct pl_data *chip) chip->usb_psy = power_supply_get_by_name("usb"); if (!chip->usb_psy) { pr_err("Couldn't get usbpsy while splitting settled\n"); - return; + return -ENOENT; } /* no client is voting, so get the total current from charger */ rc = power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_HW_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't get max current rc=%d\n", rc); - return; + return rc; } total_current_ua = pval.intval; } + *main_icl_ua = total_current_ua - slave_ua; + *slave_icl_ua = slave_ua; + *total_settled_icl_ua = total_settled_ua; + + pl_dbg(chip, PR_PARALLEL, + "Split total_current_ua=%d total_settled_ua=%d main_settled_ua=%d slave_ua=%d\n", + total_current_ua, total_settled_ua, main_settled_ua, slave_ua); + + return 0; +} + +static int validate_parallel_icl(struct pl_data *chip, bool *disable) +{ + int rc = 0; + int main_ua = 0, slave_ua = 0, total_settled_ua = 0; + + if (!IS_USBIN(chip->pl_mode) + || get_effective_result_locked(chip->pl_disable_votable)) + return 0; + + rc = get_settled_split(chip, &main_ua, &slave_ua, &total_settled_ua); + if (rc < 0) { + pr_err("Couldn't get split current rc=%d\n", rc); + return rc; + } + + if (slave_ua < chip->pl_min_icl_ua) + *disable = true; + else + *disable = false; + + return 0; +} + +static void split_settled(struct pl_data *chip) +{ + union power_supply_propval pval = {0, }; + int rc, main_ua, slave_ua, total_settled_ua; + + rc = get_settled_split(chip, &main_ua, &slave_ua, &total_settled_ua); + if (rc < 0) { + pr_err("Couldn't get split current rc=%d\n", rc); + return; + } + /* * If there is an increase in slave share * (Also handles parallel enable case) @@ -165,7 +213,7 @@ static void split_settled(struct pl_data *chip) * Set slave ICL then main ICL. */ if (slave_ua > chip->pl_settled_ua) { - pval.intval = total_current_ua - slave_ua; + pval.intval = main_ua; /* Set ICL on main charger */ rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); @@ -193,7 +241,7 @@ static void split_settled(struct pl_data *chip) return; } - pval.intval = total_current_ua - slave_ua; + pval.intval = main_ua; /* Set ICL on main charger */ rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); @@ -207,9 +255,6 @@ static void split_settled(struct pl_data *chip) chip->total_settled_ua = total_settled_ua; chip->pl_settled_ua = slave_ua; - pl_dbg(chip, PR_PARALLEL, - "Split total_current_ua=%d main_settled_ua=%d slave_ua=%d\n", - total_current_ua, main_settled_ua, slave_ua); } static ssize_t version_show(struct class *c, struct class_attribute *attr, @@ -235,14 +280,21 @@ static ssize_t slave_pct_show(struct class *c, struct class_attribute *attr, static ssize_t slave_pct_store(struct class *c, struct class_attribute *attr, const char *ubuf, size_t count) { - struct pl_data *chip = container_of(c, struct pl_data, - qcom_batt_class); + struct pl_data *chip = container_of(c, struct pl_data, qcom_batt_class); + int rc; unsigned long val; + bool disable = false; if (kstrtoul(ubuf, 10, &val)) return -EINVAL; chip->slave_pct = val; + + rc = validate_parallel_icl(chip, &disable); + if (rc < 0) + return rc; + + vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, disable, 0); rerun_election(chip->fcc_votable); rerun_election(chip->fv_votable); split_settled(chip); @@ -256,7 +308,7 @@ static struct class_attribute class_attr_slave_pct = * RESTRICTED CHARGIGNG * ************************/ static ssize_t restrict_chg_show(struct class *c, struct class_attribute *attr, - char *ubuf) + char *ubuf) { struct pl_data *chip = container_of(c, struct pl_data, qcom_batt_class); @@ -473,11 +525,9 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, &slave_fcc_ua); if (slave_fcc_ua > MINIMUM_PARALLEL_FCC_UA) { - chip->slave_fcc_ua = slave_fcc_ua; vote(chip->pl_disable_votable, PL_FCC_LOW_VOTER, false, 0); } else { - chip->slave_fcc_ua = 0; vote(chip->pl_disable_votable, PL_FCC_LOW_VOTER, true, 0); } @@ -631,11 +681,9 @@ static int pl_disable_vote_callback(struct votable *votable, { struct pl_data *chip = data; union power_supply_propval pval = {0, }; - int master_fcc_ua, total_fcc_ua, slave_fcc_ua; - int rc; - - chip->total_settled_ua = 0; - chip->pl_settled_ua = 0; + int master_fcc_ua = 0, total_fcc_ua = 0, slave_fcc_ua = 0; + int rc = 0; + bool disable = false; if (!is_main_available(chip)) return -ENODEV; @@ -647,6 +695,16 @@ static int pl_disable_vote_callback(struct votable *votable, cancel_delayed_work_sync(&chip->pl_awake_work); vote(chip->pl_awake_votable, PL_VOTER, true, 0); + rc = validate_parallel_icl(chip, &disable); + if (rc < 0) + return rc; + + if (disable) { + pr_info("Parallel ICL is less than min ICL(%d), skipping parallel enable\n", + chip->pl_min_icl_ua); + return 0; + } + /* enable parallel charging */ rc = power_supply_get_property(chip->pl_psy, POWER_SUPPLY_PROP_CHARGE_TYPE, &pval); @@ -729,8 +787,7 @@ static int pl_disable_vote_callback(struct votable *votable, pr_err("Couldn't change slave suspend state rc=%d\n", rc); - if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) - || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) + if (IS_USBIN(chip->pl_mode)) split_settled(chip); /* * we could have been enabled while in taper mode, @@ -757,8 +814,7 @@ static int pl_disable_vote_callback(struct votable *votable, (master_fcc_ua * 100) / total_fcc_ua, (slave_fcc_ua * 100) / total_fcc_ua); } else { - if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) - || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) + if (IS_USBIN(chip->pl_mode)) split_settled(chip); /* pl_psy may be NULL while in the disable branch */ @@ -781,11 +837,16 @@ static int pl_disable_vote_callback(struct votable *votable, return rc; } + /* reset parallel FCC */ + chip->slave_fcc_ua = 0; rerun_election(chip->fv_votable); cancel_delayed_work_sync(&chip->pl_awake_work); schedule_delayed_work(&chip->pl_awake_work, msecs_to_jiffies(5000)); + + chip->total_settled_ua = 0; + chip->pl_settled_ua = 0; } pl_dbg(chip, PR_PARALLEL, "parallel charging %s\n", @@ -856,8 +917,7 @@ static bool is_parallel_available(struct pl_data *chip) chip->pl_mode = pval.intval; /* Disable autonomous votage increments for USBIN-USBIN */ - if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) - || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) { + if (IS_USBIN(chip->pl_mode)) { if (!chip->hvdcp_hw_inov_dis_votable) chip->hvdcp_hw_inov_dis_votable = find_votable("HVDCP_HW_INOV_DIS"); @@ -878,6 +938,11 @@ static bool is_parallel_available(struct pl_data *chip) } chip->pl_batfet_mode = pval.intval; + pval.intval = 0; + power_supply_get_property(chip->pl_psy, POWER_SUPPLY_PROP_MIN_ICL, + &pval); + chip->pl_min_icl_ua = pval.intval; + vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0); return true; @@ -902,6 +967,7 @@ static void handle_main_charge_type(struct pl_data *chip) vote(chip->pl_disable_votable, TAPER_END_VOTER, false, 0); vote(chip->pl_disable_votable, PL_TAPER_EARLY_BAD_VOTER, false, 0); + vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, false, 0); chip->charge_type = pval.intval; return; } @@ -940,6 +1006,7 @@ static void handle_settled_icl_change(struct pl_data *chip) int main_settled_ua; int main_limited; int total_current_ua; + bool disable = false; total_current_ua = get_effective_result_locked(chip->usb_icl_votable); @@ -975,11 +1042,7 @@ static void handle_settled_icl_change(struct pl_data *chip) rerun_election(chip->fcc_votable); - if (get_effective_result(chip->pl_disable_votable)) - return; - - if (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN - || chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT) { + if (IS_USBIN(chip->pl_mode)) { /* * call aicl split only when USBIN_USBIN and enabled * and if settled current has changed by more than 300mA @@ -993,8 +1056,17 @@ static void handle_settled_icl_change(struct pl_data *chip) /* If ICL change is small skip splitting */ if (abs(new_total_settled_ua - chip->total_settled_ua) - > MIN_ICL_CHANGE_DELTA_UA) - split_settled(chip); + > MIN_ICL_CHANGE_DELTA_UA) { + rc = validate_parallel_icl(chip, &disable); + if (rc < 0) + return; + + vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, + disable, 0); + if (!get_effective_result_locked( + chip->pl_disable_votable)) + split_settled(chip); + } } } -- GitLab From fb86f293117a6cb14d5d2b693f4561406721afd8 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Fri, 15 Dec 2017 18:19:41 +0530 Subject: [PATCH 0819/1001] qcom: battery: add support to detect USB removal Add support to handle USB psy notification and detect USB presence/removal based on USB psy's "POWER_SUPPLY_PROP_PRESENT" property, this is required to ensure all stale votes gets removed on charger removal. CRs-Fixed: 2155440 Change-Id: I2863aafd88ce798cfb6ba527c3b474aa9f844024 Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/battery.c | 33 +++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 45baa2217f9a..de2fbd6c8e19 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -964,10 +964,6 @@ static void handle_main_charge_type(struct pl_data *chip) if ((pval.intval != POWER_SUPPLY_CHARGE_TYPE_FAST) && (pval.intval != POWER_SUPPLY_CHARGE_TYPE_TAPER)) { vote(chip->pl_disable_votable, CHG_STATE_VOTER, true, 0); - vote(chip->pl_disable_votable, TAPER_END_VOTER, false, 0); - vote(chip->pl_disable_votable, PL_TAPER_EARLY_BAD_VOTER, - false, 0); - vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, false, 0); chip->charge_type = pval.intval; return; } @@ -1099,6 +1095,34 @@ static void handle_parallel_in_taper(struct pl_data *chip) } } +static void handle_usb_change(struct pl_data *chip) +{ + int rc; + union power_supply_propval pval = {0, }; + + if (!chip->usb_psy) + chip->usb_psy = power_supply_get_by_name("usb"); + if (!chip->usb_psy) { + pr_err("Couldn't get usbpsy\n"); + return; + } + + rc = power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_PRESENT, &pval); + if (rc < 0) { + pr_err("Couldn't get present from USB rc=%d\n", rc); + return; + } + + if (!pval.intval) { + /* USB removed: remove all stale votes */ + vote(chip->pl_disable_votable, TAPER_END_VOTER, false, 0); + vote(chip->pl_disable_votable, PL_TAPER_EARLY_BAD_VOTER, + false, 0); + vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, false, 0); + } +} + static void status_change_work(struct work_struct *work) { struct pl_data *chip = container_of(work, @@ -1123,6 +1147,7 @@ static void status_change_work(struct work_struct *work) is_parallel_available(chip); + handle_usb_change(chip); handle_main_charge_type(chip); handle_settled_icl_change(chip); handle_parallel_in_taper(chip); -- GitLab From 833fba97c6a122b7c6435205b4c7f15f21d2fbbb Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Tue, 23 Jan 2018 18:32:58 -0800 Subject: [PATCH 0820/1001] qcom: battery: Modify FCC split logic to use slave's limit Currently, the parallel (slave) charger's share of FCC is limited by only the BCL. Since SMB1354 can only supply a max of 2.5A FCC, this can result in a "loss" of current in situations where it is allocated > 2.5A of current as a result of the existing FCC split logic. For example, if the SMB1354 is allocated 3A, the total FCC (main + charger) will be short by 0.5A (3 - 2.5) because of the charger's FCC limit. Therefore, modify FCC split logic to use the parallel charger's FCC limit to further restrict parallel's portion of FCC. This will ensure that any current that exceeds 2.5A will be part of the main's share. CRs-Fixed: 2170280 Change-Id: I01cd13d509a37963370c4dc2c815500fd1e821b9 Signed-off-by: Guru Das Srinagesh Signed-off-by: Umang Agrawal --- drivers/power/supply/qcom/battery.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index de2fbd6c8e19..95554d080542 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -73,6 +73,7 @@ struct pl_data { int charge_type; int total_settled_ua; int pl_settled_ua; + int pl_fcc_max; u32 wa_flags; struct class qcom_batt_class; struct wakeup_source *pl_ws; @@ -426,6 +427,7 @@ static void get_fcc_split(struct pl_data *chip, int total_ua, effective_total_ua = max(0, total_ua + hw_cc_delta_ua); slave_limited_ua = min(effective_total_ua, bcl_ua); *slave_ua = (slave_limited_ua * chip->slave_pct) / 100; + *slave_ua = min(*slave_ua, chip->pl_fcc_max); /* * In stacked BATFET configuration charger's current goes @@ -943,6 +945,12 @@ static bool is_parallel_available(struct pl_data *chip) &pval); chip->pl_min_icl_ua = pval.intval; + chip->pl_fcc_max = INT_MAX; + rc = power_supply_get_property(chip->pl_psy, + POWER_SUPPLY_PROP_PARALLEL_FCC_MAX, &pval); + if (!rc) + chip->pl_fcc_max = pval.intval; + vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0); return true; -- GitLab From c13680943be72ad53f7fb811cb34e57873156957 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Fri, 11 May 2018 17:25:58 +0530 Subject: [PATCH 0821/1001] power: smb5: enable parallel charging support Enable parallel charging support in charger driver: - Configure STAT CMD in main charger, which enables parallel chip. - Only disable hvdcp hw INOV for PMI8998/PM660, for all new platforms hw INOV is disabled in main charger. Change-Id: I84037ca93c9801b28e47157923817413f7091e2c Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/battery.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 95554d080542..9f9c410ab745 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -78,6 +78,7 @@ struct pl_data { struct class qcom_batt_class; struct wakeup_source *pl_ws; struct notifier_block nb; + bool pl_disable; }; struct pl_data *the_chip; @@ -88,6 +89,7 @@ enum print_reason { enum { AICL_RERUN_WA_BIT = BIT(0), + FORCE_INOV_DISABLE_BIT = BIT(1), }; static int debug_mask; @@ -851,6 +853,12 @@ static int pl_disable_vote_callback(struct votable *votable, chip->pl_settled_ua = 0; } + /* notify parallel state change */ + if (chip->pl_psy && (chip->pl_disable != pl_disable)) { + power_supply_changed(chip->pl_psy); + chip->pl_disable = (bool)pl_disable; + } + pl_dbg(chip, PR_PARALLEL, "parallel charging %s\n", pl_disable ? "disabled" : "enabled"); @@ -919,7 +927,8 @@ static bool is_parallel_available(struct pl_data *chip) chip->pl_mode = pval.intval; /* Disable autonomous votage increments for USBIN-USBIN */ - if (IS_USBIN(chip->pl_mode)) { + if (IS_USBIN(chip->pl_mode) + && (chip->wa_flags & FORCE_INOV_DISABLE_BIT)) { if (!chip->hvdcp_hw_inov_dis_votable) chip->hvdcp_hw_inov_dis_votable = find_votable("HVDCP_HW_INOV_DIS"); @@ -1044,7 +1053,6 @@ static void handle_settled_icl_change(struct pl_data *chip) else vote(chip->pl_enable_votable_indirect, USBIN_I_VOTER, true, 0); - rerun_election(chip->fcc_votable); if (IS_USBIN(chip->pl_mode)) { /* @@ -1203,7 +1211,9 @@ static void pl_config_init(struct pl_data *chip, int smb_version) switch (smb_version) { case PMI8998_SUBTYPE: case PM660_SUBTYPE: - chip->wa_flags = AICL_RERUN_WA_BIT; + chip->wa_flags = AICL_RERUN_WA_BIT | FORCE_INOV_DISABLE_BIT; + break; + case PMI632_SUBTYPE: break; default: break; @@ -1304,6 +1314,7 @@ int qcom_batt_init(int smb_version) goto unreg_notifier; } + chip->pl_disable = true; chip->qcom_batt_class.name = "qcom-battery", chip->qcom_batt_class.owner = THIS_MODULE, chip->qcom_batt_class.class_groups = batt_class_groups; -- GitLab From 5f1921ce4c936e467edee10356a8d8e7764572b3 Mon Sep 17 00:00:00 2001 From: Umang Agrawal Date: Thu, 19 Apr 2018 11:02:58 +0530 Subject: [PATCH 0822/1001] power: battery: Allow taper exit if increase in float voltage Due to reduction of float voltage in JEITA condition, taper charging can be initiated at a lower float voltage value. On removal of JEITA condition, float voltage scales back to its default value, but as per current SW design, once taper charging is initiated, the taper-check loop does not exit until parallel is disabled. Due to this, FCC does not scales back to its default value, and parallel too stays disabled leading to slow charging thereafter with lower FCC. Add support to exit taper charging on increase in float voltage if it was initiated on reduced float voltage, due to jeita. Change-Id: I5bc127253f5a303c5b0b05683ce68f0bacd79eda Signed-off-by: Umang Agrawal --- drivers/power/supply/qcom/battery.c | 32 ++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 9f9c410ab745..88c8dc6e0776 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -79,6 +79,7 @@ struct pl_data { struct wakeup_source *pl_ws; struct notifier_block nb; bool pl_disable; + int taper_entry_fv; }; struct pl_data *the_chip; @@ -455,6 +456,7 @@ static void pl_taper_work(struct work_struct *work) int eff_fcc_ua; int total_fcc_ua, master_fcc_ua, slave_fcc_ua = 0; + chip->taper_entry_fv = get_effective_result(chip->fv_votable); chip->taper_work_running = true; while (true) { if (get_effective_result(chip->pl_disable_votable)) { @@ -501,7 +503,25 @@ static void pl_taper_work(struct work_struct *work) vote(chip->fcc_votable, TAPER_STEPPER_VOTER, true, eff_fcc_ua); } else { - pl_dbg(chip, PR_PARALLEL, "master is fast charging; waiting for next taper\n"); + /* + * Due to reduction of float voltage in JEITA condition + * taper charging can be initiated at a lower FV. On + * removal of JEITA condition, FV readjusts itself. + * However, once taper charging is initiated, it doesn't + * exits until parallel chaging is disabled due to which + * FCC doesn't scale back to its original value, leading + * to slow charging thereafter. + * Check if FV increases in comparison to FV at which + * taper charging was initiated, and if yes, exit taper + * charging. + */ + if (get_effective_result(chip->fv_votable) > + chip->taper_entry_fv) { + pl_dbg(chip, PR_PARALLEL, "Float voltage increased. Exiting taper\n"); + goto done; + } else { + pl_dbg(chip, PR_PARALLEL, "master is fast charging; waiting for next taper\n"); + } } /* wait for the charger state to deglitch after FCC change */ msleep(PL_TAPER_WORK_DELAY_MS); @@ -1000,6 +1020,16 @@ static void handle_main_charge_type(struct pl_data *chip) /* handle fast/taper charge entry */ if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER || pval.intval == POWER_SUPPLY_CHARGE_TYPE_FAST) { + /* + * Undo parallel charging termination if entered taper in + * reduced float voltage condition due to jeita mitigation. + */ + if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_FAST && + (chip->taper_entry_fv < + get_effective_result(chip->fv_votable))) { + vote(chip->pl_disable_votable, TAPER_END_VOTER, + false, 0); + } pl_dbg(chip, PR_PARALLEL, "chg_state enabling parallel\n"); vote(chip->pl_disable_votable, CHG_STATE_VOTER, false, 0); chip->charge_type = pval.intval; -- GitLab From 68736f19d1c2ca8ed1cad7deefa8123ab08629d5 Mon Sep 17 00:00:00 2001 From: Umang Agrawal Date: Tue, 22 May 2018 17:05:14 +0530 Subject: [PATCH 0823/1001] power: power_supply: add property for FCC stepper Add power_supply property POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE which reports the state of FCC stepped feature. Change-Id: I0dcbf4a63f30f0003cbb57eaa4e8f1327ed91f7a Signed-off-by: Umang Agrawal --- drivers/power/supply/power_supply_sysfs.c | 1 + include/linux/power_supply.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index f7d2e49e3675..2491252fdbfc 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -382,6 +382,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(esr_nominal), POWER_SUPPLY_ATTR(soh), POWER_SUPPLY_ATTR(force_recharge), + POWER_SUPPLY_ATTR(fcc_stepper_enable), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index a3e179fe58a0..69ca434d09b4 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -308,6 +308,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_ESR_NOMINAL, POWER_SUPPLY_PROP_SOH, POWER_SUPPLY_PROP_FORCE_RECHARGE, + POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, /* Local extensions of type int64_t */ POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT, /* Properties of type `const char *' */ -- GitLab From 86c8712a94e8c162f32aec030bcbfa25e82383cb Mon Sep 17 00:00:00 2001 From: Alexei Avshalom Lazar Date: Thu, 16 Aug 2018 13:53:27 +0300 Subject: [PATCH 0824/1001] wil6210: add support for channel 4 wil6210 supports channels 1-3 of the 60GHz band. New FW added support for channel 4. Add support for channel 4 also in wil6210 driver. Change-Id: I0efce5ebc848ff546d10d52a511b34a9d54f2771 Signed-off-by: Alexei Avshalom Lazar Signed-off-by: Maya Erez --- drivers/net/wireless/ath/wil6210/cfg80211.c | 22 ++++++++++++++++++++- drivers/net/wireless/ath/wil6210/main.c | 2 ++ drivers/net/wireless/ath/wil6210/wil6210.h | 2 ++ drivers/net/wireless/ath/wil6210/wmi.h | 1 + 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 6a4a3edbaa81..cc8bfbc4b76a 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -61,7 +61,7 @@ static struct ieee80211_channel wil_60ghz_channels[] = { CHAN60G(1, 0), CHAN60G(2, 0), CHAN60G(3, 0), -/* channel 4 not supported yet */ + CHAN60G(4, 0), }; enum wil_nl_60g_cmd_type { @@ -107,6 +107,26 @@ struct wil_nl_60g_debug_force_wmi { u32 enable; } __packed; +static int wil_num_supported_channels(struct wil6210_priv *wil) +{ + int num_channels = ARRAY_SIZE(wil_60ghz_channels); + + if (!test_bit(WMI_FW_CAPABILITY_CHANNEL_4, wil->fw_capabilities)) + num_channels--; + + return num_channels; +} + +void update_supported_bands(struct wil6210_priv *wil) +{ + struct wiphy *wiphy = wil_to_wiphy(wil); + + wil_dbg_misc(wil, "update supported bands"); + + wiphy->bands[NL80211_BAND_60GHZ]->n_channels = + wil_num_supported_channels(wil); +} + /* Vendor id to be used in vendor specific command and events * to user space. * NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID, diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index fb0da63c6322..d749ed8d3bcf 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1158,6 +1158,8 @@ void wil_refresh_fw_capabilities(struct wil6210_priv *wil) wil->max_agg_wsize = WIL_MAX_AGG_WSIZE; wil->max_ampdu_size = WIL_MAX_AMPDU_SIZE; } + + update_supported_bands(wil); } void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 766c986e0fb7..e03ab272daa8 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1427,4 +1427,6 @@ int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid, u8 token, u16 status, bool amsdu, u16 agg_wsize, u16 timeout); +void update_supported_bands(struct wil6210_priv *wil); + #endif /* __WIL6210_H__ */ diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 30a7a61fbbf0..c07fca09818f 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -105,6 +105,7 @@ enum wmi_fw_capability { WMI_FW_CAPABILITY_AMSDU = 23, WMI_FW_CAPABILITY_RAW_MODE = 24, WMI_FW_CAPABILITY_TX_REQ_EXT = 25, + WMI_FW_CAPABILITY_CHANNEL_4 = 26, WMI_FW_CAPABILITY_MAX, }; -- GitLab From 55bd11baf8b8a2b9d6989ebd93f09c8507f60e7f Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Tue, 17 May 2016 11:43:54 +0530 Subject: [PATCH 0825/1001] USB: core: Add USB_DEVICE_ERROR uevent for enumeration timeout Some userspace modules expect USB driver to send event to userspace, when usb device enumeration failure with device descriptor read errors. Add USB_DEVICE_ERROR uevent in the USB driver to explicitly send the ERROR uevent for such case. Change-Id: I7128869ff0700ab90d4c949de24cd03c5c90e22e Signed-off-by: Chandana Kishori Chiluveru Signed-off-by: Ajay Agarwal --- drivers/usb/core/hub.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 6d94d96dc2e5..cc2a4c432316 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -4368,6 +4368,8 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, const char *speed; int devnum = udev->devnum; const char *driver_name; + char *error_event[] = { + "USB_DEVICE_ERROR=Device_No_Response", NULL }; /* root hub ports have a slightly longer reset period * (from USB 2.0 spec, section 7.1.7.5) @@ -4555,6 +4557,8 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, if (r != -ENODEV) dev_err(&udev->dev, "device descriptor read/64, error %d\n", r); + kobject_uevent_env(&udev->parent->dev.kobj, + KOBJ_CHANGE, error_event); retval = -EMSGSIZE; continue; } @@ -4607,6 +4611,8 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, dev_err(&udev->dev, "device descriptor read/8, error %d\n", retval); + kobject_uevent_env(&udev->parent->dev.kobj, + KOBJ_CHANGE, error_event); if (retval >= 0) retval = -EMSGSIZE; } else { -- GitLab From 28cc5c521b21f92fa6f8a5a6be16960100f70a7a Mon Sep 17 00:00:00 2001 From: Hardik Arya Date: Wed, 8 Aug 2018 14:46:20 +0530 Subject: [PATCH 0826/1001] diag: Update msg mask's ranges properly There is a possibility of out-of-bound read if msg mask ranges received from peripheral are more than max ssid per range. Cap msg mask's ssid ranges to MAX_SSID_PER_RANGE if ranges received from peripheral are greater than the same. Change-Id: I886692ad223e16678bfaecbe381c62fdf3503cb5 Signed-off-by: Hardik Arya --- drivers/char/diag/diagfwd_cntl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c index e9e964cbf234..1d3de3dd1644 100644 --- a/drivers/char/diag/diagfwd_cntl.c +++ b/drivers/char/diag/diagfwd_cntl.c @@ -519,7 +519,12 @@ static int update_msg_mask_tbl_entry(struct diag_msg_mask_t *mask, } if (range->ssid_last >= mask->ssid_last) { temp_range = range->ssid_last - mask->ssid_first + 1; - mask->ssid_last = range->ssid_last; + if (temp_range > MAX_SSID_PER_RANGE) { + temp_range = MAX_SSID_PER_RANGE; + mask->ssid_last = mask->ssid_first + temp_range - 1; + } else + mask->ssid_last = range->ssid_last; + mask->ssid_last_tools = mask->ssid_last; mask->range = temp_range; } -- GitLab From ab2b40863cdef4e9dae82df5f0ed67e876bb9302 Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Tue, 14 Aug 2018 00:40:27 +0530 Subject: [PATCH 0827/1001] ARM: dts: msm: Add measure support ddr clock for SM6150 Add an additional MC_CC debug base to map the mc clock period register used to calculate the frequency of the MC clock. Change the name of the measure_only_bimc_clk to better reflect the name of the clock(memory controller clock controller) we're trying to measure. Change-Id: I89c460113567166dd4a58fb04ede0d5a7c9ef6f2 Signed-off-by: Odelu Kukatla --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 6 ++++++ drivers/clk/qcom/debugcc-sm6150.c | 11 ++++++++--- drivers/clk/qcom/gcc-sm6150.c | 6 +++--- include/dt-bindings/clock/qcom,gcc-sm6150.h | 2 +- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index b40d15341b4d..3a52fe4de639 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -1074,6 +1074,11 @@ reg = <0x182a0018 0x4>; }; + mccc_debug: syscon@90b0000 { + compatible = "syscon"; + reg = <0x90b0000 0x1000>; + }; + clock_cpucc: qcom,cpucc@18321000 { compatible = "qcom,clk-cpu-osm-sm6150"; reg = <0x18321000 0x1400>, @@ -1094,6 +1099,7 @@ qcom,dispcc = <&clock_dispcc>; qcom,gpucc = <&clock_gpucc>; qcom,cpucc = <&cpucc_debug>; + qcom,mccc = <&mccc_debug>; clock-names = "cxo"; clocks = <&clock_rpmh RPMH_CXO_CLK>; #clock-cells = <1>; diff --git a/drivers/clk/qcom/debugcc-sm6150.c b/drivers/clk/qcom/debugcc-sm6150.c index 31a32b5a98d1..42ca11807240 100644 --- a/drivers/clk/qcom/debugcc-sm6150.c +++ b/drivers/clk/qcom/debugcc-sm6150.c @@ -240,7 +240,7 @@ static const char *const debug_mux_parent_names[] = { "gpu_cc_gx_qdss_tsctr_clk", "gpu_cc_gx_vsense_clk", "gpu_cc_sleep_clk", - "measure_only_bimc_clk", + "measure_only_mccc_clk", "measure_only_cnoc_clk", "measure_only_ipa_2x_clk", "measure_only_snoc_clk", @@ -269,6 +269,7 @@ static struct clk_debug_mux gcc_debug_mux = { .src_sel_shift = 0, .post_div_mask = 0xF, .post_div_shift = 0, + .period_offset = 0x50, MUX_SRC_LIST( { "cam_cc_bps_ahb_clk", 0x46, 1, CAM_CC, 0xE, 0xFF, 0, 0x3, 0, 2, 0xC000, 0xC004, 0xC008 }, @@ -684,8 +685,8 @@ static struct clk_debug_mux gcc_debug_mux = { 0xC, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, { "gpu_cc_sleep_clk", 0x144, 1, GPU_CC, 0x16, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, - { "measure_only_bimc_clk", 0xC2, 1, GCC, - 0xBF, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, + { "measure_only_mccc_clk", 0xC2, 1, MC_CC, + 0xC2, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "measure_only_cnoc_clk", 0x15, 1, GCC, 0x15, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "measure_only_ipa_2x_clk", 0x128, 1, GCC, @@ -797,6 +798,10 @@ static int clk_debug_sm6150_probe(struct platform_device *pdev) if (ret) return ret; + ret = map_debug_bases(pdev, "qcom,mccc", MC_CC); + if (ret) + return ret; + clk = devm_clk_register(&pdev->dev, &gcc_debug_mux.hw); if (IS_ERR(clk)) { dev_err(&pdev->dev, "Unable to register GCC debug mux\n"); diff --git a/drivers/clk/qcom/gcc-sm6150.c b/drivers/clk/qcom/gcc-sm6150.c index 99d716f9f7c3..ccab586d913c 100644 --- a/drivers/clk/qcom/gcc-sm6150.c +++ b/drivers/clk/qcom/gcc-sm6150.c @@ -3191,10 +3191,10 @@ static struct clk_branch gcc_usb2_sec_clkref_clk = { }; /* Measure-only clock for ddrss_gcc_debug_clk. */ -static struct clk_dummy measure_only_bimc_clk = { +static struct clk_dummy measure_only_mccc_clk = { .rrate = 1000, .hw.init = &(struct clk_init_data){ - .name = "measure_only_bimc_clk", + .name = "measure_only_mccc_clk", .ops = &clk_dummy_ops, }, }; @@ -3228,7 +3228,7 @@ static struct clk_dummy measure_only_snoc_clk = { struct clk_hw *gcc_sm6150_hws[] = { [GPLL0_OUT_AUX2] = &gpll0_out_aux2.hw, - [MEASURE_ONLY_BIMC_CLK] = &measure_only_bimc_clk.hw, + [MEASURE_ONLY_MMCC_CLK] = &measure_only_mccc_clk.hw, [MEASURE_ONLY_CNOC_CLK] = &measure_only_cnoc_clk.hw, [MEASURE_ONLY_IPA_2X_CLK] = &measure_only_ipa_2x_clk.hw, [MEASURE_ONLY_SNOC_CLK] = &measure_only_snoc_clk.hw, diff --git a/include/dt-bindings/clock/qcom,gcc-sm6150.h b/include/dt-bindings/clock/qcom,gcc-sm6150.h index 82f3326cd9cc..94f9965d7e45 100644 --- a/include/dt-bindings/clock/qcom,gcc-sm6150.h +++ b/include/dt-bindings/clock/qcom,gcc-sm6150.h @@ -18,7 +18,7 @@ #define GPLL0_OUT_AUX2 0 #define MEASURE_ONLY_SNOC_CLK 1 #define MEASURE_ONLY_CNOC_CLK 2 -#define MEASURE_ONLY_BIMC_CLK 3 +#define MEASURE_ONLY_MMCC_CLK 3 #define MEASURE_ONLY_IPA_2X_CLK 4 /* GCC clock registers */ -- GitLab From 5d060faad5985b1c6bc31659b2240c17ffa1e3c4 Mon Sep 17 00:00:00 2001 From: Anurag Chouhan Date: Fri, 10 Aug 2018 12:18:46 +0530 Subject: [PATCH 0828/1001] ARM: dts: msm: Enable icnss for sm6150 Enable icnss node for sm6150. Add iova address into the sm6150 to enable ipa and smmu. Add msa fixed region. Change-Id: I8bb76e4f1b4d1912cb8268f84de0753d5e437d43 Signed-off-by: Anurag Chouhan --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index b40d15341b4d..aed0097d0086 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -2478,10 +2478,12 @@ }; icnss: qcom,icnss@18800000 { - status = "disabled"; compatible = "qcom,icnss"; - reg = <0x18800000 0x800000>; - reg-names = "membase"; + reg = <0x18800000 0x800000>, + <0xa0000000 0x10000000>, + <0xb0000000 0x10000>; + reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa"; + iommus = <&apps_smmu 0x1640 0x1>; interrupts = <0 414 0 /* CE0 */ >, <0 415 0 /* CE1 */ >, <0 416 0 /* CE2 */ >, @@ -2496,6 +2498,7 @@ <0 425 0 /* CE11 */ >; qcom,smmu-s1-bypass; qcom,wlan-msa-memory = <0x100000>; + qcom,wlan-msa-fixed-region = <&wlan_msa_mem>; vdd-0.8-cx-mx-supply = <&pm6150_l9>; vdd-1.8-xo-supply = <&pm6150l_l1>; vdd-1.3-rfa-supply = <&pm6150l_l2>; -- GitLab From b2cd4930253aed9845e4b9b80e39efe2e0d11a68 Mon Sep 17 00:00:00 2001 From: Ramprasad Katkam Date: Sat, 11 Aug 2018 15:35:27 +0530 Subject: [PATCH 0829/1001] regmap: Add kconfig flag for wcd regmap Add config flag to enable wcd regmap irq driver. Change-Id: Ic25600c8702293c489f09a82de3e506cd17880e4 Signed-off-by: Ramprasad Katkam --- drivers/base/regmap/Kconfig | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 08a3f3abd502..1b065bf7ea14 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -38,6 +38,17 @@ config REGMAP_MMIO config REGMAP_IRQ bool +config REGMAP_WCD_IRQ + depends on SND_SOC + bool "Enable REGMAP IRQ for WCD" + select REGMAP_IRQ + default n + help + Say 'y' here to enable REGMAP_IRQ for generic WCD IRQ. + This config is intended for enabling REGMAP_IRQ for + WCD IRQ. Generic WCD IRQ will be used for + wcd937x and later targets. + config REGMAP_ALLOW_WRITE_DEBUGFS depends on REGMAP && DEBUG_FS bool "Allow REGMAP debugfs write" -- GitLab From 71966e053feabbf8d1683a5655c02047f59225a8 Mon Sep 17 00:00:00 2001 From: Ghanim Fodi Date: Thu, 16 Aug 2018 16:03:17 +0300 Subject: [PATCH 0830/1001] msm: ipa3: Disable checksum offload on LAN PROD pipe There is no valid use case for IP packet checksum offload on IPA LAN Producer (Client Consumer) pipe. This change disables this unused capability. CRs-Fixed: 2298057 Change-Id: I789c1ba6255651ad0fdce974c8b819e09aee2da4 Signed-off-by: Ghanim Fodi --- drivers/platform/msm/ipa/ipa_v3/ipa.c | 2 +- drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 683906ae2993..1bebfe641946 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -3240,7 +3240,7 @@ static int ipa3_setup_apps_pipes(void) sys_in.ipa_ep_cfg.hdr_ext.hdr_payload_len_inc_padding = false; sys_in.ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_offset = 0; sys_in.ipa_ep_cfg.hdr_ext.hdr_pad_to_alignment = 2; - sys_in.ipa_ep_cfg.cfg.cs_offload_en = IPA_ENABLE_CS_OFFLOAD_DL; + sys_in.ipa_ep_cfg.cfg.cs_offload_en = IPA_DISABLE_CS_OFFLOAD; /** * ipa_lan_rx_cb() intended to notify the source EP about packet diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index fb342ad41961..0fcd5dbf58a5 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -60,7 +60,6 @@ #define IPA_ODU_RX_BUFF_SZ 2048 #define IPA_ODU_RX_POOL_SZ 64 -#define IPA_SIZE_DL_CSUM_META_TRAILER 8 #define IPA_GSI_MAX_CH_LOW_WEIGHT 15 #define IPA_GSI_EVT_RING_INT_MODT (16) /* 0.5ms under 32KHz clock */ @@ -2278,8 +2277,7 @@ static int ipa3_lan_rx_pyld_hdlr(struct sk_buff *skb, return rc; } memcpy(&comp, skb->data, sizeof(comp)); - skb_pull(skb, sizeof(comp) + - IPA_SIZE_DL_CSUM_META_TRAILER); + skb_pull(skb, sizeof(comp)); complete(&comp->comp); if (atomic_dec_return(&comp->cnt) == 0) kfree(comp); @@ -2325,8 +2323,7 @@ static int ipa3_lan_rx_pyld_hdlr(struct sk_buff *skb, pad_len_byte = ((status.pkt_len + 3) & ~3) - status.pkt_len; - len = status.pkt_len + pad_len_byte + - IPA_SIZE_DL_CSUM_META_TRAILER; + len = status.pkt_len + pad_len_byte; IPADBG_LOW("pad %d pkt_len %d len %d\n", pad_len_byte, status.pkt_len, len); -- GitLab From 52566de96d0e88c2159b69141bce1bb15177f0ba Mon Sep 17 00:00:00 2001 From: Mangesh Kunchamwar Date: Thu, 16 Aug 2018 22:05:34 +0530 Subject: [PATCH 0831/1001] ARM: dts: msm: Enable BT Audio usecases Set DT flag to enable BT audio usecases. Change-Id: I4eb487d47893ab5d0f8f63289d3382dcd93d39ad Signed-off-by: Mangesh Kunchamwar --- arch/arm64/boot/dts/qcom/qcs405-audio.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi b/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi index bd0c17f9acb6..2a9453224eb0 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi @@ -60,6 +60,7 @@ qcom,mi2s-audio-intf = <1>; qcom,auxpcm-audio-intf = <1>; qcom,spdif-audio-intf = <1>; + qcom,wcn-btfm = <1>; qcom,msm-mi2s-master = <1>, <0>, <1>, <1>, <1>; qcom,ep92-name = "ep92.3-0064"; -- GitLab From 4124eb5bd78346a2af4861ddec9d8fd33f020bbd Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Tue, 14 Aug 2018 23:56:48 +0530 Subject: [PATCH 0832/1001] ARM: dts: msm: Include thermal overlay mitigation rules for SM6150 IDP Include thermal mitigation rules for pmic alarm sensors and BCL sensors for SM6150 IDP platform. Change-Id: I9f85127fa097f3e68e298917d422afb231df758f Signed-off-by: Manaf Meethalavalappu Pallikunhi --- arch/arm64/boot/dts/qcom/sm6150-idp.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi index c908afe294d8..82bb80a496dc 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi @@ -10,6 +10,7 @@ * GNU General Public License for more details. */ +#include "sm6150-thermal-overlay.dtsi" #include #include "sm6150-sde-display.dtsi" -- GitLab From b1cc67e6ab73c10a9d9065cccb5a48c2f7bb9387 Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Mon, 2 Jul 2018 18:27:30 +0530 Subject: [PATCH 0833/1001] ARM: dts: msm: Enable backlight cooling device for SM6150 Add Display backlight cooling device for SM6150. Thermal framework will mitigate the display brightness to achieve thermal cooling. Change-Id: Ib5d49edb581fbc8a2749d0aabd4a0cbf03bc472b Signed-off-by: Manaf Meethalavalappu Pallikunhi --- arch/arm64/boot/dts/qcom/sm6150-thermal-overlay.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150-thermal-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm6150-thermal-overlay.dtsi index fe5a89d4ced9..f47d16937319 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-thermal-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-thermal-overlay.dtsi @@ -176,3 +176,7 @@ }; }; }; + +&mdss_mdp { + #cooling-cells = <2>; +}; -- GitLab From aec50d80a428a7f485138ed7e91e0e798ae52a36 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Thu, 16 Aug 2018 23:18:13 +0530 Subject: [PATCH 0834/1001] ARM: dts: msm: set active display property for various sm6150 platforms Set active display property for various idp versions of sm6150 platform. Change-Id: I42f452b26053c8be4da18650475a1dd002c6ed82 Signed-off-by: Sandeep Panda --- .../arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts | 4 ++++ arch/arm64/boot/dts/qcom/sm6150-usbc-idp-overlay.dts | 4 ++++ arch/arm64/boot/dts/qcom/sm6150p-idp-overlay.dts | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts index de91a769324e..3dda6181dbe6 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts @@ -23,3 +23,7 @@ qcom,msm-id = <355 0x0>; qcom,board-id = <34 1>; }; + +&dsi_hx83112a_truly_vid_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-usbc-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-usbc-idp-overlay.dts index ba198fbdcd1a..e8325109410d 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-usbc-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-usbc-idp-overlay.dts @@ -23,3 +23,7 @@ qcom,msm-id = <355 0x0>; qcom,board-id = <34 2>; }; + +&dsi_hx83112a_truly_vid_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150p-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150p-idp-overlay.dts index 6645a619958c..aebdcf06bbb5 100644 --- a/arch/arm64/boot/dts/qcom/sm6150p-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150p-idp-overlay.dts @@ -23,3 +23,7 @@ qcom,msm-id = <369 0x0>; qcom,board-id = <34 0>; }; + +&dsi_hx83112a_truly_vid_display { + qcom,dsi-display-active; +}; -- GitLab From 075bdfafbaff0138048ba131bb00cad5eabbfbfd Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Tue, 31 Jul 2018 11:07:18 -0700 Subject: [PATCH 0835/1001] defconfig: Remove the sm8150[-perf]_defconfig symbolic links The defconfigs are moved to arch/arm64/configs/vendor/. The symbolic links were being carried temporarily until all the build system changes are in place. Hence, removing them as they are no longer required. Change-Id: I27bdb15b37679fc4451df90a8101a23148e8efb9 Signed-off-by: Raghavendra Rao Ananta --- arch/arm64/configs/sm8150-perf_defconfig | 1 - arch/arm64/configs/sm8150_defconfig | 1 - 2 files changed, 2 deletions(-) delete mode 120000 arch/arm64/configs/sm8150-perf_defconfig delete mode 120000 arch/arm64/configs/sm8150_defconfig diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig deleted file mode 120000 index faafc59228ee..000000000000 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ /dev/null @@ -1 +0,0 @@ -vendor/sm8150-perf_defconfig \ No newline at end of file diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig deleted file mode 120000 index 4ff005a12e64..000000000000 --- a/arch/arm64/configs/sm8150_defconfig +++ /dev/null @@ -1 +0,0 @@ -vendor/sm8150_defconfig \ No newline at end of file -- GitLab From 032ad6560617387c5111fc0cf1a6c0cb11651576 Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Tue, 14 Aug 2018 01:57:59 -0700 Subject: [PATCH 0836/1001] AndroidKernel: Look for defconfig under vendor/ The target configuration searches for defconfig under configs/vendor/ by default. Hence, change the search path for the same for kernel configuration. Change-Id: Ica83363fc6783eb1ce2d46acfd755a1915e1d113 Signed-off-by: Raghavendra Rao Ananta --- AndroidKernel.mk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AndroidKernel.mk b/AndroidKernel.mk index 56e752040a19..35d3573210c6 100644 --- a/AndroidKernel.mk +++ b/AndroidKernel.mk @@ -28,6 +28,10 @@ $(warning Forcing kernel header generation only for '$(TARGET_KERNEL_HEADER_ARCH KERNEL_HEADER_ARCH := $(TARGET_KERNEL_HEADER_ARCH) endif +ifeq ($(shell echo $(KERNEL_DEFCONFIG) | grep vendor),) +KERNEL_DEFCONFIG := vendor/$(KERNEL_DEFCONFIG) +endif + KERNEL_HEADER_DEFCONFIG := $(strip $(KERNEL_HEADER_DEFCONFIG)) ifeq ($(KERNEL_HEADER_DEFCONFIG),) KERNEL_HEADER_DEFCONFIG := $(KERNEL_DEFCONFIG) -- GitLab From fd010a77edb5c160da874baea36dc6f0148d2ec4 Mon Sep 17 00:00:00 2001 From: Hardik Arya Date: Wed, 15 Aug 2018 23:33:07 +0530 Subject: [PATCH 0837/1001] diag: Continue processing of remaining pkt when read len is zero Currently if read data is len is zero we are failing and stop reading other data packets. With the patch we continue read remaining data packets in this case. Change-Id: I89cd1557bc4b7a46c68a90d2894fd4aaaf881ef5 Signed-off-by: Hardik Arya --- drivers/char/diag/diagfwd_socket.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/char/diag/diagfwd_socket.c b/drivers/char/diag/diagfwd_socket.c index 2312c85fad70..d159db1f48b1 100644 --- a/drivers/char/diag/diagfwd_socket.c +++ b/drivers/char/diag/diagfwd_socket.c @@ -649,6 +649,7 @@ static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) int read_len = 0; int bytes_remaining = 0; int total_recd = 0; + int qrtr_ctrl_recd = 0; uint8_t buf_full = 0; unsigned char *temp = NULL; struct kvec iov = {0}; @@ -729,11 +730,15 @@ static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) if (info->port_type == PORT_TYPE_SERVER) socket_init_work_fn(&info->init_work); return read_len; - } else if (read_len <= 0) - goto fail; + } else if (read_len <= 0) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "Invalid read_len: %d\n", read_len); + continue; + } if (src_addr.sq_port == QRTR_PORT_CTRL) { handle_ctrl_pkt(info, temp, read_len); + qrtr_ctrl_recd += read_len; continue; } @@ -755,13 +760,6 @@ static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) else __socket_open_channel(info); } - - if (read_len < 0) { - pr_err_ratelimited("diag: In %s, error receiving data, err: %d\n", - __func__, pkt_len); - err = read_len; - goto fail; - } temp += read_len; total_recd += read_len; bytes_remaining -= read_len; @@ -780,8 +778,14 @@ static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) if (err) goto fail; } else { - DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s error in read, err: %d\n", - info->name, total_recd); + if (qrtr_ctrl_recd > 0) + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "%s read qrtr ctrl bytes: %d\n", + info->name, qrtr_ctrl_recd); + else + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "%s error in read, err: %d\n", + info->name, total_recd); goto fail; } -- GitLab From dfae9242e2ba1f0b804734037fd1cff9e49a0604 Mon Sep 17 00:00:00 2001 From: Lakshmi Narayana Kalavala Date: Wed, 15 Aug 2018 14:34:21 -0700 Subject: [PATCH 0838/1001] ARM: dts: msm: restrict the lut access to 160 bytes Display driver is not supposed to read the lut coefficients while destination scaler is active. The coefficients can only be read when destination scaler is off. Hence restrict the lut access to 160 bytes instead of 2K bytes. CRs-Fixed: 2293755 Change-Id: Ie3875aeeaa8d34af9cfa671e863eea372f88bc54 Signed-off-by: Lakshmi Narayana Kalavala --- arch/arm64/boot/dts/qcom/sm8150-sde.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi index c66b1a046c96..e77fce7eafe8 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi @@ -71,7 +71,7 @@ qcom,sde-dest-scaler-top-off = <0x00061000>; qcom,sde-dest-scaler-top-size = <0x1c>; qcom,sde-dest-scaler-off = <0x800 0x1000>; - qcom,sde-dest-scaler-size = <0x800>; + qcom,sde-dest-scaler-size = <0xa0>; qcom,sde-wb-off = <0x66000>; qcom,sde-wb-size = <0x2c8>; -- GitLab From 8cb8ef8b291fb45a564cc77744854727aa2afa58 Mon Sep 17 00:00:00 2001 From: Alok Pandey Date: Fri, 13 Jul 2018 15:34:09 +0530 Subject: [PATCH 0839/1001] msm: camera: icp: Relaxing the aggression for Clock and BW voting In current code is too aggressive while calculating voting. HLOS first set the hfi_frame_process flag for a request to be submitted and the does voting calculation. The problem with this approach is that while deciding for new voting values, HLOS is considering those requests which are yet to be submitted. With this change calculation of Clock and BW voting will consider submitted requests only. Change-Id: I50e49defda35102647b5cfdfd7bcdd593ce30401 Signed-off-by: Alok Pandey --- .../msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index 072129a57082..6639d33f31d1 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -3176,8 +3176,8 @@ static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) frame_info = (struct icp_frame_info *)config_args->priv; req_id = frame_info->request_id; idx = cam_icp_clk_idx_from_req_id(ctx_data, req_id); - ctx_data->hfi_frame_process.fw_process_flag[idx] = true; cam_icp_mgr_ipe_bps_clk_update(hw_mgr, ctx_data, idx); + ctx_data->hfi_frame_process.fw_process_flag[idx] = true; CAM_DBG(CAM_ICP, "req_id %llu, io config %llu", req_id, frame_info->io_config); -- GitLab From 556a495e76e1a5481c338455642a248f68898d77 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Thu, 16 Aug 2018 15:36:20 -0700 Subject: [PATCH 0840/1001] iommu: arm-smmu: Add DOMAIN_ATTR_NO_CFRE Some bus implementations may enter a bad state if iommu reports an error on context fault. As context faults are not always fatal, this must be avoided. Change-Id: I60d1ccb7cad64dfc9e327967c903befd3fa72877 Signed-off-by: Patrick Daly --- drivers/iommu/arm-smmu.c | 14 ++++++++++++++ include/linux/iommu.h | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 4181c15cc938..1db76912f355 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1635,6 +1635,9 @@ static void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx, reg |= SCTLR_HUPCF; } + if (attributes & (1 << DOMAIN_ATTR_NO_CFRE)) + reg &= ~SCTLR_CFRE; + if ((!(attributes & (1 << DOMAIN_ATTR_S1_BYPASS)) && !(attributes & (1 << DOMAIN_ATTR_EARLY_MAP))) || !stage1) reg |= SCTLR_M; @@ -3206,6 +3209,11 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain, & (1 << DOMAIN_ATTR_CB_STALL_DISABLE)); ret = 0; break; + case DOMAIN_ATTR_NO_CFRE: + *((int *)data) = !!(smmu_domain->attributes + & (1 << DOMAIN_ATTR_NO_CFRE)); + ret = 0; + break; case DOMAIN_ATTR_QCOM_MMU500_ERRATA_MIN_IOVA_ALIGN: *((int *)data) = smmu_domain->qsmmuv500_errata1_min_iova_align; ret = 0; @@ -3422,6 +3430,12 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain, 1 << DOMAIN_ATTR_CB_STALL_DISABLE; ret = 0; break; + case DOMAIN_ATTR_NO_CFRE: + if (*((int *)data)) + smmu_domain->attributes |= + 1 << DOMAIN_ATTR_NO_CFRE; + ret = 0; + break; default: ret = -ENODEV; } diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 6b7bf41314c8..3e4f4fedda98 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -133,6 +133,11 @@ enum iommu_cap { * DOMAIN_ATTR_FSL_PAMUV1 corresponds to the above mentioned contraints. * The caller can invoke iommu_domain_get_attr to check if the underlying * iommu implementation supports these constraints. + * + * DOMAIN_ATTR_NO_CFRE + * Some bus implementations may enter a bad state if iommu reports an error + * on context fault. As context faults are not always fatal, this must be + * avoided. */ enum iommu_attr { @@ -163,6 +168,7 @@ enum iommu_attr { DOMAIN_ATTR_BITMAP_IOVA_ALLOCATOR, DOMAIN_ATTR_QCOM_MMU500_ERRATA_MIN_IOVA_ALIGN, DOMAIN_ATTR_USE_LLC_NWA, + DOMAIN_ATTR_NO_CFRE, DOMAIN_ATTR_MAX, }; -- GitLab From 687bf8dd46dfc240aa7f7dd0d47d9d3295365063 Mon Sep 17 00:00:00 2001 From: Tapas Kumar Kundu Date: Thu, 16 Aug 2018 16:06:54 -0700 Subject: [PATCH 0841/1001] msm: vidc: Remove 'I' frame handling as sync frame Driver already has sync frame as separate flag. we don't need to tag I frame as sync frame since this is causing issues for AVC/HEVC codecs. CRs-Fixed: 2298365 Change-Id: Ieaae5b4df332f959df9636f80d82ba66436fc066 Signed-off-by: Tapas Kumar Kundu --- drivers/media/platform/msm/vidc/msm_vidc_common.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index cbfeea486d65..1b09445d8901 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -2683,10 +2683,6 @@ static void handle_fbd(enum hal_command_response cmd, void *data) if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DATACORRUPT) mbuf->vvb.flags |= V4L2_QCOM_BUF_DATA_CORRUPT; switch (fill_buf_done->picture_type) { - case HAL_PICTURE_IDR: - case HAL_PICTURE_I: - mbuf->vvb.flags |= V4L2_BUF_FLAG_KEYFRAME; - break; case HAL_PICTURE_P: mbuf->vvb.flags |= V4L2_BUF_FLAG_PFRAME; break; -- GitLab From 1b7e5a863b56ea2735bf7c3b1a197170fb52c86b Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Thu, 28 Jun 2018 18:10:36 -0700 Subject: [PATCH 0842/1001] power: qpnp-fg-gen4: Enable parallel charging current measurement Fuel gauge (FG) needs to measure the battery charging current flowing through both main charger and parallel charger to calculate the state of charge (SOC) accurately. Enable parallel charging current measurement to do that. Change-Id: I6111560f7cc6d831b6292b7322c94e85e73ff8bd Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qcom/fg-reg.h | 3 +++ drivers/power/supply/qcom/qpnp-fg-gen4.c | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/drivers/power/supply/qcom/fg-reg.h b/drivers/power/supply/qcom/fg-reg.h index 0889fdf16a59..267bb08e7a2b 100644 --- a/drivers/power/supply/qcom/fg-reg.h +++ b/drivers/power/supply/qcom/fg-reg.h @@ -268,6 +268,9 @@ #define BATT_INFO_IADC_MSB(chip) (chip->batt_info_base + 0xAF) #define IADC_MSB_MASK GENMASK(6, 0) +#define BATT_INFO_FG_CNV_CHAR_CFG(chip) (chip->batt_info_base + 0xB7) +#define SMB_MEASURE_EN_BIT BIT(2) + #define BATT_INFO_TM_MISC(chip) (chip->batt_info_base + 0xE5) #define FORCE_SEQ_RESP_TOGGLE_BIT BIT(6) #define ALG_DIRECT_VALID_DATA_BIT BIT(5) diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index 89fb5d0d897e..8abce1dcbf81 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -3367,6 +3367,15 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) int rc; u8 buf[4], val, mask; + /* Enable measurement of parallel charging current */ + val = mask = SMB_MEASURE_EN_BIT; + rc = fg_masked_write(fg, BATT_INFO_FG_CNV_CHAR_CFG(fg), mask, val); + if (rc < 0) { + pr_err("Error in writing to 0x%04x, rc=%d\n", + BATT_INFO_FG_CNV_CHAR_CFG(fg), rc); + return rc; + } + fg_encode(fg->sp, FG_SRAM_CUTOFF_VOLT, chip->dt.cutoff_volt_mv, buf); rc = fg_sram_write(fg, fg->sp[FG_SRAM_CUTOFF_VOLT].addr_word, fg->sp[FG_SRAM_CUTOFF_VOLT].addr_byte, buf, -- GitLab From c588598d37c5e9816b88c3ff24157dbd2f2688ab Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Mon, 16 Apr 2018 16:59:47 +0530 Subject: [PATCH 0843/1001] msm: camera: isp: Poll for CSID hardware reset status Currently after csid hardware reset, software wait for interrupt to come. CSID irq handler gives the complete signal once CSID reset irq raised. Instead of waiting for reset irq comes, software can poll reset status register and check status. This avoids the race conditions in the csid irq complete signals. Change-Id: Ibe0ea7bbb5efe89ea38e095371b60bfcbc34c0e3 Signed-off-by: Ravikishore Pampana --- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 7bd7b9e7206b..548e849dd45c 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -1064,10 +1064,6 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); - /* Enable the top IRQ interrupt */ - cam_io_w_mb(1, soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_top_irq_mask_addr); - val = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_hw_version_addr); CAM_DBG(CAM_ISP, "CSID:%d CSID HW version: 0x%x", @@ -2299,25 +2295,38 @@ static int cam_ife_csid_reset_retain_sw_reg( struct cam_ife_csid_hw *csid_hw) { int rc = 0; + uint32_t status; const struct cam_ife_csid_reg_offset *csid_reg = csid_hw->csid_info->csid_reg; + struct cam_hw_soc_info *soc_info; + + soc_info = &csid_hw->hw_info->soc_info; + /* clear the top interrupt first */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); - init_completion(&csid_hw->csid_top_complete); cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb, - csid_hw->hw_info->soc_info.reg_map[0].mem_base + + soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_rst_strobes_addr); - - CAM_DBG(CAM_ISP, " Waiting for SW reset complete from irq handler"); - rc = wait_for_completion_timeout(&csid_hw->csid_top_complete, - msecs_to_jiffies(IFE_CSID_TIMEOUT)); - if (rc <= 0) { - CAM_ERR(CAM_ISP, "CSID:%d reset completion in fail rc = %d", - csid_hw->hw_intf->hw_idx, rc); - if (rc == 0) - rc = -ETIMEDOUT; + rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_status_addr, + status, (status & 0x1) == 0x1, + CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + rc = -ETIMEDOUT; } else { + CAM_DBG(CAM_ISP, "CSID:%d hw reset completed %d", + csid_hw->hw_intf->hw_idx, rc); rc = 0; } + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); return rc; } @@ -2735,8 +2744,6 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_reg->rdi_reg[i]->csid_rdi_irq_status_addr); /* clear */ - cam_io_w_mb(irq_status_top, soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_top_irq_clear_addr); cam_io_w_mb(irq_status_rx, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr); if (csid_reg->cmn_reg->num_pix) @@ -2762,13 +2769,6 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) CAM_DBG(CAM_ISP, "irq_status_rdi1= 0x%x", irq_status_rdi[1]); CAM_DBG(CAM_ISP, "irq_status_rdi2= 0x%x", irq_status_rdi[2]); - if (irq_status_top) { - CAM_DBG(CAM_ISP, "CSID global reset complete......Exit"); - complete(&csid_hw->csid_top_complete); - return IRQ_HANDLED; - } - - if (irq_status_rx & BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "csi rx reset complete"); complete(&csid_hw->csid_csi2_complete); -- GitLab From 390941a310a9bf80f2a4a82fdd4415c6f4f2df2e Mon Sep 17 00:00:00 2001 From: Alex Yakavenka Date: Thu, 16 Aug 2018 17:41:05 -0700 Subject: [PATCH 0844/1001] ARM: dts: msm: Change number of channels for calypso Set number of channels for calypso to 1 to align with what firmware currently supports Change-Id: I178d6176502b3ccc8f54ff4451d2f46367c720c2 Signed-off-by: Alex Yakavenka --- arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi index 7d29320c0d12..36759b694785 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi @@ -24,7 +24,7 @@ interrupts = <38 0>; spi-max-frequency = <5000000>; qcom,clk-freq-mhz = <40000000>; - qcom,max-can-channels = <4>; + qcom,max-can-channels = <1>; qcom,bits-per-word = <8>; qcom,support-can-fd; }; -- GitLab From f8b640fb2d587eb8b29475158f0ce51d585cadf3 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Wed, 15 Aug 2018 15:11:09 +0800 Subject: [PATCH 0845/1001] pwm: pwm-qti-lpg: Add property for LPG channel synchronization Add qcom,sync-channel-ids property for grouping the LPG channels which are expected to be enabled with a synchronized pattern. Change-Id: I1f5d83f2e6094771cb30d567d9d4d4476f1f3dc9 Signed-off-by: Fenglin Wu --- .../devicetree/bindings/pwm/pwm-qti-lpg.txt | 12 +++ drivers/pwm/pwm-qti-lpg.c | 76 ++++++++++++++++++- 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt b/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt index ddd90e134a16..d01f25a190c1 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt +++ b/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt @@ -40,6 +40,17 @@ device module in Qualcomm Technologies, Inc. PMIC chips. channels. This property is required if any LPG channels support LUT mode. +- qcom,sync-channel-ids: + Usage: optional + Value type: + Definition: The hardware IDs of the LPG channel that required be + grouped together. These channels will share the same LUT + ramping configuration so that they will be enabled with a + synchronized pattern. If the LUT ramping configuration + differs for the channels grouped for synchronization, + configuration of the first channel will be applied for + all others. + Subnode is optional if LUT mode is not required, it's required if any LPG channels expected to be supported in LUT mode. @@ -114,6 +125,7 @@ Example: #pwm-cells = <2>; qcom,lut-patterns = <0 14 28 42 56 70 84 100 100 84 70 56 42 28 14 0>; + qcom,sync-channel-ids = <3 4 5>; lpg@3 { qcom,lpg-chan-id = <3>; qcom,ramp-step-ms = <200>; diff --git a/drivers/pwm/pwm-qti-lpg.c b/drivers/pwm/pwm-qti-lpg.c index aca41a8d5b9c..784fc8bb3ae2 100644 --- a/drivers/pwm/pwm-qti-lpg.c +++ b/drivers/pwm/pwm-qti-lpg.c @@ -165,6 +165,7 @@ struct qpnp_lpg_chip { struct qpnp_lpg_channel *lpgs; struct qpnp_lpg_lut *lut; struct mutex bus_lock; + u32 *lpg_group; u32 num_lpgs; }; @@ -659,8 +660,9 @@ static int qpnp_lpg_pwm_src_enable(struct qpnp_lpg_channel *lpg, bool en) { struct qpnp_lpg_chip *chip = lpg->chip; struct qpnp_lpg_lut *lut = chip->lut; + struct pwm_device *pwm; u8 mask, val; - int rc; + int i, lpg_idx, rc; mask = LPG_PWM_SRC_SELECT_MASK | LPG_EN_LPG_OUT_BIT | LPG_EN_RAMP_GEN_MASK; @@ -680,8 +682,31 @@ static int qpnp_lpg_pwm_src_enable(struct qpnp_lpg_channel *lpg, bool en) } if (lpg->src_sel == LUT_PATTERN && en) { - mutex_lock(&lut->lock); val = 1 << lpg->lpg_idx; + for (i = 0; i < chip->num_lpgs; i++) { + if (chip->lpg_group == NULL) + break; + if (chip->lpg_group[i] == 0) + break; + lpg_idx = chip->lpg_group[i] - 1; + pwm = &chip->pwm_chip.pwms[lpg_idx]; + if ((pwm_get_output_type(pwm) == PWM_OUTPUT_MODULATED) + && pwm_is_enabled(pwm)) { + rc = qpnp_lpg_masked_write(&chip->lpgs[lpg_idx], + REG_LPG_ENABLE_CONTROL, + LPG_EN_LPG_OUT_BIT, 0); + if (rc < 0) + break; + rc = qpnp_lpg_masked_write(&chip->lpgs[lpg_idx], + REG_LPG_ENABLE_CONTROL, + LPG_EN_LPG_OUT_BIT, + LPG_EN_LPG_OUT_BIT); + if (rc < 0) + break; + val |= 1 << lpg_idx; + } + } + mutex_lock(&lut->lock); rc = qpnp_lut_write(lut, REG_LPG_LUT_RAMP_CONTROL, val); if (rc < 0) dev_err(chip->dev, "Write LPG_LUT_RAMP_CONTROL failed, rc=%d\n", @@ -1146,6 +1171,53 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip) "qcom,ramp-toggle"); } + rc = of_property_count_elems_of_size(chip->dev->of_node, + "qcom,sync-channel-ids", sizeof(u32)); + if (rc < 0) + return 0; + + length = rc; + if (length > chip->num_lpgs) { + dev_err(chip->dev, "qcom,sync-channel-ids has too many channels: %d\n", + length); + return -EINVAL; + } + + chip->lpg_group = devm_kcalloc(chip->dev, chip->num_lpgs, + sizeof(u32), GFP_KERNEL); + if (!chip->lpg_group) + return -ENOMEM; + + rc = of_property_read_u32_array(chip->dev->of_node, + "qcom,sync-channel-ids", chip->lpg_group, length); + if (rc < 0) { + dev_err(chip->dev, "Get qcom,sync-channel-ids failed, rc=%d\n", + rc); + return rc; + } + + for (i = 0; i < length; i++) { + if (chip->lpg_group[i] <= 0 || + chip->lpg_group[i] > chip->num_lpgs) { + dev_err(chip->dev, "lpg_group[%d]: %d is not a valid channel\n", + i, chip->lpg_group[i]); + return -EINVAL; + } + } + + /* + * The LPG channel in the same group should have the same ramping + * configuration, so force to use the ramping configuration of the + * 1st LPG channel in the group for sychronization. + */ + lpg = &chip->lpgs[chip->lpg_group[0] - 1]; + ramp = &lpg->ramp_config; + + for (i = 1; i < length; i++) { + lpg = &chip->lpgs[chip->lpg_group[i] - 1]; + memcpy(&lpg->ramp_config, ramp, sizeof(struct lpg_ramp_config)); + } + return 0; } -- GitLab From ae49d481af1799a75fcda9b67ffd024493f843bc Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Tue, 14 Aug 2018 18:57:19 +0530 Subject: [PATCH 0846/1001] ARM: dts: msm: Add SMMU SID for SM6150 Add ETR SID and BAM SID for SM6150 smmu function. Change-Id: I60c0533532713472dbe9121c691f1a511249c1cc Signed-off-by: Mao Jinlong --- arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi b/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi index 2e5d6ecb62f3..c42151595591 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi @@ -110,6 +110,8 @@ reg-names = "tmc-base", "bam-base"; qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x01e0 0>, + <&apps_smmu 0x00a0 0>; arm,buffer-size = <0x400000>; coresight-name = "coresight-tmc-etr"; -- GitLab From e177e8a35ff7010c49d4e857e6a1c50b9bba62b8 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Tue, 14 Aug 2018 19:27:13 +0530 Subject: [PATCH 0847/1001] ARM: dts: msm: Correct the port of turing funnel for SM6150 Turing etm connects to the port 1 of turing funnel, not 0. Change-Id: Ib1477f16da33e6131e85e17637448abe158f6b70 Signed-off-by: Mao Jinlong --- arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi b/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi index c42151595591..b490193e83ca 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi @@ -827,7 +827,7 @@ }; port@1 { - reg = <0>; + reg = <1>; funnel_turing_1_in_turing_etm0: endpoint { slave-mode; remote-endpoint = -- GitLab From 6a4a3958d8b18b7b1098b3a8d7e9b860406262a4 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Thu, 16 Aug 2018 16:50:33 +0530 Subject: [PATCH 0848/1001] msm: kgsl: Add support of GPU speed bin for A608 GPU Add A608 GPU id to support speed bin feature to handle different GPU power levels. Change-Id: I85440f68638c0ebda049ce429db9e35fe8ed544b Signed-off-by: Sunil Khatri --- drivers/gpu/msm/adreno_a6xx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index d1103cc4fe2a..4f7745d1f113 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -2656,6 +2656,7 @@ static const struct { void (*func)(struct adreno_device *adreno_dev); } a6xx_efuse_funcs[] = { { adreno_is_a615, a6xx_efuse_speed_bin }, + { adreno_is_a608, a6xx_efuse_speed_bin }, }; static void a6xx_check_features(struct adreno_device *adreno_dev) -- GitLab From 0a5d57cf93b93805c09f91257f6d5282f3cfc9e7 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Thu, 9 Aug 2018 10:47:26 +0530 Subject: [PATCH 0849/1001] ARM: dts: Add 895MHz GPU clock support for SM6150 SM6150 support maximum GPU clock of 895 MHZ. Add support for this new GPU level. Change-Id: Ic2e727cfb4fc973e8a8ddce67dbb616cb3ce4b1b Signed-off-by: Sunil Khatri --- arch/arm64/boot/dts/qcom/sm6150-gpu.dtsi | 297 ++++++++++++++++++----- 1 file changed, 235 insertions(+), 62 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150-gpu.dtsi b/arch/arm64/boot/dts/qcom/sm6150-gpu.dtsi index 13a62b58b2f8..2c8fea8b7592 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-gpu.dtsi @@ -33,8 +33,10 @@ label = "kgsl-3d0"; compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; status = "ok"; - reg = <0x5000000 0x40000>; - reg-names = "kgsl_3d0_reg_memory"; + reg = <0x5000000 0x40000>, + <0x780000 0x6fff>; + reg-names = "kgsl_3d0_reg_memory", + "qfprom_memory"; interrupts = <0 300 0>; interrupt-names = "kgsl_3d0_irq"; qcom,id = <0>; @@ -108,6 +110,8 @@ /* Context aware jump target power level */ qcom,ca-target-pwrlevel = <3>; + qcom,gpu-speed-bin = <0x6004 0x1fe00000 21>; + /* GPU Mempools */ qcom,gpu-mempools { #address-cells = <1>; @@ -140,73 +144,242 @@ }; }; - qcom,gpu-pwrlevels { + /* + * Speed-bin zero is default speed bin. + * For rest of the speed bins, speed-bin value + * is calulated as FMAX/4.8 MHz round up to zero + * decimal places. + */ + qcom,gpu-pwrlevel-bins { #address-cells = <1>; #size-cells = <0>; - compatible = "qcom,gpu-pwrlevels"; - - /* TURBO */ - qcom,gpu-pwrlevel@0 { - reg = <0>; - qcom,gpu-freq = <845000000>; - qcom,bus-freq = <11>; - qcom,bus-min = <10>; - qcom,bus-max = <11>; - }; - - /* NOM L1 */ - qcom,gpu-pwrlevel@1 { - reg = <1>; - qcom,gpu-freq = <745000000>; - qcom,bus-freq = <10>; - qcom,bus-min = <9>; - qcom,bus-max = <11>; - }; - - /* NOM */ - qcom,gpu-pwrlevel@2 { - reg = <2>; - qcom,gpu-freq = <700000000>; - qcom,bus-freq = <9>; - qcom,bus-min = <8>; - qcom,bus-max = <10>; - }; - - /* SVS L1 */ - qcom,gpu-pwrlevel@3 { - reg = <3>; - qcom,gpu-freq = <550000000>; - qcom,bus-freq = <8>; - qcom,bus-min = <7>; - qcom,bus-max = <9>; - }; - - /* SVS */ - qcom,gpu-pwrlevel@4 { - reg = <4>; - qcom,gpu-freq = <435000000>; - qcom,bus-freq = <7>; - qcom,bus-min = <5>; - qcom,bus-max = <8>; + compatible="qcom,gpu-pwrlevel-bins"; + + qcom,gpu-pwrlevels-0 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <0>; + + qcom,initial-pwrlevel = <3>; + qcom,ca-target-pwrlevel = <3>; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <845000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <706000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <11>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <645000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <513000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <290000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <4>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; }; - /* Low SVS */ - qcom,gpu-pwrlevel@5 { - reg = <5>; - qcom,gpu-freq = <290000000>; - qcom,bus-freq = <4>; - qcom,bus-min = <4>; - qcom,bus-max = <5>; + qcom,gpu-pwrlevels-1 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <177>; + + qcom,initial-pwrlevel = <3>; + qcom,ca-target-pwrlevel = <3>; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <845000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <706000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <11>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <645000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <513000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <290000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <4>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; }; - /* XO */ - qcom,gpu-pwrlevel@6 { - reg = <6>; - qcom,gpu-freq = <0>; - qcom,bus-freq = <0>; - qcom,bus-min = <0>; - qcom,bus-max = <0>; + qcom,gpu-pwrlevels-2 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <187>; + + qcom,initial-pwrlevel = <3>; + qcom,ca-target-pwrlevel = <4>; + + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <895000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + /* SVS_L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <845000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM L1 */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <706000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <11>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <645000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <513000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <290000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <4>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; }; }; }; -- GitLab From 1672106395fe831fa1d512fbfe8523873971d25d Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Fri, 20 Jul 2018 12:15:06 +0530 Subject: [PATCH 0850/1001] clk: qcom: Add support for NPUCC driver Add network processing unit clock controller driver for SDMMAGPIE for the client to be able to perform clock operations. Change-Id: Ide155e693740819f6ba53ddc4e76e5c4ae283c71 Signed-off-by: Taniya Das --- .../devicetree/bindings/clock/qcom,npucc.txt | 3 +- drivers/clk/qcom/Kconfig | 8 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/npucc-sdmmagpie.c | 664 ++++++++++++++++++ .../dt-bindings/clock/qcom,npucc-sdmmagpie.h | 52 +- 5 files changed, 702 insertions(+), 26 deletions(-) create mode 100644 drivers/clk/qcom/npucc-sdmmagpie.c diff --git a/Documentation/devicetree/bindings/clock/qcom,npucc.txt b/Documentation/devicetree/bindings/clock/qcom,npucc.txt index a5310ee9df23..d5e4ed6f0f9d 100644 --- a/Documentation/devicetree/bindings/clock/qcom,npucc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,npucc.txt @@ -2,7 +2,8 @@ Qualcomm Technologies, Inc. NPU Clock & Reset Controller Binding ---------------------------------------------------------------- Required properties : -- compatible : must contain "qcom,npucc-sm8150" or "qcom,npucc-sm8150-v2". +- compatible : must contain "qcom,npucc-sm8150" or "qcom,npucc-sm8150-v2" + or "qcom,npucc-sdmmagpie". - reg : shall contain base register location and length. - reg-names: names of registers listed in the same order as in the reg property. diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 5932ad41af19..4c41dd37d07b 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -414,3 +414,11 @@ config MSM_VIDEOCC_SDMMAGPIE SDMMAGPIE devices. Say Y if you want to support video devices and functionality such as video encode/decode. + +config MSM_NPUCC_SDMMAGPIE + tristate "SDMMAGPIE NPU Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the NPU clock controller on Qualcomm Technologies, Inc + SDMMAGPIE devices. + Say Y if you want to enable use of the Network Processing Unit. diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index df36e77f22a2..eff5314e4316 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o +obj-$(CONFIG_MSM_NPUCC_SDMMAGPIE) += npucc-sdmmagpie.o obj-$(CONFIG_MSM_NPUCC_SM8150) += npucc-sm8150.o obj-$(CONFIG_MSM_VIDEOCC_SDMMAGPIE) += videocc-sdmmagpie.o obj-$(CONFIG_MSM_VIDEOCC_SM6150) += videocc-sm6150.o diff --git a/drivers/clk/qcom/npucc-sdmmagpie.c b/drivers/clk/qcom/npucc-sdmmagpie.c new file mode 100644 index 000000000000..cdbb2c7949e9 --- /dev/null +++ b/drivers/clk/qcom/npucc-sdmmagpie.c @@ -0,0 +1,664 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-branch.h" +#include "reset.h" +#include "clk-alpha-pll.h" +#include "vdd-level.h" + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + +#define CRC_SID_FSM_CTRL 0x100c +#define CRC_SID_FSM_CTRL_SETTING 0x800000 +#define CRC_MND_CFG 0x1010 +#define CRC_MND_CFG_SETTING 0x15010 + +static DEFINE_VDD_REGULATORS(vdd_cx, VDD_NUM, 1, vdd_corner); + +enum { + P_BI_TCXO, + P_CORE_BI_PLL_TEST_SE, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, + P_NPU_CC_PLL0_OUT_EVEN, + P_NPU_CC_PLL1_OUT_EVEN, + P_NPU_CC_CRC_DIV, +}; + +static const struct parent_map npu_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_NPU_CC_PLL1_OUT_EVEN, 1 }, + { P_NPU_CC_PLL0_OUT_EVEN, 2 }, + { P_GPLL0_OUT_MAIN, 4 }, + { P_GPLL0_OUT_MAIN_DIV, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const npu_cc_parent_names_0[] = { + "bi_tcxo", + "npu_cc_pll1_out_even", + "npu_cc_pll0_out_even", + "gcc_npu_gpll0_clk_src", + "gcc_npu_gpll0_div_clk_src", + "core_bi_pll_test_se", +}; + +static struct pll_vco fabia_vco[] = { + { 249600000, 2000000000, 0 }, + { 125000000, 1000000000, 1 }, +}; + +static const struct alpha_pll_config npu_cc_pll0_config = { + .l = 0x1F, + .frac = 0x4000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002067, + .user_ctl_val = 0x00000001, + .user_ctl_hi_val = 0x00004805, + .test_ctl_hi_val = 0x40000000, +}; + +static struct clk_alpha_pll npu_cc_pll0 = { + .offset = 0x0, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_pll_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 615000000, + [VDD_LOW] = 1066000000, + [VDD_LOW_L1] = 1600000000, + [VDD_NOMINAL] = 2000000000}, + }, + }, +}; + +static const struct clk_div_table post_div_table_fabia_even[] = { + { 0x0, 1 }, + { 0x1, 2 }, + { 0x3, 4 }, + { 0x7, 8 }, + { } +}; + +static struct clk_alpha_pll_postdiv npu_cc_pll0_out_even = { + .offset = 0x0, + .post_div_shift = 8, + .post_div_table = post_div_table_fabia_even, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "npu_cc_pll0_out_even", + .parent_names = (const char *[]){ "npu_cc_pll0" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_generic_pll_postdiv_ops, + }, +}; + +static const struct alpha_pll_config npu_cc_pll1_config = { + .l = 0xF, + .frac = 0xA000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002067, + .user_ctl_val = 0x00000001, + .user_ctl_hi_val = 0x00004805, + .test_ctl_hi_val = 0x40000000, +}; + +static struct clk_alpha_pll npu_cc_pll1 = { + .offset = 0x400, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_pll1", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_pll_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 615000000, + [VDD_LOW] = 1066000000, + [VDD_LOW_L1] = 1600000000, + [VDD_NOMINAL] = 2000000000}, + }, + }, +}; + +static struct clk_alpha_pll_postdiv npu_cc_pll1_out_even = { + .offset = 0x400, + .post_div_shift = 8, + .post_div_table = post_div_table_fabia_even, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "npu_cc_pll1_out_even", + .parent_names = (const char *[]){ "npu_cc_pll1" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_generic_pll_postdiv_ops, + }, +}; + +static const struct freq_tbl ftbl_npu_cc_cal_dp_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(300000000, P_NPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(350000000, P_NPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(400000000, P_NPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(466500000, P_NPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(600000000, P_NPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(700000000, P_NPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 npu_cc_cal_dp_clk_src = { + .cmd_rcgr = 0x1004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = npu_cc_parent_map_0, + .freq_tbl = ftbl_npu_cc_cal_dp_clk_src, + .enable_safe_config = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "npu_cc_cal_dp_clk_src", + .parent_names = npu_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 300000000, + [VDD_LOW] = 400000000, + [VDD_LOW_L1] = 466500000, + [VDD_NOMINAL] = 600000000, + [VDD_HIGH] = 700000000}, + }, +}; + +static const struct freq_tbl ftbl_npu_cc_npu_core_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN_DIV, 3, 0, 0), + F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(400000000, P_GPLL0_OUT_MAIN, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 npu_cc_npu_core_clk_src = { + .cmd_rcgr = 0x1030, + .mnd_width = 0, + .hid_width = 5, + .parent_map = npu_cc_parent_map_0, + .freq_tbl = ftbl_npu_cc_npu_core_clk_src, + .enable_safe_config = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "npu_cc_npu_core_clk_src", + .parent_names = npu_cc_parent_names_0, + .num_parents = 6, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .flags = CLK_SET_RATE_PARENT, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 100000000, + [VDD_LOW] = 150000000, + [VDD_LOW_L1] = 200000000, + [VDD_NOMINAL] = 300000000, + [VDD_HIGH] = 400000000}, + }, +}; + +static struct clk_branch npu_cc_armwic_core_clk = { + .halt_reg = 0x1058, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_armwic_core_clk", + .parent_names = (const char *[]){ + "npu_cc_npu_core_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_bto_core_clk = { + .halt_reg = 0x1090, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1090, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_bto_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_bwmon_clk = { + .halt_reg = 0x1088, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1088, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_bwmon_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_cal_dp_cdc_clk = { + .halt_reg = 0x1068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1068, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_cal_dp_cdc_clk", + .parent_names = (const char *[]){ + "npu_cc_cal_dp_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_cal_dp_clk = { + .halt_reg = 0x101c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x101c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_cal_dp_clk", + .parent_names = (const char *[]){ + "npu_cc_cal_dp_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_comp_noc_axi_clk = { + .halt_reg = 0x106c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x106c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_comp_noc_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_conf_noc_ahb_clk = { + .halt_reg = 0x1074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1074, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_conf_noc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_npu_core_apb_clk = { + .halt_reg = 0x1080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_npu_core_apb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_npu_core_atb_clk = { + .halt_reg = 0x1078, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1078, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_npu_core_atb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_npu_core_clk = { + .halt_reg = 0x1048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_npu_core_clk", + .parent_names = (const char *[]){ + "npu_cc_npu_core_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_npu_core_cti_clk = { + .halt_reg = 0x107c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x107c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_npu_core_cti_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_npu_cpc_clk = { + .halt_reg = 0x1050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_npu_cpc_clk", + .parent_names = (const char *[]){ + "npu_cc_npu_core_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_npu_cpc_timer_clk = { + .halt_reg = 0x105c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x105c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_npu_cpc_timer_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_perf_cnt_clk = { + .halt_reg = 0x108c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x108c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_perf_cnt_clk", + .parent_names = (const char *[]){ + "npu_cc_cal_dp_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_qtimer_core_clk = { + .halt_reg = 0x1060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1060, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_qtimer_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_sleep_clk = { + .halt_reg = 0x1064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch npu_cc_xo_clk = { + .halt_reg = 0x3020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_xo_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *npu_cc_sdmmagpie_clocks[] = { + [NPU_CC_PLL0] = &npu_cc_pll0.clkr, + [NPU_CC_PLL0_OUT_EVEN] = &npu_cc_pll0_out_even.clkr, + [NPU_CC_PLL1] = &npu_cc_pll1.clkr, + [NPU_CC_PLL1_OUT_EVEN] = &npu_cc_pll1_out_even.clkr, + [NPU_CC_ARMWIC_CORE_CLK] = &npu_cc_armwic_core_clk.clkr, + [NPU_CC_BTO_CORE_CLK] = &npu_cc_bto_core_clk.clkr, + [NPU_CC_BWMON_CLK] = &npu_cc_bwmon_clk.clkr, + [NPU_CC_CAL_DP_CDC_CLK] = &npu_cc_cal_dp_cdc_clk.clkr, + [NPU_CC_CAL_DP_CLK] = &npu_cc_cal_dp_clk.clkr, + [NPU_CC_CAL_DP_CLK_SRC] = &npu_cc_cal_dp_clk_src.clkr, + [NPU_CC_COMP_NOC_AXI_CLK] = &npu_cc_comp_noc_axi_clk.clkr, + [NPU_CC_CONF_NOC_AHB_CLK] = &npu_cc_conf_noc_ahb_clk.clkr, + [NPU_CC_NPU_CORE_APB_CLK] = &npu_cc_npu_core_apb_clk.clkr, + [NPU_CC_NPU_CORE_ATB_CLK] = &npu_cc_npu_core_atb_clk.clkr, + [NPU_CC_NPU_CORE_CLK] = &npu_cc_npu_core_clk.clkr, + [NPU_CC_NPU_CORE_CLK_SRC] = &npu_cc_npu_core_clk_src.clkr, + [NPU_CC_NPU_CORE_CTI_CLK] = &npu_cc_npu_core_cti_clk.clkr, + [NPU_CC_NPU_CPC_CLK] = &npu_cc_npu_cpc_clk.clkr, + [NPU_CC_NPU_CPC_TIMER_CLK] = &npu_cc_npu_cpc_timer_clk.clkr, + [NPU_CC_PERF_CNT_CLK] = &npu_cc_perf_cnt_clk.clkr, + [NPU_CC_QTIMER_CORE_CLK] = &npu_cc_qtimer_core_clk.clkr, + [NPU_CC_SLEEP_CLK] = &npu_cc_sleep_clk.clkr, + [NPU_CC_XO_CLK] = &npu_cc_xo_clk.clkr, +}; + +static const struct qcom_reset_map npu_cc_sdmmagpie_resets[] = { + [NPU_CC_CAL_DP_BCR] = { 0x1000 }, + [NPU_CC_NPU_CORE_BCR] = { 0x1024 }, +}; + +static const struct regmap_config npu_cc_sdmmagpie_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x8000, + .fast_io = true, +}; + +static const struct qcom_cc_desc npu_cc_sdmmagpie_desc = { + .config = &npu_cc_sdmmagpie_regmap_config, + .clks = npu_cc_sdmmagpie_clocks, + .num_clks = ARRAY_SIZE(npu_cc_sdmmagpie_clocks), + .resets = npu_cc_sdmmagpie_resets, + .num_resets = ARRAY_SIZE(npu_cc_sdmmagpie_resets), +}; + +static const struct of_device_id npu_cc_sdmmagpie_match_table[] = { + { .compatible = "qcom,npucc-sdmmagpie" }, + { } +}; +MODULE_DEVICE_TABLE(of, npu_cc_sdmmagpie_match_table); + +static int enable_npu_crc(struct regmap *regmap, struct regulator *npu_gdsc) +{ + int ret; + + /* Set npu_cc_cal_cp_clk to the lowest supported frequency */ + clk_set_rate(npu_cc_cal_dp_clk.clkr.hw.clk, + clk_round_rate(npu_cc_cal_dp_clk_src.clkr.hw.clk, 1)); + + /* Turn on the NPU GDSC */ + ret = regulator_enable(npu_gdsc); + if (ret) { + pr_err("Failed to enable the NPU GDSC during CRC sequence\n"); + return ret; + } + + /* Enable npu_cc_cal_cp_clk */ + ret = clk_prepare_enable(npu_cc_cal_dp_clk.clkr.hw.clk); + if (ret) { + pr_err("Failed to enable npu_cc_cal_dp_clk during CRC sequence\n"); + regulator_disable(npu_gdsc); + return ret; + } + + /* Enable MND RC */ + regmap_write(regmap, CRC_MND_CFG, CRC_MND_CFG_SETTING); + regmap_write(regmap, CRC_SID_FSM_CTRL, CRC_SID_FSM_CTRL_SETTING); + + /* Wait for 16 cycles before continuing */ + udelay(1); + + /* Disable npu_cc_cal_cp_clk */ + clk_disable_unprepare(npu_cc_cal_dp_clk.clkr.hw.clk); + + /* Turn off the NPU GDSC */ + regulator_disable(npu_gdsc); + + return 0; +} + +static int npu_cc_sdmmagpie_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret = 0; + + vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx"); + if (IS_ERR(vdd_cx.regulator[0])) { + if (!(PTR_ERR(vdd_cx.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_cx regulator\n"); + return PTR_ERR(vdd_cx.regulator[0]); + } + + npu_gdsc = devm_regulator_get(&pdev->dev, "npu_gdsc"); + if (IS_ERR(npu_gdsc)) { + if (!(PTR_ERR(npu_gdsc) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get npu_gdsc regulator\n"); + return PTR_ERR(npu_gdsc); + } + + regmap = qcom_cc_map(pdev, &npu_cc_sdmmagpie_desc); + if (IS_ERR(regmap)) { + pr_err("Failed to map the npu CC registers\n"); + return PTR_ERR(regmap); + } + + clk_fabia_pll_configure(&npu_cc_pll0, regmap, &npu_cc_pll0_config); + clk_fabia_pll_configure(&npu_cc_pll1, regmap, &npu_cc_pll1_config); + + ret = qcom_cc_really_probe(pdev, &npu_cc_sdmmagpie_desc, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to register NPU CC clocks\n"); + return ret; + } + + ret = enable_npu_crc(regmap, npu_gdsc); + if (ret) { + dev_err(&pdev->dev, "Failed to enable CRC for NPU cal RCG\n"); + return ret; + } + + dev_info(&pdev->dev, "Registered NPU CC clocks\n"); + return ret; +} + +static struct platform_driver npu_cc_sdmmagpie_driver = { + .probe = npu_cc_sdmmagpie_probe, + .driver = { + .name = "npu_cc-sdmmagpie", + .of_match_table = npu_cc_sdmmagpie_match_table, + }, +}; + +static int __init npu_cc_sdmmagpie_init(void) +{ + return platform_driver_register(&npu_cc_sdmmagpie_driver); +} +subsys_initcall(npu_cc_sdmmagpie_init); + +static void __exit npu_cc_sdmmagpie_exit(void) +{ + platform_driver_unregister(&npu_cc_sdmmagpie_driver); +} +module_exit(npu_cc_sdmmagpie_exit); + +MODULE_DESCRIPTION("QTI NPU_CC SDMMAGPIE Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:npu_cc-sdmmagpie"); diff --git a/include/dt-bindings/clock/qcom,npucc-sdmmagpie.h b/include/dt-bindings/clock/qcom,npucc-sdmmagpie.h index 6e9b6c377f5b..519eaa3624fb 100644 --- a/include/dt-bindings/clock/qcom,npucc-sdmmagpie.h +++ b/include/dt-bindings/clock/qcom,npucc-sdmmagpie.h @@ -11,32 +11,34 @@ * GNU General Public License for more details. */ -#ifndef _DT_BINDINGS_CLK_QCOM_NPU_CC_SM7150_H -#define _DT_BINDINGS_CLK_QCOM_NPU_CC_SM7150_H +#ifndef _DT_BINDINGS_CLK_QCOM_NPU_CC_SDMMAGPIE +#define _DT_BINDINGS_CLK_QCOM_NPU_CC_SDMMAGPIE -#define NPU_CC_ARMWIC_CORE_CLK 0 -#define NPU_CC_BTO_CORE_CLK 1 -#define NPU_CC_BWMON_CLK 2 -#define NPU_CC_CAL_DP_CDC_CLK 3 -#define NPU_CC_CAL_DP_CLK 4 -#define NPU_CC_CAL_DP_CLK_SRC 5 -#define NPU_CC_COMP_NOC_AXI_CLK 6 -#define NPU_CC_CONF_NOC_AHB_CLK 7 -#define NPU_CC_NPU_CORE_APB_CLK 8 -#define NPU_CC_NPU_CORE_ATB_CLK 9 -#define NPU_CC_NPU_CORE_CLK 10 -#define NPU_CC_NPU_CORE_CLK_SRC 11 -#define NPU_CC_NPU_CORE_CTI_CLK 12 -#define NPU_CC_NPU_CPC_CLK 13 -#define NPU_CC_NPU_CPC_TIMER_CLK 14 -#define NPU_CC_PERF_CNT_CLK 15 -#define NPU_CC_PLL0 16 -#define NPU_CC_PLL0_OUT_EVEN 17 -#define NPU_CC_PLL_TEST_CLK 18 -#define NPU_CC_QTIMER_CORE_CLK 19 -#define NPU_CC_SLEEP_CLK 20 -#define NPU_CC_XO_CLK 21 +#define NPU_CC_PLL0 0 +#define NPU_CC_PLL0_OUT_EVEN 1 +#define NPU_CC_PLL1 2 +#define NPU_CC_PLL1_OUT_EVEN 3 +#define NPU_CC_ARMWIC_CORE_CLK 4 +#define NPU_CC_BTO_CORE_CLK 5 +#define NPU_CC_BWMON_CLK 6 +#define NPU_CC_CAL_DP_CDC_CLK 7 +#define NPU_CC_CAL_DP_CLK 8 +#define NPU_CC_CAL_DP_CLK_SRC 9 +#define NPU_CC_COMP_NOC_AXI_CLK 10 +#define NPU_CC_CONF_NOC_AHB_CLK 11 +#define NPU_CC_NPU_CORE_APB_CLK 12 +#define NPU_CC_NPU_CORE_ATB_CLK 13 +#define NPU_CC_NPU_CORE_CLK 14 +#define NPU_CC_NPU_CORE_CLK_SRC 15 +#define NPU_CC_NPU_CORE_CTI_CLK 16 +#define NPU_CC_NPU_CPC_CLK 17 +#define NPU_CC_NPU_CPC_TIMER_CLK 18 +#define NPU_CC_PERF_CNT_CLK 19 +#define NPU_CC_QTIMER_CORE_CLK 20 +#define NPU_CC_SLEEP_CLK 21 +#define NPU_CC_XO_CLK 22 -#define NPU_CORE_GDSC 0 +#define NPU_CC_CAL_DP_BCR 0 +#define NPU_CC_NPU_CORE_BCR 1 #endif -- GitLab From 75dc7621ba51be25b61072fbcca16ff806e71fd6 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Sat, 4 Aug 2018 00:17:36 +0530 Subject: [PATCH 0851/1001] ARM: dts: msm: Update NPU CC clock node for SDMMAGPIE Use the real clock & gdsc drivers for NPUCC. Change-Id: I9301d8a37f6193f622dd1c5d0ea37573ca418483 Signed-off-by: Taniya Das --- arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi | 2 +- arch/arm64/boot/dts/qcom/sdmmagpie.dtsi | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi index ad367a28b2ad..790b3a14f7ee 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi @@ -218,7 +218,7 @@ /* GDSCs in NPU CC */ npu_core_gdsc: qcom,gdsc@9911028 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "npu_core_gdsc"; reg = <0x9911028 0x4>; status = "disabled"; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index 73d6e6ead97d..797fab45772f 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -684,8 +684,11 @@ }; clock_npucc: qcom,npucc { - compatible = "qcom,dummycc"; - clock-output-names = "npucc_clocks"; + compatible = "qcom,npucc-sdmmagpie", "syscon"; + reg = <0x9910000 0x10000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + npu_gdsc-supply = <&npu_core_gdsc>; #clock-cells = <1>; #reset-cells = <1>; }; @@ -1791,6 +1794,8 @@ }; &npu_core_gdsc { + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_NPU_CFG_AHB_CLK>; status = "ok"; }; -- GitLab From d8313bec68d620054a8b4d82e67b306bf741cd35 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Wed, 15 Aug 2018 19:01:14 +0530 Subject: [PATCH 0852/1001] ARM: dts: msm: Correct the ports of funnel_monaq_1 for SM6150 Modem etm need to connect to port 6 of funnel_monaq_1 and funnel modem need to connect to port 7 of funnel_monaq_1. Change-Id: Id1e1f98d14469a9981ec27cd29a5410235f42300 Signed-off-by: Mao Jinlong --- arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi b/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi index b490193e83ca..fd4535df0c8a 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi @@ -553,7 +553,7 @@ }; port@2 { - reg = <6>; + reg = <7>; funnel_monaq_1_in_funnel_modem: endpoint { slave-mode; remote-endpoint = @@ -562,7 +562,7 @@ }; port@3 { - reg = <7>; + reg = <6>; funnel_monaq_1_in_modem_etm0: endpoint { slave-mode; remote-endpoint = -- GitLab From c76e41acb98daf6a98c09e84f044acb258fe82a0 Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Thu, 16 Aug 2018 11:35:19 +0530 Subject: [PATCH 0853/1001] ARM: dts: msm: Enable QoS programming for SM6150 Bus driver requires to set the QoS parameters like QoS mode and priorities, so enable the QoS parameter programming. Change-Id: I994e8a5f6243ac86ee3a77c35557a8d4a35b0331 Signed-off-by: Odelu Kukatla --- arch/arm64/boot/dts/qcom/sm6150-bus.dtsi | 38 ++++++++++++++++++++---- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi b/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi index 797f89e181bb..8858acb6e6d4 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi @@ -308,7 +308,6 @@ qcom,qos-off = <4096>; qcom,base-offset = <16384>; qcom,sbm-offset = <0>; - qcom,bypass-qos-prg; qcom,bus-type = <1>; clocks = <>; }; @@ -359,7 +358,6 @@ qcom,qos-off = <128>; qcom,base-offset = <176128>; qcom,sbm-offset = <0>; - qcom,bypass-qos-prg; qcom,bus-type = <1>; clocks = <>; }; @@ -396,7 +394,6 @@ qcom,qos-off = <4096>; qcom,base-offset = <36864>; qcom,sbm-offset = <0>; - qcom,bypass-qos-prg; qcom,bus-type = <1>; clocks = <>; }; @@ -409,7 +406,6 @@ qcom,qos-off = <4096>; qcom,base-offset = <45056>; qcom,sbm-offset = <0>; - qcom,bypass-qos-prg; qcom,bus-type = <1>; clocks = <>; }; @@ -551,6 +547,8 @@ qcom,ap-owned; qcom,prio = <2>; qcom,forwarding; + qcom,defer-init-qos; + qcom,node-qos-bcms = <7035 0 1>; }; mas_xm_emac_avb: mas-xm-emac-avb { @@ -574,7 +572,7 @@ qcom,connections = <&slv_qns_pcie_snoc>; qcom,bus-dev = <&fab_aggre1_noc>; qcom,ap-owned; - qcom,prio = <2>; + qcom,prio = <0>; }; mas_xm_qdss_etr: mas-xm-qdss-etr { @@ -623,6 +621,12 @@ qcom,bus-dev = <&fab_aggre1_noc>; qcom,ap-owned; qcom,prio = <2>; + qcom,node-qos-clks { + clocks = + <&clock_gcc GCC_AGGRE_UFS_PHY_AXI_CLK>; + clock-names = + "clk-aggre-ufs-phy-axi-no-rate"; + }; }; mas_xm_usb2: mas-xm-usb2 { @@ -635,6 +639,12 @@ qcom,bus-dev = <&fab_aggre1_noc>; qcom,ap-owned; qcom,prio = <2>; + qcom,node-qos-clks { + clocks = + <&clock_gcc GCC_AGGRE_USB2_SEC_AXI_CLK>; + clock-names = + "clk-usb3-sec-axi-no-rate"; + }; }; mas_xm_usb3_0: mas-xm-usb3-0 { @@ -647,6 +657,12 @@ qcom,bus-dev = <&fab_aggre1_noc>; qcom,ap-owned; qcom,prio = <2>; + qcom,node-qos-clks { + clocks = + <&clock_gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>; + clock-names = + "clk-usb3-sec-axi-no-rate"; + }; }; mas_qxm_camnoc_hf0_uncomp: mas-qxm-camnoc-hf0-uncomp { @@ -833,6 +849,7 @@ qcom,ap-owned; qcom,prio = <0>; qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qnm_mnoc_sf: mas-qnm-mnoc-sf { @@ -847,6 +864,7 @@ qcom,ap-owned; qcom,prio = <0>; qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qnm_snoc_gc: mas-qnm-snoc-gc { @@ -914,6 +932,7 @@ qcom,ap-owned; qcom,prio = <0>; qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_camnoc_hf1: mas-qxm-camnoc-hf1 { @@ -928,6 +947,7 @@ qcom,ap-owned; qcom,prio = <0>; qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_camnoc_sf: mas-qxm-camnoc-sf { @@ -942,6 +962,7 @@ qcom,ap-owned; qcom,prio = <0>; qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_mdp0: mas-qxm-mdp0 { @@ -956,6 +977,7 @@ qcom,ap-owned; qcom,prio = <0>; qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_rot: mas-qxm-rot { @@ -970,6 +992,7 @@ qcom,ap-owned; qcom,prio = <0>; qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_venus0: mas-qxm-venus0 { @@ -984,6 +1007,7 @@ qcom,ap-owned; qcom,prio = <0>; qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qxm_venus_arm9: mas-qxm-venus-arm9 { @@ -998,6 +1022,7 @@ qcom,ap-owned; qcom,prio = <0>; qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; }; mas_qhm_snoc_cfg: mas-qhm-snoc-cfg { @@ -1042,6 +1067,9 @@ qcom,connections = <&slv_xs_pcie>; qcom,bus-dev = <&fab_system_noc>; qcom,bcms = <&bcm_sn8>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; }; mas_qnm_lpass_anoc: mas-qnm-lpass-anoc { -- GitLab From fd3c190c8b1f188bfa052906c89e454e4cf941bb Mon Sep 17 00:00:00 2001 From: Santosh Mardi Date: Tue, 14 Aug 2018 23:41:10 +0530 Subject: [PATCH 0854/1001] ARM: dts: msm: move devfreq nodes inside soc node for sm6150 Multiple cpu_bw_mon nodes are listed under root dt node which is incorrect. Fix this by moving them under soc node for sm6150 target. Change-Id: I37b15ca37355fb16ec9d6908cc64c4e1acfb8c10 Signed-off-by: Santosh Mardi --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 733 +++++++++++++-------------- 1 file changed, 366 insertions(+), 367 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 268ab89927f2..9a7837da4cdf 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -638,397 +638,138 @@ }; }; - llcc_pmu: llcc-pmu@90cc000 { - compatible = "qcom,qcom-llcc-pmu"; - reg = <0x090cc000 0x300>; - reg-names = "lagg-base"; + mtp_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "qg-batterydata-alium-3600mah.dtsi" + #include "qg-batterydata-mlp356477-2800mah.dtsi" }; +}; - llcc_bw_opp_table: llcc-bw-opp-table { - compatible = "operating-points-v2"; - BW_OPP_ENTRY( 150, 16); /* 2288 MB/s */ - BW_OPP_ENTRY( 300, 16); /* 4577 MB/s */ - BW_OPP_ENTRY( 466, 16); /* 7110 MB/s */ - BW_OPP_ENTRY( 600, 16); /* 9155 MB/s */ - BW_OPP_ENTRY( 806, 16); /* 12298 MB/s */ - BW_OPP_ENTRY( 933, 16); /* 14236 MB/s */ - }; +&soc { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; - cpu_cpu_llcc_bw: qcom,cpu-cpu-llcc-bw { - compatible = "qcom,devbw"; - governor = "performance"; - qcom,src-dst-ports = - ; - qcom,active-only; - operating-points-v2 = <&llcc_bw_opp_table>; + intc: interrupt-controller@17a00000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + #redistributor-regions = <1>; + redistributor-stride = <0x0 0x20000>; + reg = <0x17a00000 0x10000>, /* GICD */ + <0x17a60000 0x100000>; /* GICR * 8 */ + interrupts = <1 9 4>; + interrupt-parent = <&intc>; }; - cpu_cpu_llcc_bwmon: qcom,cpu-cpu-llcc-bwmon@90b6400 { - compatible = "qcom,bimc-bwmon4"; - reg = <0x90b6400 0x300>, <0x90b6300 0x200>; - reg-names = "base", "global_base"; - interrupts = ; - qcom,mport = <0>; - qcom,hw-timer-hz = <19200000>; - qcom,target-dev = <&cpu_cpu_llcc_bw>; - qcom,count-unit = <0x10000>; + pdc: interrupt-controller@b220000{ + compatible = "qcom,pdc-sm6150"; + reg = <0xb220000 0x400>; + #interrupt-cells = <3>; + interrupt-parent = <&intc>; + interrupt-controller; }; - ddr_bw_opp_table: ddr-bw-opp-table { - compatible = "operating-points-v2"; - BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ - BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ - BW_OPP_ENTRY( 451, 4); /* 1720 MB/s */ - BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ - BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ - BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ - BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ - BW_OPP_ENTRY(1353, 4); /* 5161 MB/s */ - BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ - BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 1 0xf08>, + <1 2 0xf08>, + <1 3 0xf08>, + <1 0 0xf08>; + clock-frequency = <19200000>; }; - cpu_llcc_ddr_bw: qcom,cpu-llcc-ddr-bw { - compatible = "qcom,devbw"; - governor = "performance"; - qcom,src-dst-ports = - ; - qcom,active-only; - operating-points-v2 = <&ddr_bw_opp_table>; - }; + timer@0x17c20000{ + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "arm,armv7-timer-mem"; + reg = <0x17c20000 0x1000>; + clock-frequency = <19200000>; - cpu_llcc_ddr_bwmon: qcom,cpu-llcc-ddr-bwmon@90cd000 { - compatible = "qcom,bimc-bwmon5"; - reg = <0x90cd000 0x1000>; - reg-names = "base"; - interrupts = ; - qcom,hw-timer-hz = <19200000>; - qcom,target-dev = <&cpu_llcc_ddr_bw>; - qcom,count-unit = <0x10000>; - }; + frame@0x17c21000 { + frame-number = <0>; + interrupts = <0 8 0x4>, + <0 6 0x4>; + reg = <0x17c21000 0x1000>, + <0x17c22000 0x1000>; + }; - suspendable_ddr_bw_opp_table: suspendable-ddr-bw-opp-table { - compatible = "operating-points-v2"; - BW_OPP_ENTRY( 0, 4); /* 0 MB/s */ - BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ - BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ - BW_OPP_ENTRY( 451, 4); /* 1720 MB/s */ - BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ - BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ - BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ - BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ - BW_OPP_ENTRY(1353, 4); /* 5161 MB/s */ - BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ - BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ - }; + frame@17c23000 { + frame-number = <1>; + interrupts = <0 9 0x4>; + reg = <0x17c23000 0x1000>; + status = "disabled"; + }; - cdsp_cdsp_l3_lat: qcom,cdsp-cdsp-l3-lat { - compatible = "devfreq-simple-dev"; - clock-names = "devfreq_clk"; - clocks = <&clock_cpucc L3_MISC_VOTE_CLK>; - governor = "powersave"; - }; + frame@17c25000 { + frame-number = <2>; + interrupts = <0 10 0x4>; + reg = <0x17c25000 0x1000>; + status = "disabled"; + }; - cpu0_cpu_l3_lat: qcom,cpu0-cpu-l3-lat { - compatible = "devfreq-simple-dev"; - clock-names = "devfreq_clk"; - clocks = <&clock_cpucc L3_CLUSTER0_VOTE_CLK>; - governor = "performance"; - }; + frame@17c27000 { + frame-number = <3>; + interrupts = <0 11 0x4>; + reg = <0x17c27000 0x1000>; + status = "disabled"; + }; - cpu0_cpu_l3_latmon: qcom,cpu0-cpu-l3-latmon { - compatible = "qcom,arm-memlat-mon"; - qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; - qcom,target-dev = <&cpu0_cpu_l3_lat>; - qcom,cachemiss-ev = <0x17>; - qcom,core-dev-table = - < 576000 300000000 >, - < 1017600 556800000 >, - < 1209660 806400000 >, - < 1516800 940800000 >, - < 1804800 1363200000 >; - }; + frame@17c29000 { + frame-number = <4>; + interrupts = <0 12 0x4>; + reg = <0x17c29000 0x1000>; + status = "disabled"; + }; - cpu6_cpu_l3_lat: qcom,cpu6-cpu-l3-lat { - compatible = "devfreq-simple-dev"; - clock-names = "devfreq_clk"; - clocks = <&clock_cpucc L3_CLUSTER1_VOTE_CLK>; - governor = "performance"; - }; + frame@17c2b000 { + frame-number = <5>; + interrupts = <0 13 0x4>; + reg = <0x17c2b000 0x1000>; + status = "disabled"; + }; - cpu6_cpu_l3_latmon: qcom,cpu6-cpu-l3-latmon { - compatible = "qcom,arm-memlat-mon"; - qcom,cpulist = <&CPU6 &CPU7>; - qcom,target-dev = <&cpu6_cpu_l3_lat>; - qcom,cachemiss-ev = <0x17>; - qcom,core-dev-table = - < 1017600 556800000 >, - < 1209600 806400000 >, - < 1516800 940800000 >, - < 1708800 1209600000 >, - < 2208000 1363200000 >; + frame@17c2d000 { + frame-number = <6>; + interrupts = <0 14 0x4>; + reg = <0x17c2d000 0x1000>; + status = "disabled"; + }; }; - cpu0_cpu_llcc_lat: qcom,cpu0-cpu-llcc-lat { - compatible = "qcom,devbw"; - governor = "performance"; - qcom,src-dst-ports = - ; - qcom,active-only; - operating-points-v2 = <&llcc_bw_opp_table>; + clocks { + sleep_clk: sleep-clk { + compatible = "fixed-clock"; + clock-frequency = <32000>; + clock-output-names = "chip_sleep_clk"; + #clock-cells = <1>; + }; }; - cpu0_cpu_llcc_latmon: qcom,cpu0-cpu-llcc-latmon { - compatible = "qcom,arm-memlat-mon"; - qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; - qcom,target-dev = <&cpu0_cpu_llcc_lat>; - qcom,cachemiss-ev = <0x2A>; - qcom,core-dev-table = - < 748000 MHZ_TO_MBPS(150, 16) >, - < 1209600 MHZ_TO_MBPS(300, 16) >, - < 1516800 MHZ_TO_MBPS(466, 16) >, - < 1804800 MHZ_TO_MBPS(600, 16) >; + clock_rpmh: qcom,rpmhclk { + compatible = "qcom,rpmh-clk-sm6150"; + mboxes = <&apps_rsc 0>; + mbox-names = "apps"; + #clock-cells = <1>; }; - cpu6_cpu_llcc_lat: qcom,cpu6-cpu-llcc-lat { - compatible = "qcom,devbw"; - governor = "performance"; - qcom,src-dst-ports = - ; - qcom,active-only; - operating-points-v2 = <&llcc_bw_opp_table>; + clock_aop: qcom,aopclk { + compatible = "qcom,aop-qmp-clk"; + #clock-cells = <1>; + mboxes = <&qmp_aop 0>; + mbox-names = "qdss_clk"; }; - cpu6_cpu_llcc_latmon: qcom,cpu6-cpu-llcc-latmon { - compatible = "qcom,arm-memlat-mon"; - qcom,cpulist = <&CPU6 &CPU7>; - qcom,target-dev = <&cpu6_cpu_llcc_lat>; - qcom,cachemiss-ev = <0x2A>; - qcom,core-dev-table = - < 768000 MHZ_TO_MBPS(300, 16) >, - < 1017600 MHZ_TO_MBPS(466, 16) >, - < 1209600 MHZ_TO_MBPS(600, 16) >, - < 1708800 MHZ_TO_MBPS(806, 16) >, - < 2208000 MHZ_TO_MBPS(933, 16) >; - }; - - cpu0_llcc_ddr_lat: qcom,cpu0-llcc-ddr-lat { - compatible = "qcom,devbw"; - governor = "performance"; - qcom,src-dst-ports = - ; - qcom,active-only; - operating-points-v2 = <&ddr_bw_opp_table>; - }; - - cpu0_llcc_ddr_latmon: qcom,cpu0-llcc-ddr-latmon { - compatible = "qcom,arm-memlat-mon"; - qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; - qcom,target-dev = <&cpu0_llcc_ddr_lat>; - qcom,cachemiss-ev = <0x1000>; - qcom,core-dev-table = - < 748000 MHZ_TO_MBPS( 300, 4) >, - < 1017600 MHZ_TO_MBPS( 451, 4) >, - < 1209600 MHZ_TO_MBPS( 547, 4) >, - < 1516800 MHZ_TO_MBPS( 768, 4) >, - < 1804800 MHZ_TO_MBPS(1017, 4) >; - }; - - cpu6_llcc_ddr_lat: qcom,cpu6-llcc-ddr-lat { - compatible = "qcom,devbw"; - governor = "performance"; - qcom,src-dst-ports = - ; - qcom,active-only; - operating-points-v2 = <&ddr_bw_opp_table>; - }; - - cpu6_llcc_ddr_latmon: qcom,cpu6-llcc-ddr-latmon { - compatible = "qcom,arm-memlat-mon"; - qcom,cpulist = <&CPU6 &CPU7>; - qcom,target-dev = <&cpu6_llcc_ddr_lat>; - qcom,cachemiss-ev = <0x1000>; - qcom,core-dev-table = - < 768000 MHZ_TO_MBPS( 451, 4) >, - < 1017600 MHZ_TO_MBPS( 547, 4) >, - < 1209600 MHZ_TO_MBPS(1017, 4) >, - < 1708800 MHZ_TO_MBPS(1555, 4) >, - < 2208000 MHZ_TO_MBPS(1804, 4) >; - }; - - cpu0_cpu_ddr_latfloor: qcom,cpu0-cpu-ddr-latfloor { - compatible = "qcom,devbw"; - governor = "performance"; - qcom,src-dst-ports = - ; - qcom,active-only; - operating-points-v2 = <&ddr_bw_opp_table>; - }; - - cpu0_computemon: qcom,cpu0-computemon { - compatible = "qcom,arm-cpu-mon"; - qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; - qcom,target-dev = <&cpu0_cpu_ddr_latfloor>; - qcom,core-dev-table = - < 748800 MHZ_TO_MBPS( 300, 4) >, - < 1209600 MHZ_TO_MBPS( 451, 4) >, - < 1593600 MHZ_TO_MBPS( 547, 4) >, - < 1804800 MHZ_TO_MBPS( 768, 4) >; - }; - - cpu6_cpu_ddr_latfloor: qcom,cpu6-cpu-ddr-latfloor { - compatible = "qcom,devbw"; - governor = "performance"; - qcom,src-dst-ports = - ; - qcom,active-only; - operating-points-v2 = <&ddr_bw_opp_table>; - }; - - cpu6_computemon: qcom,cpu6-computemon { - compatible = "qcom,arm-cpu-mon"; - qcom,cpulist = <&CPU6 &CPU7>; - qcom,target-dev = <&cpu6_cpu_ddr_latfloor>; - qcom,core-dev-table = - < 1017600 MHZ_TO_MBPS( 300, 4) >, - < 1209600 MHZ_TO_MBPS( 547, 4) >, - < 1516800 MHZ_TO_MBPS( 768, 4) >, - < 1708800 MHZ_TO_MBPS(1017, 4) >, - < 2208000 MHZ_TO_MBPS(1804, 4) >; - }; - - mtp_batterydata: qcom,battery-data { - qcom,batt-id-range-pct = <15>; - #include "qg-batterydata-alium-3600mah.dtsi" - #include "qg-batterydata-mlp356477-2800mah.dtsi" - }; -}; - -&soc { - #address-cells = <1>; - #size-cells = <1>; - ranges = <0 0 0 0xffffffff>; - compatible = "simple-bus"; - - intc: interrupt-controller@17a00000 { - compatible = "arm,gic-v3"; - #interrupt-cells = <3>; - interrupt-controller; - #redistributor-regions = <1>; - redistributor-stride = <0x0 0x20000>; - reg = <0x17a00000 0x10000>, /* GICD */ - <0x17a60000 0x100000>; /* GICR * 8 */ - interrupts = <1 9 4>; - interrupt-parent = <&intc>; - }; - - pdc: interrupt-controller@b220000{ - compatible = "qcom,pdc-sm6150"; - reg = <0xb220000 0x400>; - #interrupt-cells = <3>; - interrupt-parent = <&intc>; - interrupt-controller; - }; - - timer { - compatible = "arm,armv8-timer"; - interrupts = <1 1 0xf08>, - <1 2 0xf08>, - <1 3 0xf08>, - <1 0 0xf08>; - clock-frequency = <19200000>; - }; - - timer@0x17c20000{ - #address-cells = <1>; - #size-cells = <1>; - ranges; - compatible = "arm,armv7-timer-mem"; - reg = <0x17c20000 0x1000>; - clock-frequency = <19200000>; - - frame@0x17c21000 { - frame-number = <0>; - interrupts = <0 8 0x4>, - <0 6 0x4>; - reg = <0x17c21000 0x1000>, - <0x17c22000 0x1000>; - }; - - frame@17c23000 { - frame-number = <1>; - interrupts = <0 9 0x4>; - reg = <0x17c23000 0x1000>; - status = "disabled"; - }; - - frame@17c25000 { - frame-number = <2>; - interrupts = <0 10 0x4>; - reg = <0x17c25000 0x1000>; - status = "disabled"; - }; - - frame@17c27000 { - frame-number = <3>; - interrupts = <0 11 0x4>; - reg = <0x17c27000 0x1000>; - status = "disabled"; - }; - - frame@17c29000 { - frame-number = <4>; - interrupts = <0 12 0x4>; - reg = <0x17c29000 0x1000>; - status = "disabled"; - }; - - frame@17c2b000 { - frame-number = <5>; - interrupts = <0 13 0x4>; - reg = <0x17c2b000 0x1000>; - status = "disabled"; - }; - - frame@17c2d000 { - frame-number = <6>; - interrupts = <0 14 0x4>; - reg = <0x17c2d000 0x1000>; - status = "disabled"; - }; - }; - - clocks { - sleep_clk: sleep-clk { - compatible = "fixed-clock"; - clock-frequency = <32000>; - clock-output-names = "chip_sleep_clk"; - #clock-cells = <1>; - }; - }; - - clock_rpmh: qcom,rpmhclk { - compatible = "qcom,rpmh-clk-sm6150"; - mboxes = <&apps_rsc 0>; - mbox-names = "apps"; - #clock-cells = <1>; - }; - - clock_aop: qcom,aopclk { - compatible = "qcom,aop-qmp-clk"; - #clock-cells = <1>; - mboxes = <&qmp_aop 0>; - mbox-names = "qdss_clk"; - }; - - clock_gcc: qcom,gcc@100000 { - compatible = "qcom,gcc-sm6150", "syscon"; - reg = <0x100000 0x1f0000>; - reg-names = "cc_base"; - vdd_cx-supply = <&VDD_CX_LEVEL>; - vdd_cx_ao-supply = <&VDD_CX_LEVEL_AO>; - #clock-cells = <1>; - #reset-cells = <1>; + clock_gcc: qcom,gcc@100000 { + compatible = "qcom,gcc-sm6150", "syscon"; + reg = <0x100000 0x1f0000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_cx_ao-supply = <&VDD_CX_LEVEL_AO>; + #clock-cells = <1>; + #reset-cells = <1>; }; clock_videocc: qcom,videocc@ab00000 { @@ -2457,6 +2198,264 @@ qcom,guard-memory; }; + llcc_pmu: llcc-pmu@90cc000 { + compatible = "qcom,qcom-llcc-pmu"; + reg = <0x090cc000 0x300>; + reg-names = "lagg-base"; + }; + + llcc_bw_opp_table: llcc-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 150, 16); /* 2288 MB/s */ + BW_OPP_ENTRY( 300, 16); /* 4577 MB/s */ + BW_OPP_ENTRY( 466, 16); /* 7110 MB/s */ + BW_OPP_ENTRY( 600, 16); /* 9155 MB/s */ + BW_OPP_ENTRY( 806, 16); /* 12298 MB/s */ + BW_OPP_ENTRY( 933, 16); /* 14236 MB/s */ + }; + + cpu_cpu_llcc_bw: qcom,cpu-cpu-llcc-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&llcc_bw_opp_table>; + }; + + cpu_cpu_llcc_bwmon: qcom,cpu-cpu-llcc-bwmon@90b6400 { + compatible = "qcom,bimc-bwmon4"; + reg = <0x90b6400 0x300>, <0x90b6300 0x200>; + reg-names = "base", "global_base"; + interrupts = ; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&cpu_cpu_llcc_bw>; + qcom,count-unit = <0x10000>; + }; + + ddr_bw_opp_table: ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ + BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ + BW_OPP_ENTRY( 451, 4); /* 1720 MB/s */ + BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ + BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ + BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ + BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ + BW_OPP_ENTRY(1353, 4); /* 5161 MB/s */ + BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ + BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ + }; + + cpu_llcc_ddr_bw: qcom,cpu-llcc-ddr-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu_llcc_ddr_bwmon: qcom,cpu-llcc-ddr-bwmon@90cd000 { + compatible = "qcom,bimc-bwmon5"; + reg = <0x90cd000 0x1000>; + reg-names = "base"; + interrupts = ; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&cpu_llcc_ddr_bw>; + qcom,count-unit = <0x10000>; + }; + + suspendable_ddr_bw_opp_table: suspendable-ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 0, 4); /* 0 MB/s */ + BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ + BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ + BW_OPP_ENTRY( 451, 4); /* 1720 MB/s */ + BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ + BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ + BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ + BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ + BW_OPP_ENTRY(1353, 4); /* 5161 MB/s */ + BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ + BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ + }; + + cdsp_cdsp_l3_lat: qcom,cdsp-cdsp-l3-lat { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_cpucc L3_MISC_VOTE_CLK>; + governor = "powersave"; + }; + + cpu0_cpu_l3_lat: qcom,cpu0-cpu-l3-lat { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_cpucc L3_CLUSTER0_VOTE_CLK>; + governor = "performance"; + }; + + cpu0_cpu_l3_latmon: qcom,cpu0-cpu-l3-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_cpu_l3_lat>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 576000 300000000 >, + < 1017600 556800000 >, + < 1209660 806400000 >, + < 1516800 940800000 >, + < 1804800 1363200000 >; + }; + + cpu6_cpu_l3_lat: qcom,cpu6-cpu-l3-lat { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_cpucc L3_CLUSTER1_VOTE_CLK>; + governor = "performance"; + }; + + cpu6_cpu_l3_latmon: qcom,cpu6-cpu-l3-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&cpu6_cpu_l3_lat>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 1017600 556800000 >, + < 1209600 806400000 >, + < 1516800 940800000 >, + < 1708800 1209600000 >, + < 2208000 1363200000 >; + }; + + cpu0_cpu_llcc_lat: qcom,cpu0-cpu-llcc-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&llcc_bw_opp_table>; + }; + + cpu0_cpu_llcc_latmon: qcom,cpu0-cpu-llcc-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_cpu_llcc_lat>; + qcom,cachemiss-ev = <0x2A>; + qcom,core-dev-table = + < 748000 MHZ_TO_MBPS(150, 16) >, + < 1209600 MHZ_TO_MBPS(300, 16) >, + < 1516800 MHZ_TO_MBPS(466, 16) >, + < 1804800 MHZ_TO_MBPS(600, 16) >; + }; + + cpu6_cpu_llcc_lat: qcom,cpu6-cpu-llcc-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&llcc_bw_opp_table>; + }; + + cpu6_cpu_llcc_latmon: qcom,cpu6-cpu-llcc-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&cpu6_cpu_llcc_lat>; + qcom,cachemiss-ev = <0x2A>; + qcom,core-dev-table = + < 768000 MHZ_TO_MBPS(300, 16) >, + < 1017600 MHZ_TO_MBPS(466, 16) >, + < 1209600 MHZ_TO_MBPS(600, 16) >, + < 1708800 MHZ_TO_MBPS(806, 16) >, + < 2208000 MHZ_TO_MBPS(933, 16) >; + }; + + cpu0_llcc_ddr_lat: qcom,cpu0-llcc-ddr-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu0_llcc_ddr_latmon: qcom,cpu0-llcc-ddr-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_llcc_ddr_lat>; + qcom,cachemiss-ev = <0x1000>; + qcom,core-dev-table = + < 748000 MHZ_TO_MBPS( 300, 4) >, + < 1017600 MHZ_TO_MBPS( 451, 4) >, + < 1209600 MHZ_TO_MBPS( 547, 4) >, + < 1516800 MHZ_TO_MBPS( 768, 4) >, + < 1804800 MHZ_TO_MBPS(1017, 4) >; + }; + + cpu6_llcc_ddr_lat: qcom,cpu6-llcc-ddr-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu6_llcc_ddr_latmon: qcom,cpu6-llcc-ddr-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&cpu6_llcc_ddr_lat>; + qcom,cachemiss-ev = <0x1000>; + qcom,core-dev-table = + < 768000 MHZ_TO_MBPS( 451, 4) >, + < 1017600 MHZ_TO_MBPS( 547, 4) >, + < 1209600 MHZ_TO_MBPS(1017, 4) >, + < 1708800 MHZ_TO_MBPS(1555, 4) >, + < 2208000 MHZ_TO_MBPS(1804, 4) >; + }; + + cpu0_cpu_ddr_latfloor: qcom,cpu0-cpu-ddr-latfloor { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu0_computemon: qcom,cpu0-computemon { + compatible = "qcom,arm-cpu-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_cpu_ddr_latfloor>; + qcom,core-dev-table = + < 748800 MHZ_TO_MBPS( 300, 4) >, + < 1209600 MHZ_TO_MBPS( 451, 4) >, + < 1593600 MHZ_TO_MBPS( 547, 4) >, + < 1804800 MHZ_TO_MBPS( 768, 4) >; + }; + + cpu6_cpu_ddr_latfloor: qcom,cpu6-cpu-ddr-latfloor { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu6_computemon: qcom,cpu6-computemon { + compatible = "qcom,arm-cpu-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&cpu6_cpu_ddr_latfloor>; + qcom,core-dev-table = + < 1017600 MHZ_TO_MBPS( 300, 4) >, + < 1209600 MHZ_TO_MBPS( 547, 4) >, + < 1516800 MHZ_TO_MBPS( 768, 4) >, + < 1708800 MHZ_TO_MBPS(1017, 4) >, + < 2208000 MHZ_TO_MBPS(1804, 4) >; + }; }; #include "pm6150.dtsi" -- GitLab From c1612edde8870843516f9113bea386f3b3e7c304 Mon Sep 17 00:00:00 2001 From: Pratham Pratap Date: Thu, 26 Jul 2018 11:29:14 +0530 Subject: [PATCH 0855/1001] ARM: dts: msm: Add dp dm interrupts for SM6150 Since SM6150 uses PDC interrupts, add dp dm interrupts instead of hs_phy_irq. This change modifies the voltage range for vdd according to the power grid, updates the clock frequency and tx fifo size for secondary USB controller. Since there is no PMIC support on RUMI, delete extcon device node from rumi dts and change the dr_mode to otg. Change-Id: I6996ce1abd8fe5e398f265ef2aab15faf95242f0 Signed-off-by: Pratham Pratap --- arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi | 7 +++- arch/arm64/boot/dts/qcom/sm6150-usb.dtsi | 39 ++++++++++++----------- arch/arm64/boot/dts/qcom/sm6150.dtsi | 1 - 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi b/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi index 18d98efc50cc..34ff3eb557eb 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi @@ -191,11 +191,16 @@ }; &usb0 { + /delete-property/ extcon; dwc3@a600000 { usb-phy = <&usb_emu_phy>, <&usb_nop_phy>; maximum-speed = "high-speed"; - dr_mode = "peripheral"; + dr_mode = "otg"; }; }; +&usb_qmp_phy { + status = "disabled"; +}; + #include "sm6150-stub-regulator.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sm6150-usb.dtsi b/arch/arm64/boot/dts/qcom/sm6150-usb.dtsi index 7ba008e63868..73150062fa22 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-usb.dtsi @@ -26,8 +26,9 @@ #size-cells = <1>; ranges; - interrupts = <0 130 0>, <0 607 0>, <0 131 0>; - interrupt-names = "pwr_event_irq", "ss_phy_irq", "hs_phy_irq"; + interrupts = <0 489 0>, <0 130 0>, <0 607 0>, <0 488 0>; + interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", + "ss_phy_irq", "dm_hs_phy_irq"; qcom,use-pdc-interrupts; USB3_GDSC-supply = <&usb30_prim_gdsc>; @@ -49,7 +50,7 @@ qcom,dwc-usb3-msm-tx-fifo-size = <21288>; qcom,msm-bus,name = "usb0"; - qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-cases = <4>; qcom,msm-bus,num-paths = <3>; qcom,msm-bus,vectors-KBps = /* suspend vote */ @@ -86,8 +87,6 @@ snps,has-lpm-erratum; snps,hird-threshold = /bits/ 8 <0x10>; snps,usb3_lpm_capable; - snps,ssp-u3-u0-quirk; - snps,usb3-u1u2-disable; usb-core-id = <0>; maximum-speed = "super-speed"; dr_mode = "otg"; @@ -136,7 +135,7 @@ vdd-supply = <&pm6150_l4>; vdda18-supply = <&pm6150_l11>; vdda33-supply = <&pm6150_l17>; - qcom,vdd-voltage-level = <0 875000 875000>; + qcom,vdd-voltage-level = <0 925000 975000>; qcom,tune2-efuse-bit-pos = <25>; qcom,tune2-efuse-num-bits = <4>; qcom,qusb-phy-init-seq = <0xf8 0x80 @@ -164,13 +163,13 @@ /* Primary USB port related QMP USB PHY */ usb_qmp_phy: ssphy@88e6000 { - compatible = "qcom,usb-ssphy-qmp-dp-combo"; + compatible = "qcom,usb-ssphy-qmp-v2"; reg = <0x88e6000 0x1000>; reg-names = "qmp_phy_base"; vdd-supply = <&pm6150_l4>; core-supply = <&pm6150_l11>; - qcom,vdd-voltage-level = <0 875000 875000>; + qcom,vdd-voltage-level = <0 925000 975000>; qcom,core-voltage-level = <0 1800000 1800000>; qcom,qmp-phy-init-seq = /* */ @@ -292,13 +291,15 @@ <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, <&clock_rpmh RPMH_CXO_CLK>, <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, - <&clock_gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>; + <&clock_gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>, + <&clock_gcc GCC_AHB2PHY_WEST_CLK>; clock-names = "aux_clk", "pipe_clk", "ref_clk_src", - "ref_clk", "com_aux_clk"; + "ref_clk", "com_aux_clk", "cfg_ahb_clk"; - resets = <&clock_gcc GCC_USB30_PRIM_BCR>; - reset-names = "phy_reset"; + resets = <&clock_gcc GCC_USB3_DP_PHY_PRIM_SP0_BCR>, + <&clock_gcc GCC_USB3PHY_PHY_PRIM_SP0_BCR>; + reset-names = "phy_phy_reset", "phy_reset"; }; usb_audio_qmi_dev { @@ -324,8 +325,9 @@ #size-cells = <1>; ranges; - interrupts = <0 664 0>, <0 663 0>; - interrupt-names = "pwr_event_irq", "hs_phy_irq"; + interrupts = <0 491 0>, <0 663 0>, <0 490 0>; + interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", + "dm_hs_phy_irq"; qcom,use-pdc-interrupts; USB3_GDSC-supply = <&usb20_sec_gdsc>; @@ -341,10 +343,9 @@ resets = <&clock_gcc GCC_USB20_SEC_BCR>; reset-names = "core_reset"; - qcom,core-clk-rate = <200000000>; + qcom,core-clk-rate = <120000000>; qcom,core-clk-rate-hs = <66666667>; - qcom,num-gsi-evt-buffs = <0x3>; - qcom,dwc-usb3-msm-tx-fifo-size = <27696>; + qcom,dwc-usb3-msm-tx-fifo-size = <21288>; qcom,charging-disabled; qcom,msm-bus,name = "usb1"; @@ -362,7 +363,7 @@ compatible = "snps,dwc3"; reg = <0xa800000 0xcd00>; interrupt-parent = <&intc>; - interrupts = <0 665 0>; + interrupts = <0 664 0>; usb-phy = <&qusb_phy1>, <&usb_nop_phy>; tx-fifo-resize; linux,sysdev_is_parent; @@ -385,7 +386,7 @@ vdd-supply = <&pm6150_l4>; vdda18-supply = <&pm6150_l11>; vdda33-supply = <&pm6150_l17>; - qcom,vdd-voltage-level = <0 875000 875000>; + qcom,vdd-voltage-level = <0 925000 975000>; qcom,qusb-phy-init-seq = <0xf8 0x80 0xb3 0x84 0x83 0x88 diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 4bfae896f4b0..0e0093a86028 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -2476,7 +2476,6 @@ &usb0 { extcon = <&pm6150_pdphy>; - vbus_dwc3-supply = <&smb5_vbus>; }; &pm6150_vadc { -- GitLab From 9a71f302fc53e08c63bb974c8f16a3de28a82fd3 Mon Sep 17 00:00:00 2001 From: Amit Nischal Date: Tue, 3 Jul 2018 16:23:18 +0530 Subject: [PATCH 0856/1001] clk: qcom: Add display clock controller driver for SDMMAGPIE Add support for the display clock controller found on SDMMAGPIE based devices. This would allow display drivers to probe and control their clocks. Change-Id: I627d0c5e2ec133ba1a6ca63e60f5ba28eb23b93f Signed-off-by: Amit Nischal --- .../devicetree/bindings/clock/qcom,dispcc.txt | 7 +- drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/dispcc-sdmmagpie.c | 1162 +++++++++++++++++ .../dt-bindings/clock/qcom,dispcc-sdmmagpie.h | 76 +- 5 files changed, 1215 insertions(+), 40 deletions(-) create mode 100644 drivers/clk/qcom/dispcc-sdmmagpie.c diff --git a/Documentation/devicetree/bindings/clock/qcom,dispcc.txt b/Documentation/devicetree/bindings/clock/qcom,dispcc.txt index 9eaaeb35829a..0c2aefae8414 100644 --- a/Documentation/devicetree/bindings/clock/qcom,dispcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,dispcc.txt @@ -2,8 +2,11 @@ Qualcomm Technologies, Inc. Display Clock & Reset Controller Binding -------------------------------------------------------------------- Required properties : -- compatible : Shall contain "qcom,dispcc-sm8150" or "qcom,dispcc-sm8150-v2" or - "qcom,dispcc-sm6150". +- compatible : Shall contain one of the following: + "qcom,dispcc-sm8150", + "qcom,dispcc-sm8150-v2", + "qcom,dispcc-sm6150", + "qcom,dispcc-sdmmagpie". - reg : Shall contain base register location and length. - reg-names: Address name. Must be "cc_base". - vdd_mm-supply: phandle to the MM_CX rail that needs to be voted on behalf diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 5932ad41af19..569f0aabab06 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -396,6 +396,15 @@ config MSM_DISPCC_SM6150 Say Y if you want to support display devices and functionality such as splash screen. +config MSM_DISPCC_SDMMAGPIE + tristate "SDMMAGPIE Display Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the display clock controller on Qualcomm Technologies, Inc + SDMMAGPIE devices. + Say Y if you want to support display devices and functionality such as + splash screen. + config MSM_GCC_SDMMAGPIE tristate "SDMMAGPIE Global Clock Controller" depends on COMMON_CLK_QCOM diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index df36e77f22a2..9683424baeaf 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_MSM_DEBUGCC_SM6150) += debugcc-sm6150.o obj-$(CONFIG_MSM_DEBUGCC_SM8150) += debugcc-sm8150.o obj-$(CONFIG_MSM_DISPCC_SM6150) += dispcc-sm6150.o obj-$(CONFIG_MSM_DISPCC_SM8150) += dispcc-sm8150.o +obj-$(CONFIG_MSM_DISPCC_SDMMAGPIE) += dispcc-sdmmagpie.o obj-$(CONFIG_MDM_DEBUGCC_QCS405) += debugcc-qcs405.o obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o obj-$(CONFIG_MSM_GCC_8916) += gcc-msm8916.o diff --git a/drivers/clk/qcom/dispcc-sdmmagpie.c b/drivers/clk/qcom/dispcc-sdmmagpie.c new file mode 100644 index 000000000000..6f6cbe90eea4 --- /dev/null +++ b/drivers/clk/qcom/dispcc-sdmmagpie.c @@ -0,0 +1,1162 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "common.h" +#include "reset.h" +#include "vdd-level.h" + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + +#define DISP_CC_MISC_CMD 0x8000 + +static DEFINE_VDD_REGULATORS(vdd_cx, VDD_NUM, 1, vdd_corner); + +enum { + P_BI_TCXO, + P_CHIP_SLEEP_CLK, + P_CORE_BI_PLL_TEST_SE, + P_DISP_CC_PLL0_OUT_EVEN, + P_DISP_CC_PLL0_OUT_MAIN, + P_DP_PHY_PLL_LINK_CLK, + P_DP_PHY_PLL_VCO_DIV_CLK, + P_DSI0_PHY_PLL_OUT_BYTECLK, + P_DSI0_PHY_PLL_OUT_DSICLK, + P_DSI1_PHY_PLL_OUT_BYTECLK, + P_DSI1_PHY_PLL_OUT_DSICLK, + P_GPLL0_OUT_MAIN, +}; + +static const struct parent_map disp_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_BYTECLK, 1 }, + { P_DSI1_PHY_PLL_OUT_BYTECLK, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_0[] = { + "bi_tcxo", + "dsi0_phy_pll_out_byteclk", + "dsi1_phy_pll_out_byteclk", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_DP_PHY_PLL_LINK_CLK, 1 }, + { P_DP_PHY_PLL_VCO_DIV_CLK, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_1[] = { + "bi_tcxo", + "dp_phy_pll_link_clk", + "dp_phy_pll_vco_div_clk", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_2[] = { + "bi_tcxo", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_DISP_CC_PLL0_OUT_MAIN, 1 }, + { P_GPLL0_OUT_MAIN, 4 }, + { P_DISP_CC_PLL0_OUT_EVEN, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_3[] = { + "bi_tcxo", + "disp_cc_pll0", + "gpll0", + "disp_cc_pll0_out_even", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_DSICLK, 1 }, + { P_DSI1_PHY_PLL_OUT_DSICLK, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_4[] = { + "bi_tcxo", + "dsi0_phy_pll_out_dsiclk", + "dsi1_phy_pll_out_dsiclk", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_5[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 4 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_5[] = { + "bi_tcxo", + "gpll0", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_6[] = { + { P_CHIP_SLEEP_CLK, 0 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_6[] = { + "chip_sleep_clk", + "core_bi_pll_test_se", +}; + +static struct pll_vco fabia_vco[] = { + { 249600000, 2000000000, 0 }, + { 125000000, 1000000000, 1 }, +}; + +/* 860MHz configuration */ +static const struct alpha_pll_config disp_cc_pll0_config = { + .l = 0x2c, + .frac = 0xcaaa, + .test_ctl_val = 0x40000000, +}; + +static struct clk_alpha_pll disp_cc_pll0 = { + .offset = 0x0, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_pll_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 430000000, + [VDD_LOW_L1] = 860000000}, + }, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(37500000, P_GPLL0_OUT_MAIN, 16, 0, 0), + F(75000000, P_GPLL0_OUT_MAIN, 8, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_ahb_clk_src = { + .cmd_rcgr = 0x22bc, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_5, + .freq_tbl = ftbl_disp_cc_mdss_ahb_clk_src, + .enable_safe_config = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_ahb_clk_src", + .parent_names = disp_cc_parent_names_5, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 19200000, + [VDD_LOW] = 37500000, + [VDD_NOMINAL] = 75000000}, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_byte0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = { + .cmd_rcgr = 0x2110, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte0_clk_src", + .parent_names = disp_cc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_byte2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 180000000, + [VDD_LOW] = 275000000, + [VDD_LOW_L1] = 358000000}, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_byte1_clk_src = { + .cmd_rcgr = 0x212c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte1_clk_src", + .parent_names = disp_cc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_byte2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 180000000, + [VDD_LOW] = 275000000, + [VDD_LOW_L1] = 358000000}, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dp_aux_clk_src = { + .cmd_rcgr = 0x21dc, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_2, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_aux_clk_src", + .parent_names = disp_cc_parent_names_2, + .num_parents = 2, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 19200000}, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_dp_crypto_clk_src[] = { + F(108000, P_DP_PHY_PLL_LINK_CLK, 3, 0, 0), + F(180000, P_DP_PHY_PLL_LINK_CLK, 3, 0, 0), + F(360000, P_DP_PHY_PLL_LINK_CLK, 1.5, 0, 0), + F(540000, P_DP_PHY_PLL_LINK_CLK, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_dp_crypto_clk_src = { + .cmd_rcgr = 0x2194, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .freq_tbl = ftbl_disp_cc_mdss_dp_crypto_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_crypto_clk_src", + .parent_names = disp_cc_parent_names_1, + .num_parents = 4, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 108000, + [VDD_LOW] = 180000, + [VDD_LOW_L1] = 360000, + [VDD_NOMINAL] = 540000}, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_dp_link_clk_src[] = { + F(162000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0), + F(270000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0), + F(540000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), + F(810000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_dp_link_clk_src = { + .cmd_rcgr = 0x2178, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .freq_tbl = ftbl_disp_cc_mdss_dp_link_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_link_clk_src", + .parent_names = disp_cc_parent_names_1, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 162000, + [VDD_LOW] = 270000, + [VDD_LOW_L1] = 540000, + [VDD_NOMINAL] = 810000}, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dp_pixel1_clk_src = { + .cmd_rcgr = 0x21c4, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_pixel1_clk_src", + .parent_names = disp_cc_parent_names_1, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_dp_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 202500, + [VDD_LOW] = 337500, + [VDD_NOMINAL] = 675000}, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dp_pixel_clk_src = { + .cmd_rcgr = 0x21ac, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_pixel_clk_src", + .parent_names = disp_cc_parent_names_1, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_dp_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 202500, + [VDD_LOW] = 337500, + [VDD_NOMINAL] = 675000}, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_esc0_clk_src = { + .cmd_rcgr = 0x2148, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_esc0_clk_src", + .parent_names = disp_cc_parent_names_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 19200000}, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_esc1_clk_src = { + .cmd_rcgr = 0x2160, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_esc1_clk_src", + .parent_names = disp_cc_parent_names_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 19200000}, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(85714286, P_GPLL0_OUT_MAIN, 7, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(286666667, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(344000000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0), + F(430000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = { + .cmd_rcgr = 0x20c8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, + .freq_tbl = ftbl_disp_cc_mdss_mdp_clk_src, + .enable_safe_config = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_mdp_clk_src", + .parent_names = disp_cc_parent_names_3, + .num_parents = 5, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 200000000, + [VDD_LOW] = 300000000, + [VDD_LOW_L1] = 344000000, + [VDD_NOMINAL] = 430000000}, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .cmd_rcgr = 0x2098, + .mnd_width = 8, + .hid_width = 5, + .parent_map = disp_cc_parent_map_4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_names = disp_cc_parent_names_4, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_pixel_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 280000000, + [VDD_LOW] = 430000000, + [VDD_NOMINAL] = 570776256}, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .cmd_rcgr = 0x20b0, + .mnd_width = 8, + .hid_width = 5, + .parent_map = disp_cc_parent_map_4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_names = disp_cc_parent_names_4, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_pixel_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 280000000, + [VDD_LOW] = 430000000, + [VDD_NOMINAL] = 570776256}, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_rot_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(344000000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0), + F(430000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_rot_clk_src = { + .cmd_rcgr = 0x20e0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, + .freq_tbl = ftbl_disp_cc_mdss_rot_clk_src, + .enable_safe_config = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_rot_clk_src", + .parent_names = disp_cc_parent_names_3, + .num_parents = 5, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 200000000, + [VDD_LOW] = 300000000, + [VDD_LOW_L1] = 344000000, + [VDD_NOMINAL] = 430000000}, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = { + .cmd_rcgr = 0x20f8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_2, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_vsync_clk_src", + .parent_names = disp_cc_parent_names_2, + .num_parents = 2, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 19200000}, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_sleep_clk_src[] = { + F(32000, P_CHIP_SLEEP_CLK, 1, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_sleep_clk_src = { + .cmd_rcgr = 0x6060, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_6, + .freq_tbl = ftbl_disp_cc_sleep_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_sleep_clk_src", + .parent_names = disp_cc_parent_names_6, + .num_parents = 2, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 32000}, + }, +}; + +static struct clk_rcg2 disp_cc_xo_clk_src = { + .cmd_rcgr = 0x6044, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_2, + .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_xo_clk_src", + .parent_names = disp_cc_parent_names_2, + .num_parents = 2, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOWER] = 19200000}, + }, +}; + +static struct clk_branch disp_cc_mdss_ahb_clk = { + .halt_reg = 0x2080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_ahb_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_byte0_clk = { + .halt_reg = 0x2028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte0_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_byte0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = { + .reg = 0x2128, + .shift = 0, + .width = 2, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte0_div_clk_src", + .parent_names = (const char *[]){ + "disp_cc_mdss_byte0_clk_src", + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_byte0_intf_clk = { + .halt_reg = 0x202c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x202c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte0_intf_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_byte0_div_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_byte1_clk = { + .halt_reg = 0x2030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte1_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_byte1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap_div disp_cc_mdss_byte1_div_clk_src = { + .reg = 0x2144, + .shift = 0, + .width = 2, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte1_div_clk_src", + .parent_names = (const char *[]){ + "disp_cc_mdss_byte1_clk_src", + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_byte1_intf_clk = { + .halt_reg = 0x2034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte1_intf_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_byte1_div_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dp_aux_clk = { + .halt_reg = 0x2054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_aux_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_dp_aux_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dp_crypto_clk = { + .halt_reg = 0x2048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_crypto_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_dp_crypto_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dp_link_clk = { + .halt_reg = 0x2040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_link_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_dp_link_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dp_link_intf_clk = { + .halt_reg = 0x2044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_link_intf_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_dp_link_clk_src", + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dp_pixel1_clk = { + .halt_reg = 0x2050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_pixel1_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_dp_pixel1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dp_pixel_clk = { + .halt_reg = 0x204c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x204c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_pixel_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_dp_pixel_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_esc0_clk = { + .halt_reg = 0x2038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_esc0_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_esc0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_esc1_clk = { + .halt_reg = 0x203c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x203c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_esc1_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_esc1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_mdp_clk = { + .halt_reg = 0x200c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x200c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_mdp_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_mdp_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_mdp_lut_clk = { + .halt_reg = 0x201c, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x201c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_mdp_lut_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_mdp_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_non_gdsc_ahb_clk = { + .halt_reg = 0x4004, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x4004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_non_gdsc_ahb_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_pclk0_clk = { + .halt_reg = 0x2004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_pclk0_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_pclk0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_pclk1_clk = { + .halt_reg = 0x2008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_pclk1_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_pclk1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_rot_clk = { + .halt_reg = 0x2014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_rot_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_rot_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_rscc_ahb_clk = { + .halt_reg = 0x400c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x400c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_rscc_ahb_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_rscc_vsync_clk = { + .halt_reg = 0x4008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_rscc_vsync_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_vsync_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_vsync_clk = { + .halt_reg = 0x2024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_vsync_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_vsync_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_sleep_clk = { + .halt_reg = 0x6078, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6078, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_sleep_clk", + .parent_names = (const char *[]){ + "disp_cc_sleep_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_xo_clk = { + .halt_reg = 0x605c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x605c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_xo_clk", + .parent_names = (const char *[]){ + "disp_cc_xo_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *disp_cc_sdmmagpie_clocks[] = { + [DISP_CC_MDSS_AHB_CLK] = &disp_cc_mdss_ahb_clk.clkr, + [DISP_CC_MDSS_AHB_CLK_SRC] = &disp_cc_mdss_ahb_clk_src.clkr, + [DISP_CC_MDSS_BYTE0_CLK] = &disp_cc_mdss_byte0_clk.clkr, + [DISP_CC_MDSS_BYTE0_CLK_SRC] = &disp_cc_mdss_byte0_clk_src.clkr, + [DISP_CC_MDSS_BYTE0_DIV_CLK_SRC] = &disp_cc_mdss_byte0_div_clk_src.clkr, + [DISP_CC_MDSS_BYTE0_INTF_CLK] = &disp_cc_mdss_byte0_intf_clk.clkr, + [DISP_CC_MDSS_BYTE1_CLK] = &disp_cc_mdss_byte1_clk.clkr, + [DISP_CC_MDSS_BYTE1_CLK_SRC] = &disp_cc_mdss_byte1_clk_src.clkr, + [DISP_CC_MDSS_BYTE1_DIV_CLK_SRC] = &disp_cc_mdss_byte1_div_clk_src.clkr, + [DISP_CC_MDSS_BYTE1_INTF_CLK] = &disp_cc_mdss_byte1_intf_clk.clkr, + [DISP_CC_MDSS_DP_AUX_CLK] = &disp_cc_mdss_dp_aux_clk.clkr, + [DISP_CC_MDSS_DP_AUX_CLK_SRC] = &disp_cc_mdss_dp_aux_clk_src.clkr, + [DISP_CC_MDSS_DP_CRYPTO_CLK] = &disp_cc_mdss_dp_crypto_clk.clkr, + [DISP_CC_MDSS_DP_CRYPTO_CLK_SRC] = &disp_cc_mdss_dp_crypto_clk_src.clkr, + [DISP_CC_MDSS_DP_LINK_CLK] = &disp_cc_mdss_dp_link_clk.clkr, + [DISP_CC_MDSS_DP_LINK_CLK_SRC] = &disp_cc_mdss_dp_link_clk_src.clkr, + [DISP_CC_MDSS_DP_LINK_INTF_CLK] = &disp_cc_mdss_dp_link_intf_clk.clkr, + [DISP_CC_MDSS_DP_PIXEL1_CLK] = &disp_cc_mdss_dp_pixel1_clk.clkr, + [DISP_CC_MDSS_DP_PIXEL1_CLK_SRC] = &disp_cc_mdss_dp_pixel1_clk_src.clkr, + [DISP_CC_MDSS_DP_PIXEL_CLK] = &disp_cc_mdss_dp_pixel_clk.clkr, + [DISP_CC_MDSS_DP_PIXEL_CLK_SRC] = &disp_cc_mdss_dp_pixel_clk_src.clkr, + [DISP_CC_MDSS_ESC0_CLK] = &disp_cc_mdss_esc0_clk.clkr, + [DISP_CC_MDSS_ESC0_CLK_SRC] = &disp_cc_mdss_esc0_clk_src.clkr, + [DISP_CC_MDSS_ESC1_CLK] = &disp_cc_mdss_esc1_clk.clkr, + [DISP_CC_MDSS_ESC1_CLK_SRC] = &disp_cc_mdss_esc1_clk_src.clkr, + [DISP_CC_MDSS_MDP_CLK] = &disp_cc_mdss_mdp_clk.clkr, + [DISP_CC_MDSS_MDP_CLK_SRC] = &disp_cc_mdss_mdp_clk_src.clkr, + [DISP_CC_MDSS_MDP_LUT_CLK] = &disp_cc_mdss_mdp_lut_clk.clkr, + [DISP_CC_MDSS_NON_GDSC_AHB_CLK] = &disp_cc_mdss_non_gdsc_ahb_clk.clkr, + [DISP_CC_MDSS_PCLK0_CLK] = &disp_cc_mdss_pclk0_clk.clkr, + [DISP_CC_MDSS_PCLK0_CLK_SRC] = &disp_cc_mdss_pclk0_clk_src.clkr, + [DISP_CC_MDSS_PCLK1_CLK] = &disp_cc_mdss_pclk1_clk.clkr, + [DISP_CC_MDSS_PCLK1_CLK_SRC] = &disp_cc_mdss_pclk1_clk_src.clkr, + [DISP_CC_MDSS_ROT_CLK] = &disp_cc_mdss_rot_clk.clkr, + [DISP_CC_MDSS_ROT_CLK_SRC] = &disp_cc_mdss_rot_clk_src.clkr, + [DISP_CC_MDSS_RSCC_AHB_CLK] = &disp_cc_mdss_rscc_ahb_clk.clkr, + [DISP_CC_MDSS_RSCC_VSYNC_CLK] = &disp_cc_mdss_rscc_vsync_clk.clkr, + [DISP_CC_MDSS_VSYNC_CLK] = &disp_cc_mdss_vsync_clk.clkr, + [DISP_CC_MDSS_VSYNC_CLK_SRC] = &disp_cc_mdss_vsync_clk_src.clkr, + [DISP_CC_PLL0] = &disp_cc_pll0.clkr, + [DISP_CC_SLEEP_CLK] = &disp_cc_sleep_clk.clkr, + [DISP_CC_SLEEP_CLK_SRC] = &disp_cc_sleep_clk_src.clkr, + [DISP_CC_XO_CLK] = &disp_cc_xo_clk.clkr, + [DISP_CC_XO_CLK_SRC] = &disp_cc_xo_clk_src.clkr, +}; + +static const struct regmap_config disp_cc_sdmmagpie_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x10000, + .fast_io = true, +}; + +static const struct qcom_cc_desc disp_cc_sdmmagpie_desc = { + .config = &disp_cc_sdmmagpie_regmap_config, + .clks = disp_cc_sdmmagpie_clocks, + .num_clks = ARRAY_SIZE(disp_cc_sdmmagpie_clocks), +}; + +static const struct of_device_id disp_cc_sdmmagpie_match_table[] = { + { .compatible = "qcom,dispcc-sdmmagpie" }, + { } +}; +MODULE_DEVICE_TABLE(of, disp_cc_sdmmagpie_match_table); + +static int disp_cc_sdmmagpie_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx"); + if (IS_ERR(vdd_cx.regulator[0])) { + if (PTR_ERR(vdd_cx.regulator[0]) != -EPROBE_DEFER) + dev_err(&pdev->dev, + "Unable to get vdd_cx regulator\n"); + return PTR_ERR(vdd_cx.regulator[0]); + } + + regmap = qcom_cc_map(pdev, &disp_cc_sdmmagpie_desc); + if (IS_ERR(regmap)) { + pr_err("Failed to map the disp_cc registers\n"); + return PTR_ERR(regmap); + } + + clk_fabia_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); + + /* Enable clock gating for DSI and MDP clocks */ + regmap_update_bits(regmap, DISP_CC_MISC_CMD, 0x7f0, 0x7f0); + + ret = qcom_cc_really_probe(pdev, &disp_cc_sdmmagpie_desc, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to register Display CC clocks\n"); + return ret; + } + + dev_info(&pdev->dev, "Registered Display CC clocks\n"); + return ret; +} + +static struct platform_driver disp_cc_sdmmagpie_driver = { + .probe = disp_cc_sdmmagpie_probe, + .driver = { + .name = "disp_cc-sdmmagpie", + .of_match_table = disp_cc_sdmmagpie_match_table, + }, +}; + +static int __init disp_cc_sdmmagpie_init(void) +{ + return platform_driver_register(&disp_cc_sdmmagpie_driver); +} +subsys_initcall(disp_cc_sdmmagpie_init); + +static void __exit disp_cc_sdmmagpie_exit(void) +{ + platform_driver_unregister(&disp_cc_sdmmagpie_driver); +} +module_exit(disp_cc_sdmmagpie_exit); + +MODULE_DESCRIPTION("QTI DISP_CC sdmmagpie Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:disp_cc-sdmmagpie"); diff --git a/include/dt-bindings/clock/qcom,dispcc-sdmmagpie.h b/include/dt-bindings/clock/qcom,dispcc-sdmmagpie.h index 0a119e75cf85..70658ef0713e 100644 --- a/include/dt-bindings/clock/qcom,dispcc-sdmmagpie.h +++ b/include/dt-bindings/clock/qcom,dispcc-sdmmagpie.h @@ -14,49 +14,49 @@ #ifndef _DT_BINDINGS_CLK_QCOM_DISP_CC_SDMMAGPIE_H #define _DT_BINDINGS_CLK_QCOM_DISP_CC_SDMMAGPIE_H -#define DISP_CC_DEBUG_CLK 0 +#define DISP_CC_PLL0 0 #define DISP_CC_MDSS_AHB_CLK 1 #define DISP_CC_MDSS_AHB_CLK_SRC 2 #define DISP_CC_MDSS_BYTE0_CLK 3 #define DISP_CC_MDSS_BYTE0_CLK_SRC 4 -#define DISP_CC_MDSS_BYTE0_INTF_CLK 5 -#define DISP_CC_MDSS_BYTE1_CLK 6 -#define DISP_CC_MDSS_BYTE1_CLK_SRC 7 -#define DISP_CC_MDSS_BYTE1_INTF_CLK 8 -#define DISP_CC_MDSS_DP_AUX_CLK 9 -#define DISP_CC_MDSS_DP_AUX_CLK_SRC 10 -#define DISP_CC_MDSS_DP_CRYPTO_CLK 11 -#define DISP_CC_MDSS_DP_CRYPTO_CLK_SRC 12 -#define DISP_CC_MDSS_DP_LINK_CLK 13 -#define DISP_CC_MDSS_DP_LINK_CLK_SRC 14 -#define DISP_CC_MDSS_DP_LINK_INTF_CLK 15 -#define DISP_CC_MDSS_DP_PIXEL1_CLK 16 -#define DISP_CC_MDSS_DP_PIXEL1_CLK_SRC 17 -#define DISP_CC_MDSS_DP_PIXEL_CLK 18 -#define DISP_CC_MDSS_DP_PIXEL_CLK_SRC 19 -#define DISP_CC_MDSS_ESC0_CLK 20 -#define DISP_CC_MDSS_ESC0_CLK_SRC 21 -#define DISP_CC_MDSS_ESC1_CLK 22 -#define DISP_CC_MDSS_ESC1_CLK_SRC 23 -#define DISP_CC_MDSS_MDP_CLK 24 -#define DISP_CC_MDSS_MDP_CLK_SRC 25 -#define DISP_CC_MDSS_MDP_LUT_CLK 26 -#define DISP_CC_MDSS_NON_GDSC_AHB_CLK 27 -#define DISP_CC_MDSS_PCLK0_CLK 28 -#define DISP_CC_MDSS_PCLK0_CLK_SRC 29 -#define DISP_CC_MDSS_PCLK1_CLK 30 -#define DISP_CC_MDSS_PCLK1_CLK_SRC 31 -#define DISP_CC_MDSS_ROT_CLK 32 -#define DISP_CC_MDSS_ROT_CLK_SRC 33 -#define DISP_CC_MDSS_RSCC_AHB_CLK 34 -#define DISP_CC_MDSS_RSCC_VSYNC_CLK 35 -#define DISP_CC_MDSS_VSYNC_CLK 36 -#define DISP_CC_MDSS_VSYNC_CLK_SRC 37 -#define DISP_CC_PLL0 38 -#define DISP_CC_PLL_TEST_CLK 39 +#define DISP_CC_MDSS_BYTE0_DIV_CLK_SRC 5 +#define DISP_CC_MDSS_BYTE0_INTF_CLK 6 +#define DISP_CC_MDSS_BYTE1_CLK 7 +#define DISP_CC_MDSS_BYTE1_CLK_SRC 8 +#define DISP_CC_MDSS_BYTE1_DIV_CLK_SRC 9 +#define DISP_CC_MDSS_BYTE1_INTF_CLK 10 +#define DISP_CC_MDSS_DP_AUX_CLK 11 +#define DISP_CC_MDSS_DP_AUX_CLK_SRC 12 +#define DISP_CC_MDSS_DP_CRYPTO_CLK 13 +#define DISP_CC_MDSS_DP_CRYPTO_CLK_SRC 14 +#define DISP_CC_MDSS_DP_LINK_CLK 15 +#define DISP_CC_MDSS_DP_LINK_CLK_SRC 16 +#define DISP_CC_MDSS_DP_LINK_INTF_CLK 17 +#define DISP_CC_MDSS_DP_PIXEL1_CLK 18 +#define DISP_CC_MDSS_DP_PIXEL1_CLK_SRC 19 +#define DISP_CC_MDSS_DP_PIXEL_CLK 20 +#define DISP_CC_MDSS_DP_PIXEL_CLK_SRC 21 +#define DISP_CC_MDSS_ESC0_CLK 22 +#define DISP_CC_MDSS_ESC0_CLK_SRC 23 +#define DISP_CC_MDSS_ESC1_CLK 24 +#define DISP_CC_MDSS_ESC1_CLK_SRC 25 +#define DISP_CC_MDSS_MDP_CLK 26 +#define DISP_CC_MDSS_MDP_CLK_SRC 27 +#define DISP_CC_MDSS_MDP_LUT_CLK 28 +#define DISP_CC_MDSS_NON_GDSC_AHB_CLK 29 +#define DISP_CC_MDSS_PCLK0_CLK 30 +#define DISP_CC_MDSS_PCLK0_CLK_SRC 31 +#define DISP_CC_MDSS_PCLK1_CLK 32 +#define DISP_CC_MDSS_PCLK1_CLK_SRC 33 +#define DISP_CC_MDSS_ROT_CLK 34 +#define DISP_CC_MDSS_ROT_CLK_SRC 35 +#define DISP_CC_MDSS_RSCC_AHB_CLK 36 +#define DISP_CC_MDSS_RSCC_VSYNC_CLK 37 +#define DISP_CC_MDSS_VSYNC_CLK 38 +#define DISP_CC_MDSS_VSYNC_CLK_SRC 39 #define DISP_CC_XO_CLK 40 #define DISP_CC_XO_CLK_SRC 41 - -#define MDSS_CORE_GDSC 0 +#define DISP_CC_SLEEP_CLK 42 +#define DISP_CC_SLEEP_CLK_SRC 43 #endif -- GitLab From 0dea55f0614a54e23113b1bdc233f521b9d6744b Mon Sep 17 00:00:00 2001 From: Xiaojun Sang Date: Thu, 9 Aug 2018 12:23:38 +0800 Subject: [PATCH 0857/1001] ARM: dts: msm:Add sound node entry to support sm6150 QRD Add sm6150-QRD-specific hardware info such as sound card name, analog mic routing and WSA number. Change-Id: I55fe6387b5317b4d15b417ffe266c44ae662677f Signed-off-by: Xiaojun Sang --- .../boot/dts/qcom/sm6150-qrd-overlay.dts | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts index 5a1ded43ba61..05e667d052e6 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts @@ -15,6 +15,7 @@ #include +#include "sm6150-audio-overlay.dtsi" #include "sm6150-qrd.dtsi" / { @@ -26,3 +27,34 @@ &dsi_hx83112a_truly_vid_display { qcom,dsi-display-active; }; + +&sm6150_snd { + qcom,model = "sm6150-qrd-snd-card"; + qcom,audio-routing = + "AMIC1", "MIC BIAS1", + "MIC BIAS1", "Analog Mic1", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "Analog Mic3", + "TX_AIF1 CAP", "VA_MCLK", + "TX_AIF2 CAP", "VA_MCLK", + "RX AIF1 PB", "VA_MCLK", + "RX AIF2 PB", "VA_MCLK", + "RX AIF3 PB", "VA_MCLK", + "RX AIF4 PB", "VA_MCLK", + "HPHL_OUT", "VA_MCLK", + "HPHR_OUT", "VA_MCLK", + "AUX_OUT", "VA_MCLK", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "TX SWR_ADC0", "ADC1_OUTPUT", + "TX SWR_ADC2", "ADC2_OUTPUT", + "TX SWR_ADC3", "ADC3_OUTPUT", + "SpkrLeft IN", "WSA_SPK1 OUT", + "WSA_SPK1 OUT", "VA_MCLK"; + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft"; +}; -- GitLab From 7811322d6da1f783341a12458687e4a4ce426c16 Mon Sep 17 00:00:00 2001 From: Umang Agrawal Date: Tue, 14 Aug 2018 17:58:18 +0530 Subject: [PATCH 0858/1001] power: smb5-lib: Set parallel charger configuration is uUSB removal path Currently parallel charger configuration is re-validated and set in the TypeC removal path only. But, in case of uUSB devices, if QC 2.0 is plugged in after QC 3.0 insertion/removal cycle, parallel charger configuration is not reset to enable SMB1355 and henceforth, parallel charging remains disabled. Add check to validate and set parallel charger configuration in uUSB removal path. Change-Id: I9f5ba90f50a654bfe4db9f065a4f6c854af93038 Signed-off-by: Umang Agrawal --- drivers/power/supply/qcom/smb5-lib.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 9c260fd9b4b1..a7e38ad36b78 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -816,6 +816,14 @@ static void smblib_uusb_removal(struct smb_charger *chg) struct smb_irq_data *data; struct storm_watch *wdata; + chg->cp_reason = POWER_SUPPLY_CP_NONE; + rc = smblib_select_sec_charger(chg, + chg->sec_pl_present ? POWER_SUPPLY_CHARGER_SEC_PL : + POWER_SUPPLY_CHARGER_SEC_NONE); + if (rc < 0) + dev_err(chg->dev, "Couldn't disable secondary charger rc=%d\n", + rc); + cancel_delayed_work_sync(&chg->pl_enable_work); if (chg->wa_flags & BOOST_BACK_WA) { -- GitLab From 8e9d7486861c3f4bd06ff76f8e4a77fce979b9bc Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Mon, 2 Jul 2018 11:07:16 +0530 Subject: [PATCH 0859/1001] msm: ipa3: Driver changes to support ADPL over ODL functionality Added IPA driver change to support the acceleration data protocol logging(ADPL) over on device logging(ODL). Change-Id: I332db63ae5f40a13b9277bed9d5be907f1d65e30 Acked-by: Ashok Vuyyuru Signed-off-by: Mohammed Javid --- drivers/platform/msm/ipa/ipa_api.c | 2 + drivers/platform/msm/ipa/ipa_v3/Makefile | 2 +- drivers/platform/msm/ipa/ipa_v3/ipa.c | 12 +- drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c | 26 + drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 35 + drivers/platform/msm/ipa/ipa_v3/ipa_odl.c | 681 ++++++++++++++++++ drivers/platform/msm/ipa/ipa_v3/ipa_odl.h | 80 ++ drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 6 + drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c | 4 +- include/uapi/linux/msm_ipa.h | 38 +- 10 files changed, 882 insertions(+), 4 deletions(-) create mode 100644 drivers/platform/msm/ipa/ipa_v3/ipa_odl.c create mode 100644 drivers/platform/msm/ipa/ipa_v3/ipa_odl.h diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c index 5379ef9d2cc6..221f06832a37 100644 --- a/drivers/platform/msm/ipa/ipa_api.c +++ b/drivers/platform/msm/ipa/ipa_api.c @@ -194,6 +194,8 @@ const char *ipa_clients_strings[IPA_CLIENT_MAX] = { __stringify(IPA_CLIENT_Q6_QBAP_STATUS_CONS), __stringify(RESERVERD_PROD_80), __stringify(IPA_CLIENT_MHI_DPL_CONS), + __stringify(RESERVERD_PROD_82), + __stringify(IPA_CLIENT_ODL_DPL_CONS), }; /** diff --git a/drivers/platform/msm/ipa/ipa_v3/Makefile b/drivers/platform/msm/ipa/ipa_v3/Makefile index f6f08b152393..275b33f8dabb 100644 --- a/drivers/platform/msm/ipa/ipa_v3/Makefile +++ b/drivers/platform/msm/ipa/ipa_v3/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_IPA3) += ipat.o ipat-y := ipa.o ipa_debugfs.o ipa_hdr.o ipa_flt.o ipa_rt.o ipa_dp.o ipa_client.o \ ipa_utils.o ipa_nat.o ipa_intf.o teth_bridge.o ipa_interrupts.o \ ipa_uc.o ipa_uc_wdi.o ipa_dma.o ipa_uc_mhi.o ipa_mhi.o ipa_uc_ntn.o \ - ipa_hw_stats.o ipa_pm.o ipa_wdi3_i.o + ipa_hw_stats.o ipa_pm.o ipa_wdi3_i.o ipa_odl.o ipat-$(CONFIG_IPA_EMULATION) += ipa_dt_replacement.o diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index a1f4b19fcc1c..9b98ad30f5ea 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -59,6 +59,7 @@ #define CREATE_TRACE_POINTS #include "ipa_trace.h" +#include "ipa_odl.h" /* * The following for adding code (ie. for EMULATION) not found on x86. @@ -5487,6 +5488,16 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, IPADBG("ipa cdev added successful. major:%d minor:%d\n", MAJOR(ipa3_ctx->cdev.dev_num), MINOR(ipa3_ctx->cdev.dev_num)); + + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_1) { + result = ipa_odl_init(); + if (result) { + IPADBG("Error: ODL init fialed\n"); + result = -ENODEV; + goto fail_cdev_add; + } + } + /* * for IPA 4.0 offline charge is not needed and we need to prevent * power collapse until IPA uC is loaded. @@ -5496,7 +5507,6 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, if (ipa3_ctx->ipa_hw_type != IPA_HW_v4_0) ipa3_proxy_clk_unvote(); return 0; - fail_cdev_add: fail_gsi_pre_fw_load_init: ipa3_dma_shutdown(); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index 7efb19c759d8..7256997c1ac7 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -18,6 +18,7 @@ #include "ipa_i.h" #include "../ipa_rm_i.h" #include "ipahal/ipahal_nat.h" +#include "ipa_odl.h" #define IPA_MAX_ENTRY_STRING_LEN 500 #define IPA_MAX_MSG_LEN 4096 @@ -1130,6 +1131,27 @@ static ssize_t ipa3_read_stats(struct file *file, char __user *ubuf, return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt); } +static ssize_t ipa3_read_odlstats(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + int nbytes; + int cnt = 0; + + nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, + "ODL received pkt =%u\n" + "ODL processed pkt to DIAG=%u\n" + "ODL dropped pkt =%u\n" + "ODL packet in queue =%u\n", + ipa3_odl_ctx->stats.odl_rx_pkt, + ipa3_odl_ctx->stats.odl_tx_diag_pkt, + ipa3_odl_ctx->stats.odl_drop_pkt, + ipa3_odl_ctx->stats.numer_in_queue); + + cnt += nbytes; + + return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt); +} + static ssize_t ipa3_read_wstats(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { @@ -2174,6 +2196,10 @@ static const struct ipa3_debugfs_file debugfs_files[] = { "wstats", IPA_READ_ONLY_MODE, NULL, { .read = ipa3_read_wstats, } + }, { + "odlstats", IPA_READ_ONLY_MODE, NULL, { + .read = ipa3_read_odlstats, + } }, { "wdi", IPA_READ_ONLY_MODE, NULL, { .read = ipa3_read_wdi, diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 58dd24ca2d7f..d1d268c6aeab 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -62,6 +62,8 @@ #define IPA_ODU_RX_POOL_SZ 64 #define IPA_SIZE_DL_CSUM_META_TRAILER 8 +#define IPA_ODL_RX_BUFF_SZ (16 * 1024) + #define IPA_GSI_MAX_CH_LOW_WEIGHT 15 #define IPA_GSI_EVT_RING_INT_MODT (16) /* 0.5ms under 32KHz clock */ #define IPA_GSI_EVT_RING_INT_MODC (20) @@ -2864,6 +2866,17 @@ static int ipa3_odu_rx_pyld_hdlr(struct sk_buff *rx_skb, return 0; } +static int ipa3_odl_dpl_rx_pyld_hdlr(struct sk_buff *rx_skb, + struct ipa3_sys_context *sys) +{ + if (WARN(!sys->ep->client_notify, "sys->ep->client_notify is NULL\n")) + dev_kfree_skb_any(rx_skb); + else + sys->ep->client_notify(sys->ep->priv, IPA_RECEIVE, + (unsigned long)(rx_skb)); + + return 0; +} static void ipa3_free_rx_wrapper(struct ipa3_rx_pkt_wrapper *rk_pkt) { kmem_cache_free(ipa3_ctx->rx_pkt_wrapper_cache, rk_pkt); @@ -3054,6 +3067,26 @@ static int ipa3_assign_policy(struct ipa_sys_connect_params *in, in->client); sys->policy = IPA_POLICY_NOINTR_MODE; + } else if (in->client == IPA_CLIENT_ODL_DPL_CONS) { + IPADBG("assigning policy to ODL client:%d\n", + in->client); + sys->ep->status.status_en = true; + sys->policy = IPA_POLICY_INTR_POLL_MODE; + INIT_WORK(&sys->work, ipa3_wq_handle_rx); + INIT_DELAYED_WORK(&sys->switch_to_intr_work, + ipa3_switch_to_intr_rx_work_func); + INIT_DELAYED_WORK(&sys->replenish_rx_work, + ipa3_replenish_rx_work_func); + atomic_set(&sys->curr_polling_state, 0); + sys->rx_buff_sz = + IPA_GENERIC_RX_BUFF_SZ(IPA_ODL_RX_BUFF_SZ); + sys->pyld_hdlr = ipa3_odl_dpl_rx_pyld_hdlr; + sys->get_skb = ipa3_get_skb_ipa_rx; + sys->free_skb = ipa3_free_skb_rx; + sys->free_rx_wrapper = ipa3_recycle_rx_wrapper; + sys->repl_hdlr = ipa3_replenish_rx_cache_recycle; + sys->rx_pool_sz = in->desc_fifo_sz / + IPA_FIFO_ELEMENT_SIZE - 1; } else { WARN(1, "Need to install a RX pipe hdlr\n"); return -EINVAL; @@ -3523,8 +3556,10 @@ static void ipa_gsi_irq_rx_notify_cb(struct gsi_chan_xfer_notify *notify) IPADBG_LOW("event %d notified\n", notify->evt_id); sys = (struct ipa3_sys_context *)notify->chan_user_data; + spin_lock_bh(&sys->spinlock); rx_pkt_expected = list_first_entry(&sys->head_desc_list, struct ipa3_rx_pkt_wrapper, link); + spin_unlock_bh(&sys->spinlock); rx_pkt_rcvd = (struct ipa3_rx_pkt_wrapper *)notify->xfer_user_data; if (rx_pkt_expected != rx_pkt_rcvd) { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c new file mode 100644 index 000000000000..87920f2818c5 --- /dev/null +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c @@ -0,0 +1,681 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "ipa_i.h" +#include "ipa_odl.h" +#include +#include + +struct ipa_odl_context *ipa3_odl_ctx; + +static DECLARE_WAIT_QUEUE_HEAD(odl_ctl_msg_wq); + +static void print_ipa_odl_state_bit_mask(void) +{ + IPADBG("ipa3_odl_ctx->odl_state.odl_init --> %d\n", + ipa3_odl_ctx->odl_state.odl_init); + IPADBG("ipa3_odl_ctx->odl_state.odl_open --> %d\n", + ipa3_odl_ctx->odl_state.odl_open); + IPADBG("ipa3_odl_ctx->odl_state.adpl_open --> %d\n", + ipa3_odl_ctx->odl_state.adpl_open); + IPADBG("ipa3_odl_ctx->odl_state.aggr_byte_limit_sent --> %d\n", + ipa3_odl_ctx->odl_state.aggr_byte_limit_sent); + IPADBG("ipa3_odl_ctx->odl_state.odl_ep_setup --> %d\n", + ipa3_odl_ctx->odl_state.odl_ep_setup); + IPADBG("ipa3_odl_ctx->odl_state.odl_setup_done_sent --> %d\n", + ipa3_odl_ctx->odl_state.odl_setup_done_sent); + IPADBG("ipa3_odl_ctx->odl_state.odl_ep_info_sent --> %d\n", + ipa3_odl_ctx->odl_state.odl_ep_info_sent); + IPADBG("ipa3_odl_ctx->odl_state.odl_connected --> %d\n", + ipa3_odl_ctx->odl_state.odl_connected); + IPADBG("ipa3_odl_ctx->odl_state.odl_disconnected --> %d\n\n", + ipa3_odl_ctx->odl_state.odl_disconnected); +} + +static int ipa_odl_ctl_fops_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + + if (ipa3_odl_ctx->odl_state.odl_init) { + ipa3_odl_ctx->odl_state.odl_open = true; + } else { + IPAERR("Before odl init trying to open odl ctl pipe\n"); + print_ipa_odl_state_bit_mask(); + ret = -ENODEV; + } + + return ret; +} + +static int ipa_odl_ctl_fops_release(struct inode *inode, struct file *filp) +{ + IPADBG("QTI closed ipa_odl_ctl node\n"); + ipa3_odl_ctx->odl_state.odl_open = false; + return 0; +} + +/** + * ipa_odl_ctl_fops_read() - read message from IPA ODL device + * @filp: [in] file pointer + * @buf: [out] buffer to read into + * @count: [in] size of above buffer + * @f_pos: [inout] file position + * + * Uer-space should continuously read from /dev/ipa_odl_ctl, + * read will block when there are no messages to read. + * Upon return, user-space should read the u32 data from the + * start of the buffer. + * + * 0 --> ODL disconnected. + * 1 --> ODL connected. + * + * Buffer supplied must be big enough to + * hold the message of size u32. + * + * Returns: how many bytes copied to buffer + * + * Note: Should not be called from atomic context + */ + +static ssize_t ipa_odl_ctl_fops_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + char __user *start; + u8 data; + int ret = 0; + static bool old_state; + bool new_state = false; + + start = buf; + while (1) { + wait_event_interruptible(odl_ctl_msg_wq, + ipa3_odl_ctx->odl_ctl_msg_wq_flag == true); + ipa3_odl_ctx->odl_ctl_msg_wq_flag = false; + if (!ipa3_odl_ctx->odl_state.adpl_open && + !ipa3_odl_ctx->odl_state.odl_disconnected) + break; + + if (ipa3_odl_ctx->odl_state.odl_ep_setup) + new_state = true; + else if (ipa3_odl_ctx->odl_state.odl_disconnected) + new_state = false; + else { + ret = -EAGAIN; + break; + } + + if (old_state != new_state) { + old_state = new_state; + + if (new_state == true) + data = 1; + else if (new_state == false) + data = 0; + + if (copy_to_user(buf, &data, + sizeof(data))) { + ret = -EFAULT; + break; + } + + buf += sizeof(data); + + if (data == 1) + ipa3_odl_ctx->odl_state.odl_setup_done_sent = + true; + } + + ret = -EAGAIN; + if (filp->f_flags & O_NONBLOCK) + break; + + ret = -EINTR; + if (signal_pending(current)) + break; + + if (start != buf) + break; + } + + if (start != buf && ret != -EFAULT) + ret = buf - start; + + return ret; +} + +static long ipa_odl_ctl_fops_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct ipa_odl_ep_info ep_info = {0}; + struct ipa_odl_modem_config status; + int retval = 0; + + IPADBG("Calling odl ioctl cmd = %d\n", cmd); + if (!ipa3_odl_ctx->odl_state.odl_setup_done_sent) { + IPAERR("Before complete the odl setup trying calling ioctl\n"); + print_ipa_odl_state_bit_mask(); + retval = -ENODEV; + goto fail; + } + + switch (cmd) { + case IPA_IOC_ODL_QUERY_ADAPL_EP_INFO: + /* Send ep_info to user APP */ + ep_info.ep_type = ODL_EP_TYPE_HSUSB; + ep_info.peripheral_iface_id = ODL_EP_PERIPHERAL_IFACE_ID; + ep_info.cons_pipe_num = -1; + ep_info.prod_pipe_num = + ipa3_odl_ctx->odl_client_hdl; + if (copy_to_user((void __user *)arg, &ep_info, + sizeof(ep_info))) { + retval = -EFAULT; + goto fail; + } + ipa3_odl_ctx->odl_state.odl_ep_info_sent = true; + break; + case IPA_IOC_ODL_QUERY_MODEM_CONFIG: + IPADBG("Received the IPA_IOC_ODL_QUERY_MODEM_CONFIG :\n"); + if (copy_from_user(&status, (const void __user *)arg, + sizeof(status))) { + retval = -EFAULT; + break; + } + if (status.config_status == CONFIG_SUCCESS) + ipa3_odl_ctx->odl_state.odl_connected = true; + IPADBG("status.config_status = %d odl_connected = %d\n", + status.config_status, ipa3_odl_ctx->odl_state.odl_connected); + break; + default: + retval = -ENOIOCTLCMD; + break; + } + +fail: + return retval; +} + +static void delete_first_node(void) +{ + struct ipa3_push_msg_odl *msg; + + if (!list_empty(&ipa3_odl_ctx->adpl_msg_list)) { + msg = list_first_entry(&ipa3_odl_ctx->adpl_msg_list, + struct ipa3_push_msg_odl, link); + if (msg) { + list_del(&msg->link); + kfree(msg->buff); + kfree(msg); + ipa3_odl_ctx->stats.odl_drop_pkt++; + IPA_STATS_DEC_CNT(ipa3_odl_ctx->stats.numer_in_queue); + } + } else { + IPADBG("List Empty\n"); + } +} + +int ipa3_send_adpl_msg(unsigned long skb_data) +{ + struct ipa3_push_msg_odl *msg; + struct sk_buff *skb = (struct sk_buff *)skb_data; + void *data; + + IPADBG_LOW("Processing DPL data\n"); + msg = kzalloc(sizeof(struct ipa3_push_msg_odl), GFP_KERNEL); + if (msg == NULL) { + IPADBG("Memory allocation failed\n"); + return -ENOMEM; + } + + data = kmalloc(skb->len, GFP_KERNEL); + if (data == NULL) { + kfree(msg); + return -ENOMEM; + } + memcpy(data, skb->data, skb->len); + msg->buff = data; + msg->len = skb->len; + mutex_lock(&ipa3_odl_ctx->adpl_msg_lock); + if (ipa3_odl_ctx->stats.numer_in_queue >= MAX_QUEUE_TO_ODL) + delete_first_node(); + list_add_tail(&msg->link, &ipa3_odl_ctx->adpl_msg_list); + IPA_STATS_INC_CNT(ipa3_odl_ctx->stats.numer_in_queue); + mutex_unlock(&ipa3_odl_ctx->adpl_msg_lock); + IPA_STATS_INC_CNT(ipa3_odl_ctx->stats.odl_rx_pkt); + + return 0; +} + +/** + * odl_ipa_packet_receive_notify() - Rx notify + * + * @priv: driver context + * @evt: event type + * @data: data provided with event + * + * IPA will pass a packet to the Linux network stack with skb->data + */ +static void odl_ipa_packet_receive_notify(void *priv, + enum ipa_dp_evt_type evt, + unsigned long data) +{ + IPADBG_LOW("Rx packet was received\n"); + if (evt == IPA_RECEIVE) + ipa3_send_adpl_msg(data); + else + IPAERR("Invalid evt %d received in wan_ipa_receive\n", evt); +} + +int ipa_setup_odl_pipe(void) +{ + struct ipa_sys_connect_params *ipa_odl_ep_cfg; + int ret; + + ipa_odl_ep_cfg = &ipa3_odl_ctx->odl_sys_param; + + IPADBG("Setting up the odl endpoint\n"); + ipa_odl_ep_cfg->ipa_ep_cfg.cfg.cs_offload_en = IPA_ENABLE_CS_OFFLOAD_DL; + + ipa_odl_ep_cfg->ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR; + ipa_odl_ep_cfg->ipa_ep_cfg.aggr.aggr_hard_byte_limit_en = 1; + ipa_odl_ep_cfg->ipa_ep_cfg.aggr.aggr = IPA_GENERIC; + ipa_odl_ep_cfg->ipa_ep_cfg.aggr.aggr_byte_limit = + IPA_ODL_AGGR_BYTE_LIMIT; + ipa_odl_ep_cfg->ipa_ep_cfg.aggr.aggr_pkt_limit = 0; + + ipa_odl_ep_cfg->ipa_ep_cfg.hdr.hdr_len = 4; + ipa_odl_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1; + ipa_odl_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_metadata = 1; + ipa_odl_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1; + ipa_odl_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 2; + + ipa_odl_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_valid = true; + ipa_odl_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad = 0; + ipa_odl_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_payload_len_inc_padding = true; + ipa_odl_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_offset = 0; + ipa_odl_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_little_endian = 0; + ipa_odl_ep_cfg->ipa_ep_cfg.metadata_mask.metadata_mask = 0xFF000000; + + ipa_odl_ep_cfg->client = IPA_CLIENT_ODL_DPL_CONS; + ipa_odl_ep_cfg->notify = odl_ipa_packet_receive_notify; + + ipa_odl_ep_cfg->napi_enabled = false; + ipa_odl_ep_cfg->desc_fifo_sz = IPA_ODL_RX_RING_SIZE * + IPA_FIFO_ELEMENT_SIZE; + + ret = ipa3_setup_sys_pipe(ipa_odl_ep_cfg, + &ipa3_odl_ctx->odl_client_hdl); + return ret; + +} + +int ipa3_odl_pipe_open(void) +{ + int ret = 0; + struct ipa_ep_cfg_holb holb_cfg; + + if (!ipa3_odl_ctx->odl_state.adpl_open) { + IPAERR("adpl pipe not configured\n"); + return 0; + } + + memset(&holb_cfg, 0, sizeof(holb_cfg)); + holb_cfg.tmr_val = 0; + holb_cfg.en = 1; + + ipa3_cfg_ep_holb_by_client(IPA_CLIENT_USB_DPL_CONS, &holb_cfg); + ret = ipa_setup_odl_pipe(); + if (ret) { + IPAERR(" Setup endpoint config failed\n"); + goto fail; + } + ipa3_cfg_ep_holb_by_client(IPA_CLIENT_ODL_DPL_CONS, &holb_cfg); + ipa3_odl_ctx->odl_state.odl_ep_setup = true; + IPADBG("Setup endpoint config success\n"); + + ipa3_odl_ctx->stats.odl_drop_pkt = 0; + ipa3_odl_ctx->stats.numer_in_queue = 0; + ipa3_odl_ctx->stats.odl_rx_pkt = 0; + ipa3_odl_ctx->stats.odl_tx_diag_pkt = 0; + /* + * Send signal to ipa_odl_ctl_fops_read, + * to send ODL ep open notification + */ + ipa3_odl_ctx->odl_ctl_msg_wq_flag = true; + IPADBG("Wake up odl ctl\n"); + wake_up_interruptible(&odl_ctl_msg_wq); + if (ipa3_odl_ctx->odl_state.odl_disconnected) + ipa3_odl_ctx->odl_state.odl_disconnected = false; +fail: + return ret; + +} +static int ipa_adpl_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + + IPADBG("Called the function :\n"); + if (ipa3_odl_ctx->odl_state.odl_init) { + ipa3_odl_ctx->odl_state.adpl_open = true; + ret = ipa3_odl_pipe_open(); + } else { + IPAERR("Before odl init trying to open adpl pipe\n"); + print_ipa_odl_state_bit_mask(); + ret = -ENODEV; + } + + return ret; +} + +static int ipa_adpl_release(struct inode *inode, struct file *filp) +{ + ipa3_odl_pipe_cleanup(false); + return 0; +} + +void ipa3_odl_pipe_cleanup(bool is_ssr) +{ + bool ipa_odl_opened = false; + struct ipa_ep_cfg_holb holb_cfg; + + if (!ipa3_odl_ctx->odl_state.adpl_open) { + IPAERR("adpl pipe not configured\n"); + return; + } + if (ipa3_odl_ctx->odl_state.odl_open) + ipa_odl_opened = true; + + memset(&ipa3_odl_ctx->odl_state, 0, sizeof(ipa3_odl_ctx->odl_state)); + + /*Since init will not be done again*/ + ipa3_odl_ctx->odl_state.odl_init = true; + memset(&holb_cfg, 0, sizeof(holb_cfg)); + holb_cfg.tmr_val = 0; + holb_cfg.en = 0; + + ipa3_cfg_ep_holb_by_client(IPA_CLIENT_USB_DPL_CONS, &holb_cfg); + + ipa3_teardown_sys_pipe(ipa3_odl_ctx->odl_client_hdl); + /*Assume QTI will never close this node once opened*/ + if (ipa_odl_opened) + ipa3_odl_ctx->odl_state.odl_open = true; + + /*Assume DIAG will not close this node in SSR case*/ + if (is_ssr) + ipa3_odl_ctx->odl_state.adpl_open = true; + + ipa3_odl_ctx->odl_state.odl_disconnected = true; + ipa3_odl_ctx->odl_state.odl_ep_setup = false; + ipa3_odl_ctx->odl_state.aggr_byte_limit_sent = false; + ipa3_odl_ctx->odl_state.odl_connected = false; + /* + * Send signal to ipa_odl_ctl_fops_read, + * to send ODL ep close notification + */ + ipa3_odl_ctx->odl_ctl_msg_wq_flag = true; + ipa3_odl_ctx->stats.odl_drop_pkt = 0; + ipa3_odl_ctx->stats.numer_in_queue = 0; + ipa3_odl_ctx->stats.odl_rx_pkt = 0; + ipa3_odl_ctx->stats.odl_tx_diag_pkt = 0; + IPADBG("Wake up odl ctl\n"); + wake_up_interruptible(&odl_ctl_msg_wq); + +} + +/** + * ipa_adpl_read() - read message from IPA device + * @filp: [in] file pointer + * @buf: [out] buffer to read into + * @count: [in] size of above buffer + * @f_pos: [inout] file position + * + * User-space should continually read from /dev/ipa_adpl, + * read will block when there are no messages to read. + * Upon return, user-space should read + * Buffer supplied must be big enough to + * hold the data. + * + * Returns: how many bytes copied to buffer + * + * Note: Should not be called from atomic context + */ +static ssize_t ipa_adpl_read(struct file *filp, char __user *buf, size_t count, + loff_t *f_pos) +{ + int ret = 0; + char __user *start = buf; + struct ipa3_push_msg_odl *msg; + + while (1) { + IPADBG_LOW("Writing message to adpl pipe\n"); + if (!ipa3_odl_ctx->odl_state.odl_open) + break; + + mutex_lock(&ipa3_odl_ctx->adpl_msg_lock); + msg = NULL; + if (!list_empty(&ipa3_odl_ctx->adpl_msg_list)) { + msg = list_first_entry(&ipa3_odl_ctx->adpl_msg_list, + struct ipa3_push_msg_odl, link); + list_del(&msg->link); + IPA_STATS_DEC_CNT(ipa3_odl_ctx->stats.numer_in_queue); + } + + mutex_unlock(&ipa3_odl_ctx->adpl_msg_lock); + + if (msg != NULL) { + if (msg->len > count) { + IPAERR("Message length greater than count\n"); + kfree(msg->buff); + kfree(msg); + msg = NULL; + ret = -EAGAIN; + break; + } + + if (msg->buff) { + if (copy_to_user(buf, msg->buff, + msg->len)) { + ret = -EFAULT; + kfree(msg->buff); + kfree(msg); + msg = NULL; + ret = -EAGAIN; + break; + } + buf += msg->len; + count -= msg->len; + kfree(msg->buff); + } + IPA_STATS_INC_CNT(ipa3_odl_ctx->stats.odl_tx_diag_pkt); + kfree(msg); + msg = NULL; + } else { + ret = -EAGAIN; + break; + } + + ret = -EAGAIN; + if (filp->f_flags & O_NONBLOCK) + break; + + ret = -EINTR; + if (signal_pending(current)) + break; + + if (start != buf) + break; + + } + + if (start != buf && ret != -EFAULT) + ret = buf - start; + + return ret; +} + +static long ipa_adpl_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct odl_agg_pipe_info odl_pipe_info; + int retval = 0; + + if (!ipa3_odl_ctx->odl_state.odl_connected) { + IPAERR("ODL config in progress not allowed ioctl\n"); + print_ipa_odl_state_bit_mask(); + retval = -ENODEV; + goto fail; + } + IPADBG("Calling adpl ioctl\n"); + + switch (cmd) { + case IPA_IOC_ODL_GET_AGG_BYTE_LIMIT: + odl_pipe_info.agg_byte_limit = + ipa3_odl_ctx->odl_sys_param.ipa_ep_cfg.aggr.aggr_byte_limit; + if (copy_to_user((void __user *)arg, &odl_pipe_info, + sizeof(odl_pipe_info))) { + retval = -EFAULT; + goto fail; + } + ipa3_odl_ctx->odl_state.aggr_byte_limit_sent = true; + break; + default: + retval = -ENOIOCTLCMD; + print_ipa_odl_state_bit_mask(); + break; + } + +fail: + return retval; +} + +static const struct file_operations ipa_odl_ctl_fops = { + .owner = THIS_MODULE, + .open = ipa_odl_ctl_fops_open, + .release = ipa_odl_ctl_fops_release, + .read = ipa_odl_ctl_fops_read, + .unlocked_ioctl = ipa_odl_ctl_fops_ioctl, +}; + +static const struct file_operations ipa_adpl_fops = { + .owner = THIS_MODULE, + .open = ipa_adpl_open, + .release = ipa_adpl_release, + .read = ipa_adpl_read, + .unlocked_ioctl = ipa_adpl_ioctl, +}; + +int ipa_odl_init(void) +{ + int result = 0; + struct cdev *cdev; + int loop = 0; + struct ipa3_odl_char_device_context *odl_cdev; + + ipa3_odl_ctx = kzalloc(sizeof(*ipa3_odl_ctx), GFP_KERNEL); + if (!ipa3_odl_ctx) { + result = -ENOMEM; + goto fail_mem_ctx; + } + + odl_cdev = ipa3_odl_ctx->odl_cdev; + INIT_LIST_HEAD(&ipa3_odl_ctx->adpl_msg_list); + mutex_init(&ipa3_odl_ctx->adpl_msg_lock); + + odl_cdev[loop].class = class_create(THIS_MODULE, "ipa_adpl"); + + if (IS_ERR(odl_cdev[loop].class)) { + IPAERR("Error: odl_cdev->class NULL\n"); + result = -ENODEV; + goto create_char_dev0_fail; + } + + result = alloc_chrdev_region(&odl_cdev[loop].dev_num, 0, 1, "ipa_adpl"); + if (result) { + IPAERR("alloc_chrdev_region error for ipa adpl pipe\n"); + result = -ENODEV; + goto alloc_chrdev0_region_fail; + } + + odl_cdev[loop].dev = device_create(odl_cdev[loop].class, NULL, + odl_cdev[loop].dev_num, ipa3_ctx, "ipa_adpl"); + if (IS_ERR(odl_cdev[loop].dev)) { + IPAERR("device_create err:%ld\n", PTR_ERR(odl_cdev[loop].dev)); + result = PTR_ERR(odl_cdev[loop].dev); + goto device0_create_fail; + } + + cdev = &odl_cdev[loop].cdev; + cdev_init(cdev, &ipa_adpl_fops); + cdev->owner = THIS_MODULE; + cdev->ops = &ipa_adpl_fops; + + result = cdev_add(cdev, odl_cdev[loop].dev_num, 1); + if (result) { + IPAERR("cdev_add err=%d\n", -result); + goto cdev0_add_fail; + } + + loop++; + + odl_cdev[loop].class = class_create(THIS_MODULE, "ipa_odl_ctl"); + + if (IS_ERR(odl_cdev[loop].class)) { + IPAERR("Error: odl_cdev->class NULL\n"); + result = -ENODEV; + goto create_char_dev1_fail; + } + + result = alloc_chrdev_region(&odl_cdev[loop].dev_num, 0, 1, + "ipa_odl_ctl"); + if (result) { + IPAERR("alloc_chrdev_region error for ipa odl ctl pipe\n"); + goto alloc_chrdev1_region_fail; + } + + odl_cdev[loop].dev = device_create(odl_cdev[loop].class, NULL, + odl_cdev[loop].dev_num, ipa3_ctx, "ipa_odl_ctl"); + if (IS_ERR(odl_cdev[loop].dev)) { + IPAERR("device_create err:%ld\n", PTR_ERR(odl_cdev[loop].dev)); + result = PTR_ERR(odl_cdev[loop].dev); + goto device1_create_fail; + } + + cdev = &odl_cdev[loop].cdev; + cdev_init(cdev, &ipa_odl_ctl_fops); + cdev->owner = THIS_MODULE; + cdev->ops = &ipa_odl_ctl_fops; + + result = cdev_add(cdev, odl_cdev[loop].dev_num, 1); + if (result) { + IPAERR(":cdev_add err=%d\n", -result); + goto cdev1_add_fail; + } + + ipa3_odl_ctx->odl_state.odl_init = true; + return 0; +cdev1_add_fail: + device_destroy(odl_cdev[1].class, odl_cdev[1].dev_num); +device1_create_fail: + unregister_chrdev_region(odl_cdev[1].dev_num, 1); +alloc_chrdev1_region_fail: + class_destroy(odl_cdev[1].class); +create_char_dev1_fail: +cdev0_add_fail: + device_destroy(odl_cdev[0].class, odl_cdev[0].dev_num); +device0_create_fail: + unregister_chrdev_region(odl_cdev[0].dev_num, 1); +alloc_chrdev0_region_fail: + class_destroy(odl_cdev[0].class); +create_char_dev0_fail: + kfree(ipa3_odl_ctx); +fail_mem_ctx: + return result; +} diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.h b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.h new file mode 100644 index 000000000000..5f522505aa1e --- /dev/null +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.h @@ -0,0 +1,80 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _IPA3_ODL_H_ +#define _IPA3_ODL_H_ + +#define IPA_ODL_AGGR_BYTE_LIMIT (15 * 1024) +#define IPA_ODL_RX_RING_SIZE 192 +#define MAX_QUEUE_TO_ODL 1024 +#define CONFIG_SUCCESS 1 +#define ODL_EP_TYPE_HSUSB 2 +#define ODL_EP_PERIPHERAL_IFACE_ID 3 + +struct ipa3_odlstats { + u32 odl_rx_pkt; + u32 odl_tx_diag_pkt; + u32 odl_drop_pkt; + u32 numer_in_queue; +}; + +struct odl_state_bit_mask { + u32 odl_init:1; + u32 odl_open:1; + u32 adpl_open:1; + u32 aggr_byte_limit_sent:1; + u32 odl_ep_setup:1; + u32 odl_setup_done_sent:1; + u32 odl_ep_info_sent:1; + u32 odl_connected:1; + u32 odl_disconnected:1; + u32:0; +}; + +/** + * struct ipa3_odl_char_device_context - IPA ODL character device + * @class: pointer to the struct class + * @dev_num: device number + * @dev: the dev_t of the device + * @cdev: cdev of the device + */ +struct ipa3_odl_char_device_context { + struct class *class; + dev_t dev_num; + struct device *dev; + struct cdev cdev; +}; + +struct ipa_odl_context { + struct ipa3_odl_char_device_context odl_cdev[2]; + struct list_head adpl_msg_list; + struct mutex adpl_msg_lock; + struct ipa_sys_connect_params odl_sys_param; + u32 odl_client_hdl; + struct odl_state_bit_mask odl_state; + bool odl_ctl_msg_wq_flag; + struct ipa3_odlstats stats; +}; + +struct ipa3_push_msg_odl { + void *buff; + int len; + struct list_head link; +}; + +extern struct ipa_odl_context *ipa3_odl_ctx; + +int ipa_odl_init(void); +void ipa3_odl_pipe_cleanup(bool is_ssr); +int ipa3_odl_pipe_open(void); + +#endif /* _IPA3_ODL_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 5deb78eeb3ed..823b79de76a5 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -1790,6 +1790,12 @@ static const struct ipa_ep_configuration ipa3_ep_mapping IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 11, 6, 9, 9, IPA_EE_AP } }, + [IPA_4_1][IPA_CLIENT_ODL_DPL_CONS] = { + true, IPA_v4_0_GROUP_UL_DL, + false, + IPA_DPS_HPS_SEQ_TYPE_INVALID, + QMB_MASTER_SELECT_DDR, + { 17, 1, 9, 9, IPA_EE_AP } }, [IPA_4_1][IPA_CLIENT_ETHERNET_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 7aef668cc74b..07920706ca04 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -39,6 +39,7 @@ #include "ipa_mhi_proxy.h" #include "ipa_trace.h" +#include "ipa_odl.h" #define OUTSTANDING_HIGH_DEFAULT 256 #define OUTSTANDING_HIGH_CTL_DEFAULT (OUTSTANDING_HIGH_DEFAULT + 32) @@ -2700,6 +2701,7 @@ static int ipa3_ssr_notifier_cb(struct notifier_block *this, if (atomic_read(&rmnet_ipa3_ctx->is_ssr) && ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) ipa3_q6_post_shutdown_cleanup(); + ipa3_odl_pipe_cleanup(true); IPAWANINFO("IPA BEFORE_SHUTDOWN handling is complete\n"); break; case SUBSYS_AFTER_SHUTDOWN: @@ -2724,7 +2726,7 @@ static int ipa3_ssr_notifier_cb(struct notifier_block *this, if (!atomic_read(&rmnet_ipa3_ctx->is_initialized) && atomic_read(&rmnet_ipa3_ctx->is_ssr)) platform_driver_register(&rmnet_ipa_driver); - + ipa3_odl_pipe_open(); IPAWANINFO("IPA AFTER_POWERUP handling is complete\n"); break; default: diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index c7ca98a65db5..320bca938d51 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -100,6 +100,10 @@ #define IPA_IOCTL_GET_VLAN_MODE 58 #define IPA_IOCTL_ADD_BRIDGE_VLAN_MAPPING 59 #define IPA_IOCTL_DEL_BRIDGE_VLAN_MAPPING 60 +#define IPA_IOCTL_ODL_QUERY_ADAPL_EP_INFO 61 +#define IPA_IOCTL_ODL_GET_AGG_BYTE_LIMIT 62 +#define IPA_IOCTL_ODL_QUERY_MODEM_CONFIG 63 + /** * max size of the header to be inserted @@ -311,9 +315,13 @@ enum ipa_client_type { /* RESERVERD PROD = 80, */ IPA_CLIENT_MHI_DPL_CONS = 81, + + /* RESERVERD PROD = 82, */ + IPA_CLIENT_ODL_DPL_CONS = 83, + }; -#define IPA_CLIENT_MAX (IPA_CLIENT_MHI_DPL_CONS + 1) +#define IPA_CLIENT_MAX (IPA_CLIENT_ODL_DPL_CONS + 1) #define IPA_CLIENT_Q6_DL_NLO_DATA_PROD IPA_CLIENT_Q6_DL_NLO_DATA_PROD #define IPA_CLIENT_Q6_UL_NLO_ACK_CONS IPA_CLIENT_Q6_UL_NLO_ACK_CONS @@ -1930,6 +1938,22 @@ struct ipa_ioc_bridge_vlan_mapping_info { uint32_t subnet_mask; }; +struct ipa_odl_ep_info { + __u32 cons_pipe_num; + __u32 prod_pipe_num; + __u32 peripheral_iface_id; + __u32 ep_type; +}; + +struct odl_agg_pipe_info { + __u16 agg_byte_limit; +}; + +struct ipa_odl_modem_config { + __u8 config_status; +}; + + /** * actual IOCTLs supported by IPA driver */ @@ -2122,6 +2146,18 @@ struct ipa_ioc_bridge_vlan_mapping_info { IPA_IOCTL_CLEANUP) #define IPA_IOC_QUERY_WLAN_CLIENT _IO(IPA_IOC_MAGIC,\ IPA_IOCTL_QUERY_WLAN_CLIENT) + +#define IPA_IOC_ODL_QUERY_ADAPL_EP_INFO _IOWR(IPA_IOC_MAGIC, \ + IPA_IOCTL_ODL_QUERY_ADAPL_EP_INFO, \ + struct ipa_odl_ep_info) +#define IPA_IOC_ODL_GET_AGG_BYTE_LIMIT _IOWR(IPA_IOC_MAGIC, \ + IPA_IOCTL_ODL_GET_AGG_BYTE_LIMIT, \ + struct odl_agg_pipe_info) + +#define IPA_IOC_ODL_QUERY_MODEM_CONFIG _IOWR(IPA_IOC_MAGIC, \ + IPA_IOCTL_ODL_QUERY_MODEM_CONFIG, \ + struct ipa_odl_modem_config) + /* * unique magic number of the Tethering bridge ioctls */ -- GitLab From dd17e6b3eb2d6fea6267d6b0e65d38812b9109f5 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Thu, 16 Aug 2018 12:16:05 +0530 Subject: [PATCH 0860/1001] clk: qcom: Remove vdd class voting for xo clock Remove vdd class from the rcg for video_xo_clk_src to avoid voltage voting from the branch clock which is marked as always on. Change-Id: I7a0e452d060c580761e9a8cac2cba4daf00d526b Signed-off-by: Taniya Das --- drivers/clk/qcom/videocc-sdmmagpie.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/clk/qcom/videocc-sdmmagpie.c b/drivers/clk/qcom/videocc-sdmmagpie.c index d38c6e4335c8..8d2d57f3104d 100644 --- a/drivers/clk/qcom/videocc-sdmmagpie.c +++ b/drivers/clk/qcom/videocc-sdmmagpie.c @@ -158,10 +158,6 @@ static struct clk_rcg2 video_cc_xo_clk_src = { .parent_names = video_cc_parent_names_2, .num_parents = 2, .ops = &clk_rcg2_ops, - .vdd_class = &vdd_cx, - .num_rate_max = VDD_NUM, - .rate_max = (unsigned long[VDD_NUM]) { - [VDD_LOWER] = 19200000}, }, }; -- GitLab From 2ebe86b72836c4f07a3ac06339b5c58e258a7b56 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Fri, 17 Aug 2018 16:15:05 +0530 Subject: [PATCH 0861/1001] ARM: dts: msm: Add clocks & hw control for GDSC of SDMMAGPIE Add the required clocks for the Video GDSC and also support hardware control mode for the same. Change-Id: Icea236de2abb328ad996ca5ca6be8f059ea259d0 Signed-off-by: Taniya Das --- arch/arm64/boot/dts/qcom/sdmmagpie.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index 73d6e6ead97d..3e341a59e6f6 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -1779,14 +1779,22 @@ }; &mvsc_gdsc { + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; status = "ok"; }; &mvs0_gdsc { + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; + qcom,support-hw-trigger; status = "ok"; }; &mvs1_gdsc { + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; + qcom,support-hw-trigger; status = "ok"; }; -- GitLab From db05261d79ab911937bc392c14a2ab587132cb25 Mon Sep 17 00:00:00 2001 From: Mohamed Sunfeer Date: Fri, 17 Aug 2018 16:33:32 +0530 Subject: [PATCH 0862/1001] ARM: dts: msm: Add smcinvoke node for SM6150 Current SMCInvoke based framework supports communication between TZ and HLOS where objects are owned by TZ i.e. services are provided by TZ. However, if TZ needs a service from Linux, it has to invoke operation on an object owned by Linux. Such objects are called local objects which could be either callabck objects or memory objects. Callback objects provide services such as operations on a file. Memory objects provide large memory sharing facility between TZ and Linux. Adding smcinvoke node to support local objects. Change-Id: If4574d21dc9cf685752a87d611cc957f9759788b Signed-off-by: Mohamed Sunfeer --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 4f7000086070..590a8765f8a3 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -1621,6 +1621,12 @@ qcom,qsee-reentrancy-support = <2>; }; + qcom_smcinvoke: smcinvoke@86d00000 { + compatible = "qcom,smcinvoke"; + reg = <0x86d00000 0xe00000>; + reg-names = "secapp-region"; + }; + qcom_rng: qrng@793000 { compatible = "qcom,msm-rng"; reg = <0x793000 0x1000>; -- GitLab From c244424044f1ff65837a78f696561b1994330074 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Mon, 13 Aug 2018 16:33:30 +0530 Subject: [PATCH 0863/1001] ARM: dts: msm: add support for td4328 truly panel to sm6150 Add support for dsi td4328 truly command mode and video mode panel to sm6150 platform. Change-Id: Iddf35e2fa56c6f6e91096eda6bf128a67ab60eab Signed-off-by: Ritesh Kumar --- .../dts/qcom/dsi-panel-td4328-1080p-cmd.dtsi | 176 ++++++++++++++++++ .../qcom/dsi-panel-td4328-1080p-video.dtsi | 172 +++++++++++++++++ arch/arm64/boot/dts/qcom/sm6150-idp.dtsi | 18 ++ .../boot/dts/qcom/sm6150-sde-display.dtsi | 64 ++++++- 4 files changed, 429 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-td4328-1080p-cmd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-td4328-1080p-video.dtsi diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-td4328-1080p-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-td4328-1080p-cmd.dtsi new file mode 100644 index 000000000000..97556699dadf --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-td4328-1080p-cmd.dtsi @@ -0,0 +1,176 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&mdss_mdp { + dsi_td4328_truly_cmd: qcom,mdss_dsi_td4328_truly_cmd { + qcom,mdss-dsi-panel-name = + "td4328 cmd mode dsi truly panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <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-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + 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-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <70>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <10>; + qcom,mdss-dsi-v-front-porch = <5>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 04 B3 00 00 06 + 29 01 00 00 00 00 02 B4 00 + 29 01 00 00 00 00 06 B6 33 DB 80 12 00 + 29 01 00 00 00 00 08 B8 57 3D 19 1E 0A + 50 50 + 29 01 00 00 00 00 08 B9 6F 3D 28 3C 14 + C8 C8 + 29 01 00 00 00 00 08 BA B5 33 41 64 23 + A0 A0 + 29 01 00 00 00 00 03 BB 14 14 + 29 01 00 00 00 00 03 BC 37 32 + 29 01 00 00 00 00 03 BD 64 32 + 29 01 00 00 00 00 02 BE 04 + 29 01 00 00 00 00 02 C0 00 + 29 01 00 00 00 00 2E C1 04 48 00 00 26 + 15 19 0B 63 D2 D9 9A 73 EF BD E7 5C + 6B 93 4D 22 18 8B 2A 41 00 00 00 00 + 00 00 00 00 00 40 02 22 1B 06 03 00 + 07 FF 00 01 + 29 01 00 00 00 00 18 C2 01 F8 70 08 68 + 08 0C 10 00 08 30 00 00 00 00 00 00 + 20 02 43 00 00 00 + 29 01 00 00 00 00 3F C3 87 D8 7D 87 D0 + 00 00 00 00 00 00 04 3A 00 00 00 04 + 44 00 00 01 01 03 28 00 01 00 01 00 + 00 19 00 0C 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 32 00 19 00 5A + 02 32 00 19 00 5A 02 40 00 + 29 01 00 00 00 00 15 C4 70 00 00 00 11 + 11 00 00 00 02 02 31 01 00 00 00 02 + 01 01 01 + 29 01 00 00 00 00 08 C5 08 00 00 00 00 + 70 00 + 29 01 00 00 00 00 40 C6 5B 2D 2D 07 54 + 07 54 01 02 01 02 07 07 00 00 07 07 + 0F 11 07 5B 00 5B 5B C2 C2 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 + 29 01 00 00 00 00 27 C7 01 1D 2E 41 4F + 5A 71 80 8B 95 45 4F 5C 71 7B 88 98 + A6 BE 01 1D 2E 41 4F 5A 71 80 8B 95 + 45 4F 5C 71 7B 88 98 A6 BE + 29 01 00 00 00 00 38 C8 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 + 29 01 00 00 00 00 14 C9 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 + 29 01 00 00 00 00 2C CA 1C FC FC FC 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 + 29 01 00 00 00 00 1C CB FF FF FF FF 0F + 00 08 00 01 00 31 F0 40 08 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 CC 02 + 29 01 00 00 00 00 27 CD 10 80 37 C0 1A + 00 5C 02 19 90 11 88 D8 6C D8 6C 01 + 00 00 00 32 00 32 00 5D 02 32 32 01 + 33 00 33 00 5E 02 32 32 AF + 29 01 00 00 00 00 1A CE 5D 40 49 53 59 + 5E 63 68 6E 74 7E 8A 98 A8 BB D0 FF + 04 00 04 04 42 00 69 5A + 29 01 00 00 00 00 03 CF 4A 1D + 29 01 00 00 00 00 12 D0 33 57 D4 31 01 + 10 10 10 19 19 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 D1 00 + 29 01 00 00 00 00 20 D2 10 00 00 10 75 + 0F 03 25 20 00 00 00 00 00 00 00 00 + 04 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 17 D3 1B 3B BB 77 77 + 77 BB B3 33 00 00 6D 6E C7 C7 33 BB + F2 FD C6 0B 07 + 29 01 00 00 00 00 08 D4 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 08 D5 03 00 00 02 2B + 02 2B + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 22 D7 F6 FF 03 05 41 + 24 80 1F C7 1F 1B 00 0C 07 20 00 00 + 00 00 00 0C 00 1F 00 FC 00 00 AA 67 + 7E 5D 06 00 + 29 01 00 00 00 00 03 D9 20 14 + 29 01 00 00 00 00 05 DD 30 06 23 65 + 29 01 00 00 00 00 05 DE 00 3F FF 50 + 29 01 00 00 00 00 06 E7 00 00 00 46 61 + 29 01 00 00 00 00 02 EA 1F + 29 01 00 00 00 00 04 EE 41 51 00 + 29 01 00 00 00 00 03 F1 00 00 + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2B 00 00 08 6F + 39 01 00 00 00 00 01 2C + 29 01 00 00 00 00 02 B0 00 + 39 01 00 00 00 00 02 51 FF + 39 01 00 00 00 00 02 53 0C + 39 01 00 00 00 00 02 55 00 + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 96 00 01 11 + 05 01 00 00 32 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 96 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/arm64/boot/dts/qcom/dsi-panel-td4328-1080p-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-td4328-1080p-video.dtsi new file mode 100644 index 000000000000..12827c80a583 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-td4328-1080p-video.dtsi @@ -0,0 +1,172 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&mdss_mdp { + dsi_td4328_truly_video: qcom,mdss_dsi_td4328_truly_video { + qcom,mdss-dsi-panel-name = + "td4328 video mode dsi truly panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + 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-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + 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-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <70>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <10>; + qcom,mdss-dsi-v-front-porch = <5>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 04 B3 31 00 06 + 29 01 00 00 00 00 02 B4 00 + 29 01 00 00 00 00 06 B6 33 DB 80 12 00 + 29 01 00 00 00 00 08 B8 57 3D 19 1E 0A + 50 50 + 29 01 00 00 00 00 08 B9 6F 3D 28 3C 14 + C8 C8 + 29 01 00 00 00 00 08 BA B5 33 41 64 23 + A0 A0 + 29 01 00 00 00 00 03 BB 14 14 + 29 01 00 00 00 00 03 BC 37 32 + 29 01 00 00 00 00 03 BD 64 32 + 29 01 00 00 00 00 02 BE 04 + 29 01 00 00 00 00 02 C0 00 + 29 01 00 00 00 00 2E C1 04 48 00 00 26 + 15 19 0B 63 D2 D9 9A 73 EF BD E7 5C + 6B 93 4D 22 18 8B 2A 41 00 00 00 00 + 00 00 00 00 00 40 02 22 1B 06 03 00 + 07 FF 00 01 + 29 01 00 00 00 00 18 C2 01 F8 70 08 68 + 08 0C 10 00 08 30 00 00 00 00 00 00 + 20 02 43 00 00 00 + 29 01 00 00 00 00 3F C3 87 D8 7D 87 D0 + 00 00 00 00 00 00 04 3A 00 00 00 04 + 44 00 00 01 01 03 28 00 01 00 01 00 + 00 19 00 0C 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 32 00 19 00 5A + 02 32 00 19 00 5A 02 40 00 + 29 01 00 00 00 00 15 C4 70 00 00 00 11 + 11 00 00 00 02 02 31 01 00 00 00 02 + 01 01 01 + 29 01 00 00 00 00 08 C5 08 00 00 00 00 + 70 00 + 29 01 00 00 00 00 40 C6 5B 2D 2D 07 54 + 07 54 01 02 01 02 07 07 00 00 07 07 + 0F 11 07 5B 00 5B 5B C2 C2 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 + 29 01 00 00 00 00 27 C7 01 1D 2E 41 4F + 5A 71 80 8B 95 45 4F 5C 71 7B 88 98 + A6 BE 01 1D 2E 41 4F 5A 71 80 8B 95 + 45 4F 5C 71 7B 88 98 A6 BE + 29 01 00 00 00 00 38 C8 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 + 29 01 00 00 00 00 14 C9 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 + 29 01 00 00 00 00 2C CA 1C FC FC FC 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 + 29 01 00 00 00 00 1C CB FF FF FF FF 0F + 00 08 00 01 00 31 F0 40 08 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 CC 02 + 29 01 00 00 00 00 27 CD 10 80 37 C0 1A + 00 5C 02 19 90 11 88 D8 6C D8 6C 01 + 00 00 00 32 00 32 00 5D 02 32 32 01 + 33 00 33 00 5E 02 32 32 AF + 29 01 00 00 00 00 1A CE 5D 40 49 53 59 + 5E 63 68 6E 74 7E 8A 98 A8 BB D0 FF + 04 00 04 04 42 00 69 5A + 29 01 00 00 00 00 03 CF 4A 1D + 29 01 00 00 00 00 12 D0 33 57 D4 31 01 + 10 10 10 19 19 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 D1 00 + 29 01 00 00 00 00 20 D2 10 00 00 10 75 + 0F 03 25 20 00 00 00 00 00 00 00 00 + 04 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 17 D3 1B 3B BB 77 77 + 77 BB B3 33 00 00 6D 6E DB DB 33 BB + F2 FD C6 0B 07 + 29 01 00 00 00 00 08 D4 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 08 D5 03 00 00 02 40 + 02 40 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 22 D7 F6 FF 03 05 41 + 24 80 1F C7 1F 1B 00 0C 07 20 00 00 + 00 00 00 0C 00 1F 00 FC 00 00 AA 67 + 7E 5D 06 00 + 29 01 00 00 00 00 03 D9 20 14 + 29 01 00 00 00 00 05 DD 30 06 23 65 + 29 01 00 00 00 00 05 DE 00 3F FF 90 + 29 01 00 00 00 00 06 E7 00 00 00 46 61 + 29 01 00 00 00 00 02 EA 1F + 29 01 00 00 00 00 04 EE 41 51 00 + 29 01 00 00 00 00 03 F1 00 00 + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2B 00 00 08 6F + 39 01 00 00 00 00 01 2C + 39 01 00 00 00 00 02 51 FF + 39 01 00 00 00 00 02 53 0C + 39 01 00 00 00 00 02 55 00 + 05 01 00 00 96 00 01 11 + 05 01 00 00 32 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 96 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/arm64/boot/dts/qcom/sm6150-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi index bc4bd148979b..b1bad4023918 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi @@ -136,3 +136,21 @@ qcom,platform-te-gpio = <&tlmm 90 0>; qcom,platform-reset-gpio = <&tlmm 91 0>; }; + +&dsi_td4328_truly_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 90 0>; + qcom,platform-reset-gpio = <&tlmm 91 0>; +}; + +&dsi_td4328_truly_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 90 0>; + qcom,platform-reset-gpio = <&tlmm 91 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi index 18802d41d15c..c7dfa60b9937 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi @@ -13,6 +13,8 @@ #include "dsi-panel-sim-video.dtsi" #include "dsi-panel-sim-cmd.dtsi" #include "dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi" +#include "dsi-panel-td4328-1080p-video.dtsi" +#include "dsi-panel-td4328-1080p-cmd.dtsi" #include &soc { @@ -98,6 +100,28 @@ qcom,dsi-panel = <&dsi_hx83112a_truly_video>; }; + dsi_td4328_truly_vid_display: qcom,dsi-display@3 { + label = "dsi_td4328_truly_vid_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_td4328_truly_video>; + }; + + dsi_td4328_truly_cmd_display: qcom,dsi-display@4 { + label = "dsi_td4328_truly_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_td4328_truly_cmd>; + }; + sde_dsi: qcom,dsi-display { compatible = "qcom,dsi-display"; @@ -120,7 +144,9 @@ qcom,dsi-display-list = <&dsi_sim_vid_display &dsi_sim_cmd_display - &dsi_hx83112a_truly_vid_display>; + &dsi_hx83112a_truly_vid_display + &dsi_td4328_truly_vid_display + &dsi_td4328_truly_cmd_display>; }; sde_wb: qcom,wb-display@0 { @@ -227,3 +253,39 @@ }; }; }; + +&dsi_td4328_truly_video { + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x32>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = + [24 20 08 09 05 02 04 a0 + 24 20 08 09 05 02 04 a0 + 24 20 08 09 05 02 04 a0 + 24 20 08 09 05 02 04 a0 + 24 1d 08 09 05 02 04 a0]; + + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_td4328_truly_cmd { + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x32>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = + [24 20 08 09 05 02 04 a0 + 24 20 08 09 05 02 04 a0 + 24 20 08 09 05 02 04 a0 + 24 20 08 09 05 02 04 a0 + 24 1d 08 09 05 02 04 a0]; + + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; -- GitLab From 5298517a811666d1c86b5c21e78b962e8e1baa6a Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Wed, 15 Aug 2018 15:59:58 +0530 Subject: [PATCH 0864/1001] clk: qcom: Remove the parent for video_cc_xo_clk clock on SM6150 video_cc_xo_clk clock vote is blocking XO shutdown, remove its parent as it does not need to be modeled. Change-Id: I5abb2ce7ac2d8512a9f3f5637f729414ee2ad6c8 Signed-off-by: Odelu Kukatla --- drivers/clk/qcom/videocc-sm6150.c | 30 +------------------ .../dt-bindings/clock/qcom,videocc-sm6150.h | 1 - 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/drivers/clk/qcom/videocc-sm6150.c b/drivers/clk/qcom/videocc-sm6150.c index 4aa1cfa0714f..cc775411cba0 100644 --- a/drivers/clk/qcom/videocc-sm6150.c +++ b/drivers/clk/qcom/videocc-sm6150.c @@ -176,29 +176,6 @@ static struct clk_rcg2 video_cc_venus_clk_src = { }, }; -static const struct freq_tbl ftbl_video_cc_xo_clk_src[] = { - F(19200000, P_BI_TCXO, 1, 0, 0), - { } -}; - -static struct clk_rcg2 video_cc_xo_clk_src = { - .cmd_rcgr = 0xa98, - .mnd_width = 0, - .hid_width = 5, - .parent_map = video_cc_parent_map_2, - .freq_tbl = ftbl_video_cc_xo_clk_src, - .clkr.hw.init = &(struct clk_init_data){ - .name = "video_cc_xo_clk_src", - .parent_names = video_cc_parent_names_2, - .num_parents = 2, - .ops = &clk_rcg2_ops, - .vdd_class = &vdd_cx, - .num_rate_max = VDD_NUM, - .rate_max = (unsigned long[VDD_NUM]) { - [VDD_LOWER] = 19200000}, - }, -}; - static struct clk_branch video_cc_apb_clk = { .halt_reg = 0x990, .halt_check = BRANCH_HALT, @@ -313,11 +290,7 @@ static struct clk_branch video_cc_xo_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "video_cc_xo_clk", - .parent_names = (const char *[]){ - "video_cc_xo_clk_src", - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -334,7 +307,6 @@ static struct clk_regmap *video_cc_sm6150_clocks[] = { [VIDEO_CC_VENUS_CTL_AXI_CLK] = &video_cc_venus_ctl_axi_clk.clkr, [VIDEO_CC_VENUS_CTL_CORE_CLK] = &video_cc_venus_ctl_core_clk.clkr, [VIDEO_CC_XO_CLK] = &video_cc_xo_clk.clkr, - [VIDEO_CC_XO_CLK_SRC] = &video_cc_xo_clk_src.clkr, [VIDEO_PLL0_OUT_MAIN] = &video_pll0_out_main.clkr, }; diff --git a/include/dt-bindings/clock/qcom,videocc-sm6150.h b/include/dt-bindings/clock/qcom,videocc-sm6150.h index cfb27950126b..8ecdb2d3dbd7 100644 --- a/include/dt-bindings/clock/qcom,videocc-sm6150.h +++ b/include/dt-bindings/clock/qcom,videocc-sm6150.h @@ -26,6 +26,5 @@ #define VIDEO_CC_VENUS_CTL_AXI_CLK 8 #define VIDEO_CC_VENUS_CTL_CORE_CLK 9 #define VIDEO_CC_XO_CLK 10 -#define VIDEO_CC_XO_CLK_SRC 11 #endif -- GitLab From ecfde8144c291ab7337ff8d544b372c4191cf68e Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Wed, 28 Feb 2018 22:55:40 +0530 Subject: [PATCH 0865/1001] usb: misc: Add support for test modes via external hub Some external hubs cannot enter into test mode if EHSET fixture is connected to one of its downstream ports. Add support to enable test modes on any desired downstream port of an external hub. The port and the test mode can be selected via sysfs nodes. For example, to send TEST_J packet on downstream port 4 of external hub 3-1:1.0: echo 4 > /sys/bus/usb/devices/3-1/3-1\:1.0/test_j_portnum Change-Id: I145f150bfe8557844cb150cf39fafe03a18bd955 Signed-off-by: Ajay Agarwal --- drivers/usb/misc/ehset.c | 304 ++++++++++++++++++++++++++++++++------- 1 file changed, 254 insertions(+), 50 deletions(-) diff --git a/drivers/usb/misc/ehset.c b/drivers/usb/misc/ehset.c index c31b4a33e6bb..0efcd485c02a 100644 --- a/drivers/usb/misc/ehset.c +++ b/drivers/usb/misc/ehset.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2013, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -26,69 +26,89 @@ #define TEST_SINGLE_STEP_GET_DEV_DESC 0x0107 #define TEST_SINGLE_STEP_SET_FEATURE 0x0108 -static int ehset_probe(struct usb_interface *intf, - const struct usb_device_id *id) +static u8 numPorts; + +static int ehset_get_port_num(struct device *dev, const char *buf, + unsigned long *val) +{ + int ret; + + ret = kstrtoul(buf, 10, val); + if (ret < 0) { + dev_err(dev, "couldn't parse string %d\n", ret); + return ret; + } + + if (!*val || *val > numPorts) { + dev_err(dev, "Invalid port num entered\n"); + return -EINVAL; + } + + return 0; +} + +static int ehset_clear_port_feature(struct usb_device *udev, int feature, + int port1) +{ + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1, + NULL, 0, 1000); +} + +static int ehset_set_port_feature(struct usb_device *udev, int feature, + int port1, int timeout) +{ + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1, + NULL, 0, timeout); +} + +static int ehset_set_testmode(struct device *dev, struct usb_device *child_udev, + struct usb_device *hub_udev, int test_id, int port) { - int ret = -EINVAL; - struct usb_device *dev = interface_to_usbdev(intf); - struct usb_device *hub_udev = dev->parent; struct usb_device_descriptor *buf; - u8 portnum = dev->portnum; - u16 test_pid = le16_to_cpu(dev->descriptor.idProduct); + int ret = -EINVAL; - switch (test_pid) { + switch (test_id) { case TEST_SE0_NAK_PID: - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_TEST, - (TEST_SE0_NAK << 8) | portnum, - NULL, 0, 1000); + ret = ehset_set_port_feature(hub_udev, USB_PORT_FEAT_TEST, + (TEST_SE0_NAK << 8) | port, 1000); break; case TEST_J_PID: - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_TEST, - (TEST_J << 8) | portnum, - NULL, 0, 1000); + ret = ehset_set_port_feature(hub_udev, USB_PORT_FEAT_TEST, + (TEST_J << 8) | port, 1000); break; case TEST_K_PID: - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_TEST, - (TEST_K << 8) | portnum, - NULL, 0, 1000); + ret = ehset_set_port_feature(hub_udev, USB_PORT_FEAT_TEST, + (TEST_K << 8) | port, 1000); break; case TEST_PACKET_PID: - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_TEST, - (TEST_PACKET << 8) | portnum, - NULL, 0, 1000); + ret = ehset_set_port_feature(hub_udev, USB_PORT_FEAT_TEST, + (TEST_PACKET << 8) | port, 1000); break; case TEST_HS_HOST_PORT_SUSPEND_RESUME: /* Test: wait for 15secs -> suspend -> 15secs delay -> resume */ msleep(15 * 1000); - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_SUSPEND, portnum, - NULL, 0, 1000); - if (ret < 0) + ret = ehset_set_port_feature(hub_udev, USB_PORT_FEAT_SUSPEND, + port, 1000); + if (ret) break; msleep(15 * 1000); - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_CLEAR_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_SUSPEND, portnum, - NULL, 0, 1000); + ret = ehset_clear_port_feature(hub_udev, USB_PORT_FEAT_SUSPEND, + port); break; case TEST_SINGLE_STEP_GET_DEV_DESC: /* Test: wait for 15secs -> GetDescriptor request */ msleep(15 * 1000); buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; + if (!buf) { + ret = -ENOMEM; + break; + } - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + ret = usb_control_msg(child_udev, + usb_rcvctrlpipe(child_udev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, USB_DT_DEVICE << 8, 0, buf, USB_DT_DEVICE_SIZE, @@ -103,28 +123,212 @@ static int ehset_probe(struct usb_interface *intf, * SetPortFeature handling can only be done inside the HCD's * hub_control callback function. */ - if (hub_udev != dev->bus->root_hub) { - dev_err(&intf->dev, "SINGLE_STEP_SET_FEATURE test only supported on root hub\n"); + if (hub_udev != child_udev->bus->root_hub) { + dev_err(dev, "SINGLE_STEP_SET_FEATURE test only supported on root hub\n"); break; } - ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, - USB_PORT_FEAT_TEST, - (6 << 8) | portnum, - NULL, 0, 60 * 1000); + ret = ehset_set_port_feature(hub_udev, USB_PORT_FEAT_TEST, + (6 << 8) | port, 60 * 1000); break; default: - dev_err(&intf->dev, "%s: unsupported PID: 0x%x\n", - __func__, test_pid); + dev_err(dev, "%s: unsupported test ID: 0x%x\n", + __func__, test_id); + } + + return ret; +} + +static ssize_t test_se0_nak_portnum_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *udev = interface_to_usbdev(intf); + unsigned long portnum; + int ret; + + ret = ehset_get_port_num(dev, buf, &portnum); + if (ret) + return ret; + + usb_lock_device(udev); + ret = ehset_set_testmode(dev, NULL, udev, TEST_SE0_NAK_PID, portnum); + usb_unlock_device(udev); + if (ret) { + dev_err(dev, "Error %d while SE0_NAK test\n", ret); + return ret; } + return count; +} +static DEVICE_ATTR_WO(test_se0_nak_portnum); + +static ssize_t test_j_portnum_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *udev = interface_to_usbdev(intf); + unsigned long portnum; + int ret; + + ret = ehset_get_port_num(dev, buf, &portnum); + if (ret) + return ret; + + usb_lock_device(udev); + ret = ehset_set_testmode(dev, NULL, udev, TEST_J_PID, portnum); + usb_unlock_device(udev); + if (ret) { + dev_err(dev, "Error %d while J state test\n", ret); + return ret; + } + + return count; +} +static DEVICE_ATTR_WO(test_j_portnum); + +static ssize_t test_k_portnum_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *udev = interface_to_usbdev(intf); + unsigned long portnum; + int ret; + + ret = ehset_get_port_num(dev, buf, &portnum); + if (ret) + return ret; + + usb_lock_device(udev); + ret = ehset_set_testmode(dev, NULL, udev, TEST_K_PID, portnum); + usb_unlock_device(udev); + if (ret) { + dev_err(dev, "Error %d while K state test\n", ret); + return ret; + } + + return count; +} +static DEVICE_ATTR_WO(test_k_portnum); + +static ssize_t test_packet_portnum_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *udev = interface_to_usbdev(intf); + unsigned long portnum; + int ret; + + ret = ehset_get_port_num(dev, buf, &portnum); + if (ret) + return ret; + + usb_lock_device(udev); + ret = ehset_set_testmode(dev, NULL, udev, TEST_PACKET_PID, portnum); + usb_unlock_device(udev); + if (ret) { + dev_err(dev, "Error %d while sending test packets\n", ret); + return ret; + } + + return count; +} +static DEVICE_ATTR_WO(test_packet_portnum); + +static ssize_t test_port_susp_resume_portnum_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_device *udev = interface_to_usbdev(intf); + unsigned long portnum; + int ret; + + ret = ehset_get_port_num(dev, buf, &portnum); + if (ret) + return ret; + + usb_lock_device(udev); + ret = ehset_set_testmode(dev, NULL, udev, + TEST_HS_HOST_PORT_SUSPEND_RESUME, portnum); + usb_unlock_device(udev); + if (ret) { + dev_err(dev, "Error %d while port suspend resume test\n", ret); + return ret; + } + + return count; +} +static DEVICE_ATTR_WO(test_port_susp_resume_portnum); + +static struct attribute *ehset_attributes[] = { + &dev_attr_test_se0_nak_portnum.attr, + &dev_attr_test_j_portnum.attr, + &dev_attr_test_k_portnum.attr, + &dev_attr_test_packet_portnum.attr, + &dev_attr_test_port_susp_resume_portnum.attr, + NULL +}; + +static const struct attribute_group ehset_attr_group = { + .attrs = ehset_attributes, +}; + +static int ehset_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret = -EINVAL; + struct usb_device *dev = interface_to_usbdev(intf); + struct usb_device *hub_udev = dev->parent; + u8 portnum = dev->portnum; + u16 test_pid = le16_to_cpu(dev->descriptor.idProduct); + + /* + * If an external hub does not support the EHSET test fixture, then user + * can forcefully unbind the external hub from the hub driver (to which + * an external hub gets bound by default) and bind it to this driver, so + * as to send test signals on any downstream port of the hub. + */ + if (dev->descriptor.bDeviceClass == USB_CLASS_HUB) { + struct usb_hub_descriptor *descriptor; + + descriptor = kzalloc(sizeof(*descriptor), GFP_KERNEL); + if (!descriptor) + return -ENOMEM; + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, + USB_DT_HUB << 8, 0, descriptor, + USB_DT_HUB_NONVAR_SIZE, USB_CTRL_GET_TIMEOUT); + if (ret < 0) { + dev_err(&intf->dev, "%s: Failed to get hub desc %d\n", + __func__, ret); + kfree(descriptor); + return ret; + } + + numPorts = descriptor->bNbrPorts; + ret = sysfs_create_group(&intf->dev.kobj, &ehset_attr_group); + if (ret < 0) + dev_err(&intf->dev, "%s: Failed to create sysfs nodes %d\n", + __func__, ret); + + kfree(descriptor); + return ret; + } + + ret = ehset_set_testmode(&intf->dev, dev, hub_udev, test_pid, portnum); + return (ret < 0) ? ret : 0; } static void ehset_disconnect(struct usb_interface *intf) { + struct usb_device *dev = interface_to_usbdev(intf); + + numPorts = 0; + if (dev->descriptor.bDeviceClass == USB_CLASS_HUB) + sysfs_remove_group(&intf->dev.kobj, &ehset_attr_group); } static const struct usb_device_id ehset_id_table[] = { -- GitLab From 37a6ffdde13bc9bca3bf82cb768565b3215ce51a Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Fri, 17 Aug 2018 21:46:43 +0530 Subject: [PATCH 0866/1001] defconfig: Enable EHSET test fixture driver on sm8150 Auto Enable EHSET test fixture driver on sm8150 automotive target. This driver is used to test high speed host electrical compliance. Change-Id: I3969c5de288c6fe5bce3d4ae5fafc6fa5a3790ca Signed-off-by: Ajay Agarwal --- arch/arm64/configs/vendor/sa8155-perf_defconfig | 1 + arch/arm64/configs/vendor/sa8155_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/vendor/sa8155-perf_defconfig b/arch/arm64/configs/vendor/sa8155-perf_defconfig index 754e3f684d40..40413a4c7c39 100644 --- a/arch/arm64/configs/vendor/sa8155-perf_defconfig +++ b/arch/arm64/configs/vendor/sa8155-perf_defconfig @@ -412,6 +412,7 @@ CONFIG_USB_DWC3=y CONFIG_USB_DWC3_MSM=y CONFIG_USB_ISP1760=y CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_QCOM_EMU_PHY=y CONFIG_USB_MSM_SSPHY_QMP=y diff --git a/arch/arm64/configs/vendor/sa8155_defconfig b/arch/arm64/configs/vendor/sa8155_defconfig index 065ae9b16f8a..ddc6887dfbbc 100644 --- a/arch/arm64/configs/vendor/sa8155_defconfig +++ b/arch/arm64/configs/vendor/sa8155_defconfig @@ -430,6 +430,7 @@ CONFIG_USB_DWC3=y CONFIG_USB_DWC3_MSM=y CONFIG_USB_ISP1760=y CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_QCOM_EMU_PHY=y CONFIG_USB_MSM_SSPHY_QMP=y -- GitLab From 8fe3748bbd994dbe46c0588445b4c1efa15895e5 Mon Sep 17 00:00:00 2001 From: Vevek Venkatesan Date: Wed, 25 Jul 2018 18:23:15 +0530 Subject: [PATCH 0867/1001] input: touchscreen: hxchipset: add display dependency Add display dependency for chip init in hxchipset driver, as it is TDDI controller. Change-Id: Ia278d971d11b432f1e387170a0ca0b3966cb84e1 Signed-off-by: Vevek Venkatesan --- .../touchscreen/hxchipset/himax_common.c | 33 ++++--------------- .../touchscreen/hxchipset/himax_common.h | 6 ++-- .../touchscreen/hxchipset/himax_platform.c | 22 ++++++++++++- 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/drivers/input/touchscreen/hxchipset/himax_common.c b/drivers/input/touchscreen/hxchipset/himax_common.c index 43ea1829c4af..bac270e9fc0b 100644 --- a/drivers/input/touchscreen/hxchipset/himax_common.c +++ b/drivers/input/touchscreen/hxchipset/himax_common.c @@ -1890,23 +1890,23 @@ static void himax_update_register(struct work_struct *work) #endif #ifdef CONFIG_DRM -static void himax_fb_register(struct work_struct *work) +int himax_fb_register(struct himax_ts_data *ts) { int ret = 0; - struct himax_ts_data *ts = container_of(work, struct himax_ts_data, work_att.work); I(" %s in\n", __func__); ts->fb_notif.notifier_call = fb_notifier_callback; ret = msm_drm_register_client(&ts->fb_notif); if (ret) E(" Unable to register fb_notifier: %d\n", ret); + + return ret; } #elif defined CONFIG_FB -static void himax_fb_register(struct work_struct *work) +int himax_fb_register(struct himax_ts_data *ts) { int ret = 0; - struct himax_ts_data *ts = container_of(work, struct himax_ts_data, work_att.work); I(" %s in\n", __func__); ts->fb_notif.notifier_call = fb_notifier_callback; @@ -1914,6 +1914,8 @@ static void himax_fb_register(struct work_struct *work) if (ret) E(" Unable to register fb_notifier: %d\n", ret); + + return ret; } #endif @@ -2070,20 +2072,6 @@ int himax_chip_common_init(void) goto err_input_register_device_failed; } -#if defined(CONFIG_DRM) || defined(CONFIG_FB) - - ts->himax_att_wq = create_singlethread_workqueue("HMX_ATT_request"); - - if (!ts->himax_att_wq) { - E(" allocate syn_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)); -#endif - #ifdef HX_SMART_WAKEUP ts->SMWP_enable = 0; wakeup_source_init(&ts->ts_SMWP_wake_src, WAKE_LOCK_SUSPEND, HIMAX_common_NAME); @@ -2148,11 +2136,6 @@ remove_proc_entry(HIMAX_PROC_TOUCH_FOLDER, NULL); #ifdef HX_SMART_WAKEUP wakeup_source_trash(&ts->ts_SMWP_wake_src); #endif -#if defined(CONFIG_FB) || defined(CONFIG_DRM) -err_get_intr_bit_failed: - cancel_delayed_work_sync(&ts->work_att); - destroy_workqueue(ts->himax_att_wq); -#endif err_input_register_device_failed: input_free_device(ts->input_dev); err_detect_failed: @@ -2217,13 +2200,9 @@ void himax_chip_common_deinit(void) #ifdef CONFIG_DRM if (msm_drm_unregister_client(&ts->fb_notif)) E("Error occurred while unregistering fb_notifier.\n"); - cancel_delayed_work_sync(&ts->work_att); - destroy_workqueue(ts->himax_att_wq); #elif defined(CONFIG_FB) if (fb_unregister_client(&ts->fb_notif)) E("Error occurred while unregistering fb_notifier.\n"); - cancel_delayed_work_sync(&ts->work_att); - destroy_workqueue(ts->himax_att_wq); #endif input_free_device(ts->input_dev); #ifdef HX_ZERO_FLASH diff --git a/drivers/input/touchscreen/hxchipset/himax_common.h b/drivers/input/touchscreen/hxchipset/himax_common.h index e190490d469c..82907fd554fa 100644 --- a/drivers/input/touchscreen/hxchipset/himax_common.h +++ b/drivers/input/touchscreen/hxchipset/himax_common.h @@ -259,6 +259,7 @@ struct himax_report_data { }; struct himax_ts_data { + bool initialized; bool suspended; atomic_t suspend_mode; uint8_t x_channel; @@ -320,10 +321,8 @@ struct himax_ts_data { int in_self_test; -#if defined(CONFIG_FB) +#if defined(CONFIG_FB) || defined(CONFIG_DRM) 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 @@ -474,6 +473,7 @@ extern int himax_chip_common_suspend(struct himax_ts_data *ts); extern int himax_chip_common_resume(struct himax_ts_data *ts); extern int himax_chip_common_init(void); extern void himax_chip_common_deinit(void); +extern int himax_fb_register(struct himax_ts_data *ts); extern int himax_input_register(struct himax_ts_data *ts); extern void himax_ts_work(struct himax_ts_data *ts); extern enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer); diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.c b/drivers/input/touchscreen/hxchipset/himax_platform.c index 95564672112b..1805fa063bfc 100644 --- a/drivers/input/touchscreen/hxchipset/himax_platform.c +++ b/drivers/input/touchscreen/hxchipset/himax_platform.c @@ -658,6 +658,11 @@ int fb_notifier_callback(struct notifier_block *self, unsigned long event, void switch (*blank) { case MSM_DRM_BLANK_UNBLANK: + if (!ts->initialized) { + if (himax_chip_common_init()) + return 0; + ts->initialized = true; + } himax_common_resume(&ts->client->dev); break; case MSM_DRM_BLANK_POWERDOWN: @@ -689,6 +694,11 @@ int fb_notifier_callback(struct notifier_block *self, unsigned long event, void switch (*blank) { case FB_BLANK_UNBLANK: + if (!ts->initialized) { + if (himax_chip_common_init()) + return 0; + ts->initialized = true; + } himax_common_resume(&ts->client->dev); break; case FB_BLANK_POWERDOWN: @@ -731,8 +741,18 @@ int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_i mutex_init(&ts->rw_lock); private_ts = ts; - ret = himax_chip_common_init(); + /* + * ts chip initialization is deferred till FB_UNBLACK event; + * probe is considered pending till then. + */ + ts->initialized = false; +#if defined(CONFIG_FB) || defined(CONFIG_DRM) + ret = himax_fb_register(ts); + if (ret) + goto err_fb_notify_reg_failed; +#endif +err_fb_notify_reg_failed: err_alloc_data_failed: err_check_functionality_failed: -- GitLab From beb061a578b32b6f02c20dc532b6ce67593cc23e Mon Sep 17 00:00:00 2001 From: Vevek Venkatesan Date: Fri, 17 Aug 2018 22:28:07 +0530 Subject: [PATCH 0868/1001] input: touchscreen: hxchipset: fix crash when i2c fails Adding fix for the crash when I2C fails. Handling I2C failure case. Change-Id: I1817ff9bbe0b7b360a6d56d5f984d7eb04fc7e7c Signed-off-by: Vevek Venkatesan --- drivers/input/touchscreen/hxchipset/himax_common.c | 7 +++++++ drivers/input/touchscreen/hxchipset/himax_platform.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/hxchipset/himax_common.c b/drivers/input/touchscreen/hxchipset/himax_common.c index bac270e9fc0b..5854de063d82 100644 --- a/drivers/input/touchscreen/hxchipset/himax_common.c +++ b/drivers/input/touchscreen/hxchipset/himax_common.c @@ -1959,6 +1959,7 @@ int himax_chip_common_init(void) if (himax_parse_dt(ts, pdata) < 0) { I(" pdata is NULL for DT\n"); + err = -ECANCELED; goto err_alloc_dt_pdata_failed; } @@ -1973,6 +1974,7 @@ int himax_chip_common_init(void) if (ret < 0) { E("%s: power on failed\n", __func__); + err = ret; goto err_power_failed; } } @@ -1984,10 +1986,12 @@ int himax_chip_common_init(void) g_core_fp.fp_chip_init(); } else { E("%s: chip detect failed!\n", __func__); + err = -ECANCELED; goto error_ic_detect_failed; } } else { E("%s: function point is NULL!\n", __func__); + err = -ECANCELED; goto error_ic_detect_failed; } @@ -2028,6 +2032,7 @@ int himax_chip_common_init(void) /* Himax Power On and Load Config */ if (himax_loadSensorConfig(pdata)) { E("%s: Load Sesnsor configuration failed, unload driver.\n", __func__); + err = -ECANCELED; goto err_detect_failed; } @@ -2069,6 +2074,7 @@ int himax_chip_common_init(void) if (ret) { E("%s: Unable to register %s input device\n", __func__, ts->input_dev->name); + err = ret; goto err_input_register_device_failed; } @@ -2098,6 +2104,7 @@ int himax_chip_common_init(void) if (himax_common_proc_init()) { E(" %s: himax_common proc_init failed!\n", __func__); + err = -ECANCELED; goto err_creat_proc_file_failed; } diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.c b/drivers/input/touchscreen/hxchipset/himax_platform.c index 1805fa063bfc..c0e75f7f7309 100644 --- a/drivers/input/touchscreen/hxchipset/himax_platform.c +++ b/drivers/input/touchscreen/hxchipset/himax_platform.c @@ -660,7 +660,7 @@ int fb_notifier_callback(struct notifier_block *self, unsigned long event, void case MSM_DRM_BLANK_UNBLANK: if (!ts->initialized) { if (himax_chip_common_init()) - return 0; + return -ECANCELED; ts->initialized = true; } himax_common_resume(&ts->client->dev); -- GitLab From e0e10360344c49f3e051859bc676998e357c2726 Mon Sep 17 00:00:00 2001 From: Vatsal Bucha Date: Fri, 17 Aug 2018 17:34:04 +0530 Subject: [PATCH 0869/1001] ARM: dts: msm: Enable audio for sm6150 external codec Add nodes and change alias name to enable audio on sm6150 external codec. Change-Id: I36ee71949b23217e095d4198407cc7b0585e0f22 Signed-off-by: Vatsal Bucha --- arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi | 2 ++ arch/arm64/boot/dts/qcom/sm6150-ext-codec-audio-overlay.dtsi | 4 ++++ .../arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts | 2 ++ arch/arm64/boot/dts/qcom/sm6150-external-codec.dtsi | 2 +- 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi index ceb3708119d1..b782cad657d3 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi @@ -361,10 +361,12 @@ pinctrl-names = "active", "sleep"; pinctrl-0 = <&wcd934x_mclk_default>; pinctrl-1 = <&wcd934x_mclk_default>; + qcom,use-pinctrl = <1>; qcom,audio-ref-clk-gpio = <&pm6150_gpios 8 0>; clock-names = "osr_clk"; clocks = <&pm6150_clkdiv>; qcom,node_has_rpm_clock; + pmic-clock-names = "pm6150_div_clk1"; #clock-cells = <1>; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-ext-codec-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm6150-ext-codec-audio-overlay.dtsi index 3e2ebda7bd64..fddfc562d0e0 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-ext-codec-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-ext-codec-audio-overlay.dtsi @@ -56,6 +56,10 @@ status = "okay"; }; +&qupv3_se4_spi { + status = "okay"; +}; + &tavil_wdsp { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts index de91a769324e..f57a75449e7a 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts @@ -16,6 +16,8 @@ #include #include "sm6150-idp.dtsi" +#include "sm6150-ext-codec-audio-overlay.dtsi" +#include "sm6150-external-codec.dtsi" / { model = "Qualcomm Technologies, Inc. SM6150 External Audio Codec IDP"; diff --git a/arch/arm64/boot/dts/qcom/sm6150-external-codec.dtsi b/arch/arm64/boot/dts/qcom/sm6150-external-codec.dtsi index c629f08dd587..7bbe80ab99a5 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-external-codec.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-external-codec.dtsi @@ -111,7 +111,7 @@ &slim_aud { status = "okay"; tavil_codec { - swr_tavil: tavil_wsa_swr_master { + swr_tavil: swr_master { compatible = "qcom,swr-mstr"; #address-cells = <2>; #size-cells = <0>; -- GitLab From 871d432d21ed25bc8679511fa2fde2c710425bb6 Mon Sep 17 00:00:00 2001 From: Umang Agrawal Date: Tue, 14 Aug 2018 18:07:46 +0530 Subject: [PATCH 0870/1001] power: smb5: Enable HVDCP and BC 1.2 SRC detection for uUSB config Currently, HVDCP and BC 1.2 SRC detection is disabled by default due to change in APSD flow to execute PD detction flow first. However, micro USB configuration does not support PD capability. Hence, enable HVDCP and BC 1.2 SRC detection and disable PD support for micro USB configuration. Change-Id: I6b0d4bc0d2766992f5083b394677a9a7523b6c29 Signed-off-by: Umang Agrawal --- drivers/power/supply/qcom/qpnp-smb5.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index c83cef17a3cc..733df83cf0c9 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -1589,6 +1589,8 @@ static int smb5_configure_micro_usb(struct smb_charger *chg) { int rc; + chg->pd_not_supported = true; + rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, MICRO_USB_STATE_CHANGE_INT_EN_BIT, MICRO_USB_STATE_CHANGE_INT_EN_BIT); @@ -1598,6 +1600,16 @@ static int smb5_configure_micro_usb(struct smb_charger *chg) return rc; } + /* Enable HVDCP and BC 1.2 source detection */ + rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, + HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, + HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't enable HVDCP detection rc=%d\n", rc); + return rc; + } + return rc; } -- GitLab From a0ec26cfd775c2e00dcdfd41a554410c582d8f6a Mon Sep 17 00:00:00 2001 From: Vicky Wallace Date: Mon, 5 Jun 2017 19:03:25 -0700 Subject: [PATCH 0871/1001] clk: qcom: clk-alpha-pll: Update round rate to use kHz for the divider For the PLL that have 32 bits support for the division ratio. The DIVIDER_ROUND_CLOSEST flag is designed to round the frequency to the closest Hz for the requested rate. However the Fabia PLLs have only 16 bits support for the division ratio. Using the closest rounding flag results in a parent PLL being configured with the rate larger than Fmax. This change solves the issue by allowing the frequency to round to nearest kHz. CRs-Fixed: 2048646 Change-Id: I336945df289e383dea2b831ec8aa24da2aca54c1 Signed-off-by: Vicky Wallace --- drivers/clk/qcom/clk-alpha-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index a67237de137d..eda181fc6219 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -2009,7 +2009,7 @@ static long clk_generic_pll_postdiv_round_rate(struct clk_hw *hw, return -EINVAL; return divider_round_rate(hw, rate, prate, pll->post_div_table, - pll->width, CLK_DIVIDER_ROUND_CLOSEST); + pll->width, CLK_DIVIDER_ROUND_KHZ); } static int clk_generic_pll_postdiv_set_rate(struct clk_hw *hw, -- GitLab From 40dca8462b7a29e697c30b36259100f850cc441a Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Fri, 17 Aug 2018 11:39:17 -0700 Subject: [PATCH 0872/1001] msm: secure_buffer: Increase size of QCOM_SECURE_MEM_SIZE We are seeing cases where QCOM_SECURE_MEM_SIZE is not large enough to hyp unassign large sg lists. This is resulting in memory leaks since we can't return memory which wasn't unassigned back to the kernel. Messages such as the following will be seen in the kernel: get_info_list_from_table: Not enough memory allocated. Increase the size of QCOM_SECURE_MEM_SIZE to 2MB to accommodate these new use cases. In the future we should look into breaking up these sg lists to save memory. Change-Id: Ib30c8d46d8090b1cb7199779512b8e666924f379 Signed-off-by: Liam Mark --- drivers/soc/qcom/secure_buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/secure_buffer.c b/drivers/soc/qcom/secure_buffer.c index 2259a1a0195f..3918a840a01d 100644 --- a/drivers/soc/qcom/secure_buffer.c +++ b/drivers/soc/qcom/secure_buffer.c @@ -56,7 +56,7 @@ struct dest_vm_and_perm_info { }; static void *qcom_secure_mem; -#define QCOM_SECURE_MEM_SIZE (512*1024) +#define QCOM_SECURE_MEM_SIZE (2048*1024) static int secure_buffer_change_chunk(u32 chunks, u32 nchunks, -- GitLab From f5364d1f393e474b4c163d17b2d0e6dfd459e908 Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Thu, 17 May 2018 17:56:01 +0530 Subject: [PATCH 0873/1001] qmp-phy: Power down PHY durng disconnect to avoid leakage Currently driver is not powering down QMP PHY if target is booted up without cable connected. Due to this, 0.3mA leakage current is seen during standby mode if power measured after bootup. Fix this by putting QMP PHY in power down state during disconnect. Change-Id: Idbf7e06ca14649797c50853cf3b9ee182f70749e Signed-off-by: Vijayavardhan Vennapusa --- drivers/usb/phy/phy-msm-ssusb-qmp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c index b57ad1e25f1c..4909c6b52d6e 100644 --- a/drivers/usb/phy/phy-msm-ssusb-qmp.c +++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c @@ -638,6 +638,9 @@ static int msm_ssphy_qmp_set_suspend(struct usb_phy *uphy, int suspend) if (suspend) { if (phy->cable_connected) msm_ssusb_qmp_enable_autonomous(phy, 1); + else + writel_relaxed(0x00, + phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]); /* Make sure above write completed with PHY */ wmb(); -- GitLab From 0c8236f525308e6baf212dc874797d0e5d8b9181 Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Fri, 17 Aug 2018 14:49:45 -0700 Subject: [PATCH 0874/1001] defconfig: Increase SSR notification timeout values Extend timeouts for sysmon communication and subsystem notifier timeouts from 10 seconds to 20 seconds to allow more time for callbacks that may wait for their own events with their own timeouts. Change-Id: I90e6e1e2841dacb858414215b23a9522b84f6346 Signed-off-by: Isaac J. Manjarres --- arch/arm64/configs/vendor/sm8150-perf_defconfig | 2 ++ arch/arm64/configs/vendor/sm8150_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm64/configs/vendor/sm8150-perf_defconfig b/arch/arm64/configs/vendor/sm8150-perf_defconfig index 05575235772f..9598ff49e9cd 100644 --- a/arch/arm64/configs/vendor/sm8150-perf_defconfig +++ b/arch/arm64/configs/vendor/sm8150-perf_defconfig @@ -544,6 +544,8 @@ CONFIG_MSM_PIL=y CONFIG_MSM_SYSMON_QMI_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_SETUP_SSR_NOTIF_TIMEOUTS=y +CONFIG_SSR_SYSMON_NOTIF_TIMEOUT=20000 +CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000 CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y CONFIG_MSM_BOOT_STATS=y CONFIG_QCOM_DCC_V2=y diff --git a/arch/arm64/configs/vendor/sm8150_defconfig b/arch/arm64/configs/vendor/sm8150_defconfig index 0aa1fbe9b52d..086f392ef214 100644 --- a/arch/arm64/configs/vendor/sm8150_defconfig +++ b/arch/arm64/configs/vendor/sm8150_defconfig @@ -568,6 +568,8 @@ CONFIG_MSM_PIL=y CONFIG_MSM_SYSMON_QMI_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_SETUP_SSR_NOTIF_TIMEOUTS=y +CONFIG_SSR_SYSMON_NOTIF_TIMEOUT=20000 +CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000 CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_CORE_HANG_DETECT=y -- GitLab From d93603bd0efbcdb501692522e5c0836732a32ad0 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Fri, 17 Aug 2018 18:16:44 -0700 Subject: [PATCH 0875/1001] leds: qpnp-flash-v2: Fix property names in DT bindings documentation There is a mismatch for the following property names between driver and DT bindings documentation. - qcom,vph-droop-threshold-mv - qcom,vph-droop-hysteresis-mv Fix them. Change-Id: I08da6127be24df666c9c9ced871c34476d68fb32 Signed-off-by: Subbaraman Narayanamurthy --- .../devicetree/bindings/leds/leds-qpnp-flash-v2.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt index 169f848b534d..8728a1bdbc6a 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt @@ -24,11 +24,11 @@ Optional properties: 128, 192. Unit is uS. - qcom,short-circuit-det : Boolean property which enables short circuit fault detection. - qcom,open-circuit-det : Boolean property which enables open circuit fault detection. -- qcom,vph-droop-det : Boolean property which enables VPH droop detection. -- qcom,vph-droop-hys-mv : Integer property to specify VPH droop hysteresis. It is only used if - qcom,vph-droop-det is specified. Valid values are 0, 25, 50 and 75. - Unit is mV. -- qcom,vph-droop-thresh-mv : Integer property to specify VPH droop threshold. It is only used if +- qcom,vph-droop-det : Boolean property which enables VPH droop detection. +- qcom,vph-droop-hysteresis-mv : Integer property to specify VPH droop hysteresis. It is only used if + qcom,vph-droop-det is specified. Valid values are 0, 25, 50 and 75. + Unit is mV. +- qcom,vph-droop-threshold-mv : Integer property to specify VPH droop threshold. It is only used if qcom,vph-droop-det is specified. Valid values are 2500 to 3200 with step size of 100. Unit is mV. - qcom,vph-droop-debounce-us : Integer property to specify VPH droop debounce time. It is only used -- GitLab From aac451504f7ee2ffe7717a305b8b1ba50733f7b1 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Sat, 18 Aug 2018 00:06:58 -0700 Subject: [PATCH 0876/1001] Revert "usb: phy: dual-role: update sysfs attrs when changed" This reverts commit d1263829fb2b1f0ddcbc6887693d89e5228a2526. The previous approach of dynamically updating the writeable permission bits of the power/data_role attributes only works if the userspace application has root permission since the call to sysfs_update_group() removes and re-adds the files. If they had previously been chown/chgrp'ed, the ownership would be reset. On the other hand, if there was a ueventd rule to dynamically update the ownership, then the mode would always be overridden with the static umask given in the ueventd rule, contradicting the driver's determination of writeability. Hence, the more comprehensive fix should be done in userspace to not rely solely on writeability. Still, this change needs to be reverted since it can still cause a race between ueventd and the userspace service trying to check writability. Change-Id: Ic667a97f2bae41e5a86ee45565518b06db959b36 Signed-off-by: Jack Pham --- drivers/usb/phy/class-dual-role.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/usb/phy/class-dual-role.c b/drivers/usb/phy/class-dual-role.c index 9ef889593ef5..51fcb545a9d5 100644 --- a/drivers/usb/phy/class-dual-role.c +++ b/drivers/usb/phy/class-dual-role.c @@ -70,7 +70,15 @@ static char *kstrdupcase(const char *str, gfp_t gfp, bool to_upper) return ret; } -static void dual_role_changed_work(struct work_struct *work); +static void dual_role_changed_work(struct work_struct *work) +{ + struct dual_role_phy_instance *dual_role = + container_of(work, struct dual_role_phy_instance, + changed_work); + + dev_dbg(&dual_role->dev, "%s\n", __func__); + kobject_uevent(&dual_role->dev.kobj, KOBJ_CHANGE); +} void dual_role_instance_changed(struct dual_role_phy_instance *dual_role) { @@ -497,17 +505,6 @@ int dual_role_uevent(struct device *dev, struct kobj_uevent_env *env) return ret; } -static void dual_role_changed_work(struct work_struct *work) -{ - struct dual_role_phy_instance *dual_role = - container_of(work, struct dual_role_phy_instance, - changed_work); - - dev_dbg(&dual_role->dev, "%s\n", __func__); - sysfs_update_group(&dual_role->dev.kobj, &dual_role_attr_group); - kobject_uevent(&dual_role->dev.kobj, KOBJ_CHANGE); -} - /******************* Module Init ***********************************/ static int __init dual_role_class_init(void) -- GitLab From e2da6ba4cc9504512448d70939f5482731017ae3 Mon Sep 17 00:00:00 2001 From: Vatsal Bucha Date: Fri, 3 Aug 2018 18:09:45 +0530 Subject: [PATCH 0877/1001] defconfig: sdmsteppe: Enable compilation of regmap irq for steppe REGMAP IRQ framework is used for steppe. Enable compilation so as to resolve any unknown symbol errors. CRs-Fixed: 2286582 Change-Id: I900efb7b1b9f92aab74672b521eefe469cfc8e12 Signed-off-by: Vatsal Bucha --- arch/arm64/configs/vendor/sdmsteppe-perf_defconfig | 1 + arch/arm64/configs/vendor/sdmsteppe_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig index 07d72a730f9b..fc16fd48e145 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig @@ -235,6 +235,7 @@ CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y CONFIG_NFC_NQ=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_WCD_IRQ=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y CONFIG_ZRAM=y diff --git a/arch/arm64/configs/vendor/sdmsteppe_defconfig b/arch/arm64/configs/vendor/sdmsteppe_defconfig index 9de205387285..c5840cca2ed7 100644 --- a/arch/arm64/configs/vendor/sdmsteppe_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe_defconfig @@ -242,6 +242,7 @@ CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y CONFIG_NFC_NQ=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_WCD_IRQ=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y CONFIG_ZRAM=y -- GitLab From 7503148a96336a07c8cf772c796b183e48def609 Mon Sep 17 00:00:00 2001 From: Hareesh Gundu Date: Wed, 15 Aug 2018 00:39:24 +0530 Subject: [PATCH 0878/1001] Revert "msm: kgsl: Enable preemption for A608 GPU" This reverts commit '8a7969094927cfedd2e6bf7077ea7c1cdd7538af' to fix the gpu fault issue. Change-Id: Idb323531ec8546a895b50fbf94c56ec4a0ba3bed Signed-off-by: Hareesh Gundu --- drivers/gpu/msm/adreno-gpulist.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h index d92b482b36f0..0fb5b9f5381d 100644 --- a/drivers/gpu/msm/adreno-gpulist.h +++ b/drivers/gpu/msm/adreno-gpulist.h @@ -448,8 +448,7 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .major = 0, .minor = 8, .patchid = ANY_ID, - .features = ADRENO_64BIT | ADRENO_CONTENT_PROTECTION | - ADRENO_PREEMPTION, + .features = ADRENO_64BIT | ADRENO_CONTENT_PROTECTION, .sqefw_name = "a630_sqe.fw", .zap_name = "a608_zap", .gpudev = &adreno_a6xx_gpudev, -- GitLab From d867104f53123b10502700c402cf049613c6dc9e Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Sun, 19 Aug 2018 02:05:14 +0530 Subject: [PATCH 0879/1001] msm: ipa3: Disable filter and route table hashing in IPA 4.2 HW In IPA 4.2 HW filter and route table hashing not supported. Added changes to configure filter/route hashing disable. Change-Id: I55f4340f52a45cd4c78112ff95ead6564c935c79 Acked-by: Ashok Vuyyuru Signed-off-by: Mohammed Javid --- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 23 +++++++++++++++++++ .../msm/ipa/ipa_v3/ipahal/ipahal_reg.c | 4 ++++ .../msm/ipa/ipa_v3/ipahal/ipahal_reg.h | 1 + 3 files changed, 28 insertions(+) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index f62a320f105a..57dec8be0829 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -70,6 +70,7 @@ #define IPA_EOT_COAL_GRAN_MIN (1) #define IPA_EOT_COAL_GRAN_MAX (16) +#define IPA_FILT_ROUT_HASH_REG_VAL_v4_2 (0x00000000) #define IPA_DMA_TASK_FOR_GSI_TIMEOUT_MSEC (15) #define IPA_AGGR_BYTE_LIMIT (\ @@ -3116,6 +3117,21 @@ int ipa3_cfg_filter(u32 disable) return -EPERM; } +/** + * ipa_disable_hashing_rt_flt_v4_2() - Disable filer and route hashing. + * + * Return codes: 0 for success, negative value for failure + */ +static int ipa_disable_hashing_rt_flt_v4_2(void) +{ + + IPADBG("Disable hashing for filter and route table in IPA 4.2 HW\n"); + ipahal_write_reg(IPA_FILT_ROUT_HASH_EN, + IPA_FILT_ROUT_HASH_REG_VAL_v4_2); + return 0; +} + + /** * ipa_comp_cfg() - Configure QMB/Master port selection * @@ -3273,6 +3289,13 @@ int ipa3_init_hw(void) ipa_comp_cfg(); + /* + * In IPA 4.2 filter and routing hashing not supported + * disabling hash enable register. + */ + if (ipa3_ctx->ipa_fltrt_not_hashable) + ipa_disable_hashing_rt_flt_v4_2(); + return 0; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c index 1848c091b3cf..0c44e03265bc 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c @@ -87,6 +87,7 @@ static const char *ipareg_name_to_str[IPA_REG_MAX] = { __stringify(IPA_DEBUG_CNT_CTRL_n), __stringify(IPA_UC_MAILBOX_m_n), __stringify(IPA_FILT_ROUT_HASH_FLUSH), + __stringify(IPA_FILT_ROUT_HASH_EN), __stringify(IPA_SINGLE_NDP_MODE), __stringify(IPA_QCNCM), __stringify(IPA_SYS_PKT_PROC_CNTXT_BASE), @@ -2501,6 +2502,9 @@ static struct ipahal_reg_obj ipahal_reg_objs[IPA_HW_MAX][IPA_REG_MAX] = { [IPA_HW_v4_2][IPA_HPS_FTCH_ARB_QUEUE_WEIGHT] = { ipareg_construct_dummy, ipareg_parse_dummy, -1, 0, 0, 0, 0}, + [IPA_HW_v4_2][IPA_FILT_ROUT_HASH_EN] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00000148, 0, 0, 0, 0}, /* IPA4.5 */ [IPA_HW_v4_5][IPA_SRC_RSRC_GRP_01_RSRC_TYPE_n] = { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h index ba3cf29f1854..749d55b5571b 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h @@ -88,6 +88,7 @@ enum ipahal_reg_name { IPA_DEBUG_CNT_CTRL_n, IPA_UC_MAILBOX_m_n, IPA_FILT_ROUT_HASH_FLUSH, + IPA_FILT_ROUT_HASH_EN, IPA_SINGLE_NDP_MODE, IPA_QCNCM, IPA_SYS_PKT_PROC_CNTXT_BASE, -- GitLab From b37245fb5a6e370798b4651ac2b8e05d31908e16 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Thu, 16 Aug 2018 20:30:57 +0530 Subject: [PATCH 0880/1001] ARM: dts: msm: Add missing ctis for SM6150 Add missing ctis: coresight-cti-dlct_cti0 coresight-cti-dlct_cti1 coresight-cti-ddr_dl_0_cti0 coresight-cti-ddr_dl_0_cti1 coresight-cti-ddr_dl_1_cti0 coresight-cti-ddr_dl_1_cti1 Change-Id: Iced2b0a8e33850fd5cf4c1459ad3fb548ee4bde4 Signed-off-by: Mao Jinlong --- .../arm64/boot/dts/qcom/sm6150-coresight.dtsi | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi b/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi index fd4535df0c8a..806ce412c549 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi @@ -1356,6 +1356,78 @@ }; }; + cti0_dlct: cti@6c29000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c29000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlct: cti@6c2a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c2a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr0: cti@6a02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a02000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr0: cti@6a03000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a03000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr1: cti@6a10000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a10000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr1: cti@6a11000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a11000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + cti_mss_q6: cti@683b000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b966>; -- GitLab From 60866308a60759c87a496155ae8304c6b303826a Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Thu, 16 Aug 2018 20:46:07 +0530 Subject: [PATCH 0881/1001] ARM: dts: msm: Add wcss tpdm for SM6150 Add wcss tpdm to support wcss hardware event. Change-Id: Id87e8e2a53354625cd5e1fdd7528fb7db1f26080 Signed-off-by: Mao Jinlong --- .../arm64/boot/dts/qcom/sm6150-coresight.dtsi | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi b/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi index 806ce412c549..6f9c9fcf93bd 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi @@ -442,6 +442,19 @@ }; }; + tpdm_wcss: tpdm@699c000 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-tpdm-wcss"; + qcom,dummy-source; + + port { + tpdm_wcss_out_funnel_in1: endpoint { + remote-endpoint = <&funnel_in1_in_tpdm_wcss>; + }; + }; + }; + tpdm_west: tpdm@6b48000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b968>; @@ -1017,11 +1030,20 @@ }; port@2 { + reg = <4>; + funnel_in1_in_tpdm_wcss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_wcss_out_funnel_in1>; + }; + }; + + port@3 { reg = <7>; funnel_in1_in_funnel_apss_merg: endpoint { slave-mode; remote-endpoint = - <&funnel_apss_merg_out_funnel_in1>; + <&funnel_apss_merg_out_funnel_in1>; }; }; }; -- GitLab From 7e54c5648ee4c0ff36498967c3013a2b334b8cee Mon Sep 17 00:00:00 2001 From: Sushmita Susheelendra Date: Tue, 29 May 2018 14:19:47 -0600 Subject: [PATCH 0882/1001] msm: kgsl: Record the cacheability attribute of ion buffers Query whether an ion buffer is cached using the dmabuf API dma_buf_get_flags. Record this information in the memdesc so that any cache operations requested on the ion buffer can be honored. Change-Id: Ie763047260108a8b5b2073b60d7a6e51408ae543 Signed-off-by: Sushmita Susheelendra --- drivers/gpu/msm/kgsl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index e40c91a01742..2ef9b45c3e8d 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -2352,6 +2353,7 @@ static long _gpuobj_map_dma_buf(struct kgsl_device *device, { struct kgsl_gpuobj_import_dma_buf buf; struct dma_buf *dmabuf; + unsigned long flags = 0; int ret; /* @@ -2382,6 +2384,16 @@ static long _gpuobj_map_dma_buf(struct kgsl_device *device, if (IS_ERR_OR_NULL(dmabuf)) return (dmabuf == NULL) ? -EINVAL : PTR_ERR(dmabuf); + /* + * ION cache ops are routed through kgsl, so record if the dmabuf is + * cached or not in the memdesc. Assume uncached if dma_buf_get_flags + * fails. + */ + dma_buf_get_flags(dmabuf, &flags); + if (flags & ION_FLAG_CACHED) + entry->memdesc.flags |= + KGSL_CACHEMODE_WRITEBACK << KGSL_CACHEMODE_SHIFT; + ret = kgsl_setup_dma_buf(device, pagetable, entry, dmabuf); if (ret) dma_buf_put(dmabuf); -- GitLab From fae3ae27349bd2fd0b6458314882ab114be0a497 Mon Sep 17 00:00:00 2001 From: Mohamed Sunfeer Date: Mon, 20 Aug 2018 11:21:30 +0530 Subject: [PATCH 0883/1001] sdmsteppe_defconfig: Enable the smcinvoke driver Enable the Smcinvoke driver for sm6150 target. Change-Id: I7d881f03b4babea8ce13dba92ac38fbb602059dc Signed-off-by: Mohamed Sunfeer --- arch/arm64/configs/vendor/sdmsteppe_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/vendor/sdmsteppe_defconfig b/arch/arm64/configs/vendor/sdmsteppe_defconfig index 9de205387285..86c1db5adde9 100644 --- a/arch/arm64/configs/vendor/sdmsteppe_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe_defconfig @@ -558,6 +558,7 @@ CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_PM=y CONFIG_QCOM_FSA4480_I2C=y -- GitLab From d3947e68b4c902a911afc34d2f0c39a4808c348c Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Mon, 20 Aug 2018 11:20:53 +0530 Subject: [PATCH 0884/1001] ARM: dts: msm: add physical dimension for hx83112a truly panel Add physical dimension property for hx83112a truly panel. These values will be used to calculate display DPI. Change-Id: I82858ad65049c6988d2a4622d179c5124dc65d72 Signed-off-by: Sandeep Panda --- .../dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi index e065f002395f..817b26fe1da2 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi @@ -43,6 +43,8 @@ qcom,mdss-dsi-bl-min-level = <1>; qcom,mdss-dsi-bl-max-level = <4095>; qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <65>; + qcom,mdss-pan-physical-height-dimension = <129>; qcom,mdss-dsi-display-timings { timing@0 { -- GitLab From d2cac9a8d98e2eb89c4ebed8b207fcca046d76c8 Mon Sep 17 00:00:00 2001 From: Mohamed Sunfeer Date: Mon, 20 Aug 2018 11:36:10 +0530 Subject: [PATCH 0885/1001] qcs405_defconfig: Enable the Qseecom and tzlog driver Enable the qseecom driver to communicate with TZ and enable the Tzlog driver to capture the tz diag area for qcs405 target. Change-Id: If368d316359485e95a45539ed835fd2b7ad53afc Signed-off-by: Mohamed Sunfeer --- arch/arm64/configs/vendor/qcs405_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/configs/vendor/qcs405_defconfig b/arch/arm64/configs/vendor/qcs405_defconfig index 1065afba523c..405ebbad24bf 100644 --- a/arch/arm64/configs/vendor/qcs405_defconfig +++ b/arch/arm64/configs/vendor/qcs405_defconfig @@ -208,6 +208,7 @@ CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_QPNP_MISC=y CONFIG_SCSI=y @@ -463,6 +464,7 @@ CONFIG_QCOM_KGSL=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_MSM_TZ_LOG=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y -- GitLab From b1d5575829cb5178d75722fe66a79d1a661cec51 Mon Sep 17 00:00:00 2001 From: Vijayanand Jitta Date: Mon, 20 Aug 2018 11:48:00 +0530 Subject: [PATCH 0886/1001] ARM: dts: msm: Disable ATOS feature for smmu for sm6150 Due to HW errata on the eCATS functionality, doing TBU halt while data traffic is in progress can cause a system hang. Disabling ATOS/eCATS is the only way of working around this errata. Change-Id: Ie668d7d2a0b7473048a5070bb87d4065d35e1c25 Signed-off-by: Vijayanand Jitta --- arch/arm64/boot/dts/qcom/msm-arm-smmu-sm6150.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm6150.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm6150.dtsi index 3f224c133e65..f6eafeea4ee2 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm6150.dtsi @@ -23,6 +23,7 @@ qcom,dynamic; qcom,skip-init; qcom,use-3-lvl-tables; + qcom,disable-atos; #global-interrupts = <1>; qcom,regulator-names = "vdd"; vdd-supply = <&gpu_cx_gdsc>; @@ -70,6 +71,7 @@ #iommu-cells = <2>; qcom,skip-init; qcom,use-3-lvl-tables; + qcom,disable-atos; #global-interrupts = <1>; #size-cells = <1>; #address-cells = <1>; -- GitLab From 964428d1b0f4c2a2bd2350d112d91fb795df070c Mon Sep 17 00:00:00 2001 From: Monika Singh Date: Mon, 20 Aug 2018 15:53:23 +0530 Subject: [PATCH 0887/1001] Documentation: bindings: Add node details for VB Add reference for Verified boot node to support system properties. Change-Id: Ibef29e92ded50ec34c1fb88a2c81d216b29f3c0f Signed-off-by: Monika Singh --- .../devicetree/bindings/firmware/qcom,scm.txt | 25 +++++++++++++++++++ .../devicetree/bindings/vendor-prefixes.txt | 1 + 2 files changed, 26 insertions(+) diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.txt b/Documentation/devicetree/bindings/firmware/qcom,scm.txt index 20f26fbce875..cd091b99e4e0 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.txt +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.txt @@ -12,6 +12,8 @@ Required properties: * "qcom,scm-msm8690" for MSM8690 platforms * "qcom,scm-msm8996" for MSM8996 platforms * "qcom,scm" for later processors (MSM8916, APQ8084, MSM8974, etc) + * "android,firmware" for firmware image + * "android,vbmeta" for setting system properties for verified boot. - clocks: One to three clocks may be required based on compatible. * No clock required for "qcom,scm-msm8996" * Only core clock required for "qcom,scm-apq8064", "qcom,scm-msm8660", and "qcom,scm-msm8960" @@ -28,3 +30,26 @@ Example for MSM8916: clock-names = "core", "bus", "iface"; }; }; + +Example for SM6150: + +firmware: firmware { + android { + compatible = "android,firmware"; + vbmeta { + compatible = "android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo"; + }; + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/1d84000.ufshc/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect,avb"; + status = "ok"; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 23224632812c..caa4fc38898e 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -28,6 +28,7 @@ amstaos AMS-Taos Inc. android Google Inc. analogix Analogix Semiconductor, Inc. andestech Andes Technology Corporation +android Google apm Applied Micro Circuits Corporation (APM) aptina Aptina Imaging arasan Arasan Chip Systems -- GitLab From 0f07a9533e3bd6d62602da66e1a19cd6d7ae615d Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Mon, 20 Aug 2018 19:08:53 +0530 Subject: [PATCH 0888/1001] sched: walt: Remove unused last_switch_out_ts member from task_struct last_switch_out_ts member in task_struct is not used. So remove it. Change-Id: I7f088f1ee86fa61d3ce88646734866dd7ed2bfe2 Signed-off-by: Pavankumar Kondeti --- include/linux/sched.h | 1 - kernel/sched/walt.c | 1 - 2 files changed, 2 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 01a2d42d5589..2c23d8c57f79 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -782,7 +782,6 @@ struct task_struct { */ u32 init_load_pct; u64 last_wake_ts; - u64 last_switch_out_ts; u64 last_enqueued_ts; struct related_thread_group *grp; struct list_head grp_list; diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index b1804c966a10..ae2a73b317c2 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -2041,7 +2041,6 @@ void mark_task_starting(struct task_struct *p) wallclock = ktime_get_ns(); p->ravg.mark_start = p->last_wake_ts = wallclock; p->last_enqueued_ts = wallclock; - p->last_switch_out_ts = 0; update_task_cpu_cycles(p, cpu_of(rq), wallclock); } -- GitLab From 5b66c5f464d942af73206b5d15fd310587c68f16 Mon Sep 17 00:00:00 2001 From: Raviteja Tamatam Date: Mon, 20 Aug 2018 18:09:51 +0530 Subject: [PATCH 0889/1001] ARM: dts: msm: enable dynamic fps for SM6150 Enabling dynamic fps for hx83112a truly dsi video panels on SM6150. The feature helps to reduce fps when static screen leading to power saving. Change-Id: I719d809997067492c1130e95fc099d8fb22b3bba Signed-off-by: Raviteja Tamatam --- arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi index 27650846bc01..907029a15dcb 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi @@ -239,6 +239,11 @@ &dsi_hx83112a_truly_video { qcom,mdss-dsi-t-clk-post = <0x0e>; qcom,mdss-dsi-t-clk-pre = <0x31>; + qcom,mdss-dsi-min-refresh-rate = <53>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = + "dfps_immediate_porch_mode_vfp"; qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = -- GitLab From a8721e28744d85d4b396eacfaf81b96da53df1c5 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Mon, 28 May 2018 14:46:44 +0530 Subject: [PATCH 0890/1001] msm: ipa4: Update the missing config on sdx24 Couple of missing config changes on sdx24 with respect to EE_n_GSI_CH_k_QOS register, - USE_DB_ENG starting from sdx24, since there is no smart prefetch in MCS, this field should be 0 (for direct mode) for all channels, except for MHI with burst mode enabled. - MAX_PREFETCH This should be 0 (i.e, one prefetch buffer) - WRR_WEIGHT Software configurable, already taken care. - ESCAPE_BUFFER_ONLY update as per ep config excel. Change-Id: Ib464f5b475f843ed0f913f737a1fe6f046969fc1 Signed-off-by: Mohammed Javid --- .../platform/msm/ipa/ipa_clients/ipa_usb.c | 5 +- drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 12 +++- drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c | 20 +++++-- drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c | 1 + drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 56 +++++++++---------- 5 files changed, 59 insertions(+), 35 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c index be0032ccb21c..73369ed2fc63 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c @@ -1330,7 +1330,10 @@ static int ipa3_usb_request_xdci_channel( chan_params.chan_params.ring_base_addr = params->xfer_ring_base_addr_iova; chan_params.chan_params.ring_base_vaddr = NULL; - chan_params.chan_params.use_db_eng = GSI_CHAN_DB_MODE; + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) + chan_params.chan_params.use_db_eng = GSI_CHAN_DIRECT_MODE; + else + chan_params.chan_params.use_db_eng = GSI_CHAN_DB_MODE; chan_params.chan_params.max_prefetch = GSI_ONE_PREFETCH_SEG; if (params->dir == GSI_CHAN_DIR_FROM_GSI) chan_params.chan_params.low_weight = diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 8873c4fa39d3..f06fec9788a6 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -3813,7 +3813,10 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in, ep->gsi_mem_info.chan_ring_base_vaddr = gsi_channel_props.ring_base_vaddr; - gsi_channel_props.use_db_eng = GSI_CHAN_DB_MODE; + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) + gsi_channel_props.use_db_eng = GSI_CHAN_DIRECT_MODE; + else + gsi_channel_props.use_db_eng = GSI_CHAN_DB_MODE; gsi_channel_props.max_prefetch = GSI_ONE_PREFETCH_SEG; if (ep->client == IPA_CLIENT_APPS_CMD_PROD) gsi_channel_props.low_weight = IPA_GSI_MAX_CH_LOW_WEIGHT; @@ -4112,7 +4115,12 @@ int ipa_gsi_ch20_wa(void) dma_alloc_coherent(ipa3_ctx->pdev, gsi_channel_props.ring_len, &dma_addr, 0); gsi_channel_props.ring_base_addr = dma_addr; - gsi_channel_props.use_db_eng = GSI_CHAN_DB_MODE; + + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) + gsi_channel_props.use_db_eng = GSI_CHAN_DIRECT_MODE; + else + gsi_channel_props.use_db_eng = GSI_CHAN_DB_MODE; + gsi_channel_props.max_prefetch = GSI_ONE_PREFETCH_SEG; gsi_channel_props.low_weight = 1; gsi_channel_props.err_cb = ipa_gsi_chan_err_cb; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c index 0f472bec575a..779047815adb 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c @@ -199,6 +199,7 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, struct ipa3_ep_context *ep; const struct ipa_gsi_ep_config *ep_cfg; struct ipa_ep_cfg_ctrl ep_cfg_ctrl; + bool burst_mode_enabled = false; IPA_MHI_FUNC_ENTRY(); @@ -281,7 +282,18 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, ch_props.ring_len = params->ch_ctx_host->rlen; ch_props.ring_base_addr = IPA_MHI_HOST_ADDR_COND( params->ch_ctx_host->rbase); - ch_props.use_db_eng = GSI_CHAN_DB_MODE; + + if (params->ch_ctx_host->brstmode == IPA_MHI_BURST_MODE_DEFAULT || + params->ch_ctx_host->brstmode == IPA_MHI_BURST_MODE_ENABLE) { + burst_mode_enabled = true; + } + + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0 && + !burst_mode_enabled) + ch_props.use_db_eng = GSI_CHAN_DIRECT_MODE; + else + ch_props.use_db_eng = GSI_CHAN_DB_MODE; + ch_props.max_prefetch = GSI_ONE_PREFETCH_SEG; ch_props.low_weight = 1; ch_props.prefetch_mode = ep_cfg->prefetch_mode; @@ -315,9 +327,9 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, min(ep_cfg->ipa_if_tlv / 2, 8) * ch_props.re_size; } ch_scratch.mhi.oob_mod_threshold = 4; - if (params->ch_ctx_host->brstmode == IPA_MHI_BURST_MODE_DEFAULT || - params->ch_ctx_host->brstmode == IPA_MHI_BURST_MODE_ENABLE) { - ch_scratch.mhi.burst_mode_enabled = true; + + if (burst_mode_enabled) { + ch_scratch.mhi.burst_mode_enabled = burst_mode_enabled; ch_scratch.mhi.polling_configuration = ipa3_mhi_get_ch_poll_cfg(client, params->ch_ctx_host, (ch_props.ring_len / ch_props.re_size)); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c index e36e5fc8da0f..cd703e200915 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c @@ -935,6 +935,7 @@ static int ipa3_wdi2_gsi_alloc_channel_ring( channel_props->use_db_eng = GSI_CHAN_DB_MODE; channel_props->max_prefetch = GSI_ONE_PREFETCH_SEG; + channel_props->prefetch_mode = ep_cfg->prefetch_mode; channel_props->low_weight = 1; channel_props->err_cb = ipa_gsi_chan_err_cb; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index aff53df36774..0e6a203a8ec8 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -1872,80 +1872,80 @@ static const struct ipa_ep_configuration ipa3_ep_mapping true, IPA_DPS_HPS_REP_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP_DMAP, QMB_MASTER_SELECT_DDR, - { 3, 7, 6, 7, IPA_EE_AP } }, + { 3, 7, 6, 7, IPA_EE_AP, GSI_USE_PREFETCH_BUFS} }, [IPA_4_2][IPA_CLIENT_USB_PROD] = { true, IPA_v4_2_GROUP_UL_DL, true, IPA_DPS_HPS_REP_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP_DMAP, QMB_MASTER_SELECT_DDR, - { 0, 5, 8, 9, IPA_EE_AP } }, + { 0, 5, 8, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_APPS_LAN_PROD] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP, QMB_MASTER_SELECT_DDR, - { 2, 6, 8, 9, IPA_EE_AP } }, + { 2, 6, 8, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_APPS_WAN_PROD] = { true, IPA_v4_2_GROUP_UL_DL, true, IPA_DPS_HPS_REP_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP_DMAP, QMB_MASTER_SELECT_DDR, - { 1, 0, 8, 12, IPA_EE_AP } }, + { 1, 0, 8, 12, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_APPS_CMD_PROD] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY, QMB_MASTER_SELECT_DDR, - { 6, 1, 20, 20, IPA_EE_AP } }, + { 6, 1, 20, 20, IPA_EE_AP, GSI_USE_PREFETCH_BUFS} }, [IPA_4_2][IPA_CLIENT_Q6_WAN_PROD] = { true, IPA_v4_2_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP, QMB_MASTER_SELECT_DDR, - { 4, 0, 8, 12, IPA_EE_Q6 } }, + { 4, 0, 8, 12, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS} }, [IPA_4_2][IPA_CLIENT_Q6_CMD_PROD] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP, QMB_MASTER_SELECT_DDR, - { 5, 1, 20, 20, IPA_EE_Q6 } }, + { 5, 1, 20, 20, IPA_EE_Q6, GSI_USE_PREFETCH_BUFS} }, [IPA_4_2][IPA_CLIENT_ETHERNET_PROD] = { true, IPA_v4_2_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP, QMB_MASTER_SELECT_DDR, - { 7, 0, 8, 10, IPA_EE_UC } }, + { 7, 0, 8, 10, IPA_EE_UC, GSI_USE_PREFETCH_BUFS} }, /* Only for test purpose */ [IPA_4_2][IPA_CLIENT_TEST_PROD] = { true, IPA_v4_2_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP, QMB_MASTER_SELECT_DDR, - {0, 5, 8, 9, IPA_EE_AP } }, + {0, 5, 8, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_TEST1_PROD] = { true, IPA_v4_2_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP, QMB_MASTER_SELECT_DDR, - { 0, 5, 8, 9, IPA_EE_AP } }, + { 0, 5, 8, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_TEST2_PROD] = { true, IPA_v4_2_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP, QMB_MASTER_SELECT_DDR, - { 3, 7, 6, 7, IPA_EE_AP } }, + { 3, 7, 6, 7, IPA_EE_AP, GSI_USE_PREFETCH_BUFS} }, [IPA_4_2][IPA_CLIENT_TEST3_PROD] = { true, IPA_v4_2_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP, QMB_MASTER_SELECT_DDR, - {1, 0, 8, 12, IPA_EE_AP } }, + {1, 0, 8, 12, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_TEST4_PROD] = { true, IPA_v4_2_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_NO_UCP, QMB_MASTER_SELECT_DDR, - { 7, 10, 8, 10, IPA_EE_AP } }, + { 7, 0, 8, 10, IPA_EE_AP, GSI_USE_PREFETCH_BUFS} }, [IPA_4_2][IPA_CLIENT_WLAN1_CONS] = { @@ -1953,55 +1953,55 @@ static const struct ipa_ep_configuration ipa3_ep_mapping false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 14, 8, 6, 9, IPA_EE_AP } }, + { 14, 8, 6, 9, IPA_EE_AP, GSI_USE_PREFETCH_BUFS} }, [IPA_4_2][IPA_CLIENT_USB_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 15, 9, 6, 6, IPA_EE_AP } }, + { 15, 9, 6, 6, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_USB_DPL_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 12, 4, 4, 4, IPA_EE_AP } }, + { 12, 4, 4, 4, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_APPS_LAN_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 8, 2, 6, 6, IPA_EE_AP } }, + { 8, 2, 6, 6, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_APPS_WAN_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 9, 3, 6, 6, IPA_EE_AP } }, + { 9, 3, 6, 6, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_Q6_LAN_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 11, 3, 6, 6, IPA_EE_Q6 } }, + { 11, 3, 6, 6, IPA_EE_Q6, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_Q6_WAN_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 10, 2, 6, 6, IPA_EE_Q6 } }, + { 10, 2, 6, 6, IPA_EE_Q6, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 13, 4, 6, 6, IPA_EE_Q6 } }, + { 13, 4, 6, 6, IPA_EE_Q6, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_ETHERNET_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 16, 1, 6, 6, IPA_EE_UC } }, + { 16, 1, 6, 6, IPA_EE_UC, GSI_USE_PREFETCH_BUFS} }, /* Only for test purpose */ /* MBIM aggregation test pipes should have the same QMB as USB_CONS */ [IPA_4_2][IPA_CLIENT_TEST_CONS] = { @@ -2009,38 +2009,38 @@ static const struct ipa_ep_configuration ipa3_ep_mapping false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 15, 9, 6, 6, IPA_EE_AP } }, + { 15, 9, 6, 6, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_TEST1_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 15, 9, 6, 6, IPA_EE_AP } }, + { 15, 9, 6, 6, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_TEST2_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 12, 4, 4, 4, IPA_EE_AP } }, + { 12, 4, 4, 4, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, [IPA_4_2][IPA_CLIENT_TEST3_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 14, 8, 6, 9, IPA_EE_AP } }, + { 14, 8, 6, 9, IPA_EE_AP, GSI_USE_PREFETCH_BUFS} }, [IPA_4_2][IPA_CLIENT_TEST4_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 9, 3, 6, 6, IPA_EE_AP } }, + { 9, 3, 6, 6, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY} }, /* Dummy consumer (pipe 31) is used in L2TP rt rule */ [IPA_4_2][IPA_CLIENT_DUMMY_CONS] = { true, IPA_v4_2_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, - { 31, 31, 8, 8, IPA_EE_AP } }, + { 31, 31, 8, 8, IPA_EE_AP, GSI_USE_PREFETCH_BUFS} }, /* IPA_4_5 */ [IPA_4_5][IPA_CLIENT_WLAN1_PROD] = { -- GitLab From 897900e08037f683eda43ae05fe4f1123bcc2f7e Mon Sep 17 00:00:00 2001 From: Kyle Piefer Date: Wed, 27 Jun 2018 16:01:41 -0700 Subject: [PATCH 0891/1001] Revert "msm: kgsl: Prevent dual ownership of GMU counters" The GMU firmware team does not currently use the counters that are reserved for them, so they are allowing them to be reclaimed by KGSL for the purpose of monitoring the throttled clock cycles. This reverts commit 9d57d42d4ed99649aded636977a46735d2393575. Change-Id: I15e75f77188e91ecdbcf1ea1e2458d1f65122dfb Signed-off-by: Kyle Piefer --- drivers/gpu/msm/adreno_a6xx.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 4f7745d1f113..8c6ca7c9e0b2 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -2546,17 +2546,11 @@ static struct adreno_perfcount_register a6xx_pwrcounters_gpmu[] = { A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_3_L, A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_3_H, -1, A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, }, - /* - * Both A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4 and - * A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5 are owned - * by the GMU. Mark them as broken so there is no - * dual ownership. - */ - { KGSL_PERFCOUNTER_BROKEN, 0, 0, + { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_L, A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_H, -1, A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, }, - { KGSL_PERFCOUNTER_BROKEN, 0, 0, + { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_L, A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_H, -1, A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, }, -- GitLab From a89cab3e3cecfc88eb35dedc545b23ac8a38fd15 Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Mon, 6 Aug 2018 11:54:40 -0700 Subject: [PATCH 0892/1001] mhi: controller: qcom: fix unbalance runtime enable counts A bug in MHI system suspend function caused the function to exit prematurely without disabling runtime suspend. The subsequent runtime resume caused unbalance enable count. CRs-Fixed: 2291885 Change-Id: I9f45a86fff2caf4ba13236677d1325e7093a1947 Signed-off-by: Sujeev Dias --- drivers/bus/mhi/controllers/mhi_qcom.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/bus/mhi/controllers/mhi_qcom.c b/drivers/bus/mhi/controllers/mhi_qcom.c index 84dbbd72a867..32060a9f96fc 100644 --- a/drivers/bus/mhi/controllers/mhi_qcom.c +++ b/drivers/bus/mhi/controllers/mhi_qcom.c @@ -257,12 +257,18 @@ static int mhi_system_resume(struct device *dev) int mhi_system_suspend(struct device *dev) { struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev); + int ret; MHI_LOG("Entered\n"); /* if rpm status still active then force suspend */ - if (!pm_runtime_status_suspended(dev)) - return mhi_runtime_suspend(dev); + if (!pm_runtime_status_suspended(dev)) { + ret = mhi_runtime_suspend(dev); + if (ret) { + MHI_LOG("suspend failed ret:%d\n", ret); + return ret; + } + } pm_runtime_set_suspended(dev); pm_runtime_disable(dev); -- GitLab From 1a12ee05e1199be84665219d650c9fa26d15fbba Mon Sep 17 00:00:00 2001 From: Urvashi Agrawal Date: Mon, 6 Aug 2018 09:44:12 -0700 Subject: [PATCH 0893/1001] msm: kgsl: Don't pad VA allocations on sm8150v2 sm8150v2 does not require VA allocations to be padded up. Remove the VA padding requirement on this device. Change-Id: Ibdafa78abe8a6fe0ab87d1d31af3cfc7874d25fc Signed-off-by: Urvashi Agrawal --- drivers/gpu/msm/adreno-gpulist.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h index d92b482b36f0..f3813cb7f8c6 100644 --- a/drivers/gpu/msm/adreno-gpulist.h +++ b/drivers/gpu/msm/adreno-gpulist.h @@ -421,7 +421,6 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .gpmu_minor = 0x000, .gpmu_tsens = 0x000C000D, .max_power = 5448, - .va_padding = SZ_64K, }, { .gpurev = ADRENO_REV_A680, -- GitLab From 096d8277a3b2ece6d74f02d6b960d776f83c03b7 Mon Sep 17 00:00:00 2001 From: Sudarshan Rajagopalan Date: Mon, 20 Aug 2018 15:34:25 -0700 Subject: [PATCH 0894/1001] iommu: arm-smmu: Allow TBUs to opt-out from halting Halting certain TBUs would cause considerable impact to the system such as introducing HW deadlocks on demand. Such TBUs should not participate in being halted for any atos debugging or power collapse features. Allow such TBUs to be opted-out. Change-Id: I5ae3d72d0b2536fd4e909b556361236bae282163 Signed-off-by: Sudarshan Rajagopalan --- Documentation/devicetree/bindings/iommu/arm,smmu.txt | 6 ++++++ drivers/iommu/arm-smmu.c | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index 04faf3cf51ea..5c85a63f9164 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -117,6 +117,12 @@ conditions. Some hardware may not have full support for atos debugging in tandem with other features like power collapse. +-qcom,opt-out-tbu-halting: + Allow certain TBUs to opt-out from being halted for the + ATOS operation to proceed. Halting certain TBUs would cause + considerable impact to the system such as deadlocks on demand. + Such TBUs can be opted out to be halted from software. + - qcom,deferred-regulator-disable-delay : The time delay for deferred regulator disable in ms. In case of unmap call, regulator is enabled/disabled. This may introduce additional delay. For diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 4ec97c6af695..452daa9431ed 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -4958,6 +4958,12 @@ static int qsmmuv500_tbu_halt(struct qsmmuv500_tbu_device *tbu, u32 halt, fsr, sctlr_orig, sctlr, status; void __iomem *base, *cb_base; + if (of_property_read_bool(tbu->dev->of_node, + "qcom,opt-out-tbu-halting")) { + dev_notice(tbu->dev, "TBU opted-out for halting!\n"); + return -EBUSY; + } + spin_lock_irqsave(&tbu->halt_lock, flags); if (tbu->halt_count) { tbu->halt_count++; -- GitLab From c5800e467d2dc5455cd2910f01cb19b8c073d8c9 Mon Sep 17 00:00:00 2001 From: Sudarshan Rajagopalan Date: Mon, 20 Aug 2018 15:42:57 -0700 Subject: [PATCH 0895/1001] ARM: dts: msm: Opt-out PCIe TBU from halting When the PCIe TBU gets halted due to atos debugging, any traffic that the PCIe master sends gets halted on TBU/NNOC and any transaction sent to PCIe slave from CPU gets hanged as well because of the dependency on PCIe master to finish the transaction. Due to CPU being hanged, there is no way to unhalt the TBU by SW and the system enters into deadlock. Avoid such scenarios from occurring by opting-out PCIe TBU from being halted. Change-Id: I83f3a06cdfe509c458369ea8a550c1184a9d49ff Signed-off-by: Sudarshan Rajagopalan --- arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi | 1 + arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi index ed019eac9d88..e0376719e2ad 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi @@ -321,6 +321,7 @@ <0x15182238 0x8>; reg-names = "base", "status-reg"; qcom,stream-id-range = <0x1c00 0x400>; + qcom,opt-out-tbu-halting; qcom,regulator-names = "vdd"; vdd-supply = <&hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc>; clock-names = "gcc_aggre_noc_pcie_tbu_clk"; diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi index 688fac432a73..6ca68527d742 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi @@ -323,6 +323,7 @@ <0x15182238 0x8>; reg-names = "base", "status-reg"; qcom,stream-id-range = <0x1c00 0x400>; + qcom,opt-out-tbu-halting; qcom,regulator-names = "vdd"; vdd-supply = <&hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc>; clock-names = "gcc_aggre_noc_pcie_tbu_clk"; -- GitLab From e3ae22c800e6c34d182b56b9e42cbec7c951f889 Mon Sep 17 00:00:00 2001 From: Dinesh K Garg Date: Mon, 20 Aug 2018 11:27:13 -0700 Subject: [PATCH 0896/1001] msm: ice: Add crypto context to parse ICE settings correctly As part of improving FDE performance, code to get ICE settings is not quite clear. Hence, adding context in ICE setting so that it is clear what settings is ICE HW getting for each context. Change-Id: Iab521e893a0a204719dd29e2d69fc8f0261720d0 Signed-off-by: Dinesh K Garg --- drivers/crypto/msm/ice.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index 7bfc73aff5cc..4b37f69ef56f 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -63,6 +63,9 @@ #define QCOM_UD_FOOTER_SIZE 0x4000 #define QCOM_UD_FOOTER_SECS (QCOM_UD_FOOTER_SIZE / QCOM_SECT_LEN_IN_BYTE) +#define ICE_CRYPTO_CXT_FDE 1 +#define ICE_CRYPTO_CXT_FBE 2 + static int ice_fde_flag; struct ice_clk_info { @@ -116,16 +119,13 @@ struct ice_device { static int qti_ice_setting_config(struct request *req, struct platform_device *pdev, struct ice_crypto_setting *crypto_data, - struct ice_data_setting *setting) + struct ice_data_setting *setting, uint32_t cxt) { - struct ice_device *ice_dev = NULL; - - ice_dev = platform_get_drvdata(pdev); + struct ice_device *ice_dev = platform_get_drvdata(pdev); if (!ice_dev) { pr_debug("%s no ICE device\n", __func__); - - /* make the caller finish peacfully */ + /* make the caller finish peacefully */ return 0; } @@ -141,13 +141,17 @@ static int qti_ice_setting_config(struct request *req, memcpy(&setting->crypto_data, crypto_data, sizeof(setting->crypto_data)); - if (rq_data_dir(req) == WRITE && - (ice_fde_flag & QCOM_ICE_ENCRYPT)) - setting->encr_bypass = false; - else if (rq_data_dir(req) == READ && - (ice_fde_flag & QCOM_ICE_DECRYPT)) - setting->decr_bypass = false; - else { + if (rq_data_dir(req) == WRITE) { + if ((cxt == ICE_CRYPTO_CXT_FBE) || + ((cxt == ICE_CRYPTO_CXT_FDE) && + (ice_fde_flag & QCOM_ICE_ENCRYPT))) + setting->encr_bypass = false; + } else if (rq_data_dir(req) == READ) { + if ((cxt == ICE_CRYPTO_CXT_FBE) || + ((cxt == ICE_CRYPTO_CXT_FDE) && + (ice_fde_flag & QCOM_ICE_DECRYPT))) + setting->decr_bypass = false; + } else { /* Should I say BUG_ON */ setting->encr_bypass = true; setting->decr_bypass = true; @@ -156,6 +160,7 @@ static int qti_ice_setting_config(struct request *req, return 0; } + void qcom_ice_set_fde_flag(int flag) { ice_fde_flag = flag; @@ -1482,7 +1487,7 @@ static int qcom_ice_config_start(struct platform_device *pdev, } return qti_ice_setting_config(req, pdev, - &pfk_crypto_data, setting); + &pfk_crypto_data, setting, ICE_CRYPTO_CXT_FBE); } if (ice_fde_flag && req->part && req->part->info @@ -1510,7 +1515,8 @@ static int qcom_ice_config_start(struct platform_device *pdev, return 0; else return qti_ice_setting_config(req, pdev, - &ice_data, setting); + &ice_data, setting, + ICE_CRYPTO_CXT_FDE); } } } -- GitLab From f3eab7ec6d5c6cad8c8dcc9169fef4fce68139df Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Fri, 17 Aug 2018 15:17:57 -0700 Subject: [PATCH 0897/1001] mhi: dev: uci: remove boot logger channel from userspace External modem boot logs will be routed to ipc logging buffer instead of userspace. CRs-Fixed: 2299820 Change-Id: Ib8fc6896f9ec3e0560409422b031ae9ac60e5c71 Signed-off-by: Sujeev Dias --- drivers/bus/mhi/devices/mhi_uci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/bus/mhi/devices/mhi_uci.c b/drivers/bus/mhi/devices/mhi_uci.c index eed5429e918a..43527572463f 100644 --- a/drivers/bus/mhi/devices/mhi_uci.c +++ b/drivers/bus/mhi/devices/mhi_uci.c @@ -653,7 +653,6 @@ static const struct mhi_device_id mhi_uci_match_table[] = { { .chan = "QMI0", .driver_data = 0x1000 }, { .chan = "QMI1", .driver_data = 0x1000 }, { .chan = "TF", .driver_data = 0x1000 }, - { .chan = "BL", .driver_data = 0x1000 }, { .chan = "DUN", .driver_data = 0x1000 }, {}, }; -- GitLab From 7a8f381496913c23f68d758b31457d60bf011e1c Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Wed, 15 Nov 2017 09:57:15 -0800 Subject: [PATCH 0898/1001] dwc3: gadget: Take copy of dwc->gadget_driver before releasing lock gadget_driver can become null if gadget_stop is called while any other gadget callbacks are in progress. As gadget callbacks needs to release spinlock before the callback, store the local copy of gadget_driver to avoid the race with gadget_stop. Change-Id: I7f0cbf9af3e3b286f2826647f08215f29f699de1 Signed-off-by: Mayank Rana --- drivers/usb/dwc3/gadget.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f2c06bb61cb8..f54d8346a162 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -3017,43 +3017,55 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, static void dwc3_disconnect_gadget(struct dwc3 *dwc) { + struct usb_gadget_driver *gadget_driver; + if (dwc->gadget_driver && dwc->gadget_driver->disconnect) { + gadget_driver = dwc->gadget_driver; spin_unlock(&dwc->lock); dbg_event(0xFF, "DISCONNECT", 0); - dwc->gadget_driver->disconnect(&dwc->gadget); + gadget_driver->disconnect(&dwc->gadget); spin_lock(&dwc->lock); } } static void dwc3_suspend_gadget(struct dwc3 *dwc) { + struct usb_gadget_driver *gadget_driver; + if (dwc->gadget_driver && dwc->gadget_driver->suspend) { + gadget_driver = dwc->gadget_driver; spin_unlock(&dwc->lock); dbg_event(0xFF, "SUSPEND", 0); - dwc->gadget_driver->suspend(&dwc->gadget); + gadget_driver->suspend(&dwc->gadget); spin_lock(&dwc->lock); } } static void dwc3_resume_gadget(struct dwc3 *dwc) { + struct usb_gadget_driver *gadget_driver; + if (dwc->gadget_driver && dwc->gadget_driver->resume) { + gadget_driver = dwc->gadget_driver; spin_unlock(&dwc->lock); dbg_event(0xFF, "RESUME", 0); - dwc->gadget_driver->resume(&dwc->gadget); + gadget_driver->resume(&dwc->gadget); spin_lock(&dwc->lock); } } static void dwc3_reset_gadget(struct dwc3 *dwc) { + struct usb_gadget_driver *gadget_driver; + if (!dwc->gadget_driver) return; if (dwc->gadget.speed != USB_SPEED_UNKNOWN) { + gadget_driver = dwc->gadget_driver; spin_unlock(&dwc->lock); dbg_event(0xFF, "UDC RESET", 0); - usb_gadget_udc_reset(&dwc->gadget, dwc->gadget_driver); + usb_gadget_udc_reset(&dwc->gadget, gadget_driver); spin_lock(&dwc->lock); } } -- GitLab From 635bbd2366548ac03b0053319a7c226a2bb07e6e Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Tue, 21 Aug 2018 09:22:49 +0530 Subject: [PATCH 0899/1001] sched: walt: Refactor WALT initialization routine The global variables are initialized in walt_sched_init(). This function is called for each rq initialization and the global variables are initialized again unnecessarily. Refactor the code to fix this. Signed-off-by: Pavankumar Kondeti Change-Id: I085bc9ff576f655afa12fda015f054fbab3a0c91 --- kernel/sched/core.c | 2 +- kernel/sched/walt.c | 29 ++++++++++++++++++----------- kernel/sched/walt.h | 4 ++-- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 1023a34598f9..f46cf644af3c 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -6412,7 +6412,7 @@ void __init sched_init(void) rq->avg_idle = 2*sysctl_sched_migration_cost; rq->max_idle_balance_cost = sysctl_sched_migration_cost; rq->push_task = NULL; - walt_sched_init(rq); + walt_sched_init_rq(rq); INIT_LIST_HEAD(&rq->cfs_tasks); diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index ae2a73b317c2..f08b3ce5df5b 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -3251,15 +3251,29 @@ int walt_proc_update_handler(struct ctl_table *table, int write, return ret; } -void walt_sched_init(struct rq *rq) +static void walt_init_once(void) { - int j; - - cpumask_set_cpu(cpu_of(rq), &rq->freq_domain_cpumask); init_irq_work(&walt_migration_irq_work, walt_irq_work); init_irq_work(&walt_cpufreq_irq_work, walt_irq_work); walt_rotate_work_init(); + walt_cpu_util_freq_divisor = + (sched_ravg_window >> SCHED_CAPACITY_SHIFT) * 100; + + sched_init_task_load_windows = + div64_u64((u64)sysctl_sched_init_task_load_pct * + (u64)sched_ravg_window, 100); +} + +void walt_sched_init_rq(struct rq *rq) +{ + int j; + + if (cpu_of(rq) == 0) + walt_init_once(); + + cpumask_set_cpu(cpu_of(rq), &rq->freq_domain_cpumask); + rq->walt_stats.cumulative_runnable_avg = 0; rq->window_start = 0; rq->cum_window_start = 0; @@ -3305,11 +3319,4 @@ void walt_sched_init(struct rq *rq) } rq->cum_window_demand = 0; rq->notif_pending = false; - - walt_cpu_util_freq_divisor = - (sched_ravg_window >> SCHED_CAPACITY_SHIFT) * 100; - - sched_init_task_load_windows = - div64_u64((u64)sysctl_sched_init_task_load_pct * - (u64)sched_ravg_window, 100); } diff --git a/kernel/sched/walt.h b/kernel/sched/walt.h index cb84786556aa..1234c8ba6edb 100644 --- a/kernel/sched/walt.h +++ b/kernel/sched/walt.h @@ -293,7 +293,7 @@ void sort_clusters(void); void walt_irq_work(struct irq_work *irq_work); -void walt_sched_init(struct rq *rq); +void walt_sched_init_rq(struct rq *rq); static inline void walt_update_last_enqueue(struct task_struct *p) { @@ -305,7 +305,7 @@ extern unsigned int walt_rotation_enabled; #else /* CONFIG_SCHED_WALT */ -static inline void walt_sched_init(struct rq *rq) { } +static inline void walt_sched_init_rq(struct rq *rq) { } static inline void walt_rotate_work_init(void) { } static inline void walt_rotation_checkpoint(int nr_big) { } -- GitLab From 289dd294f3475fd917e5f2a0effb2c74dd3c33c2 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Mon, 20 Aug 2018 12:59:59 +0530 Subject: [PATCH 0900/1001] sched: walt: Optimize task_util() task_util() for WALT is currently defined as p->ravg.demand / (sched_ravg_window >> SCHED_CAPACITY_SHIFT); This math is required to scale the task demand to 1024 scale. task_util() is used many times in task placement. So the calls to this can be optimized by caching the scaled value when task demand is calculated. Change-Id: I0c170a10704ae3e8fe4e9f271e8e65c3923075e5 Signed-off-by: Pavankumar Kondeti --- include/linux/sched.h | 3 +++ kernel/sched/fair.c | 3 +-- kernel/sched/sched.h | 3 +-- kernel/sched/walt.c | 14 +++++++++++++- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 2c23d8c57f79..e025c83264d4 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -591,6 +591,8 @@ struct ravg { * * 'busy_buckets' groups historical busy time into different buckets * used for prediction + * + * 'demand_scaled' represents task's demand scaled to 1024 */ u64 mark_start; u32 sum, demand; @@ -601,6 +603,7 @@ struct ravg { u16 active_windows; u32 pred_demand; u8 busy_buckets[NUM_BUSY_BUCKETS]; + u16 demand_scaled; }; #else static inline void sched_exit(struct task_struct *p) { } diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index c7bd86920d6d..3df2e0d452c7 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -3726,8 +3726,7 @@ static inline unsigned long task_util_est(struct task_struct *p) { #ifdef CONFIG_SCHED_WALT if (likely(!walt_disabled && sysctl_sched_use_walt_task_util)) - return (p->ravg.demand / - (sched_ravg_window >> SCHED_CAPACITY_SHIFT)); + return p->ravg.demand_scaled; #endif return max(task_util(p), _task_util_est(p)); } diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 240f5e9486a4..6b9808f1247e 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1889,8 +1889,7 @@ static inline unsigned long task_util(struct task_struct *p) { #ifdef CONFIG_SCHED_WALT if (likely(!walt_disabled && sysctl_sched_use_walt_task_util)) - return p->ravg.demand / - (sched_ravg_window >> SCHED_CAPACITY_SHIFT); + return p->ravg.demand_scaled; #endif return READ_ONCE(p->se.avg.util_avg); } diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index f08b3ce5df5b..bb05b6e8cbbe 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -122,6 +122,7 @@ __read_mostly unsigned int walt_cpu_util_freq_divisor; /* Initial task load. Newly created tasks are assigned this load. */ unsigned int __read_mostly sched_init_task_load_windows; +unsigned int __read_mostly sched_init_task_load_windows_scaled; unsigned int __read_mostly sysctl_sched_init_task_load_pct = 15; /* @@ -195,6 +196,9 @@ static int __init set_sched_predl(char *str) } early_param("sched_predl", set_sched_predl); +__read_mostly unsigned int walt_scale_demand_divisor; +#define scale_demand(d) ((d)/walt_scale_demand_divisor) + void inc_rq_walt_stats(struct rq *rq, struct task_struct *p) { inc_nr_big_task(&rq->walt_stats, p); @@ -1707,6 +1711,7 @@ static void update_history(struct rq *rq, struct task_struct *p, } p->ravg.demand = demand; + p->ravg.demand_scaled = scale_demand(demand); p->ravg.coloc_demand = div64_u64(sum, sched_ravg_hist_size); p->ravg.pred_demand = pred_demand; @@ -1957,6 +1962,7 @@ void init_new_task_load(struct task_struct *p, bool idle_task) { int i; u32 init_load_windows = sched_init_task_load_windows; + u32 init_load_windows_scaled = sched_init_task_load_windows_scaled; u32 init_load_pct = current->init_load_pct; p->init_load_pct = 0; @@ -1974,11 +1980,14 @@ void init_new_task_load(struct task_struct *p, bool idle_task) if (idle_task) return; - if (init_load_pct) + if (init_load_pct) { init_load_windows = div64_u64((u64)init_load_pct * (u64)sched_ravg_window, 100); + init_load_windows_scaled = scale_demand(init_load_windows); + } p->ravg.demand = init_load_windows; + p->ravg.demand_scaled = init_load_windows_scaled; p->ravg.coloc_demand = init_load_windows; p->ravg.pred_demand = 0; for (i = 0; i < RAVG_HIST_SIZE_MAX; ++i) @@ -3259,10 +3268,13 @@ static void walt_init_once(void) walt_cpu_util_freq_divisor = (sched_ravg_window >> SCHED_CAPACITY_SHIFT) * 100; + walt_scale_demand_divisor = sched_ravg_window >> SCHED_CAPACITY_SHIFT; sched_init_task_load_windows = div64_u64((u64)sysctl_sched_init_task_load_pct * (u64)sched_ravg_window, 100); + sched_init_task_load_windows_scaled = + scale_demand(sched_init_task_load_windows); } void walt_sched_init_rq(struct rq *rq) -- GitLab From eb35eebc5ca6037f830fe23c8577e8bf7584860d Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Mon, 20 Aug 2018 17:03:58 +0530 Subject: [PATCH 0901/1001] sched: walt: Optimize cpu_util() and cpu_util_cum() The task demand in 1024 units is readily available in task_struct, so use it directly for cumulative_runnable_avg and cum_window_demand accounting. The cpu_util() and cpu_util_cum() functions which are called multiple times during the task placement can return the scaled values without doing any math. Scaling the sum of unscaled demand of tasks is more accurate compared to the sum of scaled demand of tasks, but it is good enough for task placement decisions. Change-Id: Iba4be93cd34f130bed1cb533ecaa52ab8bae5f3d Signed-off-by: Pavankumar Kondeti --- include/linux/sched.h | 1 + include/trace/events/walt.h | 4 +-- kernel/sched/debug.c | 2 +- kernel/sched/fair.c | 42 ++++++++++++++++++------------- kernel/sched/sched.h | 44 +++++++++++++------------------- kernel/sched/walt.c | 50 +++++++++++++++++++++---------------- kernel/sched/walt.h | 31 ++++++++++++----------- 7 files changed, 92 insertions(+), 82 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index e025c83264d4..1b69ef2ef669 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -604,6 +604,7 @@ struct ravg { u32 pred_demand; u8 busy_buckets[NUM_BUSY_BUCKETS]; u16 demand_scaled; + u16 pred_demand_scaled; }; #else static inline void sched_exit(struct task_struct *p) { } diff --git a/include/trace/events/walt.h b/include/trace/events/walt.h index f98e348cea60..888c36b9d8b3 100644 --- a/include/trace/events/walt.h +++ b/include/trace/events/walt.h @@ -470,7 +470,7 @@ DECLARE_EVENT_CLASS(sched_cpu_load, __entry->nr_big_tasks = rq->walt_stats.nr_big_tasks; __entry->load_scale_factor = cpu_load_scale_factor(rq->cpu); __entry->capacity = cpu_capacity(rq->cpu); - __entry->cumulative_runnable_avg = rq->walt_stats.cumulative_runnable_avg; + __entry->cumulative_runnable_avg = rq->walt_stats.cumulative_runnable_avg_scaled; __entry->irqload = irqload; __entry->max_freq = cpu_max_freq(rq->cpu); __entry->power_cost = power_cost; @@ -532,7 +532,7 @@ TRACE_EVENT(sched_load_to_gov, __entry->grp_rq_ps = rq->grp_time.prev_runnable_sum; __entry->nt_ps = rq->nt_prev_runnable_sum; __entry->grp_nt_ps = rq->grp_time.nt_prev_runnable_sum; - __entry->pl = rq->walt_stats.pred_demands_sum; + __entry->pl = rq->walt_stats.pred_demands_sum_scaled; __entry->load = load; __entry->big_task_rotation = big_task_rotation; __entry->sysctl_sched_little_cluster_coloc_fmin_khz = diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c index 943f308dd66d..84e28cfe54d0 100644 --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -759,7 +759,7 @@ do { \ P(cluster->exec_scale_factor); P(walt_stats.nr_big_tasks); SEQ_printf(m, " .%-30s: %llu\n", "walt_stats.cumulative_runnable_avg", - rq->walt_stats.cumulative_runnable_avg); + rq->walt_stats.cumulative_runnable_avg_scaled); #endif #undef P #undef PN diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 3df2e0d452c7..73c347737bbe 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -47,7 +47,8 @@ static inline bool task_fits_max(struct task_struct *p, int cpu); #ifdef CONFIG_SCHED_WALT static void walt_fixup_sched_stats_fair(struct rq *rq, struct task_struct *p, - u32 new_task_load, u32 new_pred_demand); + u16 updated_demand_scaled, + u16 updated_pred_demand_scaled); static void walt_fixup_nr_big_tasks(struct rq *rq, struct task_struct *p, int delta, bool inc); #endif /* CONFIG_SCHED_WALT */ @@ -12505,22 +12506,24 @@ __init void init_sched_fair_class(void) static void walt_init_cfs_rq_stats(struct cfs_rq *cfs_rq) { cfs_rq->walt_stats.nr_big_tasks = 0; - cfs_rq->walt_stats.cumulative_runnable_avg = 0; + cfs_rq->walt_stats.cumulative_runnable_avg_scaled = 0; cfs_rq->walt_stats.pred_demands_sum = 0; } static void walt_inc_cfs_rq_stats(struct cfs_rq *cfs_rq, struct task_struct *p) { inc_nr_big_task(&cfs_rq->walt_stats, p); - fixup_cumulative_runnable_avg(&cfs_rq->walt_stats, p->ravg.demand, - p->ravg.pred_demand); + fixup_cumulative_runnable_avg(&cfs_rq->walt_stats, + p->ravg.demand_scaled, + p->ravg.pred_demand_scaled); } static void walt_dec_cfs_rq_stats(struct cfs_rq *cfs_rq, struct task_struct *p) { dec_nr_big_task(&cfs_rq->walt_stats, p); - fixup_cumulative_runnable_avg(&cfs_rq->walt_stats, -(s64)p->ravg.demand, - -(s64)p->ravg.pred_demand); + fixup_cumulative_runnable_avg(&cfs_rq->walt_stats, + -(s64)p->ravg.demand_scaled, + -(s64)p->ravg.pred_demand_scaled); } static void walt_inc_throttled_cfs_rq_stats(struct walt_sched_stats *stats, @@ -12530,12 +12533,12 @@ static void walt_inc_throttled_cfs_rq_stats(struct walt_sched_stats *stats, stats->nr_big_tasks += tcfs_rq->walt_stats.nr_big_tasks; fixup_cumulative_runnable_avg(stats, - tcfs_rq->walt_stats.cumulative_runnable_avg, - tcfs_rq->walt_stats.pred_demands_sum); + tcfs_rq->walt_stats.cumulative_runnable_avg_scaled, + tcfs_rq->walt_stats.pred_demands_sum_scaled); if (stats == &rq->walt_stats) walt_fixup_cum_window_demand(rq, - tcfs_rq->walt_stats.cumulative_runnable_avg); + tcfs_rq->walt_stats.cumulative_runnable_avg_scaled); } @@ -12546,8 +12549,8 @@ static void walt_dec_throttled_cfs_rq_stats(struct walt_sched_stats *stats, stats->nr_big_tasks -= tcfs_rq->walt_stats.nr_big_tasks; fixup_cumulative_runnable_avg(stats, - -tcfs_rq->walt_stats.cumulative_runnable_avg, - -tcfs_rq->walt_stats.pred_demands_sum); + -tcfs_rq->walt_stats.cumulative_runnable_avg_scaled, + -tcfs_rq->walt_stats.pred_demands_sum_scaled); /* * We remove the throttled cfs_rq's tasks's contribution from the @@ -12556,16 +12559,19 @@ static void walt_dec_throttled_cfs_rq_stats(struct walt_sched_stats *stats, */ if (stats == &rq->walt_stats) walt_fixup_cum_window_demand(rq, - -tcfs_rq->walt_stats.cumulative_runnable_avg); + -tcfs_rq->walt_stats.cumulative_runnable_avg_scaled); } static void walt_fixup_sched_stats_fair(struct rq *rq, struct task_struct *p, - u32 new_task_load, u32 new_pred_demand) + u16 updated_demand_scaled, + u16 updated_pred_demand_scaled) { struct cfs_rq *cfs_rq; struct sched_entity *se = &p->se; - s64 task_load_delta = (s64)new_task_load - task_load(p); - s64 pred_demand_delta = PRED_DEMAND_DELTA; + s64 task_load_delta = (s64)updated_demand_scaled - + p->ravg.demand_scaled; + s64 pred_demand_delta = (s64)updated_pred_demand_scaled - + p->ravg.pred_demand_scaled; for_each_sched_entity(se) { cfs_rq = cfs_rq_of(se); @@ -12637,9 +12643,11 @@ static int task_will_be_throttled(struct task_struct *p) #else /* CONFIG_CFS_BANDWIDTH */ static void walt_fixup_sched_stats_fair(struct rq *rq, struct task_struct *p, - u32 new_task_load, u32 new_pred_demand) + u16 updated_demand_scaled, + u16 updated_pred_demand_scaled) { - fixup_walt_sched_stats_common(rq, p, new_task_load, new_pred_demand); + fixup_walt_sched_stats_common(rq, p, updated_demand_scaled, + updated_pred_demand_scaled); } static void walt_fixup_nr_big_tasks(struct rq *rq, struct task_struct *p, diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 6b9808f1247e..d3a72c8fe991 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -58,8 +58,8 @@ extern unsigned int walt_cpu_util_freq_divisor; struct walt_sched_stats { int nr_big_tasks; - u64 cumulative_runnable_avg; - u64 pred_demands_sum; + u64 cumulative_runnable_avg_scaled; + u64 pred_demands_sum_scaled; }; struct cpu_cycle { @@ -882,7 +882,7 @@ struct rq { u64 prev_runnable_sum; u64 nt_curr_runnable_sum; u64 nt_prev_runnable_sum; - u64 cum_window_demand; + u64 cum_window_demand_scaled; struct group_cpu_time grp_time; struct load_subtractions load_subs[NUM_TRACKED_WINDOWS]; DECLARE_BITMAP_ARRAY(top_tasks_bitmap, @@ -1615,7 +1615,8 @@ struct sched_class { #ifdef CONFIG_SCHED_WALT void (*fixup_walt_sched_stats)(struct rq *rq, struct task_struct *p, - u32 new_task_load, u32 new_pred_demand); + u16 updated_demand_scaled, + u16 updated_pred_demand_scaled); #endif }; @@ -1940,10 +1941,7 @@ static inline unsigned long cpu_util(int cpu) #ifdef CONFIG_SCHED_WALT if (likely(!walt_disabled && sysctl_sched_use_walt_cpu_util)) { u64 walt_cpu_util = - cpu_rq(cpu)->walt_stats.cumulative_runnable_avg; - - walt_cpu_util <<= SCHED_CAPACITY_SHIFT; - do_div(walt_cpu_util, sched_ravg_window); + cpu_rq(cpu)->walt_stats.cumulative_runnable_avg_scaled; return min_t(unsigned long, walt_cpu_util, capacity_orig_of(cpu)); @@ -1972,11 +1970,8 @@ static inline unsigned long cpu_util_cum(int cpu, int delta) unsigned long capacity = capacity_orig_of(cpu); #ifdef CONFIG_SCHED_WALT - if (!walt_disabled && sysctl_sched_use_walt_cpu_util) { - util = cpu_rq(cpu)->cum_window_demand; - util = div64_u64(util, - sched_ravg_window >> SCHED_CAPACITY_SHIFT); - } + if (!walt_disabled && sysctl_sched_use_walt_cpu_util) + util = cpu_rq(cpu)->cum_window_demand_scaled; #endif delta += util; if (delta < 0) @@ -2010,19 +2005,17 @@ cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load) if (walt_load) { u64 nl = cpu_rq(cpu)->nt_prev_runnable_sum + rq->grp_time.nt_prev_runnable_sum; - u64 pl = rq->walt_stats.pred_demands_sum; + u64 pl = rq->walt_stats.pred_demands_sum_scaled; /* do_pl_notif() needs unboosted signals */ rq->old_busy_time = div64_u64(util_unboosted, sched_ravg_window >> SCHED_CAPACITY_SHIFT); - rq->old_estimated_time = div64_u64(pl, sched_ravg_window >> - SCHED_CAPACITY_SHIFT); + rq->old_estimated_time = pl; nl = div64_u64(nl * (100 + boost), walt_cpu_util_freq_divisor); - pl = div64_u64(pl * (100 + boost), - walt_cpu_util_freq_divisor); + pl = div64_u64(pl * (100 + boost), 100); walt_load->prev_window_util = util; walt_load->nl = nl; @@ -2809,8 +2802,6 @@ struct related_thread_group *task_related_thread_group(struct task_struct *p) return rcu_dereference(p->grp); } -#define PRED_DEMAND_DELTA ((s64)new_pred_demand - p->ravg.pred_demand) - /* Is frequency of two cpus synchronized with each other? */ static inline int same_freq_domain(int src_cpu, int dst_cpu) { @@ -2889,11 +2880,11 @@ task_in_cum_window_demand(struct rq *rq, struct task_struct *p) rq->window_start); } -static inline void walt_fixup_cum_window_demand(struct rq *rq, s64 delta) +static inline void walt_fixup_cum_window_demand(struct rq *rq, s64 scaled_delta) { - rq->cum_window_demand += delta; - if (unlikely((s64)rq->cum_window_demand < 0)) - rq->cum_window_demand = 0; + rq->cum_window_demand_scaled += scaled_delta; + if (unlikely((s64)rq->cum_window_demand_scaled < 0)) + rq->cum_window_demand_scaled = 0; } extern void update_cpu_cluster_capacity(const cpumask_t *cpus); @@ -3036,8 +3027,6 @@ static inline int update_preferred_cluster(struct related_thread_group *grp, static inline void add_new_task_to_grp(struct task_struct *new) {} -#define PRED_DEMAND_DELTA (0) - static inline int same_freq_domain(int src_cpu, int dst_cpu) { return 1; @@ -3051,7 +3040,8 @@ static inline int alloc_related_thread_groups(void) { return 0; } #define trace_sched_cpu_load_cgroup(...) #define trace_sched_cpu_load_wakeup(...) -static inline void walt_fixup_cum_window_demand(struct rq *rq, s64 delta) { } +static inline void walt_fixup_cum_window_demand(struct rq *rq, + s64 scaled_delta) { } static inline void update_cpu_cluster_capacity(const cpumask_t *cpus) { } diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index bb05b6e8cbbe..1b171077cf24 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -212,10 +212,13 @@ void dec_rq_walt_stats(struct rq *rq, struct task_struct *p) } void fixup_walt_sched_stats_common(struct rq *rq, struct task_struct *p, - u32 new_task_load, u32 new_pred_demand) + u16 updated_demand_scaled, + u16 updated_pred_demand_scaled) { - s64 task_load_delta = (s64)new_task_load - task_load(p); - s64 pred_demand_delta = PRED_DEMAND_DELTA; + s64 task_load_delta = (s64)updated_demand_scaled - + p->ravg.demand_scaled; + s64 pred_demand_delta = (s64)updated_pred_demand_scaled - + p->ravg.pred_demand_scaled; fixup_cumulative_runnable_avg(&rq->walt_stats, task_load_delta, pred_demand_delta); @@ -283,7 +286,8 @@ update_window_start(struct rq *rq, u64 wallclock, int event) nr_windows = div64_u64(delta, sched_ravg_window); rq->window_start += (u64)nr_windows * (u64)sched_ravg_window; - rq->cum_window_demand = rq->walt_stats.cumulative_runnable_avg; + rq->cum_window_demand_scaled = + rq->walt_stats.cumulative_runnable_avg_scaled; return old_window_start; } @@ -772,8 +776,9 @@ void fixup_busy_time(struct task_struct *p, int new_cpu) */ if (p->state == TASK_WAKING && p->last_sleep_ts >= src_rq->window_start) { - walt_fixup_cum_window_demand(src_rq, -(s64)p->ravg.demand); - walt_fixup_cum_window_demand(dest_rq, p->ravg.demand); + walt_fixup_cum_window_demand(src_rq, + -(s64)p->ravg.demand_scaled); + walt_fixup_cum_window_demand(dest_rq, p->ravg.demand_scaled); } new_task = is_new_task(p); @@ -1031,6 +1036,7 @@ static inline u32 calc_pred_demand(struct rq *rq, struct task_struct *p) void update_task_pred_demand(struct rq *rq, struct task_struct *p, int event) { u32 new, old; + u16 new_scaled; if (!sched_predl) return; @@ -1059,14 +1065,16 @@ void update_task_pred_demand(struct rq *rq, struct task_struct *p, int event) if (old >= new) return; + new_scaled = scale_demand(new); if (task_on_rq_queued(p) && (!task_has_dl_policy(p) || !p->dl.dl_throttled) && p->sched_class->fixup_walt_sched_stats) p->sched_class->fixup_walt_sched_stats(rq, p, - p->ravg.demand, - new); + p->ravg.demand_scaled, + new_scaled); p->ravg.pred_demand = new; + p->ravg.pred_demand_scaled = new_scaled; } void clear_top_tasks_bitmap(unsigned long *bitmap) @@ -1291,7 +1299,7 @@ static inline unsigned int load_to_freq(struct rq *rq, unsigned int load) bool do_pl_notif(struct rq *rq) { u64 prev = rq->old_busy_time; - u64 pl = rq->walt_stats.pred_demands_sum; + u64 pl = rq->walt_stats.pred_demands_sum_scaled; int cpu = cpu_of(rq); /* If already at max freq, bail out */ @@ -1300,8 +1308,6 @@ bool do_pl_notif(struct rq *rq) prev = max(prev, rq->old_estimated_time); - pl = div64_u64(pl, sched_ravg_window >> SCHED_CAPACITY_SHIFT); - /* 400 MHz filter. */ return (pl > prev) && (load_to_freq(rq, pl - prev) > 400000); } @@ -1649,14 +1655,12 @@ static void update_history(struct rq *rq, struct task_struct *p, int ridx, widx; u32 max = 0, avg, demand, pred_demand; u64 sum = 0; - u64 prev_demand; + u16 demand_scaled, pred_demand_scaled; /* Ignore windows where task had no activity */ if (!runtime || is_idle_task(p) || exiting_task(p) || !samples) goto done; - prev_demand = p->ravg.demand; - /* Push new 'runtime' value onto stack */ widx = sched_ravg_hist_size - 1; ridx = widx - samples; @@ -1688,6 +1692,8 @@ static void update_history(struct rq *rq, struct task_struct *p, demand = max(avg, runtime); } pred_demand = predict_and_update_buckets(rq, p, runtime); + demand_scaled = scale_demand(demand); + pred_demand_scaled = scale_demand(pred_demand); /* * A throttled deadline sched class task gets dequeued without @@ -1704,16 +1710,17 @@ static void update_history(struct rq *rq, struct task_struct *p, if (!task_has_dl_policy(p) || !p->dl.dl_throttled) { if (task_on_rq_queued(p) && p->sched_class->fixup_walt_sched_stats) - p->sched_class->fixup_walt_sched_stats(rq, p, demand, - pred_demand); + p->sched_class->fixup_walt_sched_stats(rq, p, + demand_scaled, pred_demand_scaled); else if (rq->curr == p) - walt_fixup_cum_window_demand(rq, demand); + walt_fixup_cum_window_demand(rq, demand_scaled); } p->ravg.demand = demand; - p->ravg.demand_scaled = scale_demand(demand); + p->ravg.demand_scaled = demand_scaled; p->ravg.coloc_demand = div64_u64(sum, sched_ravg_hist_size); p->ravg.pred_demand = pred_demand; + p->ravg.pred_demand_scaled = pred_demand_scaled; done: trace_sched_update_history(rq, p, runtime, samples, event); @@ -1990,6 +1997,7 @@ void init_new_task_load(struct task_struct *p, bool idle_task) p->ravg.demand_scaled = init_load_windows_scaled; p->ravg.coloc_demand = init_load_windows; p->ravg.pred_demand = 0; + p->ravg.pred_demand_scaled = 0; for (i = 0; i < RAVG_HIST_SIZE_MAX; ++i) p->ravg.sum_history[i] = init_load_windows; p->misfit = false; @@ -3286,7 +3294,7 @@ void walt_sched_init_rq(struct rq *rq) cpumask_set_cpu(cpu_of(rq), &rq->freq_domain_cpumask); - rq->walt_stats.cumulative_runnable_avg = 0; + rq->walt_stats.cumulative_runnable_avg_scaled = 0; rq->window_start = 0; rq->cum_window_start = 0; rq->walt_stats.nr_big_tasks = 0; @@ -3313,7 +3321,7 @@ void walt_sched_init_rq(struct rq *rq) rq->old_busy_time = 0; rq->old_estimated_time = 0; rq->old_busy_time_group = 0; - rq->walt_stats.pred_demands_sum = 0; + rq->walt_stats.pred_demands_sum_scaled = 0; rq->ed_task = NULL; rq->curr_table = 0; rq->prev_top = 0; @@ -3329,6 +3337,6 @@ void walt_sched_init_rq(struct rq *rq) BUG_ON(!rq->top_tasks[j]); clear_top_tasks_bitmap(rq->top_tasks_bitmap[j]); } - rq->cum_window_demand = 0; + rq->cum_window_demand_scaled = 0; rq->notif_pending = false; } diff --git a/kernel/sched/walt.h b/kernel/sched/walt.h index 1234c8ba6edb..e3c1181265bc 100644 --- a/kernel/sched/walt.h +++ b/kernel/sched/walt.h @@ -95,16 +95,17 @@ walt_adjust_nr_big_tasks(struct rq *rq, int delta, bool inc) static inline void fixup_cumulative_runnable_avg(struct walt_sched_stats *stats, - s64 task_load_delta, s64 pred_demand_delta) + s64 demand_scaled_delta, + s64 pred_demand_scaled_delta) { if (sched_disable_window_stats) return; - stats->cumulative_runnable_avg += task_load_delta; - BUG_ON((s64)stats->cumulative_runnable_avg < 0); + stats->cumulative_runnable_avg_scaled += demand_scaled_delta; + BUG_ON((s64)stats->cumulative_runnable_avg_scaled < 0); - stats->pred_demands_sum += pred_demand_delta; - BUG_ON((s64)stats->pred_demands_sum < 0); + stats->pred_demands_sum_scaled += pred_demand_scaled_delta; + BUG_ON((s64)stats->pred_demands_sum_scaled < 0); } static inline void @@ -113,8 +114,8 @@ walt_inc_cumulative_runnable_avg(struct rq *rq, struct task_struct *p) if (sched_disable_window_stats) return; - fixup_cumulative_runnable_avg(&rq->walt_stats, p->ravg.demand, - p->ravg.pred_demand); + fixup_cumulative_runnable_avg(&rq->walt_stats, p->ravg.demand_scaled, + p->ravg.pred_demand_scaled); /* * Add a task's contribution to the cumulative window demand when @@ -124,7 +125,7 @@ walt_inc_cumulative_runnable_avg(struct rq *rq, struct task_struct *p) * (2) task is waking for the first time in this window. */ if (p->on_rq || (p->last_sleep_ts < rq->window_start)) - walt_fixup_cum_window_demand(rq, p->ravg.demand); + walt_fixup_cum_window_demand(rq, p->ravg.demand_scaled); } static inline void @@ -133,8 +134,9 @@ walt_dec_cumulative_runnable_avg(struct rq *rq, struct task_struct *p) if (sched_disable_window_stats) return; - fixup_cumulative_runnable_avg(&rq->walt_stats, -(s64)p->ravg.demand, - -(s64)p->ravg.pred_demand); + fixup_cumulative_runnable_avg(&rq->walt_stats, + -(s64)p->ravg.demand_scaled, + -(s64)p->ravg.pred_demand_scaled); /* * on_rq will be 1 for sleeping tasks. So check if the task @@ -142,12 +144,12 @@ walt_dec_cumulative_runnable_avg(struct rq *rq, struct task_struct *p) * prio/cgroup/class. */ if (task_on_rq_migrating(p) || p->state == TASK_RUNNING) - walt_fixup_cum_window_demand(rq, -(s64)p->ravg.demand); + walt_fixup_cum_window_demand(rq, -(s64)p->ravg.demand_scaled); } extern void fixup_walt_sched_stats_common(struct rq *rq, struct task_struct *p, - u32 new_task_load, - u32 new_pred_demand); + u16 updated_demand_scaled, + u16 updated_pred_demand_scaled); extern void inc_rq_walt_stats(struct rq *rq, struct task_struct *p); extern void dec_rq_walt_stats(struct rq *rq, struct task_struct *p); extern void fixup_busy_time(struct task_struct *p, int new_cpu); @@ -374,7 +376,8 @@ dec_rq_walt_stats(struct rq *rq, struct task_struct *p) { } static inline void fixup_walt_sched_stats_common(struct rq *rq, struct task_struct *p, - u32 new_task_load, u32 new_pred_demand) + u16 updated_demand_scaled, + u16 updated_pred_demand_scaled) { } -- GitLab From f9c503da00479f7f375c483a59fae314b7bb7e52 Mon Sep 17 00:00:00 2001 From: Monika Singh Date: Tue, 14 Aug 2018 19:44:57 +0530 Subject: [PATCH 0902/1001] ARM: dts: msm: Enable ro.boot.avb_version for sm6150 Enable ro.boot.avb_version and add "android,vbmeta" for setting system properties for verified boot. Change-Id: I91f43728f90ec6175743a5e2c52a6915b8a84777 Signed-off-by: Monika Singh --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 7fb99f5f53c1..f93c9ec99cbc 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -467,6 +467,10 @@ firmware: firmware { android { compatible = "android,firmware"; + vbmeta { + compatible = "android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo"; + }; fstab { compatible = "android,fstab"; vendor { -- GitLab From a318f0684c85b01e28d5d5335a3dbc05fc8c92d9 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Mon, 20 Aug 2018 15:48:10 +0530 Subject: [PATCH 0903/1001] defconfig: qcs405: Enable AR803x PHY config Enable AR803x PHY support for Ethernet for perf. This also enable ptp config. KS8851 PHY is not needed for qcs405 removed it. Change-Id: If0fca7b2247324915d3427f89a1fac22d5ec6b99 Acked-by: Suraj Jaiswal Signed-off-by: Mohammed Javid --- arch/arm/configs/vendor/qcs405-perf_defconfig | 3 ++- arch/arm/configs/vendor/qcs405_defconfig | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/configs/vendor/qcs405-perf_defconfig b/arch/arm/configs/vendor/qcs405-perf_defconfig index 14420b3eb670..66231a7ceddd 100644 --- a/arch/arm/configs/vendor/qcs405-perf_defconfig +++ b/arch/arm/configs/vendor/qcs405-perf_defconfig @@ -224,7 +224,7 @@ CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_TUN=y -CONFIG_KS8851=y +CONFIG_AT803X_PHY=y CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y @@ -264,6 +264,7 @@ CONFIG_I2C_CHARDEV=y CONFIG_SPI=y CONFIG_SPI_SPIDEV=y CONFIG_SPMI=y +CONFIG_PTP_1588_CLOCK=y CONFIG_PINCTRL_QCS405=y CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y diff --git a/arch/arm/configs/vendor/qcs405_defconfig b/arch/arm/configs/vendor/qcs405_defconfig index 807bed8d0722..1448d2995939 100644 --- a/arch/arm/configs/vendor/qcs405_defconfig +++ b/arch/arm/configs/vendor/qcs405_defconfig @@ -274,6 +274,7 @@ CONFIG_SPI_DEBUG=y CONFIG_SPI_SPIDEV=y CONFIG_SPMI=y CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_PTP_1588_CLOCK=y CONFIG_PINCTRL_QCS405=y CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y -- GitLab From ef6e8cfc1f3ba8b85883788d0931b0503fa9d670 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Tue, 21 Aug 2018 13:10:11 +0530 Subject: [PATCH 0904/1001] ARM: dts: msm: Enable PM for IPA device on SM6150 Adding IPA power management feature support to SM6150 target. Change-Id: Ifa7e8048a1d63f0d9919337c7bc2b6e48d49a819 Acked-by: Ashok Vuyyuru Signed-off-by: Mohammed Javid --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 7fb99f5f53c1..fa866034934f 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -2244,6 +2244,7 @@ qcom,use-64-bit-dma-mask; qcom,arm-smmu; qcom,smmu-fast-map; + qcom,use-ipa-pm; qcom,bandwidth-vote-for-ipa; qcom,msm-bus,name = "ipa"; qcom,msm-bus,num-cases = <5>; @@ -2276,6 +2277,8 @@ ; qcom,bus-vector-names = "MIN", "SVS2", "SVS", "NOMINAL", "TURBO"; + qcom,throughput-threshold = <310 600 1000>; + qcom,scaling-exceptions = <>; /* smp2p information */ qcom,smp2p_map_ipa_1_out { -- GitLab From b5516cedd0b7d7536938ab9d3ad81ddc38b88afb Mon Sep 17 00:00:00 2001 From: Arunk Khandavalli Date: Tue, 21 Aug 2018 14:20:20 +0530 Subject: [PATCH 0905/1001] nl80211: nl80211_update_ft_ies to validate NL80211_ATTR_IE Current nl80211_update_ft_ies doesn't validate NL80211_ATTR_IE before dereferencing it, which leads to a null pointer exception if not passed. This commit validates this attribute too. Change-Id: Ia40b02fc218bc26a07bc6b2153f425b8cae3bd82 CRs-Fixed: 2261685 Signed-off-by: Arunk Khandavalli Signed-off-by: Srinivas Dasari --- net/wireless/nl80211.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 30683891305f..c2a52658f273 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -11737,6 +11737,7 @@ static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info) return -EOPNOTSUPP; if (!info->attrs[NL80211_ATTR_MDID] || + !info->attrs[NL80211_ATTR_IE] || !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; -- GitLab From 15559c8e4893c983471ff149f81ef1c94b8e06e3 Mon Sep 17 00:00:00 2001 From: Aditya Bavanari Date: Tue, 14 Aug 2018 17:13:26 +0530 Subject: [PATCH 0906/1001] ARM: dts: msm: Enable wcn-btfm interface in sm6150 Enable BTFM interface to add the FM related DAI links in sm6150 target. CRs-Fixed: 2286582 Change-Id: Iad5d6f428e59fb2f098d2821df9940e80766545e Signed-off-by: Aditya Bavanari --- arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi | 5 ++++- arch/arm64/boot/dts/qcom/sm6150-audio.dtsi | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi index ceb3708119d1..3c63a7c82cd5 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi @@ -136,7 +136,10 @@ "IN3_AUX", "AUX_OUT", "TX SWR_ADC0", "ADC1_OUTPUT", "TX SWR_ADC2", "ADC2_OUTPUT", - "TX SWR_ADC3", "ADC3_OUTPUT", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", "SpkrLeft IN", "WSA_SPK1 OUT", "SpkrRight IN", "WSA_SPK2 OUT", "WSA_SPK1 OUT", "VA_MCLK", diff --git a/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi b/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi index a09257719bc9..3b4b5795c5b5 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi @@ -43,6 +43,7 @@ compatible = "qcom,sm6150-asoc-snd"; qcom,mi2s-audio-intf = <1>; qcom,auxpcm-audio-intf = <1>; + qcom,wcn-btfm = <1>; asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, -- GitLab From 1c8a2f31e7b33170cc6cdc1e53e75d6ab72d5d7c Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Tue, 21 Aug 2018 17:57:51 +0530 Subject: [PATCH 0907/1001] clk: qcom: Fix compilation issue in NPUCC clock driver Declare npu_gdsc variable to fix the compilation issue. Change-Id: Ie661fe040721f7a9491076e1eae1e7db7fe7bf04 Signed-off-by: Shefali Jain --- drivers/clk/qcom/npucc-sdmmagpie.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/qcom/npucc-sdmmagpie.c b/drivers/clk/qcom/npucc-sdmmagpie.c index cdbb2c7949e9..efa104d29189 100644 --- a/drivers/clk/qcom/npucc-sdmmagpie.c +++ b/drivers/clk/qcom/npucc-sdmmagpie.c @@ -596,6 +596,7 @@ static int enable_npu_crc(struct regmap *regmap, struct regulator *npu_gdsc) static int npu_cc_sdmmagpie_probe(struct platform_device *pdev) { struct regmap *regmap; + struct regulator *npu_gdsc; int ret = 0; vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx"); -- GitLab From 4a7e4fdbf035a008535dcf07624a8b4d03a04fc2 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Mon, 20 Aug 2018 13:33:16 +0530 Subject: [PATCH 0908/1001] drm/msm/dsi-staging: avoid dumping panel commands in dmesg Avoid unnecessarily dumping all the panel specific commands in dmesg log. Change-Id: I6b1189b32c7477d6aab39b65e430fc7171cef6e5 Signed-off-by: Sandeep Panda --- drivers/gpu/drm/msm/dsi-staging/dsi_panel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index 3b383a5629db..dc57ae8912fe 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -1603,8 +1603,8 @@ static int dsi_panel_parse_cmd_sets_sub(struct dsi_panel_cmd_set *cmd, pr_debug("type=%d, name=%s, length=%d\n", type, cmd_set_prop_map[type], length); - print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, - 8, 1, data, length, false); + print_hex_dump_debug("", DUMP_PREFIX_NONE, + 8, 1, data, length, false); rc = dsi_panel_get_cmd_pkt_count(data, length, &packet_count); if (rc) { -- GitLab From b1b5abb3bb544310f4362d32218ba20a200e95a9 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Tue, 21 Aug 2018 19:32:12 +0530 Subject: [PATCH 0909/1001] ARM: dts: msm: enable ESD for hx83112a panel on sm6150 Enable ESD feature for hx83112a video mode panel on sm6150 platform. Change-Id: I068f08f4ea43f239ac9f1910528d639c092e99ea Signed-off-by: Sandeep Panda --- arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi index 907029a15dcb..834d377bd9f7 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi @@ -244,6 +244,13 @@ qcom,mdss-dsi-pan-enable-dynamic-fps; qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>; + qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>; + qcom,mdss-dsi-panel-status-read-length = <4>; qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = -- GitLab From c22c0e078dc129ca1f25c069232e168b43339a8e Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Tue, 21 Aug 2018 10:33:55 -0700 Subject: [PATCH 0910/1001] msm: ipa3: send usb-connect from rndis-ipa To resolve the timing issue between usb-driver and android framework, made the change on rndis ipa to send the usb-connect msg when usb-driver connect the IPA pipes. Change-Id: I51de37bc7610cb0a94659c64146f10ed322210b2 Signed-off-by: Skylar Chang --- .../platform/msm/ipa/ipa_clients/rndis_ipa.c | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c index fe916076e6c3..21bba6e8e9d0 100644 --- a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c +++ b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c @@ -454,6 +454,11 @@ struct rndis_pkt_hdr rndis_template_hdr = { .zeroes = {0}, }; +static void rndis_ipa_msg_free_cb(void *buff, u32 len, u32 type) +{ + kfree(buff); +} + /** * rndis_ipa_init() - create network device and initialize internal * data structures @@ -677,6 +682,8 @@ int rndis_ipa_pipe_connect_notify( int result; int ret; unsigned long flags; + struct ipa_ecm_msg *rndis_msg; + struct ipa_msg_meta msg_meta; RNDIS_IPA_LOG_ENTRY(); @@ -762,6 +769,26 @@ int rndis_ipa_pipe_connect_notify( } RNDIS_IPA_DEBUG("netif_carrier_on() was called\n"); + rndis_msg = kzalloc(sizeof(*rndis_msg), GFP_KERNEL); + if (!rndis_msg) { + result = -ENOMEM; + goto fail; + } + + memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); + msg_meta.msg_type = ECM_CONNECT; + msg_meta.msg_len = sizeof(struct ipa_ecm_msg); + strlcpy(rndis_msg->name, rndis_ipa_ctx->net->name, + IPA_RESOURCE_NAME_MAX); + rndis_msg->ifindex = rndis_ipa_ctx->net->ifindex; + + result = ipa_send_msg(&msg_meta, rndis_msg, rndis_ipa_msg_free_cb); + if (result) { + RNDIS_IPA_ERROR("fail to send ECM_CONNECT for rndis\n"); + kfree(rndis_msg); + goto fail; + } + spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags); next_state = rndis_ipa_next_state(rndis_ipa_ctx->state, RNDIS_IPA_CONNECT); @@ -1222,6 +1249,8 @@ int rndis_ipa_pipe_disconnect_notify(void *private) int retval; int ret; unsigned long flags; + struct ipa_ecm_msg *rndis_msg; + struct ipa_msg_meta msg_meta; RNDIS_IPA_LOG_ENTRY(); @@ -1253,6 +1282,24 @@ int rndis_ipa_pipe_disconnect_notify(void *private) netif_carrier_off(rndis_ipa_ctx->net); RNDIS_IPA_DEBUG("carrier_off notification was sent\n"); + rndis_msg = kzalloc(sizeof(*rndis_msg), GFP_KERNEL); + if (!rndis_msg) + return -ENOMEM; + + memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); + msg_meta.msg_type = ECM_DISCONNECT; + msg_meta.msg_len = sizeof(struct ipa_ecm_msg); + strlcpy(rndis_msg->name, rndis_ipa_ctx->net->name, + IPA_RESOURCE_NAME_MAX); + rndis_msg->ifindex = rndis_ipa_ctx->net->ifindex; + + retval = ipa_send_msg(&msg_meta, rndis_msg, rndis_ipa_msg_free_cb); + if (retval) { + RNDIS_IPA_ERROR("fail to send ECM_DISCONNECT for rndis\n"); + kfree(rndis_msg); + return -EPERM; + } + netif_stop_queue(rndis_ipa_ctx->net); RNDIS_IPA_DEBUG("queue stopped\n"); -- GitLab From 822cef0c6a872f4555a0e085b8f29d4d8998b915 Mon Sep 17 00:00:00 2001 From: Mangesh Kunchamwar Date: Tue, 21 Aug 2018 23:04:17 +0530 Subject: [PATCH 0911/1001] ARM: dts: msm: Enable WCD9335 in QCS405 sEVB,SLT and RCM variants Update QCS405 sEVB,SLT and RCM variants DT files to include WCD9335 entries. Change-Id: I7c797c19fb40065d3d9ca7b60be5e06e04fd14b1 Signed-off-by: Mangesh Kunchamwar --- arch/arm64/boot/dts/qcom/qcs403-iot-sku2.dts | 2 +- arch/arm64/boot/dts/qcom/qcs405-iot-sku3.dts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcs403-iot-sku2.dts b/arch/arm64/boot/dts/qcom/qcs403-iot-sku2.dts index fc6b265c4dad..e40e24350d7c 100644 --- a/arch/arm64/boot/dts/qcom/qcs403-iot-sku2.dts +++ b/arch/arm64/boot/dts/qcom/qcs403-iot-sku2.dts @@ -14,7 +14,7 @@ /dts-v1/; #include "qcs403.dtsi" -#include "qcs405-nowcd-audio-overlay.dtsi" +#include "qcs405-audio-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS403 RCM IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku3.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku3.dts index 198ccc831376..9ec18758df4d 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku3.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku3.dts @@ -14,7 +14,7 @@ /dts-v1/; #include "qcs405.dtsi" -#include "qcs405-nowcd-audio-overlay.dtsi" +#include "qcs405-audio-overlay.dtsi" #include "qcs405-geni-ir-overlay.dtsi" #include "qcs405-pinctrl.dtsi" -- GitLab From 51035bcc59141f6e1d12a3ba00d6c3b4415d6bac Mon Sep 17 00:00:00 2001 From: Oleg Perelet Date: Tue, 14 Aug 2018 14:38:22 -0700 Subject: [PATCH 0912/1001] msm: kgsl: add support for cx gdsc operation mode Provide control to support cx gdsc operational mode via quirk. Change-Id: I94230a303de3763ef86fd8b95edb641392efaa9c Signed-off-by: Oleg Perelet --- drivers/gpu/msm/adreno.c | 1 + drivers/gpu/msm/adreno.h | 2 ++ drivers/gpu/msm/kgsl_gmu.c | 8 ++++++++ 3 files changed, 11 insertions(+) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index dda9872c7ca2..e3cd9803dc88 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -756,6 +756,7 @@ static struct { { ADRENO_QUIRK_LIMIT_UCHE_GBIF_RW, "qcom,gpu-quirk-limit-uche-gbif-rw" }, { ADRENO_QUIRK_MMU_SECURE_CB_ALT, "qcom,gpu-quirk-mmu-secure-cb-alt" }, + { ADRENO_QUIRK_CX_GDSC, "qcom,gpu-quirk-cx-gdsc" }, }; static struct device_node * diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index daf61170707f..013191281180 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -157,6 +157,8 @@ #define ADRENO_QUIRK_LIMIT_UCHE_GBIF_RW BIT(8) /* Select alternate secure context bank for mmu */ #define ADRENO_QUIRK_MMU_SECURE_CB_ALT BIT(9) +/* Do explicit mode control of cx gdsc */ +#define ADRENO_QUIRK_CX_GDSC BIT(10) /* Flags to control command packet settings */ #define KGSL_CMD_FLAGS_NONE 0 diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index 872595e25eb6..0ea075fb93eb 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -1520,7 +1520,15 @@ static int gmu_suspend(struct kgsl_device *device) return -EINVAL; gmu_disable_clks(device); + + if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_CX_GDSC)) + regulator_set_mode(gmu->cx_gdsc, REGULATOR_MODE_IDLE); + gmu_disable_gdsc(gmu); + + if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_CX_GDSC)) + regulator_set_mode(gmu->cx_gdsc, REGULATOR_MODE_NORMAL); + dev_err(&gmu->pdev->dev, "Suspended GMU\n"); return 0; } -- GitLab From 325ffb56baa2566d4bd0c083201e779dff7d1e6d Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Wed, 7 Mar 2018 12:05:49 +0530 Subject: [PATCH 0913/1001] sched: Improve the scheduler This change is for general scheduler improvement Change-Id: I5ad0b6e4e90e7d9cb3bd5d5bd5e909ebcb9739e2 Signed-off-by: Pavankumar Kondeti --- kernel/sched/fair.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index c7bd86920d6d..ec8eb218cd6b 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -10953,6 +10953,19 @@ static int load_balance(int this_cpu, struct rq *this_rq, raw_spin_lock_irqsave(&busiest->lock, flags); + /* + * The CPUs are marked as reserved if tasks + * are pushed/pulled from other CPUs. In that case, + * bail out from the load balancer. + */ + if (is_reserved(this_cpu) || + is_reserved(cpu_of(busiest))) { + raw_spin_unlock_irqrestore(&busiest->lock, + flags); + *continue_balancing = 0; + goto out; + } + /* don't kick the active_load_balance_cpu_stop, * if the curr task on busiest cpu can't be * moved to this_cpu -- GitLab From cc0c47ab2018127362ed5af6614e172ed71566d0 Mon Sep 17 00:00:00 2001 From: Amit Shekhar Date: Tue, 21 Aug 2018 15:02:51 -0700 Subject: [PATCH 0914/1001] msm: vidc: Remove redundant RC CQ before setting HEIC controls Video driver shouldn't assume any order while setting parameters, since, client can set them in any order. We, also, check params for HEIF encode before stream starts, therefore RC CQ check before setting HEIC controls is redundant. Change-Id: Iab6b2f165d1a7c00389a9335ce5fd6327b9581c7 Signed-off-by: Amit Shekhar --- drivers/media/platform/msm/vidc/msm_venc.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 13a862691b90..12a7cf83eb77 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -1435,14 +1435,6 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) } case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_QUALITY: { - struct v4l2_ctrl *rc_mode = TRY_GET_CTRL( - V4L2_CID_MPEG_VIDEO_BITRATE_MODE); - if (rc_mode->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) { - dprintk(VIDC_ERR, - "Frame quality supported only for CQ\n"); - rc = -ENOTSUPP; - break; - } if (ctrl->val < MIN_FRAME_QUALITY || ctrl->val > MAX_FRAME_QUALITY) { dprintk(VIDC_ERR, @@ -1459,15 +1451,6 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) } case V4L2_CID_MPEG_VIDC_IMG_GRID_ENABLE: { - struct v4l2_ctrl *rc_mode = TRY_GET_CTRL( - V4L2_CID_MPEG_VIDEO_BITRATE_MODE); - if (rc_mode->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CQ && - ctrl->val) { - dprintk(VIDC_ERR, - "Grid enable supported only for CQ\n"); - rc = -ENOTSUPP; - break; - } property_id = HAL_CONFIG_HEIC_GRID_ENABLE; grid_enable.grid_enable = ctrl->val; inst->grid_enable = ctrl->val; -- GitLab From 9f0d98f712194dbd40adc208a1df687133e1b3bd Mon Sep 17 00:00:00 2001 From: Maheshwar Ajja Date: Tue, 21 Aug 2018 15:32:30 -0700 Subject: [PATCH 0915/1001] msm: vidc: ignore processing responses in invalid state No need to process response messages from video hardware after device went into invalid state. Processing responses may result in use-after-free memory fault because client might free all the resources after error. Change-Id: Ia2c22a2740466e6368e61437aa4246927150858b Signed-off-by: Maheshwar Ajja --- drivers/media/platform/msm/vidc/venus_hfi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index f5b3604c1a5d..cb4fd19e1aa4 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -3689,6 +3689,12 @@ static void venus_hfi_core_work_handler(struct work_struct *work) i < num_responses; ++i) { struct msm_vidc_cb_info *r = &device->response_pkt[i]; + if (!__core_in_valid_state(device)) { + dprintk(VIDC_ERR, + "Ignore responses from %d to %d as device is in invalid state", + (i + 1), num_responses); + break; + } dprintk(VIDC_DBG, "Processing response %d of %d, type %d\n", (i + 1), num_responses, r->response_type); device->callback(r->response_type, &r->response); -- GitLab From 4207270b6c9d589a8ab11aa4eec6fdb25224e334 Mon Sep 17 00:00:00 2001 From: Sean Tranchetti Date: Thu, 16 Aug 2018 16:22:48 -0600 Subject: [PATCH 0916/1001] soc: qcom: dfc: Enable QMAP DFC commands Enable QMAP DFC commands to either request new grants when current grant reaches threshold or acknowledge the flow disable messages. CRs-fixed: 2280803 Change-Id: I46fb37ceaabfc8d25c877e1ef232176f63a0e76c Acked-by: Weiyi Chen Signed-off-by: Sean Tranchetti --- .../ethernet/qualcomm/rmnet/rmnet_map_data.c | 34 ++++- drivers/soc/qcom/dfc_qmi.c | 136 +++++++++++++++--- drivers/soc/qcom/qmi_rmnet.c | 85 ++++++++--- drivers/soc/qcom/qmi_rmnet_i.h | 13 +- include/soc/qcom/rmnet_qmi.h | 4 + include/trace/events/dfc.h | 27 ++++ 6 files changed, 243 insertions(+), 56 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c index e5f991c26bfc..98199521f6f8 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c @@ -533,10 +533,8 @@ static void rmnet_map_flush_tx_packet_work(struct work_struct *work) } spin_unlock_irqrestore(&port->agg_lock, flags); - if (skb) { - skb->protocol = htons(ETH_P_MAP); + if (skb) dev_queue_xmit(skb); - } kfree(work); } @@ -598,6 +596,7 @@ void rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port) dev_queue_xmit(skb); return; } + port->agg_skb->protocol = htons(ETH_P_MAP); port->agg_count = 1; getnstimeofday(&port->agg_time); dev_kfree_skb_any(skb); @@ -616,7 +615,6 @@ void rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port) port->agg_state = 0; spin_unlock_irqrestore(&port->agg_lock, flags); hrtimer_cancel(&port->hrtimer); - agg_skb->protocol = htons(ETH_P_MAP); dev_queue_xmit(agg_skb); goto new_packet; } @@ -663,3 +661,31 @@ void rmnet_map_tx_aggregate_exit(struct rmnet_port *port) spin_unlock_irqrestore(&port->agg_lock, flags); } + +void rmnet_map_tx_qmap_cmd(struct sk_buff *qmap_skb) +{ + struct rmnet_port *port; + struct sk_buff *agg_skb; + unsigned long flags; + + port = rmnet_get_port(qmap_skb->dev); + + if (port->data_format & RMNET_EGRESS_FORMAT_AGGREGATION) { + spin_lock_irqsave(&port->agg_lock, flags); + if (port->agg_skb) { + agg_skb = port->agg_skb; + port->agg_skb = 0; + port->agg_count = 0; + memset(&port->agg_time, 0, sizeof(struct timespec)); + port->agg_state = 0; + spin_unlock_irqrestore(&port->agg_lock, flags); + hrtimer_cancel(&port->hrtimer); + dev_queue_xmit(agg_skb); + } else { + spin_unlock_irqrestore(&port->agg_lock, flags); + } + } + + dev_queue_xmit(qmap_skb); +} +EXPORT_SYMBOL(rmnet_map_tx_qmap_cmd); diff --git a/drivers/soc/qcom/dfc_qmi.c b/drivers/soc/qcom/dfc_qmi.c index 0d8be8ff87ce..7a701d971b20 100644 --- a/drivers/soc/qcom/dfc_qmi.c +++ b/drivers/soc/qcom/dfc_qmi.c @@ -24,6 +24,33 @@ #define DFC_MAX_BEARERS_V01 16 #define DFC_MAX_QOS_ID_V01 2 +#define DFC_ACK_TYPE_DISABLE 1 +#define DFC_ACK_TYPE_THRESHOLD 2 + +struct dfc_qmap_header { + u8 pad_len:6; + u8 reserved_bit:1; + u8 cd_bit:1; + u8 mux_id; + __be16 pkt_len; +} __aligned(1); + +struct dfc_ack_cmd { + struct dfc_qmap_header header; + u8 command_name; + u8 cmd_type:2; + u8 reserved:6; + u16 reserved2; + u32 transaction_id; + u8 ver:2; + u8 reserved3:6; + u8 type:2; + u8 reserved4:6; + u16 dfc_seq; + u8 reserved5[3]; + u8 bearer_id; +} __aligned(1); + struct dfc_qmi_data { void *rmnet_port; struct workqueue_struct *dfc_wq; @@ -514,25 +541,75 @@ static int dfc_init_service(struct dfc_qmi_data *data, struct qmi_info *qmi) return dfc_indication_register_req(&data->handle, &data->ssctl, 1); } -static int dfc_bearer_flow_ctl(struct net_device *dev, struct qos_info *qos, - u8 bearer_id, u32 grant_size, int enable) +static void +dfc_send_ack(struct net_device *dev, u8 bearer_id, u16 seq, u8 mux_id, u8 type) +{ + struct qos_info *qos = rmnet_get_qos_pt(dev); + struct sk_buff *skb; + struct dfc_ack_cmd *msg; + int data_size = sizeof(struct dfc_ack_cmd); + int header_size = sizeof(struct dfc_qmap_header); + + if (!qos) + return; + + skb = alloc_skb(data_size, GFP_ATOMIC); + if (!skb) + return; + + msg = (struct dfc_ack_cmd *)skb_put(skb, data_size); + memset(msg, 0, data_size); + + msg->header.cd_bit = 1; + msg->header.mux_id = mux_id; + msg->header.pkt_len = htons(data_size - header_size); + + msg->bearer_id = bearer_id; + msg->command_name = 4; + msg->cmd_type = 0; + msg->dfc_seq = htons(seq); + msg->type = type; + msg->ver = 2; + msg->transaction_id = htonl(qos->tran_num); + + skb->dev = qos->real_dev; + skb->protocol = htons(ETH_P_MAP); + + trace_dfc_qmap_cmd(mux_id, bearer_id, seq, type, qos->tran_num); + qos->tran_num++; + + rmnet_map_tx_qmap_cmd(skb); +} + +static int dfc_bearer_flow_ctl(struct net_device *dev, + struct rmnet_bearer_map *bearer, + struct qos_info *qos) { struct list_head *p; struct rmnet_flow_map *itm; int rc = 0, qlen; + int enable; + + enable = bearer->grant_size ? 1 : 0; list_for_each(p, &qos->flow_head) { itm = list_entry(p, struct rmnet_flow_map, list); - if (itm->bearer_id == bearer_id) { + if (itm->bearer_id == bearer->bearer_id) { qlen = tc_qdisc_flow_control(dev, itm->tcm_handle, enable); trace_dfc_qmi_tc(itm->bearer_id, itm->flow_id, - grant_size, qlen, itm->tcm_handle, - enable); + bearer->grant_size, qlen, + itm->tcm_handle, enable); rc++; } } + + if (enable == 0 && bearer->ack_req) + dfc_send_ack(dev, bearer->bearer_id, + bearer->seq, qos->mux_id, + DFC_ACK_TYPE_DISABLE); + return rc; } @@ -550,6 +627,8 @@ static int dfc_all_bearer_flow_ctl(struct net_device *dev, bearer_itm = list_entry(p, struct rmnet_bearer_map, list); bearer_itm->grant_size = fc_info->num_bytes; + bearer_itm->grant_thresh = + qmi_rmnet_grant_per(bearer_itm->grant_size); bearer_itm->seq = fc_info->seq_num; bearer_itm->ack_req = ack_req; } @@ -565,6 +644,12 @@ static int dfc_all_bearer_flow_ctl(struct net_device *dev, flow_itm->tcm_handle, enable); rc++; } + + if (enable == 0 && ack_req) + dfc_send_ack(dev, fc_info->bearer_id, + fc_info->seq_num, fc_info->mux_id, + DFC_ACK_TYPE_DISABLE); + return rc; } @@ -584,12 +669,12 @@ static int dfc_update_fc_map(struct net_device *dev, struct qos_info *qos, action = 0; itm->grant_size = fc_info->num_bytes; + itm->grant_thresh = qmi_rmnet_grant_per(itm->grant_size); itm->seq = fc_info->seq_num; itm->ack_req = ack_req; if (action != -1) - rc = dfc_bearer_flow_ctl(dev, qos, fc_info->bearer_id, - itm->grant_size, action); + rc = dfc_bearer_flow_ctl(dev, itm, qos); } else { pr_debug("grant %u before flow activate", fc_info->num_bytes); qos->default_grant = fc_info->num_bytes; @@ -614,18 +699,10 @@ static void dfc_do_burst_flow_control(struct work_struct *work) return; } -get_lock: local_bh_disable(); - /* This will drop some messages but that is - * unavoidable for now since the notifier callback is - * protected by rtnl_lock() and destroy_workqueue() - * will dead lock with this. - */ - if (!rtnl_trylock()) { + while (!rtnl_trylock()) { if (!svc_ind->data->restart_state) { - local_bh_enable(); - msleep(20); - goto get_lock; + cond_resched_softirq(); } else { kfree(ind); kfree(svc_ind); @@ -713,6 +790,11 @@ static void dfc_bearer_limit_work(struct work_struct *work) } } + if (dfc_ind->bearer->ack_req) + dfc_send_ack(dfc_ind->dev, dfc_ind->bearer->bearer_id, + dfc_ind->bearer->seq, dfc_ind->qos->mux_id, + DFC_ACK_TYPE_DISABLE); + done: kfree(dfc_ind); rtnl_unlock(); @@ -899,11 +981,12 @@ void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, struct rmnet_flow_map *itm; struct dfc_qmi_data *data; int ip_type; + u32 start_grant; ip_type = (ip_hdr(skb)->version == IP_VER_6) ? AF_INET6 : AF_INET; itm = qmi_rmnet_get_flow_map(qos, skb->mark, ip_type); - if (!itm) + if (unlikely(!itm)) return; bearer = qmi_rmnet_get_bearer_map(qos, itm->bearer_id); @@ -915,11 +998,22 @@ void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, if (!bearer->grant_size) return; - if (skb->len < bearer->grant_size) { + start_grant = bearer->grant_size; + if (skb->len >= bearer->grant_size) + bearer->grant_size = 0; + else bearer->grant_size -= skb->len; - return; + + if (start_grant > bearer->grant_thresh && + bearer->grant_size <= bearer->grant_thresh) { + dfc_send_ack(dev, bearer->bearer_id, + bearer->seq, qos->mux_id, + DFC_ACK_TYPE_THRESHOLD); } + if (bearer->grant_size) + return; + data = (struct dfc_qmi_data *)qmi_rmnet_has_dfc_client(qmi); if (!data) return; @@ -935,8 +1029,6 @@ void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, dfc_ind->bearer = bearer; dfc_ind->data = data; - bearer->grant_size = 0; - /* stop the flow in hope that the worker thread is * immediately scheduled beyond this point of time */ diff --git a/drivers/soc/qcom/qmi_rmnet.c b/drivers/soc/qcom/qmi_rmnet.c index cb23b80c462d..812fc01a2150 100644 --- a/drivers/soc/qcom/qmi_rmnet.c +++ b/drivers/soc/qcom/qmi_rmnet.c @@ -19,6 +19,7 @@ #include #include "qmi_rmnet_i.h" #include +#include #define NLMSG_FLOW_ACTIVATE 1 #define NLMSG_FLOW_DEACTIVATE 2 @@ -31,6 +32,10 @@ #define PS_INTERVAL (0x0004 * HZ) #define NO_DELAY (0x0000 * HZ) +#ifdef CONFIG_QCOM_QMI_DFC +static unsigned int qmi_rmnet_scale_factor = 5; +#endif + struct qmi_elem_info data_ep_id_type_v01_ei[] = { { .data_type = QMI_SIGNED_4_BYTE_ENUM, @@ -228,20 +233,26 @@ static int qmi_rmnet_add_flow(struct net_device *dev, struct tcmsg *tcm, qmi_rmnet_update_flow_link(qmi, dev, itm, 1); qmi_rmnet_update_flow_map(itm, &new_map); list_add(&itm->list, &qos_info->flow_head); - } - bearer = qmi_rmnet_get_bearer_map(qos_info, new_map.bearer_id); - if (bearer) { - bearer->flow_ref++; - } else { - bearer = kzalloc(sizeof(*bearer), GFP_KERNEL); - if (!bearer) - return -ENOMEM; + bearer = qmi_rmnet_get_bearer_map(qos_info, new_map.bearer_id); + if (bearer) { + bearer->flow_ref++; + } else { + bearer = kzalloc(sizeof(*bearer), GFP_KERNEL); + if (!bearer) + return -ENOMEM; + + bearer->bearer_id = new_map.bearer_id; + bearer->flow_ref = 1; + bearer->grant_size = qos_info->default_grant; + bearer->grant_thresh = + qmi_rmnet_grant_per(bearer->grant_size); + qos_info->default_grant = DEFAULT_GRANT; + list_add(&bearer->list, &qos_info->bearer_head); + } - bearer->bearer_id = new_map.bearer_id; - bearer->flow_ref = 1; - bearer->grant_size = qos_info->default_grant; - list_add(&bearer->list, &qos_info->bearer_head); + tc_qdisc_flow_control(dev, itm->tcm_handle, + bearer->grant_size > 0 ? 1 : 0); } return 0; @@ -276,18 +287,19 @@ qmi_rmnet_del_flow(struct net_device *dev, struct tcmsg *tcm, new_map.ip_type, itm->tcm_handle, 0); qmi_rmnet_update_flow_link(qmi, dev, itm, 0); list_del(&itm->list); - } - /*clear bearer map*/ - bearer = qmi_rmnet_get_bearer_map(qos_info, new_map.bearer_id); - if (bearer && --bearer->flow_ref == 0) { - list_del(&bearer->list); - bearer_removed = 1; + /*clear bearer map*/ + bearer = qmi_rmnet_get_bearer_map(qos_info, new_map.bearer_id); + if (bearer && --bearer->flow_ref == 0) { + list_del(&bearer->list); + bearer_removed = 1; + } + + kfree(itm); + if (bearer_removed) + kfree(bearer); } - kfree(itm); - if (bearer_removed) - kfree(bearer); return 0; } @@ -311,7 +323,9 @@ static int qmi_rmnet_enable_all_flows(struct qmi_info *qmi) if (bearer) { if (bearer->grant_size == 0) need_enable = 1; - bearer->grant_size = qos->default_grant; + bearer->grant_size = DEFAULT_GRANT; + bearer->grant_thresh = + qmi_rmnet_grant_per(DEFAULT_GRANT); if (need_enable) { qlen = tc_qdisc_flow_control(qmi->flow[i].dev, m->tcm_handle, 1); @@ -324,6 +338,27 @@ static int qmi_rmnet_enable_all_flows(struct qmi_info *qmi) return 0; } + +static int qmi_rmnet_set_scale_factor(const char *val, + const struct kernel_param *kp) +{ + int ret; + unsigned int num = 0; + + ret = kstrtouint(val, 10, &num); + if (ret != 0 || num == 0) + return -EINVAL; + + return param_set_uint(val, kp); +} + +static const struct kernel_param_ops qmi_rmnet_scale_ops = { + .set = qmi_rmnet_set_scale_factor, + .get = param_get_uint, +}; + +module_param_cb(qmi_rmnet_scale_factor, &qmi_rmnet_scale_ops, + &qmi_rmnet_scale_factor, 0664); #else static inline void qmi_rmnet_update_flow_link(struct qmi_info *qmi, struct net_device *dev, @@ -531,6 +566,12 @@ void qmi_rmnet_burst_fc_check(struct net_device *dev, struct sk_buff *skb) } EXPORT_SYMBOL(qmi_rmnet_burst_fc_check); +inline unsigned int qmi_rmnet_grant_per(unsigned int grant) +{ + return grant / qmi_rmnet_scale_factor; +} +EXPORT_SYMBOL(qmi_rmnet_grant_per); + void *qmi_rmnet_qos_init(struct net_device *real_dev, u8 mux_id) { struct qos_info *qos; diff --git a/drivers/soc/qcom/qmi_rmnet_i.h b/drivers/soc/qcom/qmi_rmnet_i.h index 770cb2b3d65e..a2c4ce1e4897 100644 --- a/drivers/soc/qcom/qmi_rmnet_i.h +++ b/drivers/soc/qcom/qmi_rmnet_i.h @@ -37,6 +37,7 @@ struct rmnet_bearer_map { u8 bearer_id; int flow_ref; u32 grant_size; + u32 grant_thresh; u16 seq; u8 ack_req; }; @@ -93,6 +94,8 @@ struct data_ep_id_type_v01 { extern struct qmi_elem_info data_ep_id_type_v01_ei[]; +void *qmi_rmnet_has_dfc_client(struct qmi_info *qmi); + #ifdef CONFIG_QCOM_QMI_DFC struct rmnet_flow_map * qmi_rmnet_get_flow_map(struct qos_info *qos_info, @@ -101,6 +104,8 @@ qmi_rmnet_get_flow_map(struct qos_info *qos_info, struct rmnet_bearer_map * qmi_rmnet_get_bearer_map(struct qos_info *qos_info, u8 bearer_id); +unsigned int qmi_rmnet_grant_per(unsigned int grant); + int dfc_qmi_client_init(void *port, int index, struct qmi_info *qmi); void dfc_qmi_client_exit(void *dfc_data); @@ -108,8 +113,6 @@ void dfc_qmi_client_exit(void *dfc_data); void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, struct sk_buff *skb, struct qmi_info *qmi); - -void *qmi_rmnet_has_dfc_client(struct qmi_info *qmi); #else static inline struct rmnet_flow_map * qmi_rmnet_get_flow_map(struct qos_info *qos_info, @@ -139,12 +142,6 @@ dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, struct sk_buff *skb, struct qmi_info *qmi) { } - -static inline -void *qmi_rmnet_has_dfc_client(struct qmi_info *qmi) -{ - return NULL; -} #endif #ifdef CONFIG_QCOM_QMI_POWER_COLLAPSE diff --git a/include/soc/qcom/rmnet_qmi.h b/include/soc/qcom/rmnet_qmi.h index 4d2fc0277547..0b5debd3157c 100644 --- a/include/soc/qcom/rmnet_qmi.h +++ b/include/soc/qcom/rmnet_qmi.h @@ -15,6 +15,10 @@ #define _RMNET_QMI_H #include +#include + +void rmnet_map_tx_qmap_cmd(struct sk_buff *qmap_skb); + #ifdef CONFIG_QCOM_QMI_RMNET void *rmnet_get_qmi_pt(void *port); void *rmnet_get_qos_pt(struct net_device *dev); diff --git a/include/trace/events/dfc.h b/include/trace/events/dfc.h index 6b6a8a214014..dc763220e656 100644 --- a/include/trace/events/dfc.h +++ b/include/trace/events/dfc.h @@ -195,6 +195,33 @@ TRACE_EVENT(dfc_client_state_down, __entry->idx, __entry->from_cb) ); +TRACE_EVENT(dfc_qmap_cmd, + + TP_PROTO(u8 mux_id, u8 bearer_id, u16 seq_num, u8 type, u32 tran), + + TP_ARGS(mux_id, bearer_id, seq_num, type, tran), + + TP_STRUCT__entry( + __field(u8, mid) + __field(u8, bid) + __field(u16, seq) + __field(u8, type) + __field(u32, tran) + ), + + TP_fast_assign( + __entry->mid = mux_id; + __entry->bid = bearer_id; + __entry->seq = seq_num; + __entry->type = type; + __entry->tran = tran; + ), + + TP_printk("mux_id=%u bearer_id=%u seq_num=%u type=%u tran=%u", + __entry->mid, __entry->bid, __entry->seq, + __entry->type, __entry->tran) +); + #endif /* _TRACE_DFC_H */ /* This part must be outside protection */ -- GitLab From 8e4e63ce1a4969a563e77b8171ca68601b0d0ea1 Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Mon, 6 Aug 2018 16:58:31 -0700 Subject: [PATCH 0917/1001] qseecom: processing invalid listener request If the requested listener id is not valid, then its service entry and whitelist table don't exist, so change to use legacy listener response cmd without whitelist support in this case. Change-Id: If23b659242b7e447d67abff14ed9cdd03d928cd0 Signed-off-by: Zhen Kong --- drivers/misc/qseecom.c | 170 +++++++++++++++++++++++++---------------- 1 file changed, 103 insertions(+), 67 deletions(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index c7001596f025..d2b8c029186d 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -1773,8 +1773,9 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, int rc = 0; uint32_t lstnr; unsigned long flags; - struct qseecom_client_listener_data_irsp send_data_rsp; - struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit; + struct qseecom_client_listener_data_irsp send_data_rsp = {0}; + struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit + = {0}; struct qseecom_registered_listener_list *ptr_svc = NULL; sigset_t new_sigset; sigset_t old_sigset; @@ -1872,67 +1873,80 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, } err_resp: qseecom.send_resp_flag = 0; - ptr_svc->send_resp_flag = 0; - table = ptr_svc->sglistinfo_ptr; + if (ptr_svc) { + ptr_svc->send_resp_flag = 0; + table = ptr_svc->sglistinfo_ptr; + } if (qseecom.qsee_version < QSEE_VERSION_40) { send_data_rsp.listener_id = lstnr; send_data_rsp.status = status; - send_data_rsp.sglistinfo_ptr = - (uint32_t)virt_to_phys(table); - send_data_rsp.sglistinfo_len = - SGLISTINFO_TABLE_SIZE; - dmac_flush_range((void *)table, - (void *)table + SGLISTINFO_TABLE_SIZE); + if (table) { + send_data_rsp.sglistinfo_ptr = + (uint32_t)virt_to_phys(table); + send_data_rsp.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + } cmd_buf = (void *)&send_data_rsp; cmd_len = sizeof(send_data_rsp); } else { send_data_rsp_64bit.listener_id = lstnr; send_data_rsp_64bit.status = status; - send_data_rsp_64bit.sglistinfo_ptr = - virt_to_phys(table); - send_data_rsp_64bit.sglistinfo_len = - SGLISTINFO_TABLE_SIZE; - dmac_flush_range((void *)table, - (void *)table + SGLISTINFO_TABLE_SIZE); + if (table) { + send_data_rsp_64bit.sglistinfo_ptr = + virt_to_phys(table); + send_data_rsp_64bit.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + } cmd_buf = (void *)&send_data_rsp_64bit; cmd_len = sizeof(send_data_rsp_64bit); } - if (qseecom.whitelist_support == false) + if (qseecom.whitelist_support == false || table == NULL) *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND; else *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST; - ret = qseecom_dmabuf_cache_operations(ptr_svc->dmabuf, - QSEECOM_CACHE_CLEAN); - if (ret) - return ret; - if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) { ret = __qseecom_enable_clk(CLK_QSEE); if (ret) return ret; } - ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, + if (ptr_svc) { + ret = qseecom_dmabuf_cache_operations(ptr_svc->dmabuf, + QSEECOM_CACHE_CLEAN); + if (ret) + goto exit; + + ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, resp, sizeof(*resp)); - ptr_svc->listener_in_use = false; - __qseecom_clean_listener_sglistinfo(ptr_svc); + ptr_svc->listener_in_use = false; + __qseecom_clean_listener_sglistinfo(ptr_svc); - if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) - __qseecom_disable_clk(CLK_QSEE); + if (ret) { + pr_err("scm_call() failed with err: %d (app_id = %d)\n", + ret, data->client.app_id); + goto exit; + } - if (ret) { - pr_err("scm_call() failed with err: %d (app_id = %d)\n", - ret, data->client.app_id); - return ret; + ret = qseecom_dmabuf_cache_operations(ptr_svc->dmabuf, + QSEECOM_CACHE_INVALIDATE); + if (ret) + goto exit; + } else { + ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, + cmd_buf, cmd_len, resp, sizeof(*resp)); + if (ret) { + pr_err("scm_call() failed with err: %d (app_id = %d)\n", + ret, data->client.app_id); + goto exit; + } } - ret = qseecom_dmabuf_cache_operations(ptr_svc->dmabuf, - QSEECOM_CACHE_INVALIDATE); - if (ret) - return ret; - pr_debug("resp status %d, res= %d, app_id = %d, lstr = %d\n", status, resp->result, data->client.app_id, lstnr); if ((resp->result != QSEOS_RESULT_SUCCESS) && @@ -1941,6 +1955,10 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, resp->result, data->client.app_id, lstnr); ret = -EINVAL; } +exit: + if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) + __qseecom_disable_clk(CLK_QSEE); + } if (rc) return rc; @@ -2075,8 +2093,9 @@ static int __qseecom_reentrancy_process_incomplete_cmd( int rc = 0; uint32_t lstnr; unsigned long flags; - struct qseecom_client_listener_data_irsp send_data_rsp; - struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit; + struct qseecom_client_listener_data_irsp send_data_rsp = {0}; + struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit + = {0}; struct qseecom_registered_listener_list *ptr_svc = NULL; sigset_t new_sigset; sigset_t old_sigset; @@ -2167,30 +2186,36 @@ static int __qseecom_reentrancy_process_incomplete_cmd( status = QSEOS_RESULT_SUCCESS; } err_resp: - table = ptr_svc->sglistinfo_ptr; + if (ptr_svc) + table = ptr_svc->sglistinfo_ptr; if (qseecom.qsee_version < QSEE_VERSION_40) { send_data_rsp.listener_id = lstnr; send_data_rsp.status = status; - send_data_rsp.sglistinfo_ptr = - (uint32_t)virt_to_phys(table); - send_data_rsp.sglistinfo_len = SGLISTINFO_TABLE_SIZE; - dmac_flush_range((void *)table, - (void *)table + SGLISTINFO_TABLE_SIZE); + if (table) { + send_data_rsp.sglistinfo_ptr = + (uint32_t)virt_to_phys(table); + send_data_rsp.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + } cmd_buf = (void *)&send_data_rsp; cmd_len = sizeof(send_data_rsp); } else { send_data_rsp_64bit.listener_id = lstnr; send_data_rsp_64bit.status = status; - send_data_rsp_64bit.sglistinfo_ptr = - virt_to_phys(table); - send_data_rsp_64bit.sglistinfo_len = - SGLISTINFO_TABLE_SIZE; - dmac_flush_range((void *)table, - (void *)table + SGLISTINFO_TABLE_SIZE); + if (table) { + send_data_rsp_64bit.sglistinfo_ptr = + virt_to_phys(table); + send_data_rsp_64bit.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + } cmd_buf = (void *)&send_data_rsp_64bit; cmd_len = sizeof(send_data_rsp_64bit); } - if (qseecom.whitelist_support == false) + if (qseecom.whitelist_support == false || table == NULL) *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND; else *(uint32_t *)cmd_buf = @@ -2202,26 +2227,36 @@ static int __qseecom_reentrancy_process_incomplete_cmd( return ret; } - ret = qseecom_dmabuf_cache_operations(ptr_svc->dmabuf, + if (ptr_svc) { + ret = qseecom_dmabuf_cache_operations(ptr_svc->dmabuf, QSEECOM_CACHE_CLEAN); - if (ret) - goto exit; + if (ret) + goto exit; - ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, + ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, resp, sizeof(*resp)); - ptr_svc->listener_in_use = false; - __qseecom_clean_listener_sglistinfo(ptr_svc); - wake_up_interruptible(&ptr_svc->listener_block_app_wq); + ptr_svc->listener_in_use = false; + __qseecom_clean_listener_sglistinfo(ptr_svc); + wake_up_interruptible(&ptr_svc->listener_block_app_wq); - if (ret) { - pr_err("scm_call() failed with err: %d (app_id = %d)\n", - ret, data->client.app_id); - goto exit; - } - ret = qseecom_dmabuf_cache_operations(ptr_svc->dmabuf, + if (ret) { + pr_err("scm_call() failed with err: %d (app_id = %d)\n", + ret, data->client.app_id); + goto exit; + } + ret = qseecom_dmabuf_cache_operations(ptr_svc->dmabuf, QSEECOM_CACHE_INVALIDATE); - if (ret) - goto exit; + if (ret) + goto exit; + } else { + ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, + cmd_buf, cmd_len, resp, sizeof(*resp)); + if (ret) { + pr_err("scm_call() failed with err: %d (app_id = %d)\n", + ret, data->client.app_id); + goto exit; + } + } switch (resp->result) { case QSEOS_RESULT_BLOCKED_ON_LISTENER: @@ -2746,6 +2781,7 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, } } +unload_exit: if (found_app) { spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1); if (app_crash) { @@ -2768,7 +2804,7 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, spin_unlock_irqrestore(&qseecom.registered_app_list_lock, flags1); } -unload_exit: + if (data->client.dmabuf) qseecom_vaddr_unmap(data->client.sb_virt, data->client.sgt, data->client.attach, data->client.dmabuf); -- GitLab From f142eece7a678102ae8c96d40a673a763c9ba757 Mon Sep 17 00:00:00 2001 From: Maheshwar Ajja Date: Sun, 19 Aug 2018 18:07:27 -0700 Subject: [PATCH 0918/1001] msm: vidc: access vb2 buffer under vb2_queue lock Access vb2 buffer under vb2_queue->lock and if streaming only else vb2 buffer might be removed by vb2 framework while response handler thread is accessing it which results in video usecases failure. Change-Id: Ie4fbade47e2e4db282e8714125e7aad8712b2028 Signed-off-by: Maheshwar Ajja --- .../media/platform/msm/vidc/msm_vidc_common.c | 156 +++++++++--------- .../media/platform/msm/vidc/msm_vidc_common.h | 2 +- 2 files changed, 78 insertions(+), 80 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 7903b22677c0..137b15bf444c 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -2322,9 +2322,13 @@ struct vb2_buffer *msm_comm_get_vb_using_vidc_buffer( return NULL; } - q = &inst->bufq[port].vb2_bufq; mutex_lock(&inst->bufq[port].lock); found = false; + q = &inst->bufq[port].vb2_bufq; + if (!q->streaming) { + dprintk(VIDC_ERR, "port %d is not streaming", port); + goto unlock; + } list_for_each_entry(vb, &q->queued_list, queued_entry) { if (vb->state != VB2_BUF_STATE_ACTIVE) continue; @@ -2333,6 +2337,7 @@ struct vb2_buffer *msm_comm_get_vb_using_vidc_buffer( break; } } +unlock: mutex_unlock(&inst->bufq[port].lock); if (!found) { print_vidc_buffer(VIDC_ERR, "vb2 not found for", inst, mbuf); @@ -2343,28 +2348,52 @@ struct vb2_buffer *msm_comm_get_vb_using_vidc_buffer( } int msm_comm_vb2_buffer_done(struct msm_vidc_inst *inst, - struct vb2_buffer *vb) + struct msm_vidc_buffer *mbuf) { - u32 port; + struct vb2_buffer *vb2; + struct vb2_v4l2_buffer *vbuf; + u32 i, port; - if (!inst || !vb) { + if (!inst || !mbuf) { dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n", - __func__, inst, vb); + __func__, inst, mbuf); return -EINVAL; } - if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + if (mbuf->vvb.vb2_buf.type == + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) port = CAPTURE_PORT; - } else if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + else if (mbuf->vvb.vb2_buf.type == + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) port = OUTPUT_PORT; - } else { - dprintk(VIDC_ERR, "%s: invalid type %d\n", - __func__, vb->type); + else + return -EINVAL; + + vb2 = msm_comm_get_vb_using_vidc_buffer(inst, mbuf); + if (!vb2) return -EINVAL; - } + /* + * access vb2 buffer under q->lock and if streaming only to + * ensure the buffer was not free'd by vb2 framework while + * we are accessing it here. + */ mutex_lock(&inst->bufq[port].lock); - vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + if (inst->bufq[port].vb2_bufq.streaming) { + vbuf = to_vb2_v4l2_buffer(vb2); + vbuf->flags = mbuf->vvb.flags; + vb2->timestamp = mbuf->vvb.vb2_buf.timestamp; + for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) { + vb2->planes[i].bytesused = + mbuf->vvb.vb2_buf.planes[i].bytesused; + vb2->planes[i].data_offset = + mbuf->vvb.vb2_buf.planes[i].data_offset; + } + vb2_buffer_done(vb2, VB2_BUF_STATE_DONE); + } else { + dprintk(VIDC_ERR, "%s: port %d is not streaming\n", + __func__, port); + } mutex_unlock(&inst->bufq[port].lock); return 0; @@ -2438,12 +2467,11 @@ static void handle_ebd(enum hal_command_response cmd, void *data) { struct msm_vidc_cb_data_done *response = data; struct msm_vidc_buffer *mbuf; - struct vb2_buffer *vb, *vb2; + struct vb2_buffer *vb; struct msm_vidc_inst *inst; struct vidc_hal_ebd *empty_buf_done; - struct vb2_v4l2_buffer *vbuf; u32 planes[VIDEO_MAX_PLANES] = {0}; - u32 extra_idx = 0, i; + u32 extra_idx = 0; if (!response) { dprintk(VIDC_ERR, "Invalid response from vidc_hal\n"); @@ -2476,15 +2504,6 @@ static void handle_ebd(enum hal_command_response cmd, void *data) __func__, planes[0], planes[1]); goto exit; } - vb2 = msm_comm_get_vb_using_vidc_buffer(inst, mbuf); - - /* - * take registeredbufs.lock to update mbuf & vb2 variables together - * so that both are in sync else if mbuf and vb2 variables are not - * in sync msm_comm_compare_vb2_planes() returns false for the - * right buffer due to data_offset field mismatch. - */ - mutex_lock(&inst->registeredbufs.lock); vb = &mbuf->vvb.vb2_buf; vb->planes[0].bytesused = response->input_done.filled_len; @@ -2510,18 +2529,6 @@ static void handle_ebd(enum hal_command_response cmd, void *data) if (extra_idx && extra_idx < VIDEO_MAX_PLANES) vb->planes[extra_idx].bytesused = vb->planes[extra_idx].length; - if (vb2) { - vbuf = to_vb2_v4l2_buffer(vb2); - vbuf->flags |= mbuf->vvb.flags; - for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) { - vb2->planes[i].bytesused = - mbuf->vvb.vb2_buf.planes[i].bytesused; - vb2->planes[i].data_offset = - mbuf->vvb.vb2_buf.planes[i].data_offset; - } - } - mutex_unlock(&inst->registeredbufs.lock); - update_recon_stats(inst, &empty_buf_done->recon_stats); msm_vidc_clear_freq_entry(inst, mbuf->smem[0].device_addr); /* @@ -2535,7 +2542,7 @@ static void handle_ebd(enum hal_command_response cmd, void *data) * in put_buffer. */ msm_comm_put_vidc_buffer(inst, mbuf); - msm_comm_vb2_buffer_done(inst, vb2); + msm_comm_vb2_buffer_done(inst, mbuf); msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_EBD); kref_put_mbuf(mbuf); exit: @@ -2589,13 +2596,12 @@ static void handle_fbd(enum hal_command_response cmd, void *data) struct msm_vidc_cb_data_done *response = data; struct msm_vidc_buffer *mbuf; struct msm_vidc_inst *inst; - struct vb2_buffer *vb, *vb2; + struct vb2_buffer *vb; struct vidc_hal_fbd *fill_buf_done; - struct vb2_v4l2_buffer *vbuf; enum hal_buffer buffer_type; u64 time_usec = 0; u32 planes[VIDEO_MAX_PLANES] = {0}; - u32 extra_idx, i; + u32 extra_idx; if (!response) { dprintk(VIDC_ERR, "Invalid response from vidc_hal\n"); @@ -2623,7 +2629,6 @@ static void handle_fbd(enum hal_command_response cmd, void *data) __func__, planes[0], planes[1]); goto exit; } - vb2 = msm_comm_get_vb_using_vidc_buffer(inst, mbuf); } else { if (handle_multi_stream_buffers(inst, fill_buf_done->packet_buffer1)) @@ -2632,14 +2637,6 @@ static void handle_fbd(enum hal_command_response cmd, void *data) &fill_buf_done->packet_buffer1); goto exit; } - - /* - * take registeredbufs.lock to update mbuf & vb2 variables together - * so that both are in sync else if mbuf and vb2 variables are not - * in sync msm_comm_compare_vb2_planes() returns false for the - * right buffer due to data_offset field mismatch. - */ - mutex_lock(&inst->registeredbufs.lock); vb = &mbuf->vvb.vb2_buf; if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DROP_FRAME) @@ -2702,19 +2699,6 @@ static void handle_fbd(enum hal_command_response cmd, void *data) break; } - if (vb2) { - vbuf = to_vb2_v4l2_buffer(vb2); - vbuf->flags = mbuf->vvb.flags; - vb2->timestamp = mbuf->vvb.vb2_buf.timestamp; - for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) { - vb2->planes[i].bytesused = - mbuf->vvb.vb2_buf.planes[i].bytesused; - vb2->planes[i].data_offset = - mbuf->vvb.vb2_buf.planes[i].data_offset; - } - } - mutex_unlock(&inst->registeredbufs.lock); - /* * dma cache operations need to be performed before dma_unmap * which is done inside msm_comm_put_vidc_buffer() @@ -2726,7 +2710,7 @@ static void handle_fbd(enum hal_command_response cmd, void *data) * in put_buffer. */ msm_comm_put_vidc_buffer(inst, mbuf); - msm_comm_vb2_buffer_done(inst, vb2); + msm_comm_vb2_buffer_done(inst, mbuf); msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_FBD); kref_put_mbuf(mbuf); @@ -6134,7 +6118,6 @@ bool msm_comm_compare_vb2_plane(struct msm_vidc_inst *inst, vb = &mbuf->vvb.vb2_buf; if (vb->planes[i].m.fd == vb2->planes[i].m.fd && - vb->planes[i].data_offset == vb2->planes[i].data_offset && vb->planes[i].length == vb2->planes[i].length) { return true; } @@ -6266,6 +6249,7 @@ int msm_comm_flush_vidc_buffer(struct msm_vidc_inst *inst, { int rc; struct vb2_buffer *vb; + u32 port; if (!inst || !mbuf) { dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n", @@ -6280,11 +6264,24 @@ int msm_comm_flush_vidc_buffer(struct msm_vidc_inst *inst, return -EINVAL; } - vb->planes[0].bytesused = 0; - rc = msm_comm_vb2_buffer_done(inst, vb); - if (rc) - print_vidc_buffer(VIDC_ERR, - "vb2_buffer_done failed for", inst, mbuf); + if (mbuf->vvb.vb2_buf.type == + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + port = CAPTURE_PORT; + else if (mbuf->vvb.vb2_buf.type == + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + port = OUTPUT_PORT; + else + return -EINVAL; + + mutex_lock(&inst->bufq[port].lock); + if (inst->bufq[port].vb2_bufq.streaming) { + vb->planes[0].bytesused = 0; + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + } else { + dprintk(VIDC_ERR, "%s: port %d is not streaming\n", + __func__, port); + } + mutex_unlock(&inst->bufq[port].lock); return rc; } @@ -6449,23 +6446,24 @@ struct msm_vidc_buffer *msm_comm_get_vidc_buffer(struct msm_vidc_inst *inst, } mutex_lock(&inst->registeredbufs.lock); - if (inst->session_type == MSM_VIDC_DECODER) { + /* + * for encoder input, client may queue the same buffer with different + * fd before driver returned old buffer to the client. This buffer + * should be treated as new buffer Search the list with fd so that + * it will be treated as new msm_vidc_buffer. + */ + if (is_encode_session(inst) && vb2->type == + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { list_for_each_entry(mbuf, &inst->registeredbufs.list, list) { - if (msm_comm_compare_dma_planes(inst, mbuf, - dma_planes)) { + if (msm_comm_compare_vb2_planes(inst, mbuf, vb2)) { found = true; break; } } } else { - /* - * for encoder, client may queue the same buffer with different - * fd before driver returned old buffer to the client. This - * buffer should be treated as new buffer. Search the list with - * fd so that it will be treated as new msm_vidc_buffer. - */ list_for_each_entry(mbuf, &inst->registeredbufs.list, list) { - if (msm_comm_compare_vb2_planes(inst, mbuf, vb2)) { + if (msm_comm_compare_dma_planes(inst, mbuf, + dma_planes)) { found = true; break; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h index c0dfc729ffc6..16eed4928f03 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h @@ -213,7 +213,7 @@ void msm_comm_put_vidc_buffer(struct msm_vidc_inst *inst, void handle_release_buffer_reference(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf); int msm_comm_vb2_buffer_done(struct msm_vidc_inst *inst, - struct vb2_buffer *vb); + struct msm_vidc_buffer *mbuf); int msm_comm_flush_vidc_buffer(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf); int msm_comm_unmap_vidc_buffer(struct msm_vidc_inst *inst, -- GitLab From 69797674afd027bc68bdf4581e145bfde09d39c7 Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Fri, 17 Aug 2018 17:14:12 -0700 Subject: [PATCH 0919/1001] mhi: controller: qcom: route modem SBL logs to an ipc logging buffer To debug modem boot failures, route modem SBL logs to an ipc logging buffer. CRs-Fixed: 2299820 Change-Id: Ia4171c63477508a40351f178abf935494cab0350 Signed-off-by: Sujeev Dias --- drivers/bus/mhi/controllers/mhi_arch_qcom.c | 114 ++++++++++++++++++++ drivers/bus/mhi/controllers/mhi_qcom.h | 3 + 2 files changed, 117 insertions(+) diff --git a/drivers/bus/mhi/controllers/mhi_arch_qcom.c b/drivers/bus/mhi/controllers/mhi_arch_qcom.c index c2c88d443ec7..f6ef83ff7ce0 100644 --- a/drivers/bus/mhi/controllers/mhi_arch_qcom.c +++ b/drivers/bus/mhi/controllers/mhi_arch_qcom.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -38,6 +39,16 @@ struct arch_info { struct dma_iommu_mapping *mapping; }; +struct mhi_bl_info { + struct mhi_device *mhi_device; + async_cookie_t cookie; + void *ipc_log; +}; + +/* ipc log markings */ +#define DLOG "Dev->Host: " +#define HLOG "Host: " + #ifdef CONFIG_MHI_DEBUG #define MHI_IPC_LOG_PAGES (100) @@ -142,6 +153,107 @@ void mhi_arch_esoc_ops_power_off(void *priv, bool mdm_state) mhi_dev->powered_on = false; } +static void mhi_bl_dl_cb(struct mhi_device *mhi_dev, + struct mhi_result *mhi_result) +{ + struct mhi_bl_info *mhi_bl_info = mhi_device_get_devdata(mhi_dev); + char *buf = mhi_result->buf_addr; + + /* force a null at last character */ + buf[mhi_result->bytes_xferd - 1] = 0; + + ipc_log_string(mhi_bl_info->ipc_log, "%s %s", DLOG, buf); +} + +static void mhi_bl_dummy_cb(struct mhi_device *mhi_dev, + struct mhi_result *mhi_result) +{ +} + +static void mhi_bl_remove(struct mhi_device *mhi_dev) +{ + struct mhi_bl_info *mhi_bl_info = mhi_device_get_devdata(mhi_dev); + + ipc_log_string(mhi_bl_info->ipc_log, HLOG "Received Remove notif.\n"); + + /* wait for boot monitor to exit */ + async_synchronize_cookie(mhi_bl_info->cookie + 1); +} + +static void mhi_bl_boot_monitor(void *data, async_cookie_t cookie) +{ + struct mhi_bl_info *mhi_bl_info = data; + struct mhi_device *mhi_device = mhi_bl_info->mhi_device; + struct mhi_controller *mhi_cntrl = mhi_device->mhi_cntrl; + /* 15 sec timeout for booting device */ + const u32 timeout = msecs_to_jiffies(15000); + + /* wait for device to enter boot stage */ + wait_event_timeout(mhi_cntrl->state_event, mhi_cntrl->ee == MHI_EE_AMSS + || mhi_cntrl->ee == MHI_EE_DISABLE_TRANSITION, + timeout); + + if (mhi_cntrl->ee == MHI_EE_AMSS) { + ipc_log_string(mhi_bl_info->ipc_log, HLOG + "Device successfully booted to mission mode\n"); + + mhi_unprepare_from_transfer(mhi_device); + } else { + ipc_log_string(mhi_bl_info->ipc_log, HLOG + "Device failed to boot to mission mode, ee = %s\n", + TO_MHI_EXEC_STR(mhi_cntrl->ee)); + } +} + +static int mhi_bl_probe(struct mhi_device *mhi_dev, + const struct mhi_device_id *id) +{ + char node_name[32]; + struct mhi_bl_info *mhi_bl_info; + + mhi_bl_info = devm_kzalloc(&mhi_dev->dev, sizeof(*mhi_bl_info), + GFP_KERNEL); + if (!mhi_bl_info) + return -ENOMEM; + + snprintf(node_name, sizeof(node_name), "mhi_bl_%04x_%02u.%02u.%02u", + mhi_dev->dev_id, mhi_dev->domain, mhi_dev->bus, mhi_dev->slot); + + mhi_bl_info->ipc_log = ipc_log_context_create(MHI_IPC_LOG_PAGES, + node_name, 0); + if (!mhi_bl_info->ipc_log) + return -EINVAL; + + mhi_bl_info->mhi_device = mhi_dev; + mhi_device_set_devdata(mhi_dev, mhi_bl_info); + + ipc_log_string(mhi_bl_info->ipc_log, HLOG + "Entered SBL, Session ID:0x%x\n", + mhi_dev->mhi_cntrl->session_id); + + /* start a thread to monitor entering mission mode */ + mhi_bl_info->cookie = async_schedule(mhi_bl_boot_monitor, mhi_bl_info); + + return 0; +} + +static const struct mhi_device_id mhi_bl_match_table[] = { + { .chan = "BL" }, + {}, +}; + +static struct mhi_driver mhi_bl_driver = { + .id_table = mhi_bl_match_table, + .remove = mhi_bl_remove, + .probe = mhi_bl_probe, + .ul_xfer_cb = mhi_bl_dummy_cb, + .dl_xfer_cb = mhi_bl_dl_cb, + .driver = { + .name = "MHI_BL", + .owner = THIS_MODULE, + }, +}; + int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) { struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl); @@ -212,6 +324,8 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl) /* save reference state for pcie config space */ arch_info->ref_pcie_state = pci_store_saved_state( mhi_dev->pci_dev); + + mhi_driver_register(&mhi_bl_driver); } return mhi_arch_set_bus_request(mhi_cntrl, 1); diff --git a/drivers/bus/mhi/controllers/mhi_qcom.h b/drivers/bus/mhi/controllers/mhi_qcom.h index 1d06dfeeb138..30333c3fb385 100644 --- a/drivers/bus/mhi/controllers/mhi_qcom.h +++ b/drivers/bus/mhi/controllers/mhi_qcom.h @@ -24,6 +24,9 @@ #define MHI_RPM_SUSPEND_TMR_MS (1000) #define MHI_PCI_BAR_NUM (0) +extern const char * const mhi_ee_str[MHI_EE_MAX]; +#define TO_MHI_EXEC_STR(ee) (ee >= MHI_EE_MAX ? "INVALID_EE" : mhi_ee_str[ee]) + struct mhi_dev { struct pci_dev *pci_dev; u32 smmu_cfg; -- GitLab From 57b21993715e5ea7a16818a543866bc329089851 Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Fri, 17 Aug 2018 17:15:09 -0700 Subject: [PATCH 0920/1001] ARM: dts: msm: auto start Boot Log (BL) and disable its outbound channel Boot Log is an inbound channel only, therefore disable outbound channel. Also, automatically move channel to start state after probe since BL client expects it. CRs-Fixed: 2299820 Change-Id: Iedb3635181d794a75ca7152f77d95ded9f4abd53 Signed-off-by: Sujeev Dias --- arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi | 26 ++++-------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi b/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi index e240b35a8dda..3479d30dbb70 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi @@ -258,17 +258,6 @@ mhi,ee = <0x4>; }; - mhi_chan@24 { - reg = <24>; - label = "BL"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x2>; - }; - mhi_chan@25 { reg = <25>; label = "BL"; @@ -278,6 +267,8 @@ mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <0x2>; + mhi,auto-queue; + mhi,auto-start; }; mhi_chan@26 { @@ -686,17 +677,6 @@ mhi,ee = <0x4>; }; - mhi_chan@24 { - reg = <24>; - label = "BL"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x2>; - }; - mhi_chan@25 { reg = <25>; label = "BL"; @@ -706,6 +686,8 @@ mhi,data-type = <0>; mhi,doorbell-mode = <2>; mhi,ee = <0x2>; + mhi,auto-queue; + mhi,auto-start; }; mhi_chan@26 { -- GitLab From 2129ce57d71f4115a6c565ec1aac2fe819c91a5c Mon Sep 17 00:00:00 2001 From: Shivaprasad Hongal Date: Wed, 22 Aug 2018 10:53:31 -0700 Subject: [PATCH 0921/1001] Revert "pfk: keymaster support to set/clear ice keys" This reverts commit cd1be5fac519d6089289e513deb3b50ae3df9637. Reverting to have FBE in sync with upstream implementation. Change-Id: I21d84211c0469d1a4b3d8685033a64cc04854109 Signed-off-by: Shivaprasad Hongal --- security/pfe/Kconfig | 13 --- security/pfe/Makefile | 1 - security/pfe/pfk_ice.c | 206 +++++++++-------------------------------- security/pfe/pfk_ice.h | 26 ------ 4 files changed, 42 insertions(+), 204 deletions(-) diff --git a/security/pfe/Kconfig b/security/pfe/Kconfig index 9bc24a4dfcf2..0cd9e81a4952 100644 --- a/security/pfe/Kconfig +++ b/security/pfe/Kconfig @@ -25,17 +25,4 @@ config PFK Information is used when file is encrypted later using ICE or dm crypto engine -config PFK_WRAPPED_KEY_SUPPORTED - bool "Per-File-Key driver with wrapped key support" - depends on SECURITY - depends on SECURITY_SELINUX - depends on QSEECOM - depends on PFK - default n - help - Adds wrapped key support in PFK driver. Instead of setting - the key directly from vold, it unwraps the key in a secure - environment and sets the key in ICE. This is because the key - is not directly available in HLOS and needs to be unwrapped - in a secure environment. endmenu diff --git a/security/pfe/Makefile b/security/pfe/Makefile index c52caf90a987..242a2165fccb 100644 --- a/security/pfe/Makefile +++ b/security/pfe/Makefile @@ -5,7 +5,6 @@ ccflags-y += -Isecurity/selinux -Isecurity/selinux/include ccflags-y += -Ifs/ext4 ccflags-y += -Ifs/crypto -ccflags-y += -Idrivers/misc obj-$(CONFIG_PFT) += pft.o obj-$(CONFIG_PFK) += pfk.o pfk_kc.o pfk_ice.o pfk_ext4.o diff --git a/security/pfe/pfk_ice.c b/security/pfe/pfk_ice.c index 6452b4220136..bf60dd18dd76 100644 --- a/security/pfe/pfk_ice.c +++ b/security/pfe/pfk_ice.c @@ -24,7 +24,7 @@ #include #include #include "pfk_ice.h" -#include "qseecom_kernel.h" + /**********************************/ /** global definitions **/ @@ -55,120 +55,48 @@ TZ_SYSCALL_CREATE_PARAM_ID_1( \ TZ_SYSCALL_PARAM_TYPE_VAL) -#define CONTEXT_SIZE 0x1000 - -#define KEYMASTER_UTILS_CMD_ID 0x200UL -#define KEYMASTER_SET_ICE_KEY (KEYMASTER_UTILS_CMD_ID + 18UL) -#define KEYMASTER_CLEAR_ICE_KEY (KEYMASTER_UTILS_CMD_ID + 19UL) - #define ICE_KEY_SIZE 32 #define ICE_SALT_SIZE 32 static uint8_t ice_key[ICE_KEY_SIZE]; static uint8_t ice_salt[ICE_KEY_SIZE]; -static struct qseecom_handle *qhandle; - -static int set_wrapped_key(uint32_t index, const uint8_t *key, - const uint8_t *salt) -{ - int ret = 0; - u32 set_req_len = 0; - u32 set_rsp_len = 0; - struct pfk_ice_key_req *set_req_buf; - struct pfk_ice_key_rsp *set_rsp_buf; - - memcpy(ice_key, key, sizeof(ice_key)); - memcpy(ice_salt, salt, sizeof(ice_salt)); - - if (!qhandle) { - ret = qseecom_start_app(&qhandle, "keymaster64", - CONTEXT_SIZE); - if (ret) { - pr_err("Qseecom start app failed\n"); - return ret; - } - } - - set_req_buf = (struct pfk_ice_key_req *) qhandle->sbuf; - set_req_buf->cmd_id = KEYMASTER_SET_ICE_KEY; - set_req_buf->index = index; - set_req_buf->ice_key_offset = sizeof(struct pfk_ice_key_req); - set_req_buf->ice_key_size = ICE_KEY_SIZE; - set_req_buf->ice_salt_offset = set_req_buf->ice_key_offset + - set_req_buf->ice_key_size; - set_req_buf->ice_salt_size = ICE_SALT_SIZE; - - memcpy((uint8_t *) set_req_buf + set_req_buf->ice_key_offset, ice_key, - set_req_buf->ice_key_size); - memcpy((uint8_t *) set_req_buf + set_req_buf->ice_salt_offset, ice_salt, - set_req_buf->ice_salt_size); - - set_req_len = sizeof(struct pfk_ice_key_req) + set_req_buf->ice_key_size - + set_req_buf->ice_salt_size; - - set_rsp_buf = (struct pfk_ice_key_rsp *) (qhandle->sbuf + - set_req_len); - set_rsp_len = sizeof(struct pfk_ice_key_rsp); - - ret = qseecom_send_command(qhandle, - set_req_buf, set_req_len, - set_rsp_buf, set_rsp_len); - - if (ret) - pr_err("%s: Set wrapped key error: Status %d\n", __func__, - set_rsp_buf->ret); - - return ret; -} - -static int clear_wrapped_key(uint32_t index) -{ - int ret = 0; - - u32 clear_req_len = 0; - u32 clear_rsp_len = 0; - struct pfk_ice_key_req *clear_req_buf; - struct pfk_ice_key_rsp *clear_rsp_buf; - - clear_req_buf = (struct pfk_ice_key_req *) qhandle->sbuf; - memset(clear_req_buf, 0, sizeof(qhandle->sbuf)); - clear_req_buf->cmd_id = KEYMASTER_CLEAR_ICE_KEY; - clear_req_buf->index = index; - clear_req_len = sizeof(struct pfk_ice_key_req); - clear_rsp_buf = (struct pfk_ice_key_rsp *) (qhandle->sbuf + - QSEECOM_ALIGN(clear_req_len)); - clear_rsp_len = sizeof(struct pfk_ice_key_rsp); - - ret = qseecom_send_command(qhandle, clear_req_buf, clear_req_len, - clear_rsp_buf, clear_rsp_len); - if (ret) - pr_err("%s: Clear wrapped key error: Status %d\n", __func__, - clear_rsp_buf->ret); - - return ret; -} - -static int set_key(uint32_t index, const uint8_t *key, const uint8_t *salt) +int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, + char *storage_type) { struct scm_desc desc = {0}; - int ret = 0; - uint32_t smc_id = 0; + int ret, ret1; char *tzbuf_key = (char *)ice_key; char *tzbuf_salt = (char *)ice_salt; + char *s_type = storage_type; + uint32_t smc_id = 0; u32 tzbuflen_key = sizeof(ice_key); u32 tzbuflen_salt = sizeof(ice_salt); + if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { + pr_err("%s Invalid index %d\n", __func__, index); + return -EINVAL; + } + if (!key || !salt) { + pr_err("%s Invalid key/salt\n", __func__); + return -EINVAL; + } + if (!tzbuf_key || !tzbuf_salt) { pr_err("%s No Memory\n", __func__); return -ENOMEM; } + if (s_type == NULL) { + pr_err("%s Invalid Storage type\n", __func__); + return -EINVAL; + } + memset(tzbuf_key, 0, tzbuflen_key); memset(tzbuf_salt, 0, tzbuflen_salt); - memcpy(ice_key, key, sizeof(ice_key)); - memcpy(ice_salt, salt, sizeof(ice_salt)); + memcpy(ice_key, key, tzbuflen_key); + memcpy(ice_salt, salt, tzbuflen_salt); dmac_flush_range(tzbuf_key, tzbuf_key + tzbuflen_key); dmac_flush_range(tzbuf_salt, tzbuf_salt + tzbuflen_salt); @@ -182,84 +110,33 @@ static int set_key(uint32_t index, const uint8_t *key, const uint8_t *salt) desc.args[3] = virt_to_phys(tzbuf_salt); desc.args[4] = tzbuflen_salt; - ret = scm_call2(smc_id, &desc); - if (ret) - pr_err("%s:SCM call Error: 0x%x\n", __func__, ret); - - return ret; -} - -static int clear_key(uint32_t index) -{ - struct scm_desc desc = {0}; - int ret = 0; - uint32_t smc_id = 0; - - smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; - - desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; - desc.args[0] = index; - - ret = scm_call2(smc_id, &desc); - if (ret) - pr_err("%s:SCM call Error: 0x%x\n", __func__, ret); - return ret; -} - -int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, - char *storage_type) -{ - int ret = 0, ret1 = 0; - char *s_type = storage_type; - - if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { - pr_err("%s Invalid index %d\n", __func__, index); - return -EINVAL; - } - if (!key || !salt) { - pr_err("%s Invalid key/salt\n", __func__); - return -EINVAL; - } - - if (s_type == NULL) { - pr_err("%s Invalid Storage type\n", __func__); - return -EINVAL; - } - ret = qcom_ice_setup_ice_hw((const char *)s_type, true); if (ret) { pr_err("%s: could not enable clocks: %d\n", __func__, ret); goto out; } - if (pfk_wrapped_key_supported()) { - pr_debug("%s: Setting wrapped key\n", __func__); - ret = set_wrapped_key(index, key, salt); - } else { - pr_debug("%s: Setting keys with QSEE kernel\n", __func__); - ret = set_key(index, key, salt); - } - + ret = scm_call2(smc_id, &desc); if (ret) { pr_err("%s: Set Key Error: %d\n", __func__, ret); if (ret == -EBUSY) { if (qcom_ice_setup_ice_hw((const char *)s_type, false)) pr_err("%s: clock disable failed\n", __func__); - goto out; + goto out; } /* Try to invalidate the key to keep ICE in proper state */ - if (pfk_wrapped_key_supported()) - ret1 = clear_wrapped_key(index); - else - ret1 = clear_key(index); - + smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; + desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; + desc.args[0] = index; + ret1 = scm_call2(smc_id, &desc); if (ret1) - pr_err("%s: Invalidate key error: %d\n", __func__, ret); + pr_err("%s: Invalidate Key Error: %d\n", __func__, + ret1); } ret1 = qcom_ice_setup_ice_hw((const char *)s_type, false); - if (ret) - pr_err("%s: Error %d disabling clocks\n", __func__, ret); + if (ret1) + pr_err("%s: Error %d disabling clocks\n", __func__, ret1); out: return ret; @@ -267,8 +144,11 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type) { + struct scm_desc desc = {0}; int ret = 0; + uint32_t smc_id = 0; + if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { pr_err("%s Invalid index %d\n", __func__, index); return -EINVAL; @@ -279,22 +159,20 @@ int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type) return -EINVAL; } + smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; + + desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; + desc.args[0] = index; + ret = qcom_ice_setup_ice_hw((const char *)storage_type, true); if (ret) { pr_err("%s: could not enable clocks: 0x%x\n", __func__, ret); return ret; } - if (pfk_wrapped_key_supported()) { - ret = clear_wrapped_key(index); - pr_debug("%s: Clearing wrapped key\n", __func__); - } else { - pr_debug("%s: Clearing keys with QSEE kernel\n", __func__); - ret = clear_key(index); - } - + ret = scm_call2(smc_id, &desc); if (ret) - pr_err("%s: Invalidate key error: %d\n", __func__, ret); + pr_err("%s: Error: 0x%x\n", __func__, ret); if (qcom_ice_setup_ice_hw((const char *)storage_type, false)) pr_err("%s: could not disable clocks\n", __func__); diff --git a/security/pfe/pfk_ice.h b/security/pfe/pfk_ice.h index 5adfcb200b68..a00193919116 100644 --- a/security/pfe/pfk_ice.h +++ b/security/pfe/pfk_ice.h @@ -22,35 +22,9 @@ #include -struct __attribute__ ((__packed__)) pfk_ice_key_req { - uint32_t cmd_id; - uint32_t index; - uint32_t ice_key_offset; - uint32_t ice_key_size; - uint32_t ice_salt_offset; - uint32_t ice_salt_size; -}; - -struct __attribute__ ((__packed__)) pfk_ice_key_rsp { - uint32_t ret; - uint32_t cmd_id; -}; - int pfk_ice_init(void); int pfk_ice_deinit(void); -#ifdef CONFIG_PFK_WRAPPED_KEY_SUPPORTED -static inline bool pfk_wrapped_key_supported(void) -{ - return true; -} -#else -static inline bool pfk_wrapped_key_supported(void) -{ - return false; -} -#endif - int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, char *storage_type); int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type); -- GitLab From 367c46b11cb19cbe7efcfb24f5c8543fc013fb73 Mon Sep 17 00:00:00 2001 From: Shivaprasad Hongal Date: Tue, 21 Aug 2018 14:52:13 -0700 Subject: [PATCH 0922/1001] Enable hardware based FBE on f2fs and adapt ext4 fs Hardware File Based Encryption (FBE) uses inline crypto engine to encrypt the user data. 1. security/pfk: changes to support per file encryption for f2fs using hardware crypto engine. 2. fs/ext4: adapted crypto APIs for generic crypto layer. 3. fs/f2fs: support hardware crypto engine based per file encryption. 4. fs/crypto: export APIs to support hardware crypto engine based per file encryption. 5. security/pfe: added wrapped key support based on upstream changes. Other changes made to provide support framework for per file encryption. Reverting commit e02a4e21f640 ("ext4: Add HW File Based Encryption on ext4 file system") and adding changes to have FBE in sync with upstream implementation of FBE. Change-Id: I17f9909c43ba744eb874f6d237745fbf88a2b848 Signed-off-by: Shivaprasad Hongal --- block/bio.c | 9 ++ block/blk-merge.c | 5 +- block/elevator.c | 8 +- drivers/crypto/Kconfig | 1 + drivers/scsi/scsi_lib.c | 2 + drivers/scsi/ufs/ufs-qcom.c | 19 ++- fs/crypto/Makefile | 7 +- fs/crypto/bio.c | 6 +- fs/crypto/ext4_ice.c | 108 --------------- fs/crypto/fscrypt_ice.c | 146 ++++++++++++++++++++ fs/crypto/fscrypt_ice.h | 106 ++++++++++++++ fs/crypto/fscrypt_private.h | 14 +- fs/crypto/keyinfo.c | 162 +++++++++++----------- fs/direct-io.c | 3 +- fs/ext4/Makefile | 1 - fs/ext4/ext4.h | 3 - fs/ext4/ext4_ice.h | 104 -------------- fs/ext4/inode.c | 26 ++-- fs/ext4/ioctl.c | 10 +- fs/ext4/page-io.c | 7 +- fs/ext4/super.c | 6 + fs/f2fs/data.c | 37 ++++- fs/f2fs/f2fs.h | 13 +- fs/f2fs/super.c | 6 + fs/namei.c | 2 - include/linux/bio.h | 8 ++ include/linux/blk_types.h | 10 +- include/linux/blkdev.h | 3 + include/linux/bvec.h | 1 + include/linux/fscrypt.h | 12 +- include/linux/fscrypt_notsupp.h | 15 ++ include/linux/fscrypt_supp.h | 8 ++ include/linux/pfk.h | 16 ++- include/linux/security.h | 4 +- include/scsi/scsi_host.h | 3 + include/uapi/linux/fs.h | 1 + security/Kconfig | 1 - security/Makefile | 4 +- security/pfe/Kconfig | 11 ++ security/pfe/Makefile | 4 +- security/pfe/pfk.c | 176 ++++++++++++++++-------- security/pfe/pfk_ext4.c | 44 ++++-- security/pfe/pfk_f2fs.c | 200 +++++++++++++++++++++++++++ security/pfe/pfk_f2fs.h | 37 +++++ security/pfe/pfk_ice.c | 206 ++++++++++++++++++++++------ security/pfe/pfk_ice.h | 26 ++++ security/pfe/pfk_kc.c | 2 + security/security.c | 2 +- security/selinux/include/objsec.h | 2 +- security/selinux/include/security.h | 1 + 50 files changed, 1135 insertions(+), 473 deletions(-) delete mode 100644 fs/crypto/ext4_ice.c create mode 100644 fs/crypto/fscrypt_ice.c create mode 100644 fs/crypto/fscrypt_ice.h delete mode 100644 fs/ext4/ext4_ice.h create mode 100644 security/pfe/pfk_f2fs.c create mode 100644 security/pfe/pfk_f2fs.h diff --git a/block/bio.c b/block/bio.c index 61975a2bd9e0..6328c6e71b27 100644 --- a/block/bio.c +++ b/block/bio.c @@ -577,6 +577,14 @@ inline int bio_phys_segments(struct request_queue *q, struct bio *bio) } EXPORT_SYMBOL(bio_phys_segments); +static inline void bio_clone_crypt_key(struct bio *dst, const struct bio *src) +{ +#ifdef CONFIG_PFK + dst->bi_crypt_key = src->bi_crypt_key; + dst->bi_iter.bi_dun = src->bi_iter.bi_dun; +#endif +} + /** * __bio_clone_fast - clone a bio that shares the original bio's biovec * @bio: destination bio @@ -606,6 +614,7 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src) bio->bi_iter = bio_src->bi_iter; bio->bi_io_vec = bio_src->bi_io_vec; bio->bi_dio_inode = bio_src->bi_dio_inode; + bio_clone_crypt_key(bio, bio_src); bio_clone_blkcg_association(bio, bio_src); } EXPORT_SYMBOL(__bio_clone_fast); diff --git a/block/blk-merge.c b/block/blk-merge.c index 4f7e70419ba2..e8c45fd4a972 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -7,9 +7,9 @@ #include #include #include -#include -#include +#include +#include #include "blk.h" static struct bio *blk_bio_discard_split(struct request_queue *q, @@ -705,6 +705,7 @@ static struct request *attempt_merge(struct request_queue *q, if (crypto_not_mergeable(req->bio, next->bio)) return 0; + /* * If we are allowed to merge, then append bio list * from next to rq and release next. merge_requests_fn diff --git a/block/elevator.c b/block/elevator.c index 153926a90901..154dc38a03a3 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -436,7 +436,7 @@ enum elv_merge elv_merge(struct request_queue *q, struct request **req, { struct elevator_queue *e = q->elevator; struct request *__rq; - + enum elv_merge ret; /* * Levels of merges: * nomerges: No merges at all attempted @@ -449,9 +449,11 @@ enum elv_merge elv_merge(struct request_queue *q, struct request **req, /* * First try one-hit cache. */ - if (q->last_merge && elv_bio_merge_ok(q->last_merge, bio)) { - enum elv_merge ret = blk_try_merge(q->last_merge, bio); + if (q->last_merge) { + if (!elv_bio_merge_ok(q->last_merge, bio)) + return ELEVATOR_NO_MERGE; + ret = blk_try_merge(q->last_merge, bio); if (ret != ELEVATOR_NO_MERGE) { *req = q->last_merge; return ret; diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 0359f0c484fc..fe89328d3d99 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -773,4 +773,5 @@ config CRYPTO_DEV_ARTPEC6 if ARCH_QCOM source drivers/crypto/msm/Kconfig endif + endif # CRYPTO_HW diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 60345cb4e414..11ff33c1e5c4 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2159,6 +2159,8 @@ void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q) if (!shost->use_clustering) q->limits.cluster = 0; + if (shost->inlinecrypt_support) + queue_flag_set_unlocked(QUEUE_FLAG_INLINECRYPT, q); /* * Set a reasonable default alignment: The larger of 32-byte (dword), * which is a common minimum for HBAs, and the minimum DMA alignment, diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index fb42b567a1b7..a7430a46da45 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -937,11 +937,18 @@ static int ufs_qcom_crypto_req_setup(struct ufs_hba *hba, req = lrbp->cmd->request; else return 0; - - /* Use request LBA as the DUN value */ - if (req->bio) - *dun = (req->bio->bi_iter.bi_sector) >> - UFS_QCOM_ICE_TR_DATA_UNIT_4_KB; + /* + * Right now ICE do not support variable dun but can be + * taken as future enhancement + * if (bio_dun(req->bio)) { + * dun @bio can be split, so we have to adjust offset + * *dun = bio_dun(req->bio); + * } else + */ + if (req->bio) { + *dun = req->bio->bi_iter.bi_sector; + *dun >>= UFS_QCOM_ICE_TR_DATA_UNIT_4_KB; + } ret = ufs_qcom_ice_req_setup(host, lrbp->cmd, cc_index, enable); @@ -2180,6 +2187,8 @@ static int ufs_qcom_init(struct ufs_hba *hba) dev_err(dev, "%s: ufs_qcom_ice_get_dev failed %d\n", __func__, err); goto out_variant_clear; + } else { + hba->host->inlinecrypt_support = 1; } host->generic_phy = devm_phy_get(dev, "ufsphy"); diff --git a/fs/crypto/Makefile b/fs/crypto/Makefile index e7bee887b605..cc42e5e29472 100644 --- a/fs/crypto/Makefile +++ b/fs/crypto/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o -fscrypto-y := crypto.o fname.o hooks.o keyinfo.o policy.o -fscrypto-$(CONFIG_BLOCK) += bio.o ccflags-y += -Ifs/ext4 -fscrypto-$(CONFIG_EXT4_FS_ICE_ENCRYPTION) += ext4_ice.o +ccflags-y += -Ifs/f2fs + +fscrypto-y := crypto.o fname.o hooks.o keyinfo.o policy.o fscrypt_ice.o +fscrypto-$(CONFIG_BLOCK) += bio.o diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index d32a5c69ca38..93cd5e567d07 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -25,7 +25,6 @@ #include #include #include "fscrypt_private.h" -#include "ext4_ice.h" static void __fscrypt_decrypt_bio(struct bio *bio, bool done) { @@ -34,12 +33,11 @@ static void __fscrypt_decrypt_bio(struct bio *bio, bool done) bio_for_each_segment_all(bv, bio, i) { struct page *page = bv->bv_page; - if (ext4_should_be_processed_by_ice(page->mapping->host)) { + if (fscrypt_using_hardware_encryption(page->mapping->host)) { SetPageUptodate(page); } else { int ret = fscrypt_decrypt_page(page->mapping->host, - page, PAGE_SIZE, 0, page->index); - + page, PAGE_SIZE, 0, page->index); if (ret) { WARN_ON_ONCE(1); SetPageError(page); diff --git a/fs/crypto/ext4_ice.c b/fs/crypto/ext4_ice.c deleted file mode 100644 index a8098e338f29..000000000000 --- a/fs/crypto/ext4_ice.c +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "ext4_ice.h" -#include "fscrypt_private.h" - -/* - * Retrieves encryption key from the inode - */ -char *ext4_get_ice_encryption_key(const struct inode *inode) -{ - struct fscrypt_info *ci = NULL; - - if (!inode) - return NULL; - - ci = inode->i_crypt_info; - if (!ci) - return NULL; - - return &(ci->ci_raw_key[0]); -} - -/* - * Retrieves encryption salt from the inode - */ -char *ext4_get_ice_encryption_salt(const struct inode *inode) -{ - struct fscrypt_info *ci = NULL; - - if (!inode) - return NULL; - - ci = inode->i_crypt_info; - if (!ci) - return NULL; - - return &(ci->ci_raw_key[ext4_get_ice_encryption_key_size(inode)]); -} - -/* - * returns true if the cipher mode in inode is AES XTS - */ -int ext4_is_aes_xts_cipher(const struct inode *inode) -{ - struct fscrypt_info *ci = NULL; - - ci = inode->i_crypt_info; - if (!ci) - return 0; - - return (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE); -} - -/* - * returns true if encryption info in both inodes is equal - */ -int ext4_is_ice_encryption_info_equal(const struct inode *inode1, - const struct inode *inode2) -{ - char *key1 = NULL; - char *key2 = NULL; - char *salt1 = NULL; - char *salt2 = NULL; - - if (!inode1 || !inode2) - return 0; - - if (inode1 == inode2) - return 1; - - /* both do not belong to ice, so we don't care, they are equal for us */ - if (!ext4_should_be_processed_by_ice(inode1) && - !ext4_should_be_processed_by_ice(inode2)) - return 1; - - /* one belongs to ice, the other does not -> not equal */ - if (ext4_should_be_processed_by_ice(inode1) ^ - ext4_should_be_processed_by_ice(inode2)) - return 0; - - key1 = ext4_get_ice_encryption_key(inode1); - key2 = ext4_get_ice_encryption_key(inode2); - salt1 = ext4_get_ice_encryption_salt(inode1); - salt2 = ext4_get_ice_encryption_salt(inode2); - - /* key and salt should not be null by this point */ - if (!key1 || !key2 || !salt1 || !salt2 || - (ext4_get_ice_encryption_key_size(inode1) != - ext4_get_ice_encryption_key_size(inode2)) || - (ext4_get_ice_encryption_salt_size(inode1) != - ext4_get_ice_encryption_salt_size(inode2))) - return 0; - - return ((memcmp(key1, key2, - ext4_get_ice_encryption_key_size(inode1)) == 0) && - (memcmp(salt1, salt2, - ext4_get_ice_encryption_salt_size(inode1)) == 0)); -} diff --git a/fs/crypto/fscrypt_ice.c b/fs/crypto/fscrypt_ice.c new file mode 100644 index 000000000000..62dae83cf732 --- /dev/null +++ b/fs/crypto/fscrypt_ice.c @@ -0,0 +1,146 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "fscrypt_ice.h" + +int fscrypt_using_hardware_encryption(const struct inode *inode) +{ + struct fscrypt_info *ci = inode->i_crypt_info; + + return S_ISREG(inode->i_mode) && ci && + ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE; +} +EXPORT_SYMBOL(fscrypt_using_hardware_encryption); + +/* + * Retrieves encryption key from the inode + */ +char *fscrypt_get_ice_encryption_key(const struct inode *inode) +{ + struct fscrypt_info *ci = NULL; + + if (!inode) + return NULL; + + ci = inode->i_crypt_info; + if (!ci) + return NULL; + + return &(ci->ci_raw_key[0]); +} + +/* + * Retrieves encryption salt from the inode + */ +char *fscrypt_get_ice_encryption_salt(const struct inode *inode) +{ + struct fscrypt_info *ci = NULL; + + if (!inode) + return NULL; + + ci = inode->i_crypt_info; + if (!ci) + return NULL; + + return &(ci->ci_raw_key[fscrypt_get_ice_encryption_key_size(inode)]); +} + +/* + * returns true if the cipher mode in inode is AES XTS + */ +int fscrypt_is_aes_xts_cipher(const struct inode *inode) +{ + struct fscrypt_info *ci = inode->i_crypt_info; + + if (!ci) + return 0; + + return (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE); +} + +/* + * returns true if encryption info in both inodes is equal + */ +bool fscrypt_is_ice_encryption_info_equal(const struct inode *inode1, + const struct inode *inode2) +{ + char *key1 = NULL; + char *key2 = NULL; + char *salt1 = NULL; + char *salt2 = NULL; + + if (!inode1 || !inode2) + return false; + + if (inode1 == inode2) + return true; + + /* both do not belong to ice, so we don't care, they are equal + *for us + */ + if (!fscrypt_should_be_processed_by_ice(inode1) && + !fscrypt_should_be_processed_by_ice(inode2)) + return true; + + /* one belongs to ice, the other does not -> not equal */ + if (fscrypt_should_be_processed_by_ice(inode1) ^ + fscrypt_should_be_processed_by_ice(inode2)) + return false; + + key1 = fscrypt_get_ice_encryption_key(inode1); + key2 = fscrypt_get_ice_encryption_key(inode2); + salt1 = fscrypt_get_ice_encryption_salt(inode1); + salt2 = fscrypt_get_ice_encryption_salt(inode2); + + /* key and salt should not be null by this point */ + if (!key1 || !key2 || !salt1 || !salt2 || + (fscrypt_get_ice_encryption_key_size(inode1) != + fscrypt_get_ice_encryption_key_size(inode2)) || + (fscrypt_get_ice_encryption_salt_size(inode1) != + fscrypt_get_ice_encryption_salt_size(inode2))) + return false; + + if ((memcmp(key1, key2, + fscrypt_get_ice_encryption_key_size(inode1)) == 0) && + (memcmp(salt1, salt2, + fscrypt_get_ice_encryption_salt_size(inode1)) == 0)) + return true; + + return false; +} + +void fscrypt_set_ice_dun(const struct inode *inode, struct bio *bio, u64 dun) +{ + if (fscrypt_should_be_processed_by_ice(inode)) + bio->bi_iter.bi_dun = dun; +} +EXPORT_SYMBOL(fscrypt_set_ice_dun); + +/* + * This function will be used for filesystem when deciding to merge bios. + * Basic assumption is, if inline_encryption is set, single bio has to + * guarantee consecutive LBAs as well as ino|pg->index. + */ +bool fscrypt_mergeable_bio(struct bio *bio, u64 dun, bool bio_encrypted) +{ + if (!bio) + return true; + + /* if both of them are not encrypted, no further check is needed */ + if (!bio_dun(bio) && !bio_encrypted) + return true; + + /* ICE allows only consecutive iv_key stream. */ + return bio_end_dun(bio) == dun; +} +EXPORT_SYMBOL(fscrypt_mergeable_bio); diff --git a/fs/crypto/fscrypt_ice.h b/fs/crypto/fscrypt_ice.h new file mode 100644 index 000000000000..38e8ba69f3c2 --- /dev/null +++ b/fs/crypto/fscrypt_ice.h @@ -0,0 +1,106 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _FSCRYPT_ICE_H +#define _FSCRYPT_ICE_H + +#include +#include "fscrypt_private.h" + +#if IS_ENABLED(CONFIG_FS_ENCRYPTION) +static inline bool fscrypt_should_be_processed_by_ice(const struct inode *inode) +{ + if (!inode->i_sb->s_cop) + return 0; + if (!inode->i_sb->s_cop->is_encrypted((struct inode *)inode)) + return 0; + + return fscrypt_using_hardware_encryption(inode); +} + +static inline int fscrypt_is_ice_capable(const struct super_block *sb) +{ + return blk_queue_inlinecrypt(bdev_get_queue(sb->s_bdev)); +} + +int fscrypt_is_aes_xts_cipher(const struct inode *inode); + +char *fscrypt_get_ice_encryption_key(const struct inode *inode); +char *fscrypt_get_ice_encryption_salt(const struct inode *inode); + +bool fscrypt_is_ice_encryption_info_equal(const struct inode *inode1, + const struct inode *inode2); + +static inline size_t fscrypt_get_ice_encryption_key_size( + const struct inode *inode) +{ + return FS_AES_256_XTS_KEY_SIZE / 2; +} + +static inline size_t fscrypt_get_ice_encryption_salt_size( + const struct inode *inode) +{ + return FS_AES_256_XTS_KEY_SIZE / 2; +} +#else +static inline bool fscrypt_should_be_processed_by_ice(const struct inode *inode) +{ + return 0; +} + +static inline int fscrypt_is_ice_capable(const struct super_block *sb) +{ + return 0; +} + +static inline char *fscrypt_get_ice_encryption_key(const struct inode *inode) +{ + return NULL; +} + +static inline char *fscrypt_get_ice_encryption_salt(const struct inode *inode) +{ + return NULL; +} + +static inline size_t fscrypt_get_ice_encryption_key_size( + const struct inode *inode) +{ + return 0; +} + +static inline size_t fscrypt_get_ice_encryption_salt_size( + const struct inode *inode) +{ + return 0; +} + +static inline int fscrypt_is_xts_cipher(const struct inode *inode) +{ + return 0; +} + +static inline bool fscrypt_is_ice_encryption_info_equal( + const struct inode *inode1, + const struct inode *inode2) +{ + return 0; +} + +static inline int fscrypt_is_aes_xts_cipher(const struct inode *inode) +{ + return 0; +} + +#endif + +#endif /* _FSCRYPT_ICE_H */ diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index c9ca9e79411d..ca6e75a5cb37 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -17,6 +17,7 @@ #endif #include #include +#include /* Encryption parameters */ #define FS_IV_SIZE 16 @@ -61,11 +62,18 @@ struct fscrypt_symlink_data { char encrypted_path[1]; } __packed; +enum ci_mode_info { + CI_NONE_MODE = 0, + CI_DATA_MODE, + CI_FNAME_MODE, +}; + /* * A pointer to this structure is stored in the file system's in-core * representation of an inode. */ struct fscrypt_info { + u8 ci_mode; u8 ci_data_mode; u8 ci_filename_mode; u8 ci_flags; @@ -105,12 +113,12 @@ static inline bool fscrypt_valid_enc_modes(u32 contents_mode, return false; } -static inline bool is_private_mode(struct fscrypt_info *ci) +static inline bool is_private_data_mode(struct fscrypt_info *ci) { - return ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE; + return ci->ci_mode == CI_DATA_MODE && + ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE; } - /* crypto.c */ extern struct kmem_cache *fscrypt_info_cachep; extern int fscrypt_initialize(unsigned int cop_flags); diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index 27edc5b9eb66..737af4b41f71 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -16,7 +16,7 @@ #include #include #include "fscrypt_private.h" -#include "ext4_ice.h" +#include "fscrypt_ice.h" static struct crypto_shash *essiv_hash_tfm; @@ -69,7 +69,7 @@ static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE], } static int validate_user_key(struct fscrypt_info *crypt_info, - struct fscrypt_context *ctx, u8 *raw_key, + struct fscrypt_context *ctx, const char *prefix, int min_keysize) { char *description; @@ -117,21 +117,20 @@ static int validate_user_key(struct fscrypt_info *crypt_info, res = -ENOKEY; goto out; } - /* - * If we don't need to derive, we still want to do everything + res = derive_key_aes(ctx->nonce, master_key, crypt_info->ci_raw_key); + /* If we don't need to derive, we still want to do everything * up until now to validate the key. It's cleaner to fail now * than to fail in block I/O. */ - if (!is_private_mode(crypt_info)) { + if (!is_private_data_mode(crypt_info)) { res = derive_key_aes(ctx->nonce, master_key, crypt_info->ci_raw_key); } else { - /* - * Inline encryption: no key derivation required because IVs are + /* Inline encryption: no key derivation required because IVs are * assigned based on iv_sector. */ - if (sizeof(crypt_info->ci_raw_key) != sizeof(master_key->raw)) - goto out; + BUILD_BUG_ON(sizeof(crypt_info->ci_raw_key) != + sizeof(master_key->raw)); memcpy(crypt_info->ci_raw_key, master_key->raw, sizeof(crypt_info->ci_raw_key)); res = 0; @@ -156,42 +155,37 @@ static const struct { FS_AES_128_CTS_KEY_SIZE }, [FS_ENCRYPTION_MODE_SPECK128_256_XTS] = { "xts(speck128)", 64 }, [FS_ENCRYPTION_MODE_SPECK128_256_CTS] = { "cts(cbc(speck128))", 32 }, - [FS_ENCRYPTION_MODE_PRIVATE] = { "bugon", FS_AES_256_XTS_KEY_SIZE }, + [FS_ENCRYPTION_MODE_PRIVATE] = { "bugon", + FS_AES_256_XTS_KEY_SIZE }, }; static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode, - const char **cipher_str_ret, int *keysize_ret, int *fname) + 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; - } else if (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE) { - *cipher_str_ret = "bugon"; - *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; + u32 mode; + + if (!fscrypt_valid_enc_modes(ci->ci_data_mode, ci->ci_filename_mode)) { + pr_warn_ratelimited("fscrypt: inode %lu uses unsupported encryption modes (contents mode %d, filenames mode %d)\n", + inode->i_ino, + ci->ci_data_mode, ci->ci_filename_mode); + return -EINVAL; } - 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; - *fname = 1; - return 0; - } - pr_warn_once("fscrypto: unsupported filenames encryption mode %d for inode %lu\n", - ci->ci_filename_mode, inode->i_ino); - return -ENOKEY; + if (S_ISREG(inode->i_mode)) { + ci->ci_mode = CI_DATA_MODE; + mode = ci->ci_data_mode; + } else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) { + ci->ci_mode = CI_FNAME_MODE; + mode = ci->ci_filename_mode; + } else { + WARN_ONCE(1, "fscrypt: filesystem tried to load encryption info for inode %lu, which is not encryptable (file type %d)\n", + inode->i_ino, (inode->i_mode & S_IFMT)); + return -EINVAL; } - pr_warn_once("fscrypto: unsupported file type %d for inode %lu\n", - (inode->i_mode & S_IFMT), inode->i_ino); - return -ENOKEY; + *cipher_str_ret = available_modes[mode].cipher_str; + *keysize_ret = available_modes[mode].keysize; + return 0; } static void put_crypt_info(struct fscrypt_info *ci) @@ -201,6 +195,7 @@ static void put_crypt_info(struct fscrypt_info *ci) crypto_free_skcipher(ci->ci_ctfm); crypto_free_cipher(ci->ci_essiv_tfm); + memset(ci, 0, sizeof(*ci)); /* sanitizes ->ci_raw_key */ kmem_cache_free(fscrypt_info_cachep, ci); } @@ -271,20 +266,11 @@ void __exit fscrypt_essiv_cleanup(void) crypto_free_shash(essiv_hash_tfm); } -static int fs_data_encryption_mode(void) +static int fscrypt_data_encryption_mode(struct inode *inode) { - return ext4_is_ice_enabled() ? FS_ENCRYPTION_MODE_PRIVATE : - FS_ENCRYPTION_MODE_AES_256_XTS; -} - -int fs_using_hardware_encryption(struct inode *inode) -{ - struct fscrypt_info *ci = inode->i_crypt_info; - - return S_ISREG(inode->i_mode) && ci && - ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE; + return fscrypt_should_be_processed_by_ice(inode) ? + FS_ENCRYPTION_MODE_PRIVATE : FS_ENCRYPTION_MODE_AES_256_XTS; } -EXPORT_SYMBOL(fs_using_hardware_encryption); int fscrypt_get_encryption_info(struct inode *inode) { @@ -293,8 +279,8 @@ int fscrypt_get_encryption_info(struct inode *inode) struct crypto_skcipher *ctfm; const char *cipher_str; int keysize; + u8 *raw_key = NULL; int res; - int fname = 0; if (inode->i_crypt_info) return 0; @@ -311,7 +297,8 @@ int fscrypt_get_encryption_info(struct inode *inode) /* Fake up a context for an unencrypted directory */ memset(&ctx, 0, sizeof(ctx)); ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1; - ctx.contents_encryption_mode = fs_data_encryption_mode(); + ctx.contents_encryption_mode = + fscrypt_data_encryption_mode(inode); ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS; memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE); } else if (res != sizeof(ctx)) { @@ -336,8 +323,7 @@ int fscrypt_get_encryption_info(struct inode *inode) 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, &fname); + res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize); if (res) goto out; @@ -346,17 +332,16 @@ int fscrypt_get_encryption_info(struct inode *inode) * crypto API as part of key derivation. */ res = -ENOMEM; + raw_key = kmalloc(FS_MAX_KEY_SIZE, GFP_NOFS); + if (!raw_key) + goto out; - if (fscrypt_dummy_context_enabled(inode)) { - memset(crypt_info->ci_raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE); - goto got_key; - } - res = validate_user_key(crypt_info, &ctx, crypt_info->ci_raw_key, - FS_KEY_DESC_PREFIX, FS_KEY_DESC_PREFIX_SIZE); + res = validate_user_key(crypt_info, &ctx, FS_KEY_DESC_PREFIX, + keysize); if (res && inode->i_sb->s_cop->key_prefix) { int res2 = validate_user_key(crypt_info, &ctx, - crypt_info->ci_raw_key, - inode->i_sb->s_cop->key_prefix, keysize); + inode->i_sb->s_cop->key_prefix, + keysize); if (res2) { if (res2 == -ENOKEY) res = -ENOKEY; @@ -366,42 +351,57 @@ int fscrypt_get_encryption_info(struct inode *inode) } else if (res) { goto out; } -got_key: - if (crypt_info->ci_data_mode != FS_ENCRYPTION_MODE_PRIVATE || fname) { - ctfm = crypto_alloc_skcipher(cipher_str, 0, 0); - if (!ctfm || IS_ERR(ctfm)) { - res = ctfm ? PTR_ERR(ctfm) : -ENOMEM; - pr_err("%s: error %d inode %u allocating crypto tfm\n", - __func__, res, (unsigned int) inode->i_ino); + + if (is_private_data_mode(crypt_info)) { + if (!fscrypt_is_ice_capable(inode->i_sb)) { + pr_warn("%s: ICE support not available\n", + __func__); + res = -EINVAL; goto out; } - crypt_info->ci_ctfm = ctfm; - crypto_skcipher_clear_flags(ctfm, ~0); - crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY); - /* - * if the provided key is longer than keysize, we use the first - * keysize bytes of the derived key only - */ - res = crypto_skcipher_setkey(ctfm, crypt_info->ci_raw_key, - keysize); - if (res) - goto out; - } else if (S_ISREG(inode->i_mode) && + /* Let's encrypt/decrypt by ICE */ + goto do_ice; + } + + + ctfm = crypto_alloc_skcipher(cipher_str, 0, 0); + if (!ctfm || IS_ERR(ctfm)) { + res = ctfm ? PTR_ERR(ctfm) : -ENOMEM; + pr_debug("%s: error %d (inode %lu) allocating crypto tfm\n", + __func__, res, inode->i_ino); + goto out; + } + crypt_info->ci_ctfm = ctfm; + crypto_skcipher_clear_flags(ctfm, ~0); + crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY); + /* + * if the provided key is longer than keysize, we use the first + * keysize bytes of the derived key only + */ + res = crypto_skcipher_setkey(ctfm, crypt_info->ci_raw_key, keysize); + if (res) + goto out; + + if (S_ISREG(inode->i_mode) && crypt_info->ci_data_mode == FS_ENCRYPTION_MODE_AES_128_CBC) { res = init_essiv_generator(crypt_info, crypt_info->ci_raw_key, - keysize); + keysize); if (res) { pr_debug("%s: error %d (inode %lu) allocating essiv tfm\n", __func__, res, inode->i_ino); goto out; } } + memzero_explicit(crypt_info->ci_raw_key, + sizeof(crypt_info->ci_raw_key)); +do_ice: if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) == NULL) crypt_info = NULL; out: if (res == -ENOKEY) res = 0; put_crypt_info(crypt_info); + kzfree(raw_key); return res; } EXPORT_SYMBOL(fscrypt_get_encryption_info); diff --git a/fs/direct-io.c b/fs/direct-io.c index 96a103249a0b..c03813a80a34 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -473,10 +473,9 @@ struct inode *dio_bio_get_inode(struct bio *bio) return NULL; inode = bio->bi_dio_inode; - return inode; } -EXPORT_SYMBOL(dio_bio_get_inode); + /* * Release any resources in case of a failure */ diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index 7cf69c14f796..8fdfcd3c3e04 100644 --- a/fs/ext4/Makefile +++ b/fs/ext4/Makefile @@ -2,7 +2,6 @@ # # Makefile for the linux ext4-filesystem routines. # -ccflags-y += -Ifs/crypto obj-$(CONFIG_EXT4_FS) += ext4.o diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 2dd8c7e0f298..69e83cf4c699 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -40,9 +40,7 @@ #include #endif -#ifndef __FS_HAS_ENCRYPTION #define __FS_HAS_ENCRYPTION IS_ENABLED(CONFIG_EXT4_FS_ENCRYPTION) -#endif #include /* @@ -2352,7 +2350,6 @@ static inline int ext4_fname_setup_filename(struct inode *dir, } static inline void ext4_fname_free_filename(struct ext4_filename *fname) { } -#define fscrypt_set_d_op(i) #endif /* dir.c */ diff --git a/fs/ext4/ext4_ice.h b/fs/ext4/ext4_ice.h deleted file mode 100644 index b0149dd7bad4..000000000000 --- a/fs/ext4/ext4_ice.h +++ /dev/null @@ -1,104 +0,0 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _EXT4_ICE_H -#define _EXT4_ICE_H - -#include "ext4.h" -#include - -#ifdef CONFIG_EXT4_FS_ICE_ENCRYPTION -static inline int ext4_should_be_processed_by_ice(const struct inode *inode) -{ - if (!ext4_encrypted_inode((struct inode *)inode)) - return 0; - - return fs_using_hardware_encryption((struct inode *)inode); -} - -static inline int ext4_is_ice_enabled(void) -{ - return 1; -} - -int ext4_is_aes_xts_cipher(const struct inode *inode); - -char *ext4_get_ice_encryption_key(const struct inode *inode); -char *ext4_get_ice_encryption_salt(const struct inode *inode); - -int ext4_is_ice_encryption_info_equal(const struct inode *inode1, - const struct inode *inode2); - -static inline size_t ext4_get_ice_encryption_key_size( - const struct inode *inode) -{ - return FS_AES_256_XTS_KEY_SIZE / 2; -} - -static inline size_t ext4_get_ice_encryption_salt_size( - const struct inode *inode) -{ - return FS_AES_256_XTS_KEY_SIZE / 2; -} - -#else -static inline int ext4_should_be_processed_by_ice(const struct inode *inode) -{ - return 0; -} -static inline int ext4_is_ice_enabled(void) -{ - return 0; -} - -static inline char *ext4_get_ice_encryption_key(const struct inode *inode) -{ - return NULL; -} - -static inline char *ext4_get_ice_encryption_salt(const struct inode *inode) -{ - return NULL; -} - -static inline size_t ext4_get_ice_encryption_key_size( - const struct inode *inode) -{ - return 0; -} - -static inline size_t ext4_get_ice_encryption_salt_size( - const struct inode *inode) -{ - return 0; -} - -static inline int ext4_is_xts_cipher(const struct inode *inode) -{ - return 0; -} - -static inline int ext4_is_ice_encryption_info_equal( - const struct inode *inode1, - const struct inode *inode2) -{ - return 0; -} - -static inline int ext4_is_aes_xts_cipher(const struct inode *inode) -{ - return 0; -} - -#endif - -#endif /* _EXT4_ICE_H */ diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 2764b4d1ce32..7e777ea24614 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -44,7 +44,6 @@ #include "xattr.h" #include "acl.h" #include "truncate.h" -#include "ext4_ice.h" #include #include @@ -1220,7 +1219,7 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, *wait_bh++ = bh; decrypt = ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) && - !ext4_should_be_processed_by_ice(inode); + !fscrypt_using_hardware_encryption(inode); } } /* @@ -3716,15 +3715,14 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) get_block_func = ext4_dio_get_block_unwritten_async; dio_flags = DIO_LOCKING; } - -#if defined(CONFIG_EXT4_FS_ENCRYPTION) && \ -!defined(CONFIG_EXT4_FS_ICE_ENCRYPTION) - if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)) - return 0; +#if defined(CONFIG_EXT4_FS_ENCRYPTION) + WARN_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) + && !fscrypt_using_hardware_encryption(inode)); #endif - ret = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, iter, - get_block_func, ext4_end_io_dio, NULL, - dio_flags); + ret = __blockdev_direct_IO(iocb, inode, + inode->i_sb->s_bdev, iter, + get_block_func, + ext4_end_io_dio, NULL, dio_flags); if (ret > 0 && !overwrite && ext4_test_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN)) { @@ -3830,9 +3828,9 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ssize_t ret; int rw = iov_iter_rw(iter); -#if defined(CONFIG_EXT4_FS_ENCRYPTION) && \ -!defined(CONFIG_EXT4_FS_ICE_ENCRYPTION) - if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)) +#if defined(CONFIG_EXT4_FS_ENCRYPTION) + if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) + && !fscrypt_using_hardware_encryption(inode)) return 0; #endif @@ -4042,7 +4040,7 @@ static int __ext4_block_zero_page_range(handle_t *handle, goto unlock; if (S_ISREG(inode->i_mode) && ext4_encrypted_inode(inode) && - !ext4_should_be_processed_by_ice(inode)) { + !fscrypt_using_hardware_encryption(inode)) { /* We expect the key to be set. */ BUG_ON(!fscrypt_has_encryption_key(inode)); BUG_ON(blocksize != PAGE_SIZE); diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 53bd5d893a58..1eb68e626931 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -939,13 +939,11 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case EXT4_IOC_PRECACHE_EXTENTS: return ext4_ext_precache(inode); - case EXT4_IOC_SET_ENCRYPTION_POLICY: { -#ifdef CONFIG_EXT4_FS_ENCRYPTION + case EXT4_IOC_SET_ENCRYPTION_POLICY: + if (!ext4_has_feature_encrypt(sb)) + return -EOPNOTSUPP; return fscrypt_ioctl_set_policy(filp, (const void __user *)arg); -#else - return -EOPNOTSUPP; -#endif - } + case EXT4_IOC_GET_ENCRYPTION_PWSALT: { #ifdef CONFIG_EXT4_FS_ENCRYPTION int err, err2; diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index bc475426f0c3..11566757db26 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -29,7 +29,6 @@ #include "ext4_jbd2.h" #include "xattr.h" #include "acl.h" -#include "ext4_ice.h" static struct kmem_cache *io_end_cachep; @@ -483,9 +482,9 @@ int ext4_bio_write_page(struct ext4_io_submit *io, gfp_t gfp_flags = GFP_NOFS; retry_encrypt: - if (!ext4_should_be_processed_by_ice(inode)) - data_page = fscrypt_encrypt_page(inode, page, PAGE_SIZE, - 0, page->index, gfp_flags); + if (!fscrypt_using_hardware_encryption(inode)) + data_page = fscrypt_encrypt_page(inode, page, PAGE_SIZE, 0, + page->index, gfp_flags); if (IS_ERR(data_page)) { ret = PTR_ERR(data_page); if (ret == -ENOMEM && wbc->sync_mode == WB_SYNC_ALL) { diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 84a038a6f604..491d09a1f7bf 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1235,6 +1235,11 @@ static unsigned ext4_max_namelen(struct inode *inode) EXT4_NAME_LEN; } +static inline bool ext4_is_encrypted(struct inode *inode) +{ + return ext4_encrypted_inode(inode); +} + static const struct fscrypt_operations ext4_cryptops = { .key_prefix = "ext4:", .get_context = ext4_get_context, @@ -1242,6 +1247,7 @@ static const struct fscrypt_operations ext4_cryptops = { .dummy_context = ext4_dummy_context, .empty_dir = ext4_empty_dir, .max_namelen = ext4_max_namelen, + .is_encrypted = ext4_is_encrypted, }; #endif diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index c9db73e498a6..39dc4810ea5f 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -439,6 +439,7 @@ 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 inode *inode = fio->page->mapping->host; verify_block_addr(fio, fio->new_blkaddr); trace_f2fs_submit_page_bio(page, fio); @@ -448,6 +449,9 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio) bio = __bio_alloc(fio->sbi, fio->new_blkaddr, fio->io_wbc, 1, is_read_io(fio->op), fio->type, fio->temp); + if (f2fs_may_encrypt_bio(inode, fio)) + fscrypt_set_ice_dun(inode, bio, PG_DUN(inode, fio->page)); + if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { bio_put(bio); return -EFAULT; @@ -467,6 +471,9 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) enum page_type btype = PAGE_TYPE_OF_BIO(fio->type); struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp; struct page *bio_page; + struct inode *inode; + bool bio_encrypted; + u64 dun; int err = 0; f2fs_bug_on(sbi, is_read_io(fio->op)); @@ -490,6 +497,9 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) verify_block_addr(fio, fio->new_blkaddr); bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page; + inode = fio->page->mapping->host; + dun = PG_DUN(inode, fio->page); + bio_encrypted = f2fs_may_encrypt_bio(inode, fio); /* set submitted = true as a return value */ fio->submitted = true; @@ -500,6 +510,11 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) (io->fio.op != fio->op || io->fio.op_flags != fio->op_flags) || !__same_bdev(sbi, fio->new_blkaddr, io->bio))) __submit_merged_bio(io); + + /* ICE support */ + if (!fscrypt_mergeable_bio(io->bio, dun, bio_encrypted)) + __submit_merged_bio(io); + alloc_new: if (io->bio == NULL) { if ((fio->type == DATA || fio->type == NODE) && @@ -511,6 +526,9 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) io->bio = __bio_alloc(sbi, fio->new_blkaddr, fio->io_wbc, BIO_MAX_PAGES, false, fio->type, fio->temp); + if (bio_encrypted) + fscrypt_set_ice_dun(inode, io->bio, dun); + io->fio = *fio; } @@ -577,6 +595,9 @@ static int f2fs_submit_page_read(struct inode *inode, struct page *page, if (IS_ERR(bio)) return PTR_ERR(bio); + if (f2fs_may_encrypt_bio(inode, NULL)) + fscrypt_set_ice_dun(inode, bio, PG_DUN(inode, page)); + if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { bio_put(bio); return -EFAULT; @@ -1436,6 +1457,8 @@ static int f2fs_mpage_readpages(struct address_space *mapping, sector_t last_block_in_file; sector_t block_nr; struct f2fs_map_blocks map; + bool bio_encrypted; + u64 dun; map.m_pblk = 0; map.m_lblk = 0; @@ -1513,6 +1536,14 @@ static int f2fs_mpage_readpages(struct address_space *mapping, __submit_bio(F2FS_I_SB(inode), bio, DATA); bio = NULL; } + + dun = PG_DUN(inode, page); + bio_encrypted = f2fs_may_encrypt_bio(inode, NULL); + if (!fscrypt_mergeable_bio(bio, dun, bio_encrypted)) { + __submit_bio(F2FS_I_SB(inode), bio, DATA); + bio = NULL; + } + if (bio == NULL) { bio = f2fs_grab_read_bio(inode, block_nr, nr_pages); if (IS_ERR(bio)) { @@ -1520,7 +1551,8 @@ static int f2fs_mpage_readpages(struct address_space *mapping, goto set_error_page; } } - + if (bio_encrypted) + fscrypt_set_ice_dun(inode, bio, dun); if (bio_add_page(bio, page, blocksize, 0) < blocksize) goto submit_and_realloc; @@ -1590,6 +1622,9 @@ static int encrypt_one_page(struct f2fs_io_info *fio) f2fs_wait_on_block_writeback(fio->sbi, fio->old_blkaddr); retry_encrypt: + if (fscrypt_using_hardware_encryption(inode)) + return 0; + fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page, PAGE_SIZE, 0, fio->page->index, gfp_flags); if (!IS_ERR(fio->encrypted_page)) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index bc633925d7b7..5895204c39d1 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3279,9 +3279,20 @@ static inline bool f2fs_may_encrypt(struct inode *inode) static inline bool f2fs_force_buffered_io(struct inode *inode, int rw) { - return (f2fs_post_read_required(inode) || + return ((f2fs_post_read_required(inode) && + !fscrypt_using_hardware_encryption(inode)) || (rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) || F2FS_I_SB(inode)->s_ndevs); } +static inline bool f2fs_may_encrypt_bio(struct inode *inode, + struct f2fs_io_info *fio) +{ + if (fio && (fio->type != DATA || fio->encrypted_page)) + return false; + + return (f2fs_encrypted_file(inode) && + fscrypt_using_hardware_encryption(inode)); +} + #endif diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 2b79c1a7a2f2..a26bd6dda9b4 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1940,6 +1940,11 @@ static unsigned f2fs_max_namelen(struct inode *inode) inode->i_sb->s_blocksize : F2FS_NAME_LEN; } +static inline bool f2fs_is_encrypted(struct inode *inode) +{ + return f2fs_encrypted_file(inode); +} + static const struct fscrypt_operations f2fs_cryptops = { .key_prefix = "f2fs:", .get_context = f2fs_get_context, @@ -1947,6 +1952,7 @@ static const struct fscrypt_operations f2fs_cryptops = { .dummy_context = f2fs_dummy_context, .empty_dir = f2fs_empty_dir, .max_namelen = f2fs_max_namelen, + .is_encrypted = f2fs_is_encrypted, }; #endif diff --git a/fs/namei.c b/fs/namei.c index 055c6c40901b..d3650e50a6ed 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3742,11 +3742,9 @@ int vfs_mknod2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, u error = dir->i_op->mknod(dir, dentry, mode, dev); if (error) return error; - error = security_inode_post_create(dir, dentry, mode); if (error) return error; - if (!error) fsnotify_create(dir, dentry); return error; diff --git a/include/linux/bio.h b/include/linux/bio.h index 5aa40f4712ff..8988ccdb10c8 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -69,6 +69,9 @@ ((bio)->bi_iter.bi_size != bio_iovec(bio).bv_len) #define bio_sectors(bio) ((bio)->bi_iter.bi_size >> 9) #define bio_end_sector(bio) ((bio)->bi_iter.bi_sector + bio_sectors((bio))) +#define bio_dun(bio) ((bio)->bi_iter.bi_dun) +#define bio_duns(bio) (bio_sectors(bio) >> 3) /* 4KB unit */ +#define bio_end_dun(bio) (bio_dun(bio) + bio_duns(bio)) /* * Return the data direction, READ or WRITE. @@ -173,6 +176,11 @@ static inline void bio_advance_iter(struct bio *bio, struct bvec_iter *iter, { iter->bi_sector += bytes >> 9; +#ifdef CONFIG_PFK + if (iter->bi_dun) + iter->bi_dun += bytes >> 12; +#endif + if (bio_no_advance_iter(bio)) { iter->bi_size -= bytes; iter->bi_done += bytes; diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index be2bee81c748..ba4b484c0008 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -100,6 +100,10 @@ struct bio { struct bio_integrity_payload *bi_integrity; /* data integrity */ #endif }; +#ifdef CONFIG_PFK + /* Encryption key to use (NULL if none) */ + const struct blk_encryption_key *bi_crypt_key; +#endif unsigned short bi_vcnt; /* how many bio_vec's */ @@ -115,12 +119,8 @@ struct bio { struct bio_set *bi_pool; - /* - * When using dircet-io (O_DIRECT), we can't get the inode from a bio - * by walking bio->bi_io_vec->bv_page->mapping->host - * since the page is anon. - */ struct inode *bi_dio_inode; + /* * We can inline a number of vecs at the end of the bio, to avoid * double allocations for a small number of bio_vecs. This member diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 64ac8e3c5a40..c3a488f8b2e1 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -652,6 +652,7 @@ struct request_queue { #define QUEUE_FLAG_REGISTERED 26 /* queue has been registered to a disk */ #define QUEUE_FLAG_SCSI_PASSTHROUGH 27 /* queue supports SCSI commands */ #define QUEUE_FLAG_QUIESCED 28 /* queue has been quiesced */ +#define QUEUE_FLAG_INLINECRYPT 29 /* inline encryption support */ #define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ (1 << QUEUE_FLAG_STACKABLE) | \ @@ -751,6 +752,8 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q) #define blk_queue_dax(q) test_bit(QUEUE_FLAG_DAX, &(q)->queue_flags) #define blk_queue_scsi_passthrough(q) \ test_bit(QUEUE_FLAG_SCSI_PASSTHROUGH, &(q)->queue_flags) +#define blk_queue_inlinecrypt(q) \ + test_bit(QUEUE_FLAG_INLINECRYPT, &(q)->queue_flags) #define blk_noretry_request(rq) \ ((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \ diff --git a/include/linux/bvec.h b/include/linux/bvec.h index ec8a4d7af6bd..41d309fda777 100644 --- a/include/linux/bvec.h +++ b/include/linux/bvec.h @@ -44,6 +44,7 @@ struct bvec_iter { unsigned int bi_bvec_done; /* number of bytes completed in current bvec */ + u64 bi_dun; /* DUN setting for bio */ }; /* diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 2a3957bc2221..129b948bee5a 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -17,10 +17,16 @@ #include #define FS_CRYPTO_BLOCK_SIZE 16 -#define FS_ENCRYPTION_MODE_PRIVATE 127 -#define FS_AES_256_XTS_KEY_SIZE 64 struct fscrypt_ctx; + +/* iv sector for security/pfe/pfk_fscrypt.c and f2fs. sizeof is required + * to accommodate 32 bit targets. + */ +#define PG_DUN(i, p) \ + ((((i)->i_ino & 0xffffffff) << (sizeof((i)->i_ino)/2)) | \ + ((p)->index & 0xffffffff)) + struct fscrypt_info; struct fscrypt_str { @@ -44,8 +50,6 @@ struct fscrypt_name { /* Maximum value for the third parameter of fscrypt_operations.set_context(). */ #define FSCRYPT_SET_CONTEXT_MAX_SIZE 28 -extern int fs_using_hardware_encryption(struct inode *inode); - #if __FS_HAS_ENCRYPTION #include #else diff --git a/include/linux/fscrypt_notsupp.h b/include/linux/fscrypt_notsupp.h index 9770be37c9d4..07f6b63f4240 100644 --- a/include/linux/fscrypt_notsupp.h +++ b/include/linux/fscrypt_notsupp.h @@ -184,6 +184,21 @@ static inline int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, return -EOPNOTSUPP; } +/* fscrypt_ice.c */ +static inline int fscrypt_using_hardware_encryption(const struct inode *inode) +{ + return 0; +} + +static inline void fscrypt_set_ice_dun(const struct inode *inode, + struct bio *bio, u64 dun){} + +static inline bool fscrypt_mergeable_bio(struct bio *bio, + sector_t iv_block, bool bio_encrypted) +{ + return true; +} + /* hooks.c */ static inline int fscrypt_file_open(struct inode *inode, struct file *filp) diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h index 2c9a86ac5e83..483de436fbb6 100644 --- a/include/linux/fscrypt_supp.h +++ b/include/linux/fscrypt_supp.h @@ -30,6 +30,7 @@ struct fscrypt_operations { bool (*dummy_context)(struct inode *); bool (*empty_dir)(struct inode *); unsigned (*max_namelen)(struct inode *); + bool (*is_encrypted)(struct inode *); }; struct fscrypt_ctx { @@ -196,6 +197,13 @@ extern void fscrypt_pullback_bio_page(struct page **, bool); extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t, unsigned int); +/* fscrypt_ice.c */ +extern int fscrypt_using_hardware_encryption(const struct inode *inode); +extern void fscrypt_set_ice_dun(const struct inode *inode, + struct bio *bio, u64 dun); +extern bool fscrypt_mergeable_bio(struct bio *bio, u64 dun, bool bio_encrypted); + + /* hooks.c */ extern int fscrypt_file_open(struct inode *inode, struct file *filp); extern int __fscrypt_prepare_link(struct inode *inode, struct inode *dir); diff --git a/include/linux/pfk.h b/include/linux/pfk.h index 3c7a389fd4d4..8cc20edb6802 100644 --- a/include/linux/pfk.h +++ b/include/linux/pfk.h @@ -19,8 +19,22 @@ struct ice_crypto_setting; #ifdef CONFIG_PFK +/* + * Default key for inline encryption. + * + * For now only AES-256-XTS is supported, so this is a fixed length. But if + * ever needed, this should be made variable-length with a 'mode' and 'size'. + * (Remember to update pfk_allow_merge_bio() when doing so!) + */ +#define BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS 64 + +struct blk_encryption_key { + u8 raw[BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS]; +}; + int pfk_load_key_start(const struct bio *bio, - struct ice_crypto_setting *ice_setting, bool *is_pfe, bool); + struct ice_crypto_setting *ice_setting, + bool *is_pfe, bool async); int pfk_load_key_end(const struct bio *bio, bool *is_pfe); int pfk_remove_key(const unsigned char *key, size_t key_size); bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2); diff --git a/include/linux/security.h b/include/linux/security.h index 30fb23a4ca81..0cd947e5fb00 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -668,8 +668,8 @@ static inline int security_inode_create(struct inode *dir, } static inline int security_inode_post_create(struct inode *dir, - struct dentry *dentry, - umode_t mode) + struct dentry *dentry, + umode_t mode) { return 0; } diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 00f18dd00372..8fd4cda282c3 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -663,6 +663,9 @@ struct Scsi_Host { /* The controller does not support WRITE SAME */ unsigned no_write_same:1; + /* Inline encryption support? */ + unsigned inlinecrypt_support:1; + unsigned use_blk_mq:1; unsigned use_cmd_list:1; diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h index 971e82aec6d0..5bf4dcb38013 100644 --- a/include/uapi/linux/fs.h +++ b/include/uapi/linux/fs.h @@ -277,6 +277,7 @@ struct fsxattr { #define FS_ENCRYPTION_MODE_AES_128_CTS 6 #define FS_ENCRYPTION_MODE_SPECK128_256_XTS 7 #define FS_ENCRYPTION_MODE_SPECK128_256_CTS 8 +#define FS_ENCRYPTION_MODE_PRIVATE 127 struct fscrypt_policy { __u8 version; diff --git a/security/Kconfig b/security/Kconfig index 87d8bb2df7c8..1996a6bace8a 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -10,7 +10,6 @@ if ARCH_QCOM source security/pfe/Kconfig endif - config SECURITY_DMESG_RESTRICT bool "Restrict unprivileged access to the kernel syslog" default n diff --git a/security/Makefile b/security/Makefile index f15945d3800b..47bffaa3f5f8 100644 --- a/security/Makefile +++ b/security/Makefile @@ -10,7 +10,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor subdir-$(CONFIG_SECURITY_YAMA) += yama subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin -subdir-$(CONFIG_ARCH_QCOM) += pfe +subdir-$(CONFIG_ARCH_QCOM) += pfe # always enable default capabilities obj-y += commoncap.o @@ -26,8 +26,8 @@ obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/ obj-$(CONFIG_SECURITY_YAMA) += yama/ obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ -obj-$(CONFIG_ARCH_QCOM) += pfe/ obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o +obj-$(CONFIG_ARCH_QCOM) += pfe/ # Object integrity file lists subdir-$(CONFIG_INTEGRITY) += integrity diff --git a/security/pfe/Kconfig b/security/pfe/Kconfig index 0cd9e81a4952..45640adf8101 100644 --- a/security/pfe/Kconfig +++ b/security/pfe/Kconfig @@ -25,4 +25,15 @@ config PFK Information is used when file is encrypted later using ICE or dm crypto engine +config PFK_WRAPPED_KEY_SUPPORTED + bool "Per-File-Key driver with wrapped key support" + depends on SECURITY + depends on SECURITY_SELINUX + depends on QSEECOM + depends on PFK + default n + help + Adds wrapped key support in PFK driver. Instead of setting + the key directly in ICE, it unwraps the key and sets the key + in ICE. endmenu diff --git a/security/pfe/Makefile b/security/pfe/Makefile index 242a2165fccb..2507557837db 100644 --- a/security/pfe/Makefile +++ b/security/pfe/Makefile @@ -3,8 +3,8 @@ # ccflags-y += -Isecurity/selinux -Isecurity/selinux/include -ccflags-y += -Ifs/ext4 ccflags-y += -Ifs/crypto +ccflags-y += -Idrivers/misc obj-$(CONFIG_PFT) += pft.o -obj-$(CONFIG_PFK) += pfk.o pfk_kc.o pfk_ice.o pfk_ext4.o +obj-$(CONFIG_PFK) += pfk.o pfk_kc.o pfk_ice.o pfk_ext4.o pfk_f2fs.o diff --git a/security/pfe/pfk.c b/security/pfe/pfk.c index b38cd5c4b05d..27a2ede61946 100644 --- a/security/pfe/pfk.c +++ b/security/pfe/pfk.c @@ -37,6 +37,9 @@ * */ + +/* Uncomment the line below to enable debug messages */ +/* #define DEBUG 1 */ #define pr_fmt(fmt) "pfk [%s]: " fmt, __func__ #include @@ -45,24 +48,27 @@ #include #include #include -#include +#include #include -#include "ext4.h" -#include "objsec.h" +#include + #include "pfk_kc.h" +#include "objsec.h" #include "pfk_ice.h" #include "pfk_ext4.h" +#include "pfk_f2fs.h" #include "pfk_internal.h" static bool pfk_ready; + /* might be replaced by a table when more than one cipher is supported */ #define PFK_SUPPORTED_KEY_SIZE 32 #define PFK_SUPPORTED_SALT_SIZE 32 /* Various PFE types and function tables to support each one of them */ -enum pfe_type {EXT4_CRYPT_PFE, INVALID_PFE}; +enum pfe_type {EXT4_CRYPT_PFE, F2FS_CRYPT_PFE, INVALID_PFE}; typedef int (*pfk_parse_inode_type)(const struct bio *bio, const struct inode *inode, @@ -76,31 +82,40 @@ typedef bool (*pfk_allow_merge_bio_type)(const struct bio *bio1, static const pfk_parse_inode_type pfk_parse_inode_ftable[] = { /* EXT4_CRYPT_PFE */ &pfk_ext4_parse_inode, + /* F2FS_CRYPT_PFE */ &pfk_f2fs_parse_inode, }; static const pfk_allow_merge_bio_type pfk_allow_merge_bio_ftable[] = { /* EXT4_CRYPT_PFE */ &pfk_ext4_allow_merge_bio, + /* F2FS_CRYPT_PFE */ &pfk_f2fs_allow_merge_bio, }; static void __exit pfk_exit(void) { pfk_ready = false; pfk_ext4_deinit(); + pfk_f2fs_deinit(); pfk_kc_deinit(); } static int __init pfk_init(void) { + int ret = 0; ret = pfk_ext4_init(); if (ret != 0) goto fail; + ret = pfk_f2fs_init(); + if (ret != 0) + goto fail; + ret = pfk_kc_init(); if (ret != 0) { pr_err("could init pfk key cache, error %d\n", ret); pfk_ext4_deinit(); + pfk_f2fs_deinit(); goto fail; } @@ -126,6 +141,9 @@ static enum pfe_type pfk_get_pfe_type(const struct inode *inode) if (pfk_is_ext4_type(inode)) return EXT4_CRYPT_PFE; + if (pfk_is_f2fs_type(inode)) + return F2FS_CRYPT_PFE; + return INVALID_PFE; } @@ -142,6 +160,9 @@ char *inode_to_filename(const struct inode *inode) struct dentry *dentry = NULL; char *filename = NULL; + if (!inode) + return "NULL"; + if (hlist_empty(&inode->i_dentry)) return "unknown"; @@ -176,30 +197,30 @@ static inline bool pfk_is_ready(void) */ static struct inode *pfk_bio_get_inode(const struct bio *bio) { - struct address_space *mapping; - if (!bio) return NULL; + if (!bio_has_data((struct bio *)bio)) + return NULL; if (!bio->bi_io_vec) return NULL; if (!bio->bi_io_vec->bv_page) return NULL; - if (!bio_has_data((struct bio *)bio)) - return NULL; if (PageAnon(bio->bi_io_vec->bv_page)) { struct inode *inode; + /* Using direct-io (O_DIRECT) without page cache */ inode = dio_bio_get_inode((struct bio *)bio); pr_debug("inode on direct-io, inode = 0x%pK.\n", inode); + return inode; } - mapping = page_mapping(bio->bi_io_vec->bv_page); - if (!mapping) + if (!page_mapping(bio->bi_io_vec->bv_page)) return NULL; - if (!mapping->host) + if (!bio->bi_io_vec->bv_page->mapping->host) + return NULL; return bio->bi_io_vec->bv_page->mapping->host; @@ -250,6 +271,58 @@ bool pfe_is_inode_filesystem_type(const struct inode *inode, return (strcmp(inode->i_sb->s_type->name, fs_type) == 0); } +/** + * pfk_get_key_for_bio() - get the encryption key to be used for a bio + * + * @bio: pointer to the BIO + * @key_info: pointer to the key information which will be filled in + * @algo_mode: optional pointer to the algorithm identifier which will be set + * @is_pfe: will be set to false if the BIO should be left unencrypted + * + * Return: 0 if a key is being used, otherwise a -errno value + */ +static int pfk_get_key_for_bio(const struct bio *bio, + struct pfk_key_info *key_info, + enum ice_cryto_algo_mode *algo_mode, + bool *is_pfe) +{ + const struct inode *inode; + enum pfe_type which_pfe; + const struct blk_encryption_key *key; + + inode = pfk_bio_get_inode(bio); + which_pfe = pfk_get_pfe_type(inode); + + if (which_pfe != INVALID_PFE) { + /* Encrypted file; override ->bi_crypt_key */ + pr_debug("parsing inode %lu with PFE type %d\n", + inode->i_ino, which_pfe); + return (*(pfk_parse_inode_ftable[which_pfe])) + (bio, inode, key_info, algo_mode, is_pfe); + } + + /* + * bio is not for an encrypted file. Use ->bi_crypt_key if it was set. + * Otherwise, don't encrypt/decrypt the bio. + */ + key = bio->bi_crypt_key; + if (!key) { + *is_pfe = false; + return -EINVAL; + } + + /* Note: the "salt" is really just the second half of the XTS key. */ + BUILD_BUG_ON(sizeof(key->raw) != + PFK_SUPPORTED_KEY_SIZE + PFK_SUPPORTED_SALT_SIZE); + key_info->key = &key->raw[0]; + key_info->key_size = PFK_SUPPORTED_KEY_SIZE; + key_info->salt = &key->raw[PFK_SUPPORTED_KEY_SIZE]; + key_info->salt_size = PFK_SUPPORTED_SALT_SIZE; + if (algo_mode) + *algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS; + return 0; +} + /** * pfk_load_key_start() - loads PFE encryption key to the ICE @@ -279,8 +352,6 @@ int pfk_load_key_start(const struct bio *bio, enum ice_cryto_algo_mode algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS; enum ice_crpto_key_size key_size_type = 0; u32 key_index = 0; - struct inode *inode = NULL; - enum pfe_type which_pfe = INVALID_PFE; if (!is_pfe) { pr_err("is_pfe is NULL\n"); @@ -301,26 +372,16 @@ int pfk_load_key_start(const struct bio *bio, pr_err("ice setting is NULL\n"); return -EINVAL; } - inode = pfk_bio_get_inode(bio); - if (!inode) { - *is_pfe = false; - return -EINVAL; - } - which_pfe = pfk_get_pfe_type(inode); - if (which_pfe == INVALID_PFE) { - *is_pfe = false; - return -EPERM; - } - pr_debug("parsing file %s with PFE %d\n", - inode_to_filename(inode), which_pfe); - ret = (*(pfk_parse_inode_ftable[which_pfe])) - (bio, inode, &key_info, &algo_mode, is_pfe); + ret = pfk_get_key_for_bio(bio, &key_info, &algo_mode, is_pfe); + if (ret != 0) return ret; + ret = pfk_key_size_to_key_type(key_info.key_size, &key_size_type); if (ret != 0) return ret; + ret = pfk_kc_load_key_start(key_info.key, key_info.key_size, key_info.salt, key_info.salt_size, &key_index, async); if (ret) { @@ -338,7 +399,7 @@ int pfk_load_key_start(const struct bio *bio, ice_setting->key_index = key_index; pr_debug("loaded key for file %s key_index %d\n", - inode_to_filename(inode), key_index); + inode_to_filename(pfk_bio_get_inode(bio)), key_index); return 0; } @@ -357,9 +418,7 @@ int pfk_load_key_start(const struct bio *bio, int pfk_load_key_end(const struct bio *bio, bool *is_pfe) { int ret = 0; - struct pfk_key_info key_info = {0}; - enum pfe_type which_pfe = INVALID_PFE; - struct inode *inode = NULL; + struct pfk_key_info key_info = {NULL, NULL, 0, 0}; if (!is_pfe) { pr_err("is_pfe is NULL\n"); @@ -375,20 +434,7 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe) if (!pfk_is_ready()) return -ENODEV; - inode = pfk_bio_get_inode(bio); - if (!inode) { - *is_pfe = false; - return -EINVAL; - } - - which_pfe = pfk_get_pfe_type(inode); - if (which_pfe == INVALID_PFE) { - *is_pfe = false; - return -EPERM; - } - - ret = (*(pfk_parse_inode_ftable[which_pfe])) - (bio, inode, &key_info, NULL, is_pfe); + ret = pfk_get_key_for_bio(bio, &key_info, NULL, is_pfe); if (ret != 0) return ret; @@ -396,7 +442,7 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe) key_info.salt, key_info.salt_size); pr_debug("finished using key for file %s\n", - inode_to_filename(inode)); + inode_to_filename(pfk_bio_get_inode(bio))); return 0; } @@ -418,10 +464,12 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe) */ bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2) { - struct inode *inode1 = NULL; - struct inode *inode2 = NULL; - enum pfe_type which_pfe1 = INVALID_PFE; - enum pfe_type which_pfe2 = INVALID_PFE; + const struct blk_encryption_key *key1; + const struct blk_encryption_key *key2; + const struct inode *inode1; + const struct inode *inode2; + enum pfe_type which_pfe1; + enum pfe_type which_pfe2; if (!pfk_is_ready()) return false; @@ -432,24 +480,38 @@ bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2) if (bio1 == bio2) return true; + key1 = bio1->bi_crypt_key; + key2 = bio2->bi_crypt_key; + inode1 = pfk_bio_get_inode(bio1); inode2 = pfk_bio_get_inode(bio2); - which_pfe1 = pfk_get_pfe_type(inode1); which_pfe2 = pfk_get_pfe_type(inode2); - /* nodes with different encryption, do not merge */ + /* + * If one bio is for an encrypted file and the other is for a different + * type of encrypted file or for blocks that are not part of an + * encrypted file, do not merge. + */ if (which_pfe1 != which_pfe2) return false; - /* both nodes do not have encryption, allow merge */ - if (which_pfe1 == INVALID_PFE) - return true; + if (which_pfe1 != INVALID_PFE) { + /* Both bios are for the same type of encrypted file. */ + return (*(pfk_allow_merge_bio_ftable[which_pfe1]))(bio1, bio2, + inode1, inode2); + } - return (*(pfk_allow_merge_bio_ftable[which_pfe1]))(bio1, bio2, - inode1, inode2); + /* + * Neither bio is for an encrypted file. Merge only if the default keys + * are the same (or both are NULL). + */ + return key1 == key2 || + (key1 && key2 && + !crypto_memneq(key1->raw, key2->raw, sizeof(key1->raw))); } + /** * Flush key table on storage core reset. During core reset key configuration * is lost in ICE. We need to flash the cache, so that the keys will be diff --git a/security/pfe/pfk_ext4.c b/security/pfe/pfk_ext4.c index 05a8628e34b8..0eb122565ecc 100644 --- a/security/pfe/pfk_ext4.c +++ b/security/pfe/pfk_ext4.c @@ -26,6 +26,9 @@ * */ + +/* Uncomment the line below to enable debug messages */ +/* #define DEBUG 1 */ #define pr_fmt(fmt) "pfk_ext4 [%s]: " fmt, __func__ #include @@ -33,8 +36,9 @@ #include #include -#include "ext4_ice.h" +#include "fscrypt_ice.h" #include "pfk_ext4.h" +//#include "ext4_ice.h" static bool pfk_ext4_ready; @@ -67,6 +71,29 @@ static inline bool pfk_ext4_is_ready(void) return pfk_ext4_ready; } +/** + * pfk_ext4_dump_inode() - dumps all interesting info about inode to the screen + * + * + */ +/* + * static void pfk_ext4_dump_inode(const struct inode* inode) + * { + * struct ext4_crypt_info *ci = ext4_encryption_info((struct inode*)inode); + * + * pr_debug("dumping inode with address 0x%p\n", inode); + * pr_debug("S_ISREG is %d\n", S_ISREG(inode->i_mode)); + * pr_debug("EXT4_INODE_ENCRYPT flag is %d\n", + * ext4_test_inode_flag((struct inode*)inode, EXT4_INODE_ENCRYPT)); + * if (ci) { + * pr_debug("crypt_info address 0x%p\n", ci); + * pr_debug("ci->ci_data_mode %d\n", ci->ci_data_mode); + * } else { + * pr_debug("crypt_info is NULL\n"); + * } + * } + */ + /** * pfk_is_ext4_type() - return true if inode belongs to ICE EXT4 PFE * @inode: inode pointer @@ -76,7 +103,7 @@ bool pfk_is_ext4_type(const struct inode *inode) if (!pfe_is_inode_filesystem_type(inode, "ext4")) return false; - return ext4_should_be_processed_by_ice(inode); + return fscrypt_should_be_processed_by_ice(inode); } /** @@ -98,7 +125,7 @@ static int pfk_ext4_parse_cipher(const struct inode *inode, if (!inode) return -EINVAL; - if (!ext4_is_aes_xts_cipher(inode)) { + if (!fscrypt_is_aes_xts_cipher(inode)) { pr_err("ext4 alghoritm is not supported by pfk\n"); return -EINVAL; } @@ -109,6 +136,7 @@ static int pfk_ext4_parse_cipher(const struct inode *inode, return 0; } + int pfk_ext4_parse_inode(const struct bio *bio, const struct inode *inode, struct pfk_key_info *key_info, @@ -136,25 +164,25 @@ int pfk_ext4_parse_inode(const struct bio *bio, if (!key_info) return -EINVAL; - key_info->key = ext4_get_ice_encryption_key(inode); + key_info->key = fscrypt_get_ice_encryption_key(inode); if (!key_info->key) { pr_err("could not parse key from ext4\n"); return -EINVAL; } - key_info->key_size = ext4_get_ice_encryption_key_size(inode); + key_info->key_size = fscrypt_get_ice_encryption_key_size(inode); if (!key_info->key_size) { pr_err("could not parse key size from ext4\n"); return -EINVAL; } - key_info->salt = ext4_get_ice_encryption_salt(inode); + key_info->salt = fscrypt_get_ice_encryption_salt(inode); if (!key_info->salt) { pr_err("could not parse salt from ext4\n"); return -EINVAL; } - key_info->salt_size = ext4_get_ice_encryption_salt_size(inode); + key_info->salt_size = fscrypt_get_ice_encryption_salt_size(inode); if (!key_info->salt_size) { pr_err("could not parse salt size from ext4\n"); return -EINVAL; @@ -180,5 +208,5 @@ bool pfk_ext4_allow_merge_bio(const struct bio *bio1, if (!inode1 || !inode2) return false; - return ext4_is_ice_encryption_info_equal(inode1, inode2); + return fscrypt_is_ice_encryption_info_equal(inode1, inode2); } diff --git a/security/pfe/pfk_f2fs.c b/security/pfe/pfk_f2fs.c new file mode 100644 index 000000000000..8b9d515043e8 --- /dev/null +++ b/security/pfe/pfk_f2fs.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Per-File-Key (PFK) - f2fs + * + * This driver is used for working with EXT4/F2FS crypt extension + * + * The key information is stored in node by EXT4/F2FS when file is first opened + * and will be later accessed by Block Device Driver to actually load the key + * to encryption hw. + * + * PFK exposes API's for loading and removing keys from encryption hw + * and also API to determine whether 2 adjacent blocks can be agregated by + * Block Layer in one request to encryption hw. + * + */ + + +/* Uncomment the line below to enable debug messages */ +#define DEBUG 1 +#define pr_fmt(fmt) "pfk_f2fs [%s]: " fmt, __func__ + +#include +#include +#include +#include + +#include "fscrypt_ice.h" +#include "pfk_f2fs.h" + +static bool pfk_f2fs_ready; + +/* + * pfk_f2fs_deinit() - Deinit function, should be invoked by upper PFK layer + */ +void pfk_f2fs_deinit(void) +{ + pfk_f2fs_ready = false; +} + +/* + * pfk_f2fs_init() - Init function, should be invoked by upper PFK layer + */ +int __init pfk_f2fs_init(void) +{ + pfk_f2fs_ready = true; + pr_info("PFK F2FS inited successfully\n"); + + return 0; +} + +/** + * pfk_f2fs_is_ready() - driver is initialized and ready. + * + * Return: true if the driver is ready. + */ +static inline bool pfk_f2fs_is_ready(void) +{ + return pfk_f2fs_ready; +} + +/** + * pfk_is_f2fs_type() - return true if inode belongs to ICE F2FS PFE + * @inode: inode pointer + */ +bool pfk_is_f2fs_type(const struct inode *inode) +{ + if (!pfe_is_inode_filesystem_type(inode, "f2fs")) + return false; + + return fscrypt_should_be_processed_by_ice(inode); +} + +/** + * pfk_f2fs_parse_cipher() - parse cipher from inode to enum + * @inode: inode + * @algo: pointer to store the output enum (can be null) + * + * return 0 in case of success, error otherwise (i.e not supported cipher) + */ +static int pfk_f2fs_parse_cipher(const struct inode *inode, + enum ice_cryto_algo_mode *algo) +{ + /* + * currently only AES XTS algo is supported + * in the future, table with supported ciphers might + * be introduced + */ + if (!inode) + return -EINVAL; + + if (!fscrypt_is_aes_xts_cipher(inode)) { + pr_err("f2fs alghoritm is not supported by pfk\n"); + return -EINVAL; + } + + if (algo) + *algo = ICE_CRYPTO_ALGO_MODE_AES_XTS; + + return 0; +} + + +int pfk_f2fs_parse_inode(const struct bio *bio, + const struct inode *inode, + struct pfk_key_info *key_info, + enum ice_cryto_algo_mode *algo, + bool *is_pfe) +{ + int ret = 0; + + if (!is_pfe) + return -EINVAL; + + /* + * only a few errors below can indicate that + * this function was not invoked within PFE context, + * otherwise we will consider it PFE + */ + *is_pfe = true; + + if (!pfk_f2fs_is_ready()) + return -ENODEV; + + if (!inode) + return -EINVAL; + + if (!key_info) + return -EINVAL; + + key_info->key = fscrypt_get_ice_encryption_key(inode); + if (!key_info->key) { + pr_err("could not parse key from f2fs\n"); + return -EINVAL; + } + + key_info->key_size = fscrypt_get_ice_encryption_key_size(inode); + if (!key_info->key_size) { + pr_err("could not parse key size from f2fs\n"); + return -EINVAL; + } + + key_info->salt = fscrypt_get_ice_encryption_salt(inode); + if (!key_info->salt) { + pr_err("could not parse salt from f2fs\n"); + return -EINVAL; + } + + key_info->salt_size = fscrypt_get_ice_encryption_salt_size(inode); + if (!key_info->salt_size) { + pr_err("could not parse salt size from f2fs\n"); + return -EINVAL; + } + + ret = pfk_f2fs_parse_cipher(inode, algo); + if (ret != 0) { + pr_err("not supported cipher\n"); + return ret; + } + + return 0; +} + +bool pfk_f2fs_allow_merge_bio(const struct bio *bio1, + const struct bio *bio2, const struct inode *inode1, + const struct inode *inode2) +{ + bool mergeable; + + /* if there is no f2fs pfk, don't disallow merging blocks */ + if (!pfk_f2fs_is_ready()) + return true; + + if (!inode1 || !inode2) + return false; + + mergeable = fscrypt_is_ice_encryption_info_equal(inode1, inode2); + if (!mergeable) + return false; + + + /* ICE allows only consecutive iv_key stream. */ + if (!bio_dun(bio1) && !bio_dun(bio2)) + return true; + else if (!bio_dun(bio1) || !bio_dun(bio2)) + return false; + + return bio_end_dun(bio1) == bio_dun(bio2); +} diff --git a/security/pfe/pfk_f2fs.h b/security/pfe/pfk_f2fs.h new file mode 100644 index 000000000000..551d529bced6 --- /dev/null +++ b/security/pfe/pfk_f2fs.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _PFK_F2FS_H_ +#define _PFK_F2FS_H_ + +#include +#include +#include +#include "pfk_internal.h" + +bool pfk_is_f2fs_type(const struct inode *inode); + +int pfk_f2fs_parse_inode(const struct bio *bio, + const struct inode *inode, + struct pfk_key_info *key_info, + enum ice_cryto_algo_mode *algo, + bool *is_pfe); + +bool pfk_f2fs_allow_merge_bio(const struct bio *bio1, + const struct bio *bio2, const struct inode *inode1, + const struct inode *inode2); + +int __init pfk_f2fs_init(void); + +void pfk_f2fs_deinit(void); + +#endif /* _PFK_F2FS_H_ */ diff --git a/security/pfe/pfk_ice.c b/security/pfe/pfk_ice.c index bf60dd18dd76..6452b4220136 100644 --- a/security/pfe/pfk_ice.c +++ b/security/pfe/pfk_ice.c @@ -24,7 +24,7 @@ #include #include #include "pfk_ice.h" - +#include "qseecom_kernel.h" /**********************************/ /** global definitions **/ @@ -55,48 +55,120 @@ TZ_SYSCALL_CREATE_PARAM_ID_1( \ TZ_SYSCALL_PARAM_TYPE_VAL) +#define CONTEXT_SIZE 0x1000 + +#define KEYMASTER_UTILS_CMD_ID 0x200UL +#define KEYMASTER_SET_ICE_KEY (KEYMASTER_UTILS_CMD_ID + 18UL) +#define KEYMASTER_CLEAR_ICE_KEY (KEYMASTER_UTILS_CMD_ID + 19UL) + #define ICE_KEY_SIZE 32 #define ICE_SALT_SIZE 32 static uint8_t ice_key[ICE_KEY_SIZE]; static uint8_t ice_salt[ICE_KEY_SIZE]; -int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, - char *storage_type) +static struct qseecom_handle *qhandle; + +static int set_wrapped_key(uint32_t index, const uint8_t *key, + const uint8_t *salt) +{ + int ret = 0; + u32 set_req_len = 0; + u32 set_rsp_len = 0; + struct pfk_ice_key_req *set_req_buf; + struct pfk_ice_key_rsp *set_rsp_buf; + + memcpy(ice_key, key, sizeof(ice_key)); + memcpy(ice_salt, salt, sizeof(ice_salt)); + + if (!qhandle) { + ret = qseecom_start_app(&qhandle, "keymaster64", + CONTEXT_SIZE); + if (ret) { + pr_err("Qseecom start app failed\n"); + return ret; + } + } + + set_req_buf = (struct pfk_ice_key_req *) qhandle->sbuf; + set_req_buf->cmd_id = KEYMASTER_SET_ICE_KEY; + set_req_buf->index = index; + set_req_buf->ice_key_offset = sizeof(struct pfk_ice_key_req); + set_req_buf->ice_key_size = ICE_KEY_SIZE; + set_req_buf->ice_salt_offset = set_req_buf->ice_key_offset + + set_req_buf->ice_key_size; + set_req_buf->ice_salt_size = ICE_SALT_SIZE; + + memcpy((uint8_t *) set_req_buf + set_req_buf->ice_key_offset, ice_key, + set_req_buf->ice_key_size); + memcpy((uint8_t *) set_req_buf + set_req_buf->ice_salt_offset, ice_salt, + set_req_buf->ice_salt_size); + + set_req_len = sizeof(struct pfk_ice_key_req) + set_req_buf->ice_key_size + + set_req_buf->ice_salt_size; + + set_rsp_buf = (struct pfk_ice_key_rsp *) (qhandle->sbuf + + set_req_len); + set_rsp_len = sizeof(struct pfk_ice_key_rsp); + + ret = qseecom_send_command(qhandle, + set_req_buf, set_req_len, + set_rsp_buf, set_rsp_len); + + if (ret) + pr_err("%s: Set wrapped key error: Status %d\n", __func__, + set_rsp_buf->ret); + + return ret; +} + +static int clear_wrapped_key(uint32_t index) +{ + int ret = 0; + + u32 clear_req_len = 0; + u32 clear_rsp_len = 0; + struct pfk_ice_key_req *clear_req_buf; + struct pfk_ice_key_rsp *clear_rsp_buf; + + clear_req_buf = (struct pfk_ice_key_req *) qhandle->sbuf; + memset(clear_req_buf, 0, sizeof(qhandle->sbuf)); + clear_req_buf->cmd_id = KEYMASTER_CLEAR_ICE_KEY; + clear_req_buf->index = index; + clear_req_len = sizeof(struct pfk_ice_key_req); + clear_rsp_buf = (struct pfk_ice_key_rsp *) (qhandle->sbuf + + QSEECOM_ALIGN(clear_req_len)); + clear_rsp_len = sizeof(struct pfk_ice_key_rsp); + + ret = qseecom_send_command(qhandle, clear_req_buf, clear_req_len, + clear_rsp_buf, clear_rsp_len); + if (ret) + pr_err("%s: Clear wrapped key error: Status %d\n", __func__, + clear_rsp_buf->ret); + + return ret; +} + +static int set_key(uint32_t index, const uint8_t *key, const uint8_t *salt) { struct scm_desc desc = {0}; - int ret, ret1; + int ret = 0; + uint32_t smc_id = 0; char *tzbuf_key = (char *)ice_key; char *tzbuf_salt = (char *)ice_salt; - char *s_type = storage_type; - uint32_t smc_id = 0; u32 tzbuflen_key = sizeof(ice_key); u32 tzbuflen_salt = sizeof(ice_salt); - if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { - pr_err("%s Invalid index %d\n", __func__, index); - return -EINVAL; - } - if (!key || !salt) { - pr_err("%s Invalid key/salt\n", __func__); - return -EINVAL; - } - if (!tzbuf_key || !tzbuf_salt) { pr_err("%s No Memory\n", __func__); return -ENOMEM; } - if (s_type == NULL) { - pr_err("%s Invalid Storage type\n", __func__); - return -EINVAL; - } - memset(tzbuf_key, 0, tzbuflen_key); memset(tzbuf_salt, 0, tzbuflen_salt); - memcpy(ice_key, key, tzbuflen_key); - memcpy(ice_salt, salt, tzbuflen_salt); + memcpy(ice_key, key, sizeof(ice_key)); + memcpy(ice_salt, salt, sizeof(ice_salt)); dmac_flush_range(tzbuf_key, tzbuf_key + tzbuflen_key); dmac_flush_range(tzbuf_salt, tzbuf_salt + tzbuflen_salt); @@ -110,33 +182,84 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, desc.args[3] = virt_to_phys(tzbuf_salt); desc.args[4] = tzbuflen_salt; + ret = scm_call2(smc_id, &desc); + if (ret) + pr_err("%s:SCM call Error: 0x%x\n", __func__, ret); + + return ret; +} + +static int clear_key(uint32_t index) +{ + struct scm_desc desc = {0}; + int ret = 0; + uint32_t smc_id = 0; + + smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; + + desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; + desc.args[0] = index; + + ret = scm_call2(smc_id, &desc); + if (ret) + pr_err("%s:SCM call Error: 0x%x\n", __func__, ret); + return ret; +} + +int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, + char *storage_type) +{ + int ret = 0, ret1 = 0; + char *s_type = storage_type; + + if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { + pr_err("%s Invalid index %d\n", __func__, index); + return -EINVAL; + } + if (!key || !salt) { + pr_err("%s Invalid key/salt\n", __func__); + return -EINVAL; + } + + if (s_type == NULL) { + pr_err("%s Invalid Storage type\n", __func__); + return -EINVAL; + } + ret = qcom_ice_setup_ice_hw((const char *)s_type, true); if (ret) { pr_err("%s: could not enable clocks: %d\n", __func__, ret); goto out; } - ret = scm_call2(smc_id, &desc); + if (pfk_wrapped_key_supported()) { + pr_debug("%s: Setting wrapped key\n", __func__); + ret = set_wrapped_key(index, key, salt); + } else { + pr_debug("%s: Setting keys with QSEE kernel\n", __func__); + ret = set_key(index, key, salt); + } + if (ret) { pr_err("%s: Set Key Error: %d\n", __func__, ret); if (ret == -EBUSY) { if (qcom_ice_setup_ice_hw((const char *)s_type, false)) pr_err("%s: clock disable failed\n", __func__); - goto out; + goto out; } /* Try to invalidate the key to keep ICE in proper state */ - smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; - desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; - desc.args[0] = index; - ret1 = scm_call2(smc_id, &desc); + if (pfk_wrapped_key_supported()) + ret1 = clear_wrapped_key(index); + else + ret1 = clear_key(index); + if (ret1) - pr_err("%s: Invalidate Key Error: %d\n", __func__, - ret1); + pr_err("%s: Invalidate key error: %d\n", __func__, ret); } ret1 = qcom_ice_setup_ice_hw((const char *)s_type, false); - if (ret1) - pr_err("%s: Error %d disabling clocks\n", __func__, ret1); + if (ret) + pr_err("%s: Error %d disabling clocks\n", __func__, ret); out: return ret; @@ -144,11 +267,8 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type) { - struct scm_desc desc = {0}; int ret = 0; - uint32_t smc_id = 0; - if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { pr_err("%s Invalid index %d\n", __func__, index); return -EINVAL; @@ -159,20 +279,22 @@ int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type) return -EINVAL; } - smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; - - desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; - desc.args[0] = index; - ret = qcom_ice_setup_ice_hw((const char *)storage_type, true); if (ret) { pr_err("%s: could not enable clocks: 0x%x\n", __func__, ret); return ret; } - ret = scm_call2(smc_id, &desc); + if (pfk_wrapped_key_supported()) { + ret = clear_wrapped_key(index); + pr_debug("%s: Clearing wrapped key\n", __func__); + } else { + pr_debug("%s: Clearing keys with QSEE kernel\n", __func__); + ret = clear_key(index); + } + if (ret) - pr_err("%s: Error: 0x%x\n", __func__, ret); + pr_err("%s: Invalidate key error: %d\n", __func__, ret); if (qcom_ice_setup_ice_hw((const char *)storage_type, false)) pr_err("%s: could not disable clocks\n", __func__); diff --git a/security/pfe/pfk_ice.h b/security/pfe/pfk_ice.h index a00193919116..5adfcb200b68 100644 --- a/security/pfe/pfk_ice.h +++ b/security/pfe/pfk_ice.h @@ -22,9 +22,35 @@ #include +struct __attribute__ ((__packed__)) pfk_ice_key_req { + uint32_t cmd_id; + uint32_t index; + uint32_t ice_key_offset; + uint32_t ice_key_size; + uint32_t ice_salt_offset; + uint32_t ice_salt_size; +}; + +struct __attribute__ ((__packed__)) pfk_ice_key_rsp { + uint32_t ret; + uint32_t cmd_id; +}; + int pfk_ice_init(void); int pfk_ice_deinit(void); +#ifdef CONFIG_PFK_WRAPPED_KEY_SUPPORTED +static inline bool pfk_wrapped_key_supported(void) +{ + return true; +} +#else +static inline bool pfk_wrapped_key_supported(void) +{ + return false; +} +#endif + int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, char *storage_type); int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type); diff --git a/security/pfe/pfk_kc.c b/security/pfe/pfk_kc.c index 6ccfbd1a5484..041a02f1b3ee 100644 --- a/security/pfe/pfk_kc.c +++ b/security/pfe/pfk_kc.c @@ -435,6 +435,7 @@ int pfk_kc_init(void) } kc_ready = true; kc_spin_unlock(); + return 0; } @@ -448,6 +449,7 @@ int pfk_kc_deinit(void) int res = pfk_kc_clear(); kc_ready = false; + return res; } diff --git a/security/security.c b/security/security.c index d0d99921b751..2ba27d75f052 100644 --- a/security/security.c +++ b/security/security.c @@ -613,7 +613,7 @@ int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode EXPORT_SYMBOL_GPL(security_inode_create); int security_inode_post_create(struct inode *dir, struct dentry *dentry, - umode_t mode) + umode_t mode) { if (unlikely(IS_PRIVATE(dir))) return 0; diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index af8582501f93..9cec304b6937 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -66,7 +66,7 @@ struct inode_security_struct { u16 sclass; /* security class of this object */ unsigned char initialized; /* initialization flag */ u32 tag; /* Per-File-Encryption tag */ - void *pfk_data; /* Per-File-Key data from ecryptfs */ + void *pfk_data; /* Per-File-Key data from ecryptfs */ spinlock_t lock; }; diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index de4c7d32b955..99203f1b32ff 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -13,6 +13,7 @@ #include #include #include +//#include "flask.h" #define SECSID_NULL 0x00000000 /* unspecified SID */ #define SECSID_WILD 0xffffffff /* wildcard SID */ -- GitLab From 5af9c5b2aeb0554829a7e2735f04e8bfcdaf09c7 Mon Sep 17 00:00:00 2001 From: Maheshwar Ajja Date: Tue, 21 Aug 2018 19:34:19 -0700 Subject: [PATCH 0923/1001] msm: vidc: Fix under vote issue in multi session usecase When calculating bus vote and clocks before each input buffer queuing we try to check the available input buffers which are not queued to firmware yet and select the bus vote and clocks if any such buffers available. This method will function properly for single session as one input which is not yet queued is always available. For multiple sessions case the other sessions input buffers which are not queued yet are not available and hence we don't add other sessions required bus vote and clocks leading to under vote in multiple sessions usecase. Change-Id: I14f33738da2d3ce0fbf96219c14545d3f290bc02 Signed-off-by: Maheshwar Ajja --- drivers/media/platform/msm/vidc/msm_vidc_clocks.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c index 912ed07de814..0adbca342037 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c @@ -241,8 +241,7 @@ int msm_comm_vote_bus(struct msm_vidc_core *core) list_for_each_entry_safe(temp, next, &inst->registeredbufs.list, list) { if (temp->vvb.vb2_buf.type == - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && - temp->flags & MSM_VIDC_FLAG_DEFERRED) { + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { filled_len = max(filled_len, temp->vvb.vb2_buf.planes[0].bytesused); device_addr = temp->smem[0].device_addr; @@ -257,7 +256,8 @@ int msm_comm_vote_bus(struct msm_vidc_core *core) if ((!filled_len || !device_addr) && (inst->session_type != MSM_VIDC_CVP)) { - dprintk(VIDC_DBG, "%s No ETBs\n", __func__); + dprintk(VIDC_DBG, "%s: no input for session %x\n", + __func__, hash32_ptr(inst->session)); continue; } @@ -920,8 +920,7 @@ int msm_comm_scale_clocks(struct msm_vidc_inst *inst) mutex_lock(&inst->registeredbufs.lock); list_for_each_entry_safe(temp, next, &inst->registeredbufs.list, list) { if (temp->vvb.vb2_buf.type == - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && - temp->flags & MSM_VIDC_FLAG_DEFERRED) { + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { filled_len = max(filled_len, temp->vvb.vb2_buf.planes[0].bytesused); if (inst->session_type == MSM_VIDC_ENCODER && @@ -935,7 +934,8 @@ int msm_comm_scale_clocks(struct msm_vidc_inst *inst) mutex_unlock(&inst->registeredbufs.lock); if (!filled_len || !device_addr) { - dprintk(VIDC_DBG, "%s No ETBs\n", __func__); + dprintk(VIDC_DBG, "%s no input for session %x\n", + __func__, hash32_ptr(inst->session)); goto no_clock_change; } -- GitLab From 90fa50356b9aeec8b1775bd11cfadb8f618a2cd3 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Fri, 20 Jul 2018 19:13:18 -0600 Subject: [PATCH 0924/1001] net: qualcomm: rmnet: Use dowlink marker for GRO flushing Switch to using backlog NAPI instead of GRO cells. This helps to reduce some latency in the packet processing. CRs-Fixed: 2285862 Change-Id: Ibd0e9d552c246025c229a8b1100e667022d085a1 Signed-off-by: Subash Abhinov Kasiviswanathan --- .../ethernet/qualcomm/rmnet/rmnet_config.h | 1 + .../ethernet/qualcomm/rmnet/rmnet_handlers.c | 22 ++++++++++++++----- .../qualcomm/rmnet/rmnet_map_command.c | 12 ++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h index 5516d0f169de..2def5e5d3cd0 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h @@ -71,6 +71,7 @@ struct rmnet_port { /* dl marker elements */ struct list_head dl_list; struct rmnet_port_priv_stats stats; + int dl_marker_flush; }; extern struct rtnl_link_ops rmnet_link_ops; diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c index 3e95d301b2ec..244dd1f41841 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c @@ -77,8 +77,8 @@ EXPORT_SYMBOL(rmnet_shs_skb_entry); void rmnet_deliver_skb(struct sk_buff *skb, struct rmnet_port *port) { - struct rmnet_priv *priv = netdev_priv(skb->dev); int (*rmnet_shs_stamp)(struct sk_buff *skb, struct rmnet_port *port); + struct rmnet_priv *priv = netdev_priv(skb->dev); skb_reset_transport_header(skb); skb_reset_network_header(skb); @@ -93,10 +93,22 @@ rmnet_deliver_skb(struct sk_buff *skb, struct rmnet_port *port) return; } - if (!rmnet_check_skb_can_gro(skb)) - gro_cells_receive(&priv->gro_cells, skb); - else - netif_receive_skb(skb); + if (port->data_format & RMNET_INGRESS_FORMAT_DL_MARKER) { + if (!rmnet_check_skb_can_gro(skb) && + port->dl_marker_flush >= 0) { + struct napi_struct *napi = get_current_napi_context(); + + napi_gro_receive(napi, skb); + port->dl_marker_flush++; + } else { + netif_receive_skb(skb); + } + } else { + if (!rmnet_check_skb_can_gro(skb)) + gro_cells_receive(&priv->gro_cells, skb); + else + netif_receive_skb(skb); + } } EXPORT_SYMBOL(rmnet_deliver_skb); diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c index ce17e2749888..56457f72a3c6 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c @@ -99,6 +99,8 @@ static void rmnet_map_dl_hdr_notify(struct rmnet_port *port, { struct rmnet_map_dl_ind *tmp; + port->dl_marker_flush = 0; + list_for_each_entry(tmp, &port->dl_list, list) tmp->dl_hdr_handler(dlhdr); } @@ -107,9 +109,17 @@ static void rmnet_map_dl_trl_notify(struct rmnet_port *port, struct rmnet_map_dl_ind_trl *dltrl) { struct rmnet_map_dl_ind *tmp; + struct napi_struct *napi; list_for_each_entry(tmp, &port->dl_list, list) tmp->dl_trl_handler(dltrl); + + if (port->dl_marker_flush) { + napi = get_current_napi_context(); + napi_gro_flush(napi, false); + } + + port->dl_marker_flush = -1; } static void rmnet_map_process_flow_start(struct sk_buff *skb, @@ -253,6 +263,8 @@ void rmnet_map_cmd_exit(struct rmnet_port *port) void rmnet_map_cmd_init(struct rmnet_port *port) { INIT_LIST_HEAD(&port->dl_list); + + port->dl_marker_flush = -1; } int rmnet_map_dl_ind_register(struct rmnet_port *port, -- GitLab From fb447725596cdbf295036a93bf19af072d01f2fa Mon Sep 17 00:00:00 2001 From: Tapas Kumar Kundu Date: Tue, 21 Aug 2018 14:45:38 -0700 Subject: [PATCH 0925/1001] msm: vidc: Introducing CBR_CFR upto 720p@30fps Introducing CBR_CFR (CBR = constant bitrate, CFR = constant framerate ) upto 720p@30fps due to tighter bitrate convergence. Change-Id: Ic6423a5dfa7df5116f450368021cb5cdb4e09aeb Signed-off-by: Tapas Kumar Kundu --- drivers/media/platform/msm/vidc/msm_vidc.c | 17 ++++++++++------- .../media/platform/msm/vidc/msm_vidc_clocks.c | 11 ++++++++++- .../media/platform/msm/vidc/msm_vidc_common.h | 1 + 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index b00d7ee75f33..0bf9f372491b 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -918,11 +918,19 @@ int msm_vidc_set_internal_config(struct msm_vidc_inst *inst) (void *)&rc_mode); } + output_height = inst->prop.height[CAPTURE_PORT]; + output_width = inst->prop.width[CAPTURE_PORT]; + fps = inst->prop.fps; + mbps = NUM_MBS_PER_SEC(output_height, output_width, fps); if ((rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR || rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR) && (codec != V4L2_PIX_FMT_VP8)) { - hrd_buf_size.vbv_hdr_buf_size = 1000; - dprintk(VIDC_DBG, "Enable cbr+ hdr_buf_size %d :\n", + if (rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR && + mbps < CBR_MB_LIMIT) + hrd_buf_size.vbv_hdr_buf_size = 500; + else + hrd_buf_size.vbv_hdr_buf_size = 1000; + dprintk(VIDC_DBG, "Enable hdr_buf_size %d :\n", hrd_buf_size.vbv_hdr_buf_size); rc = call_hfi_op(hdev, session_set_property, (void *)inst->session, HAL_CONFIG_VENC_VBV_HRD_BUF_SIZE, @@ -942,13 +950,8 @@ int msm_vidc_set_internal_config(struct msm_vidc_inst *inst) if ((codec == V4L2_PIX_FMT_H264 || codec == V4L2_PIX_FMT_HEVC) && slice_mode != V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) { - - output_height = inst->prop.height[CAPTURE_PORT]; - output_width = inst->prop.width[CAPTURE_PORT]; - fps = inst->prop.fps; bitrate = inst->clk_data.bitrate; mb_per_frame = NUM_MBS_PER_FRAME(output_height, output_width); - mbps = NUM_MBS_PER_SEC(output_height, output_width, fps); if (rc_mode != V4L2_MPEG_VIDEO_BITRATE_MODE_RC_OFF && rc_mode != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR && diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c index 912ed07de814..5261b8025cb6 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c @@ -1189,6 +1189,7 @@ int msm_vidc_decide_work_route(struct msm_vidc_inst *inst) } else if (inst->session_type == MSM_VIDC_ENCODER) { u32 slice_mode = 0; u32 rc_mode = 0; + u32 output_width, output_height, fps, mbps; switch (inst->fmts[CAPTURE_PORT].fourcc) { case V4L2_PIX_FMT_VP8: @@ -1206,9 +1207,16 @@ int msm_vidc_decide_work_route(struct msm_vidc_inst *inst) } slice_mode = msm_comm_g_ctrl_for_id(inst, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE); + output_height = inst->prop.height[CAPTURE_PORT]; + output_width = inst->prop.width[CAPTURE_PORT]; + fps = inst->prop.fps; + mbps = NUM_MBS_PER_SEC(output_height, output_width, fps); if (slice_mode == - V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { + V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES || + (rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR && + mbps < CBR_MB_LIMIT)) { pdata.video_work_route = 1; + dprintk(VIDC_DBG, "Configured work route = 1"); } } else { return -EINVAL; @@ -1311,6 +1319,7 @@ int msm_vidc_decide_work_mode(struct msm_vidc_inst *inst) if (inst->clk_data.low_latency_mode) { pdata.video_work_mode = VIDC_WORK_MODE_1; + dprintk(VIDC_DBG, "Configured work mode = 1"); goto decision_done; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h index c0dfc729ffc6..01791b3a5bfa 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h @@ -24,6 +24,7 @@ #define DEFAULT_FRAME_QUALITY 80 #define FRAME_QUALITY_STEP 1 #define HEIC_GRID_DIMENSION 512 +#define CBR_MB_LIMIT (1280*720/256*30) struct vb2_buf_entry { struct list_head list; -- GitLab From 0800fc3a04afd7a8e2b887b3ecd38ccc13988eb5 Mon Sep 17 00:00:00 2001 From: Sudarshan Rajagopalan Date: Wed, 22 Aug 2018 14:41:34 -0700 Subject: [PATCH 0926/1001] mm/memory_hotplug: Reduce migration re-try timeout value Currently, the timeout value for migration re-tries during memory offlining is 120 seconds. If migration encounters a pinned page, it is guaranteed to fail no matter how many re-tries are attempted, and there is much CPU cycles spent on the re-tries with this timeout, which would contribute to power. Hence, reduce the timeout to half, 60 seconds. Change-Id: Ib300c4c1c3c4f5d10f5d8652d04a783c0f459fc1 Signed-off-by: Sudarshan Rajagopalan --- include/linux/memory_hotplug.h | 3 +++ mm/memory_hotplug.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index 911aa6164617..1d8fb03b97ca 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h @@ -14,6 +14,9 @@ struct mem_section; struct memory_block; struct resource; +/* Timeout for migration re-tries in seconds */ +#define MIGRATE_TIMEOUT_SEC 60 + #ifdef CONFIG_MEMORY_HOTPLUG /* * Return page for the valid pfn only if the page is online. All pfn diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index d5364921ccaf..c1ee2d3ddc03 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -1766,7 +1766,8 @@ static int __ref __offline_pages(unsigned long start_pfn, /* Must be protected by mem_hotplug_begin() or a device_lock */ int offline_pages(unsigned long start_pfn, unsigned long nr_pages) { - return __offline_pages(start_pfn, start_pfn + nr_pages, 120 * HZ); + return __offline_pages(start_pfn, start_pfn + nr_pages, + MIGRATE_TIMEOUT_SEC * HZ); } #endif /* CONFIG_MEMORY_HOTREMOVE */ -- GitLab From 2d85589825182fe7fb525307775f0331a5b82dc4 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Tue, 21 Aug 2018 19:13:49 -0700 Subject: [PATCH 0927/1001] power: qpnp-fg-gen4: Initialize work and mutex locks early Currently, all the works are cancelled in fg_gen4_cleanup when it is invoked when the driver probe fails. When the works are cancelled even before they're initialized, a warning is printed out from debug objects. Fix this by initializing them earlier. Change-Id: Ibe73dd1e7f5aef65b30c331d7878b7dc83b85205 Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qcom/qpnp-fg-gen4.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index 8abce1dcbf81..8fc5944e3ef7 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -4166,6 +4166,16 @@ static int fg_gen4_probe(struct platform_device *pdev) return -ENXIO; } + mutex_init(&fg->bus_lock); + mutex_init(&fg->sram_rw_lock); + mutex_init(&fg->charge_full_lock); + init_completion(&fg->soc_update); + init_completion(&fg->soc_ready); + INIT_WORK(&fg->status_change_work, status_change_work); + INIT_DELAYED_WORK(&fg->profile_load_work, profile_load_work); + INIT_DELAYED_WORK(&fg->sram_dump_work, sram_dump_work); + INIT_WORK(&chip->esr_calib_work, esr_calib_work); + fg->awake_votable = create_votable("FG_WS", VOTE_SET_ANY, fg_awake_cb, fg); if (IS_ERR(fg->awake_votable)) { @@ -4218,16 +4228,6 @@ static int fg_gen4_probe(struct platform_device *pdev) } } - mutex_init(&fg->bus_lock); - mutex_init(&fg->sram_rw_lock); - mutex_init(&fg->charge_full_lock); - init_completion(&fg->soc_update); - init_completion(&fg->soc_ready); - INIT_WORK(&fg->status_change_work, status_change_work); - INIT_DELAYED_WORK(&fg->profile_load_work, profile_load_work); - INIT_DELAYED_WORK(&fg->sram_dump_work, sram_dump_work); - INIT_WORK(&chip->esr_calib_work, esr_calib_work); - rc = fg_memif_init(fg); if (rc < 0) { dev_err(fg->dev, "Error in initializing FG_MEMIF, rc:%d\n", -- GitLab From b6855242ecf308f609ae6f37eca9e155b94d18f9 Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Wed, 25 Jul 2018 10:24:55 -0700 Subject: [PATCH 0928/1001] mm: Allow only __GFP_CMA allocations from Movable zone Ensure that only allocations which include __GFP_CMA can be satisfied from zone Movable. This restriction helps reduces the likelihood of a page in the movable zone being pinned which would prevent memory from being offlined. Change-Id: I570970ff848d4a7147f3ccda2b294f08bcdf88d8 Signed-off-by: Liam Mark --- include/linux/gfp.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/linux/gfp.h b/include/linux/gfp.h index 3d6265fd3209..ef8d6d0aaee3 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -407,7 +407,14 @@ static inline bool gfpflags_allow_blocking(const gfp_t gfp_flags) static inline enum zone_type gfp_zone(gfp_t flags) { enum zone_type z; - int bit = (__force int) (flags & GFP_ZONEMASK); + int bit; + + if (!IS_ENABLED(CONFIG_HIGHMEM)) { + if ((flags & __GFP_MOVABLE) && !(flags & __GFP_CMA)) + flags &= ~__GFP_HIGHMEM; + } + + bit = (__force int) (flags & GFP_ZONEMASK); z = (GFP_ZONE_TABLE >> (bit * GFP_ZONES_SHIFT)) & ((1 << GFP_ZONES_SHIFT) - 1); -- GitLab From 6ec8d413935ff96b400297ca4d7864cd3cea4064 Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Fri, 27 Jul 2018 11:25:43 -0700 Subject: [PATCH 0929/1001] mm/filemap: Allow filemap_fault Movable allocations from CMA region There are a lot of filemap_fault Movable allocations. [] get_page_from_freelist+0xa60 [] __alloc_pages_nodemask+0x174 [] __do_page_cache_readahead+0xc0 [] filemap_fault+0x41c [] ext4_filemap_fault+0x34 [] __do_fault+0x28 [] handle_pte_fault+0x9d4 [] handle_mm_fault+0x1d0 [] do_page_fault+0x2a0 [] do_translation_fault+0x50 [] do_mem_abort+0x5c [] el0_da+0x20 The filesystem code doesn't appear to pin these pages, so allow them to be satisfied from the CMA region in order to better utilize CMA memory. Change-Id: I1ca6c6cc31107b9ba5e314c0be341299cf659feb Signed-off-by: Liam Mark --- mm/filemap.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mm/filemap.c b/mm/filemap.c index e77e15d08670..3729f2b93052 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2409,6 +2409,11 @@ int filemap_fault(struct vm_fault *vmf) do_async_mmap_readahead(vmf->vma, ra, file, page, offset); } else if (!page) { /* No page in the page cache at all */ + struct address_space *mapping = file->f_mapping; + + if (mapping && (mapping->gfp_mask & __GFP_MOVABLE)) + mapping->gfp_mask |= __GFP_CMA; + do_sync_mmap_readahead(vmf->vma, ra, file, offset); count_vm_event(PGMAJFAULT); count_memcg_event_mm(vmf->vma->vm_mm, PGMAJFAULT); -- GitLab From ee99f5d5e3ccb08ce8ec07412bd86b2c67840134 Mon Sep 17 00:00:00 2001 From: David Collins Date: Thu, 16 Aug 2018 11:12:08 -0700 Subject: [PATCH 0930/1001] drivers: mailbox: rpmh: include asm/arch_timer.h Include the header file asm/arch_timer.h so that the function arch_counter_get_cntvct() does not cause a compilation failure for arch arm. Change-Id: Ib50a348493ae3372fe0d64753422a66b3f369ca3 Signed-off-by: David Collins --- drivers/mailbox/qcom-rpmh-mailbox.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mailbox/qcom-rpmh-mailbox.c b/drivers/mailbox/qcom-rpmh-mailbox.c index 94bd6f99395e..8f4b3f780f33 100644 --- a/drivers/mailbox/qcom-rpmh-mailbox.c +++ b/drivers/mailbox/qcom-rpmh-mailbox.c @@ -30,6 +30,7 @@ #include #include +#include #include #include -- GitLab From 5e77deb3f71a7b238b71ad46b21dc23c09467b95 Mon Sep 17 00:00:00 2001 From: David Collins Date: Thu, 16 Aug 2018 10:55:55 -0700 Subject: [PATCH 0931/1001] defconfig: sdxprairie: enable RPMh driver API Enable the RPMh driver API so that clients can utilize it. Change-Id: I550b15ce586aed03a5e2425cf7c2e33bfbdb6fde Signed-off-by: David Collins --- arch/arm/configs/vendor/sdxprairie-perf_defconfig | 1 + arch/arm/configs/vendor/sdxprairie_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/vendor/sdxprairie-perf_defconfig b/arch/arm/configs/vendor/sdxprairie-perf_defconfig index b4ef2bd487e4..62a973069bf6 100644 --- a/arch/arm/configs/vendor/sdxprairie-perf_defconfig +++ b/arch/arm/configs/vendor/sdxprairie-perf_defconfig @@ -274,6 +274,7 @@ CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y +CONFIG_QTI_RPMH_API=y CONFIG_PWM=y CONFIG_ANDROID=y CONFIG_EXT3_FS=y diff --git a/arch/arm/configs/vendor/sdxprairie_defconfig b/arch/arm/configs/vendor/sdxprairie_defconfig index 1b8fdfc6f1ad..dd30efc0b964 100644 --- a/arch/arm/configs/vendor/sdxprairie_defconfig +++ b/arch/arm/configs/vendor/sdxprairie_defconfig @@ -265,6 +265,7 @@ CONFIG_IOMMU_TESTS=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y CONFIG_MSM_BOOT_STATS=y +CONFIG_QTI_RPMH_API=y CONFIG_PWM=y CONFIG_ANDROID=y CONFIG_STM=y -- GitLab From 125668eaa657c6f167fb9740cbd2c1f0c8bceffe Mon Sep 17 00:00:00 2001 From: Sudarshan Rajagopalan Date: Thu, 16 Aug 2018 17:08:20 -0700 Subject: [PATCH 0932/1001] ARM: dts: msm: Update TBU stream id range for sm8150 For the TBU with id=8, the sid start value is 0x2000. Update the DT entry. Change-Id: I907e2bcf86861904fc62b3cdbdd97a4f1a931b63 Signed-off-by: Sudarshan Rajagopalan --- arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi | 2 +- arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi index ed019eac9d88..64e136120d82 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi @@ -343,7 +343,7 @@ reg = <0x151a5000 0x1000>, <0x15182240 0x8>; reg-names = "base", "status-reg"; - qcom,stream-id-range = <0x1c00 0x400>; + qcom,stream-id-range = <0x2000 0x400>; qcom,regulator-names = "vdd"; vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc>; qcom,msm-bus,name = "mnoc_sf_0_tbu"; diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi index 688fac432a73..f4c9cd30ed0a 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi @@ -345,7 +345,7 @@ reg = <0x151A5000 0x1000>, <0x15182240 0x8>; reg-names = "base", "status-reg"; - qcom,stream-id-range = <0x1c00 0x400>; + qcom,stream-id-range = <0x2000 0x400>; /* No GDSC */ qcom,msm-bus,name = "apps_smmu"; qcom,msm-bus,num-cases = <2>; -- GitLab From 4ae7b668bf52c4d378b02d158d0d9a19eb38f9d6 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 15 Aug 2018 15:35:01 -0700 Subject: [PATCH 0933/1001] rpmsg: glink: Move intent work to private workqueue The rx done command is time sensitive for some remote processors. The remote will not release memory until this ack is sent to them. Create a kthread a queue the rx_done work on this worker instead of using the global workthread. Change-Id: I34a6a2e8e63f8e82c59b4f5a67e29cc5729c57a1 Signed-off-by: Chris Lew --- drivers/rpmsg/qcom_glink_native.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index a7e74f9204d1..f432d62a8e6f 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -114,6 +115,8 @@ struct glink_core_rx_intent { * @rx_pipe: pipe object for receive FIFO * @tx_pipe: pipe object for transmit FIFO * @irq: IRQ for signaling incoming events + * @kworker: kworker to handle rx_done work + * @task: kthread running @kworker * @rx_work: worker for handling received control messages * @rx_lock: protects the @rx_queue * @rx_queue: queue of received control messages to be processed in @rx_work @@ -136,6 +139,9 @@ struct qcom_glink { int irq; + struct kthread_worker kworker; + struct task_struct *task; + struct work_struct rx_work; spinlock_t rx_lock; struct list_head rx_queue; @@ -200,7 +206,7 @@ struct glink_channel { spinlock_t intent_lock; struct idr liids; struct idr riids; - struct work_struct intent_work; + struct kthread_work intent_work; struct list_head done_intents; struct glink_core_rx_intent *buf; @@ -240,7 +246,7 @@ static const struct rpmsg_endpoint_ops glink_endpoint_ops; #define GLINK_FEATURE_INTENTLESS BIT(1) -static void qcom_glink_rx_done_work(struct work_struct *work); +static void qcom_glink_rx_done_work(struct kthread_work *work); static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, const char *name) @@ -264,7 +270,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, init_completion(&channel->intent_req_comp); INIT_LIST_HEAD(&channel->done_intents); - INIT_WORK(&channel->intent_work, qcom_glink_rx_done_work); + kthread_init_work(&channel->intent_work, qcom_glink_rx_done_work); idr_init(&channel->liids); idr_init(&channel->riids); @@ -280,6 +286,8 @@ static void qcom_glink_channel_release(struct kref *ref) unsigned long flags; CH_INFO(channel, "\n"); + kthread_cancel_work_sync(&channel->intent_work); + spin_lock_irqsave(&channel->intent_lock, flags); idr_destroy(&channel->liids); idr_destroy(&channel->riids); @@ -504,7 +512,7 @@ static void qcom_glink_send_close_ack(struct qcom_glink *glink, qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true); } -static void qcom_glink_rx_done_work(struct work_struct *work) +static void qcom_glink_rx_done_work(struct kthread_work *work) { struct glink_channel *channel = container_of(work, struct glink_channel, intent_work); @@ -566,7 +574,7 @@ static void qcom_glink_rx_done(struct qcom_glink *glink, list_add_tail(&intent->node, &channel->done_intents); spin_unlock(&channel->intent_lock); - schedule_work(&channel->intent_work); + kthread_queue_work(&glink->kworker, &channel->intent_work); } /** @@ -1610,7 +1618,7 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid) CH_INFO(channel, "\n"); /* cancel pending rx_done work */ - cancel_work_sync(&channel->intent_work); + kthread_cancel_work_sync(&channel->intent_work); if (channel->rpdev) { strlcpy(chinfo.name, channel->name, sizeof(chinfo.name)); @@ -1800,6 +1808,15 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, return ERR_CAST(glink->mbox_chan); } + kthread_init_worker(&glink->kworker); + glink->task = kthread_run(kthread_worker_fn, &glink->kworker, + "glink_%s", glink->name); + if (IS_ERR(glink->task)) { + dev_err(dev, "failed to spawn intent kthread %d\n", + PTR_ERR(glink->task)); + return ERR_CAST(glink->task); + } + irq = of_irq_get(dev->of_node, 0); ret = devm_request_irq(dev, irq, qcom_glink_native_intr, @@ -1864,6 +1881,8 @@ void qcom_glink_native_remove(struct qcom_glink *glink) idr_destroy(&glink->rcids); spin_unlock_irqrestore(&glink->idr_lock, flags); + kthread_flush_worker(&glink->kworker); + kthread_stop(glink->task); qcom_glink_pipe_reset(glink); mbox_free_channel(glink->mbox_chan); } -- GitLab From 2f21e665a72ddeeed9de2b97816fce344064676b Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Wed, 15 Aug 2018 16:22:22 -0700 Subject: [PATCH 0934/1001] power: qpnp-fg-gen4: disable parallel charging during battery removal During battery hotswap, parallel charging is disabled and enabled by charger driver when battery is removed and inserted. However, this changes ESR FCC configuration from SW control to HW control during battery removal. ESR FCC configuration stays in HW control before the parallel charging is enabled again and notified to FG driver. During this period, when an ESR pulse is triggered right after the battery insertion, FG HW can request for a decrement in FCC but charger can end up incrementing FCC due to not accounting the distribution of FCC via the parallel charger. To fix this issue, vote to disable parallel charging upon battery removal and enable it 5 seconds after battery insertion. Change-Id: I029007ec4ba2161c332efae32e9f35b05b2ab8e2 Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qcom/qpnp-fg-gen4.c | 36 ++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index 8fc5944e3ef7..a2d905baa909 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -215,8 +215,11 @@ struct fg_gen4_chip { struct cap_learning *cl; struct ttf *ttf; struct votable *delta_esr_irq_en_votable; + struct votable *pl_disable_votable; + struct votable *cp_disable_votable; struct work_struct esr_calib_work; struct alarm esr_fast_cal_timer; + struct delayed_work pl_enable_work; char batt_profile[PROFILE_LEN]; int delta_esr_count; int recharge_soc_thr; @@ -1599,10 +1602,12 @@ static void profile_load_work(struct work_struct *work) batt_psy_initialized(fg); fg_notify_charger(fg); - schedule_delayed_work(&chip->ttf->ttf_work, 10000); + schedule_delayed_work(&chip->ttf->ttf_work, msecs_to_jiffies(10000)); fg_dbg(fg, FG_STATUS, "profile loaded successfully"); out: fg->soc_reporting_ready = true; + vote(fg->awake_votable, ESR_FCC_VOTER, true, 0); + schedule_delayed_work(&chip->pl_enable_work, msecs_to_jiffies(5000)); vote(fg->awake_votable, PROFILE_LOAD, false, 0); if (!work_pending(&fg->status_change_work)) { pm_stay_awake(fg->dev); @@ -2155,6 +2160,12 @@ static irqreturn_t fg_batt_missing_irq_handler(int irq, void *data) kfree(chip->ttf->step_chg_data); chip->ttf->step_chg_data = NULL; mutex_unlock(&chip->ttf->lock); + cancel_delayed_work_sync(&chip->pl_enable_work); + vote(fg->awake_votable, ESR_FCC_VOTER, false, 0); + if (chip->pl_disable_votable) + vote(chip->pl_disable_votable, ESR_FCC_VOTER, true, 0); + if (chip->cp_disable_votable) + vote(chip->cp_disable_votable, ESR_FCC_VOTER, true, 0); return IRQ_HANDLED; } @@ -2727,6 +2738,20 @@ static void esr_calib_work(struct work_struct *work) vote(fg->awake_votable, ESR_CALIB, false, 0); } +static void pl_enable_work(struct work_struct *work) +{ + struct fg_gen4_chip *chip = container_of(work, + struct fg_gen4_chip, + pl_enable_work.work); + struct fg_dev *fg = &chip->fg; + + if (chip->pl_disable_votable) + vote(chip->pl_disable_votable, ESR_FCC_VOTER, false, 0); + if (chip->cp_disable_votable) + vote(chip->cp_disable_votable, ESR_FCC_VOTER, false, 0); + vote(fg->awake_votable, ESR_FCC_VOTER, false, 0); +} + static void status_change_work(struct work_struct *work) { struct fg_dev *fg = container_of(work, @@ -2735,6 +2760,12 @@ static void status_change_work(struct work_struct *work) int rc, batt_soc, batt_temp; bool input_present, qnovo_en; + if (!chip->pl_disable_votable) + chip->pl_disable_votable = find_votable("PL_DISABLE"); + + if (!chip->cp_disable_votable) + chip->cp_disable_votable = find_votable("CP_DISABLE"); + if (!batt_psy_initialized(fg)) { fg_dbg(fg, FG_STATUS, "Charger not available?!\n"); goto out; @@ -4172,9 +4203,10 @@ static int fg_gen4_probe(struct platform_device *pdev) init_completion(&fg->soc_update); init_completion(&fg->soc_ready); INIT_WORK(&fg->status_change_work, status_change_work); + INIT_WORK(&chip->esr_calib_work, esr_calib_work); INIT_DELAYED_WORK(&fg->profile_load_work, profile_load_work); INIT_DELAYED_WORK(&fg->sram_dump_work, sram_dump_work); - INIT_WORK(&chip->esr_calib_work, esr_calib_work); + INIT_DELAYED_WORK(&chip->pl_enable_work, pl_enable_work); fg->awake_votable = create_votable("FG_WS", VOTE_SET_ANY, fg_awake_cb, fg); -- GitLab From 565581c11756d95662f5fc75f5e07c27b7a49471 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Mon, 20 Aug 2018 13:28:10 -0700 Subject: [PATCH 0935/1001] power: qpnp-fg-gen4: Add support for slope limiter configuration Add support to configure the slope limiter coefficients based on battery temperature and charging status. This helps with tuning the state of charge (SOC) accuracy. While at it, print monotonic SOC instead of the capacity shown by FG driver and cache the battery temperature during driver probe. Change-Id: I64af892ac5973bb95d66c6aa20c0af6d39b31f94 Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qcom/qpnp-fg-gen4.c | 76 +++++++++++++++++++++--- 1 file changed, 69 insertions(+), 7 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index a2d905baa909..a82dfaefc6bf 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -221,6 +221,7 @@ struct fg_gen4_chip { struct alarm esr_fast_cal_timer; struct delayed_work pl_enable_work; char batt_profile[PROFILE_LEN]; + enum slope_limit_status slope_limit_sts; int delta_esr_count; int recharge_soc_thr; int esr_actual; @@ -1075,6 +1076,49 @@ static int fg_gen4_adjust_ki_coeff_dischg(struct fg_dev *fg) return 0; } +static int fg_gen4_slope_limit_config(struct fg_gen4_chip *chip, int batt_temp) +{ + struct fg_dev *fg = &chip->fg; + enum slope_limit_status status; + int rc; + u8 buf; + + if (!chip->slope_limit_en) + return 0; + + if (fg->charge_status == POWER_SUPPLY_STATUS_CHARGING || + fg->charge_status == POWER_SUPPLY_STATUS_FULL) { + if (batt_temp < chip->dt.slope_limit_temp) + status = LOW_TEMP_CHARGE; + else + status = HIGH_TEMP_CHARGE; + } else { + if (batt_temp < chip->dt.slope_limit_temp) + status = LOW_TEMP_DISCHARGE; + else + status = HIGH_TEMP_DISCHARGE; + } + + if (chip->slope_limit_sts == status) + return 0; + + fg_encode(fg->sp, FG_SRAM_SLOPE_LIMIT, + chip->dt.slope_limit_coeffs[status], &buf); + rc = fg_sram_write(fg, fg->sp[FG_SRAM_SLOPE_LIMIT].addr_word, + fg->sp[FG_SRAM_SLOPE_LIMIT].addr_byte, &buf, + fg->sp[FG_SRAM_SLOPE_LIMIT].len, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in configuring slope_limit coefficient, rc=%d\n", + rc); + return rc; + } + + chip->slope_limit_sts = status; + fg_dbg(fg, FG_STATUS, "Slope limit status: %d value: %x\n", status, + buf); + return 0; +} + static int fg_gen4_get_batt_profile(struct fg_dev *fg) { struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); @@ -2189,6 +2233,7 @@ static irqreturn_t fg_batt_temp_irq_handler(int irq, void *data) static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data) { struct fg_dev *fg = data; + struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); int rc, batt_temp; rc = fg_gen4_get_battery_temp(fg, &batt_temp); @@ -2199,6 +2244,10 @@ static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data) fg_dbg(fg, FG_IRQ, "irq %d triggered batt_temp:%d\n", irq, batt_temp); + rc = fg_gen4_slope_limit_config(chip, batt_temp); + if (rc < 0) + pr_err("Error in configuring slope limiter rc:%d\n", rc); + if (abs(fg->last_batt_temp - batt_temp) > 30) pr_warn("Battery temperature last:%d current: %d\n", fg->last_batt_temp, batt_temp); @@ -2264,12 +2313,19 @@ static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data) fg->charge_status, fg->charge_done, input_present); rc = fg_gen4_get_battery_temp(fg, &batt_temp); - if (rc < 0) + if (rc < 0) { pr_err("Failed to read battery temp rc: %d\n", rc); - else if (chip->cl->active) - cap_learning_update(chip->cl, batt_temp, batt_soc, - fg->charge_status, fg->charge_done, input_present, - is_qnovo_en(fg)); + } else { + if (chip->cl->active) + cap_learning_update(chip->cl, batt_temp, batt_soc, + fg->charge_status, fg->charge_done, + input_present, is_qnovo_en(fg)); + + rc = fg_gen4_slope_limit_config(chip, batt_temp); + if (rc < 0) + pr_err("Error in configuring slope limiter rc:%d\n", + rc); + } rc = fg_gen4_charge_full_update(fg); if (rc < 0) @@ -2804,6 +2860,10 @@ static void status_change_work(struct work_struct *work) if (rc < 0) pr_err("Error in charge_full_update, rc=%d\n", rc); + rc = fg_gen4_slope_limit_config(chip, batt_temp); + if (rc < 0) + pr_err("Error in configuring slope limiter rc:%d\n", rc); + rc = fg_gen4_adjust_ki_coeff_dischg(fg); if (rc < 0) pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc); @@ -4318,7 +4378,7 @@ static int fg_gen4_probe(struct platform_device *pdev) rc = fg_get_battery_voltage(fg, &volt_uv); if (!rc) - rc = fg_gen4_get_prop_capacity(fg, &msoc); + rc = fg_get_msoc(fg, &msoc); if (!rc) rc = fg_gen4_get_battery_temp(fg, &batt_temp); @@ -4326,9 +4386,11 @@ static int fg_gen4_probe(struct platform_device *pdev) if (!rc) rc = fg_gen4_get_batt_id(chip); - if (!rc) + if (!rc) { + fg->last_batt_temp = batt_temp; pr_info("battery SOC:%d voltage: %duV temp: %d id: %d ohms\n", msoc, volt_uv, batt_temp, fg->batt_id_ohms); + } device_init_wakeup(fg->dev, true); schedule_delayed_work(&fg->profile_load_work, 0); -- GitLab From bc411262e22d04bb1b3e84b8ffa133fd2f977eab Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Mon, 20 Aug 2018 17:44:29 -0700 Subject: [PATCH 0936/1001] power: qpnp-fg-gen4: Add support for rapid SOC reduction In certain cases, battery state of charge (SOC) can stay higher than 0 when the battery voltage drops below the cutoff voltage. Userspace initiates a shutdown only when SOC hits 0. To avoid a potential under voltage lockout and help with graceful shutdown, add support for rapid SOC reduction on detecting this condition. Change-Id: I9a23e67afee68060bd1127699205973a61c3d09d Signed-off-by: Subbaraman Narayanamurthy --- .../power/supply/qcom/qpnp-fg-gen4.txt | 7 ++ drivers/power/supply/qcom/qpnp-fg-gen4.c | 93 +++++++++++++++++-- 2 files changed, 90 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt index e6158732517a..91d9047f193d 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt @@ -351,6 +351,13 @@ First Level Node - FG Gen4 device property "qcom,slope-limit-temp-threshold" to make dynamic slope limit adjustment functional. +- qcom,rapid-soc-dec-en + Usage: optional + Value type: + Definition: A boolean property that when defined enables rapid SOC + decrease when the battery SOC is low but not converging to + zero with battery voltage dropping rapidly below Vcutoff. + ========================================================== Second Level Nodes - Peripherals managed by FG Gen4 driver ========================================================== diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index a82dfaefc6bf..2cc7d5d1f125 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -176,6 +176,7 @@ struct fg_dt_props { bool force_load_profile; bool hold_soc_while_full; bool linearize_soc; + bool rapid_soc_dec_en; int cutoff_volt_mv; int empty_volt_mv; int cutoff_curr_ma; @@ -234,6 +235,7 @@ struct fg_gen4_chip { bool esr_fast_cal_timer_expired; bool esr_fcc_ctrl_en; bool rslow_low; + bool rapid_soc_dec_en; }; struct bias_config { @@ -1083,7 +1085,7 @@ static int fg_gen4_slope_limit_config(struct fg_gen4_chip *chip, int batt_temp) int rc; u8 buf; - if (!chip->slope_limit_en) + if (!chip->slope_limit_en || chip->rapid_soc_dec_en) return 0; if (fg->charge_status == POWER_SUPPLY_STATUS_CHARGING || @@ -1119,6 +1121,50 @@ static int fg_gen4_slope_limit_config(struct fg_gen4_chip *chip, int batt_temp) return 0; } +static int fg_gen4_configure_cutoff_current(struct fg_dev *fg, int current_ma) +{ + int rc; + u8 buf[2]; + + fg_encode(fg->sp, FG_SRAM_CUTOFF_CURR, current_ma, buf); + rc = fg_sram_write(fg, fg->sp[FG_SRAM_CUTOFF_CURR].addr_word, + fg->sp[FG_SRAM_CUTOFF_CURR].addr_byte, buf, + fg->sp[FG_SRAM_CUTOFF_CURR].len, FG_IMA_DEFAULT); + if (rc < 0) + pr_err("Error in writing cutoff_curr, rc=%d\n", rc); + + return rc; +} + +#define SLOPE_LIMIT_DEFAULT 5738 +#define CUTOFF_CURRENT_MAX 15999 +static int fg_gen4_rapid_soc_config(struct fg_gen4_chip *chip, bool en) +{ + struct fg_dev *fg = &chip->fg; + int rc, slope_limit_coeff, cutoff_curr_ma; + u8 buf; + + slope_limit_coeff = en ? SLOPE_LIMIT_COEFF_MAX : SLOPE_LIMIT_DEFAULT; + fg_encode(fg->sp, FG_SRAM_SLOPE_LIMIT, slope_limit_coeff, &buf); + rc = fg_sram_write(fg, fg->sp[FG_SRAM_SLOPE_LIMIT].addr_word, + fg->sp[FG_SRAM_SLOPE_LIMIT].addr_byte, &buf, + fg->sp[FG_SRAM_SLOPE_LIMIT].len, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in configuring slope_limit coefficient, rc=%d\n", + rc); + return rc; + } + + cutoff_curr_ma = en ? CUTOFF_CURRENT_MAX : chip->dt.cutoff_curr_ma; + rc = fg_gen4_configure_cutoff_current(fg, cutoff_curr_ma); + if (rc < 0) + return rc; + + fg_dbg(fg, FG_STATUS, "Configured slope limit coeff %d cutoff current %d mA\n", + slope_limit_coeff, cutoff_curr_ma); + return 0; +} + static int fg_gen4_get_batt_profile(struct fg_dev *fg) { struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); @@ -2160,13 +2206,34 @@ static irqreturn_t fg_delta_esr_irq_handler(int irq, void *data) static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data) { struct fg_dev *fg = data; - int rc, vbatt_mv; + struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); + int rc, vbatt_mv, msoc_raw; rc = fg_get_battery_voltage(fg, &vbatt_mv); if (rc < 0) return IRQ_HANDLED; - fg_dbg(fg, FG_IRQ, "irq %d triggered vbatt_mv: %d\n", irq, vbatt_mv); + vbatt_mv /= 1000; + rc = fg_get_msoc_raw(fg, &msoc_raw); + if (rc < 0) + return IRQ_HANDLED; + + fg_dbg(fg, FG_IRQ, "irq %d triggered vbatt_mv: %d msoc_raw:%d\n", irq, + vbatt_mv, msoc_raw); + + if (chip->dt.rapid_soc_dec_en && vbatt_mv < chip->dt.cutoff_volt_mv) { + /* + * Set this flag so that slope limiter coefficient cannot be + * configured during rapid SOC decrease. + */ + chip->rapid_soc_dec_en = true; + + rc = fg_gen4_rapid_soc_config(chip, true); + if (rc < 0) + pr_err("Error in configuring for rapid SOC reduction rc:%d\n", + rc); + } + if (batt_psy_initialized(fg)) power_supply_changed(fg->batt_psy); @@ -3476,14 +3543,9 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) return rc; } - fg_encode(fg->sp, FG_SRAM_CUTOFF_CURR, chip->dt.cutoff_curr_ma, buf); - rc = fg_sram_write(fg, fg->sp[FG_SRAM_CUTOFF_CURR].addr_word, - fg->sp[FG_SRAM_CUTOFF_CURR].addr_byte, buf, - fg->sp[FG_SRAM_CUTOFF_CURR].len, FG_IMA_DEFAULT); - if (rc < 0) { - pr_err("Error in writing cutoff_curr, rc=%d\n", rc); + rc = fg_gen4_configure_cutoff_current(fg, chip->dt.cutoff_curr_ma); + if (rc < 0) return rc; - } fg_encode(fg->sp, FG_SRAM_SYS_TERM_CURR, chip->dt.sys_term_curr_ma, buf); @@ -4204,6 +4266,8 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) if (rc < 0) return rc; + chip->dt.rapid_soc_dec_en = of_property_read_bool(node, + "qcom,rapid-soc-dec-en"); return 0; } @@ -4416,6 +4480,15 @@ static void fg_gen4_shutdown(struct platform_device *pdev) struct fg_dev *fg = &chip->fg; int rc, bsoc; + fg_unregister_interrupts(fg, chip, FG_GEN4_IRQ_MAX); + + if (chip->rapid_soc_dec_en) { + rc = fg_gen4_rapid_soc_config(chip, false); + if (rc < 0) + pr_err("Error in reverting rapid SOC decrease config rc:%d\n", + rc); + } + rc = fg_get_sram_prop(fg, FG_SRAM_BATT_SOC, &bsoc); if (rc < 0) { pr_err("Error in getting BATT_SOC, rc=%d\n", rc); -- GitLab From a58bd15a688b456d703ea43af3d28293c44d7481 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Wed, 18 Jul 2018 11:02:43 +0800 Subject: [PATCH 0937/1001] input: qti-haptics: Add VMAX per effect setting Currently, property "qcom,vmax-mv" is defined as the maximum output of the haptics module to meet the requirement of the Vrms of the motor to prevent it from damage. However, if the playing duration is short, it's safe to overdrive the motor for an intense effect. Add "qcom,wf-vmax-mv" per effect configuration to achieve this. Change-Id: I96a48356bb9959cacf5e15cf614d89c774615312 Signed-off-by: Fenglin Wu --- .../devicetree/bindings/input/qti-haptics.txt | 9 +++++++++ drivers/input/misc/qti-haptics.c | 18 ++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/input/qti-haptics.txt b/Documentation/devicetree/bindings/input/qti-haptics.txt index 2c4f4f02ae34..b3daa49fe443 100644 --- a/Documentation/devicetree/bindings/input/qti-haptics.txt +++ b/Documentation/devicetree/bindings/input/qti-haptics.txt @@ -130,6 +130,15 @@ waveforms/effects: [5:1]: waveform amplitude [0]: reserved. +- qcom,wf-vmax-mv + Usage: optional + Value type: + Definition: Specifies the maximum allowed output voltage in millivolts + for this effect. Value specified here will be rounded + off to the closest multiple of 116 mV. Allowed values: + 0 to 3596. If this is not specified, the value defined in + "qcom,vmax-mv" will be applied. + - qcom,wf-play-rate-us Usage: optional Value type: diff --git a/drivers/input/misc/qti-haptics.c b/drivers/input/misc/qti-haptics.c index 310eb4162af0..40e955606204 100644 --- a/drivers/input/misc/qti-haptics.c +++ b/drivers/input/misc/qti-haptics.c @@ -175,6 +175,7 @@ struct qti_hap_effect { u8 *pattern; int pattern_length; u16 play_rate_us; + u16 vmax_mv; u8 wf_repeat_n; u8 wf_s_repeat_n; u8 brake[HAP_BRAKE_PATTERN_MAX]; @@ -830,10 +831,6 @@ static int qti_haptics_upload_effect(struct input_dev *dev, goto disable_vdd; } - level = effect->u.periodic.magnitude; - tmp = level * config->vmax_mv; - play->vmax_mv = tmp / 0x7fff; - if (copy_from_user(data, effect->u.periodic.custom_data, sizeof(s16) * CUSTOM_DATA_LEN)) { rc = -EFAULT; @@ -852,6 +849,10 @@ static int qti_haptics_upload_effect(struct input_dev *dev, goto disable_vdd; } + level = effect->u.periodic.magnitude; + tmp = level * chip->predefined[i].vmax_mv; + play->vmax_mv = tmp / 0x7fff; + dev_dbg(chip->dev, "upload effect %d, vmax_mv=%d\n", chip->predefined[i].id, play->vmax_mv); rc = qti_haptics_load_predefined_effect(chip, i); @@ -1234,6 +1235,15 @@ static int qti_haptics_parse_dt(struct qti_hap_chip *chip) return rc; } + effect->vmax_mv = config->vmax_mv; + rc = of_property_read_u32(child_node, "qcom,wf-vmax-mv", &tmp); + if (rc < 0) + dev_dbg(chip->dev, "Read qcom,wf-vmax-mv failed, rc=%d\n", + rc); + else + effect->vmax_mv = (tmp > HAP_VMAX_MV_MAX) ? + HAP_VMAX_MV_MAX : tmp; + rc = of_property_count_elems_of_size(child_node, "qcom,wf-pattern", sizeof(u8)); if (rc < 0) { -- GitLab From 68c3538b10e8d569128a407726137e165c770350 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Fri, 27 Jul 2018 09:06:32 +0800 Subject: [PATCH 0938/1001] input: misc: qti-haptics: Add some corrections in the driver Following corrections are added: -- Read "qcom,lra-auto-resonance-disable" from the effect child node, as that property is under per effect configuration. -- Don't stop playing in play IRQ handler: Play IRQ is intended for notifying the pattern has been copied into the shadow buffer instead of playing done. -- Toggle PLAY bit when playing pattern to make the vibration stop immediately after the pattern is played. -- Always set BRAKE_EN bit regardless of the brake pattern, it helps the module stop playing waveform sample immediately after the valid values are played. -- Play rate may be changed after playing a predefined effect, set play rate back to default play rate when playing a constant waveform. -- Add debug log to show all of the predefined effect settings. Change-Id: I15548bb73684e978c87f3cbb9d616b87a2d652bd Signed-off-by: Fenglin Wu --- drivers/input/misc/qti-haptics.c | 47 ++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/drivers/input/misc/qti-haptics.c b/drivers/input/misc/qti-haptics.c index 40e955606204..fa3bec79972a 100644 --- a/drivers/input/misc/qti-haptics.c +++ b/drivers/input/misc/qti-haptics.c @@ -528,7 +528,6 @@ static int qti_haptics_config_brake(struct qti_hap_chip *chip, u8 *brake) { u8 addr, mask, val; int i, rc; - bool en = true; addr = REG_HAP_BRAKE; for (val = 0, i = 0; i < HAP_BRAKE_PATTERN_MAX; i++) @@ -540,14 +539,12 @@ static int qti_haptics_config_brake(struct qti_hap_chip *chip, u8 *brake) dev_err(chip->dev, "write brake pattern failed, rc=%d\n", rc); return rc; } - - if (val == 0) - en = false; - - /* Set BRAKE_EN only if brake pattern is non-zero */ + /* + * Set BRAKE_EN regardless of the brake pattern, this helps to stop + * playing immediately once the valid values in WF_Sx are played. + */ addr = REG_HAP_EN_CTL2; - mask = HAP_BRAKE_EN_BIT; - val = en; + val = mask = HAP_BRAKE_EN_BIT; rc = qti_haptics_masked_write(chip, addr, mask, val); if (rc < 0) dev_err(chip->dev, "set EN_CTL2 failed, rc=%d\n", rc); @@ -580,6 +577,9 @@ static int qti_haptics_load_constant_waveform(struct qti_hap_chip *chip) if (rc < 0) return rc; + rc = qti_haptics_config_play_rate_us(chip, config->play_rate_us); + if (rc < 0) + return rc; /* * Using VMAX waveform source if playing length is >= 20ms, * otherwise using buffer waveform source and calculate the @@ -697,7 +697,6 @@ static irqreturn_t qti_haptics_play_irq_handler(int irq, void *data) dev_dbg(chip->dev, "play_irq triggered\n"); if (play->playing_pos == effect->pattern_length) { dev_dbg(chip->dev, "waveform playing done\n"); - qti_haptics_play(chip, false); if (chip->play_irq_en) { disable_irq_nosync(chip->play_irq); chip->play_irq_en = false; @@ -919,6 +918,10 @@ static int qti_haptics_playback(struct input_dev *dev, int effect_id, int val) enable_irq(chip->play_irq); chip->play_irq_en = true; } + /* Toggle PLAY when playing pattern */ + rc = qti_haptics_play(chip, false); + if (rc < 0) + return rc; } else { if (chip->play_irq_en) { disable_irq_nosync(chip->play_irq); @@ -1093,7 +1096,7 @@ static int qti_haptics_parse_dt(struct qti_hap_chip *chip) struct device_node *child_node; struct qti_hap_effect *effect; const char *str; - int rc = 0, tmp, i = 0, j; + int rc = 0, tmp, i = 0, j, m; u8 val; rc = of_property_read_u32(node, "reg", &tmp); @@ -1311,7 +1314,7 @@ static int qti_haptics_parse_dt(struct qti_hap_chip *chip) effect->wf_s_repeat_n = j; } - effect->lra_auto_res_disable = of_property_read_bool(node, + effect->lra_auto_res_disable = of_property_read_bool(child_node, "qcom,lra-auto-resonance-disable"); tmp = of_property_count_elems_of_size(child_node, @@ -1347,6 +1350,28 @@ static int qti_haptics_parse_dt(struct qti_hap_chip *chip) effect->brake_en = (val != 0); } + for (j = 0; j < i; j++) { + dev_dbg(chip->dev, "effect: %d\n", chip->predefined[j].id); + dev_dbg(chip->dev, " vmax: %d mv\n", + chip->predefined[j].vmax_mv); + dev_dbg(chip->dev, " play_rate: %d us\n", + chip->predefined[j].play_rate_us); + for (m = 0; m < chip->predefined[j].pattern_length; m++) + dev_dbg(chip->dev, " pattern[%d]: 0x%x\n", + m, chip->predefined[j].pattern[m]); + for (m = 0; m < chip->predefined[j].brake_pattern_length; m++) + dev_dbg(chip->dev, " brake_pattern[%d]: 0x%x\n", + m, chip->predefined[j].brake[m]); + dev_dbg(chip->dev, " brake_en: %d\n", + chip->predefined[j].brake_en); + dev_dbg(chip->dev, " wf_repeat_n: %d\n", + chip->predefined[j].wf_repeat_n); + dev_dbg(chip->dev, " wf_s_repeat_n: %d\n", + chip->predefined[j].wf_s_repeat_n); + dev_dbg(chip->dev, " lra_auto_res_disable: %d\n", + chip->predefined[j].lra_auto_res_disable); + } + return 0; } -- GitLab From b961c241df7b64febea1495a16fbae0d2dea72a4 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Mon, 16 Jul 2018 15:50:08 +0800 Subject: [PATCH 0939/1001] input: qti-haptics: Add FF_GAIN capability support Add FF_GAIN capability support. It can be used to change the vibration magnitude dynamically. Change-Id: I07b029e63ec0ee52bc440884c5b6f89a2de69def Signed-off-by: Fenglin Wu --- drivers/input/misc/qti-haptics.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/input/misc/qti-haptics.c b/drivers/input/misc/qti-haptics.c index fa3bec79972a..f60e835af89c 100644 --- a/drivers/input/misc/qti-haptics.c +++ b/drivers/input/misc/qti-haptics.c @@ -970,6 +970,22 @@ static int qti_haptics_erase(struct input_dev *dev, int effect_id) return rc; } +static void qti_haptics_set_gain(struct input_dev *dev, u16 gain) +{ + struct qti_hap_chip *chip = input_get_drvdata(dev); + struct qti_hap_config *config = &chip->config; + struct qti_hap_play_info *play = &chip->play; + + if (gain == 0) + return; + + if (gain > 0x7fff) + gain = 0x7fff; + + play->vmax_mv = ((u32)(gain * config->vmax_mv)) / 0x7fff; + qti_haptics_config_vmax(chip, play->vmax_mv); +} + static int qti_haptics_hw_init(struct qti_hap_chip *chip) { struct qti_hap_config *config = &chip->config; @@ -1439,6 +1455,7 @@ static int qti_haptics_probe(struct platform_device *pdev) chip->input_dev = input_dev; input_set_capability(input_dev, EV_FF, FF_CONSTANT); + input_set_capability(input_dev, EV_FF, FF_GAIN); if (chip->effects_count != 0) { input_set_capability(input_dev, EV_FF, FF_PERIODIC); input_set_capability(input_dev, EV_FF, FF_CUSTOM); @@ -1459,6 +1476,7 @@ static int qti_haptics_probe(struct platform_device *pdev) ff->upload = qti_haptics_upload_effect; ff->playback = qti_haptics_playback; ff->erase = qti_haptics_erase; + ff->set_gain = qti_haptics_set_gain; rc = input_register_device(input_dev); if (rc < 0) { -- GitLab From 98ea5c4f1370ba61f7f0ec57674903878779791f Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Thu, 19 Jul 2018 09:08:38 +0800 Subject: [PATCH 0940/1001] ARM: dts: msm: Update haptics configuration for SM8150 platforms Change the predefined effects settings according to the motor being used on each device for better user experience. Change-Id: I22e6879649cd4dbbb598ead8f4976f4c78a05cd2 Signed-off-by: Fenglin Wu --- arch/arm64/boot/dts/qcom/pm8150b.dtsi | 22 +++++++++++++--- arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi | 32 ++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/pm8150b.dtsi b/arch/arm64/boot/dts/qcom/pm8150b.dtsi index 9b0ad6f380ed..94ee3ec63c7f 100644 --- a/arch/arm64/boot/dts/qcom/pm8150b.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8150b.dtsi @@ -479,7 +479,7 @@ <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "hap-sc-irq", "hap-play-irq"; qcom,actuator-type = "lra"; - qcom,vmax-mv = <3600>; + qcom,vmax-mv = <3400>; qcom,play-rate-us = <6667>; qcom,lra-resonance-sig-shape = "sine"; qcom,lra-auto-resonance-mode = "qwd"; @@ -488,38 +488,54 @@ wf_0 { /* CLICK */ qcom,effect-id = <0>; + qcom,wf-vmax-mv = <3600>; qcom,wf-pattern = [3e 3e 3e]; qcom,wf-play-rate-us = <6667>; + qcom,wf-brake-pattern = [01 00 00 00]; + qcom,lra-auto-resonance-disable; }; wf_1 { /* DOUBLE CLICK */ qcom,effect-id = <1>; - qcom,wf-pattern = [7e 7e 02 02 02 02 7e 7e]; + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [7e 7e 02 02 02 02 02 02]; qcom,wf-play-rate-us = <7143>; + qcom,wf-repeat-count = <2>; + qcom,wf-s-repeat-count = <1>; + qcom,lra-auto-resonance-disable; }; wf_2 { /* TICK */ qcom,effect-id = <2>; + qcom,wf-vmax-mv = <3600>; qcom,wf-pattern = [7e 7e]; qcom,wf-play-rate-us = <4000>; + qcom,lra-auto-resonance-disable; }; wf_3 { /* THUD */ qcom,effect-id = <3>; + qcom,wf-vmax-mv = <3600>; qcom,wf-pattern = [7e 7e 7e]; - qcom,wf-play-rate-us = <5714>; + qcom,wf-play-rate-us = <6667>; + qcom,lra-auto-resonance-disable; }; wf_4 { /* POP */ qcom,effect-id = <4>; + qcom,wf-vmax-mv = <3600>; qcom,wf-pattern = [7e 7e]; qcom,wf-play-rate-us = <5000>; + qcom,lra-auto-resonance-disable; }; wf_5 { /* HEAVY CLICK */ qcom,effect-id = <5>; + qcom,wf-vmax-mv = <3600>; qcom,wf-pattern = [7e 7e 7e]; qcom,wf-play-rate-us = <6667>; + qcom,wf-brake-pattern = [03 00 00 00]; + qcom,lra-auto-resonance-disable; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index 6336bbce62d1..c548de3b99df 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -521,6 +521,38 @@ status = "ok"; }; +&pm8150b_haptics { + qcom,vmax-mv = <2545>; + qcom,play-rate-us = <4255>; + wf_0 { + /* CLICK */ + qcom,wf-pattern = [3e 3e 3e 3e]; + qcom,wf-play-rate-us = <4255>; + }; + wf_1 { + /* DOUBLE CLICK */ + qcom,wf-play-rate-us = <7143>; + }; + wf_2 { + /* TICK */ + qcom,wf-play-rate-us = <4000>; + }; + wf_3 { + /* THUD */ + qcom,wf-pattern = [7e 7e 7e 7e]; + qcom,wf-play-rate-us = <4255>; + }; + wf_4 { + /* POP */ + qcom,wf-play-rate-us = <5000>; + }; + wf_5 { + /* HEAVY CLICK */ + qcom,wf-pattern = [7e 7e 7e 7e]; + qcom,wf-play-rate-us = <4255>; + }; +}; + &pm8150b_charger { qcom,sec-charger-config = <1>; qcom,auto-recharge-soc = <98>; -- GitLab From 0c93b5f9ee4ebe9e99e42a0befd5c8394944da65 Mon Sep 17 00:00:00 2001 From: Zhongbo Shi Date: Wed, 15 Aug 2018 17:37:31 +0800 Subject: [PATCH 0941/1001] msm: vidc: defer set rotation/flip and swapped output resolution Defer set rotation/flip and swapped output resolution to HAL during start of streaming. Change-Id: Id0f088ee9ad38dacb1b8219d6b44d3075fd8c8c9 Signed-off-by: Zhongbo Shi --- drivers/media/platform/msm/vidc/msm_venc.c | 19 +----- drivers/media/platform/msm/vidc/msm_vidc.c | 60 +++++++++++++++++++ .../media/platform/msm/vidc/msm_vidc_common.c | 30 ---------- 3 files changed, 62 insertions(+), 47 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 13a862691b90..c3f8028c102f 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -1296,7 +1296,6 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) enum hal_h264_entropy h264_entropy; struct hal_intra_period intra_period; struct hal_idr_period idr_period; - struct hal_vpe_rotation vpe_rotation; struct hal_intra_refresh intra_refresh; struct hal_multi_slice_control multi_slice_control; struct hal_h264_db_control h264_db_control; @@ -1594,31 +1593,17 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) break; case V4L2_CID_ROTATE: { - temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FLIP); - property_id = HAL_PARAM_VPE_ROTATION; - if (ctrl->val != 0 && ctrl->val != 90 && ctrl->val != 180 && ctrl->val != 270) { dprintk(VIDC_ERR, "Invalid rotation angle"); rc = -ENOTSUPP; } - - vpe_rotation.rotate = ctrl->val; - vpe_rotation.flip = msm_comm_v4l2_to_hal( - V4L2_CID_MPEG_VIDC_VIDEO_FLIP, - temp_ctrl->val); - pdata = &vpe_rotation; + dprintk(VIDC_DBG, "Rotation %d\n", ctrl->val); break; } case V4L2_CID_MPEG_VIDC_VIDEO_FLIP: { - temp_ctrl = TRY_GET_CTRL(V4L2_CID_ROTATE); - property_id = HAL_PARAM_VPE_ROTATION; - vpe_rotation.rotate = temp_ctrl->val; - vpe_rotation.flip = msm_comm_v4l2_to_hal( - V4L2_CID_MPEG_VIDC_VIDEO_FLIP, - ctrl->val); - pdata = &vpe_rotation; + dprintk(VIDC_DBG, "Flip %d\n", ctrl->val); break; } case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: { diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index b00d7ee75f33..4dbf04d0c715 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -994,6 +994,57 @@ int msm_vidc_set_internal_config(struct msm_vidc_inst *inst) return rc; } +static int msm_vidc_set_rotation(struct msm_vidc_inst *inst) +{ + int rc = 0; + int value = 0; + struct hfi_device *hdev; + struct hal_vpe_rotation vpe_rotation; + struct hal_frame_size frame_sz; + + hdev = inst->core->device; + + /* Set rotation and flip first */ + value = msm_comm_g_ctrl_for_id(inst, V4L2_CID_ROTATE); + if (value < 0) { + dprintk(VIDC_ERR, "Get control for rotation failed\n"); + return value; + } + vpe_rotation.rotate = value; + value = msm_comm_g_ctrl_for_id(inst, V4L2_CID_MPEG_VIDC_VIDEO_FLIP); + if (value < 0) { + dprintk(VIDC_ERR, "Get control for flip failed\n"); + return value; + } + vpe_rotation.flip = value; + dprintk(VIDC_DBG, "Set rotation = %d, flip = %d for capture port.\n", + vpe_rotation.rotate, vpe_rotation.flip); + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, + HAL_PARAM_VPE_ROTATION, &vpe_rotation); + if (rc) { + dprintk(VIDC_ERR, "Set rotation/flip at start stream failed\n"); + return rc; + } + + /* flip the output resolution if required */ + if (vpe_rotation.rotate == 90 || vpe_rotation.rotate == 270) { + frame_sz.buffer_type = HAL_BUFFER_OUTPUT; + frame_sz.width = inst->prop.height[CAPTURE_PORT]; + frame_sz.height = inst->prop.width[CAPTURE_PORT]; + dprintk(VIDC_DBG, "CAPTURE port width = %d, height = %d\n", + frame_sz.width, frame_sz.height); + rc = call_hfi_op(hdev, session_set_property, (void *) + inst->session, HAL_PARAM_FRAME_SIZE, &frame_sz); + if (rc) { + dprintk(VIDC_ERR, + "Failed to set framesize for CAPTURE port\n"); + return rc; + } + } + return rc; +} + static inline int start_streaming(struct msm_vidc_inst *inst) { int rc = 0; @@ -1005,6 +1056,15 @@ static inline int start_streaming(struct msm_vidc_inst *inst) hash32_ptr(inst->session), inst); hdev = inst->core->device; + if (inst->session_type == MSM_VIDC_ENCODER) { + rc = msm_vidc_set_rotation(inst); + if (rc) { + dprintk(VIDC_ERR, + "Set rotation for encoder failed %pK\n"); + goto fail_start; + } + } + rc_mode = msm_comm_g_ctrl_for_id(inst, V4L2_CID_MPEG_VIDEO_BITRATE_MODE); /* HEIC HW/FWK tiling encode is supported only for CQ RC mode */ diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index cbfeea486d65..98cb1116b0f5 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -5437,7 +5437,6 @@ int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst) { u32 x_min, x_max, y_min, y_max; u32 input_height, input_width, output_height, output_width; - u32 rotation; if (inst->grid_enable > 0) { dprintk(VIDC_DBG, "Skip scaling check for HEIC\n"); @@ -5478,20 +5477,6 @@ int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst) return 0; } - rotation = msm_comm_g_ctrl_for_id(inst, - V4L2_CID_ROTATE); - - if ((output_width != output_height) && - (rotation == 90 || - rotation == 270)) { - - output_width = inst->prop.height[CAPTURE_PORT]; - output_height = inst->prop.width[CAPTURE_PORT]; - dprintk(VIDC_DBG, - "Rotation=%u Swapped Output W=%u H=%u to check scaling", - rotation, output_width, output_height); - } - x_min = (1<<16)/inst->capability.scale_x.min; y_min = (1<<16)/inst->capability.scale_y.min; x_max = inst->capability.scale_x.max >> 16; @@ -5537,7 +5522,6 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst) struct hfi_device *hdev; struct msm_vidc_core *core; u32 output_height, output_width, input_height, input_width; - u32 rotation; if (!inst || !inst->core || !inst->core->device) { dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__); @@ -5576,23 +5560,9 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst) rc = -ENOTSUPP; } - rotation = msm_comm_g_ctrl_for_id(inst, - V4L2_CID_ROTATE); - output_height = ALIGN(inst->prop.height[CAPTURE_PORT], 16); output_width = ALIGN(inst->prop.width[CAPTURE_PORT], 16); - if ((output_width != output_height) && - (rotation == 90 || - rotation == 270)) { - - output_width = ALIGN(inst->prop.height[CAPTURE_PORT], 16); - output_height = ALIGN(inst->prop.width[CAPTURE_PORT], 16); - dprintk(VIDC_DBG, - "Rotation=%u Swapped Output W=%u H=%u to check capability", - rotation, output_width, output_height); - } - if (!rc) { if (output_width < capability->width.min || output_height < capability->height.min) { -- GitLab From d8fca2c23b3ac94dad5bd187de2a1391cd0248cf Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Tue, 7 Aug 2018 11:17:22 +0530 Subject: [PATCH 0942/1001] clk: qcom: Add support for GPUCC driver Add graphics clock controller driver for SDMMAGPIE for the client to be able to perform clock operations. Change-Id: I833595a6dd3b4ef3922550bb2be8cb2d9993af69 Signed-off-by: Taniya Das --- .../devicetree/bindings/clock/qcom,gpucc.txt | 3 +- drivers/clk/qcom/Kconfig | 8 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gpucc-sdmmagpie.c | 596 ++++++++++++++++++ .../dt-bindings/clock/qcom,gpucc-sdmmagpie.h | 41 +- 5 files changed, 626 insertions(+), 23 deletions(-) create mode 100644 drivers/clk/qcom/gpucc-sdmmagpie.c diff --git a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt index c05328047241..a500819ceb31 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt @@ -5,7 +5,8 @@ Required properties : - compatible : shall contain one of the following: "qcom,gpucc-sm8150", "qcom,gpucc-sdmshrike", - "qcom,gpucc-sm6150". + "qcom,gpucc-sm6150", + "qcom,gpucc-sdmmagpie". - reg : shall contain base register offset and size. - reg-names: names of registers listed in the same order as in the reg property. diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 7ec1deff66ab..ce3df73c6668 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -431,3 +431,11 @@ config MSM_NPUCC_SDMMAGPIE Support for the NPU clock controller on Qualcomm Technologies, Inc SDMMAGPIE devices. Say Y if you want to enable use of the Network Processing Unit. + +config MSM_GPUCC_SDMMAGPIE + tristate "SDMMAGPIE graphics Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the graphics clock controller on Qualcomm Technologies, Inc. + SDMMAGPIE devices. + Say Y if you want to support graphics clocks. diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 31c86aa29c00..a454f82e8d34 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_MSM_GCC_SM6150) += gcc-sm6150.o obj-$(CONFIG_MSM_GCC_SM8150) += gcc-sm8150.o obj-$(CONFIG_MSM_GCC_SDMMAGPIE) += gcc-sdmmagpie.o obj-$(CONFIG_MSM_GCC_SDMSHRIKE) += gcc-sdmshrike.o +obj-$(CONFIG_MSM_GPUCC_SDMMAGPIE) += gpucc-sdmmagpie.o obj-$(CONFIG_MSM_GPUCC_SM6150) += gpucc-sm6150.o obj-$(CONFIG_MSM_GPUCC_SM8150) += gpucc-sm8150.o obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o diff --git a/drivers/clk/qcom/gpucc-sdmmagpie.c b/drivers/clk/qcom/gpucc-sdmmagpie.c new file mode 100644 index 000000000000..b2d18f94ddaa --- /dev/null +++ b/drivers/clk/qcom/gpucc-sdmmagpie.c @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "common.h" +#include "reset.h" +#include "vdd-level.h" + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + +enum vdd_gx_levels { + VDD_GX_NONE, + VDD_GX_MIN, /* MIN SVS */ + VDD_GX_LOWER, /* SVS2 */ + VDD_GX_LOW, /* SVS */ + VDD_GX_LOW_L1, /* SVSL1 */ + VDD_GX_NOMINAL, /* NOM */ + VDD_GX_NOMINAL_L1, /* NOM1 */ + VDD_GX_HIGH, /* TURBO */ + VDD_GX_HIGH_L1, /* TURBO1 */ + VDD_GX_NUM, +}; + +static int vdd_gx_corner[] = { + RPMH_REGULATOR_LEVEL_OFF, /* VDD_GX_NONE */ + RPMH_REGULATOR_LEVEL_MIN_SVS, /* VDD_GX_MIN */ + RPMH_REGULATOR_LEVEL_LOW_SVS, /* VDD_GX_LOWER */ + RPMH_REGULATOR_LEVEL_SVS, /* VDD_GX_LOW */ + RPMH_REGULATOR_LEVEL_SVS_L1, /* VDD_GX_LOW_L1 */ + RPMH_REGULATOR_LEVEL_NOM, /* VDD_GX_NOMINAL */ + RPMH_REGULATOR_LEVEL_NOM_L1, /* VDD_GX_NOMINAL_L1 */ + RPMH_REGULATOR_LEVEL_TURBO, /* VDD_GX_HIGH */ + RPMH_REGULATOR_LEVEL_TURBO_L1, /* VDD_GX_HIGH_L1 */ + RPMH_REGULATOR_LEVEL_MAX, /* VDD_GX_MAX */ +}; + +static DEFINE_VDD_REGULATORS(vdd_cx, VDD_NUM, 1, vdd_corner); +static DEFINE_VDD_REGULATORS(vdd_mx, VDD_NUM, 1, vdd_corner); +static DEFINE_VDD_REGULATORS(vdd_gx, VDD_GX_NUM, 1, vdd_gx_corner); + +#define CX_GMU_CBCR_SLEEP_MASK 0xF +#define CX_GMU_CBCR_SLEEP_SHIFT 4 +#define CX_GMU_CBCR_WAKE_MASK 0xF +#define CX_GMU_CBCR_WAKE_SHIFT 8 + +enum { + P_BI_TCXO, + P_CORE_BI_PLL_TEST_SE, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, + P_GPU_CC_PLL0_OUT_EVEN, + P_GPU_CC_PLL0_OUT_MAIN, + P_GPU_CC_PLL0_OUT_ODD, + P_GPU_CC_PLL1_OUT_EVEN, + P_GPU_CC_PLL1_OUT_MAIN, + P_GPU_CC_PLL1_OUT_ODD, +}; + +static const struct parent_map gpu_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_MAIN, 1 }, + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gpu_cc_parent_names_0[] = { + "bi_tcxo", + "gpu_cc_pll0", + "gpu_cc_pll1", + "gcc_gpu_gpll0_clk_src", + "gcc_gpu_gpll0_div_clk_src", + "core_bi_pll_test_se", +}; + +static const struct parent_map gpu_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_EVEN, 1 }, + { P_GPU_CC_PLL0_OUT_ODD, 2 }, + { P_GPU_CC_PLL1_OUT_EVEN, 3 }, + { P_GPU_CC_PLL1_OUT_ODD, 4 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gpu_cc_parent_names_1[] = { + "bi_tcxo", + "gpu_cc_pll0_out_even", + "gpu_cc_pll0_out_odd", + "gpu_cc_pll1_out_even", + "gpu_cc_pll1_out_odd", + "gcc_gpu_gpll0_clk_src", + "core_bi_pll_test_se", +}; + +static struct pll_vco fabia_vco[] = { + { 249600000, 2000000000, 0 }, + { 125000000, 1000000000, 1 }, +}; + +static const struct alpha_pll_config gpu_cc_pll0_config = { + .l = 0x12, + .alpha = 0xC000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002067, + .user_ctl_val = 0x00000001, + .user_ctl_hi_val = 0x00004805, + .test_ctl_hi_val = 0x40000000, +}; + +static struct clk_alpha_pll gpu_cc_pll0 = { + .offset = 0x0, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_pll_ops, + .vdd_class = &vdd_mx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 615000000, + [VDD_LOW] = 1066000000, + [VDD_LOW_L1] = 1600000000, + [VDD_NOMINAL] = 2000000000}, + }, + }, +}; + +static const struct clk_div_table post_div_table_fabia_even[] = { + { 0x0, 1 }, + { 0x1, 2 }, + { 0x3, 4 }, + { 0x7, 8 }, + { } +}; + +static struct clk_alpha_pll_postdiv gpu_cc_pll0_out_even = { + .offset = 0x0, + .post_div_shift = 8, + .post_div_table = post_div_table_fabia_even, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll0_out_even", + .parent_names = (const char *[]){ "gpu_cc_pll0" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_generic_pll_postdiv_ops, + }, +}; + +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_gmu_clk_src = { + .cmd_rcgr = 0x1120, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_0, + .freq_tbl = ftbl_gpu_cc_gmu_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gmu_clk_src", + .parent_names = gpu_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 200000000}, + }, +}; + +/* PLL would be 2 times. */ +static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src[] = { + F(180000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(267000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(355000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(430000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(565000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(650000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(750000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(780000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = { + .cmd_rcgr = 0x101c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_1, + .freq_tbl = ftbl_gpu_cc_gx_gfx3d_clk_src, + .flags = FORCE_ENABLE_RCG, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gfx3d_clk_src", + .parent_names = gpu_cc_parent_names_1, + .num_parents = 7, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_gx, + .num_rate_max = VDD_GX_NUM, + .rate_max = (unsigned long[VDD_GX_NUM]) { + [VDD_GX_MIN] = 180000000, + [VDD_GX_LOWER] = 267000000, + [VDD_GX_LOW] = 355000000, + [VDD_GX_LOW_L1] = 430000000, + [VDD_GX_NOMINAL] = 565000000, + [VDD_GX_NOMINAL_L1] = 650000000, + [VDD_GX_HIGH] = 750000000, + [VDD_GX_HIGH_L1] = 780000000}, + }, +}; + +static struct clk_branch gpu_cc_acd_ahb_clk = { + .halt_reg = 0x1168, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1168, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_acd_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_acd_cxo_clk = { + .halt_reg = 0x1164, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1164, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_acd_cxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_ahb_clk = { + .halt_reg = 0x1078, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1078, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_crc_ahb_clk = { + .halt_reg = 0x107c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x107c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_crc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_apb_clk = { + .halt_reg = 0x1088, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1088, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_apb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gfx3d_clk = { + .halt_reg = 0x10a4, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x10a4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gfx3d_clk", + .parent_names = (const char *[]){ + "gpu_cc_gx_gfx3d_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gfx3d_slv_clk = { + .halt_reg = 0x10a8, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x10a8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gfx3d_slv_clk", + .parent_names = (const char *[]){ + "gpu_cc_gx_gfx3d_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gmu_clk = { + .halt_reg = 0x1098, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1098, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gmu_clk", + .parent_names = (const char *[]){ + "gpu_cc_gmu_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_snoc_dvm_clk = { + .halt_reg = 0x108c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x108c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_snoc_dvm_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_aon_clk = { + .halt_reg = 0x1004, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cxo_aon_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_clk = { + .halt_reg = 0x109c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x109c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_cxo_clk = { + .halt_reg = 0x1060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1060, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_cxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gfx3d_clk = { + .halt_reg = 0x1054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gfx3d_clk", + .parent_names = (const char *[]){ + "gpu_cc_gx_gfx3d_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gmu_clk = { + .halt_reg = 0x1064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gmu_clk", + .parent_names = (const char *[]){ + "gpu_cc_gmu_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_vsense_clk = { + .halt_reg = 0x1058, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_vsense_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *gpu_cc_sdmmagpie_clocks[] = { + [GPU_CC_ACD_AHB_CLK] = &gpu_cc_acd_ahb_clk.clkr, + [GPU_CC_ACD_CXO_CLK] = &gpu_cc_acd_cxo_clk.clkr, + [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr, + [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, + [GPU_CC_CX_APB_CLK] = &gpu_cc_cx_apb_clk.clkr, + [GPU_CC_CX_GFX3D_CLK] = &gpu_cc_cx_gfx3d_clk.clkr, + [GPU_CC_CX_GFX3D_SLV_CLK] = &gpu_cc_cx_gfx3d_slv_clk.clkr, + [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr, + [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr, + [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr, + [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr, + [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr, + [GPU_CC_GX_CXO_CLK] = &gpu_cc_gx_cxo_clk.clkr, + [GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr, + [GPU_CC_GX_GFX3D_CLK_SRC] = &gpu_cc_gx_gfx3d_clk_src.clkr, + [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr, + [GPU_CC_GX_VSENSE_CLK] = &gpu_cc_gx_vsense_clk.clkr, + [GPU_CC_PLL0] = &gpu_cc_pll0.clkr, + [GPU_CC_PLL0_OUT_EVEN] = &gpu_cc_pll0_out_even.clkr, +}; + +static const struct regmap_config gpu_cc_sdmmagpie_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x8008, + .fast_io = true, +}; + +static const struct qcom_cc_desc gpu_cc_sdmmagpie_desc = { + .config = &gpu_cc_sdmmagpie_regmap_config, + .clks = gpu_cc_sdmmagpie_clocks, + .num_clks = ARRAY_SIZE(gpu_cc_sdmmagpie_clocks), +}; + +static const struct of_device_id gpu_cc_sdmmagpie_match_table[] = { + { .compatible = "qcom,gpucc-sdmmagpie" }, + { } +}; +MODULE_DEVICE_TABLE(of, gpu_cc_sdmmagpie_match_table); + +static int gpu_cc_sdmmagpie_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + unsigned int value, mask; + + /* Get CX voltage regulator for CX and GMU clocks. */ + vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx"); + if (IS_ERR(vdd_cx.regulator[0])) { + if (!(PTR_ERR(vdd_cx.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_cx regulator\n"); + return PTR_ERR(vdd_cx.regulator[0]); + } + + /* Get MX voltage regulator for GPU PLL graphic clock. */ + vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_mx"); + if (IS_ERR(vdd_mx.regulator[0])) { + if (!(PTR_ERR(vdd_mx.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_mx regulator\n"); + return PTR_ERR(vdd_mx.regulator[0]); + } + + /* GFX voltage regulators for GFX3D graphic clock. */ + vdd_gx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_gfx"); + if (IS_ERR(vdd_gx.regulator[0])) { + if (PTR_ERR(vdd_gx.regulator[0]) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get vdd_gx regulator\n"); + return PTR_ERR(vdd_gx.regulator[0]); + } + + /* Avoid turning on the rail during clock registration */ + vdd_gx.skip_handoff = true; + + regmap = qcom_cc_map(pdev, &gpu_cc_sdmmagpie_desc); + if (IS_ERR(regmap)) { + pr_err("Failed to map the gpu_cc registers\n"); + return PTR_ERR(regmap); + } + + clk_fabia_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); + + ret = qcom_cc_really_probe(pdev, &gpu_cc_sdmmagpie_desc, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to register GPU CC clocks\n"); + return ret; + } + + /* Recommended WAKEUP/SLEEP settings for the gpu_cc_cx_gmu_clk */ + mask = CX_GMU_CBCR_WAKE_MASK << CX_GMU_CBCR_WAKE_SHIFT; + mask |= CX_GMU_CBCR_SLEEP_MASK << CX_GMU_CBCR_SLEEP_SHIFT; + value = 0xF << CX_GMU_CBCR_WAKE_SHIFT | 0xF << CX_GMU_CBCR_SLEEP_SHIFT; + regmap_update_bits(regmap, gpu_cc_cx_gmu_clk.clkr.enable_reg, + mask, value); + + dev_info(&pdev->dev, "Registered GPU CC clocks\n"); + + return ret; +} + +static struct platform_driver gpu_cc_sdmmagpie_driver = { + .probe = gpu_cc_sdmmagpie_probe, + .driver = { + .name = "gpu_cc-sdmmagpie", + .of_match_table = gpu_cc_sdmmagpie_match_table, + }, +}; + +static int __init gpu_cc_sdmmagpie_init(void) +{ + return platform_driver_register(&gpu_cc_sdmmagpie_driver); +} +subsys_initcall(gpu_cc_sdmmagpie_init); + +static void __exit gpu_cc_sdmmagpie_exit(void) +{ + platform_driver_unregister(&gpu_cc_sdmmagpie_driver); +} +module_exit(gpu_cc_sdmmagpie_exit); + +MODULE_DESCRIPTION("QTI GPU_CC SDMMAGPIE Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:gpu_cc-sdmmagpie"); diff --git a/include/dt-bindings/clock/qcom,gpucc-sdmmagpie.h b/include/dt-bindings/clock/qcom,gpucc-sdmmagpie.h index d7160420a7d3..d0df54ca4099 100644 --- a/include/dt-bindings/clock/qcom,gpucc-sdmmagpie.h +++ b/include/dt-bindings/clock/qcom,gpucc-sdmmagpie.h @@ -14,28 +14,25 @@ #ifndef _DT_BINDINGS_CLK_QCOM_GPU_CC_SDMMAGPIE_H #define _DT_BINDINGS_CLK_QCOM_GPU_CC_SDMMAGPIE_H -#define GPU_CC_ACD_AHB_CLK 0 -#define GPU_CC_ACD_CXO_CLK 1 -#define GPU_CC_AHB_CLK 2 -#define GPU_CC_CRC_AHB_CLK 3 -#define GPU_CC_CX_APB_CLK 4 -#define GPU_CC_CX_GFX3D_CLK 5 -#define GPU_CC_CX_GFX3D_SLV_CLK 6 -#define GPU_CC_CX_GMU_CLK 7 -#define GPU_CC_CX_SNOC_DVM_CLK 8 -#define GPU_CC_CXO_AON_CLK 9 -#define GPU_CC_CXO_CLK 10 -#define GPU_CC_GMU_CLK_SRC 11 -#define GPU_CC_GX_CXO_CLK 12 -#define GPU_CC_GX_GFX3D_CLK 13 -#define GPU_CC_GX_GFX3D_CLK_SRC 14 -#define GPU_CC_GX_GMU_CLK 15 -#define GPU_CC_GX_VSENSE_CLK 16 -#define GPU_CC_PLL0 17 -#define GPU_CC_PLL0_OUT_EVEN 18 +#define GPU_CC_PLL0 0 +#define GPU_CC_PLL0_OUT_EVEN 1 +#define GPU_CC_ACD_AHB_CLK 2 +#define GPU_CC_ACD_CXO_CLK 3 +#define GPU_CC_AHB_CLK 4 +#define GPU_CC_CRC_AHB_CLK 5 +#define GPU_CC_CX_APB_CLK 6 +#define GPU_CC_CX_GFX3D_CLK 7 +#define GPU_CC_CX_GFX3D_SLV_CLK 8 +#define GPU_CC_CX_GMU_CLK 9 +#define GPU_CC_CX_SNOC_DVM_CLK 10 +#define GPU_CC_CXO_AON_CLK 11 +#define GPU_CC_CXO_CLK 12 +#define GPU_CC_GMU_CLK_SRC 13 +#define GPU_CC_GX_CXO_CLK 14 +#define GPU_CC_GX_GFX3D_CLK 15 +#define GPU_CC_GX_GFX3D_CLK_SRC 16 +#define GPU_CC_GX_GMU_CLK 17 +#define GPU_CC_GX_VSENSE_CLK 18 #define GPU_CC_SLEEP_CLK 19 -#define CX_GDSC 0 -#define GX_GDSC 1 - #endif -- GitLab From 83154934dafd4a609ed8ffb52bf905bb32c7318c Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Tue, 14 Aug 2018 11:17:32 +0530 Subject: [PATCH 0943/1001] ARM: dts: msm: Update the GPUCC clock node for SDMMAGPIE Update GPU clock controller node and gdsc to use the GPU clock driver. Change-Id: I995d58491914fe8a19f56359c43113854c2b1721 Signed-off-by: Shefali Jain --- arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi | 16 ++++++++++++++-- arch/arm64/boot/dts/qcom/sdmmagpie.dtsi | 14 ++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi index 790b3a14f7ee..6c4228397337 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-gdsc.dtsi @@ -175,8 +175,18 @@ reg = <0x5091540 0x4>; }; + gpu_gx_domain_addr: syscon@0x5091508 { + compatible = "syscon"; + reg = <0x5091508 0x4>; + }; + + gpu_gx_sw_reset: syscon@0x5091008 { + compatible = "syscon"; + reg = <0x5091008 0x4>; + }; + gpu_cx_gdsc: qcom,gdsc@509106c { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "gpu_cx_gdsc"; reg = <0x509106c 0x4>; hw-ctrl-addr = <&gpu_cx_hw_ctrl>; @@ -187,10 +197,12 @@ }; gpu_gx_gdsc: qcom,gdsc@509100c { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "gpu_gx_gdsc"; reg = <0x509100c 0x4>; qcom,poll-cfg-gdscr; + domain-addr = <&gpu_gx_domain_addr>; + sw-reset = <&gpu_gx_sw_reset>; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index f43e8081888a..b7a530460641 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -661,8 +661,12 @@ }; clock_gpucc: qcom,gpucc { - compatible = "qcom,dummycc"; - clock-output-names = "gpucc_clocks"; + compatible = "qcom,gpucc-sdmmagpie", "syscon"; + reg = <0x5090000 0x9000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_mx-supply = <&VDD_MX_LEVEL>; + vdd_gfx-supply = <&VDD_GFX_LEVEL>; #clock-cells = <1>; #reset-cells = <1>; }; @@ -1774,10 +1778,16 @@ }; &gpu_cx_gdsc { + parent-supply = <&VDD_CX_LEVEL>; status = "ok"; }; &gpu_gx_gdsc { + clock-names = "core_root_clk"; + clocks = <&clock_gpucc GPU_CC_GX_GFX3D_CLK_SRC>; + qcom,force-enable-root-clk; + parent-supply = <&VDD_GFX_LEVEL>; + qcom,reset-aon-logic; status = "ok"; }; -- GitLab From c20189289451f6b5b297a6e54d542f584e50c1d5 Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Tue, 21 Aug 2018 16:23:25 +0530 Subject: [PATCH 0944/1001] defconfig: Enable GPUCC and NPUCC drivers for SDMSTEPPE Enable graphics clock controller and network processing unit clock controller drivers for SDMSTEPPE. Change-Id: If2bd3c6757c805e30e22ab77326cbb2791c093e7 Signed-off-by: Shefali Jain --- arch/arm64/configs/vendor/sdmsteppe-perf_defconfig | 2 ++ arch/arm64/configs/vendor/sdmsteppe_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig index 07d72a730f9b..0b0adee7ef72 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig @@ -490,6 +490,8 @@ CONFIG_MSM_CAMCC_SM6150=y CONFIG_MSM_DISPCC_SM6150=y CONFIG_MSM_GCC_SDMMAGPIE=y CONFIG_MSM_VIDEOCC_SDMMAGPIE=y +CONFIG_MSM_NPUCC_SDMMAGPIE=y +CONFIG_MSM_GPUCC_SDMMAGPIE=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_QCOM_APCS_IPC=y diff --git a/arch/arm64/configs/vendor/sdmsteppe_defconfig b/arch/arm64/configs/vendor/sdmsteppe_defconfig index 86c1db5adde9..d5d4f2c23d4f 100644 --- a/arch/arm64/configs/vendor/sdmsteppe_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe_defconfig @@ -507,6 +507,8 @@ CONFIG_MSM_CAMCC_SM6150=y CONFIG_MSM_DISPCC_SM6150=y CONFIG_MSM_GCC_SDMMAGPIE=y CONFIG_MSM_VIDEOCC_SDMMAGPIE=y +CONFIG_MSM_NPUCC_SDMMAGPIE=y +CONFIG_MSM_GPUCC_SDMMAGPIE=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_QCOM_APCS_IPC=y -- GitLab From abb915b9667d342d8832c02d6acaf66cfd71a6f2 Mon Sep 17 00:00:00 2001 From: Santosh Mardi Date: Mon, 20 Aug 2018 15:20:22 +0530 Subject: [PATCH 0945/1001] ARM: dts: msm: update base and global base address for sm6150 There are difference in offset for base and global base address for the throttle HW block in gemnoc. Update the address accordingly for sm6150 target. Change-Id: Ibfb6da32c3b9653a0d3d634038224ea3420c448a Signed-off-by: Santosh Mardi --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 7fb99f5f53c1..db3ac007516d 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -2387,7 +2387,7 @@ cpu_cpu_llcc_bwmon: qcom,cpu-cpu-llcc-bwmon@90b6400 { compatible = "qcom,bimc-bwmon4"; - reg = <0x90b6400 0x300>, <0x90b6300 0x200>; + reg = <0x90b6300 0x300>, <0x90b6200 0x200>; reg-names = "base", "global_base"; interrupts = ; qcom,mport = <0>; -- GitLab From df7b91db32b0129fb3845a863249d7e8fb331671 Mon Sep 17 00:00:00 2001 From: Bandari Ramesh Date: Sun, 12 Aug 2018 22:09:05 +0530 Subject: [PATCH 0946/1001] bluetooth: Add bluetooth uart node for sm6150 IDP, QRD - Add bluetooth uart node for sm6150 IDP - Add bluetooth uart node for sm6150 QRD CRs-Fixed: 2298556 Change-Id: Iaba2e31baf83de8b5eb147ee62e3609c60a8a3a6 Signed-off-by: Bandari Ramesh --- arch/arm64/boot/dts/qcom/sm6150-idp.dtsi | 4 ++++ arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi index 5859c444f2e7..835339cf32ff 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi @@ -27,6 +27,10 @@ status = "ok"; }; +&qupv3_se7_4uart { + status = "ok"; +}; + &pm6150l_wled { qcom,string-cfg= <3>; status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi index 63e8ab9c8ae4..321708df7e12 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi @@ -23,6 +23,10 @@ &soc { }; +&qupv3_se7_4uart { + status = "ok"; +}; + &pm6150l_wled { qcom,string-cfg= <3>; status = "ok"; -- GitLab From 7774be3375fb10b2fb5394c6bc3893d9f313a29a Mon Sep 17 00:00:00 2001 From: Mulu He Date: Thu, 23 Aug 2018 13:52:35 +0800 Subject: [PATCH 0947/1001] ARM: dts: msm: Remove funnel SSC for sm8150 SSC will configure SSC funnel according to the QMI call from HLOS,so remove SSC funnel config from HLOS side. Change-Id: Ib8b4f7debbd7a7021c279b80c4e6fe5774e85d60 Signed-off-by: Mulu He --- .../arm64/boot/dts/qcom/sm8150-coresight.dtsi | 43 ++----------------- 1 file changed, 4 insertions(+), 39 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi b/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi index 3a6441e486d3..340bc0599bab 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi @@ -199,10 +199,10 @@ }; port@1 { reg = <5>; - funnel_swao_in_funnel_ssc: endpoint { + funnel_swao_in_ssc_etm0: endpoint { slave-mode; remote-endpoint= - <&funnel_ssc_out_funnel_swao>; + <&ssc_etm0_out_funnel_swao>; }; }; port@2 { @@ -2388,9 +2388,9 @@ qcom,inst-id = <8>; port { - ssc_etm0_out_funnel_ssc: endpoint { + ssc_etm0_out_funnel_swao: endpoint { remote-endpoint = - <&funnel_ssc_in_ssc_etm0>; + <&funnel_swao_in_ssc_etm0>; }; }; }; @@ -2715,39 +2715,4 @@ }; }; }; - - funnel_ssc: funnel@6b14000 { - compatible = "arm,primecell"; - arm,primecell-periphid = <0x0003b908>; - - reg = <0x6b14000 0x1000>; - reg-names = "funnel-base"; - - coresight-name = "coresight-funnel-ssc"; - - clocks = <&clock_aop QDSS_CLK>; - clock-names = "apb_pclk"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - funnel_ssc_out_funnel_swao: endpoint { - remote-endpoint = - <&funnel_swao_in_funnel_ssc>; - }; - }; - - port@1 { - reg = <0>; - funnel_ssc_in_ssc_etm0: endpoint { - slave-mode; - remote-endpoint = - <&ssc_etm0_out_funnel_ssc>; - }; - }; - }; - }; }; -- GitLab From b3169ad93f1011ef137a5048080c9fcd6f45f6b3 Mon Sep 17 00:00:00 2001 From: Vevek Venkatesan Date: Sun, 12 Aug 2018 20:07:03 +0530 Subject: [PATCH 0948/1001] input: touchscreen: add fix in driver to support VMAP_STACK Add fix in hxchipset Himax touchscreen driver, to support VMAP_STACK security feature and minor correction in Makefile. Change-Id: I05d05d22088e82c1ab808e86521949a682963174 Signed-off-by: Vevek Venkatesan --- drivers/input/touchscreen/Makefile | 2 +- .../touchscreen/hxchipset/himax_common.c | 9 +- .../touchscreen/hxchipset/himax_common.h | 2 + .../touchscreen/hxchipset/himax_platform.c | 98 +++++++++++++++---- .../touchscreen/hxchipset/himax_platform.h | 8 +- 5 files changed, 95 insertions(+), 24 deletions(-) diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index b04e1c77eb57..fbc7fdbaf3f0 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -106,4 +106,4 @@ obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o obj-$(CONFIG_TOUCHSCREEN_ST) += st/ -obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET)» += hxchipset/ +obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET) += hxchipset/ diff --git a/drivers/input/touchscreen/hxchipset/himax_common.c b/drivers/input/touchscreen/hxchipset/himax_common.c index 5854de063d82..980ceeb685bb 100644 --- a/drivers/input/touchscreen/hxchipset/himax_common.c +++ b/drivers/input/touchscreen/hxchipset/himax_common.c @@ -986,7 +986,7 @@ static int himax_touch_get(struct himax_ts_data *ts, uint8_t *buf, int ts_path, || (HX_ESD_RESET_ACTIVATE) #endif ) { - if (!g_core_fp.fp_read_event_stack(buf, 128)) { + if (!g_core_fp.fp_read_event_stack(buf, HX_REPORT_SZ)) { E("%s: can't read data from chip!\n", __func__); ts_status = HX_TS_GET_DATA_FAIL; goto END_FUNCTION; @@ -1013,7 +1013,7 @@ static int himax_touch_get(struct himax_ts_data *ts, uint8_t *buf, int ts_path, break; #endif case HX_REPORT_COORD_RAWDATA: - if (!g_core_fp.fp_read_event_stack(buf, 128)) { + if (!g_core_fp.fp_read_event_stack(buf, HX_REPORT_SZ)) { E("%s: can't read data from chip!\n", __func__); ts_status = HX_TS_GET_DATA_FAIL; goto END_FUNCTION; @@ -1750,7 +1750,7 @@ int himax_report_data(struct himax_ts_data *ts, int ts_path, int ts_status) static int himax_ts_operation(struct himax_ts_data *ts, int ts_path, int ts_status) { uint8_t hw_reset_check[2]; - uint8_t buf[128]; + uint8_t buf[HX_REPORT_SZ]; memset(buf, 0x00, sizeof(buf)); memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); @@ -1895,7 +1895,7 @@ int himax_fb_register(struct himax_ts_data *ts) int ret = 0; I(" %s in\n", __func__); - ts->fb_notif.notifier_call = fb_notifier_callback; + ts->fb_notif.notifier_call = drm_notifier_callback; ret = msm_drm_register_client(&ts->fb_notif); if (ret) E(" Unable to register fb_notifier: %d\n", ret); @@ -2230,6 +2230,7 @@ void himax_chip_common_deinit(void) kfree(hx_touch_data); kfree(ic_data); kfree(ts->pdata); + kfree(ts->report_i2c_data); kfree(ts); probe_fail_flag = 0; } diff --git a/drivers/input/touchscreen/hxchipset/himax_common.h b/drivers/input/touchscreen/hxchipset/himax_common.h index 82907fd554fa..45bd140f94a9 100644 --- a/drivers/input/touchscreen/hxchipset/himax_common.h +++ b/drivers/input/touchscreen/hxchipset/himax_common.h @@ -142,6 +142,7 @@ #define HX_FINGER_ON 1 #define HX_FINGER_LEAVE 2 +#define HX_REPORT_SZ 128 enum HX_TS_PATH { HX_REPORT_COORD = 1, @@ -363,6 +364,7 @@ struct himax_ts_data { struct work_struct ito_test_work; #endif + uint8_t *report_i2c_data; }; struct himax_debug { diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.c b/drivers/input/touchscreen/hxchipset/himax_platform.c index c0e75f7f7309..8672e95d240d 100644 --- a/drivers/input/touchscreen/hxchipset/himax_platform.c +++ b/drivers/input/touchscreen/hxchipset/himax_platform.c @@ -168,7 +168,10 @@ int himax_parse_dt(struct himax_ts_data *ts, struct himax_i2c_platform_data *pda int himax_bus_read(uint8_t command, uint8_t *data, uint32_t length, uint8_t toRetry) { int retry; - struct i2c_client *client = private_ts->client; + bool reallocate = false; + struct himax_ts_data *ts = private_ts; + uint8_t *buf = ts->report_i2c_data; + struct i2c_client *client = ts->client; struct i2c_msg msg[] = { { .addr = client->addr, @@ -180,11 +183,22 @@ int himax_bus_read(uint8_t command, uint8_t *data, uint32_t length, uint8_t toRe .addr = client->addr, .flags = I2C_M_RD, .len = length, - .buf = data, + .buf = buf, } }; - mutex_lock(&private_ts->rw_lock); + if (length > HX_REPORT_SZ * 2) { + E("%s: data length too large %d!\n", __func__, length); + buf = kmalloc(length, GFP_KERNEL); + if (!buf) { + E("%s: failed realloc buf %d\n", __func__, length); + return -EIO; + } + reallocate = true; + msg[1].buf = buf; + } + + mutex_lock(&ts->rw_lock); for (retry = 0; retry < toRetry; retry++) { if (i2c_transfer(client->adapter, msg, 2) == 2) @@ -196,19 +210,26 @@ int himax_bus_read(uint8_t command, uint8_t *data, uint32_t length, uint8_t toRe if (retry == toRetry) { E("%s: i2c_read_block retry over %d\n", __func__, toRetry); i2c_error_count = toRetry; - mutex_unlock(&private_ts->rw_lock); + mutex_unlock(&ts->rw_lock); return -EIO; } - mutex_unlock(&private_ts->rw_lock); + memcpy(data, buf, length); + mutex_unlock(&ts->rw_lock); + + if (reallocate) + kfree(buf); + return 0; } int himax_bus_write(uint8_t command, uint8_t *data, uint32_t length, uint8_t toRetry) { int retry; - uint8_t buf[length + 1]; - struct i2c_client *client = private_ts->client; + bool reallocate = false; + struct himax_ts_data *ts = private_ts; + uint8_t *buf = ts->report_i2c_data; + struct i2c_client *client = ts->client; struct i2c_msg msg[] = { { .addr = client->addr, @@ -218,7 +239,17 @@ int himax_bus_write(uint8_t command, uint8_t *data, uint32_t length, uint8_t toR } }; - mutex_lock(&private_ts->rw_lock); + if (length + 1 > HX_REPORT_SZ * 2) { + E("%s: data length too large %d!\n", __func__, length + 1); + buf = kmalloc(length + 1, GFP_KERNEL); + if (!buf) { + E("%s: failed realloc buf %d\n", __func__, length + 1); + return -EIO; + } + reallocate = true; + } + + mutex_lock(&ts->rw_lock); buf[0] = command; memcpy(buf + 1, data, length); @@ -232,11 +263,15 @@ int himax_bus_write(uint8_t command, uint8_t *data, uint32_t length, uint8_t toR if (retry == toRetry) { E("%s: i2c_write_block retry over %d\n", __func__, toRetry); i2c_error_count = toRetry; - mutex_unlock(&private_ts->rw_lock); + mutex_unlock(&ts->rw_lock); return -EIO; } - mutex_unlock(&private_ts->rw_lock); + mutex_unlock(&ts->rw_lock); + + if (reallocate) + kfree(buf); + return 0; } @@ -248,7 +283,9 @@ int himax_bus_write_command(uint8_t command, uint8_t toRetry) int himax_bus_master_write(uint8_t *data, uint32_t length, uint8_t toRetry) { int retry; - uint8_t buf[length]; + bool reallocate = false; + struct himax_ts_data *ts = private_ts; + uint8_t *buf = ts->report_i2c_data; struct i2c_client *client = private_ts->client; struct i2c_msg msg[] = { { @@ -259,7 +296,17 @@ int himax_bus_master_write(uint8_t *data, uint32_t length, uint8_t toRetry) } }; - mutex_lock(&private_ts->rw_lock); + if (length > HX_REPORT_SZ * 2) { + E("%s: data length too large %d!\n", __func__, length); + buf = kmalloc(length, GFP_KERNEL); + if (!buf) { + E("%s: failed realloc buf %d\n", __func__, length); + return -EIO; + } + reallocate = true; + } + + mutex_lock(&ts->rw_lock); memcpy(buf, data, length); for (retry = 0; retry < toRetry; retry++) { @@ -272,11 +319,15 @@ int himax_bus_master_write(uint8_t *data, uint32_t length, uint8_t toRetry) if (retry == toRetry) { E("%s: i2c_write_block retry over %d\n", __func__, toRetry); i2c_error_count = toRetry; - mutex_unlock(&private_ts->rw_lock); + mutex_unlock(&ts->rw_lock); return -EIO; } - mutex_unlock(&private_ts->rw_lock); + mutex_unlock(&ts->rw_lock); + + if (reallocate) + kfree(buf); + return 0; } @@ -641,7 +692,8 @@ static int himax_common_resume(struct device *dev) #if defined(CONFIG_DRM) -int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) +int drm_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) { struct msm_drm_notifier *evdata = data; int *blank; @@ -676,7 +728,8 @@ int fb_notifier_callback(struct notifier_block *self, unsigned long event, void #elif defined(CONFIG_FB) -int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) +int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) { struct fb_event *evdata = data; int *blank; @@ -741,6 +794,13 @@ int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_i mutex_init(&ts->rw_lock); private_ts = ts; + ts->report_i2c_data = kmalloc(HX_REPORT_SZ * 2, GFP_KERNEL); + if (ts->report_i2c_data == NULL) { + E("%s: allocate report_i2c_data failed\n", __func__); + ret = -ENOMEM; + goto err_report_i2c_data; + } + /* * ts chip initialization is deferred till FB_UNBLACK event; * probe is considered pending till then. @@ -752,7 +812,12 @@ int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_i goto err_fb_notify_reg_failed; #endif + return ret; + err_fb_notify_reg_failed: + kfree(ts->report_i2c_data); +err_report_i2c_data: + kfree(ts); err_alloc_data_failed: err_check_functionality_failed: @@ -762,7 +827,6 @@ int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_i int himax_chip_common_remove(struct i2c_client *client) { himax_chip_common_deinit(); - return 0; } diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.h b/drivers/input/touchscreen/hxchipset/himax_platform.h index ac6e37d55dce..9e83f4212c5c 100644 --- a/drivers/input/touchscreen/hxchipset/himax_platform.h +++ b/drivers/input/touchscreen/hxchipset/himax_platform.h @@ -125,8 +125,12 @@ extern uint8_t himax_int_gpio_read(int pinnum); extern int himax_gpio_power_config(struct himax_i2c_platform_data *pdata); -#if defined(CONFIG_DRM) || defined(CONFIG_FB) - extern int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data); +#if defined(CONFIG_DRM) + extern int drm_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); +#elif defined(CONFIG_FB) + extern int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); #endif #if defined(HX_PLATFOME_DEFINE_KEY) -- GitLab From 31ebfc913792bf40ae34d169f6d6c981f17b80d2 Mon Sep 17 00:00:00 2001 From: Srinivas Ramana Date: Tue, 21 Aug 2018 19:42:27 +0530 Subject: [PATCH 0949/1001] ARM: dts: msm: Support command mode display platform for sm6150 Add new sm6150 platform with support for command mode display. Change-Id: I7d8824d30d06717d1a6806e4ba692061c68c700a Signed-off-by: Srinivas Ramana --- arch/arm64/boot/dts/qcom/Makefile | 3 ++ .../sm6150-cmd-mode-display-idp-overlay.dts | 30 +++++++++++++++++++ .../dts/qcom/sm6150-cmd-mode-display-idp.dts | 22 ++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sm6150-cmd-mode-display-idp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sm6150-cmd-mode-display-idp.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 07f4e8043d8c..2bf868632f9c 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -88,6 +88,7 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) sm6150p-idp-overlay.dtbo \ sm6150-external-codec-idp-overlay.dtbo \ sm6150-usbc-idp-overlay.dtbo \ + sm6150-cmd-mode-display-idp-overlay.dtbo \ sa6155-adp-star-overlay.dtbo \ sa6155p-adp-star-overlay.dtbo @@ -98,6 +99,7 @@ sm6150p-qrd-overlay.dtbo-base := sm6150p.dtb sm6150p-idp-overlay.dtbo-base := sm6150p.dtb sm6150-external-codec-idp-overlay.dtbo-base := sm6150.dtb sm6150-usbc-idp-overlay.dtbo-base := sm6150.dtb +sm6150-cmd-mode-display-idp-overlay.dtbo-base := sm6150.dtb sa6155-adp-star-overlay.dtbo-base := sa6155.dtb sa6155p-adp-star-overlay.dtbo-base := sa6155p.dtb else @@ -108,6 +110,7 @@ dtb-$(CONFIG_ARCH_SM6150) += sm6150-rumi.dtb \ sm6150p-idp.dtb \ sm6150-external-codec-idp.dtb \ sm6150-usbc-idp.dtb \ + sm6150-cmd-mode-display-idp.dtb \ sa6155-adp-star.dtb \ sa6155p-adp-star.dtb diff --git a/arch/arm64/boot/dts/qcom/sm6150-cmd-mode-display-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-cmd-mode-display-idp-overlay.dts new file mode 100644 index 000000000000..12f9774b0fa2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-cmd-mode-display-idp-overlay.dts @@ -0,0 +1,30 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "sm6150-idp.dtsi" +#include "sm6150-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM6150 Command mode display IDP"; + compatible = "qcom,sm6150-idp", "qcom,sm6150", "qcom,idp"; + qcom,msm-id = <355 0x0>; + qcom,board-id = <34 3>; +}; + +&dsi_hx83112a_truly_vid_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-cmd-mode-display-idp.dts b/arch/arm64/boot/dts/qcom/sm6150-cmd-mode-display-idp.dts new file mode 100644 index 000000000000..c8c7110cbebe --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-cmd-mode-display-idp.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sm6150.dtsi" +#include "sm6150-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM6150 Command mode display IDP"; + compatible = "qcom,sm6150-idp", "qcom,sm6150", "qcom,idp"; + qcom,board-id = <34 3>; +}; -- GitLab From 64616e1007238640c829fed47e45000e5e6e4c15 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Thu, 23 Aug 2018 12:23:56 +0530 Subject: [PATCH 0950/1001] ARM: dts: msm: Add coresight nodes for sdmmagpie Add coresight nodes for sdmmagpie. CRs-fixed: 2300965 Change-Id: I1c283255ab50f8d17d773cf4c6077a5abe4d63ef Signed-off-by: Mao Jinlong --- .../boot/dts/qcom/sdmmagpie-coresight.dtsi | 2589 +++++++++++++++++ arch/arm64/boot/dts/qcom/sdmmagpie.dtsi | 10 + 2 files changed, 2599 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sdmmagpie-coresight.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-coresight.dtsi new file mode 100644 index 000000000000..d03872951951 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-coresight.dtsi @@ -0,0 +1,2589 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +&soc { + + csr: csr@6001000 { + compatible = "qcom,coresight-csr"; + reg = <0x6001000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-csr"; + + qcom,usb-bam-support; + qcom,hwctrl-set-support; + qcom,set-byte-cntr-support; + qcom,blk-size = <1>; + }; + + replicator_qdss: replicator@6046000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x6046000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + replicator_out_tmc_etr: endpoint { + remote-endpoint = + <&tmc_etr_in_replicator>; + }; + }; + + port@1 { + reg = <1>; + replicator_out_replicator1_in: endpoint { + remote-endpoint= + <&replicator1_in_replicator_out>; + }; + }; + + port@2 { + reg = <0>; + replicator_in_tmc_etf: endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_out_replicator>; + }; + }; + }; + }; + + replicator_qdss1: replicator@604a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x604a000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-qdss1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <1>; + replicator1_out_funnel_swao: endpoint { + remote-endpoint= + <&funnel_swao_in_replicator1_out>; + }; + }; + + port@1 { + reg = <1>; + replicator1_in_replicator_out: endpoint { + slave-mode; + remote-endpoint= + <&replicator_out_replicator1_in>; + }; + }; + }; + }; + + tmc_etr: tmc@6048000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6048000 0x1000>, + <0x6064000 0x15000>; + reg-names = "tmc-base", "bam-base"; + + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x05e0 0>, + <&apps_smmu 0x04a0 0>; + + arm,buffer-size = <0x400000>; + + coresight-name = "coresight-tmc-etr"; + coresight-ctis = <&cti0 &cti0>; + coresight-csr = <&csr>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + interrupts = ; + interrupt-names = "byte-cntr-irq"; + + port { + tmc_etr_in_replicator: endpoint { + slave-mode; + remote-endpoint = <&replicator_out_tmc_etr>; + }; + }; + }; + + tmc_etf: tmc@6047000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6047000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf"; + coresight-ctis = <&cti0 &cti0>; + arm,default-sink; + coresight-csr = <&csr>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tmc_etf_out_replicator: endpoint { + remote-endpoint = + <&replicator_in_tmc_etf>; + }; + }; + + port@1 { + reg = <1>; + tmc_etf_in_funnel_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_merg_out_tmc_etf>; + }; + }; + }; + + }; + + funnel_merg: funnel@6045000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6045000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-merg"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_merg_out_tmc_etf: endpoint { + remote-endpoint = + <&tmc_etf_in_funnel_merg>; + }; + }; + + port@1 { + reg = <0>; + funnel_merg_in_funnel_in0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in0_out_funnel_merg>; + }; + }; + + port@2 { + reg = <1>; + funnel_merg_in_funnel_in1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in1_out_funnel_merg>; + }; + }; + + port@3 { + reg = <2>; + funnel_merg_in_funnel_in2: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in2_out_funnel_merg>; + }; + }; + }; + }; + + funnel_in0: funnel@0x6041000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6041000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in0_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in0>; + }; + }; + + port@1 { + reg = <4>; + funnel_in0_in_audio_etm0: endpoint { + slave-mode; + remote-endpoint = + <&audio_etm0_out_funnel_in0>; + }; + }; + + port@2 { + reg = <6>; + funnel_in0_in_funnel_qatb: endpoint { + slave-mode; + remote-endpoint = + <&funnel_qatb_out_funnel_in0>; + }; + }; + + port@3 { + reg = <7>; + funnel_in0_in_stm: endpoint { + slave-mode; + remote-endpoint = <&stm_out_funnel_in0>; + }; + }; + }; + }; + + audio_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-audio-etm0"; + qcom,inst-id = <5>; + + port { + audio_etm0_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_audio_etm0>; + }; + }; + }; + + funnel_in1: funnel@6042000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6042000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in1_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in1>; + }; + }; + + port@1 { + reg = <3>; + funnel_in1_in_modem_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm0_out_funnel_in1>; + }; + }; + + port@2 { + reg = <4>; + funnel_in1_in_replicator_swao: endpoint { + slave-mode; + remote-endpoint = + <&replicator_swao_out_funnel_in1>; + }; + }; + + port@3 { + reg = <0>; + funnel_in1_in_funnel_modem: endpoint { + slave-mode; + remote-endpoint = + <&funnel_modem_out_funnel_in1>; + }; + }; + }; + }; + + funnel_modem: funnel@6832000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6832000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-modem"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_modem_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_modem>; + }; + }; + + port@1 { + reg = <0>; + funnel_modem_in_tpda_modem: endpoint { + slave-mode; + remote-endpoint = + <&tpda_modem_out_funnel_modem>; + }; + }; + }; + }; + + tpda_modem: tpda@6831000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6831000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-modem"; + + qcom,tpda-atid = <67>; + qcom,dsb-elem-size = <0 32>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_modem_out_funnel_modem: endpoint { + remote-endpoint = + <&funnel_modem_in_tpda_modem>; + }; + }; + + port@1 { + reg = <0>; + tpda_modem_in_tpdm_modem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_modem_out_tpda_modem>; + }; + }; + }; + }; + + tpdm_modem: tpdm@6830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6830000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-modem"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_modem_out_tpda_modem: endpoint { + remote-endpoint = <&tpda_modem_in_tpdm_modem>; + }; + }; + }; + + modem_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-modem-etm0"; + qcom,inst-id = <2>; + + port { + modem_etm0_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_modem_etm0>; + }; + }; + }; + + dummy_eud: dummy_sink { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-eud"; + + qcom,dummy-sink; + port { + eud_in_replicator_swao: endpoint { + slave-mode; + remote-endpoint = + <&replicator_swao_out_eud>; + }; + }; + }; + + replicator_swao: replicator@6b0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x6b0a000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-swao"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* Always have EUD before funnel leading to ETR. If both + * sink are active we need to give preference to EUD + * over ETR + */ + port@0 { + reg = <1>; + replicator_swao_out_eud: endpoint { + remote-endpoint = + <&eud_in_replicator_swao>; + }; + }; + + port@1 { + reg = <0>; + replicator_swao_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_replicator_swao>; + }; + }; + + port@2 { + reg = <0>; + replicator_swao_in_tmc_etf_swao: endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_swao_out_replicator_swao>; + }; + }; + + }; + }; + + tmc_etf_swao: tmc@6b09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6b09000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf-swao"; + coresight-csr = <&csr>; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tmc_etf_swao_out_replicator_swao: endpoint { + remote-endpoint= + <&replicator_swao_in_tmc_etf_swao>; + }; + }; + + port@1 { + reg = <0>; + tmc_etf_swao_in_funnel_swao: endpoint { + slave-mode; + remote-endpoint= + <&funnel_swao_out_tmc_etf_swao>; + }; + }; + }; + + }; + + swao_csr: csr@6b0e000 { + compatible = "qcom,coresight-csr"; + reg = <0x6b0e000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-swao-csr"; + qcom,timestamp-support; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,blk-size = <1>; + }; + + funnel_swao: funnel@6b08000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6b08000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-swao"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_swao_out_tmc_etf_swao: endpoint { + remote-endpoint = + <&tmc_etf_swao_in_funnel_swao>; + }; + }; + + port@1 { + reg = <6>; + funnel_swao_in_replicator1_out: endpoint { + slave-mode; + remote-endpoint= + <&replicator1_out_funnel_swao>; + }; + }; + + port@2 { + reg = <7>; + funnel_swao_in_tpda_swao: endpoint { + slave-mode; + remote-endpoint= + <&tpda_swao_out_funnel_swao>; + }; + }; + }; + }; + + tpda_swao: tpda@6b01000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6b01000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-swao"; + + qcom,tpda-atid = <71>; + qcom,dsb-elem-size = <1 32>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tpda_swao_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_tpda_swao>; + }; + + }; + + port@1 { + reg = <0>; + tpda_swao_in_tpdm_swao0: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_swao0_out_tpda_swao>; + }; + }; + + port@2 { + reg = <1>; + tpda_swao_in_tpdm_swao1: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_swao1_out_tpda_swao>; + }; + + }; + }; + }; + + tpdm_swao0: tpdm@6b02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + + reg = <0x6b02000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-swao-0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_swao0_out_tpda_swao: endpoint { + remote-endpoint = <&tpda_swao_in_tpdm_swao0>; + }; + }; + }; + + tpdm_swao1: tpdm@6b03000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6b03000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name="coresight-tpdm-swao-1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_swao1_out_tpda_swao: endpoint { + remote-endpoint = <&tpda_swao_in_tpdm_swao1>; + }; + }; + }; + + funnel_in2: funnel@6043000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6043000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in2_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in2>; + }; + }; + + port@1 { + reg = <2>; + funnel_in2_in_funnel_apss_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_merg_out_funnel_in2>; + }; + }; + }; + }; + + funnel_apss_merg: funnel@7810000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x7810000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss-merg"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss_merg_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_funnel_apss_merg>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss_merg_in_funnel_apss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_out_funnel_apss_merg>; + }; + }; + + port@2 { + reg = <2>; + funnel_apss_merg_in_tpda_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpda_olc_out_funnel_apss_merg>; + }; + }; + + port@3 { + reg = <3>; + funnel_apss_merg_in_tpda_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_silver_out_funnel_apss_merg>; + }; + }; + + port@4 { + reg = <4>; + funnel_apss_merg_in_tpda_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_gold_out_funnel_apss_merg>; + }; + }; + + port@5 { + reg = <5>; + funnel_apss_merg_in_tpda_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_apss_out_funnel_apss_merg>; + }; + }; + }; + }; + + tpda_olc: tpda@7832000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x7832000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-olc"; + + qcom,tpda-atid = <69>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_olc_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_olc>; + }; + }; + port@1 { + reg = <0>; + tpda_olc_in_tpdm_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_olc_out_tpda_olc>; + }; + }; + }; + }; + + tpdm_olc: tpdm@7830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x7830000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-olc"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port{ + tpdm_olc_out_tpda_olc: endpoint { + remote-endpoint = <&tpda_olc_in_tpdm_olc>; + }; + }; + }; + + tpda_apss: tpda@7862000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x7862000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-apss"; + + qcom,tpda-atid = <66>; + qcom,dsb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_apss_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_apss>; + }; + }; + + port@1 { + reg = <0>; + tpda_apss_in_tpdm_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_apss_out_tpda_apss>; + }; + }; + }; + }; + + tpdm_apss: tpdm@7860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x7860000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-apss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_apss_out_tpda_apss: endpoint { + remote-endpoint = <&tpda_apss_in_tpdm_apss>; + }; + }; + }; + + tpda_llm_silver: tpda@78c0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x78c0000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-llm-silver"; + + qcom,tpda-atid = <72>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_llm_silver_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_llm_silver>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_silver_in_tpdm_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_silver_out_tpda_llm_silver>; + }; + }; + }; + }; + + tpdm_llm_silver: tpdm@78a0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x78a0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-llm-silver"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_llm_silver_out_tpda_llm_silver: endpoint { + remote-endpoint = + <&tpda_llm_silver_in_tpdm_llm_silver>; + }; + }; + }; + + tpda_llm_gold: tpda@78d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x78d0000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-llm-gold"; + + qcom,tpda-atid = <73>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_llm_gold_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_llm_gold>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_gold_in_tpdm_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_gold_out_tpda_llm_gold>; + }; + }; + }; + }; + + tpdm_llm_gold: tpdm@78b0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x78b0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-llm-gold"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_llm_gold_out_tpda_llm_gold: endpoint { + remote-endpoint = + <&tpda_llm_gold_in_tpdm_llm_gold>; + }; + }; + }; + funnel_apss: funnel@7800000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x7800000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_funnel_apss>; + }; + }; + port@1 { + reg = <0>; + funnel_apss_in_etm0: endpoint { + slave-mode; + remote-endpoint = + <&etm0_out_funnel_apss>; + }; + }; + + port@2 { + reg = <1>; + funnel_apss_in_etm1: endpoint { + slave-mode; + remote-endpoint = + <&etm1_out_funnel_apss>; + }; + }; + + port@3 { + reg = <2>; + funnel_apss_in_etm2: endpoint { + slave-mode; + remote-endpoint = + <&etm2_out_funnel_apss>; + }; + }; + + port@4 { + reg = <3>; + funnel_apss_in_etm3: endpoint { + slave-mode; + remote-endpoint = + <&etm3_out_funnel_apss>; + }; + }; + + port@5 { + reg = <4>; + funnel_apss_in_etm4: endpoint { + slave-mode; + remote-endpoint = + <&etm4_out_funnel_apss>; + }; + }; + + port@6 { + reg = <5>; + funnel_apss_in_etm5: endpoint { + slave-mode; + remote-endpoint = + <&etm5_out_funnel_apss>; + }; + }; + + port@7 { + reg = <6>; + funnel_apss_in_etm6: endpoint { + slave-mode; + remote-endpoint = + <&etm6_out_funnel_apss>; + }; + }; + + port@8 { + reg = <7>; + funnel_apss_in_etm7: endpoint { + slave-mode; + remote-endpoint = + <&etm7_out_funnel_apss>; + }; + }; + }; + }; + + etm0: etm@7040000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7040000 0x1000>; + cpu = <&CPU0>; + + coresight-name = "coresight-etm0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm0_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm0>; + }; + }; + }; + + etm1: etm@7140000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7140000 0x1000>; + cpu = <&CPU1>; + + coresight-name = "coresight-etm1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm1_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm1>; + }; + }; + }; + + etm2: etm@7240000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7240000 0x1000>; + cpu = <&CPU2>; + + coresight-name = "coresight-etm2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm2_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm2>; + }; + }; + }; + + etm3: etm@7340000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7340000 0x1000>; + cpu = <&CPU3>; + + coresight-name = "coresight-etm3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm3_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm3>; + }; + }; + }; + + etm4: etm@7440000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7440000 0x1000>; + cpu = <&CPU4>; + + coresight-name = "coresight-etm4"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm4_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm4>; + }; + }; + }; + + etm5: etm@7540000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7540000 0x1000>; + cpu = <&CPU5>; + + coresight-name = "coresight-etm5"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm5_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm5>; + }; + }; + }; + + etm6: etm@7640000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7640000 0x1000>; + cpu = <&CPU6>; + + coresight-name = "coresight-etm6"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm6_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm6>; + }; + }; + }; + + etm7: etm@7740000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7740000 0x1000>; + cpu = <&CPU7>; + + coresight-name = "coresight-etm7"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm7_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm7>; + }; + }; + }; + + stm: stm@6002000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b962>; + + reg = <0x6002000 0x1000>, + <0x16280000 0x180000>; + reg-names = "stm-base", "stm-stimulus-base"; + + coresight-name = "coresight-stm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + stm_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_stm>; + }; + }; + + }; + + funnel_qatb: funnel@6005000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6005000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-qatb"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_qatb_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_qatb>; + }; + }; + + port@1 { + reg = <0>; + funnel_qatb_in_tpda: endpoint { + slave-mode; + remote-endpoint = + <&tpda_out_funnel_qatb>; + }; + }; + + port@2 { + reg = <3>; + funnel_qatb_in_funnel_dl_south_1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_south_1_out_funnel_qatb>; + }; + }; + + port@3 { + reg = <5>; + funnel_qatb_in_funnel_turing_1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_1_out_funnel_qatb>; + }; + }; + }; + }; + + funnel_wcss: funnel@699e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x699e000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-wcss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_wcss_out_funnel_dl_south_1: endpoint { + remote-endpoint = + <&funnel_dl_south_1_in_funnel_wcss>; + }; + }; + + port@1 { + reg = <1>; + funnel_wcss_in_tpdm_wcss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_wcss_out_funnel_wcss>; + }; + }; + }; + }; + + funnel_dl_south_1: funnel_1@6b53000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6b58000 0x10>, + <0x6b53000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-south-1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_dl_south_1_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_funnel_dl_south_1>; + }; + }; + + port@1 { + reg = <2>; + funnel_dl_south_1_in_funnel_wcss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_wcss_out_funnel_dl_south_1>; + }; + }; + }; + }; + + tpdm_wcss: tpdm@699c000 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-tpdm-wcss"; + qcom,dummy-source; + + port { + tpdm_wcss_out_funnel_wcss: endpoint { + remote-endpoint = + <&funnel_wcss_in_tpdm_wcss>; + }; + }; + }; + + tpda: tpda@6004000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6004000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda"; + + qcom,tpda-atid = <65>; + qcom,bc-elem-size = <10 32>, + <13 32>; + qcom,tc-elem-size = <13 32>; + qcom,dsb-elem-size = <0 32>, + <2 32>, + <3 32>, + <5 32>, + <6 32>, + <10 32>, + <11 32>, + <13 32>; + qcom,cmb-elem-size = <3 64>, + <7 64>, + <13 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_tpda>; + }; + + }; + + port@1 { + reg = <1>; + tpda_in_funnel_dl_mm: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_mm_out_tpda>; + }; + }; + + port@2 { + reg = <2>; + tpda_in_tpdm_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dl_center_out_tpda>; + }; + }; + + + port@3 { + reg = <3>; + tpda_in_funnel_dl_south: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_south_out_tpda>; + }; + }; + + port@4 { + reg = <5>; + tpda_in_funnel_turing: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_out_tpda>; + }; + }; + + port@5 { + reg = <6>; + tpda_in_funnel_ddr_0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_ddr_0_out_tpda>; + }; + }; + + port@6 { + reg = <7>; + tpda_in_funnel_gfx: endpoint { + slave-mode; + remote-endpoint = + <&funnel_gfx_out_tpda>; + }; + }; + + port@7 { + reg = <8>; + tpda_in_tpdm_vsense: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_vsense_out_tpda>; + }; + }; + + port@8 { + reg = <9>; + tpda_in_tpdm_dcc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dcc_out_tpda>; + }; + }; + + port@9 { + reg = <10>; + tpda_in_tpdm_prng: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_prng_out_tpda>; + }; + }; + + port@10 { + reg = <11>; + tpda_in_tpdm_north: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_north_out_tpda>; + }; + }; + + port@11 { + reg = <12>; + tpda_in_tpdm_qm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_qm_out_tpda>; + }; + }; + + port@12 { + reg = <13>; + tpda_in_tpdm_pimem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_pimem_out_tpda>; + }; + }; + + port@13 { + reg = <15>; + tpda_in_tpdm_center: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_center_out_tpda>; + }; + }; + }; + }; + + funnel_dl_mm: funnel@69C3000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x69C3000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-mm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_dl_mm_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_dl_mm>; + }; + }; + + port@1 { + reg = <0>; + funnel_dl_mm_in_tpdm_dl_mm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dl_mm_out_funnel_dl_mm>; + }; + }; + }; + }; + + tpdm_dl_mm: tpdm@69c0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x69c0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dl-mm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_dl_mm_out_funnel_dl_mm: endpoint { + remote-endpoint = + <&funnel_dl_mm_in_tpdm_dl_mm>; + }; + }; + }; + + tpdm_dl_center: tpdm@6c28000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c28000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dl-center"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_dl_center_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_dl_center>; + }; + }; + }; + + funnel_dl_south: funnel@6b53000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x6b53000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-south"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_dl_south_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_dl_south>; + }; + }; + + port@1 { + reg = <0>; + funnel_dl_south_in_tpdm_dl_south: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dl_south_out_funnel_dl_south>; + }; + }; + }; + }; + + tpdm_dl_south: tpdm@6b52000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6b52000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dl-south"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_dl_south_out_funnel_dl_south: endpoint { + remote-endpoint = + <&funnel_dl_south_in_tpdm_dl_south>; + }; + }; + }; + + funnel_turing: funnel@6861000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6861000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_turing_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_turing>; + }; + }; + + port@1 { + reg = <0>; + funnel_turing_in_tpdm_turing: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_turing_out_funnel_turing>; + }; + }; + }; + }; + + funnel_turing1: funnel_1@6861000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6867010 0x10>, + <0x6861000 0x1000>; + reg-names = "funnel-base-dummy", "funnel-base-real"; + + coresight-name = "coresight-funnel-turing1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + qcom,duplicate-funnel; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_turing_1_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_funnel_turing_1>; + }; + }; + + port@1 { + reg = <1>; + funnel_turing_1_in_turing_etm0: endpoint { + slave-mode; + remote-endpoint = + <&turing_etm0_out_funnel_turing_1>; + }; + }; + }; + }; + + turing_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-turing-etm0"; + qcom,inst-id = <13>; + + port{ + turing_etm0_out_funnel_turing_1: endpoint { + remote-endpoint = + <&funnel_turing_1_in_turing_etm0>; + }; + }; + }; + + tpdm_turing: tpdm@6860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6860000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_turing_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_tpdm_turing>; + }; + }; + }; + + funnel_ddr_0: funnel@6a05000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6a05000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-ddr-0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_ddr_0_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_ddr_0>; + }; + }; + + port@1 { + reg = <0>; + funnel_ddr_0_in_tpdm_ddr: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_ddr_out_funnel_ddr_0>; + }; + }; + }; + }; + + tpdm_ddr: tpdm@6a00000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x06a00000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-ddr"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_ddr_out_funnel_ddr_0: endpoint { + remote-endpoint = <&funnel_ddr_0_in_tpdm_ddr>; + }; + }; + }; + + funnel_gfx: funnel@6943000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6943000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-gfx"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_gfx_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_gfx>; + }; + }; + + port@1 { + reg = <0>; + funnel_gfx_in_tpdm_gfx: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_gfx_out_funnel_gfx>; + }; + }; + }; + }; + + tpdm_gfx: tpdm@6940000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6940000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-gfx"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_gfx_out_funnel_gfx: endpoint { + remote-endpoint = <&funnel_gfx_in_tpdm_gfx>; + }; + }; + }; + + tpdm_vsense: tpdm@6840000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6840000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-vsense"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port{ + tpdm_vsense_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_vsense>; + }; + }; + }; + + tpdm_dcc: tpdm@6870000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6870000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dcc"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + + port { + tpdm_dcc_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_dcc>; + }; + }; + }; + + tpdm_prng: tpdm@684c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x684c000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-prng"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_prng_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_prng>; + }; + }; + }; + + tpdm_north: tpdm@6b48000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6b48000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-north"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_north_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_north>; + }; + }; + }; + + tpdm_qm: tpdm@69d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x69d0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-qm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_qm_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_qm>; + }; + }; + }; + + + tpdm_pimem: tpdm@6850000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6850000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-pimem"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_pimem_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_pimem>; + }; + }; + }; + + tpdm_center: tpdm@6c28000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c28000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-center"; + + qcom,msr-fix-req; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_center_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_center>; + }; + }; + }; + + hwevent: hwevent@0x014066f0 { + compatible = "qcom,coresight-hwevent"; + reg = <0x14066f0 0x4>, + <0x14166f0 0x4>, + <0x1406038 0x4>, + <0x1416038 0x4>; + reg-names = "ddr-ch0-cfg", "ddr-ch23-cfg", "ddr-ch0-ctrl", + "ddr-ch23-ctrl"; + + coresight-csr = <&csr>; + coresight-name = "coresight-hwevent"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_apss: cti@78e0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x78e0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_apss: cti@78f0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x78f0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_apss: cti@7900000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7900000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr0: cti@6a02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a02000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr0: cti@6a03000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a03000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr1: cti@6a10000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a10000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr1: cti@6a11000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a11000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_ddr1: cti@6a12000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a12000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_dlmm: cti@6c09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c09000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlmm_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlmm: cti@6c0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c0a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlmm_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_dlct: cti@6c29000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c29000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlct: cti@6c2a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c2a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_wcss: cti@69a4000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x69a4000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-wcss_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_wcss: cti@69a5000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x69a5000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-wcss_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_wcss: cti@69a6000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x69a6000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-wcss_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_mss_q6: cti@683b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x683b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-mss-q6"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_turing: cti@6867000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6867000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_swao: cti@6b04000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b04000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_swao: cti@6b05000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b05000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_swao: cti@6b06000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b06000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti3_swao: cti@6b07000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b07000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_aop_m3: cti@6b21000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b21000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-aop-m3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_titan: cti@6c13000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c13000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-titan"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_venus_arm9: cti@6c20000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c20000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-venus-arm9"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0: cti@6010000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6010000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti1: cti@6011000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6011000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti2: cti@6012000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6012000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti3: cti@6013000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6013000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti4: cti@6014000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6014000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti4"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti5: cti@6015000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6015000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti5"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti6: cti@6016000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6016000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti6"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti7: cti@6017000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6017000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti7"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti8: cti@6018000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6018000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti8"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti9: cti@6019000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6019000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti9"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti10: cti@601a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti10"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti11: cti@601b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti11"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti12: cti@601c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti12"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti13: cti@601d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601d000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti13"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti14: cti@601e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601e000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti14"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti15: cti@601f000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601f000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti15"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + ipcb_tgu: tgu@6b0c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b999>; + reg = <0x06b0c000 0x1000>; + reg-names = "tgu-base"; + tgu-steps = <3>; + tgu-conditions = <4>; + tgu-regs = <4>; + tgu-timer-counters = <8>; + + coresight-name = "coresight-tgu-ipcb"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index c32968e70353..dd156d58b226 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -1050,6 +1050,15 @@ #thermal-sensor-cells = <1>; }; + dcc: dcc_v2@10a2000 { + compatible = "qcom,dcc-v2"; + reg = <0x10a2000 0x1000>, + <0x10ae000 0x2000>; + reg-names = "dcc-base", "dcc-ram-base"; + + dcc-ram-offset = <0x6000>; + }; + qcom,llcc@9200000 { compatible = "qcom,llcc-core", "syscon", "simple-mfd"; reg = <0x9200000 0x450000>; @@ -1819,3 +1828,4 @@ #include "pm6150.dtsi" #include "pm6150l.dtsi" #include "sdmmagpie-regulator.dtsi" +#include "sdmmagpie-coresight.dtsi" -- GitLab From cc740810c7b4c723007e95585d74b12c3addaadb Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Thu, 23 Aug 2018 12:18:50 +0530 Subject: [PATCH 0951/1001] ARM: dts: Update available frequenices in energy costs for SM6150 Update new frequencies in energy costs for SM6150, which are used by schduler in task placement decisions. Change-Id: I9f9272370e1b3e0ce1f2ca34f87a5d0608b9a93d Signed-off-by: Lingutla Chandrasekhar --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 30 ++++++++++++++++++---------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 8775f9465808..81fa87c9d62c 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -384,6 +384,7 @@ CPU_COST_0: core-cost0 { busy-cost-data = < + 300000 24 576000 25 748800 31 1017600 54 @@ -391,6 +392,7 @@ 1363200 105 1516800 116 1593600 139 + 1708800 168 1804800 178 >; idle-cost-data = < @@ -400,6 +402,7 @@ CPU_COST_1: core-cost1 { busy-cost-data = < + 300000 180 652800 236 768000 273 979200 446 @@ -409,6 +412,7 @@ 1516800 989 1708800 1276 1900800 1652 + 2016000 2040 2112000 2242 2208000 2713 >; @@ -419,6 +423,7 @@ CLUSTER_COST_0: cluster-cost0 { busy-cost-data = < + 300000 8 576000 8 748800 9 1017600 12 @@ -426,6 +431,7 @@ 1363200 18 1516800 21 1593600 22 + 1708800 23 1804800 24 >; idle-cost-data = < @@ -435,17 +441,19 @@ CLUSTER_COST_1: cluster-cost1 { busy-cost-data = < - 652800 26 - 768000 27 - 979200 36 - 1017600 45 - 1209600 55 - 1363200 64 - 1516800 66 - 1708800 72 - 1900800 77 - 2112000 84 - 2208000 90 + 300000 28 + 652800 35 + 768000 36 + 979200 48 + 1017600 59 + 1209600 73 + 1363200 86 + 1516800 88 + 1708800 96 + 1900800 103 + 2016000 107 + 2112000 112 + 2208000 120 >; idle-cost-data = < 4 3 2 1 -- GitLab From 605d813c8d3ecb6720c75df99d2af925117e4248 Mon Sep 17 00:00:00 2001 From: Vamsi Krishna Samavedam Date: Mon, 20 Aug 2018 16:54:46 -0700 Subject: [PATCH 0952/1001] usb: phy: qmp: Reset phy mode to USB on disconnect USB qmp phy driver initializes phy mode to be combo (USB and DP) so that both USB and DP (display port) can share the phy. This adds additional refgen vote from qmp phy dp instance. Reset the phy mode to USB only to avoid any additional refgen voting on physical cable disconnect or DP 4 lane usecase. In case of DP 4 lane usecase, DP driver will explicitly update the phy mode to DP only. Change-Id: Ia6c4c11d8de8b111c2330d4ec7a0b3607d2b6f77 Signed-off-by: Vamsi Krishna Samavedam --- drivers/usb/phy/phy-msm-ssusb-qmp.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c index 4909c6b52d6e..1f481c2b4001 100644 --- a/drivers/usb/phy/phy-msm-ssusb-qmp.c +++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c @@ -79,6 +79,7 @@ enum core_ldo_levels { /* USB3_DP_COM_PHY_MODE_CTRL bits */ #define USB3_MODE BIT(0) /* enables USB3 mode */ #define DP_MODE BIT(1) /* enables DP mode */ +#define USB3_DP_COMBO_MODE (USB3_MODE | DP_MODE) /*enables combo mode */ /* USB3 Gen2 link training indicator */ #define RX_EQUALIZATION_IN_PROGRESS BIT(3) @@ -344,6 +345,18 @@ static int configure_phy_regs(struct usb_phy *uphy, return 0; } +static void msm_ssphy_qmp_setmode(struct msm_ssphy_qmp *phy, u32 mode) +{ + mode = mode & USB3_DP_COMBO_MODE; + + writel_relaxed(mode, + phy->base + phy->phy_reg[USB3_DP_COM_PHY_MODE_CTRL]); + + /* flush the write by reading it */ + readl_relaxed(phy->base + phy->phy_reg[USB3_DP_COM_PHY_MODE_CTRL]); +} + + static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy) { int val; @@ -373,8 +386,7 @@ static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy) phy->phy_reg[USB3_DP_COM_TYPEC_CTRL]); } - writel_relaxed(USB3_MODE | DP_MODE, - phy->base + phy->phy_reg[USB3_DP_COM_PHY_MODE_CTRL]); + msm_ssphy_qmp_setmode(phy, USB3_DP_COMBO_MODE); /* bring both QMP USB and QMP DP PHYs PCS block out of reset */ writel_relaxed(0x00, @@ -636,11 +648,14 @@ static int msm_ssphy_qmp_set_suspend(struct usb_phy *uphy, int suspend) } if (suspend) { - if (phy->cable_connected) + if (phy->cable_connected) { msm_ssusb_qmp_enable_autonomous(phy, 1); - else + } else { + if (uphy->type == USB_PHY_TYPE_USB3_AND_DP) + msm_ssphy_qmp_setmode(phy, USB3_MODE); writel_relaxed(0x00, phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]); + } /* Make sure above write completed with PHY */ wmb(); -- GitLab From eb1041ba088bad2e45badcba4c69e10283d00a35 Mon Sep 17 00:00:00 2001 From: Hardik Kantilal Patel Date: Tue, 21 Aug 2018 14:40:19 +0530 Subject: [PATCH 0953/1001] icnss: Clear ICNSS_MSA0_ASSIGNED flag in cap failure case During capability qmi message failure ICNSS_MSA0_ASSIGNED flag is not getting clear. Due to this after PDR/SSR next time it is not configuring the MSA0 permission to q6 which result into NOC error as q6 is not having access permission. To address above issue clear ICNSS_MSA0_ASSIGNED bit in failure case. CRs-Fixed: 2300877 Change-Id: I6aeaedb5a394b843c4f1c8ef1e0be47a6947b331 Signed-off-by: Hardik Kantilal Patel --- drivers/soc/qcom/icnss.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 4749ffe6c9ce..5c354fdb0df1 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -800,6 +800,7 @@ static int icnss_driver_event_server_arrive(void *data) err_setup_msa: icnss_assign_msa_perm_all(penv, ICNSS_MSA_PERM_HLOS_ALL); + clear_bit(ICNSS_MSA0_ASSIGNED, &penv->state); err_power_on: icnss_hw_power_off(penv); clear_server: -- GitLab From 9af759b770753ab482588642bae085ccff6a2e03 Mon Sep 17 00:00:00 2001 From: Amar Singhal Date: Fri, 20 Jul 2018 12:15:18 -0700 Subject: [PATCH 0954/1001] cfg80211: never ignore user regulatory hint Currently user regulatory hint is ignored if all wiphys in the system are self managed. But the hint is not ignored if there is no wiphy in the system. This affects the global regulatory setting. Global regulatory setting needs to be maintained so that it can be applied to a new wiphy entering the system. Therefore, do not ignore user regulatory setting even if all wiphys in the system are self managed. Signed-off-by: Amar Singhal Signed-off-by: Johannes Berg Change-Id: I468fcd3403259b03369e011fa41b003e8ff33d3c CRs-Fixed: 2276224 Git-commit: e31f6456c01c76f154e1b25cd54df97809a49edb Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git Signed-off-by: Amar Singhal --- net/wireless/reg.c | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index bbd39109aad6..480ceb868663 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1691,7 +1691,9 @@ static void wiphy_update_regulatory(struct wiphy *wiphy, * as some drivers used this to restore its orig_* reg domain. */ if (initiator == NL80211_REGDOM_SET_BY_CORE && - wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) + wiphy->regulatory_flags & REGULATORY_CUSTOM_REG && + !(wiphy->regulatory_flags & + REGULATORY_WIPHY_SELF_MANAGED)) reg_call_notifier(wiphy, lr); return; } @@ -2243,26 +2245,6 @@ static void notify_self_managed_wiphys(struct regulatory_request *request) } } -static bool reg_only_self_managed_wiphys(void) -{ - struct cfg80211_registered_device *rdev; - struct wiphy *wiphy; - bool self_managed_found = false; - - ASSERT_RTNL(); - - list_for_each_entry(rdev, &cfg80211_rdev_list, list) { - wiphy = &rdev->wiphy; - if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) - self_managed_found = true; - else - return false; - } - - /* make sure at least one self-managed wiphy exists */ - return self_managed_found; -} - /* * Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_* * Regulatory hints come on a first come first serve basis and we @@ -2295,10 +2277,6 @@ static void reg_process_pending_hints(void) spin_unlock(®_requests_lock); notify_self_managed_wiphys(reg_request); - if (reg_only_self_managed_wiphys()) { - reg_free_request(reg_request); - return; - } reg_process_hint(reg_request); -- GitLab From aaf190857b418bbae35a275106cfe1939e89800e Mon Sep 17 00:00:00 2001 From: Laxminath Kasam Date: Thu, 23 Aug 2018 23:03:38 +0530 Subject: [PATCH 0955/1001] ARM: dts: msm: Update audio routing and dmic sample rate for sm6150 Fix dmic sample rate to 2.4MHz as per mems mic spec. Update audio routing to use sidetone and loopback paths on bolero. Change-Id: I68e124e17469eea2cc8b09abf2d9e9a6d259c6ef Signed-off-by: Laxminath Kasam --- arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi index 874ad3cee11f..0ffcb7c42ece 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi @@ -32,7 +32,7 @@ clocks = <&clock_audio_tx_1 0>, <&clock_audio_tx_2 0>; qcom,tx-swr-gpios = <&tx_swr_gpios>; - qcom,tx-dmic-sample-rate = <4800000>; + qcom,tx-dmic-sample-rate = <2400000>; swr_2: tx_swr_master { compatible = "qcom,swr-mstr"; #address-cells = <2>; @@ -136,6 +136,9 @@ "IN3_AUX", "AUX_OUT", "TX SWR_ADC0", "ADC1_OUTPUT", "TX SWR_ADC2", "ADC2_OUTPUT", + "WSA SRC0_INP", "SRC0", + "WSA_TX DEC0_INP", "TX DEC0 MUX", + "WSA_TX DEC1_INP", "TX DEC1 MUX", "RX_TX DEC0_INP", "TX DEC0 MUX", "RX_TX DEC1_INP", "TX DEC1 MUX", "RX_TX DEC2_INP", "TX DEC2 MUX", -- GitLab From 03855bea639043ce50941e1fd57a934f05050b57 Mon Sep 17 00:00:00 2001 From: Sudarshan Rajagopalan Date: Thu, 16 Aug 2018 14:25:10 -0700 Subject: [PATCH 0956/1001] iommu: arm-smmu: Add more logging during tlb sync timeout TLB sync timeouts are critical issues. To debug such error cases, we would need more info such as cb indx, sid, device name to identify which TBU the local tlb inv request was done. Currently, we are blacked-out on who the originator/requestor is. Change-Id: I64533fd5eed446187ff0a6e070118c0a19cd6ac2 Signed-off-by: Sudarshan Rajagopalan --- drivers/iommu/arm-smmu.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index e8f09add1c35..261536dce3b5 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -976,7 +976,7 @@ static void arm_smmu_domain_power_off(struct iommu_domain *domain, } /* Wait for any pending TLB invalidations to complete */ -static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu, +static int __arm_smmu_tlb_sync(struct arm_smmu_device *smmu, void __iomem *sync, void __iomem *status) { unsigned int spin_cnt, delay; @@ -985,7 +985,7 @@ static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu, for (delay = 1; delay < TLB_LOOP_TIMEOUT; delay *= 2) { for (spin_cnt = TLB_SPIN_COUNT; spin_cnt > 0; spin_cnt--) { if (!(readl_relaxed(status) & sTLBGSTATUS_GSACTIVE)) - return; + return 0; cpu_relax(); } udelay(delay); @@ -993,6 +993,7 @@ static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu, trace_tlbsync_timeout(smmu->dev, 0); dev_err_ratelimited(smmu->dev, "TLB sync timed out -- SMMU may be deadlocked\n"); + return -EINVAL; } static void arm_smmu_tlb_sync_global(struct arm_smmu_device *smmu) @@ -1001,8 +1002,10 @@ static void arm_smmu_tlb_sync_global(struct arm_smmu_device *smmu) unsigned long flags; spin_lock_irqsave(&smmu->global_sync_lock, flags); - __arm_smmu_tlb_sync(smmu, base + ARM_SMMU_GR0_sTLBGSYNC, - base + ARM_SMMU_GR0_sTLBGSTATUS); + if (__arm_smmu_tlb_sync(smmu, base + ARM_SMMU_GR0_sTLBGSYNC, + base + ARM_SMMU_GR0_sTLBGSTATUS)) + dev_err_ratelimited(smmu->dev, + "TLB global sync failed!\n"); spin_unlock_irqrestore(&smmu->global_sync_lock, flags); } @@ -1014,8 +1017,12 @@ static void arm_smmu_tlb_sync_context(void *cookie) unsigned long flags; spin_lock_irqsave(&smmu_domain->sync_lock, flags); - __arm_smmu_tlb_sync(smmu, base + ARM_SMMU_CB_TLBSYNC, - base + ARM_SMMU_CB_TLBSTATUS); + if (__arm_smmu_tlb_sync(smmu, base + ARM_SMMU_CB_TLBSYNC, + base + ARM_SMMU_CB_TLBSTATUS)) + dev_err_ratelimited(smmu->dev, + "TLB sync on cb%d failed for device %s\n", + smmu_domain->cfg.cbndx, + dev_name(smmu_domain->dev)); spin_unlock_irqrestore(&smmu_domain->sync_lock, flags); } -- GitLab From e9df2fe75529d0b5f0028a8092eef2d9186552d7 Mon Sep 17 00:00:00 2001 From: Amit Shekhar Date: Thu, 23 Aug 2018 16:17:12 -0700 Subject: [PATCH 0957/1001] msm: vidc: Fix minimum supported resolution for HW HEIC encode Input frame having width or height less than 512 is not supported by HW HEIC encoder. Change-Id: I8f504985452ce9661513a73a326d7da2d7192cba Signed-off-by: Amit Shekhar --- drivers/media/platform/msm/vidc/msm_vidc_common.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index eeb0f8f3cda6..5672eabd4555 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -2402,10 +2402,10 @@ bool heic_encode_session_supported(struct msm_vidc_inst *inst) n_bframes == 0 && n_pframes == 0) { if (inst->grid_enable > 0) { - if (!(inst->prop.height[CAPTURE_PORT] == - inst->prop.width[CAPTURE_PORT] && - inst->prop.width[CAPTURE_PORT] == - HEIC_GRID_DIMENSION)) + if (inst->prop.width[CAPTURE_PORT] < + HEIC_GRID_DIMENSION || + inst->prop.height[CAPTURE_PORT] < + HEIC_GRID_DIMENSION) return false; } return true; -- GitLab From cac972c209bce3fd8566663196e139bc36b439c0 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Wed, 1 Aug 2018 19:18:04 -0600 Subject: [PATCH 0958/1001] net: trace event change Change netif_receive_skb_core entry trace to more verbose version Change-Id: If0dfc940d34e7c9e3f1dea441aef3aafeab4dd9b Acked-by: Raul Martinez Signed-off-by: Subash Abhinov Kasiviswanathan --- include/trace/events/net.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/trace/events/net.h b/include/trace/events/net.h index f1a300c8ef85..135141e93a6e 100644 --- a/include/trace/events/net.h +++ b/include/trace/events/net.h @@ -124,13 +124,6 @@ DEFINE_EVENT(net_dev_template, net_dev_queue, TP_ARGS(skb) ); -DEFINE_EVENT(net_dev_template, netif_receive_skb, - - TP_PROTO(struct sk_buff *skb), - - TP_ARGS(skb) -); - DEFINE_EVENT(net_dev_template, netif_rx, TP_PROTO(struct sk_buff *skb), @@ -216,6 +209,13 @@ DEFINE_EVENT(net_dev_rx_verbose_template, napi_gro_receive_entry, TP_ARGS(skb) ); +DEFINE_EVENT(net_dev_rx_verbose_template, netif_receive_skb, + + TP_PROTO(const struct sk_buff *skb), + + TP_ARGS(skb) +); + DEFINE_EVENT(net_dev_rx_verbose_template, netif_receive_skb_entry, TP_PROTO(const struct sk_buff *skb), -- GitLab From d19990ce8746ced98aca0a3f57d2bb6c44a6eb54 Mon Sep 17 00:00:00 2001 From: Kiran Gunda Date: Thu, 16 Aug 2018 14:40:15 +0530 Subject: [PATCH 0959/1001] ARM: dts: msm: add gpio_key device for VOL_UP button on SM6150 IDP and QRD Add pinctrl configurations for volume up button which utilize PM6150L GPIO 2. Add gpio_key devices for this button on SM6150 IDP and QRD targets. Change-Id: I59edde7b6d753385ae32caa5c034bd21842372fa Signed-off-by: Kiran Gunda --- arch/arm64/boot/dts/qcom/sm6150-idp.dtsi | 31 ++++++++++++++++++++++++ arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi | 31 ++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi index fb1f17c47338..1bb32e90e620 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi @@ -12,7 +12,9 @@ #include "sm6150-thermal-overlay.dtsi" #include "sm6150-camera-sensor-idp.dtsi" +#include #include +#include #include "sm6150-sde-display.dtsi" &qupv3_se3_i2c { @@ -21,7 +23,36 @@ #include "smb1355.dtsi" }; +&pm6150l_gpios { + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio2"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; +}; + &soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm6150l_gpios 2 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + linux,can-disable; + debounce-interval = <15>; + gpio-key,wakeup; + }; + }; }; &qupv3_se0_2uart { diff --git a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi index 321708df7e12..827edb0665dc 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi @@ -11,7 +11,9 @@ */ #include "sm6150-thermal-overlay.dtsi" +#include #include +#include #include "sm6150-sde-display.dtsi" &qupv3_se3_i2c { @@ -20,7 +22,36 @@ #include "smb1355.dtsi" }; +&pm6150l_gpios { + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio2"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; +}; + &soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm6150l_gpios 2 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + linux,can-disable; + debounce-interval = <15>; + gpio-key,wakeup; + }; + }; }; &qupv3_se7_4uart { -- GitLab From 6b626a2a5fe549903e745a7d22feb9a81483e3fb Mon Sep 17 00:00:00 2001 From: Shaoqing Liu Date: Fri, 17 Aug 2018 17:21:23 +0800 Subject: [PATCH 0960/1001] soc: qcom: Add ODL support for qdss bridge driver Add ODL(On Device Logging) mode that it can read messages from the mhi bus channel to user space via a device node in qdss bridge driver. Change-Id: I9d8f420ba8047adb4f27a284c6388faf899eada2 Signed-off-by: Shaoqing Liu --- drivers/soc/qcom/qdss_bridge.c | 482 +++++++++++++++++++++++++++++++-- drivers/soc/qcom/qdss_bridge.h | 22 +- 2 files changed, 474 insertions(+), 30 deletions(-) diff --git a/drivers/soc/qcom/qdss_bridge.c b/drivers/soc/qcom/qdss_bridge.c index 79921d2259d3..bb67e8296ed4 100644 --- a/drivers/soc/qcom/qdss_bridge.c +++ b/drivers/soc/qcom/qdss_bridge.c @@ -15,6 +15,8 @@ #include #include +#include +#include #include #include #include @@ -39,6 +41,28 @@ module_param(poolsize, int, 0644); static int itemsize = QDSS_BUF_SIZE; module_param(itemsize, int, 0644); +static struct class *mhi_class; + +static const char * const str_mhi_transfer_mode[] = { + [MHI_TRANSFER_TYPE_USB] = "usb", + [MHI_TRANSFER_TYPE_UCI] = "uci", +}; + +static int qdss_destroy_mhi_buf_tbl(struct qdss_bridge_drvdata *drvdata) +{ + struct list_head *start, *temp; + struct qdss_mhi_buf_tbl_t *entry = NULL; + + list_for_each_safe(start, temp, &drvdata->mhi_buf_tbl) { + entry = list_entry(start, struct qdss_mhi_buf_tbl_t, link); + list_del(&entry->link); + kfree(entry->buf); + kfree(entry); + } + + return 0; +} + static int qdss_destroy_buf_tbl(struct qdss_bridge_drvdata *drvdata) { struct list_head *start, *temp; @@ -67,7 +91,7 @@ static int qdss_create_buf_tbl(struct qdss_bridge_drvdata *drvdata) if (!entry) goto err; - buf = kzalloc(QDSS_BUF_SIZE, GFP_KERNEL); + buf = kzalloc(drvdata->mtu, GFP_KERNEL); usb_req = kzalloc(sizeof(*usb_req), GFP_KERNEL); entry->buf = buf; @@ -129,11 +153,99 @@ static void qdss_buf_tbl_remove(struct qdss_bridge_drvdata *drvdata, static void mhi_ch_close(struct qdss_bridge_drvdata *drvdata) { - flush_workqueue(drvdata->mhi_wq); - qdss_destroy_buf_tbl(drvdata); - mhi_unprepare_from_transfer(drvdata->mhi_dev); + if (drvdata->mode == MHI_TRANSFER_TYPE_USB) { + flush_workqueue(drvdata->mhi_wq); + qdss_destroy_buf_tbl(drvdata); + } else if (drvdata->mode == MHI_TRANSFER_TYPE_UCI) { + qdss_destroy_mhi_buf_tbl(drvdata); + if (drvdata->cur_buf) + kfree(drvdata->cur_buf->buf); + + drvdata->cur_buf = NULL; + } +} + +static ssize_t mhi_show_transfer_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qdss_bridge_drvdata *drvdata = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%s\n", + str_mhi_transfer_mode[drvdata->mode]); +} + +static ssize_t mhi_store_transfer_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct qdss_bridge_drvdata *drvdata = dev_get_drvdata(dev); + char str[10] = ""; + int ret; + + if (strlen(buf) >= 10) + return -EINVAL; + if (sscanf(buf, "%3s", str) != 1) + return -EINVAL; + + spin_lock_bh(&drvdata->lock); + if (!strcmp(str, str_mhi_transfer_mode[MHI_TRANSFER_TYPE_UCI])) { + if (drvdata->mode == MHI_TRANSFER_TYPE_USB) { + if (drvdata->opened == ENABLE) { + drvdata->opened = DISABLE; + drvdata->mode = MHI_TRANSFER_TYPE_UCI; + spin_unlock_bh(&drvdata->lock); + usb_qdss_close(drvdata->usb_ch); + mhi_unprepare_from_transfer(drvdata->mhi_dev); + mhi_ch_close(drvdata); + } else if (drvdata->opened == DISABLE) { + drvdata->mode = MHI_TRANSFER_TYPE_UCI; + spin_unlock_bh(&drvdata->lock); + } else { + ret = -ERESTARTSYS; + goto out; + } + } else + spin_unlock_bh(&drvdata->lock); + + } else if (!strcmp(str, str_mhi_transfer_mode[MHI_TRANSFER_TYPE_USB])) { + if (drvdata->mode == MHI_TRANSFER_TYPE_UCI) { + if (drvdata->opened == ENABLE) { + drvdata->opened = DISABLE; + spin_unlock_bh(&drvdata->lock); + wake_up(&drvdata->uci_wq); + mhi_unprepare_from_transfer(drvdata->mhi_dev); + mhi_ch_close(drvdata); + drvdata->mode = MHI_TRANSFER_TYPE_USB; + queue_work(drvdata->mhi_wq, + &drvdata->open_work); + } else if (drvdata->opened == DISABLE) { + drvdata->mode = MHI_TRANSFER_TYPE_USB; + spin_unlock_bh(&drvdata->lock); + queue_work(drvdata->mhi_wq, + &drvdata->open_work); + } else { + ret = -ERESTARTSYS; + goto out; + } + } else + spin_unlock_bh(&drvdata->lock); + + } else { + ret = -EINVAL; + goto out; + } + + ret = size; + return ret; +out: + spin_unlock_bh(&drvdata->lock); + return ret; } +static DEVICE_ATTR(mode, 0644, + mhi_show_transfer_mode, mhi_store_transfer_mode); + + static void mhi_read_work_fn(struct work_struct *work) { int err = 0; @@ -146,14 +258,14 @@ static void mhi_read_work_fn(struct work_struct *work) read_work); do { - if (!drvdata->opened) + if (drvdata->opened != ENABLE) break; entry = qdss_get_entry(drvdata); if (!entry) break; err = mhi_queue_transfer(drvdata->mhi_dev, DMA_FROM_DEVICE, - entry->buf, QDSS_BUF_SIZE, mhi_flags); + entry->buf, drvdata->mtu, mhi_flags); if (err) { pr_err_ratelimited("Unable to read from MHI buffer err:%d", err); @@ -203,7 +315,7 @@ static void mhi_read_done_work_fn(struct work_struct *work) LIST_HEAD(head); do { - if (!(drvdata->opened)) + if (drvdata->opened != ENABLE) break; spin_lock_bh(&drvdata->lock); if (list_empty(&drvdata->read_done_list)) { @@ -227,7 +339,7 @@ static void mhi_read_done_work_fn(struct work_struct *work) * read, discard the buffers here and do not forward * them to the mux layer. */ - if (drvdata->opened) { + if (drvdata->opened == ENABLE) { err = usb_write(drvdata, buf, len); if (err) qdss_buf_tbl_remove(drvdata, buf); @@ -282,18 +394,26 @@ static int mhi_ch_open(struct qdss_bridge_drvdata *drvdata) { int ret; - if (drvdata->opened) + spin_lock_bh(&drvdata->lock); + if (drvdata->opened == ENABLE) return 0; + if (drvdata->opened == SSR) + return -ERESTARTSYS; + drvdata->opened = ENABLE; + spin_unlock_bh(&drvdata->lock); + ret = mhi_prepare_for_transfer(drvdata->mhi_dev); if (ret) { pr_err("Unable to open MHI channel\n"); - return ret; + goto err; } + return 0; +err: spin_lock_bh(&drvdata->lock); - drvdata->opened = 1; + drvdata->opened = DISABLE; spin_unlock_bh(&drvdata->lock); - return 0; + return ret; } static void qdss_bridge_open_work_fn(struct work_struct *work) @@ -320,6 +440,7 @@ static void qdss_bridge_open_work_fn(struct work_struct *work) return; err: + mhi_unprepare_from_transfer(drvdata->mhi_dev); mhi_ch_close(drvdata); err_open: pr_err("Open work failed with err:%d\n", ret); @@ -342,8 +463,10 @@ static void qdss_mhi_read_cb(struct mhi_device *mhi_dev, return; buf = result->buf_addr; - if (drvdata->opened && + spin_lock_bh(&drvdata->lock); + if (drvdata->opened == ENABLE && result->transaction_status != -ENOTCONN) { + spin_unlock_bh(&drvdata->lock); tp = kmalloc(sizeof(*tp), GFP_ATOMIC); if (!tp) return; @@ -352,12 +475,243 @@ static void qdss_mhi_read_cb(struct mhi_device *mhi_dev, spin_lock_bh(&drvdata->lock); list_add_tail(&tp->link, &drvdata->read_done_list); spin_unlock_bh(&drvdata->lock); - queue_work(drvdata->mhi_wq, &drvdata->read_done_work); + if (drvdata->mode == MHI_TRANSFER_TYPE_USB) + queue_work(drvdata->mhi_wq, &drvdata->read_done_work); + else + wake_up(&drvdata->uci_wq); } else { - qdss_buf_tbl_remove(drvdata, buf); + if (drvdata->mode == MHI_TRANSFER_TYPE_USB) { + spin_unlock_bh(&drvdata->lock); + qdss_buf_tbl_remove(drvdata, buf); + } else { + spin_unlock_bh(&drvdata->lock); + return; + } } + } +static int mhi_uci_release(struct inode *inode, struct file *file) +{ + struct qdss_bridge_drvdata *drvdata = file->private_data; + + spin_lock_bh(&drvdata->lock); + if (drvdata->mode == MHI_TRANSFER_TYPE_UCI) { + if (drvdata->opened == ENABLE) { + drvdata->opened = DISABLE; + spin_unlock_bh(&drvdata->lock); + wake_up(&drvdata->uci_wq); + mhi_unprepare_from_transfer(drvdata->mhi_dev); + mhi_ch_close(drvdata); + } else if (drvdata->opened == SSR) { + spin_unlock_bh(&drvdata->lock); + complete(&drvdata->completion); + } else + spin_unlock_bh(&drvdata->lock); + } else + spin_unlock_bh(&drvdata->lock); + + return 0; +} + +static ssize_t mhi_uci_read(struct file *file, + char __user *buf, + size_t count, + loff_t *ppos) +{ + struct qdss_bridge_drvdata *drvdata = file->private_data; + struct mhi_device *mhi_dev = drvdata->mhi_dev; + struct qdss_mhi_buf_tbl_t *uci_buf; + char *ptr; + size_t to_copy; + int ret = 0; + + if (!buf) + return -EINVAL; + + pr_debug("Client provided buf len:%lu\n", count); + + /* confirm channel is active */ + spin_lock_bh(&drvdata->lock); + if (drvdata->opened != ENABLE || + drvdata->mode != MHI_TRANSFER_TYPE_UCI) { + spin_unlock_bh(&drvdata->lock); + return -ERESTARTSYS; + } + + /* No data available to read, wait */ + if (!drvdata->cur_buf && list_empty(&drvdata->read_done_list)) { + spin_unlock_bh(&drvdata->lock); + + pr_debug("No data available to read waiting\n"); + ret = wait_event_interruptible(drvdata->uci_wq, + ((drvdata->opened != ENABLE + || !list_empty(&drvdata->read_done_list)))); + if (ret == -ERESTARTSYS) { + pr_debug("Exit signal caught for node\n"); + return -ERESTARTSYS; + } + + spin_lock_bh(&drvdata->lock); + if (drvdata->opened != ENABLE) { + spin_unlock_bh(&drvdata->lock); + pr_debug("node was disabled or SSR occurred.\n"); + ret = -ERESTARTSYS; + return ret; + } + } + + /* new read, get the next descriptor from the list */ + if (!drvdata->cur_buf) { + uci_buf = list_first_entry_or_null(&drvdata->read_done_list, + struct qdss_mhi_buf_tbl_t, link); + if (unlikely(!uci_buf)) { + ret = -EIO; + goto read_error; + } + + list_del(&uci_buf->link); + drvdata->cur_buf = uci_buf; + drvdata->rx_size = uci_buf->len; + pr_debug("Got pkt of size:%zu\n", drvdata->rx_size); + } + + uci_buf = drvdata->cur_buf; + spin_unlock_bh(&drvdata->lock); + + /* Copy the buffer to user space */ + to_copy = min_t(size_t, count, drvdata->rx_size); + ptr = uci_buf->buf + (uci_buf->len - drvdata->rx_size); + ret = copy_to_user(buf, ptr, to_copy); + if (ret) + return ret; + + pr_debug("Copied %lu of %lu bytes\n", to_copy, drvdata->rx_size); + drvdata->rx_size -= to_copy; + + /* we finished with this buffer, queue it back to hardware */ + if (!drvdata->rx_size) { + spin_lock_bh(&drvdata->lock); + drvdata->cur_buf = NULL; + + if (drvdata->opened == ENABLE) + ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, + uci_buf->buf, drvdata->mtu, + MHI_EOT); + else + ret = -ERESTARTSYS; + + if (ret) { + pr_err("Failed to recycle element, ret: %d\n", ret); + kfree(uci_buf->buf); + kfree(uci_buf); + uci_buf->buf = NULL; + uci_buf = NULL; + goto read_error; + } + + spin_unlock_bh(&drvdata->lock); + } + + pr_debug("Returning %lu bytes\n", to_copy); + return to_copy; + +read_error: + spin_unlock_bh(&drvdata->lock); + return ret; +} + +static int mhi_queue_inbound(struct qdss_bridge_drvdata *drvdata) +{ + struct mhi_device *mhi_dev = drvdata->mhi_dev; + int nr_trbs = mhi_get_no_free_descriptors(mhi_dev, DMA_FROM_DEVICE); + void *buf; + struct qdss_mhi_buf_tbl_t *entry; + int ret = -EIO, i; + + for (i = 0; i < nr_trbs; i++) { + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + goto err; + + buf = kzalloc(drvdata->mtu, GFP_KERNEL); + if (!buf) { + kfree(entry); + goto err; + } + + entry->buf = buf; + + ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, buf, + drvdata->mtu, + MHI_EOT); + if (ret) { + kfree(buf); + kfree(entry); + pr_err("Failed to queue buffer %d\n", i); + return ret; + } + list_add_tail(&entry->link, &drvdata->mhi_buf_tbl); + } + + return ret; +err: + return -ENOMEM; + +} + +static int mhi_uci_open(struct inode *inode, struct file *filp) +{ + int ret = -EIO; + struct qdss_mhi_buf_tbl_t *buf_itr, *tmp; + struct qdss_bridge_drvdata *drvdata = container_of(inode->i_cdev, + struct qdss_bridge_drvdata, + cdev); + + spin_lock_bh(&drvdata->lock); + if (drvdata->opened) { + pr_err("Node was opened or SSR occurred\n"); + spin_unlock_bh(&drvdata->lock); + return ret; + } + drvdata->opened = ENABLE; + spin_unlock_bh(&drvdata->lock); + + ret = mhi_prepare_for_transfer(drvdata->mhi_dev); + if (ret) { + pr_err("Error starting transfer channels\n"); + goto error_open_chan; + } + + ret = mhi_queue_inbound(drvdata); + if (ret) + goto error_rx_queue; + + filp->private_data = drvdata; + return ret; + +error_rx_queue: + mhi_unprepare_from_transfer(drvdata->mhi_dev); + list_for_each_entry_safe(buf_itr, tmp, &drvdata->read_done_list, link) { + list_del(&buf_itr->link); + kfree(buf_itr->buf); + } + +error_open_chan: + spin_lock_bh(&drvdata->lock); + drvdata->opened = DISABLE; + spin_unlock_bh(&drvdata->lock); + return ret; +} + + + +static const struct file_operations mhidev_fops = { + .open = mhi_uci_open, + .release = mhi_uci_release, + .read = mhi_uci_read, +}; + static void qdss_mhi_remove(struct mhi_device *mhi_dev) { struct qdss_bridge_drvdata *drvdata = NULL; @@ -367,14 +721,26 @@ static void qdss_mhi_remove(struct mhi_device *mhi_dev) drvdata = mhi_dev->priv_data; if (!drvdata) return; - if (!drvdata->opened) - return; spin_lock_bh(&drvdata->lock); - drvdata->opened = 0; - spin_unlock_bh(&drvdata->lock); - usb_qdss_close(drvdata->usb_ch); - flush_workqueue(drvdata->mhi_wq); - qdss_destroy_buf_tbl(drvdata); + if (drvdata->opened == ENABLE) { + drvdata->opened = SSR; + if (drvdata->mode == MHI_TRANSFER_TYPE_UCI) { + spin_unlock_bh(&drvdata->lock); + wake_up(&drvdata->uci_wq); + wait_for_completion(&drvdata->completion); + } else { + spin_unlock_bh(&drvdata->lock); + usb_qdss_close(drvdata->usb_ch); + } + mhi_ch_close(drvdata); + + } else + spin_unlock_bh(&drvdata->lock); + + device_remove_file(drvdata->dev, &dev_attr_mode); + device_destroy(mhi_class, drvdata->cdev.dev); + cdev_del(&drvdata->cdev); + unregister_chrdev_region(drvdata->cdev.dev, 1); } int qdss_mhi_init(struct qdss_bridge_drvdata *drvdata) @@ -388,8 +754,11 @@ int qdss_mhi_init(struct qdss_bridge_drvdata *drvdata) INIT_WORK(&(drvdata->read_done_work), mhi_read_done_work_fn); INIT_WORK(&(drvdata->open_work), qdss_bridge_open_work_fn); INIT_LIST_HEAD(&drvdata->buf_tbl); + INIT_LIST_HEAD(&drvdata->mhi_buf_tbl); + init_waitqueue_head(&drvdata->uci_wq); + init_completion(&drvdata->completion); INIT_LIST_HEAD(&drvdata->read_done_list); - drvdata->opened = 0; + drvdata->opened = DISABLE; return 0; } @@ -398,7 +767,10 @@ static int qdss_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id) { int ret; + unsigned int baseminor = 0; + unsigned int count = 1; struct qdss_bridge_drvdata *drvdata; + dev_t dev; drvdata = devm_kzalloc(&mhi_dev->dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) { @@ -406,21 +778,63 @@ static int qdss_mhi_probe(struct mhi_device *mhi_dev, return ret; } + ret = alloc_chrdev_region(&dev, baseminor, count, "mhi_qdss"); + if (ret < 0) { + pr_err("alloc_chrdev_region failed %d\n", ret); + return ret; + } + cdev_init(&drvdata->cdev, &mhidev_fops); + + drvdata->cdev.owner = THIS_MODULE; + drvdata->cdev.ops = &mhidev_fops; + + ret = cdev_add(&drvdata->cdev, dev, 1); + if (ret) + goto exit_unreg_chrdev_region; + + drvdata->dev = device_create(mhi_class, NULL, + drvdata->cdev.dev, drvdata, + "mhi_qdss"); + if (IS_ERR(drvdata->dev)) { + pr_err("class_device_create failed %d\n", ret); + ret = -ENOMEM; + goto exit_cdev_add; + } + + drvdata->mode = MHI_TRANSFER_TYPE_USB; + drvdata->mtu = min_t(size_t, id->driver_data, mhi_dev->mtu); drvdata->mhi_dev = mhi_dev; mhi_device_set_devdata(mhi_dev, drvdata); + dev_set_drvdata(drvdata->dev, drvdata); + + ret = device_create_file(drvdata->dev, &dev_attr_mode); + if (ret) { + pr_err("sysfs node create failed error:%d\n", ret); + goto exit_destroy_device; + } ret = qdss_mhi_init(drvdata); - if (ret) - goto err; + if (ret) { + pr_err("Device probe failed err:%d\n", ret); + goto remove_sysfs_exit; + } queue_work(drvdata->mhi_wq, &drvdata->open_work); return 0; -err: - pr_err("Device probe failed err:%d\n", ret); + +remove_sysfs_exit: + device_remove_file(drvdata->dev, &dev_attr_mode); +exit_destroy_device: + device_destroy(mhi_class, drvdata->cdev.dev); +exit_cdev_add: + cdev_del(&drvdata->cdev); +exit_unreg_chrdev_region: + unregister_chrdev_region(drvdata->cdev.dev, 1); return ret; + } static const struct mhi_device_id qdss_mhi_match_table[] = { - { .chan = "QDSS" }, + { .chan = "QDSS", .driver_data = 0x4000 }, {}, }; @@ -438,7 +852,17 @@ static struct mhi_driver qdss_mhi_driver = { static int __init qdss_bridge_init(void) { - return mhi_driver_register(&qdss_mhi_driver); + int ret; + + mhi_class = class_create(THIS_MODULE, MODULE_NAME); + if (IS_ERR(mhi_class)) + return -ENODEV; + + ret = mhi_driver_register(&qdss_mhi_driver); + if (ret) + class_destroy(mhi_class); + + return ret; } static void __exit qdss_bridge_exit(void) diff --git a/drivers/soc/qcom/qdss_bridge.h b/drivers/soc/qcom/qdss_bridge.h index 60c8b4c63cd2..f5e119b0ce84 100644 --- a/drivers/soc/qcom/qdss_bridge.h +++ b/drivers/soc/qcom/qdss_bridge.h @@ -26,10 +26,26 @@ struct qdss_mhi_buf_tbl_t { size_t len; }; +enum mhi_transfer_mode { + MHI_TRANSFER_TYPE_USB, + MHI_TRANSFER_TYPE_UCI, +}; + +enum open_status { + DISABLE, + ENABLE, + SSR, +}; + struct qdss_bridge_drvdata { int alias; - bool opened; + enum open_status opened; + struct completion completion; + size_t mtu; + enum mhi_transfer_mode mode; spinlock_t lock; + struct device *dev; + struct cdev cdev; struct mhi_device *mhi_dev; struct work_struct read_work; struct work_struct read_done_work; @@ -39,8 +55,12 @@ struct qdss_bridge_drvdata { struct mhi_client_handle *hdl; struct mhi_client_info_t *client_info; struct list_head buf_tbl; + struct list_head mhi_buf_tbl; struct list_head read_done_list; struct usb_qdss_ch *usb_ch; + struct qdss_mhi_buf_tbl_t *cur_buf; + wait_queue_head_t uci_wq; + size_t rx_size; }; #endif -- GitLab From f64ff42aba1dc702630cf523d0edccad45e53c0e Mon Sep 17 00:00:00 2001 From: Prateek Sood Date: Thu, 16 Aug 2018 15:18:20 +0530 Subject: [PATCH 0961/1001] ARM: dts: msm: Add EUD device node for sdmmagpie The EUD (Embedded USB Debugger) is a mini-USB hub implemented on chip to support the USB-based debug and trace capabilities. Add device tree node to support EUD on sdmmagpie based platforms. Change-Id: I6573b4064410ba9d0669976eaa8012116ce3ab04 Signed-off-by: Prateek Sood --- arch/arm64/boot/dts/qcom/sdmmagpie.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index 2d7e7e3c3806..1faf13868369 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -843,6 +843,15 @@ qcom,wakeup-enable; }; + eud: qcom,msm-eud@88e0000 { + compatible = "qcom,msm-eud"; + interrupt-names = "eud_irq"; + interrupts = ; + reg = <0x88e0000 0x2000>; + reg-names = "eud_base"; + status = "ok"; + }; + qcom,chd_sliver { compatible = "qcom,core-hang-detect"; label = "silver"; -- GitLab From 2ce5c327385ed1922481a4c7a6c3e37e06b5ca35 Mon Sep 17 00:00:00 2001 From: Prateek Sood Date: Thu, 16 Aug 2018 17:13:21 +0530 Subject: [PATCH 0962/1001] ARM: dts: msm: Add llcc cache dump support for sdmmagpie sdmmagpie supports two instance of Last level cache controller with 256KB system cache. Add dump size to allocate buffers for llcc cache dumps. Change-Id: I205d9b5e024845c23e2d1a1e296817ffca963252 Signed-off-by: Prateek Sood --- arch/arm64/boot/dts/qcom/sdmmagpie.dtsi | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index 1faf13868369..d71a99367b2e 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -1037,6 +1037,16 @@ qcom,dump-node = <&L2_TLB_700>; qcom,dump-id = <0x127>; }; + + qcom,llcc1_d_cache { + qcom,dump-node = <&LLCC_1>; + qcom,dump-id = <0x140>; + }; + + qcom,llcc2_d_cache { + qcom,dump-node = <&LLCC_2>; + qcom,dump-id = <0x141>; + }; }; thermal_zones: thermal-zones {}; @@ -1095,6 +1105,14 @@ qcom,llcc-amon { compatible = "qcom,llcc-amon"; }; + + LLCC_1: llcc_1_dcache { + qcom,dump-size = <0x6c000>; + }; + + LLCC_2: llcc_2_dcache { + qcom,dump-size = <0x6c000>; + }; }; apps_rsc: mailbox@18220000 { -- GitLab From 20265c7cad508eb14212c4cac8f9f079cebbd211 Mon Sep 17 00:00:00 2001 From: Prateek Sood Date: Thu, 16 Aug 2018 17:18:55 +0530 Subject: [PATCH 0963/1001] ARM: dts: msm: Add llcc perfmon device for sdmmagpie Adding llcc perfmon configuration. Perfmon driver can monitor llcc hardware events, which can be used for profiling. Change-Id: I28c44081dba058515e57a3fcce5fa63adc3c0617 Signed-off-by: Prateek Sood --- arch/arm64/boot/dts/qcom/sdmmagpie.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index d71a99367b2e..6998e80752db 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -1096,6 +1096,10 @@ cap-based-alloc-and-pwr-collapse; }; + qcom,llcc-perfmon { + compatible = "qcom,llcc-perfmon"; + }; + qcom,llcc-erp { compatible = "qcom,llcc-erp"; interrupt-names = "ecc_irq"; -- GitLab From 9db00f1f733803cc15ea0a1311f8a8f8d38d8d19 Mon Sep 17 00:00:00 2001 From: Prateek Sood Date: Thu, 16 Aug 2018 17:46:49 +0530 Subject: [PATCH 0964/1001] ARM: dts: msm: add DSU PMU support for sdmmagpie Add DT node to support the ARM DynamIQ Shared Unit (DSU) PMU. This allows the perf subsystem clients to record the events corresponding to the events related to L3 cache, snoop control protocol, using its 32-bit counters. Change-Id: If115f76a275ca1a5aab82b197d7e5baa644ea659 Signed-off-by: Prateek Sood --- arch/arm64/boot/dts/qcom/sdmmagpie.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index 6998e80752db..2c3c0b65b290 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -708,6 +708,13 @@ interrupts = ; }; + dsu_pmu@0 { + compatible = "arm,dsu-pmu"; + interrupts = ; + cpus = <&CPU0>, <&CPU1>, <&CPU2>, <&CPU3>, + <&CPU4>, <&CPU5>, <&CPU6>, <&CPU7>; + }; + qcom,msm-imem@146aa000 { compatible = "qcom,msm-imem"; reg = <0x146aa000 0x1000>; -- GitLab From 5be1c5db9f95a53d916fd34fcbaaad1451e6451c Mon Sep 17 00:00:00 2001 From: Prateek Sood Date: Thu, 16 Aug 2018 18:10:41 +0530 Subject: [PATCH 0965/1001] ARM: dts: msm: Fix the core numbering in sdmmagpie Fix the core numbering for cluster1 in sdmmagpie. Without this change topology parsing fails while parsing cluster1 cores. Change-Id: Iff41eed6f5826b3c0439eba09bfa03891f0370da Signed-off-by: Prateek Sood --- arch/arm64/boot/dts/qcom/sdmmagpie.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index 2c3c0b65b290..3573b2d99754 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -331,11 +331,11 @@ }; cluster1 { - core6 { + core0 { cpu = <&CPU6>; }; - core7 { + core1 { cpu = <&CPU7>; }; }; -- GitLab From 56053c212cb167eb9b911050e6faf5aa3dc8232d Mon Sep 17 00:00:00 2001 From: Prateek Sood Date: Fri, 24 Aug 2018 12:06:21 +0530 Subject: [PATCH 0966/1001] pinctrl: sdmmagpie: fix offset for pin groups. SDC and UFS_RESET pin groups are having wrong offsets. Fix it. Change-Id: I8bd1f28a4f7460eb1f69aabcd2bdfbcdaaffc5d5 Signed-off-by: Prateek Sood --- drivers/pinctrl/qcom/pinctrl-sdmmagpie.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-sdmmagpie.c b/drivers/pinctrl/qcom/pinctrl-sdmmagpie.c index 48e20ce254be..f6e6f8aa075f 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdmmagpie.c +++ b/drivers/pinctrl/qcom/pinctrl-sdmmagpie.c @@ -1440,14 +1440,14 @@ static const struct msm_pingroup sdmmagpie_groups[] = { [116] = PINGROUP(116, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), [117] = PINGROUP(117, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), [118] = PINGROUP(118, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), - [119] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x9a000, 15, 0), - [120] = SDC_QDSD_PINGROUP(sdc1_clk, 0x9a000, 13, 6), - [121] = SDC_QDSD_PINGROUP(sdc1_cmd, 0x9a000, 11, 3), - [122] = SDC_QDSD_PINGROUP(sdc1_data, 0x9a000, 9, 0), - [123] = SDC_QDSD_PINGROUP(sdc2_clk, 0x98000, 14, 6), - [124] = SDC_QDSD_PINGROUP(sdc2_cmd, 0x98000, 11, 3), - [125] = SDC_QDSD_PINGROUP(sdc2_data, 0x98000, 9, 0), - [126] = UFS_RESET(ufs_reset, 0x9f000), + [119] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x19a000, 15, 0), + [120] = SDC_QDSD_PINGROUP(sdc1_clk, 0x19a000, 13, 6), + [121] = SDC_QDSD_PINGROUP(sdc1_cmd, 0x19a000, 11, 3), + [122] = SDC_QDSD_PINGROUP(sdc1_data, 0x19a000, 9, 0), + [123] = SDC_QDSD_PINGROUP(sdc2_clk, 0x998000, 14, 6), + [124] = SDC_QDSD_PINGROUP(sdc2_cmd, 0x998000, 11, 3), + [125] = SDC_QDSD_PINGROUP(sdc2_data, 0x998000, 9, 0), + [126] = UFS_RESET(ufs_reset, 0x19f000), }; static struct msm_dir_conn sdmmagpie_dir_conn[] = { -- GitLab From fab1bdc07fa17c8d270b7cb9817acba256b1ce39 Mon Sep 17 00:00:00 2001 From: Srinivas Ramana Date: Fri, 24 Aug 2018 12:14:51 +0530 Subject: [PATCH 0967/1001] ARM: dts: msm: Fix compilation issue with camera nodes on sm6150 New overlay files added for sm6150 does not include camera headers and results in compilation issue. fix it. Change-Id: I3874f18fa7d37ab36390cde2f09b6fa53062cfc7 Signed-off-by: Srinivas Ramana Signed-off-by: Sridhar Gujje --- arch/arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts | 1 + arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts | 1 + arch/arm64/boot/dts/qcom/sm6150-rumi-overlay.dts | 1 + arch/arm64/boot/dts/qcom/sm6150-usbc-idp-overlay.dts | 1 + arch/arm64/boot/dts/qcom/sm6150p-idp-overlay.dts | 1 + arch/arm64/boot/dts/qcom/sm6150p-qrd-overlay.dts | 1 + 6 files changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts index de315d3ca9ce..345251a025ae 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-external-codec-idp-overlay.dts @@ -14,6 +14,7 @@ /plugin/; #include +#include #include "sm6150-idp.dtsi" #include "sm6150-ext-codec-audio-overlay.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts index 05e667d052e6..798260de1846 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts @@ -14,6 +14,7 @@ /plugin/; #include +#include #include "sm6150-audio-overlay.dtsi" #include "sm6150-qrd.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sm6150-rumi-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-rumi-overlay.dts index 47b69d465511..40685f9ae444 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-rumi-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-rumi-overlay.dts @@ -14,6 +14,7 @@ /plugin/; #include +#include #include "sm6150-rumi.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sm6150-usbc-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-usbc-idp-overlay.dts index e8325109410d..634d127d31ee 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-usbc-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-usbc-idp-overlay.dts @@ -14,6 +14,7 @@ /plugin/; #include +#include #include "sm6150-idp.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sm6150p-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150p-idp-overlay.dts index aebdcf06bbb5..a5423f1ef523 100644 --- a/arch/arm64/boot/dts/qcom/sm6150p-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150p-idp-overlay.dts @@ -14,6 +14,7 @@ /plugin/; #include +#include #include "sm6150-idp.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sm6150p-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150p-qrd-overlay.dts index e6286ee3ca58..b08051cdc0c1 100644 --- a/arch/arm64/boot/dts/qcom/sm6150p-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150p-qrd-overlay.dts @@ -14,6 +14,7 @@ /plugin/; #include +#include #include "sm6150-qrd.dtsi" -- GitLab From 4099436817575cdd478e2eebe0aaef98fe72ea17 Mon Sep 17 00:00:00 2001 From: Vevek Venkatesan Date: Thu, 23 Aug 2018 16:19:57 +0530 Subject: [PATCH 0968/1001] ARM: dts: msm: add Synaptics Touch panel support for SM6150 Add Synaptics TDDI touch controller driver support and remove Himax Touch support for SM6150 IDP command mode panel. Change-Id: I43534780f480f5c4d4f9cac88b3fac2e816b15a9 Signed-off-by: Vevek Venkatesan --- .../devicetree/bindings/vendor-prefixes.txt | 2 +- .../dts/qcom/sm6150-cmd-mode-display-idp.dts | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index caa4fc38898e..0753f394367a 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -331,7 +331,7 @@ summit Summit microelectronics sunchip Shenzhen Sunchip Technology Co., Ltd SUNW Sun Microsystems, Inc swir Sierra Wireless -syna Synaptics Inc. +synaptics Synaptics Inc. synology Synology, Inc. tbs TBS Technologies tcg Trusted Computing Group diff --git a/arch/arm64/boot/dts/qcom/sm6150-cmd-mode-display-idp.dts b/arch/arm64/boot/dts/qcom/sm6150-cmd-mode-display-idp.dts index c8c7110cbebe..0769cb287d91 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-cmd-mode-display-idp.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-cmd-mode-display-idp.dts @@ -15,6 +15,36 @@ #include "sm6150.dtsi" #include "sm6150-idp.dtsi" +&qupv3_se1_i2c { + status = "okay"; + synaptics_dsx@20 { + compatible = "synaptics,dsx-i2c"; + reg = <0x20>; + interrupt-parent = <&tlmm>; + interrupts = <89 0x2008>; + vdd-supply = <&pm6150_l10>; + avdd-supply = <&pm6150l_l7>; + 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>; + synaptics,pwr-reg-name = "avdd"; + synaptics,bus-reg-name = "vdd"; + synaptics,ub-i2c-addr = <0x20>; + synaptics,max-y-for-2d = <2159>; + synaptics,irq-gpio = <&tlmm 89 0x2008>; + synaptics,reset-gpio = <&tlmm 88 0x0>; + synaptics,irq-on-state = <0>; + synaptics,power-delay-ms = <200>; + synaptics,reset-delay-ms = <200>; + synaptics,reset-on-state = <0>; + synaptics,reset-active-ms = <20>; + }; + + /delete-node/ himax_ts@48; +}; + / { model = "Qualcomm Technologies, Inc. SM6150 Command mode display IDP"; compatible = "qcom,sm6150-idp", "qcom,sm6150", "qcom,idp"; -- GitLab From 755f7cb0d73516b224cc042a4bfdc41b837e7903 Mon Sep 17 00:00:00 2001 From: Vevek Venkatesan Date: Tue, 14 Aug 2018 19:32:08 +0530 Subject: [PATCH 0969/1001] input: touchscreen: synaptics_dsx: add display dependency Add display dependency for chip init in synaptics_dsx driver. Change-Id: I59c3573d9f9ba8d0c04a4ef1d0047cd523487822 Signed-off-by: Vevek Venkatesan --- .../synaptics_dsx/synaptics_dsx_core.c | 46 +++++++++++++------ .../synaptics_dsx/synaptics_dsx_core.h | 1 + 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c index 1f45adddec76..0d1453873d73 100644 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c +++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c @@ -147,6 +147,8 @@ static int synaptics_rmi4_suspend(struct device *dev); static int synaptics_rmi4_resume(struct device *dev); +static int synaptics_rmi4_defer_probe(struct platform_device *pdev); + static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); @@ -4226,7 +4228,6 @@ EXPORT_SYMBOL(synaptics_rmi4_new_function); static int synaptics_rmi4_probe(struct platform_device *pdev) { int retval; - unsigned char attr_count; struct synaptics_rmi4_data *rmi4_data; const struct synaptics_dsx_hw_interface *hw_if; const struct synaptics_dsx_board_data *bdata; @@ -4277,6 +4278,31 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) vir_button_map = bdata->vir_button_map; + rmi4_data->initialized = false; +#ifdef CONFIG_FB + rmi4_data->fb_notifier.notifier_call = + synaptics_rmi4_dsi_panel_notifier_cb; + retval = msm_drm_register_client(&rmi4_data->fb_notifier); + if (retval < 0) { + dev_err(&pdev->dev, + "%s: Failed to register fb notifier client\n", + __func__); + } +#endif + return retval; +} + +static int synaptics_rmi4_defer_probe(struct platform_device *pdev) +{ + int retval; + struct synaptics_rmi4_data *rmi4_data; + const struct synaptics_dsx_hw_interface *hw_if; + const struct synaptics_dsx_board_data *bdata; + unsigned char attr_count; + + rmi4_data = platform_get_drvdata(pdev); + hw_if = rmi4_data->hw_if; + bdata = hw_if->board_data; retval = synaptics_rmi4_get_reg(rmi4_data, true); if (retval < 0) { dev_err(&pdev->dev, @@ -4335,18 +4361,6 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) goto err_set_input_dev; } -#ifdef CONFIG_FB - rmi4_data->fb_notifier.notifier_call = synaptics_rmi4_dsi_panel_notifier_cb; - retval = msm_drm_register_client(&rmi4_data->fb_notifier); - if (retval < 0) { - - - dev_err(&pdev->dev, - "%s: Failed to register fb notifier client\n", - __func__); - } -#endif - #ifdef USE_EARLYSUSPEND rmi4_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; rmi4_data->early_suspend.suspend = synaptics_rmi4_early_suspend; @@ -4594,6 +4608,12 @@ static int synaptics_rmi4_dsi_panel_notifier_cb(struct notifier_block *self, synaptics_rmi4_suspend(&rmi4_data->pdev->dev); rmi4_data->fb_ready = false; } else if (transition == MSM_DRM_BLANK_UNBLANK) { + if (rmi4_data->initialized == false) { + if (synaptics_rmi4_defer_probe( + rmi4_data->pdev)) + return -ECANCELED; + rmi4_data->initialized = true; + } synaptics_rmi4_resume(&rmi4_data->pdev->dev); rmi4_data->fb_ready = true; } diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h index 34170708a96b..423db092f976 100644 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h +++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h @@ -353,6 +353,7 @@ struct synaptics_rmi4_device_info { * @report_touch: pointer to touch reporting function */ struct synaptics_rmi4_data { + bool initialized; struct platform_device *pdev; struct input_dev *input_dev; struct input_dev *stylus_dev; -- GitLab From c7ae8d74dea0aa4978fe4bf9a0786c145ea861aa Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Mon, 25 Jun 2018 16:13:39 +0530 Subject: [PATCH 0970/1001] Revert "sched: Remove sched_ktime_clock()" This reverts 'commit 24c18127e9ba ("sched: Remove sched_ktime_clock()")' WALT accounting uses ktime_get() as time source to keep windows in align with the tick. ktime_get() API should not be called while the timekeeping subsystem is suspended during the system suspend. The code before the reverted patch has a wrapper around ktime_get() to avoid calling ktime_get() when timekeeping subsystem is suspended. The reverted patch removed this wrapper with the assumption that there will not be any scheduler activity while timekeeping subsystem is suspended. The timekeeping subsystem is resumed very early even before non-boot CPUs are brought online. However it is possible that tasks can wake up from the idle notifiers which gets called before timekeeping subsystem is resumed. When this happens, the time read from ktime_get() will not be consistent. We see a jump from the values that would be returned later when timekeeping subsystem is resumed. The rq->window_start update happens with incorrect time. This rq->window_start becomes inconsistent with the rest of the CPUs's rq->window_start and wallclock time after timekeeping subsystem is resumed. This results in WALT accounting bugs. Change-Id: I9c3b2fb9ffbf1103d1bd78778882450560dac09f Signed-off-by: Pavankumar Kondeti [clingutla@codeaurora.org: Resolved trivial merge conflicts.] Signed-off-by: Lingutla Chandrasekhar --- kernel/sched/core.c | 14 ++++----- kernel/sched/cpufreq_schedutil.c | 4 +-- kernel/sched/fair.c | 2 +- kernel/sched/sched.h | 11 ++++++- kernel/sched/walt.c | 54 ++++++++++++++++++++++++++------ kernel/sched/walt.h | 2 +- 6 files changed, 65 insertions(+), 22 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index f46cf644af3c..a522a5f17e0d 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -785,7 +785,7 @@ static inline void dequeue_task(struct rq *rq, struct task_struct *p, int flags) p->sched_class->dequeue_task(rq, p, flags); #ifdef CONFIG_SCHED_WALT if (p == rq->ed_task) - early_detection_notify(rq, ktime_get_ns()); + early_detection_notify(rq, sched_ktime_clock()); #endif trace_sched_enq_deq_task(p, 0, cpumask_bits(&p->cpus_allowed)[0]); } @@ -2041,7 +2041,7 @@ static inline void walt_try_to_wake_up(struct task_struct *p) rq_lock_irqsave(rq, &rf); old_load = task_load(p); - wallclock = ktime_get_ns(); + wallclock = sched_ktime_clock(); update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0); update_task_ravg(p, rq, TASK_WAKE, wallclock, 0); rq_unlock_irqrestore(rq, &rf); @@ -2175,7 +2175,7 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags, set_task_cpu(p, cpu); } - wallclock = ktime_get_ns(); + wallclock = sched_ktime_clock(); note_task_waking(p, wallclock); #else /* CONFIG_SMP */ @@ -2240,7 +2240,7 @@ static void try_to_wake_up_local(struct task_struct *p, struct rq_flags *rf) trace_sched_waking(p); if (!task_on_rq_queued(p)) { - u64 wallclock = ktime_get_ns(); + u64 wallclock = sched_ktime_clock(); update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0); update_task_ravg(p, rq, TASK_WAKE, wallclock, 0); @@ -3163,7 +3163,7 @@ void scheduler_tick(void) old_load = task_load(curr); set_window_start(rq); - wallclock = ktime_get_ns(); + wallclock = sched_ktime_clock(); update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0); update_rq_clock(rq); curr->sched_class->task_tick(rq, curr, 0); @@ -3547,7 +3547,7 @@ static void __sched notrace __schedule(bool preempt) clear_tsk_need_resched(prev); clear_preempt_need_resched(); - wallclock = ktime_get_ns(); + wallclock = sched_ktime_clock(); if (likely(prev != next)) { if (!prev->on_rq) prev->last_sleep_ts = wallclock; @@ -7426,7 +7426,7 @@ void sched_exit(struct task_struct *p) rq = task_rq_lock(p, &rf); /* rq->curr == p */ - wallclock = ktime_get_ns(); + wallclock = sched_ktime_clock(); update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0); dequeue_task(rq, p, 0); /* diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index 98739c5f55c4..1e23ffb7a099 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -540,7 +540,7 @@ static void sugov_work(struct kthread_work *work) mutex_lock(&sg_policy->work_lock); raw_spin_lock_irqsave(&sg_policy->update_lock, flags); sugov_track_cycles(sg_policy, sg_policy->policy->cur, - ktime_get_ns()); + sched_ktime_clock()); raw_spin_unlock_irqrestore(&sg_policy->update_lock, flags); __cpufreq_driver_target(sg_policy->policy, sg_policy->next_freq, CPUFREQ_RELATION_L); @@ -993,7 +993,7 @@ static void sugov_limits(struct cpufreq_policy *policy) mutex_lock(&sg_policy->work_lock); raw_spin_lock_irqsave(&sg_policy->update_lock, flags); sugov_track_cycles(sg_policy, sg_policy->policy->cur, - ktime_get_ns()); + sched_ktime_clock()); raw_spin_unlock_irqrestore(&sg_policy->update_lock, flags); cpufreq_policy_apply_limits(policy); mutex_unlock(&sg_policy->work_lock); diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index a0ac1bc27fe4..511e58643dbf 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -12750,7 +12750,7 @@ static void walt_check_for_rotation(struct rq *src_rq) if (!is_min_capacity_cpu(src_cpu)) return; - wc = ktime_get_ns(); + wc = sched_ktime_clock(); for_each_possible_cpu(i) { struct rq *rq = cpu_rq(i); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index d3a72c8fe991..7c757b79a0f0 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1841,6 +1841,15 @@ static inline int hrtick_enabled(struct rq *rq) #endif /* CONFIG_SCHED_HRTICK */ +#ifdef CONFIG_SCHED_WALT +u64 sched_ktime_clock(void); +#else +static inline u64 sched_ktime_clock(void) +{ + return 0; +} +#endif + #ifdef CONFIG_SMP extern void sched_avg_update(struct rq *rq); extern unsigned long sched_get_rt_rq_util(int cpu); @@ -2479,7 +2488,7 @@ static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) data = rcu_dereference_sched(*per_cpu_ptr(&cpufreq_update_util_data, cpu_of(rq))); if (data) - data->func(data, ktime_get_ns(), flags); + data->func(data, sched_ktime_clock(), flags); } #else static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) {} diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index 1b171077cf24..52fd3d25837c 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -19,6 +19,7 @@ * and Todd Kjos */ +#include #include #include #include @@ -42,6 +43,8 @@ const char *migrate_type_names[] = {"GROUP_TO_RQ", "RQ_TO_GROUP", #define EARLY_DETECTION_DURATION 9500000 +static ktime_t ktime_last; +static bool sched_ktime_suspended; static struct cpu_cycle_counter_cb cpu_cycle_counter_cb; static bool use_cycle_counter; DEFINE_MUTEX(cluster_lock); @@ -51,6 +54,37 @@ u64 walt_load_reported_window; static struct irq_work walt_cpufreq_irq_work; static struct irq_work walt_migration_irq_work; +u64 sched_ktime_clock(void) +{ + if (unlikely(sched_ktime_suspended)) + return ktime_to_ns(ktime_last); + return ktime_get_ns(); +} + +static void sched_resume(void) +{ + sched_ktime_suspended = false; +} + +static int sched_suspend(void) +{ + ktime_last = ktime_get(); + sched_ktime_suspended = true; + return 0; +} + +static struct syscore_ops sched_syscore_ops = { + .resume = sched_resume, + .suspend = sched_suspend +}; + +static int __init sched_init_ops(void) +{ + register_syscore_ops(&sched_syscore_ops); + return 0; +} +late_initcall(sched_init_ops); + static void acquire_rq_locks_irqsave(const cpumask_t *cpus, unsigned long *flags) { @@ -361,7 +395,7 @@ void sched_account_irqstart(int cpu, struct task_struct *curr, u64 wallclock) if (is_idle_task(curr)) { /* We're here without rq->lock held, IRQ disabled */ raw_spin_lock(&rq->lock); - update_task_cpu_cycles(curr, cpu, ktime_get_ns()); + update_task_cpu_cycles(curr, cpu, sched_ktime_clock()); raw_spin_unlock(&rq->lock); } } @@ -416,7 +450,7 @@ void sched_account_irqtime(int cpu, struct task_struct *curr, cur_jiffies_ts = get_jiffies_64(); if (is_idle_task(curr)) - update_task_ravg(curr, rq, IRQ_UPDATE, ktime_get_ns(), + update_task_ravg(curr, rq, IRQ_UPDATE, sched_ktime_clock(), delta); nr_windows = cur_jiffies_ts - rq->irqload_ts; @@ -756,7 +790,7 @@ void fixup_busy_time(struct task_struct *p, int new_cpu) if (sched_disable_window_stats) goto done; - wallclock = ktime_get_ns(); + wallclock = sched_ktime_clock(); update_task_ravg(task_rq(p)->curr, task_rq(p), TASK_UPDATE, @@ -2055,7 +2089,7 @@ void mark_task_starting(struct task_struct *p) return; } - wallclock = ktime_get_ns(); + wallclock = sched_ktime_clock(); p->ravg.mark_start = p->last_wake_ts = wallclock; p->last_enqueued_ts = wallclock; update_task_cpu_cycles(p, cpu_of(rq), wallclock); @@ -2401,7 +2435,7 @@ static int cpufreq_notifier_trans(struct notifier_block *nb, raw_spin_lock_irqsave(&rq->lock, flags); update_task_ravg(rq->curr, rq, TASK_UPDATE, - ktime_get_ns(), 0); + sched_ktime_clock(), 0); raw_spin_unlock_irqrestore(&rq->lock, flags); } @@ -2561,7 +2595,7 @@ static void _set_preferred_cluster(struct related_thread_group *grp) if (list_empty(&grp->tasks)) return; - wallclock = ktime_get_ns(); + wallclock = sched_ktime_clock(); /* * wakeup of two or more related tasks could race with each other and @@ -2587,7 +2621,7 @@ static void _set_preferred_cluster(struct related_thread_group *grp) grp->preferred_cluster = best_cluster(grp, combined_demand, group_boost); - grp->last_update = ktime_get_ns(); + grp->last_update = sched_ktime_clock(); trace_sched_set_preferred_cluster(grp, combined_demand); } @@ -2611,7 +2645,7 @@ int update_preferred_cluster(struct related_thread_group *grp, * has passed since we last updated preference */ if (abs(new_load - old_load) > sched_ravg_window / 4 || - ktime_get_ns() - grp->last_update > sched_ravg_window) + sched_ktime_clock() - grp->last_update > sched_ravg_window) return 1; return 0; @@ -2994,7 +3028,7 @@ static void transfer_busy_time(struct rq *rq, struct related_thread_group *grp, bool new_task; int i; - wallclock = ktime_get_ns(); + wallclock = sched_ktime_clock(); update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0); update_task_ravg(p, rq, TASK_UPDATE, wallclock, 0); @@ -3166,7 +3200,7 @@ void walt_irq_work(struct irq_work *irq_work) for_each_cpu(cpu, cpu_possible_mask) raw_spin_lock(&cpu_rq(cpu)->lock); - wc = ktime_get_ns(); + wc = sched_ktime_clock(); walt_load_reported_window = atomic64_read(&walt_irq_work_lastq_ws); for_each_sched_cluster(cluster) { u64 aggr_grp_load = 0; diff --git a/kernel/sched/walt.h b/kernel/sched/walt.h index e3c1181265bc..7575063b40ac 100644 --- a/kernel/sched/walt.h +++ b/kernel/sched/walt.h @@ -299,7 +299,7 @@ void walt_sched_init_rq(struct rq *rq); static inline void walt_update_last_enqueue(struct task_struct *p) { - p->last_enqueued_ts = ktime_get_ns(); + p->last_enqueued_ts = sched_ktime_clock(); } extern void walt_rotate_work_init(void); extern void walt_rotation_checkpoint(int nr_big); -- GitLab From aee9cc3c530e5cb5f41a6c79a67c7beb6a4f6cd1 Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Fri, 24 Aug 2018 22:20:08 +0530 Subject: [PATCH 0971/1001] drivers: bcl_pmic5: Fix Ibat related warnings if not enabled BCL peripheral throws error messages during boot-up, if Ibat is not enabled. Bypass Ibat settings gracefully on this case and avoid these error messages. Change-Id: Iaa2a73132523862dd924c32f124d8c7736b43eee Signed-off-by: Manaf Meethalavalappu Pallikunhi --- drivers/thermal/qcom/bcl_pmic5.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/qcom/bcl_pmic5.c b/drivers/thermal/qcom/bcl_pmic5.c index 42d5817e3c12..7a5124e11f26 100644 --- a/drivers/thermal/qcom/bcl_pmic5.c +++ b/drivers/thermal/qcom/bcl_pmic5.c @@ -496,7 +496,7 @@ static void bcl_fetch_trip(struct platform_device *pdev, enum bcl_dev_type type, data->irq_num = 0; data->irq_enabled = false; irq_num = platform_get_irq_byname(pdev, int_name); - if (irq_num && handle) { + if (irq_num > 0 && handle) { ret = devm_request_threaded_irq(&pdev->dev, irq_num, NULL, handle, IRQF_TRIGGER_RISING | IRQF_ONESHOT, @@ -510,7 +510,7 @@ static void bcl_fetch_trip(struct platform_device *pdev, enum bcl_dev_type type, } disable_irq_nosync(irq_num); data->irq_num = irq_num; - } else if (irq_num && !handle) { + } else if (irq_num > 0 && !handle) { disable_irq_nosync(irq_num); data->irq_num = irq_num; } @@ -559,6 +559,9 @@ static void bcl_ibat_init(struct platform_device *pdev, ibat->type = type; ibat->dev = bcl_perph; bcl_fetch_trip(pdev, type, ibat, NULL); + if (ibat->irq_num <= 0) + return; + ibat->ops.get_temp = bcl_read_ibat; ibat->ops.set_trips = bcl_set_ibat; -- GitLab From 6af10d4d44ac63126bfd1b8dfd1fda7c34c9a37d Mon Sep 17 00:00:00 2001 From: Shivaprasad Hongal Date: Fri, 17 Aug 2018 13:44:56 -0700 Subject: [PATCH 0972/1001] defconfig: sm8150: Enable wrapped key support for FBE Enable wrapped key support for FBE where the keys are wrapped and unwrapped in a secure environment before using them. Change-Id: I4f9a4a08d0b4795f81c7d1dfec43764e521dac77 Signed-off-by: Shivaprasad Hongal --- arch/arm64/configs/vendor/sm8150-perf_defconfig | 1 + arch/arm64/configs/vendor/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/vendor/sm8150-perf_defconfig b/arch/arm64/configs/vendor/sm8150-perf_defconfig index 9598ff49e9cd..d6d9d695decf 100644 --- a/arch/arm64/configs/vendor/sm8150-perf_defconfig +++ b/arch/arm64/configs/vendor/sm8150-perf_defconfig @@ -649,6 +649,7 @@ CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_TGU=y CONFIG_CORESIGHT_EVENT=y CONFIG_PFK=y +CONFIG_PFK_WRAPPED_KEY_SUPPORTED=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y diff --git a/arch/arm64/configs/vendor/sm8150_defconfig b/arch/arm64/configs/vendor/sm8150_defconfig index b954cd674178..08f2bb3b8842 100644 --- a/arch/arm64/configs/vendor/sm8150_defconfig +++ b/arch/arm64/configs/vendor/sm8150_defconfig @@ -729,6 +729,7 @@ CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_TGU=y CONFIG_CORESIGHT_EVENT=y CONFIG_PFK=y +CONFIG_PFK_WRAPPED_KEY_SUPPORTED=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y -- GitLab From 8d7d063acc13e7c56e0e161018f6544906fbd64e Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 12 Apr 2017 11:09:25 -0700 Subject: [PATCH 0973/1001] ANDROID: add dm-default-key target for ICE metadata encryption Add a device-mapper target "dm-default-key" which assigns an encryption key to bios that don't already have one. This will be used on Android's userdata partition, so that all data not already encrypted with ext4 encryption is still encrypted with a default key (which will not be derived from a user credential but will still be protected in some way). Currently this feature depends on inline encryption support in hardware via Qualcomm ICE; no software fallback is implemented yet. An alternate approach considered was to introduce a block device ioctl which would associate an encryption key with a struct block_device, which would then be used as the default for bios issued to that block_device. However, that approach had some issues which made the dm target seem like the better solution, and perhaps more likely to be accepted upstream in some form someday (at least, once we have vendor-independent inline encryption support upstream). Specifically: 1.) The struct block_device for a partition really only represents a part of some underlying disk along with some state associated with its current users. Notably, the block_device for a given partition is not guaranteed to stay around while no one has it opened or mounted. This means that any extra state like an encryption key we may try to tie a block_device can be lost if there is a period of time when no one is using the block device. Granted, this can't happen while the filesystem on the device is mounted, and it also can't happen on systems that use tmpfs for their /dev because the block_device will be pinned by the device node. But either way, a dm target does not have this problem. 2.) The block_device for a partition doesn't have its own request_queue or queue_limits. One way in which this could cause problems is that the disk could support discard requests and have discard_zeroes_data set to true, which specifies that data read back following a discard is guaranteed to be zeros. That will not be true for an encrypted partition, so any filesystem that issues zeroouts (which the block layer may implement with discard) would potentially be broken. We can handle this correctly in a dm target since each dm device has its own request_queue and we can disable discard_zeroes_data, just as dm-crypt does for example. 3.) Since the block layer remaps bios from partitions to the devices containing them, we'd still need to have ->bi_crypt_key and initialize it somewhere, e.g. in generic_make_request_checks() before it does the partition remapping. We can't simply read ->bi_bdev->bd_default_key from the PFK module. 4.) With a block device ioctl, we'd need to carefully handle the cases where the ioctl is executed while someone else has the block device open (fail with EBUSY?) or while the block device's mapping already has pages cached (sync and invalidate them?). This would not be too difficult, but with a dm target neither of these is a problem. Change-Id: Ia3884842004cfb84d315ef38e54ab4f35b48cf5f Signed-off-by: Eric Biggers Signed-off-by: Shivaprasad Hongal --- drivers/md/Kconfig | 18 +++ drivers/md/Makefile | 1 + drivers/md/dm-default-key.c | 224 ++++++++++++++++++++++++++++++++++++ 3 files changed, 243 insertions(+) create mode 100644 drivers/md/dm-default-key.c diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index e4a0eced8950..5849c025c273 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -286,6 +286,24 @@ config DM_CRYPT If unsure, say N. +config DM_DEFAULT_KEY + tristate "Default-key crypt target support" + depends on BLK_DEV_DM + depends on PFK + ---help--- + This (currently Android-specific) device-mapper target allows you to + create a device that assigns a default encryption key to bios that + don't already have one. This can sit between inline cryptographic + acceleration hardware and filesystems that use it. This ensures that + where the filesystem doesn't explicitly specify a key, such as for + filesystem metadata, a default key will be used instead, leaving no + sectors unencrypted. + + To compile this code as a module, choose M here: the module will be + called dm-default-key. + + If unsure, say N. + config DM_SNAPSHOT tristate "Snapshot target" depends on BLK_DEV_DM diff --git a/drivers/md/Makefile b/drivers/md/Makefile index 26c2f8f28ec0..bfd027659aaf 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_BLK_DEV_DM_BUILTIN) += dm-builtin.o obj-$(CONFIG_DM_BUFIO) += dm-bufio.o obj-$(CONFIG_DM_BIO_PRISON) += dm-bio-prison.o obj-$(CONFIG_DM_CRYPT) += dm-crypt.o +obj-$(CONFIG_DM_DEFAULT_KEY) += dm-default-key.o obj-$(CONFIG_DM_DELAY) += dm-delay.o obj-$(CONFIG_DM_FLAKEY) += dm-flakey.o obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o diff --git a/drivers/md/dm-default-key.c b/drivers/md/dm-default-key.c new file mode 100644 index 000000000000..6d4326095525 --- /dev/null +++ b/drivers/md/dm-default-key.c @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2017 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +#define DM_MSG_PREFIX "default-key" + +struct default_key_c { + struct dm_dev *dev; + sector_t start; + struct blk_encryption_key key; +}; + +static void default_key_dtr(struct dm_target *ti) +{ + struct default_key_c *dkc = ti->private; + + if (dkc->dev) + dm_put_device(ti, dkc->dev); + kzfree(dkc); +} + +/* + * Construct a default-key mapping: + */ +static int default_key_ctr(struct dm_target *ti, unsigned int argc, char **argv) +{ + struct default_key_c *dkc; + size_t key_size; + unsigned long long tmp; + char dummy; + int err; + + if (argc != 4) { + ti->error = "Invalid argument count"; + return -EINVAL; + } + + dkc = kzalloc(sizeof(*dkc), GFP_KERNEL); + if (!dkc) { + ti->error = "Out of memory"; + return -ENOMEM; + } + ti->private = dkc; + + if (strcmp(argv[0], "AES-256-XTS") != 0) { + ti->error = "Unsupported encryption mode"; + err = -EINVAL; + goto bad; + } + + key_size = strlen(argv[1]); + if (key_size != 2 * BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS) { + ti->error = "Unsupported key size"; + err = -EINVAL; + goto bad; + } + key_size /= 2; + + if (hex2bin(dkc->key.raw, argv[1], key_size) != 0) { + ti->error = "Malformed key string"; + err = -EINVAL; + goto bad; + } + + err = dm_get_device(ti, argv[2], dm_table_get_mode(ti->table), + &dkc->dev); + if (err) { + ti->error = "Device lookup failed"; + goto bad; + } + + if (sscanf(argv[3], "%llu%c", &tmp, &dummy) != 1) { + ti->error = "Invalid start sector"; + err = -EINVAL; + goto bad; + } + dkc->start = tmp; + + if (!blk_queue_inlinecrypt(bdev_get_queue(dkc->dev->bdev))) { + ti->error = "Device does not support inline encryption"; + err = -EINVAL; + goto bad; + } + + /* Pass flush requests through to the underlying device. */ + ti->num_flush_bios = 1; + + /* + * We pass discard requests through to the underlying device, although + * the discarded blocks will be zeroed, which leaks information about + * unused blocks. It's also impossible for dm-default-key to know not + * to decrypt discarded blocks, so they will not be read back as zeroes + * and we must set discard_zeroes_data_unsupported. + */ + ti->num_discard_bios = 1; + + /* + * It's unclear whether WRITE_SAME would work with inline encryption; it + * would depend on whether the hardware duplicates the data before or + * after encryption. But since the internal storage in some devices + * (MSM8998-based) doesn't claim to support WRITE_SAME anyway, we don't + * currently have a way to test it. Leave it disabled it for now. + */ + /*ti->num_write_same_bios = 1;*/ + + return 0; + +bad: + default_key_dtr(ti); + return err; +} + +static int default_key_map(struct dm_target *ti, struct bio *bio) +{ + const struct default_key_c *dkc = ti->private; + + bio_set_dev(bio, dkc->dev->bdev); + if (bio_sectors(bio)) { + bio->bi_iter.bi_sector = dkc->start + + dm_target_offset(ti, bio->bi_iter.bi_sector); + } + + if (!bio->bi_crypt_key) + bio->bi_crypt_key = &dkc->key; + + return DM_MAPIO_REMAPPED; +} + +static void default_key_status(struct dm_target *ti, status_type_t type, + unsigned int status_flags, char *result, + unsigned int maxlen) +{ + const struct default_key_c *dkc = ti->private; + unsigned int sz = 0; + + switch (type) { + case STATUSTYPE_INFO: + result[0] = '\0'; + break; + + case STATUSTYPE_TABLE: + + /* encryption mode */ + DMEMIT("AES-256-XTS"); + + /* reserved for key; dm-crypt shows it, but we don't for now */ + DMEMIT(" -"); + + /* name of underlying device, and the start sector in it */ + DMEMIT(" %s %llu", dkc->dev->name, + (unsigned long long)dkc->start); + break; + } +} + +static int default_key_prepare_ioctl(struct dm_target *ti, + struct block_device **bdev, fmode_t *mode) +{ + struct default_key_c *dkc = ti->private; + struct dm_dev *dev = dkc->dev; + + *bdev = dev->bdev; + + /* + * Only pass ioctls through if the device sizes match exactly. + */ + if (dkc->start || + ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT) + return 1; + return 0; +} + +static int default_key_iterate_devices(struct dm_target *ti, + iterate_devices_callout_fn fn, + void *data) +{ + struct default_key_c *dkc = ti->private; + + return fn(ti, dkc->dev, dkc->start, ti->len, data); +} + +static struct target_type default_key_target = { + .name = "default-key", + .version = {1, 0, 0}, + .module = THIS_MODULE, + .ctr = default_key_ctr, + .dtr = default_key_dtr, + .map = default_key_map, + .status = default_key_status, + .prepare_ioctl = default_key_prepare_ioctl, + .iterate_devices = default_key_iterate_devices, +}; + +static int __init dm_default_key_init(void) +{ + return dm_register_target(&default_key_target); +} + +static void __exit dm_default_key_exit(void) +{ + dm_unregister_target(&default_key_target); +} + +module_init(dm_default_key_init); +module_exit(dm_default_key_exit); + +MODULE_AUTHOR("Paul Lawrence "); +MODULE_AUTHOR("Paul Crowley "); +MODULE_AUTHOR("Eric Biggers "); +MODULE_DESCRIPTION(DM_NAME " target for encrypting filesystem metadata"); +MODULE_LICENSE("GPL v2"); -- GitLab From 1611298c81197a4109ebfa9c6245a8cef6a8ac39 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 12 Apr 2017 11:09:24 -0700 Subject: [PATCH 0974/1001] ANDROID: dm table: propagate inline encryption flag to dm devices If all targets in a device-mapper table support inline encryption, mark the mapped device as supporting inline encryption. This will allow filesystems such as ext4 to tell whether the hardware supports inline encryption even in the case where there is an intervening dm device. Change-Id: I596829f6c5a39fb0d5bedfac9f18828ae27444cb Signed-off-by: Eric Biggers Signed-off-by: Shivaprasad Hongal --- drivers/md/dm-table.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 23e8bde4c500..52a695f065e1 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -1686,6 +1686,16 @@ static int queue_supports_sg_merge(struct dm_target *ti, struct dm_dev *dev, return q && !test_bit(QUEUE_FLAG_NO_SG_MERGE, &q->queue_flags); } +static int queue_supports_inline_encryption(struct dm_target *ti, + struct dm_dev *dev, + sector_t start, sector_t len, + void *data) +{ + struct request_queue *q = bdev_get_queue(dev->bdev); + + return q && blk_queue_inlinecrypt(q); +} + static bool dm_table_all_devices_attribute(struct dm_table *t, iterate_devices_callout_fn func) { @@ -1836,6 +1846,11 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, else queue_flag_set_unlocked(QUEUE_FLAG_NO_SG_MERGE, q); + if (dm_table_all_devices_attribute(t, queue_supports_inline_encryption)) + queue_flag_set_unlocked(QUEUE_FLAG_INLINECRYPT, q); + else + queue_flag_clear_unlocked(QUEUE_FLAG_INLINECRYPT, q); + dm_table_verify_integrity(t); /* -- GitLab From af4ef71b89c5a7740a99dcc7afbfd79d9e96e0e3 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 20 Apr 2018 19:26:09 -0700 Subject: [PATCH 0975/1001] dm-default-key, f2fs, ICE: support dm-default-key with f2fs/ICE This patch fixes assigning bi_crypt_key for moving data which was previously encrypted by f2fs. Note that, dm-default-key should not assign bi_crypt_key, if bi_crypt_skip is set. The bug sceanrios is: 1. write data with user key by f2fs - ENC(KU, IVU, DATA) 2. log out user key 3. read data #1 w/o user key from LBA #a 4. dm-default-key assigns default key - DEC(KD, LBA#a, ENC(KU, IVU, DATA)) 5. write data #1 w/o user key into LBA #b 6. dm-default-key assigns default key - ENC(KD, LBA#b, DEC(KD, LBA#a, ENC(KU, IVU, DATA))) 7. Read DATA out with valid logged-in user key - DEC(KU, IVU, ENC(KD, LBA#b, DEC(KD, LBA#a, ENC(KU, IVU, DATA)))) So, this patch introduces bi_crypt_skip to avoid 4. ~ 6 with right flow: 1. write data with user key by f2fs - ENC(KU, IVU, DATA) 2. log out user key 3. read data #1 w/o user key from LBA #a 4. dm-default-key skip to assign default key - ENC(KU, IVU, DATA) 5. write data #1 w/o user key into LBA #b 6. dm-default-key skips to assign default key - ENC(KU, IVU, DATA) 7. Try to read DATA with valid logged-in user key - DEC(KU, IVU, ENC(KU, IVU, DATA)) Bug: 68721442 Change-Id: Icefe85f608b7c3c84beb2bfa4267efd0f3787453 Signed-off-by: Jaegeuk Kim Signed-off-by: Shivaprasad Hongal --- block/bio.c | 6 +++++- fs/crypto/fscrypt_ice.c | 15 ++++++++++++++- fs/f2fs/data.c | 9 ++++++--- include/linux/blk_types.h | 3 +++ include/linux/fscrypt_notsupp.h | 7 ++++++- include/linux/fscrypt_supp.h | 5 +++-- security/pfe/pfk.c | 13 ++++++++++--- 7 files changed, 47 insertions(+), 11 deletions(-) diff --git a/block/bio.c b/block/bio.c index 6328c6e71b27..336c5c2423cb 100644 --- a/block/bio.c +++ b/block/bio.c @@ -580,8 +580,12 @@ EXPORT_SYMBOL(bio_phys_segments); static inline void bio_clone_crypt_key(struct bio *dst, const struct bio *src) { #ifdef CONFIG_PFK - dst->bi_crypt_key = src->bi_crypt_key; dst->bi_iter.bi_dun = src->bi_iter.bi_dun; +#ifdef CONFIG_DM_DEFAULT_KEY + dst->bi_crypt_key = src->bi_crypt_key; + dst->bi_crypt_skip = src->bi_crypt_skip; +#endif + dst->bi_dio_inode = src->bi_dio_inode; #endif } diff --git a/fs/crypto/fscrypt_ice.c b/fs/crypto/fscrypt_ice.c index 62dae83cf732..ae28cdfd83e4 100644 --- a/fs/crypto/fscrypt_ice.c +++ b/fs/crypto/fscrypt_ice.c @@ -126,16 +126,29 @@ void fscrypt_set_ice_dun(const struct inode *inode, struct bio *bio, u64 dun) } EXPORT_SYMBOL(fscrypt_set_ice_dun); +void fscrypt_set_ice_skip(struct bio *bio, int bi_crypt_skip) +{ +#ifdef CONFIG_DM_DEFAULT_KEY + bio->bi_crypt_skip = bi_crypt_skip; +#endif +} +EXPORT_SYMBOL(fscrypt_set_ice_skip); + /* * This function will be used for filesystem when deciding to merge bios. * Basic assumption is, if inline_encryption is set, single bio has to * guarantee consecutive LBAs as well as ino|pg->index. */ -bool fscrypt_mergeable_bio(struct bio *bio, u64 dun, bool bio_encrypted) +bool fscrypt_mergeable_bio(struct bio *bio, u64 dun, bool bio_encrypted, + int bi_crypt_skip) { if (!bio) return true; +#ifdef CONFIG_DM_DEFAULT_KEY + if (bi_crypt_skip != bio->bi_crypt_skip) + return false; +#endif /* if both of them are not encrypted, no further check is needed */ if (!bio_dun(bio) && !bio_encrypted) return true; diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 39dc4810ea5f..d503bdfd3c57 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -451,6 +451,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio) if (f2fs_may_encrypt_bio(inode, fio)) fscrypt_set_ice_dun(inode, bio, PG_DUN(inode, fio->page)); + fscrypt_set_ice_skip(bio, fio->encrypted_page ? 1 : 0); if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { bio_put(bio); @@ -473,6 +474,7 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) struct page *bio_page; struct inode *inode; bool bio_encrypted; + int bi_crypt_skip; u64 dun; int err = 0; @@ -499,6 +501,7 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page; inode = fio->page->mapping->host; dun = PG_DUN(inode, fio->page); + bi_crypt_skip = fio->encrypted_page ? 1 : 0; bio_encrypted = f2fs_may_encrypt_bio(inode, fio); /* set submitted = true as a return value */ @@ -512,7 +515,7 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) __submit_merged_bio(io); /* ICE support */ - if (!fscrypt_mergeable_bio(io->bio, dun, bio_encrypted)) + if (!fscrypt_mergeable_bio(io->bio, dun, bio_encrypted, bi_crypt_skip)) __submit_merged_bio(io); alloc_new: @@ -528,7 +531,7 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) fio->type, fio->temp); if (bio_encrypted) fscrypt_set_ice_dun(inode, io->bio, dun); - + fscrypt_set_ice_skip(io->bio, bi_crypt_skip); io->fio = *fio; } @@ -1539,7 +1542,7 @@ static int f2fs_mpage_readpages(struct address_space *mapping, dun = PG_DUN(inode, page); bio_encrypted = f2fs_may_encrypt_bio(inode, NULL); - if (!fscrypt_mergeable_bio(bio, dun, bio_encrypted)) { + if (!fscrypt_mergeable_bio(bio, dun, bio_encrypted, 0)) { __submit_bio(F2FS_I_SB(inode), bio, DATA); bio = NULL; } diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index ba4b484c0008..30f317099366 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -104,6 +104,9 @@ struct bio { /* Encryption key to use (NULL if none) */ const struct blk_encryption_key *bi_crypt_key; #endif +#ifdef CONFIG_DM_DEFAULT_KEY + int bi_crypt_skip; +#endif unsigned short bi_vcnt; /* how many bio_vec's */ diff --git a/include/linux/fscrypt_notsupp.h b/include/linux/fscrypt_notsupp.h index 07f6b63f4240..68862592d875 100644 --- a/include/linux/fscrypt_notsupp.h +++ b/include/linux/fscrypt_notsupp.h @@ -193,8 +193,13 @@ static inline int fscrypt_using_hardware_encryption(const struct inode *inode) static inline void fscrypt_set_ice_dun(const struct inode *inode, struct bio *bio, u64 dun){} +static inline void fscrypt_set_ice_skip(struct bio *bio, int bi_crypt_skip) +{ + return; +} + static inline bool fscrypt_mergeable_bio(struct bio *bio, - sector_t iv_block, bool bio_encrypted) + sector_t iv_block, bool bio_encrypted, int bi_crypt_skip) { return true; } diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h index 483de436fbb6..083f1fcf483e 100644 --- a/include/linux/fscrypt_supp.h +++ b/include/linux/fscrypt_supp.h @@ -201,8 +201,9 @@ extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t, extern int fscrypt_using_hardware_encryption(const struct inode *inode); extern void fscrypt_set_ice_dun(const struct inode *inode, struct bio *bio, u64 dun); -extern bool fscrypt_mergeable_bio(struct bio *bio, u64 dun, bool bio_encrypted); - +extern void fscrypt_set_ice_skip(struct bio *bio, int bi_crypt_skip); +extern bool fscrypt_mergeable_bio(struct bio *bio, u64 dun, bool bio_encrypted, + int bi_crypt_skip); /* hooks.c */ extern int fscrypt_file_open(struct inode *inode, struct file *filp); diff --git a/security/pfe/pfk.c b/security/pfe/pfk.c index 27a2ede61946..f66577307573 100644 --- a/security/pfe/pfk.c +++ b/security/pfe/pfk.c @@ -288,7 +288,7 @@ static int pfk_get_key_for_bio(const struct bio *bio, { const struct inode *inode; enum pfe_type which_pfe; - const struct blk_encryption_key *key; + const struct blk_encryption_key *key = NULL; inode = pfk_bio_get_inode(bio); which_pfe = pfk_get_pfe_type(inode); @@ -305,7 +305,9 @@ static int pfk_get_key_for_bio(const struct bio *bio, * bio is not for an encrypted file. Use ->bi_crypt_key if it was set. * Otherwise, don't encrypt/decrypt the bio. */ +#ifdef CONFIG_DM_DEFAULT_KEY key = bio->bi_crypt_key; +#endif if (!key) { *is_pfe = false; return -EINVAL; @@ -464,13 +466,18 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe) */ bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2) { - const struct blk_encryption_key *key1; - const struct blk_encryption_key *key2; + const struct blk_encryption_key *key1 = NULL; + const struct blk_encryption_key *key2 = NULL; const struct inode *inode1; const struct inode *inode2; enum pfe_type which_pfe1; enum pfe_type which_pfe2; +#ifdef CONFIG_DM_DEFAULT_KEY + key1 = bio1->bi_crypt_key; + key2 = bio2->bi_crypt_key; +#endif + if (!pfk_is_ready()) return false; -- GitLab From 1aa7229fbc2a54a2cb4b07effa89bf420eefe3c1 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 20 Apr 2018 19:26:09 -0700 Subject: [PATCH 0976/1001] dm-default-key: fix wrong encryption/decryption when f2fs moves blocks commit 2b425b7413e2 ("dm-default-key, f2fs, ICE: support dm-default-key with f2fs/ICE") supports bio->bi_crypt_skip, so this patch should address the original issue by adding this condition. Change-Id: I215cd9d02e364af07eebf388000809cdf0cce472 Signed-off-by: Jaegeuk Kim Signed-off-by: Shivaprasad Hongal --- drivers/md/dm-default-key.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/dm-default-key.c b/drivers/md/dm-default-key.c index 6d4326095525..23e91d8af0bd 100644 --- a/drivers/md/dm-default-key.c +++ b/drivers/md/dm-default-key.c @@ -133,7 +133,7 @@ static int default_key_map(struct dm_target *ti, struct bio *bio) dm_target_offset(ti, bio->bi_iter.bi_sector); } - if (!bio->bi_crypt_key) + if (!bio->bi_crypt_key && !bio->bi_crypt_skip) bio->bi_crypt_key = &dkc->key; return DM_MAPIO_REMAPPED; -- GitLab From 87a38fbdf3dbcd51801ae5ed8e34ca959a035da9 Mon Sep 17 00:00:00 2001 From: Shivaprasad Hongal Date: Wed, 22 Aug 2018 10:53:01 -0700 Subject: [PATCH 0977/1001] defconfig: sm8150: Enable ICE metadata encryption Enable the device-mapper target "dm-default-key" which assigns an encryption key to bios that don't already have one. This will be used on Android's userdata partition, so that all data not already encrypted with ext4 encryption is still encrypted with a default key. Change-Id: If6ef872019b1ae489ff1122a56ced0917a9aae85 Signed-off-by: Shivaprasad Hongal --- arch/arm64/configs/vendor/sm8150-perf_defconfig | 1 + arch/arm64/configs/vendor/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/vendor/sm8150-perf_defconfig b/arch/arm64/configs/vendor/sm8150-perf_defconfig index d6d9d695decf..fed30e51e3a0 100644 --- a/arch/arm64/configs/vendor/sm8150-perf_defconfig +++ b/arch/arm64/configs/vendor/sm8150-perf_defconfig @@ -273,6 +273,7 @@ CONFIG_SCSI_UFS_QCOM=y CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y +CONFIG_DM_DEFAULT_KEY=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y diff --git a/arch/arm64/configs/vendor/sm8150_defconfig b/arch/arm64/configs/vendor/sm8150_defconfig index 08f2bb3b8842..07e5cb7ba6a5 100644 --- a/arch/arm64/configs/vendor/sm8150_defconfig +++ b/arch/arm64/configs/vendor/sm8150_defconfig @@ -286,6 +286,7 @@ CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y +CONFIG_DM_DEFAULT_KEY=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y -- GitLab From 2cc5c06d71ea5b946093f0c7f9b134e8a9f03c50 Mon Sep 17 00:00:00 2001 From: Vaibhav Deshu Venkatesh Date: Tue, 21 Aug 2018 16:26:06 -0700 Subject: [PATCH 0978/1001] msm: vidc: Add level 6 and 6.1 for VP9 Add support for level 6 and 6.1 for VP9. Currently max level is shown as 5, this is wrong. CRs-Fixed: 2300757 Change-Id: I9c728cb68fe116a7f7a684e1839b0525386bbfc7 Signed-off-by: Vaibhav Deshu Venkatesh --- drivers/media/platform/msm/vidc/msm_vdec.c | 6 ++++-- drivers/media/platform/msm/vidc/msm_vidc_common.c | 4 ++++ drivers/media/platform/msm/vidc/vidc_hfi_api.h | 2 ++ include/uapi/linux/v4l2-controls.h | 6 ++++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index f91ed9e7bb93..b480f05e3d09 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -81,6 +81,8 @@ static const char *const vp9_level[] = { "4.1", "5.0", "5.1", + "6.0", + "6.1", }; static const char *const mpeg2_profile[] = { @@ -248,8 +250,8 @@ static struct msm_vidc_ctrl msm_vdec_ctrls[] = { .name = "VP9 Level", .type = V4L2_CTRL_TYPE_MENU, .minimum = V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_UNUSED, - .maximum = V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_51, - .default_value = V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_51, + .maximum = V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61, + .default_value = V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61, .menu_skip_mask = 0, .qmenu = vp9_level, .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 6778c1734b8c..b2121e5dfb31 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -300,6 +300,10 @@ int msm_comm_hal_to_v4l2(int id, int value) return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_5; case HAL_VP9_LEVEL_51: return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_51; + case HAL_VP9_LEVEL_6: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_6; + case HAL_VP9_LEVEL_61: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61; case HAL_VP9_LEVEL_UNUSED: return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_UNUSED; default: diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h index 0efa9b88848a..083f6d5cc705 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h @@ -406,6 +406,8 @@ enum hal_vp9_level { HAL_VP9_LEVEL_41 = 0x00000080, HAL_VP9_LEVEL_5 = 0x00000100, HAL_VP9_LEVEL_51 = 0x00000200, + HAL_VP9_LEVEL_6 = 0x00000400, + HAL_VP9_LEVEL_61 = 0x00000800, }; struct hal_frame_rate { diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 85bdb5631399..2f226b145f7d 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -941,6 +941,12 @@ enum v4l2_mpeg_vidc_video_vp9_level { V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_41 = 8, V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_5 = 9, V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_51 = 10, +#define V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_6 \ + V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_6 + V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_6 = 11, +#define V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61 \ + V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61 + V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61 = 12, }; #define V4L2_CID_MPEG_VIDC_VIDEO_ADAPTIVE_B \ -- GitLab From db9b28b0f7d2d4c2a89263e7e22a7b65381c8326 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Thu, 16 Aug 2018 12:06:40 -0700 Subject: [PATCH 0979/1001] ARM: dts: msm: Update alium 3600mAh battery profile As per the battery characterization data, update alium 3600mAh battery profile which is used on SM8150 platforms. Change-Id: Idf19dc4bd21e714ef87033759231943cb508e89f Signed-off-by: Subbaraman Narayanamurthy --- .../fg-gen4-batterydata-alium-3600mah.dtsi | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-alium-3600mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-alium-3600mah.dtsi index 22a8d112a783..83efb69d4583 100644 --- a/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-alium-3600mah.dtsi +++ b/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-alium-3600mah.dtsi @@ -11,8 +11,8 @@ * GNU General Public License for more details. */ -qcom,alium_860_89032_0000_3600mah_averaged_masterslave_jun15th2018 { - /* #Alium_860_89032_0000_3600mAh_averaged_MasterSlave_Jun15th2018*/ +qcom,alium_860_89032_0000_3600mah_averaged_masterslave_aug6th2018 { + /* #Alium_860_89032_0000_3600mAh_averaged_MasterSlave_Aug6th2018*/ qcom,max-voltage-uv = <4350000>; qcom,fastchg-current-ma = <5400>; qcom,jeita-fcc-ranges = <0 100 2500000 @@ -28,29 +28,29 @@ qcom,alium_860_89032_0000_3600mah_averaged_masterslave_jun15th2018 { qcom,battery-beta = <4250>; qcom,therm-room-temp = <100000>; qcom,fg-cc-cv-threshold-mv = <4340>; - qcom,battery-type = "alium_860_89032_0000_3600mah_jun15th2018"; + qcom,battery-type = "alium_860_89032_0000_3600mah_aug6th2018"; qcom,therm-coefficients = <0x2318 0xd0c 0xdaf7 0xc556 0x848d>; qcom,therm-center-offset = <0x70>; qcom,therm-pull-up = <100>; qcom,rslow-normal-coeffs = <0xa4 0x01 0x24 0x13>; - qcom,rslow-low-coeffs = <0xa7 0xd5 0x0e 0x13>; - qcom,checksum = <0xCDFB>; - qcom,gui-version = "PM8150GUI - 1.0.0.7"; + qcom,rslow-low-coeffs = <0xa4 0x01 0x24 0x13>; + qcom,checksum = <0x99F7>; + qcom,gui-version = "PM855GUI - 1.0.0.10"; qcom,fg-profile-data = [ - 09 00 B5 EA - 3F CC 33 AA - E7 C2 00 00 - 13 BC 83 8A - 03 80 D1 92 - AB 9D 47 80 + 09 00 BD EA + 40 CC E8 BC + DD C3 00 00 + B0 C5 72 92 + F3 87 C8 A2 + E6 9C E2 87 18 00 A4 01 24 13 47 FD A9 F2 CE 07 - 32 00 A6 00 - EF F5 CB FD - 11 0D 4A 23 - 60 2A C1 23 - 6F 42 F8 43 + 32 00 0E E3 + 06 ED 2E EA + 83 FD 5B 14 + B8 1C 75 3A + 5C 42 CA 3A 40 00 3A 00 40 00 48 00 3B 00 34 00 -- GitLab From d43b69c4ad2a977406c84d47fe8a5261e0099e78 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Thu, 9 Aug 2018 17:19:54 -0700 Subject: [PATCH 0980/1001] sched/core: fix userspace affining threads incorrectly Certain userspace applications, to achieve max performance, affines its threads to cpus that run the fastest. This is not always the correct strategy. For e.g. in certain architectures all the cores have the same max freq but few of them have a bigger cache. Affining to the cpus that have bigger cache is advantageous but such an application would end up affining them to all the cores. Similarly if an architecture has just one cpu that runs at max freq, it ends up crowding all its thread on that single core, which is detrimental for performance. To address this issue, we need to detect a suspicious looking affinity request from userspace and check if it links in a particular library. The latter can easily be detected by traversing executable vm areas that map a file and checking for that library name. When such a affinity request is found, change it to use a proper affinity. The suspicious affinity request, the proper affinity request and the library name can be configured by the userspace. Change-Id: I6bb8c310ca54c03261cc721f28dfd6023ab5591a Signed-off-by: Abhijeet Dharmapurikar --- include/linux/sched.h | 1 + include/linux/sched/sysctl.h | 5 +++ kernel/compat.c | 2 +- kernel/sched/core.c | 67 +++++++++++++++++++++++++++++++++++- kernel/sysctl.c | 26 ++++++++++++++ 5 files changed, 99 insertions(+), 2 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 1b69ef2ef669..5885ead11231 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1918,6 +1918,7 @@ static inline void set_task_cpu(struct task_struct *p, unsigned int cpu) # define vcpu_is_preempted(cpu) false #endif +extern long msm_sched_setaffinity(pid_t pid, struct cpumask *new_mask); extern long sched_setaffinity(pid_t pid, const struct cpumask *new_mask); extern long sched_getaffinity(pid_t pid, struct cpumask *mask); diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h index 4a059b73eedf..d02fb9c24555 100644 --- a/include/linux/sched/sysctl.h +++ b/include/linux/sched/sysctl.h @@ -129,4 +129,9 @@ extern int sched_little_cluster_coloc_fmin_khz_handler(struct ctl_table *table, size_t *lenp, loff_t *ppos); #endif +#define LIB_PATH_LENGTH 512 +extern char sched_lib_name[LIB_PATH_LENGTH]; +extern unsigned int sched_lib_mask_check; +extern unsigned int sched_lib_mask_force; + #endif /* _LINUX_SCHED_SYSCTL_H */ diff --git a/kernel/compat.c b/kernel/compat.c index 7e83733d4c95..f3925fca9339 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -334,7 +334,7 @@ COMPAT_SYSCALL_DEFINE3(sched_setaffinity, compat_pid_t, pid, if (retval) goto out; - retval = sched_setaffinity(pid, new_mask); + retval = msm_sched_setaffinity(pid, new_mask); out: free_cpumask_var(new_mask); return retval; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index f46cf644af3c..05802cb35360 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -4910,6 +4910,71 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask) return retval; } +char sched_lib_name[LIB_PATH_LENGTH]; +unsigned int sched_lib_mask_check; +unsigned int sched_lib_mask_force; +static inline bool is_sched_lib_based_app(pid_t pid) +{ + const char *name = NULL; + struct vm_area_struct *vma; + char path_buf[LIB_PATH_LENGTH]; + bool found = false; + struct task_struct *p; + + if (strnlen(sched_lib_name, LIB_PATH_LENGTH) == 0) + return false; + + rcu_read_lock(); + + p = find_process_by_pid(pid); + if (!p) { + rcu_read_unlock(); + return false; + } + + /* Prevent p going away */ + get_task_struct(p); + rcu_read_unlock(); + + if (!p->mm) + goto put_task_struct; + + down_read(&p->mm->mmap_sem); + for (vma = p->mm->mmap; vma ; vma = vma->vm_next) { + if (vma->vm_file && vma->vm_flags & VM_EXEC) { + name = d_path(&vma->vm_file->f_path, + path_buf, LIB_PATH_LENGTH); + if (IS_ERR(name)) + goto release_sem; + + if (strnstr(name, sched_lib_name, + strnlen(name, LIB_PATH_LENGTH))) { + found = true; + break; + } + } + } + +release_sem: + up_read(&p->mm->mmap_sem); +put_task_struct: + put_task_struct(p); + return found; +} + +long msm_sched_setaffinity(pid_t pid, struct cpumask *new_mask) +{ + if (sched_lib_mask_check != 0 && sched_lib_mask_force != 0 && + (cpumask_bits(new_mask)[0] == sched_lib_mask_check) && + is_sched_lib_based_app(pid)) { + + cpumask_t forced_mask = { {sched_lib_mask_force} }; + + cpumask_copy(new_mask, &forced_mask); + } + return sched_setaffinity(pid, new_mask); +} + static int get_user_cpu_mask(unsigned long __user *user_mask_ptr, unsigned len, struct cpumask *new_mask) { @@ -4940,7 +5005,7 @@ SYSCALL_DEFINE3(sched_setaffinity, pid_t, pid, unsigned int, len, retval = get_user_cpu_mask(user_mask_ptr, len, new_mask); if (retval == 0) - retval = sched_setaffinity(pid, new_mask); + retval = msm_sched_setaffinity(pid, new_mask); free_cpumask_var(new_mask); return retval; } diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 3a4e11d61f87..9f36ed4be3a2 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -139,6 +139,7 @@ static int ten_thousand = 10000; #ifdef CONFIG_PERF_EVENTS static int six_hundred_forty_kb = 640 * 1024; #endif +static int two_hundred_fifty_five = 255; /* this is needed for the proc_doulongvec_minmax of vm_dirty_bytes */ static unsigned long dirty_bytes_min = 2 * PAGE_SIZE; @@ -578,6 +579,31 @@ static struct ctl_table kern_table[] = { .extra1 = &one, }, #endif + { + .procname = "sched_lib_name", + .data = sched_lib_name, + .maxlen = LIB_PATH_LENGTH, + .mode = 0644, + .proc_handler = proc_dostring, + }, + { + .procname = "sched_lib_mask_check", + .data = &sched_lib_mask_check, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_douintvec_minmax, + .extra1 = &zero, + .extra2 = &two_hundred_fifty_five, + }, + { + .procname = "sched_lib_mask_force", + .data = &sched_lib_mask_force, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_douintvec_minmax, + .extra1 = &zero, + .extra2 = &two_hundred_fifty_five, + }, #ifdef CONFIG_PROVE_LOCKING { .procname = "prove_locking", -- GitLab From 2ce74b94f8ca9f7176a50d845a49d94a0d9b08a6 Mon Sep 17 00:00:00 2001 From: Tony Truong Date: Wed, 1 Aug 2018 01:48:51 -0700 Subject: [PATCH 0981/1001] ARM: dts: msm: add RC sub-nodes under each PCIe node on sm8150 Add root complex (RC) sub-nodes under each PCIe node so that RC specific entries can be added and parsed from sm8150 devicetree. Change-Id: I083543d4bde0bf34b43ec76f2edae6122de04aa2 Signed-off-by: Tony Truong --- arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi | 1656 ++++++++++----------- arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi | 8 + 2 files changed, 834 insertions(+), 830 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi b/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi index 3479d30dbb70..86221703c855 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-mhi.dtsi @@ -11,840 +11,836 @@ * GNU General Public License for more details. */ -&pcie1 { - pci,bus@1 { - reg = <0 0 0 0 0>; - - mhi_0: qcom,mhi@0 { - reg = <0 0 0 0 0 >; - - /* controller specific configuration */ - qcom,smmu-cfg = <0x3>; - qcom,msm-bus,name = "mhi"; - qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - <100 512 0 0>, - <100 512 1200000000 650000000>; - - /* mhi bus specific settings */ - mhi,max-channels = <106>; - mhi,timeout = <2000>; - - #address-cells = <1>; - #size-cells = <0>; - - mhi_chan@0 { - reg = <0>; - label = "LOOPBACK"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@1 { - reg = <1>; - label = "LOOPBACK"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@2 { - reg = <2>; - label = "SAHARA"; - mhi,num-elements = <128>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x2>; - }; - - mhi_chan@3 { - reg = <3>; - label = "SAHARA"; - mhi,num-elements = <128>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x2>; - }; - - mhi_chan@4 { - reg = <4>; - label = "DIAG"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@5 { - reg = <5>; - label = "DIAG"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@8 { - reg = <8>; - label = "QDSS"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@9 { - reg = <9>; - label = "QDSS"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@10 { - reg = <10>; - label = "EFS"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@11 { - reg = <11>; - label = "EFS"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@14 { - reg = <14>; - label = "QMI0"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@15 { - reg = <15>; - label = "QMI0"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@16 { - reg = <16>; - label = "QMI1"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@17 { - reg = <17>; - label = "QMI1"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@18 { - reg = <18>; - label = "IP_CTRL"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@19 { - reg = <19>; - label = "IP_CTRL"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - mhi,auto-queue; - }; - - mhi_chan@20 { - reg = <20>; - label = "IPCR"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <1>; - mhi,data-type = <1>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - mhi,auto-start; - }; - - mhi_chan@21 { - reg = <21>; - label = "IPCR"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - mhi,auto-queue; - mhi,auto-start; - }; - - mhi_chan@22 { - reg = <22>; - label = "TF"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@23 { - reg = <23>; - label = "TF"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@25 { - reg = <25>; - label = "BL"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x2>; - mhi,auto-queue; - mhi,auto-start; - }; - - mhi_chan@26 { - reg = <26>; - label = "DCI"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@27 { - reg = <27>; - label = "DCI"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@32 { - reg = <32>; - label = "DUN"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@33 { - reg = <33>; - label = "DUN"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@100 { - reg = <100>; - label = "IP_HW0"; - mhi,num-elements = <512>; - mhi,event-ring = <4>; - mhi,chan-dir = <1>; - mhi,data-type = <1>; - mhi,doorbell-mode = <3>; - mhi,ee = <0x4>; - mhi,db-mode-switch; - }; - - mhi_chan@101 { - reg = <101>; - label = "IP_HW0"; - mhi,num-elements = <512>; - mhi,event-ring = <5>; - mhi,chan-dir = <2>; - mhi,data-type = <1>; - mhi,doorbell-mode = <3>; - mhi,ee = <0x4>; - }; - - mhi_chan@104 { - reg = <104>; - label = "IP_HW_OFFLOAD_0"; - mhi,event-ring = <4>; - mhi,chan-dir = <1>; - mhi,data-type = <3>; - mhi,ee = <0x4>; - mhi,offload-chan; - }; - - mhi_chan@105 { - reg = <105>; - label = "IP_HW_OFFLOAD_0"; - mhi,event-ring = <5>; - mhi,chan-dir = <2>; - mhi,data-type = <3>; - mhi,ee = <0x4>; - mhi,offload-chan; - mhi,lpm-notify; - }; - - mhi_event@0 { - mhi,num-elements = <32>; - mhi,intmod = <1>; - mhi,msi = <1>; - mhi,priority = <1>; - mhi,brstmode = <2>; - mhi,data-type = <1>; - }; - - mhi_event@1 { - mhi,num-elements = <256>; - mhi,intmod = <1>; - mhi,msi = <2>; - mhi,priority = <1>; - mhi,brstmode = <2>; - }; - - mhi_event@2 { - mhi,num-elements = <256>; - mhi,intmod = <1>; - mhi,msi = <3>; - mhi,priority = <1>; - mhi,brstmode = <2>; - }; - - mhi_event@3 { - mhi,num-elements = <256>; - mhi,intmod = <1>; - mhi,msi = <4>; - mhi,priority = <1>; - mhi,brstmode = <2>; - }; - - mhi_event@4 { - mhi,num-elements = <1024>; - mhi,intmod = <5>; - mhi,msi = <5>; - mhi,chan = <100>; - mhi,priority = <1>; - mhi,brstmode = <3>; - mhi,hw-ev; - }; - - mhi_event@5 { - mhi,num-elements = <1024>; - mhi,intmod = <5>; - mhi,msi = <6>; - mhi,chan = <101>; - mhi,priority = <1>; - mhi,brstmode = <3>; - mhi,hw-ev; - mhi,client-manage; - }; - - mhi_netdev_0: mhi_rmnet@0 { - reg = <0x0>; - mhi,chan = "IP_HW0"; - mhi,interface-name = "rmnet_mhi"; - mhi,mru = <0x4000>; - }; - - mhi_netdev_1: mhi_rmnet@1 { - reg = <0x1>; - mhi,chan = "IP_HW_ADPL"; - mhi,interface-name = "rmnet_mhi"; - mhi,mru = <0x4000>; - }; +&pcie_rc1 { + reg = <0 0 0 0 0>; + + mhi_0: qcom,mhi@0 { + reg = <0 0 0 0 0 >; + + /* controller specific configuration */ + qcom,smmu-cfg = <0x3>; + qcom,msm-bus,name = "mhi"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <100 512 0 0>, + <100 512 1200000000 650000000>; + + /* mhi bus specific settings */ + mhi,max-channels = <106>; + mhi,timeout = <2000>; + + #address-cells = <1>; + #size-cells = <0>; + + mhi_chan@0 { + reg = <0>; + label = "LOOPBACK"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@1 { + reg = <1>; + label = "LOOPBACK"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@2 { + reg = <2>; + label = "SAHARA"; + mhi,num-elements = <128>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x2>; + }; + + mhi_chan@3 { + reg = <3>; + label = "SAHARA"; + mhi,num-elements = <128>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x2>; + }; + + mhi_chan@4 { + reg = <4>; + label = "DIAG"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@5 { + reg = <5>; + label = "DIAG"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@8 { + reg = <8>; + label = "QDSS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@9 { + reg = <9>; + label = "QDSS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@10 { + reg = <10>; + label = "EFS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@11 { + reg = <11>; + label = "EFS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@14 { + reg = <14>; + label = "QMI0"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@15 { + reg = <15>; + label = "QMI0"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@16 { + reg = <16>; + label = "QMI1"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@17 { + reg = <17>; + label = "QMI1"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@18 { + reg = <18>; + label = "IP_CTRL"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@19 { + reg = <19>; + label = "IP_CTRL"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + mhi,auto-queue; + }; + + mhi_chan@20 { + reg = <20>; + label = "IPCR"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <1>; + mhi,data-type = <1>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + mhi,auto-start; + }; + + mhi_chan@21 { + reg = <21>; + label = "IPCR"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + mhi,auto-queue; + mhi,auto-start; + }; + + mhi_chan@22 { + reg = <22>; + label = "TF"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@23 { + reg = <23>; + label = "TF"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@25 { + reg = <25>; + label = "BL"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x2>; + mhi,auto-queue; + mhi,auto-start; + }; + + mhi_chan@26 { + reg = <26>; + label = "DCI"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@27 { + reg = <27>; + label = "DCI"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@32 { + reg = <32>; + label = "DUN"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@33 { + reg = <33>; + label = "DUN"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@100 { + reg = <100>; + label = "IP_HW0"; + mhi,num-elements = <512>; + mhi,event-ring = <4>; + mhi,chan-dir = <1>; + mhi,data-type = <1>; + mhi,doorbell-mode = <3>; + mhi,ee = <0x4>; + mhi,db-mode-switch; + }; + + mhi_chan@101 { + reg = <101>; + label = "IP_HW0"; + mhi,num-elements = <512>; + mhi,event-ring = <5>; + mhi,chan-dir = <2>; + mhi,data-type = <1>; + mhi,doorbell-mode = <3>; + mhi,ee = <0x4>; + }; + + mhi_chan@104 { + reg = <104>; + label = "IP_HW_OFFLOAD_0"; + mhi,event-ring = <4>; + mhi,chan-dir = <1>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + }; + + mhi_chan@105 { + reg = <105>; + label = "IP_HW_OFFLOAD_0"; + mhi,event-ring = <5>; + mhi,chan-dir = <2>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + mhi,lpm-notify; + }; + + mhi_event@0 { + mhi,num-elements = <32>; + mhi,intmod = <1>; + mhi,msi = <1>; + mhi,priority = <1>; + mhi,brstmode = <2>; + mhi,data-type = <1>; + }; + + mhi_event@1 { + mhi,num-elements = <256>; + mhi,intmod = <1>; + mhi,msi = <2>; + mhi,priority = <1>; + mhi,brstmode = <2>; + }; + + mhi_event@2 { + mhi,num-elements = <256>; + mhi,intmod = <1>; + mhi,msi = <3>; + mhi,priority = <1>; + mhi,brstmode = <2>; + }; + + mhi_event@3 { + mhi,num-elements = <256>; + mhi,intmod = <1>; + mhi,msi = <4>; + mhi,priority = <1>; + mhi,brstmode = <2>; + }; + + mhi_event@4 { + mhi,num-elements = <1024>; + mhi,intmod = <5>; + mhi,msi = <5>; + mhi,chan = <100>; + mhi,priority = <1>; + mhi,brstmode = <3>; + mhi,hw-ev; + }; + + mhi_event@5 { + mhi,num-elements = <1024>; + mhi,intmod = <5>; + mhi,msi = <6>; + mhi,chan = <101>; + mhi,priority = <1>; + mhi,brstmode = <3>; + mhi,hw-ev; + mhi,client-manage; + }; + + mhi_netdev_0: mhi_rmnet@0 { + reg = <0x0>; + mhi,chan = "IP_HW0"; + mhi,interface-name = "rmnet_mhi"; + mhi,mru = <0x4000>; + }; + + mhi_netdev_1: mhi_rmnet@1 { + reg = <0x1>; + mhi,chan = "IP_HW_ADPL"; + mhi,interface-name = "rmnet_mhi"; + mhi,mru = <0x4000>; }; }; }; -&pcie0 { - pci,bus@1 { - reg = <0 0 0 0 0>; - - mhi_1: qcom,mhi@0 { - reg = <0 0 0 0 0 >; - - /* controller specific configuration */ - qcom,smmu-cfg = <0x3>; - qcom,msm-bus,name = "mhi"; - qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - <45 512 0 0>, - <45 512 1200000000 650000000>; - - /* mhi bus specific settings */ - mhi,max-channels = <106>; - mhi,timeout = <2000>; - - #address-cells = <1>; - #size-cells = <0>; - - mhi_chan@0 { - reg = <0>; - label = "LOOPBACK"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@1 { - reg = <1>; - label = "LOOPBACK"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@2 { - reg = <2>; - label = "SAHARA"; - mhi,num-elements = <128>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x2>; - }; - - mhi_chan@3 { - reg = <3>; - label = "SAHARA"; - mhi,num-elements = <128>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x2>; - }; - - mhi_chan@4 { - reg = <4>; - label = "DIAG"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@5 { - reg = <5>; - label = "DIAG"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@8 { - reg = <8>; - label = "QDSS"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@9 { - reg = <9>; - label = "QDSS"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@10 { - reg = <10>; - label = "EFS"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@11 { - reg = <11>; - label = "EFS"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@14 { - reg = <14>; - label = "QMI0"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@15 { - reg = <15>; - label = "QMI0"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@16 { - reg = <16>; - label = "QMI1"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@17 { - reg = <17>; - label = "QMI1"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@18 { - reg = <18>; - label = "IP_CTRL"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@19 { - reg = <19>; - label = "IP_CTRL"; - mhi,num-elements = <64>; - mhi,event-ring = <1>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - mhi,auto-queue; - }; - - mhi_chan@20 { - reg = <20>; - label = "IPCR"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <1>; - mhi,data-type = <1>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - mhi,auto-start; - }; - - mhi_chan@21 { - reg = <21>; - label = "IPCR"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - mhi,auto-queue; - mhi,auto-start; - }; - - mhi_chan@22 { - reg = <22>; - label = "TF"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@23 { - reg = <23>; - label = "TF"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@25 { - reg = <25>; - label = "BL"; - mhi,num-elements = <64>; - mhi,event-ring = <2>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x2>; - mhi,auto-queue; - mhi,auto-start; - }; - - mhi_chan@26 { - reg = <26>; - label = "DCI"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@27 { - reg = <27>; - label = "DCI"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@32 { - reg = <32>; - label = "DUN"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <1>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@33 { - reg = <33>; - label = "DUN"; - mhi,num-elements = <64>; - mhi,event-ring = <3>; - mhi,chan-dir = <2>; - mhi,data-type = <0>; - mhi,doorbell-mode = <2>; - mhi,ee = <0x4>; - }; - - mhi_chan@100 { - reg = <100>; - label = "IP_HW0"; - mhi,num-elements = <512>; - mhi,event-ring = <4>; - mhi,chan-dir = <1>; - mhi,data-type = <1>; - mhi,doorbell-mode = <3>; - mhi,ee = <0x4>; - mhi,db-mode-switch; - }; - - mhi_chan@101 { - reg = <101>; - label = "IP_HW0"; - mhi,num-elements = <512>; - mhi,event-ring = <5>; - mhi,chan-dir = <2>; - mhi,data-type = <1>; - mhi,doorbell-mode = <3>; - mhi,ee = <0x4>; - }; - - mhi_chan@104 { - reg = <104>; - label = "IP_HW_OFFLOAD_0"; - mhi,event-ring = <4>; - mhi,chan-dir = <1>; - mhi,data-type = <3>; - mhi,ee = <0x4>; - mhi,offload-chan; - }; - - mhi_chan@105 { - reg = <105>; - label = "IP_HW_OFFLOAD_0"; - mhi,event-ring = <5>; - mhi,chan-dir = <2>; - mhi,data-type = <3>; - mhi,ee = <0x4>; - mhi,offload-chan; - mhi,lpm-notify; - }; - - mhi_event@0 { - mhi,num-elements = <32>; - mhi,intmod = <1>; - mhi,msi = <1>; - mhi,priority = <1>; - mhi,brstmode = <2>; - mhi,data-type = <1>; - }; - - mhi_event@1 { - mhi,num-elements = <256>; - mhi,intmod = <1>; - mhi,msi = <2>; - mhi,priority = <1>; - mhi,brstmode = <2>; - }; - - mhi_event@2 { - mhi,num-elements = <256>; - mhi,intmod = <1>; - mhi,msi = <3>; - mhi,priority = <1>; - mhi,brstmode = <2>; - }; - - mhi_event@3 { - mhi,num-elements = <256>; - mhi,intmod = <1>; - mhi,msi = <4>; - mhi,priority = <1>; - mhi,brstmode = <2>; - }; - - mhi_event@4 { - mhi,num-elements = <1024>; - mhi,intmod = <5>; - mhi,msi = <5>; - mhi,chan = <100>; - mhi,priority = <1>; - mhi,brstmode = <3>; - mhi,hw-ev; - }; - - mhi_event@5 { - mhi,num-elements = <1024>; - mhi,intmod = <5>; - mhi,msi = <6>; - mhi,chan = <101>; - mhi,priority = <1>; - mhi,brstmode = <3>; - mhi,hw-ev; - mhi,client-manage; - }; - - mhi_netdev_2: mhi_rmnet@0 { - reg = <0x0>; - mhi,chan = "IP_HW0"; - mhi,interface-name = "rmnet_mhi"; - mhi,mru = <0x4000>; - }; - - mhi_netdev_3: mhi_rmnet@1 { - reg = <0x1>; - mhi,chan = "IP_HW_ADPL"; - mhi,interface-name = "rmnet_mhi"; - mhi,mru = <0x4000>; - }; +&pcie_rc0 { + reg = <0 0 0 0 0>; + + mhi_1: qcom,mhi@0 { + reg = <0 0 0 0 0 >; + + /* controller specific configuration */ + qcom,smmu-cfg = <0x3>; + qcom,msm-bus,name = "mhi"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <45 512 0 0>, + <45 512 1200000000 650000000>; + + /* mhi bus specific settings */ + mhi,max-channels = <106>; + mhi,timeout = <2000>; + + #address-cells = <1>; + #size-cells = <0>; + + mhi_chan@0 { + reg = <0>; + label = "LOOPBACK"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@1 { + reg = <1>; + label = "LOOPBACK"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@2 { + reg = <2>; + label = "SAHARA"; + mhi,num-elements = <128>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x2>; + }; + + mhi_chan@3 { + reg = <3>; + label = "SAHARA"; + mhi,num-elements = <128>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x2>; + }; + + mhi_chan@4 { + reg = <4>; + label = "DIAG"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@5 { + reg = <5>; + label = "DIAG"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@8 { + reg = <8>; + label = "QDSS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@9 { + reg = <9>; + label = "QDSS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@10 { + reg = <10>; + label = "EFS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@11 { + reg = <11>; + label = "EFS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@14 { + reg = <14>; + label = "QMI0"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@15 { + reg = <15>; + label = "QMI0"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@16 { + reg = <16>; + label = "QMI1"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@17 { + reg = <17>; + label = "QMI1"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@18 { + reg = <18>; + label = "IP_CTRL"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@19 { + reg = <19>; + label = "IP_CTRL"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + mhi,auto-queue; + }; + + mhi_chan@20 { + reg = <20>; + label = "IPCR"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <1>; + mhi,data-type = <1>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + mhi,auto-start; + }; + + mhi_chan@21 { + reg = <21>; + label = "IPCR"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + mhi,auto-queue; + mhi,auto-start; + }; + + mhi_chan@22 { + reg = <22>; + label = "TF"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@23 { + reg = <23>; + label = "TF"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@25 { + reg = <25>; + label = "BL"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x2>; + mhi,auto-queue; + mhi,auto-start; + }; + + mhi_chan@26 { + reg = <26>; + label = "DCI"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@27 { + reg = <27>; + label = "DCI"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@32 { + reg = <32>; + label = "DUN"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@33 { + reg = <33>; + label = "DUN"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@100 { + reg = <100>; + label = "IP_HW0"; + mhi,num-elements = <512>; + mhi,event-ring = <4>; + mhi,chan-dir = <1>; + mhi,data-type = <1>; + mhi,doorbell-mode = <3>; + mhi,ee = <0x4>; + mhi,db-mode-switch; + }; + + mhi_chan@101 { + reg = <101>; + label = "IP_HW0"; + mhi,num-elements = <512>; + mhi,event-ring = <5>; + mhi,chan-dir = <2>; + mhi,data-type = <1>; + mhi,doorbell-mode = <3>; + mhi,ee = <0x4>; + }; + + mhi_chan@104 { + reg = <104>; + label = "IP_HW_OFFLOAD_0"; + mhi,event-ring = <4>; + mhi,chan-dir = <1>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + }; + + mhi_chan@105 { + reg = <105>; + label = "IP_HW_OFFLOAD_0"; + mhi,event-ring = <5>; + mhi,chan-dir = <2>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + mhi,lpm-notify; + }; + + mhi_event@0 { + mhi,num-elements = <32>; + mhi,intmod = <1>; + mhi,msi = <1>; + mhi,priority = <1>; + mhi,brstmode = <2>; + mhi,data-type = <1>; + }; + + mhi_event@1 { + mhi,num-elements = <256>; + mhi,intmod = <1>; + mhi,msi = <2>; + mhi,priority = <1>; + mhi,brstmode = <2>; + }; + + mhi_event@2 { + mhi,num-elements = <256>; + mhi,intmod = <1>; + mhi,msi = <3>; + mhi,priority = <1>; + mhi,brstmode = <2>; + }; + + mhi_event@3 { + mhi,num-elements = <256>; + mhi,intmod = <1>; + mhi,msi = <4>; + mhi,priority = <1>; + mhi,brstmode = <2>; + }; + + mhi_event@4 { + mhi,num-elements = <1024>; + mhi,intmod = <5>; + mhi,msi = <5>; + mhi,chan = <100>; + mhi,priority = <1>; + mhi,brstmode = <3>; + mhi,hw-ev; + }; + + mhi_event@5 { + mhi,num-elements = <1024>; + mhi,intmod = <5>; + mhi,msi = <6>; + mhi,chan = <101>; + mhi,priority = <1>; + mhi,brstmode = <3>; + mhi,hw-ev; + mhi,client-manage; + }; + + mhi_netdev_2: mhi_rmnet@0 { + reg = <0x0>; + mhi,chan = "IP_HW0"; + mhi,interface-name = "rmnet_mhi"; + mhi,mru = <0x4000>; + }; + + mhi_netdev_3: mhi_rmnet@1 { + reg = <0x1>; + mhi,chan = "IP_HW_ADPL"; + mhi,interface-name = "rmnet_mhi"; + mhi,mru = <0x4000>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi b/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi index f11fc041bd2b..3c48494c30d2 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi @@ -282,6 +282,10 @@ reset-names = "pcie_0_core_reset", "pcie_0_phy_reset"; + + pcie_rc0: pcie_rc0 { + reg = <0 0 0 0 0>; + }; }; pcie1: qcom,pcie@1c08000 { @@ -602,5 +606,9 @@ reset-names = "pcie_1_core_reset", "pcie_1_phy_reset"; + + pcie_rc1: pcie_rc1 { + reg = <0 0 0 0 0>; + }; }; }; -- GitLab From 9986db286a41121a0eaedc87b38a140517a65952 Mon Sep 17 00:00:00 2001 From: Jilai Wang Date: Thu, 23 Aug 2018 14:43:49 -0400 Subject: [PATCH 0982/1001] ARM: dts: msm: Update NPU clock frequency settings for sm8150 v2 Add one power level to increase the total power level count to 6 and update clock frequency settings in each power level. Change-Id: Id5afed77a23242b8eb83f7917ecfad7eb44a6c27 Signed-off-by: Jilai Wang --- arch/arm64/boot/dts/qcom/sm8150-v2.dtsi | 32 +++++++++++++++++++++---- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi b/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi index dc2b32403ffb..32748b4672d1 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi @@ -437,7 +437,7 @@ #address-cells = <1>; #size-cells = <0>; compatible = "qcom,npu-pwrlevels"; - initial-pwrlevel = <3>; + initial-pwrlevel = <5>; qcom,npu-pwrlevel@0 { reg = <0>; clk-freq = <300000000 @@ -509,12 +509,12 @@ }; qcom,npu-pwrlevel@3 { reg = <3>; - clk-freq = <773000000 + clk-freq = <652000000 19200000 300000000 19200000 19200000 - 773000000 + 652000000 403000000 75000000 19200000 @@ -523,7 +523,7 @@ 150000000 300000000 19200000 - 773000000 + 652000000 19200000 0 0 @@ -532,6 +532,29 @@ }; qcom,npu-pwrlevel@4 { reg = <4>; + clk-freq = <811000000 + 19200000 + 400000000 + 19200000 + 19200000 + 811000000 + 533000000 + 75000000 + 19200000 + 300000000 + 400000000 + 150000000 + 400000000 + 19200000 + 811000000 + 19200000 + 0 + 0 + 0 + 0>; + }; + qcom,npu-pwrlevel@5 { + reg = <5>; clk-freq = <908000000 19200000 400000000 @@ -553,7 +576,6 @@ 0 0>; }; - /delete-node/ qcom,npu-pwrlevel@5; }; }; -- GitLab From 075045401075126d7a44b9846d65b214eddb8905 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Sun, 26 Aug 2018 08:52:32 +0300 Subject: [PATCH 0983/1001] msm_11ad: use %pK to avoid kernel address information leak Use %pK instead of plain %p to avoid leaking of kernel addresses to userspace. Change-Id: Ie870cc2df07c45ba04140fd51d52b5e28cc8df41 Signed-off-by: Maya Erez --- drivers/platform/msm/msm_11ad/msm_11ad.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/platform/msm/msm_11ad/msm_11ad.c b/drivers/platform/msm/msm_11ad/msm_11ad.c index 14c88122c808..9b0c3bda787f 100644 --- a/drivers/platform/msm/msm_11ad/msm_11ad.c +++ b/drivers/platform/msm/msm_11ad/msm_11ad.c @@ -780,7 +780,7 @@ static int msm_11ad_smmu_init(struct msm11ad_ctx *ctx) static int msm_11ad_ssr_shutdown(const struct subsys_desc *subsys, bool force_stop) { - pr_info("%s(%p,%d)\n", __func__, subsys, force_stop); + pr_info("%s(%pK,%d)\n", __func__, subsys, force_stop); /* nothing is done in shutdown. We do full recovery in powerup */ return 0; } @@ -791,7 +791,7 @@ static int msm_11ad_ssr_powerup(const struct subsys_desc *subsys) struct platform_device *pdev; struct msm11ad_ctx *ctx; - pr_info("%s(%p)\n", __func__, subsys); + pr_info("%s(%pK)\n", __func__, subsys); pdev = to_platform_device(subsys->dev); ctx = platform_get_drvdata(pdev); @@ -1185,12 +1185,12 @@ static int msm_11ad_probe(struct platform_device *pdev) msm_11ad_init_cpu_boost(ctx); /* report */ - dev_info(ctx->dev, "msm_11ad discovered. %p {\n" + dev_info(ctx->dev, "msm_11ad discovered. %pK {\n" " gpio_en = %d\n" " sleep_clk_en = %d\n" " rc_index = %d\n" " use_smmu = %d\n" - " pcidev = %p\n" + " pcidev = %pK\n" "}\n", ctx, ctx->gpio_en, ctx->sleep_clk_en, ctx->rc_index, ctx->use_smmu, ctx->pcidev); @@ -1227,7 +1227,7 @@ static int msm_11ad_remove(struct platform_device *pdev) msm_11ad_ssr_deinit(ctx); list_del(&ctx->list); - dev_info(ctx->dev, "%s: pdev %p pcidev %p\n", __func__, pdev, + dev_info(ctx->dev, "%s: pdev %pK pcidev %pK\n", __func__, pdev, ctx->pcidev); kfree(ctx->pristine_state); @@ -1490,7 +1490,7 @@ void *msm_11ad_dev_init(struct device *dev, struct wil_platform_ops *ops, struct msm11ad_ctx *ctx = pcidev2ctx(pcidev); if (!ctx) { - pr_err("Context not found for pcidev %p\n", pcidev); + pr_err("Context not found for pcidev %pK\n", pcidev); return NULL; } -- GitLab From fd72c45386b0bc0505b82a7c19096cc0ca871e84 Mon Sep 17 00:00:00 2001 From: Pratham Pratap Date: Thu, 16 Aug 2018 19:39:00 +0530 Subject: [PATCH 0984/1001] usb: phy: qmp: Add portselect for USB3 only phy This change adds portselect for USB3 only phy and changes the offset of MISC_TYPEC_CTRL register. Change-Id: I706f87493ca478455db7077af653b66d565ee5f6 Signed-off-by: Pratham Pratap --- drivers/usb/phy/phy-msm-ssusb-qmp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c index 1f481c2b4001..bb1575b0faea 100644 --- a/drivers/usb/phy/phy-msm-ssusb-qmp.c +++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c @@ -92,6 +92,9 @@ enum qmp_phy_rev_reg { USB3_PHY_SW_RESET, USB3_PHY_START, + /* TypeC port select configuration (optional) */ + USB3_PHY_PCS_MISC_TYPEC_CTRL, + /* USB DP Combo PHY related */ USB3_DP_DP_PHY_PD_CTL, USB3_DP_COM_POWER_DOWN_CTRL, @@ -104,8 +107,6 @@ enum qmp_phy_rev_reg { USB3_DP_PCS_PCS_STATUS2, USB3_DP_PCS_INSIG_SW_CTRL3, USB3_DP_PCS_INSIG_MX_CTRL3, - /* TypeC port select configuration (optional) */ - USB3_PHY_PCS_MISC_TYPEC_CTRL, USB3_PHY_REG_MAX, }; @@ -393,6 +394,7 @@ static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy) phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]); break; case USB_PHY_TYPE_USB3_OR_DP: + case USB_PHY_TYPE_USB3: if (val > 0) { dev_err(phy->phy.dev, "USB QMP PHY: Update TYPEC CTRL(%d)\n", val); -- GitLab From 0d64b70cef97ce0bd49b7591d69c8deea4eb9219 Mon Sep 17 00:00:00 2001 From: Raghavendra Kakarla Date: Tue, 21 Aug 2018 16:24:01 +0530 Subject: [PATCH 0985/1001] drivers: pinctrl: Check whether irq mapping exists before creating it Calling to create mapping without checking if mapping already exists leads to loop to all available domains to get the corresponding domain and then checks for available mapping. Client driver calling gpio_to_irq from atomic context may get sleeping function called from invalid context. Add a check to see if irq mapping exist before creating it. Change-Id: If922b06448138107d5c797f35d2835b20a490ada Signed-off-by: Raghavendra Kakarla --- drivers/pinctrl/qcom/pinctrl-msm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index ed11b59348fb..fef0970abaf2 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -1390,6 +1390,12 @@ static void msm_gpio_setup_dir_connects(struct msm_pinctrl *pctrl) static int msm_gpiochip_to_irq(struct gpio_chip *chip, unsigned int offset) { struct irq_fwspec fwspec; + struct irq_domain *domain = chip->irqdomain; + int virq; + + virq = irq_find_mapping(domain, offset); + if (virq) + return virq; fwspec.fwnode = of_node_to_fwnode(chip->of_node); fwspec.param[0] = offset; -- GitLab From cdac23da45a1404a364e0c2b608a6b41c6bacff5 Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Thu, 23 Aug 2018 11:01:26 +0530 Subject: [PATCH 0986/1001] ARM: dts: msm: Disable QoS programming for SM6150 Disable QoS programming on SM6150 for now, will be enabled back after proper access control settings are enabled. Bus driver requires to set the QoS parameters like QoS mode and priorities, so enable the QoS parameter programming. Change-Id: I87e5530a7f94da68e27a02c858baf7fdf4b6af5b Signed-off-by: Odelu Kukatla --- arch/arm64/boot/dts/qcom/sm6150-bus.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi b/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi index 8858acb6e6d4..c216c45afd35 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi @@ -308,6 +308,7 @@ qcom,qos-off = <4096>; qcom,base-offset = <16384>; qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; qcom,bus-type = <1>; clocks = <>; }; @@ -358,6 +359,7 @@ qcom,qos-off = <128>; qcom,base-offset = <176128>; qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; qcom,bus-type = <1>; clocks = <>; }; @@ -394,6 +396,7 @@ qcom,qos-off = <4096>; qcom,base-offset = <36864>; qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; qcom,bus-type = <1>; clocks = <>; }; @@ -407,6 +410,7 @@ qcom,base-offset = <45056>; qcom,sbm-offset = <0>; qcom,bus-type = <1>; + qcom,bypass-qos-prg; clocks = <>; }; -- GitLab From 5564205c61d7f41473971985cc9724f838102d8a Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Thu, 16 Aug 2018 14:52:04 +0530 Subject: [PATCH 0987/1001] diag: Prevent out of bound access while initializing msg mask Move the mask_info mutex initialization outside mask structure to facilitate prevention of out of bound access while initializing msg mask during md session creation. Use separate msg_mask_tbl_count for ODL session msg mask and regular msg mask to prevent out of bound access in a possible race condition of accessing mask ranges. Change-Id: I87497c67daff8cc1797a1266d50456bdbd3a9c23 Signed-off-by: Manoj Prabhu B --- drivers/char/diag/diag_masks.c | 84 +++++++++++++++++++++++-------- drivers/char/diag/diag_masks.h | 7 +-- drivers/char/diag/diagchar.h | 1 + drivers/char/diag/diagchar_core.c | 13 +++-- 4 files changed, 78 insertions(+), 27 deletions(-) diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index 39e4933a0fdc..4fd21d8327cc 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -336,12 +336,13 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) int header_len = sizeof(struct diag_ctrl_msg_mask); uint8_t *buf = NULL, *temp = NULL; uint8_t upd = 0; - uint8_t msg_mask_tbl_count_local; + uint8_t msg_mask_tbl_count_local = 0; uint32_t mask_size = 0, pd_mask = 0; struct diag_mask_info *mask_info = NULL; struct diag_msg_mask_t *mask = NULL; struct diag_ctrl_msg_mask header; struct diagfwd_info *fwd_info = NULL; + struct diag_md_session_t *md_session_info = NULL; if (peripheral >= NUM_PERIPHERALS) return; @@ -357,14 +358,19 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) if (driver->md_session_mask != 0) { if (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)) { - if (driver->md_session_map[peripheral]) + if (driver->md_session_map[peripheral]) { mask_info = driver->md_session_map[peripheral]->msg_mask; + md_session_info = + driver->md_session_map[peripheral]; + } } else if (driver->md_session_mask & pd_mask) { upd = diag_mask_to_pd_value(driver->md_session_mask); - if (upd && driver->md_session_map[upd]) + if (upd && driver->md_session_map[upd]) { mask_info = driver->md_session_map[upd]->msg_mask; + md_session_info = driver->md_session_map[upd]; + } } else { DIAG_LOG(DIAG_DEBUG_MASKS, "asking for mask update with unknown session mask\n"); @@ -383,7 +389,10 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) return; } buf = mask_info->update_buf; - msg_mask_tbl_count_local = driver->msg_mask_tbl_count; + if (md_session_info) + msg_mask_tbl_count_local = md_session_info->msg_mask_tbl_count; + else + msg_mask_tbl_count_local = driver->msg_mask_tbl_count; mutex_unlock(&driver->msg_mask_lock); mutex_lock(&mask_info->lock); switch (mask_info->status) { @@ -565,6 +574,7 @@ static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len, { int i; int write_len = 0; + uint8_t msg_mask_tbl_count = 0; struct diag_msg_mask_t *mask_ptr = NULL; struct diag_msg_ssid_query_t rsp; struct diag_ssid_range_t ssid_range; @@ -594,15 +604,17 @@ static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len, return 0; } mutex_lock(&driver->msg_mask_lock); + msg_mask_tbl_count = (info) ? info->msg_mask_tbl_count : + driver->msg_mask_tbl_count; rsp.cmd_code = DIAG_CMD_MSG_CONFIG; rsp.sub_cmd = DIAG_CMD_OP_GET_SSID_RANGE; rsp.status = MSG_STATUS_SUCCESS; rsp.padding = 0; - rsp.count = driver->msg_mask_tbl_count; + rsp.count = msg_mask_tbl_count; memcpy(dest_buf, &rsp, sizeof(rsp)); write_len += sizeof(rsp); mask_ptr = (struct diag_msg_mask_t *)mask_info->ptr; - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask_ptr++) { + for (i = 0; i < msg_mask_tbl_count; i++, mask_ptr++) { if (write_len + sizeof(ssid_range) > dest_len) { pr_err("diag: In %s, Truncating response due to size limitations of rsp buffer\n", __func__); @@ -679,6 +691,7 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, int i; int write_len = 0; uint32_t mask_size = 0; + uint8_t msg_mask_tbl_count = 0; struct diag_msg_mask_t *mask = NULL; struct diag_build_mask_req_t *req = NULL; struct diag_msg_build_mask_t rsp; @@ -709,6 +722,8 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, } mutex_lock(&driver->msg_mask_lock); + msg_mask_tbl_count = (info) ? info->msg_mask_tbl_count : + driver->msg_mask_tbl_count; req = (struct diag_build_mask_req_t *)src_buf; rsp.cmd_code = DIAG_CMD_MSG_CONFIG; rsp.sub_cmd = DIAG_CMD_OP_GET_MSG_MASK; @@ -724,7 +739,7 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, mutex_unlock(&driver->md_session_lock); return -EINVAL; } - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + for (i = 0; i < msg_mask_tbl_count; i++, mask++) { if (!mask->ptr) continue; if ((req->ssid_first < mask->ssid_first) || @@ -760,6 +775,7 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, struct diag_mask_info *mask_info = NULL; struct diag_msg_mask_t *mask_next = NULL; struct diag_md_session_t *info = NULL; + uint8_t msg_mask_tbl_count = 0; mutex_lock(&driver->md_session_lock); info = diag_md_session_get_pid(pid); @@ -792,10 +808,12 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, mutex_unlock(&driver->md_session_lock); return -EINVAL; } - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + msg_mask_tbl_count = (info) ? info->msg_mask_tbl_count : + driver->msg_mask_tbl_count; + for (i = 0; i < msg_mask_tbl_count; i++, mask++) { if (!mask->ptr) continue; - if (i < (driver->msg_mask_tbl_count - 1)) { + if (i < (msg_mask_tbl_count - 1)) { mask_next = mask; mask_next++; } else @@ -905,6 +923,7 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, struct diag_msg_mask_t *mask = NULL; struct diag_mask_info *mask_info = NULL; struct diag_md_session_t *info = NULL; + uint8_t msg_mask_tbl_count = 0; mutex_lock(&driver->md_session_lock); info = diag_md_session_get_pid(pid); @@ -939,9 +958,11 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, mutex_unlock(&driver->md_session_lock); return -EINVAL; } + msg_mask_tbl_count = (info) ? info->msg_mask_tbl_count : + driver->msg_mask_tbl_count; mask_info->status = (req->rt_mask) ? DIAG_CTRL_MASK_ALL_ENABLED : DIAG_CTRL_MASK_ALL_DISABLED; - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + for (i = 0; i < msg_mask_tbl_count; i++, mask++) { if (mask && mask->ptr) { mutex_lock(&mask->lock); memset(mask->ptr, req->rt_mask, @@ -1755,7 +1776,6 @@ static int __diag_mask_init(struct diag_mask_info *mask_info, int mask_len, } kmemleak_not_leak(mask_info->update_buf); } - mutex_init(&mask_info->lock); return 0; } @@ -1778,9 +1798,10 @@ int diag_log_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) struct diag_log_mask_t *src_mask = NULL; struct diag_log_mask_t *dest_mask = NULL; - if (!src) + if (!src || !dest) return -EINVAL; + mutex_init(&dest->lock); err = __diag_mask_init(dest, LOG_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; @@ -1842,9 +1863,11 @@ static int diag_msg_mask_init(void) { int err = 0, i; + mutex_init(&msg_mask.lock); err = __diag_mask_init(&msg_mask, MSG_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; + err = diag_create_msg_mask_table(); if (err) { pr_err("diag: Unable to create msg masks, err: %d\n", err); @@ -1859,7 +1882,8 @@ static int diag_msg_mask_init(void) return 0; } -int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) +int diag_msg_mask_copy(struct diag_md_session_t *new_session, + struct diag_mask_info *dest, struct diag_mask_info *src) { int i, err = 0, mask_size = 0; struct diag_msg_mask_t *src_mask = NULL; @@ -1869,17 +1893,25 @@ int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) if (!src || !dest) return -EINVAL; - err = __diag_mask_init(dest, MSG_MASK_SIZE, APPS_BUF_SIZE); - if (err) - return err; + mutex_init(&dest->lock); mutex_lock(&dest->lock); mutex_lock(&driver->msg_mask_lock); + new_session->msg_mask_tbl_count = + driver->msg_mask_tbl_count; + err = __diag_mask_init(dest, + (new_session->msg_mask_tbl_count * + sizeof(struct diag_msg_mask_t)), APPS_BUF_SIZE); + if (err) { + mutex_unlock(&driver->msg_mask_lock); + mutex_unlock(&dest->lock); + return err; + } src_mask = (struct diag_msg_mask_t *)src->ptr; dest_mask = (struct diag_msg_mask_t *)dest->ptr; dest->mask_len = src->mask_len; dest->status = src->status; - for (i = 0; i < driver->msg_mask_tbl_count; i++) { + for (i = 0; i < new_session->msg_mask_tbl_count; i++) { range.ssid_first = src_mask->ssid_first; range.ssid_last = src_mask->ssid_last; err = diag_create_msg_mask_table_entry(dest_mask, &range); @@ -1898,10 +1930,12 @@ int diag_msg_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src) return err; } -void diag_msg_mask_free(struct diag_mask_info *mask_info) +void diag_msg_mask_free(struct diag_mask_info *mask_info, + struct diag_md_session_t *session_info) { int i; struct diag_msg_mask_t *mask = NULL; + uint8_t msg_mask_tbl_count = 0; if (!mask_info || !mask_info->ptr) return; @@ -1915,7 +1949,10 @@ void diag_msg_mask_free(struct diag_mask_info *mask_info) mutex_unlock(&mask_info->lock); return; } - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + msg_mask_tbl_count = (session_info) ? + session_info->msg_mask_tbl_count : + driver->msg_mask_tbl_count; + for (i = 0; i < msg_mask_tbl_count; i++, mask++) { kfree(mask->ptr); mask->ptr = NULL; } @@ -1947,6 +1984,7 @@ static int diag_build_time_mask_init(void) int err = 0; /* There is no need for update buffer for Build Time masks */ + mutex_init(&msg_bt_mask.lock); err = __diag_mask_init(&msg_bt_mask, MSG_MASK_SIZE, 0); if (err) return err; @@ -1980,6 +2018,7 @@ static int diag_log_mask_init(void) { int err = 0, i; + mutex_init(&log_mask.lock); err = __diag_mask_init(&log_mask, LOG_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; @@ -2013,6 +2052,7 @@ static int diag_event_mask_init(void) { int err = 0, i; + mutex_init(&event_mask.lock); err = __diag_mask_init(&event_mask, EVENT_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; @@ -2034,6 +2074,7 @@ int diag_event_mask_copy(struct diag_mask_info *dest, if (!src || !dest) return -EINVAL; + mutex_init(&dest->lock); err = __diag_mask_init(dest, EVENT_MASK_SIZE, APPS_BUF_SIZE); if (err) return err; @@ -2070,6 +2111,7 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, struct diag_mask_info *mask_info = NULL; struct diag_msg_mask_t *mask = NULL; unsigned char *ptr = NULL; + uint8_t msg_mask_tbl_count = 0; if (!buf || count == 0) return -EINVAL; @@ -2094,7 +2136,9 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, mutex_unlock(&mask_info->lock); return -EINVAL; } - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + msg_mask_tbl_count = (info) ? info->msg_mask_tbl_count : + driver->msg_mask_tbl_count; + for (i = 0; i < msg_mask_tbl_count; i++, mask++) { if (!mask->ptr) continue; ptr = mask_info->update_buf; diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h index 0e87f3835113..0ccadf30f092 100644 --- a/drivers/char/diag/diag_masks.h +++ b/drivers/char/diag/diag_masks.h @@ -160,12 +160,13 @@ int diag_masks_init(void); void diag_masks_exit(void); int diag_log_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src); -int diag_msg_mask_copy(struct diag_mask_info *dest, - struct diag_mask_info *src); +int diag_msg_mask_copy(struct diag_md_session_t *new_session, + struct diag_mask_info *dest, struct diag_mask_info *src); int diag_event_mask_copy(struct diag_mask_info *dest, struct diag_mask_info *src); void diag_log_mask_free(struct diag_mask_info *mask_info); -void diag_msg_mask_free(struct diag_mask_info *mask_info); +void diag_msg_mask_free(struct diag_mask_info *mask_info, + struct diag_md_session_t *session_info); void diag_event_mask_free(struct diag_mask_info *mask_info); int diag_process_apps_masks(unsigned char *buf, int len, int pid); void diag_send_updates_peripheral(uint8_t peripheral); diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index 083622f84eed..cb33b3619e02 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -482,6 +482,7 @@ struct diag_md_session_t { int pid; int peripheral_mask; uint8_t hdlc_disabled; + uint8_t msg_mask_tbl_count; struct timer_list hdlc_reset_timer; struct diag_mask_info *msg_mask; struct diag_mask_info *log_mask; diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 4678e48a266a..b1f235495118 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -1265,7 +1265,8 @@ static void diag_md_session_exit(void) diag_log_mask_free(session_info->log_mask); kfree(session_info->log_mask); session_info->log_mask = NULL; - diag_msg_mask_free(session_info->msg_mask); + diag_msg_mask_free(session_info->msg_mask, + session_info); kfree(session_info->msg_mask); session_info->msg_mask = NULL; diag_event_mask_free(session_info->event_mask); @@ -1336,7 +1337,9 @@ int diag_md_session_create(int mode, int peripheral_mask, int proc) "return value of event copy. err %d\n", err); goto fail_peripheral; } - err = diag_msg_mask_copy(new_session->msg_mask, &msg_mask); + new_session->msg_mask_tbl_count = 0; + err = diag_msg_mask_copy(new_session, new_session->msg_mask, + &msg_mask); if (err) { DIAG_LOG(DIAG_DEBUG_USERSPACE, "return value of msg copy. err %d\n", err); @@ -1372,7 +1375,8 @@ int diag_md_session_create(int mode, int peripheral_mask, int proc) diag_event_mask_free(new_session->event_mask); kfree(new_session->event_mask); new_session->event_mask = NULL; - diag_msg_mask_free(new_session->msg_mask); + diag_msg_mask_free(new_session->msg_mask, + new_session); kfree(new_session->msg_mask); new_session->msg_mask = NULL; kfree(new_session); @@ -1400,7 +1404,8 @@ static void diag_md_session_close(int pid) diag_log_mask_free(session_info->log_mask); kfree(session_info->log_mask); session_info->log_mask = NULL; - diag_msg_mask_free(session_info->msg_mask); + diag_msg_mask_free(session_info->msg_mask, + session_info); kfree(session_info->msg_mask); session_info->msg_mask = NULL; diag_event_mask_free(session_info->event_mask); -- GitLab From 16bd2d576962defb24f7965deeaee2147244ca1a Mon Sep 17 00:00:00 2001 From: Mukesh Kumar Savaliya Date: Thu, 16 Aug 2018 02:03:29 +0530 Subject: [PATCH 0988/1001] ARM: dts: qcom: Update QUPv3 core master bus id for SDMMAGPIE Bus ID got changed for SDMMAGPIE, hence incorporate the same changes for QUPV3_0 and QUPV3_1 wrapper cores. Change-Id: I0780890549474d6287f08187ea1fa92fff2b0eee Signed-off-by: Mukesh Kumar Savaliya --- arch/arm64/boot/dts/qcom/sdmmagpie-qupv3.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-qupv3.dtsi index 70e03825fc96..b6987a2fa256 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-qupv3.dtsi @@ -17,7 +17,7 @@ qupv3_0: qcom,qupv3_0_geni_se@0x8c0000 { compatible = "qcom,qupv3-geni-se"; reg = <0x8c0000 0x2000>; - qcom,bus-mas-id = ; + qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; @@ -263,7 +263,7 @@ qupv3_1: qcom,qupv3_1_geni_se@0xac0000 { compatible = "qcom,qupv3-geni-se"; reg = <0xac0000 0x2000>; - qcom,bus-mas-id = ; + qcom,bus-mas-id = ; qcom,bus-slv-id = ; qcom,iommu-s1-bypass; -- GitLab From 94f4efdbbb7f653945457509ace0771e5dfa56bc Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 27 Aug 2018 17:26:48 +0530 Subject: [PATCH 0989/1001] clk: qcom: cpu-qcs405: Update the fmax voltage for HF PLL The voltage requirement for the HFPLL to support 2GHz has been updated as per the HW design recommendation. Change-Id: I5c9f3919cd247bb0005c4902b65bbb621fee4fde Signed-off-by: Taniya Das --- drivers/clk/qcom/clk-cpu-qcs405.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/clk/qcom/clk-cpu-qcs405.c b/drivers/clk/qcom/clk-cpu-qcs405.c index dc2e03bac40c..331f3e195e3c 100644 --- a/drivers/clk/qcom/clk-cpu-qcs405.c +++ b/drivers/clk/qcom/clk-cpu-qcs405.c @@ -267,8 +267,7 @@ static struct clk_pll apcs_cpu_pll = { .ops = &clk_pll_hf_ops, .vdd_class = &vdd_hf_pll, .rate_max = (unsigned long[VDD_HF_PLL_NUM]) { - [VDD_HF_PLL_SVS] = 1000000000, - [VDD_HF_PLL_NOM] = 2000000000, + [VDD_HF_PLL_SVS] = 2000000000, }, .num_rate_max = VDD_HF_PLL_NUM, }, -- GitLab From 44037a91e32a7e87e1ba2eb6747c552c4ed76e50 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Thu, 14 Jun 2018 21:31:28 +0800 Subject: [PATCH 0990/1001] coresight: tmc: Avoid reading tmc node before it being enabled It is possible that the mem_size of tmc_etr will be allocated failed while enabling. And if we read tmc-etr after this, system reset will happen. So don't read tmc before it being enabled. CRs-Fixed: 2243995 Change-Id: I6a0be80834f7d4c1c7464f9684228e5b35f31a77 Signed-off-by: Mao Jinlong --- .../hwtracing/coresight/coresight-tmc-etr.c | 1 - drivers/hwtracing/coresight/coresight-tmc.c | 3 +- drivers/hwtracing/coresight/coresight.c | 90 ++++++++++++------- 3 files changed, 59 insertions(+), 35 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 42e263347e4f..6aafdba97956 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -937,7 +937,6 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) tmc_etr_enable_hw(drvdata); drvdata->enable = true; - drvdata->sticky_enable = true; out: spin_unlock_irqrestore(&drvdata->spinlock, flags); diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index 8ed08a9c129f..20dd35e71830 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -141,7 +141,6 @@ static void __tmc_reg_dump(struct tmc_drvdata *drvdata) void tmc_enable_hw(struct tmc_drvdata *drvdata) { drvdata->enable = true; - drvdata->sticky_enable = true; writel_relaxed(TMC_CTL_CAPT_EN, drvdata->base + TMC_CTL); if (drvdata->force_reg_dump) __tmc_reg_dump(drvdata); @@ -157,7 +156,7 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata) { int ret = 0; - if (!drvdata->sticky_enable) + if (!drvdata->enable) return -EPERM; switch (drvdata->config_type) { diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index ef79c9efd840..7f4d263bf7ea 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -206,8 +206,10 @@ static int coresight_enable_link(struct coresight_device *csdev, if (atomic_inc_return(&csdev->refcnt[refport]) == 1) { if (link_ops(csdev)->enable) { ret = link_ops(csdev)->enable(csdev, inport, outport); - if (ret) + if (ret) { + atomic_dec(&csdev->refcnt[refport]); return ret; + } } } @@ -296,42 +298,66 @@ static bool coresight_disable_source(struct coresight_device *csdev) return !csdev->enable; } -void coresight_disable_path(struct list_head *path) +static void coresigh_disable_list_node(struct list_head *path, + struct coresight_node *nd) { u32 type; - struct coresight_node *nd; struct coresight_device *csdev, *parent, *child; - list_for_each_entry(nd, path, link) { - csdev = nd->csdev; - type = csdev->type; + csdev = nd->csdev; + type = csdev->type; - /* - * ETF devices are tricky... They can be a link or a sink, - * depending on how they are configured. If an ETF has been - * "activated" it will be configured as a sink, otherwise - * go ahead with the link configuration. - */ - if (type == CORESIGHT_DEV_TYPE_LINKSINK) - type = (csdev == coresight_get_sink(path)) ? - CORESIGHT_DEV_TYPE_SINK : - CORESIGHT_DEV_TYPE_LINK; + /* + * ETF devices are tricky... They can be a link or a sink, + * depending on how they are configured. If an ETF has been + * "activated" it will be configured as a sink, otherwise + * go ahead with the link configuration. + */ + if (type == CORESIGHT_DEV_TYPE_LINKSINK) + type = (csdev == coresight_get_sink(path)) ? + CORESIGHT_DEV_TYPE_SINK : + CORESIGHT_DEV_TYPE_LINK; + + switch (type) { + case CORESIGHT_DEV_TYPE_SINK: + coresight_disable_sink(csdev); + break; + case CORESIGHT_DEV_TYPE_SOURCE: + /* sources are disabled from either sysFS or Perf */ + break; + case CORESIGHT_DEV_TYPE_LINK: + parent = list_prev_entry(nd, link)->csdev; + child = list_next_entry(nd, link)->csdev; + coresight_disable_link(csdev, parent, child); + break; + default: + break; + } +} - switch (type) { - case CORESIGHT_DEV_TYPE_SINK: - coresight_disable_sink(csdev); - break; - case CORESIGHT_DEV_TYPE_SOURCE: - /* sources are disabled from either sysFS or Perf */ - break; - case CORESIGHT_DEV_TYPE_LINK: - parent = list_prev_entry(nd, link)->csdev; - child = list_next_entry(nd, link)->csdev; - coresight_disable_link(csdev, parent, child); - break; - default: - break; - } +/** + * During enabling path, if it is failed, then only those enabled + * devices need to be disabled. This function is to disable devices + * which is enabled before the failed device. + * + * @path the head of the list + * @nd the failed device node + */ +static void coresight_disable_previous_devs(struct list_head *path, + struct coresight_node *nd) +{ + + list_for_each_entry_continue(nd, path, link) { + coresigh_disable_list_node(path, nd); + } +} + +void coresight_disable_path(struct list_head *path) +{ + struct coresight_node *nd; + + list_for_each_entry(nd, path, link) { + coresigh_disable_list_node(path, nd); } } @@ -382,7 +408,7 @@ int coresight_enable_path(struct list_head *path, u32 mode) out: return ret; err: - coresight_disable_path(path); + coresight_disable_previous_devs(path, nd); goto out; } -- GitLab From 1b642eb7a7562751cf1a20825be5edfb4f816910 Mon Sep 17 00:00:00 2001 From: Ghanim Fodi Date: Mon, 27 Aug 2018 18:30:36 +0300 Subject: [PATCH 0991/1001] msm: ipa: Make sure aggregation limit is upper bounded IPA supports packet based as well as byte based aggregations. The limits boundaries defined by the H/W. If the requested limit exceeds the boundary, make sure to use the maximal limit supported by the H/W. CRs-Fixed: 2303737 Change-Id: I97391010a48ea4d22bd3fa3afe30dcae23bd0ab3 Signed-off-by: Ghanim Fodi --- .../msm/ipa/ipa_v3/ipahal/ipahal_reg.c | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c index 0153b0694844..c487e965640d 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c @@ -1709,6 +1709,10 @@ static void ipareg_construct_endp_init_aggr_n(enum ipahal_reg_name reg, { struct ipa_ep_cfg_aggr *ep_aggr = (struct ipa_ep_cfg_aggr *)fields; + u32 byte_limit; + u32 pkt_limit; + u32 max_byte_limit; + u32 max_pkt_limit; IPA_SETFIELD_IN_REG(*val, ep_aggr->aggr_en, IPA_ENDP_INIT_AGGR_n_AGGR_EN_SHFT, @@ -1718,7 +1722,12 @@ static void ipareg_construct_endp_init_aggr_n(enum ipahal_reg_name reg, IPA_ENDP_INIT_AGGR_n_AGGR_TYPE_SHFT, IPA_ENDP_INIT_AGGR_n_AGGR_TYPE_BMSK); - IPA_SETFIELD_IN_REG(*val, ep_aggr->aggr_byte_limit, + /* make sure aggregation byte limit does not cross HW boundaries */ + max_byte_limit = IPA_ENDP_INIT_AGGR_n_AGGR_BYTE_LIMIT_BMSK >> + IPA_ENDP_INIT_AGGR_n_AGGR_BYTE_LIMIT_SHFT; + byte_limit = (ep_aggr->aggr_byte_limit > max_byte_limit) ? + max_byte_limit : ep_aggr->aggr_byte_limit; + IPA_SETFIELD_IN_REG(*val, byte_limit, IPA_ENDP_INIT_AGGR_n_AGGR_BYTE_LIMIT_SHFT, IPA_ENDP_INIT_AGGR_n_AGGR_BYTE_LIMIT_BMSK); @@ -1727,7 +1736,12 @@ static void ipareg_construct_endp_init_aggr_n(enum ipahal_reg_name reg, IPA_ENDP_INIT_AGGR_n_AGGR_TIME_LIMIT_SHFT, IPA_ENDP_INIT_AGGR_n_AGGR_TIME_LIMIT_BMSK); - IPA_SETFIELD_IN_REG(*val, ep_aggr->aggr_pkt_limit, + /* make sure aggregation pkt limit does not cross HW boundaries */ + max_pkt_limit = IPA_ENDP_INIT_AGGR_n_AGGR_PKT_LIMIT_BMSK >> + IPA_ENDP_INIT_AGGR_n_AGGR_PKT_LIMIT_SHFT; + pkt_limit = (ep_aggr->aggr_pkt_limit > max_pkt_limit) ? + max_pkt_limit : ep_aggr->aggr_pkt_limit; + IPA_SETFIELD_IN_REG(*val, pkt_limit, IPA_ENDP_INIT_AGGR_n_AGGR_PKT_LIMIT_SHFT, IPA_ENDP_INIT_AGGR_n_AGGR_PKT_LIMIT_BMSK); @@ -1746,6 +1760,10 @@ static void ipareg_construct_endp_init_aggr_n_v4_5(enum ipahal_reg_name reg, { struct ipa_ep_cfg_aggr *ep_aggr = (struct ipa_ep_cfg_aggr *)fields; + u32 byte_limit; + u32 pkt_limit; + u32 max_byte_limit; + u32 max_pkt_limit; IPA_SETFIELD_IN_REG(*val, ep_aggr->aggr_en, IPA_ENDP_INIT_AGGR_n_AGGR_EN_SHFT_V4_5, @@ -1755,7 +1773,12 @@ static void ipareg_construct_endp_init_aggr_n_v4_5(enum ipahal_reg_name reg, IPA_ENDP_INIT_AGGR_n_AGGR_TYPE_SHFT_V4_5, IPA_ENDP_INIT_AGGR_n_AGGR_TYPE_BMSK_V4_5); - IPA_SETFIELD_IN_REG(*val, ep_aggr->aggr_byte_limit, + /* make sure aggregation byte limit does not cross HW boundaries */ + max_byte_limit = IPA_ENDP_INIT_AGGR_n_AGGR_BYTE_LIMIT_BMSK_V4_5 >> + IPA_ENDP_INIT_AGGR_n_AGGR_BYTE_LIMIT_SHFT_V4_5; + byte_limit = (ep_aggr->aggr_byte_limit > max_byte_limit) ? + max_byte_limit : ep_aggr->aggr_byte_limit; + IPA_SETFIELD_IN_REG(*val, byte_limit, IPA_ENDP_INIT_AGGR_n_AGGR_BYTE_LIMIT_SHFT_V4_5, IPA_ENDP_INIT_AGGR_n_AGGR_BYTE_LIMIT_BMSK_V4_5); @@ -1763,6 +1786,11 @@ static void ipareg_construct_endp_init_aggr_n_v4_5(enum ipahal_reg_name reg, IPA_ENDP_INIT_AGGR_n_AGGR_TIME_LIMIT_SHFT_V4_5, IPA_ENDP_INIT_AGGR_n_AGGR_TIME_LIMIT_BMSK_V4_5); + /* make sure aggregation pkt limit does not cross HW boundaries */ + max_pkt_limit = IPA_ENDP_INIT_AGGR_n_AGGR_PKT_LIMIT_BMSK_V4_5 >> + IPA_ENDP_INIT_AGGR_n_AGGR_PKT_LIMIT_SHFT_V4_5; + pkt_limit = (ep_aggr->aggr_pkt_limit > max_pkt_limit) ? + max_pkt_limit : ep_aggr->aggr_pkt_limit; IPA_SETFIELD_IN_REG(*val, ep_aggr->aggr_pkt_limit, IPA_ENDP_INIT_AGGR_n_AGGR_PKT_LIMIT_SHFT_V4_5, IPA_ENDP_INIT_AGGR_n_AGGR_PKT_LIMIT_BMSK_V4_5); -- GitLab From faad2fbeca0ed4989b201ca25c96f3c76fe56b27 Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Fri, 24 Aug 2018 10:54:22 -0700 Subject: [PATCH 0992/1001] scsi: ufs-qcom: fix ref-clk pad regulator initialization UFS device's reference clock is sourced via REF CLK pad on host and this pad is powered by 1.2v fixed voltage rail. As we don't need to explicitly set the voltage for this rail, relevant voltage level parameters from device tree are optional and hence absence of them shouldn't fail the ref-clk regulator voting from UFS driver. Fix this by treating the voltage level parameters optional which was the original intent. Change-Id: Ic498e5c89a869374bfabfef9ae796a2e78aef834 Signed-off-by: Subhash Jadavani --- drivers/scsi/ufs/ufs-qcom.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index a7430a46da45..7b1a958b2bbf 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -2100,6 +2100,7 @@ static int ufs_qcom_parse_reg_info(struct ufs_qcom_host *host, char *name, dev_dbg(dev, "%s: unable to find %s err %d, using default\n", __func__, prop_name, ret); vreg->min_uV = VDDP_REF_CLK_MIN_UV; + ret = 0; } snprintf(prop_name, MAX_PROP_SIZE, "%s-max-uV", name); @@ -2108,6 +2109,7 @@ static int ufs_qcom_parse_reg_info(struct ufs_qcom_host *host, char *name, dev_dbg(dev, "%s: unable to find %s err %d, using default\n", __func__, prop_name, ret); vreg->max_uV = VDDP_REF_CLK_MAX_UV; + ret = 0; } out: -- GitLab From 8182accd6f9ca34c36ae4186f3c08cce929be7f2 Mon Sep 17 00:00:00 2001 From: Vamsi Krishna Samavedam Date: Thu, 26 Jul 2018 13:10:16 -0700 Subject: [PATCH 0993/1001] usb: dwc3: Powerdown the SS PHY while connected to HS device SNPS controller can wakeup both HS PHY and SS PHY (for UTMI clock and PIPE clock) for any xhci command or doorbell rings. This might result in additional power consumption when only HS device is connected to root port. To avoid additional power consumption when operating in high-speed only mode, power down SS PHY. Change-Id: I35195934c617d7c581976e34da73777bfa13fe6f Signed-off-by: Vamsi Krishna Samavedam --- drivers/usb/dwc3/dwc3-msm.c | 9 +++++++++ drivers/usb/phy/phy-msm-ssusb-qmp.c | 18 ++++++++++++++++++ include/linux/usb/phy.h | 19 +++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 4f48541f12c6..e2575c3e3711 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -3709,6 +3709,14 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb, udev->dev.parent->parent == &dwc->xhci->dev) { if (event == USB_DEVICE_ADD && udev->actconfig) { if (!dwc3_msm_is_ss_rhport_connected(mdwc)) { + /* + * controller may wakeup ss phy during hs data + * transfers or doorbell rings. Power down the + * ss phy to avoid turning on pipe clock during + * these wake-ups. + */ + usb_phy_powerdown(mdwc->ss_phy); + /* * Core clock rate can be reduced only if root * hub SS port is not enabled/connected. @@ -3724,6 +3732,7 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb, mdwc->max_rh_port_speed = USB_SPEED_SUPER; } } else { + usb_phy_powerup(mdwc->ss_phy); /* set rate back to default core clk rate */ clk_set_rate(mdwc->core_clk, mdwc->core_clk_rate); dev_dbg(mdwc->dev, "set core clk rate %ld\n", diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c index 1f481c2b4001..828e78f79afb 100644 --- a/drivers/usb/phy/phy-msm-ssusb-qmp.c +++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c @@ -782,6 +782,23 @@ static int msm_ssphy_qmp_notify_disconnect(struct usb_phy *uphy, return 0; } +static int msm_ssphy_qmp_powerup(struct usb_phy *uphy, bool powerup) +{ + struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp, + phy); + u8 reg = powerup ? 1 : 0; + u8 temp; + + writel_relaxed(reg, + phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]); + temp = readl_relaxed(phy->base + + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]); + + dev_dbg(uphy->dev, "P3 powerup:%x\n", temp); + + return 0; +} + static int msm_ssphy_qmp_get_clks(struct msm_ssphy_qmp *phy, struct device *dev) { int ret = 0; @@ -1083,6 +1100,7 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev) phy->phy.set_suspend = msm_ssphy_qmp_set_suspend; phy->phy.notify_connect = msm_ssphy_qmp_notify_connect; phy->phy.notify_disconnect = msm_ssphy_qmp_notify_disconnect; + phy->phy.powerup = msm_ssphy_qmp_powerup; if (of_property_read_bool(dev->of_node, "qcom,link-training-reset")) phy->phy.link_training = msm_ssphy_qmp_link_training; diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index 8642f030f05a..0ad1073a8816 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h @@ -164,6 +164,7 @@ struct usb_phy { int (*notify_disconnect)(struct usb_phy *x, enum usb_device_speed speed); int (*link_training)(struct usb_phy *x, bool start); + int (*powerup)(struct usb_phy *x, bool start); /* * Charger detection method can be implemented if you need to @@ -406,6 +407,24 @@ usb_phy_stop_link_training(struct usb_phy *x) return 0; } +static inline int +usb_phy_powerup(struct usb_phy *x) +{ + if (x && x->powerup) + return x->powerup(x, true); + else + return 0; +} + +static inline int +usb_phy_powerdown(struct usb_phy *x) +{ + if (x && x->powerup) + return x->powerup(x, false); + else + return 0; +} + static inline int usb_phy_notify_disconnect(struct usb_phy *x, enum usb_device_speed speed) { -- GitLab From c226cbb7b78912b6c5fccb425d36f31cccda7e46 Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Tue, 21 Aug 2018 15:53:44 -0700 Subject: [PATCH 0994/1001] msm: gsi: wait for interrupts for commands When sending a command to gsi, an interrupt is expected. This change is waiting for this interrupt until timeout has expired. Change-Id: I876c4386aa34d90a1449aed308c99f93d61837d6 Acked-by: Ady Abraham Signed-off-by: Skylar Chang --- drivers/platform/msm/gsi/gsi.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index f22bcb78ddb7..e07c765bff82 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -116,8 +116,7 @@ static void __gsi_config_gen_irq(int ee, uint32_t mask, uint32_t val) static void gsi_channel_state_change_wait(unsigned long chan_hdl, struct gsi_chan_ctx *ctx, - uint32_t tm, - enum gsi_chan_state next_state) + uint32_t tm) { int poll_cnt; int gsi_pending_intr; @@ -166,9 +165,6 @@ static void gsi_channel_state_change_wait(unsigned long chan_hdl, ch, ctx->state, gsi_pending_intr); - - if (ctx->state == next_state) - break; } } @@ -2469,8 +2465,7 @@ int gsi_start_channel(unsigned long chan_hdl) GSIDBG("GSI Channel Start, waiting for completion\n"); gsi_channel_state_change_wait(chan_hdl, ctx, - GSI_START_CMD_TIMEOUT_MS, - GSI_CHAN_STATE_STARTED); + GSI_START_CMD_TIMEOUT_MS); if (ctx->state != GSI_CHAN_STATE_STARTED) { /* @@ -2543,8 +2538,7 @@ int gsi_stop_channel(unsigned long chan_hdl) GSIDBG("GSI Channel Stop, waiting for completion\n"); gsi_channel_state_change_wait(chan_hdl, ctx, - GSI_STOP_CMD_TIMEOUT_MS, - GSI_CHAN_STATE_STOPPED); + GSI_STOP_CMD_TIMEOUT_MS); if (ctx->state != GSI_CHAN_STATE_STOPPED && ctx->state != GSI_CHAN_STATE_STOP_IN_PROC) { -- GitLab From 09ea89606e06d7e0138fd4f6f19dcb5059a52198 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Mon, 27 Aug 2018 15:15:51 -0600 Subject: [PATCH 0995/1001] soc: qcom: dfc: Change workqueue type to single thread The max_active flag is not sufficient to guarantee that only one instance of the work for dfc_do_burst_flow_control is running across all cores. Change the allocation API to guarantee this behavior. Additionally, remove all references to disabling bottom half processing as SOFTIRQ NET_TX cannot invoke this thread as the transmit path no longer calls the rtnl lock. CRs-Fixed: 2303876 Change-Id: I5ecd7edc4c7d75b6b8df98a42d011b19e1fa75c0 Signed-off-by: Subash Abhinov Kasiviswanathan --- drivers/soc/qcom/dfc_qmi.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/soc/qcom/dfc_qmi.c b/drivers/soc/qcom/dfc_qmi.c index 7a701d971b20..b2ad30d7756a 100644 --- a/drivers/soc/qcom/dfc_qmi.c +++ b/drivers/soc/qcom/dfc_qmi.c @@ -699,14 +699,12 @@ static void dfc_do_burst_flow_control(struct work_struct *work) return; } - local_bh_disable(); while (!rtnl_trylock()) { if (!svc_ind->data->restart_state) { - cond_resched_softirq(); + cond_resched(); } else { kfree(ind); kfree(svc_ind); - local_bh_enable(); return; } } @@ -742,7 +740,6 @@ static void dfc_do_burst_flow_control(struct work_struct *work) kfree(ind); kfree(svc_ind); rtnl_unlock(); - local_bh_enable(); } static void dfc_bearer_limit_work(struct work_struct *work) @@ -752,21 +749,16 @@ static void dfc_bearer_limit_work(struct work_struct *work) struct list_head *p; int qlen, fc; - local_bh_disable(); - /* enable transmit on device so that the other * flows which transmit proceed normally. - * do it here under bh disabled so that the TX softirq - * may not run here */ netif_start_queue(dfc_ind->dev); while (!rtnl_trylock()) { if (!dfc_ind->data->restart_state) { - cond_resched_softirq(); + cond_resched(); } else { kfree(dfc_ind); - local_bh_enable(); return; } } @@ -798,7 +790,6 @@ static void dfc_bearer_limit_work(struct work_struct *work) done: kfree(dfc_ind); rtnl_unlock(); - local_bh_enable(); } static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, @@ -921,7 +912,7 @@ int dfc_qmi_client_init(void *port, int index, struct qmi_info *qmi) data->index = index; data->restart_state = 0; - data->dfc_wq = alloc_workqueue("dfc_wq", WQ_HIGHPRI, 1); + data->dfc_wq = create_singlethread_workqueue("dfc_wq"); if (!data->dfc_wq) { pr_err("%s Could not create workqueue\n", __func__); goto err0; -- GitLab From e9bbe149b7189ee376c27cf4d7760c4945980d9a Mon Sep 17 00:00:00 2001 From: Satya Durga Srinivasu Prabhala Date: Fri, 24 Aug 2018 12:23:08 -0700 Subject: [PATCH 0996/1001] sysctl/sched: do not allow value "0" for sched_{up,down}_migrate knobs Right now sched_{up,down}_migrate knobs are accepting zero as a valid value and we end up with upmigrate value is less than downmigrate value when zero is written by user to upmigrate knob, we go ahead and update upmigrate value which would end up being lesser than downmigrate value. Also, there is a div by zero issue by accepting zero as valid value for these knobs. So, update check to make sure zero isn't allowed as a valid value. Change-Id: Ic44d8fda14e99f622bbadc6c78ce7a28aedbd5b2 Signed-off-by: Satya Durga Srinivasu Prabhala --- kernel/sysctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 9f36ed4be3a2..3727de0c9c46 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -3290,7 +3290,7 @@ static int do_proc_douintvec_capacity_conv(bool *negp, unsigned long *lvalp, int *valp, int write, void *data) { if (write) { - if (*negp) + if (*negp || *lvalp == 0) return -EINVAL; *valp = SCHED_FIXEDPOINT_SCALE * 100 / *lvalp; } else { -- GitLab From d49c4e9f74a6a0b1bf9de148ed0d5f76aa866682 Mon Sep 17 00:00:00 2001 From: Sudarshan Rajagopalan Date: Thu, 23 Aug 2018 14:27:39 -0700 Subject: [PATCH 0997/1001] iommu: arm-smmu: Standardize deep pre-fetch errata workaround Some hardware revision might have the deep prefetch bug where invalid entries in the prefetch window would cause improper permissions to be cached for the valid entries in this window. Enable the workaround on such hardware by aligning the start and end of all mapped buffers to prefetch size boundary. Change-Id: Ib9ffd84d6e30087baabef35781e74d0544856233 Signed-off-by: Sudarshan Rajagopalan --- Documentation/devicetree/bindings/iommu/arm,smmu.txt | 8 ++++++++ drivers/iommu/arm-smmu.c | 7 +++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index 5c85a63f9164..c8ad1b304dc5 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -129,6 +129,14 @@ conditions. clients who do not detach, it's not possible to keep regulator vote while smmu is attached. Type is . +- qcom,min-iova-align: + Some hardware revision might have the deep prefetch bug where + invalid entries in the prefetch window would cause improper + permissions to be cached for the valid entries in this window. + Enable the workaround on such hardware by aligning the start + and end of all mapped buffers to prefetch size boundary, which + is defined by ARM_SMMU_MIN_IOVA_ALIGN. + - clocks : List of clocks to be used during SMMU register access. See Documentation/devicetree/bindings/clock/clock-bindings.txt for information about the format. For each clock specified diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 6a5e7bdff9cf..ea26ce6a6684 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -255,6 +255,7 @@ struct arm_smmu_device { #define ARM_SMMU_OPT_NO_ASID_RETENTION (1 << 5) #define ARM_SMMU_OPT_STATIC_CB (1 << 6) #define ARM_SMMU_OPT_DISABLE_ATOS (1 << 7) +#define ARM_SMMU_OPT_MIN_IOVA_ALIGN (1 << 8) u32 options; enum arm_smmu_arch_version version; enum arm_smmu_implementation model; @@ -394,6 +395,7 @@ static struct arm_smmu_option_prop arm_smmu_options[] = { { ARM_SMMU_OPT_NO_ASID_RETENTION, "qcom,no-asid-retention" }, { ARM_SMMU_OPT_STATIC_CB, "qcom,enable-static-cb"}, { ARM_SMMU_OPT_DISABLE_ATOS, "qcom,disable-atos" }, + { ARM_SMMU_OPT_MIN_IOVA_ALIGN, "qcom,min-iova-align" }, { 0, NULL}, }; @@ -5344,8 +5346,9 @@ static void qsmmuv500_init_cb(struct arm_smmu_domain *smmu_domain, * Prefetch only works properly if the start and end of all * buffers in the page table are aligned to ARM_SMMU_MIN_IOVA_ALIGN. */ - if ((iommudata->actlr >> QSMMUV500_ACTLR_DEEP_PREFETCH_SHIFT) & - QSMMUV500_ACTLR_DEEP_PREFETCH_MASK) + if (((iommudata->actlr >> QSMMUV500_ACTLR_DEEP_PREFETCH_SHIFT) & + QSMMUV500_ACTLR_DEEP_PREFETCH_MASK) && + (smmu->options & ARM_SMMU_OPT_MIN_IOVA_ALIGN)) smmu_domain->qsmmuv500_errata1_min_iova_align = true; } -- GitLab From 4b3bb01f45f27e5d99701797948e17c95f552a22 Mon Sep 17 00:00:00 2001 From: Sudarshan Rajagopalan Date: Thu, 23 Aug 2018 14:34:53 -0700 Subject: [PATCH 0998/1001] ARM: dts: msm: Enable deep pre-fetch errata workaround for sm8150 Due to the deep pre-fetch errata in MMU-500, invalid page-table entries in the prefetch window would cause permissions may be cached for valid entries in this window. Ensure the start and end of all mapped buffers are aligned to 16kB boundary. Change-Id: I0ba1843e2dbe9607b1c49cc3913b214cf4e09527 Signed-off-by: Sudarshan Rajagopalan --- arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi index ae5aaba36fab..3bec9d3b1834 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi @@ -25,6 +25,7 @@ qcom,use-3-lvl-tables; qcom,no-asid-retention; qcom,disable-atos; + qcom,min-iova-align; #global-interrupts = <1>; qcom,regulator-names = "vdd"; vdd-supply = <&gpu_cx_gdsc>; @@ -74,6 +75,7 @@ qcom,use-3-lvl-tables; qcom,no-asid-retention; qcom,disable-atos; + qcom,min-iova-align; #global-interrupts = <1>; #size-cells = <1>; #address-cells = <1>; -- GitLab From d896f9d6f15ab2685f5e07a7466b2507f5f2d1c0 Mon Sep 17 00:00:00 2001 From: Sudarshan Rajagopalan Date: Tue, 21 Aug 2018 14:26:42 -0700 Subject: [PATCH 0999/1001] ARM: dts: msm: Enable deep pre-fetch for NPU for sm8150 Enable context caching with deep pre-fetch of length 4 x 4k pages for all context banks of NPU for sm8150 v1. Change-Id: Id9a3e976aff877dde8c6e96458a4ac046fbdf869 Signed-off-by: Sudarshan Rajagopalan --- .../boot/dts/qcom/msm-arm-smmu-sm8150.dtsi | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi index 3bec9d3b1834..b3c5b0eb1f1a 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi @@ -388,6 +388,23 @@ }; &kgsl_smmu { - qcom,actlr = <0x0 0x407 0x303>; + qcom,actlr = + /* All CBs of GFX: +15 deep PF */ + <0x0 0x407 0x303>; +}; + +&apps_smmu { + qcom,actlr = + /* SIDs 0x1460 - 0x1463 of NPU: +3 deep PF */ + <0x1460 0x3 0x103>, + + /* SIDs 0x1464 - 0x1465 of NPU: +3 deep PF */ + <0x1464 0x1 0x103>, + + /* SIDs 0x2060 - 0x2063 of NPU: +3 deep PF */ + <0x2060 0x3 0x103>, + + /* SIDs 0x2064 - 0x2065 of NPU: +3 deep PF */ + <0x2064 0x1 0x103>; }; -- GitLab From f3cb57708e79e3f14bba81fc203456ceb0782254 Mon Sep 17 00:00:00 2001 From: Sudarshan Rajagopalan Date: Thu, 16 Aug 2018 17:14:06 -0700 Subject: [PATCH 1000/1001] ARM: dts: msm: Remove no asid retention workaround for sm8150 The ASID retention issue is fixed in hardware for sm8150. This WA is no longer needed and can be disabled. Change-Id: I006bde4a9bfbd449b33608de4c5109df75a58275 Signed-off-by: Sudarshan Rajagopalan --- arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi | 2 -- arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi | 2 -- 2 files changed, 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi index b77b138e2e66..ba808d0fbb4e 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi @@ -23,7 +23,6 @@ qcom,dynamic; qcom,skip-init; qcom,use-3-lvl-tables; - qcom,no-asid-retention; #global-interrupts = <1>; qcom,regulator-names = "vdd"; vdd-supply = <&gpu_cx_gdsc>; @@ -71,7 +70,6 @@ #iommu-cells = <2>; qcom,skip-init; qcom,use-3-lvl-tables; - qcom,no-asid-retention; qcom,disable-atos; #global-interrupts = <1>; #size-cells = <1>; diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi index ae5aaba36fab..6c8ffae3dae5 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi @@ -23,7 +23,6 @@ qcom,dynamic; qcom,skip-init; qcom,use-3-lvl-tables; - qcom,no-asid-retention; qcom,disable-atos; #global-interrupts = <1>; qcom,regulator-names = "vdd"; @@ -72,7 +71,6 @@ #iommu-cells = <2>; qcom,skip-init; qcom,use-3-lvl-tables; - qcom,no-asid-retention; qcom,disable-atos; #global-interrupts = <1>; #size-cells = <1>; -- GitLab From 56a0829b189046a1c3f780be0e98e7114a809f78 Mon Sep 17 00:00:00 2001 From: David Dai Date: Tue, 14 Aug 2018 15:21:25 -0700 Subject: [PATCH 1001/1001] ARM: dts: msm: Add sensors ahb master for sm8150 Add new sensors ahb master port. Change-Id: Iaf9100bd5e5a0d8dff9cc324af6c5e01af603c64 Signed-off-by: David Dai --- arch/arm64/boot/dts/qcom/sm8150-bus.dtsi | 9 +++++++++ include/dt-bindings/msm/msm-bus-ids.h | 1 + 2 files changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-bus.dtsi b/arch/arm64/boot/dts/qcom/sm8150-bus.dtsi index a4c32e4df8c1..f419222d6fd5 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-bus.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-bus.dtsi @@ -666,6 +666,15 @@ qcom,prio = <2>; }; + mas_qhm_sensorss_ahb: mas-qhm-sensorss-ahb { + cell-id = ; + label = "mas-qhm-sensorss-ahb"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + }; + mas_qhm_tsif: mas-qhm-tsif { cell-id = ; label = "mas-qhm-tsif"; diff --git a/include/dt-bindings/msm/msm-bus-ids.h b/include/dt-bindings/msm/msm-bus-ids.h index 3fb0f6aedd0c..0fef11f49985 100644 --- a/include/dt-bindings/msm/msm-bus-ids.h +++ b/include/dt-bindings/msm/msm-bus-ids.h @@ -278,6 +278,7 @@ #define MSM_BUS_MASTER_PCIE_3 167 #define MSM_BUS_MASTER_LPASS_ANOC 168 #define MSM_BUS_MASTER_USB2 169 +#define MSM_BUS_MASTER_SENSORS_AHB 170 #define MSM_BUS_MASTER_LLCC_DISPLAY 20000 #define MSM_BUS_MASTER_MNOC_HF_MEM_NOC_DISPLAY 20001 -- GitLab