From 4d3d125d28ad0de455e97a5cd7c33667b15ade31 Mon Sep 17 00:00:00 2001 From: Yue Ma Date: Fri, 12 Jan 2018 14:34:19 -0800 Subject: [PATCH 001/604] cnss2: Consolidate logging message Currently the code makes liberal use of macros that print a log message (with pr_err or pr_debug) and then passes the same string on to the IPC logging mechanism. The problem is that it doesn't actually end up being the same string in the binary. Using pr_err or one of its friends appends the KERN_* code to the front of the string with the pre-processor and the IPC logger just uses the passed in string. Every string used by the macros ends up appearing twice in the binary, once with KERN_* prepended and the other not. This change fixes this duplication issue by appending KERN_* to the front of the IPC logger for CNSS2 driver. Change-Id: I62facd7aaf23bd06fad84d272144f1a50ad539a5 Signed-off-by: Yue Ma --- drivers/net/wireless/cnss2/debug.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/cnss2/debug.h b/drivers/net/wireless/cnss2/debug.h index f31fdfeaad0e..bf2e755f8ee0 100644 --- a/drivers/net/wireless/cnss2/debug.h +++ b/drivers/net/wireless/cnss2/debug.h @@ -26,23 +26,23 @@ extern void *cnss_ipc_log_context; } while (0) #define cnss_pr_err(_fmt, ...) do { \ - pr_err("cnss: " _fmt, ##__VA_ARGS__); \ - cnss_ipc_log_string("ERR: " _fmt, ##__VA_ARGS__); \ + printk("%scnss: " _fmt, KERN_ERR, ##__VA_ARGS__); \ + cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\ } while (0) #define cnss_pr_warn(_fmt, ...) do { \ - pr_warn("cnss: " _fmt, ##__VA_ARGS__); \ - cnss_ipc_log_string("WRN: " _fmt, ##__VA_ARGS__); \ + printk("%scnss: " _fmt, KERN_WARNING, ##__VA_ARGS__); \ + cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\ } while (0) #define cnss_pr_info(_fmt, ...) do { \ - pr_info("cnss: " _fmt, ##__VA_ARGS__); \ - cnss_ipc_log_string("INF: " _fmt, ##__VA_ARGS__); \ + printk("%scnss: " _fmt, KERN_INFO, ##__VA_ARGS__); \ + cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\ } while (0) #define cnss_pr_dbg(_fmt, ...) do { \ - pr_debug("cnss: " _fmt, ##__VA_ARGS__); \ - cnss_ipc_log_string("DBG: " _fmt, ##__VA_ARGS__); \ + printk("%scnss: " _fmt, KERN_DEBUG, ##__VA_ARGS__); \ + cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\ } while (0) #ifdef CONFIG_CNSS2_DEBUG -- GitLab From ed21936849fe62f61b5a1e2e30a1653f3a69721a Mon Sep 17 00:00:00 2001 From: Maheshwar Ajja Date: Thu, 17 May 2018 01:00:02 -0700 Subject: [PATCH 002/604] msm: vidc: Fix double list_del in rbr event processing Do not use mbuf after kref_put_mbuf() instead get the mbuf from the registeredbufs list to use it again. Using the same mbuf after kref_put_mbuf() might lead to video failures. Change-Id: I69f03ca1f9b7d607d407952e7a83d4977962cc5d Signed-off-by: Maheshwar Ajja --- .../media/platform/msm/vidc/msm_vidc_common.c | 16 ++++++++++++---- 1 file changed, 12 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 7d9bbed94599..4b0ca8e89738 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -6620,6 +6620,7 @@ void handle_release_buffer_reference(struct msm_vidc_inst *inst, struct msm_vidc_buffer *temp; bool found = false; int i = 0; + u32 planes[VIDEO_MAX_PLANES] = {0}; mutex_lock(&inst->flush_lock); mutex_lock(&inst->registeredbufs.lock); @@ -6633,6 +6634,10 @@ void handle_release_buffer_reference(struct msm_vidc_inst *inst, } } if (found) { + /* save device_addr */ + for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) + planes[i] = mbuf->smem[i].device_addr; + /* send RBR event to client */ msm_vidc_queue_rbr_event(inst, mbuf->vvb.vb2_buf.planes[0].m.fd, @@ -6651,6 +6656,7 @@ void handle_release_buffer_reference(struct msm_vidc_inst *inst, if (!mbuf->smem[0].refcount) { list_del(&mbuf->list); kref_put_mbuf(mbuf); + mbuf = NULL; } } else { print_vidc_buffer(VIDC_ERR, "mbuf not found", inst, mbuf); @@ -6668,8 +6674,8 @@ void handle_release_buffer_reference(struct msm_vidc_inst *inst, */ found = false; list_for_each_entry(temp, &inst->registeredbufs.list, list) { - if (msm_comm_compare_vb2_plane(inst, mbuf, - &temp->vvb.vb2_buf, 0)) { + if (msm_comm_compare_device_plane(temp, planes, 0)) { + mbuf = temp; found = true; break; } @@ -6689,9 +6695,11 @@ void handle_release_buffer_reference(struct msm_vidc_inst *inst, /* don't queue the buffer */ found = false; } - /* clear DEFERRED flag, if any, as the buffer is going to be queued */ - if (found) + /* clear required flags as the buffer is going to be queued */ + if (found) { mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED; + mbuf->flags &= ~MSM_VIDC_FLAG_RBR_PENDING; + } unlock: mutex_unlock(&inst->registeredbufs.lock); -- GitLab From f3f2b3d828c6bd48b24aca17ab7ab0536c95c7f2 Mon Sep 17 00:00:00 2001 From: Ravi kumar Koyyana Date: Mon, 29 Jan 2018 18:26:49 -0800 Subject: [PATCH 003/604] msm: camera: sync: use lock to protect row state read Add lock to protect row state read and fix UHD video recording failures Change-Id: I3a6fd1e857fcc436ee33658a1aa1f370ee35f9d7 Signed-off-by: Ravi kumar Koyyana Signed-off-by: Junzhe Zou --- .../platform/msm/camera/cam_sync/cam_sync.c | 11 ++++++--- .../msm/camera/cam_sync/cam_sync_util.c | 23 +++++++++++-------- 2 files changed, 21 insertions(+), 13 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 517b7dfe8128..55896f497c59 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c @@ -46,6 +46,7 @@ int cam_sync_create(int32_t *sync_obj, const char *name) } *sync_obj = idx; + CAM_DBG(CAM_SYNC, "sync_obj: %i", *sync_obj); spin_unlock_bh(&sync_dev->row_spinlocks[idx]); return rc; @@ -170,21 +171,24 @@ int cam_sync_signal(int32_t sync_obj, uint32_t status) INIT_LIST_HEAD(&sync_list); if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) { - CAM_ERR(CAM_SYNC, "Error: Out of range sync obj"); + CAM_ERR(CAM_SYNC, "Error: Out of range sync obj (0 <= %d < %d)", + sync_obj, CAM_SYNC_MAX_OBJS); return -EINVAL; } row = sync_dev->sync_table + sync_obj; + spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]); if (row->state == CAM_SYNC_STATE_INVALID) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); CAM_ERR(CAM_SYNC, "Error: accessing an uninitialized sync obj = %d", sync_obj); return -EINVAL; } - spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]); if (row->type == CAM_SYNC_TYPE_GROUP) { spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); - CAM_ERR(CAM_SYNC, "Error: Signaling a GROUP sync object = %d", + CAM_ERR(CAM_SYNC, + "Error: Signaling a GROUP sync object = %d", sync_obj); return -EINVAL; } @@ -368,6 +372,7 @@ int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) int cam_sync_destroy(int32_t sync_obj) { + CAM_DBG(CAM_SYNC, "sync_obj: %i", sync_obj); return cam_sync_deinit_object(sync_dev->sync_table, sync_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 ed69829575bb..cb02dd268ac9 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 @@ -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 @@ -51,8 +51,9 @@ int cam_sync_init_object(struct sync_table_row *table, init_completion(&row->signaled); INIT_LIST_HEAD(&row->callback_list); INIT_LIST_HEAD(&row->user_payload_list); - CAM_DBG(CAM_SYNC, "Sync object Initialised: sync_id:%u row_state:%u ", - row->sync_id, row->state); + CAM_DBG(CAM_SYNC, + "row name:%s sync_id:%i [idx:%u] row_state:%u ", + row->name, row->sync_id, idx, row->state); return 0; } @@ -209,12 +210,16 @@ int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx) if (!table || idx <= 0 || idx >= CAM_SYNC_MAX_OBJS) return -EINVAL; + CAM_DBG(CAM_SYNC, + "row name:%s sync_id:%i [idx:%u] row_state:%u", + row->name, row->sync_id, idx, row->state); + spin_lock_bh(&sync_dev->row_spinlocks[idx]); if (row->state == CAM_SYNC_STATE_INVALID) { + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); CAM_ERR(CAM_SYNC, "Error: accessing an uninitialized sync obj: idx = %d", idx); - spin_unlock_bh(&sync_dev->row_spinlocks[idx]); return -EINVAL; } row->state = CAM_SYNC_STATE_INVALID; @@ -252,9 +257,9 @@ int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx) spin_lock_bh(&sync_dev->row_spinlocks[child_info->sync_id]); if (child_row->state == CAM_SYNC_STATE_INVALID) { + list_del_init(&child_info->list); spin_unlock_bh(&sync_dev->row_spinlocks[ child_info->sync_id]); - list_del_init(&child_info->list); kfree(child_info); continue; } @@ -262,9 +267,8 @@ int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx) cam_sync_util_cleanup_parents_list(child_row, SYNC_LIST_CLEAN_ONE, idx); - spin_unlock_bh(&sync_dev->row_spinlocks[child_info->sync_id]); - list_del_init(&child_info->list); + spin_unlock_bh(&sync_dev->row_spinlocks[child_info->sync_id]); kfree(child_info); } @@ -277,9 +281,9 @@ int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx) spin_lock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); if (parent_row->state == CAM_SYNC_STATE_INVALID) { + list_del_init(&parent_info->list); spin_unlock_bh(&sync_dev->row_spinlocks[ parent_info->sync_id]); - list_del_init(&parent_info->list); kfree(parent_info); continue; } @@ -287,9 +291,8 @@ int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx) cam_sync_util_cleanup_children_list(parent_row, SYNC_LIST_CLEAN_ONE, idx); - spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); - list_del_init(&parent_info->list); + spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); kfree(parent_info); } -- GitLab From 58fbaa5dd6522711e83d28c59350629bdf3acff6 Mon Sep 17 00:00:00 2001 From: Shrey Vijay Date: Thu, 24 May 2018 14:48:28 +0530 Subject: [PATCH 004/604] 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 bc4af98a0280..9cdbd3c49f25 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -524,8 +524,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] = @@ -546,7 +554,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; @@ -555,8 +563,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] = @@ -578,7 +594,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; @@ -589,12 +605,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, @@ -602,12 +612,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 54f1dc05da62e83fbb842a5ca0ae2d0e9474f49f Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Thu, 31 May 2018 10:20:48 -0700 Subject: [PATCH 005/604] FROMLIST: f2fs: run fstrim asynchronously if runtime discard is on Cherry-picked from: origin/upstream-f2fs-stable-linux-4.9.y We don't need to wait for whole bunch of discard candidates in fstrim, since runtime discard will issue them in idle time. Change-Id: I2b4556522fcfa7ca2fc5461ecfbfad338a23a692 Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 98fe1edb0e6d..f04781b45985 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -2439,9 +2439,18 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) __init_discard_policy(sbi, &dpolicy, DPOLICY_FSTRIM, cpc.trim_minlen); __issue_discard_cmd_range(sbi, &dpolicy, start_block, end_block); - trimmed = __wait_discard_cmd_range(sbi, &dpolicy, + + /* + * We filed discard candidates, but actually we don't need to wait for + * all of them, since they'll be issued in idle time along with runtime + * discard option. User configuration looks like using runtime discard + * or periodic fstrim instead of it. + */ + if (!test_opt(sbi, DISCARD)) { + trimmed = __wait_discard_cmd_range(sbi, &dpolicy, start_block, end_block); - range->len = F2FS_BLK_TO_BYTES(trimmed); + range->len = F2FS_BLK_TO_BYTES(trimmed); + } out: return err; } -- GitLab From b27fb13e93b0b41d56706c1a577759ab69d80a3f Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 21 May 2018 17:44:57 +0100 Subject: [PATCH 006/604] arm64: lse: Add early clobbers to some input/output asm operands commit 32c3fa7cdf0c4a3eb8405fc3e13398de019e828b upstream. For LSE atomics that read and write a register operand, we need to ensure that these operands are annotated as "early clobber" if the register is written before all of the input operands have been consumed. Failure to do so can result in the compiler allocating the same register to both operands, leading to splats such as: Unable to handle kernel paging request at virtual address 11111122222221 [...] x1 : 1111111122222222 x0 : 1111111122222221 Process swapper/0 (pid: 1, stack limit = 0x000000008209f908) Call trace: test_atomic64+0x1360/0x155c where x0 has been allocated as both the value to be stored and also the atomic_t pointer. This patch adds the missing clobbers. Cc: Cc: Dave Martin Cc: Robin Murphy Reported-by: Mark Salter Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/atomic_lse.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h index 7457ce082b5f..d32a0160c89f 100644 --- a/arch/arm64/include/asm/atomic_lse.h +++ b/arch/arm64/include/asm/atomic_lse.h @@ -117,7 +117,7 @@ static inline void atomic_and(int i, atomic_t *v) /* LSE atomics */ " mvn %w[i], %w[i]\n" " stclr %w[i], %[v]") - : [i] "+r" (w0), [v] "+Q" (v->counter) + : [i] "+&r" (w0), [v] "+Q" (v->counter) : "r" (x1) : __LL_SC_CLOBBERS); } @@ -135,7 +135,7 @@ static inline int atomic_fetch_and##name(int i, atomic_t *v) \ /* LSE atomics */ \ " mvn %w[i], %w[i]\n" \ " ldclr" #mb " %w[i], %w[i], %[v]") \ - : [i] "+r" (w0), [v] "+Q" (v->counter) \ + : [i] "+&r" (w0), [v] "+Q" (v->counter) \ : "r" (x1) \ : __LL_SC_CLOBBERS, ##cl); \ \ @@ -161,7 +161,7 @@ static inline void atomic_sub(int i, atomic_t *v) /* LSE atomics */ " neg %w[i], %w[i]\n" " stadd %w[i], %[v]") - : [i] "+r" (w0), [v] "+Q" (v->counter) + : [i] "+&r" (w0), [v] "+Q" (v->counter) : "r" (x1) : __LL_SC_CLOBBERS); } @@ -180,7 +180,7 @@ static inline int atomic_sub_return##name(int i, atomic_t *v) \ " neg %w[i], %w[i]\n" \ " ldadd" #mb " %w[i], w30, %[v]\n" \ " add %w[i], %w[i], w30") \ - : [i] "+r" (w0), [v] "+Q" (v->counter) \ + : [i] "+&r" (w0), [v] "+Q" (v->counter) \ : "r" (x1) \ : __LL_SC_CLOBBERS , ##cl); \ \ @@ -207,7 +207,7 @@ static inline int atomic_fetch_sub##name(int i, atomic_t *v) \ /* LSE atomics */ \ " neg %w[i], %w[i]\n" \ " ldadd" #mb " %w[i], %w[i], %[v]") \ - : [i] "+r" (w0), [v] "+Q" (v->counter) \ + : [i] "+&r" (w0), [v] "+Q" (v->counter) \ : "r" (x1) \ : __LL_SC_CLOBBERS, ##cl); \ \ @@ -314,7 +314,7 @@ static inline void atomic64_and(long i, atomic64_t *v) /* LSE atomics */ " mvn %[i], %[i]\n" " stclr %[i], %[v]") - : [i] "+r" (x0), [v] "+Q" (v->counter) + : [i] "+&r" (x0), [v] "+Q" (v->counter) : "r" (x1) : __LL_SC_CLOBBERS); } @@ -332,7 +332,7 @@ static inline long atomic64_fetch_and##name(long i, atomic64_t *v) \ /* LSE atomics */ \ " mvn %[i], %[i]\n" \ " ldclr" #mb " %[i], %[i], %[v]") \ - : [i] "+r" (x0), [v] "+Q" (v->counter) \ + : [i] "+&r" (x0), [v] "+Q" (v->counter) \ : "r" (x1) \ : __LL_SC_CLOBBERS, ##cl); \ \ @@ -358,7 +358,7 @@ static inline void atomic64_sub(long i, atomic64_t *v) /* LSE atomics */ " neg %[i], %[i]\n" " stadd %[i], %[v]") - : [i] "+r" (x0), [v] "+Q" (v->counter) + : [i] "+&r" (x0), [v] "+Q" (v->counter) : "r" (x1) : __LL_SC_CLOBBERS); } @@ -377,7 +377,7 @@ static inline long atomic64_sub_return##name(long i, atomic64_t *v) \ " neg %[i], %[i]\n" \ " ldadd" #mb " %[i], x30, %[v]\n" \ " add %[i], %[i], x30") \ - : [i] "+r" (x0), [v] "+Q" (v->counter) \ + : [i] "+&r" (x0), [v] "+Q" (v->counter) \ : "r" (x1) \ : __LL_SC_CLOBBERS, ##cl); \ \ @@ -404,7 +404,7 @@ static inline long atomic64_fetch_sub##name(long i, atomic64_t *v) \ /* LSE atomics */ \ " neg %[i], %[i]\n" \ " ldadd" #mb " %[i], %[i], %[v]") \ - : [i] "+r" (x0), [v] "+Q" (v->counter) \ + : [i] "+&r" (x0), [v] "+Q" (v->counter) \ : "r" (x1) \ : __LL_SC_CLOBBERS, ##cl); \ \ @@ -516,7 +516,7 @@ static inline long __cmpxchg_double##name(unsigned long old1, \ " eor %[old1], %[old1], %[oldval1]\n" \ " eor %[old2], %[old2], %[oldval2]\n" \ " orr %[old1], %[old1], %[old2]") \ - : [old1] "+r" (x0), [old2] "+r" (x1), \ + : [old1] "+&r" (x0), [old2] "+&r" (x1), \ [v] "+Q" (*(unsigned long *)ptr) \ : [new1] "r" (x2), [new2] "r" (x3), [ptr] "r" (x4), \ [oldval1] "r" (oldval1), [oldval2] "r" (oldval2) \ -- GitLab From 09ae0d2ec919b2cf2e6f7dd4be034b060f12c18f Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Fri, 18 May 2018 11:37:42 +1000 Subject: [PATCH 007/604] powerpc/64s: Clear PCR on boot commit faf37c44a105f3608115785f17cbbf3500f8bc71 upstream. Clear the PCR (Processor Compatibility Register) on boot to ensure we are not running in a compatibility mode. We've seen this cause problems when a crash (and kdump) occurs while running compat mode guests. The kdump kernel then runs with the PCR set and causes problems. The symptom in the kdump kernel (also seen in petitboot after fast-reboot) is early userspace programs taking sigills on newer instructions (seen in libc). Signed-off-by: Michael Neuling Cc: stable@vger.kernel.org Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/cpu_setup_power.S | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S index 9e05c8828ee2..ff45d007d195 100644 --- a/arch/powerpc/kernel/cpu_setup_power.S +++ b/arch/powerpc/kernel/cpu_setup_power.S @@ -28,6 +28,7 @@ _GLOBAL(__setup_cpu_power7) beqlr li r0,0 mtspr SPRN_LPID,r0 + mtspr SPRN_PCR,r0 mfspr r3,SPRN_LPCR bl __init_LPCR bl __init_tlb_power7 @@ -41,6 +42,7 @@ _GLOBAL(__restore_cpu_power7) beqlr li r0,0 mtspr SPRN_LPID,r0 + mtspr SPRN_PCR,r0 mfspr r3,SPRN_LPCR bl __init_LPCR bl __init_tlb_power7 @@ -57,6 +59,7 @@ _GLOBAL(__setup_cpu_power8) beqlr li r0,0 mtspr SPRN_LPID,r0 + mtspr SPRN_PCR,r0 mfspr r3,SPRN_LPCR ori r3, r3, LPCR_PECEDH bl __init_LPCR @@ -78,6 +81,7 @@ _GLOBAL(__restore_cpu_power8) beqlr li r0,0 mtspr SPRN_LPID,r0 + mtspr SPRN_PCR,r0 mfspr r3,SPRN_LPCR ori r3, r3, LPCR_PECEDH bl __init_LPCR @@ -98,6 +102,7 @@ _GLOBAL(__setup_cpu_power9) li r0,0 mtspr SPRN_LPID,r0 mtspr SPRN_PID,r0 + mtspr SPRN_PCR,r0 mfspr r3,SPRN_LPCR LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE) or r3, r3, r4 @@ -121,6 +126,7 @@ _GLOBAL(__restore_cpu_power9) li r0,0 mtspr SPRN_LPID,r0 mtspr SPRN_PID,r0 + mtspr SPRN_PCR,r0 mfspr r3,SPRN_LPCR LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE) or r3, r3, r4 -- GitLab From 60a1dc530d3ab65ce07eb19d5bb630cef54a24bf Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 21 Nov 2016 13:19:31 +0100 Subject: [PATCH 008/604] USB: serial: cp210x: use tcflag_t to fix incompatible pointer type commit 009615ab7fd4e43b82a38e4e6adc5e23c1ee567f upstream. On sparc32, tcflag_t is unsigned long, unlike all other architectures: drivers/usb/serial/cp210x.c: In function 'cp210x_get_termios': drivers/usb/serial/cp210x.c:717:3: warning: passing argument 2 of 'cp210x_get_termios_port' from incompatible pointer type cp210x_get_termios_port(tty->driver_data, ^ drivers/usb/serial/cp210x.c:35:13: note: expected 'unsigned int *' but argument is of type 'tcflag_t *' static void cp210x_get_termios_port(struct usb_serial_port *port, ^ Consistently use tcflag_t to fix this. Signed-off-by: Geert Uytterhoeven Signed-off-by: Johan Hovold Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index d98531823998..46b4dea7a0ec 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -33,7 +33,7 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *); static void cp210x_close(struct usb_serial_port *); static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *); static void cp210x_get_termios_port(struct usb_serial_port *port, - unsigned int *cflagp, unsigned int *baudp); + tcflag_t *cflagp, unsigned int *baudp); static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *, struct ktermios *); static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *, @@ -728,7 +728,7 @@ static void cp210x_get_termios(struct tty_struct *tty, &tty->termios.c_cflag, &baud); tty_encode_baud_rate(tty, baud, baud); } else { - unsigned int cflag; + tcflag_t cflag; cflag = 0; cp210x_get_termios_port(port, &cflag, &baud); } @@ -739,10 +739,10 @@ static void cp210x_get_termios(struct tty_struct *tty, * This is the heart of cp210x_get_termios which always uses a &usb_serial_port. */ static void cp210x_get_termios_port(struct usb_serial_port *port, - unsigned int *cflagp, unsigned int *baudp) + tcflag_t *cflagp, unsigned int *baudp) { struct device *dev = &port->dev; - unsigned int cflag; + tcflag_t cflag; struct cp210x_flow_ctl flow_ctl; u32 baud; u16 bits; -- GitLab From 38accd6e50791d1136c0196f187523ba0eed6294 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 31 May 2018 17:58:13 +0200 Subject: [PATCH 009/604] Revert "pinctrl: msm: Use dynamic GPIO numbering" This reverts commit 0bd77073e693e8f93ff6ddba65a9f426153221cb which is commit a7aa75a2a7dba32594291a71c3704000a2fd7089 upstream. There's been too many complaints about this. Personally I think it's going to blow up when people hit this in mainline, but hey, it's not my systems. At least we don't have to backport the mess to the stable kernels to give them some more life to live unscathed :) Reported-by: Timur Tabi Reported-by: Sebastian Gottschall Cc: Bjorn Andersson Cc: Linus Walleij Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/pinctrl/qcom/pinctrl-msm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 056845bdf67b..bedce3453dd3 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -790,7 +790,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) return -EINVAL; chip = &pctrl->chip; - chip->base = -1; + chip->base = 0; chip->ngpio = ngpio; chip->label = dev_name(pctrl->dev); chip->parent = pctrl->dev; -- GitLab From 0f929c96926569416e9d1a1a81d1c4f59d8436aa Mon Sep 17 00:00:00 2001 From: Brian Foster Date: Thu, 15 Mar 2018 10:51:58 -0700 Subject: [PATCH 010/604] xfs: detect agfl count corruption and reset agfl commit a27ba2607e60312554cbcd43fc660b2c7f29dc9c upstream. The struct xfs_agfl v5 header was originally introduced with unexpected padding that caused the AGFL to operate with one less slot than intended. The header has since been packed, but the fix left an incompatibility for users who upgrade from an old kernel with the unpacked header to a newer kernel with the packed header while the AGFL happens to wrap around the end. The newer kernel recognizes one extra slot at the physical end of the AGFL that the previous kernel did not. The new kernel will eventually attempt to allocate a block from that slot, which contains invalid data, and cause a crash. This condition can be detected by comparing the active range of the AGFL to the count. While this detects a padding mismatch, it can also trigger false positives for unrelated flcount corruption. Since we cannot distinguish a size mismatch due to padding from unrelated corruption, we can't trust the AGFL enough to simply repopulate the empty slot. Instead, avoid unnecessarily complex detection logic and and use a solution that can handle any form of flcount corruption that slips through read verifiers: distrust the entire AGFL and reset it to an empty state. Any valid blocks within the AGFL are intentionally leaked. This requires xfs_repair to rectify (which was already necessary based on the state the AGFL was found in). The reset mitigates the side effect of the padding mismatch problem from a filesystem crash to a free space accounting inconsistency. The generic approach also means that this patch can be safely backported to kernels with or without a packed struct xfs_agfl. Check the AGF for an invalid freelist count on initial read from disk. If detected, set a flag on the xfs_perag to indicate that a reset is required before the AGFL can be used. In the first transaction that attempts to use a flagged AGFL, reset it to empty, warn the user about the inconsistency and allow the freelist fixup code to repopulate the AGFL with new blocks. The xfs_perag flag is cleared to eliminate the need for repeated checks on each block allocation operation. This allows kernels that include the packing fix commit 96f859d52bcb ("libxfs: pack the agfl header structure so XFS_AGFL_SIZE is correct") to handle older unpacked AGFL formats without a filesystem crash. Suggested-by: Dave Chinner Signed-off-by: Brian Foster Reviewed-by: Darrick J. Wong Reviewed-by Dave Chiluk Signed-off-by: Darrick J. Wong Signed-off-by: Dave Chiluk Signed-off-by: Greg Kroah-Hartman --- fs/xfs/libxfs/xfs_alloc.c | 94 +++++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_mount.h | 1 + fs/xfs/xfs_trace.h | 9 +++- 3 files changed, 103 insertions(+), 1 deletion(-) diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c index c3702cda010a..e567551402a6 100644 --- a/fs/xfs/libxfs/xfs_alloc.c +++ b/fs/xfs/libxfs/xfs_alloc.c @@ -2034,6 +2034,93 @@ xfs_alloc_space_available( return true; } +/* + * Check the agfl fields of the agf for inconsistency or corruption. The purpose + * is to detect an agfl header padding mismatch between current and early v5 + * kernels. This problem manifests as a 1-slot size difference between the + * on-disk flcount and the active [first, last] range of a wrapped agfl. This + * may also catch variants of agfl count corruption unrelated to padding. Either + * way, we'll reset the agfl and warn the user. + * + * Return true if a reset is required before the agfl can be used, false + * otherwise. + */ +static bool +xfs_agfl_needs_reset( + struct xfs_mount *mp, + struct xfs_agf *agf) +{ + uint32_t f = be32_to_cpu(agf->agf_flfirst); + uint32_t l = be32_to_cpu(agf->agf_fllast); + uint32_t c = be32_to_cpu(agf->agf_flcount); + int agfl_size = XFS_AGFL_SIZE(mp); + int active; + + /* no agfl header on v4 supers */ + if (!xfs_sb_version_hascrc(&mp->m_sb)) + return false; + + /* + * The agf read verifier catches severe corruption of these fields. + * Repeat some sanity checks to cover a packed -> unpacked mismatch if + * the verifier allows it. + */ + if (f >= agfl_size || l >= agfl_size) + return true; + if (c > agfl_size) + return true; + + /* + * Check consistency between the on-disk count and the active range. An + * agfl padding mismatch manifests as an inconsistent flcount. + */ + if (c && l >= f) + active = l - f + 1; + else if (c) + active = agfl_size - f + l + 1; + else + active = 0; + + return active != c; +} + +/* + * Reset the agfl to an empty state. Ignore/drop any existing blocks since the + * agfl content cannot be trusted. Warn the user that a repair is required to + * recover leaked blocks. + * + * The purpose of this mechanism is to handle filesystems affected by the agfl + * header padding mismatch problem. A reset keeps the filesystem online with a + * relatively minor free space accounting inconsistency rather than suffer the + * inevitable crash from use of an invalid agfl block. + */ +static void +xfs_agfl_reset( + struct xfs_trans *tp, + struct xfs_buf *agbp, + struct xfs_perag *pag) +{ + struct xfs_mount *mp = tp->t_mountp; + struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); + + ASSERT(pag->pagf_agflreset); + trace_xfs_agfl_reset(mp, agf, 0, _RET_IP_); + + xfs_warn(mp, + "WARNING: Reset corrupted AGFL on AG %u. %d blocks leaked. " + "Please unmount and run xfs_repair.", + pag->pag_agno, pag->pagf_flcount); + + agf->agf_flfirst = 0; + agf->agf_fllast = cpu_to_be32(XFS_AGFL_SIZE(mp) - 1); + agf->agf_flcount = 0; + xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLFIRST | XFS_AGF_FLLAST | + XFS_AGF_FLCOUNT); + + pag->pagf_flcount = 0; + pag->pagf_agflreset = false; +} + /* * Decide whether to use this allocation group for this allocation. * If so, fix up the btree freelist's size. @@ -2095,6 +2182,10 @@ xfs_alloc_fix_freelist( } } + /* reset a padding mismatched agfl before final free space check */ + if (pag->pagf_agflreset) + xfs_agfl_reset(tp, agbp, pag); + /* If there isn't enough total space or single-extent, reject it. */ need = xfs_alloc_min_freelist(mp, pag); if (!xfs_alloc_space_available(args, need, flags)) @@ -2251,6 +2342,7 @@ xfs_alloc_get_freelist( agf->agf_flfirst = 0; pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno)); + ASSERT(!pag->pagf_agflreset); be32_add_cpu(&agf->agf_flcount, -1); xfs_trans_agflist_delta(tp, -1); pag->pagf_flcount--; @@ -2362,6 +2454,7 @@ xfs_alloc_put_freelist( agf->agf_fllast = 0; pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno)); + ASSERT(!pag->pagf_agflreset); be32_add_cpu(&agf->agf_flcount, 1); xfs_trans_agflist_delta(tp, 1); pag->pagf_flcount++; @@ -2568,6 +2661,7 @@ xfs_alloc_read_agf( pag->pagb_count = 0; pag->pagb_tree = RB_ROOT; pag->pagf_init = 1; + pag->pagf_agflreset = xfs_agfl_needs_reset(mp, agf); } #ifdef DEBUG else if (!XFS_FORCED_SHUTDOWN(mp)) { diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 5415f9031ef8..7cb099e1c84c 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -368,6 +368,7 @@ typedef struct xfs_perag { char pagi_inodeok; /* The agi is ok for inodes */ __uint8_t pagf_levels[XFS_BTNUM_AGF]; /* # of levels in bno & cnt btree */ + bool pagf_agflreset; /* agfl requires reset before use */ __uint32_t pagf_flcount; /* count of blocks in freelist */ xfs_extlen_t pagf_freeblks; /* total free blocks */ xfs_extlen_t pagf_longest; /* longest free space */ diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index bdf69e1c7410..42a7c0da898f 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -1516,7 +1516,7 @@ TRACE_EVENT(xfs_trans_commit_lsn, __entry->lsn) ); -TRACE_EVENT(xfs_agf, +DECLARE_EVENT_CLASS(xfs_agf_class, TP_PROTO(struct xfs_mount *mp, struct xfs_agf *agf, int flags, unsigned long caller_ip), TP_ARGS(mp, agf, flags, caller_ip), @@ -1572,6 +1572,13 @@ TRACE_EVENT(xfs_agf, __entry->longest, (void *)__entry->caller_ip) ); +#define DEFINE_AGF_EVENT(name) \ +DEFINE_EVENT(xfs_agf_class, name, \ + TP_PROTO(struct xfs_mount *mp, struct xfs_agf *agf, int flags, \ + unsigned long caller_ip), \ + TP_ARGS(mp, agf, flags, caller_ip)) +DEFINE_AGF_EVENT(xfs_agf); +DEFINE_AGF_EVENT(xfs_agfl_reset); TRACE_EVENT(xfs_free_extent, TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno, -- GitLab From 28fffa9066d48794171a0cd8bf37c5d6ee0dd834 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Wed, 2 Nov 2016 09:14:16 -0400 Subject: [PATCH 011/604] Revert "ima: limit file hash setting by user to fix and log modes" commit f5acb3dcba1ffb7f0b8cbb9dba61500eea5d610b upstream. Userspace applications have been modified to write security xattrs, but they are not context aware. In the case of security.ima, the security xattr can be either a file hash or a file signature. Permitting writing one, but not the other requires the application to be context aware. In addition, userspace applications might write files to a staging area, which might not be in policy, and then change some file metadata (eg. owner) making it in policy. As a result, these files are not labeled properly. This reverts commit c68ed80c97d9720f51ef31fe91560fdd1e121533, which prevents writing file hashes as security.ima xattrs. Requested-by: Patrick Ohly Cc: Dmitry Kasatkin Signed-off-by: Mimi Zohar Cc: Mike Rapoport Signed-off-by: Greg Kroah-Hartman --- security/integrity/ima/ima_appraise.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 7bf8b005a178..1e6f23f77f15 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -389,14 +389,10 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, result = ima_protect_xattr(dentry, xattr_name, xattr_value, xattr_value_len); if (result == 1) { - bool digsig; - if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST)) return -EINVAL; - digsig = (xvalue->type == EVM_IMA_XATTR_DIGSIG); - if (!digsig && (ima_appraise & IMA_APPRAISE_ENFORCE)) - return -EPERM; - ima_reset_appraise_flags(d_backing_inode(dentry), digsig); + ima_reset_appraise_flags(d_backing_inode(dentry), + (xvalue->type == EVM_IMA_XATTR_DIGSIG) ? 1 : 0); result = 0; } return result; -- GitLab From 87efba9b5b558bd87c2a3bdd9f0193519fa7c3a7 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 22 May 2018 17:19:57 -0700 Subject: [PATCH 012/604] Input: elan_i2c_smbus - fix corrupted stack commit 40f7090bb1b4ec327ea1e1402ff5783af5b35195 upstream. New ICs (like the one on the Lenovo T480s) answer to ETP_SMBUS_IAP_VERSION_CMD 4 bytes instead of 3. This corrupts the stack as i2c_smbus_read_block_data() uses the values returned by the i2c device to know how many data it need to return. i2c_smbus_read_block_data() can read up to 32 bytes (I2C_SMBUS_BLOCK_MAX) and there is no safeguard on how many bytes are provided in the return value. Ensure we always have enough space for any future firmware. Also 0-initialize the values to prevent any access to uninitialized memory. Cc: # v4.4.x, v4.9.x, v4.14.x, v4.15.x, v4.16.x Signed-off-by: Benjamin Tissoires Acked-by: KT Liao Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/mouse/elan_i2c_smbus.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c index e23b2495d52e..05b8695a6369 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c @@ -130,7 +130,7 @@ static int elan_smbus_get_baseline_data(struct i2c_client *client, bool max_baseline, u8 *value) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, max_baseline ? @@ -149,7 +149,7 @@ static int elan_smbus_get_version(struct i2c_client *client, bool iap, u8 *version) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, iap ? ETP_SMBUS_IAP_VERSION_CMD : @@ -169,7 +169,7 @@ static int elan_smbus_get_sm_version(struct i2c_client *client, u8 *ic_type, u8 *version) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, ETP_SMBUS_SM_VERSION_CMD, val); @@ -186,7 +186,7 @@ static int elan_smbus_get_sm_version(struct i2c_client *client, static int elan_smbus_get_product_id(struct i2c_client *client, u16 *id) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, ETP_SMBUS_UNIQUEID_CMD, val); @@ -203,7 +203,7 @@ static int elan_smbus_get_checksum(struct i2c_client *client, bool iap, u16 *csum) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, iap ? ETP_SMBUS_FW_CHECKSUM_CMD : @@ -224,7 +224,7 @@ static int elan_smbus_get_max(struct i2c_client *client, { int ret; int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; ret = i2c_smbus_read_block_data(client, ETP_SMBUS_RANGE_CMD, val); if (ret != 3) { @@ -244,7 +244,7 @@ static int elan_smbus_get_resolution(struct i2c_client *client, { int ret; int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; ret = i2c_smbus_read_block_data(client, ETP_SMBUS_RESOLUTION_CMD, val); if (ret != 3) { @@ -265,7 +265,7 @@ static int elan_smbus_get_num_traces(struct i2c_client *client, { int ret; int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; ret = i2c_smbus_read_block_data(client, ETP_SMBUS_XY_TRACENUM_CMD, val); if (ret != 3) { @@ -292,7 +292,7 @@ static int elan_smbus_iap_get_mode(struct i2c_client *client, { int error; u16 constant; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, ETP_SMBUS_IAP_CTRL_CMD, val); if (error < 0) { @@ -343,7 +343,7 @@ static int elan_smbus_prepare_fw_update(struct i2c_client *client) int len; int error; enum tp_mode mode; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; u8 cmd[4] = {0x0F, 0x78, 0x00, 0x06}; u16 password; @@ -417,7 +417,7 @@ static int elan_smbus_write_fw_block(struct i2c_client *client, struct device *dev = &client->dev; int error; u16 result; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; /* * Due to the limitation of smbus protocol limiting -- GitLab From dfc80dcea2b101828cb07654dcc797166d3e1292 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Sun, 27 May 2018 20:54:44 -0400 Subject: [PATCH 013/604] tracing: Fix crash when freeing instances with event triggers commit 86b389ff22bd6ad8fd3cb98e41cd271886c6d023 upstream. If a instance has an event trigger enabled when it is freed, it could cause an access of free memory. Here's the case that crashes: # cd /sys/kernel/tracing # mkdir instances/foo # echo snapshot > instances/foo/events/initcall/initcall_start/trigger # rmdir instances/foo Would produce: general protection fault: 0000 [#1] PREEMPT SMP PTI Modules linked in: tun bridge ... CPU: 5 PID: 6203 Comm: rmdir Tainted: G W 4.17.0-rc4-test+ #933 Hardware name: Hewlett-Packard HP Compaq Pro 6300 SFF/339A, BIOS K01 v03.03 07/14/2016 RIP: 0010:clear_event_triggers+0x3b/0x70 RSP: 0018:ffffc90003783de0 EFLAGS: 00010286 RAX: 0000000000000000 RBX: 6b6b6b6b6b6b6b2b RCX: 0000000000000000 RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff8800c7130ba0 RBP: ffffc90003783e00 R08: ffff8801131993f8 R09: 0000000100230016 R10: ffffc90003783d80 R11: 0000000000000000 R12: ffff8800c7130ba0 R13: ffff8800c7130bd8 R14: ffff8800cc093768 R15: 00000000ffffff9c FS: 00007f6f4aa86700(0000) GS:ffff88011eb40000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f6f4a5aed60 CR3: 00000000cd552001 CR4: 00000000001606e0 Call Trace: event_trace_del_tracer+0x2a/0xc5 instance_rmdir+0x15c/0x200 tracefs_syscall_rmdir+0x52/0x90 vfs_rmdir+0xdb/0x160 do_rmdir+0x16d/0x1c0 __x64_sys_rmdir+0x17/0x20 do_syscall_64+0x55/0x1a0 entry_SYSCALL_64_after_hwframe+0x49/0xbe This was due to the call the clears out the triggers when an instance is being deleted not removing the trigger from the link list. Cc: stable@vger.kernel.org Fixes: 85f2b08268c01 ("tracing: Add basic event trigger framework") Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_events_trigger.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c index 6721a1e89f39..88f398af57fa 100644 --- a/kernel/trace/trace_events_trigger.c +++ b/kernel/trace/trace_events_trigger.c @@ -481,9 +481,10 @@ clear_event_triggers(struct trace_array *tr) struct trace_event_file *file; list_for_each_entry(file, &tr->events, list) { - struct event_trigger_data *data; - list_for_each_entry_rcu(data, &file->triggers, list) { + struct event_trigger_data *data, *n; + list_for_each_entry_safe(data, n, &file->triggers, list) { trace_event_trigger_enable_disable(file, 0); + list_del_rcu(&data->list); if (data->ops->free) data->ops->free(data->ops, data); } -- GitLab From c738c806495e62e0eef6a2ee2eddb32b83751eb8 Mon Sep 17 00:00:00 2001 From: Sachin Grover Date: Fri, 25 May 2018 14:01:39 +0530 Subject: [PATCH 014/604] selinux: KASAN: slab-out-of-bounds in xattr_getsecurity commit efe3de79e0b52ca281ef6691480c8c68c82a4657 upstream. Call trace: [] dump_backtrace+0x0/0x428 [] show_stack+0x28/0x38 [] dump_stack+0xd4/0x124 [] print_address_description+0x68/0x258 [] kasan_report.part.2+0x228/0x2f0 [] kasan_report+0x5c/0x70 [] check_memory_region+0x12c/0x1c0 [] memcpy+0x34/0x68 [] xattr_getsecurity+0xe0/0x160 [] vfs_getxattr+0xc8/0x120 [] getxattr+0x100/0x2c8 [] SyS_fgetxattr+0x64/0xa0 [] el0_svc_naked+0x24/0x28 If user get root access and calls security.selinux setxattr() with an embedded NUL on a file and then if some process performs a getxattr() on that file with a length greater than the actual length of the string, it would result in a panic. To fix this, add the actual length of the string to the security context instead of the length passed by the userspace process. Signed-off-by: Sachin Grover Cc: stable@vger.kernel.org Signed-off-by: Paul Moore Signed-off-by: Greg Kroah-Hartman --- security/selinux/ss/services.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index d656b7c98394..bfc4ffa1fa1a 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -1435,7 +1435,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, scontext_len, &context, def_sid); if (rc == -EINVAL && force) { context.str = str; - context.len = scontext_len; + context.len = strlen(str) + 1; str = NULL; } else if (rc) goto out_unlock; -- GitLab From fa4724c51a898f64263ed06b4f76976b48debedf Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 14 May 2018 20:09:24 -0700 Subject: [PATCH 015/604] cfg80211: further limit wiphy names to 64 bytes commit 814596495dd2b9d4aab92d8f89cf19060d25d2ea upstream. wiphy names were recently limited to 128 bytes by commit a7cfebcb7594 ("cfg80211: limit wiphy names to 128 bytes"). As it turns out though, this isn't sufficient because dev_vprintk_emit() needs the syslog header string "SUBSYSTEM=ieee80211\0DEVICE=+ieee80211:$devname" to fit into 128 bytes. This triggered the "device/subsystem name too long" WARN when the device name was >= 90 bytes. As before, this was reproduced by syzbot by sending an HWSIM_CMD_NEW_RADIO command to the MAC80211_HWSIM generic netlink family. Fix it by further limiting wiphy names to 64 bytes. Reported-by: syzbot+e64565577af34b3768dc@syzkaller.appspotmail.com Fixes: a7cfebcb7594 ("cfg80211: limit wiphy names to 128 bytes") Signed-off-by: Eric Biggers Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/nl80211.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 7290eacc8cee..b902f106f69a 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2379,7 +2379,7 @@ enum nl80211_attrs { #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS #define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS -#define NL80211_WIPHY_NAME_MAXLEN 128 +#define NL80211_WIPHY_NAME_MAXLEN 64 #define NL80211_MAX_SUPP_RATES 32 #define NL80211_MAX_SUPP_HT_RATES 77 -- GitLab From ecfed29cc1951c5affac0cb5be9f50cfa1036700 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 15 Sep 2017 00:05:16 +0100 Subject: [PATCH 016/604] dma-buf: remove redundant initialization of sg_table commit 531beb067c6185aceabfdee0965234c6a8fd133b upstream. sg_table is being initialized and is never read before it is updated again later on, hence making the initialization redundant. Remove the initialization. Detected by clang scan-build: "warning: Value stored to 'sg_table' during its initialization is never read" Signed-off-by: Colin Ian King Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20170914230516.6056-1-colin.king@canonical.com Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/dma-buf/dma-buf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 6b54e02da10c..e48140e76043 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -551,7 +551,7 @@ EXPORT_SYMBOL_GPL(dma_buf_detach); struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, enum dma_data_direction direction) { - struct sg_table *sg_table = ERR_PTR(-EINVAL); + struct sg_table *sg_table; might_sleep(); -- GitLab From fd9c9fff2fee867a42d83eca65eb5767d1837193 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Thu, 8 Feb 2018 16:57:12 -0800 Subject: [PATCH 017/604] rtlwifi: rtl8192cu: Remove variable self-assignment in rf.c commit fb239c1209bb0f0b4830cc72507cc2f2d63fadbd upstream. In _rtl92c_get_txpower_writeval_by_regulatory() the variable writeVal is assigned to itself in an if ... else statement, apparently only to document that the branch condition is handled and that a previously read value should be returned unmodified. The self-assignment causes clang to raise the following warning: drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c:304:13: error: explicitly assigning value of variable of type 'u32' (aka 'unsigned int') to itself [-Werror,-Wself-assign] writeVal = writeVal; Delete the branch with the self-assignment. Signed-off-by: Matthias Kaehlcke Acked-by: Larry Finger Reviewed-by: Guenter Roeck Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c index ec2ea56f7933..fdbd35954d15 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c @@ -304,9 +304,6 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw, writeVal = 0x00000000; if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1) writeVal = writeVal - 0x06060606; - else if (rtlpriv->dm.dynamic_txhighpower_lvl == - TXHIGHPWRLEVEL_BT2) - writeVal = writeVal; *(p_outwriteval + rf) = writeVal; } } -- GitLab From a38249d6dcfb6554f0765f9529d49f96454d9a1e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 19 Oct 2017 14:33:52 +0200 Subject: [PATCH 018/604] ASoC: Intel: sst: remove redundant variable dma_dev_name commit 271ef65b5882425d500e969e875c98e47a6b0c86 upstream. The pointer dma_dev_name is assigned but never read, it is redundant and can therefore be removed. Cleans up clang warning: sound/soc/intel/common/sst-firmware.c:288:3: warning: Value stored to 'dma_dev_name' is never read Signed-off-by: Colin Ian King Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- sound/soc/intel/common/sst-firmware.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c index a086c35f91bb..79a9fdf94d38 100644 --- a/sound/soc/intel/common/sst-firmware.c +++ b/sound/soc/intel/common/sst-firmware.c @@ -274,7 +274,6 @@ int sst_dma_new(struct sst_dsp *sst) struct sst_pdata *sst_pdata = sst->pdata; struct sst_dma *dma; struct resource mem; - const char *dma_dev_name; int ret = 0; if (sst->pdata->resindex_dma_base == -1) @@ -285,7 +284,6 @@ int sst_dma_new(struct sst_dsp *sst) * is attached to the ADSP IP. */ switch (sst->pdata->dma_engine) { case SST_DMA_TYPE_DW: - dma_dev_name = "dw_dmac"; break; default: dev_err(sst->dev, "error: invalid DMA engine %d\n", -- GitLab From 219270d70a8783ad067e7c471eefdf27cc93b1d1 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 31 Oct 2017 10:27:47 +0000 Subject: [PATCH 019/604] platform/chrome: cros_ec_lpc: remove redundant pointer request commit d3b56c566d4ba8cae688baf3cca94425d57ea783 upstream. Pointer request is being assigned but never used, so remove it. Cleans up the clang warning: drivers/platform/chrome/cros_ec_lpc.c:68:2: warning: Value stored to 'request' is never read Signed-off-by: Colin Ian King Signed-off-by: Benson Leung Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/platform/chrome/cros_ec_lpc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c index f9a245465fd0..6a25bfd4541e 100644 --- a/drivers/platform/chrome/cros_ec_lpc.c +++ b/drivers/platform/chrome/cros_ec_lpc.c @@ -49,7 +49,6 @@ static int ec_response_timed_out(void) static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec, struct cros_ec_command *msg) { - struct ec_host_request *request; struct ec_host_response response; u8 sum = 0; int i; @@ -62,8 +61,6 @@ static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec, for (i = 0; i < ret; i++) outb(ec->dout[i], EC_LPC_ADDR_HOST_PACKET + i); - request = (struct ec_host_request *)ec->dout; - /* Here we go */ outb(EC_COMMAND_PROTOCOL_3, EC_LPC_ADDR_HOST_CMD); -- GitLab From 474928b8f0a6ba49872ef2769610b80638820aad Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Wed, 30 May 2018 13:09:56 +0200 Subject: [PATCH 020/604] x86/amd: revert commit 944e0fc51a89c9827b9 Revert commit 944e0fc51a89c9827b98813d65dc083274777c7f ("x86/amd: don't set X86_BUG_SYSRET_SS_ATTRS when running under Xen") as it is lacking a prerequisite patch and is making things worse. Signed-off-by: Juergen Gross Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/amd.c | 5 ++--- arch/x86/xen/enlighten.c | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 4c2be99fa0fb..cd0abf8ed314 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -857,9 +857,8 @@ static void init_amd(struct cpuinfo_x86 *c) if (cpu_has(c, X86_FEATURE_3DNOW) || cpu_has(c, X86_FEATURE_LM)) set_cpu_cap(c, X86_FEATURE_3DNOWPREFETCH); - /* AMD CPUs don't reset SS attributes on SYSRET, Xen does. */ - if (!cpu_has(c, X86_FEATURE_XENPV)) - set_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS); + /* AMD CPUs don't reset SS attributes on SYSRET */ + set_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS); } #ifdef CONFIG_X86_32 diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index e3a3f5a64884..b19ba66c15f1 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -1980,8 +1980,10 @@ EXPORT_SYMBOL_GPL(xen_hvm_need_lapic); static void xen_set_cpu_features(struct cpuinfo_x86 *c) { - if (xen_pv_domain()) + if (xen_pv_domain()) { + clear_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS); set_cpu_cap(c, X86_FEATURE_XENPV); + } } static void xen_pin_vcpu(int cpu) -- GitLab From bb70de1f993b5a7fffe9d42c68907b60ef5319a6 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Wed, 30 May 2018 13:09:57 +0200 Subject: [PATCH 021/604] xen: set cpu capabilities from xen_start_kernel() Upstream commit: 0808e80cb760de2733c0527d2090ed2205a1eef8 ("xen: set cpu capabilities from xen_start_kernel()") There is no need to set the same capabilities for each cpu individually. This can easily be done for all cpus when starting the kernel. Signed-off-by: Juergen Gross Reviewed-by: Boris Ostrovsky Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/enlighten.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index b19ba66c15f1..27f461fe4f29 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -472,6 +472,14 @@ static void __init xen_init_cpuid_mask(void) cpuid_leaf1_ecx_set_mask = (1 << (X86_FEATURE_MWAIT % 32)); } +static void __init xen_init_capabilities(void) +{ + if (xen_pv_domain()) { + setup_clear_cpu_cap(X86_BUG_SYSRET_SS_ATTRS); + setup_force_cpu_cap(X86_FEATURE_XENPV); + } +} + static void xen_set_debugreg(int reg, unsigned long val) { HYPERVISOR_set_debugreg(reg, val); @@ -1634,6 +1642,7 @@ asmlinkage __visible void __init xen_start_kernel(void) xen_init_irq_ops(); xen_init_cpuid_mask(); + xen_init_capabilities(); #ifdef CONFIG_X86_LOCAL_APIC /* @@ -1978,14 +1987,6 @@ bool xen_hvm_need_lapic(void) } EXPORT_SYMBOL_GPL(xen_hvm_need_lapic); -static void xen_set_cpu_features(struct cpuinfo_x86 *c) -{ - if (xen_pv_domain()) { - clear_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS); - set_cpu_cap(c, X86_FEATURE_XENPV); - } -} - static void xen_pin_vcpu(int cpu) { static bool disable_pinning; @@ -2032,7 +2033,6 @@ const struct hypervisor_x86 x86_hyper_xen = { .init_platform = xen_hvm_guest_init, #endif .x2apic_available = xen_x2apic_para_available, - .set_cpu_features = xen_set_cpu_features, .pin_vcpu = xen_pin_vcpu, }; EXPORT_SYMBOL(x86_hyper_xen); -- GitLab From c43b4ff972a986c85bdd8dc1aa05fe23b29ef99c Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Wed, 30 May 2018 13:09:58 +0200 Subject: [PATCH 022/604] x86/amd: don't set X86_BUG_SYSRET_SS_ATTRS when running under Xen Upstream commit: def9331a12977770cc6132d79f8e6565871e8e38 ("x86/amd: don't set X86_BUG_SYSRET_SS_ATTRS when running under Xen") When running as Xen pv guest X86_BUG_SYSRET_SS_ATTRS must not be set on AMD cpus. This bug/feature bit is kind of special as it will be used very early when switching threads. Setting the bit and clearing it a little bit later leaves a critical window where things can go wrong. This time window has enlarged a little bit by using setup_clear_cpu_cap() instead of the hypervisor's set_cpu_features callback. It seems this larger window now makes it rather easy to hit the problem. The proper solution is to never set the bit in case of Xen. Signed-off-by: Juergen Gross Reviewed-by: Boris Ostrovsky Acked-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/amd.c | 5 +++-- arch/x86/xen/enlighten.c | 4 +--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index cd0abf8ed314..4c2be99fa0fb 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -857,8 +857,9 @@ static void init_amd(struct cpuinfo_x86 *c) if (cpu_has(c, X86_FEATURE_3DNOW) || cpu_has(c, X86_FEATURE_LM)) set_cpu_cap(c, X86_FEATURE_3DNOWPREFETCH); - /* AMD CPUs don't reset SS attributes on SYSRET */ - set_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS); + /* AMD CPUs don't reset SS attributes on SYSRET, Xen does. */ + if (!cpu_has(c, X86_FEATURE_XENPV)) + set_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS); } #ifdef CONFIG_X86_32 diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 27f461fe4f29..2986a13b9786 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -474,10 +474,8 @@ static void __init xen_init_cpuid_mask(void) static void __init xen_init_capabilities(void) { - if (xen_pv_domain()) { - setup_clear_cpu_cap(X86_BUG_SYSRET_SS_ATTRS); + if (xen_pv_domain()) setup_force_cpu_cap(X86_FEATURE_XENPV); - } } static void xen_set_debugreg(int reg, unsigned long val) -- GitLab From 7966e76f6a2484573e00e1661a37c974854f4367 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 10 Dec 2017 17:55:03 -0800 Subject: [PATCH 023/604] tcp: avoid integer overflows in tcp_rcv_space_adjust() commit 607065bad9931e72207b0cac365d7d4abc06bd99 upstream. When using large tcp_rmem[2] values (I did tests with 500 MB), I noticed overflows while computing rcvwin. Lets fix this before the following patch. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Acked-by: Wei Wang Acked-by: Neal Cardwell Signed-off-by: David S. Miller [Backport: sysctl_tcp_rmem is not Namespace-ify'd in older kernels] Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- include/linux/tcp.h | 2 +- net/ipv4/tcp_input.c | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index f50b717ce644..d0c3615f9050 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -337,7 +337,7 @@ struct tcp_sock { /* Receiver queue space */ struct { - int space; + u32 space; u32 seq; u32 time; } rcvq_space; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 52b0a84be765..94a55b83e48c 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -581,8 +581,8 @@ static inline void tcp_rcv_rtt_measure_ts(struct sock *sk, void tcp_rcv_space_adjust(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); + u32 copied; int time; - int copied; time = tcp_time_stamp - tp->rcvq_space.time; if (time < (tp->rcv_rtt_est.rtt >> 3) || tp->rcv_rtt_est.rtt == 0) @@ -604,12 +604,13 @@ void tcp_rcv_space_adjust(struct sock *sk) if (sysctl_tcp_moderate_rcvbuf && !(sk->sk_userlocks & SOCK_RCVBUF_LOCK)) { - int rcvwin, rcvmem, rcvbuf; + int rcvmem, rcvbuf; + u64 rcvwin; /* minimal window to cope with packet losses, assuming * steady state. Add some cushion because of small variations. */ - rcvwin = (copied << 1) + 16 * tp->advmss; + rcvwin = ((u64)copied << 1) + 16 * tp->advmss; /* If rate increased by 25%, * assume slow start, rcvwin = 3 * copied @@ -629,7 +630,8 @@ void tcp_rcv_space_adjust(struct sock *sk) while (tcp_win_from_space(rcvmem) < tp->advmss) rcvmem += 128; - rcvbuf = min(rcvwin / tp->advmss * rcvmem, sysctl_tcp_rmem[2]); + do_div(rcvwin, tp->advmss); + rcvbuf = min_t(u64, rcvwin * rcvmem, sysctl_tcp_rmem[2]); if (rcvbuf > sk->sk_rcvbuf) { sk->sk_rcvbuf = rcvbuf; -- GitLab From b0a12b452a082ee2b29dfe9ce3818b3690c6f596 Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Wed, 23 Nov 2016 16:31:41 -0800 Subject: [PATCH 024/604] scsi: ufs: fix failure to read the string descriptor commit bde44bb665d049468b6a1a2fa7d666434de4f83f upstream. While reading variable size descriptors (like string descriptor), some UFS devices may report the "LENGTH" (field in "Transaction Specific fields" of Query Response UPIU) same as what was requested in Query Request UPIU instead of reporting the actual size of the variable size descriptor. Although it's safe to ignore the "LENGTH" field for variable size descriptors as we can always derive the length of the descriptor from the descriptor header fields. Hence this change impose the length match check only for fixed size descriptors (for which we always request the correct size as part of Query Request UPIU). Reviewed-by: Venkat Gopalakrishnan Signed-off-by: Subhash Jadavani Signed-off-by: Martin K. Petersen [Wei Li: Slight tweaks to get the cherry-pick to apply,resolved collisions.] Signed-off-by: Li Wei Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/ufs/ufshcd.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 98a7111dd53f..a4fee1e4fdda 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2086,15 +2086,38 @@ static int ufshcd_read_desc_param(struct ufs_hba *hba, desc_id, desc_index, 0, desc_buf, &buff_len); - if (ret || (buff_len < ufs_query_desc_max_size[desc_id]) || - (desc_buf[QUERY_DESC_LENGTH_OFFSET] != - ufs_query_desc_max_size[desc_id]) - || (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id)) { - dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d param_offset %d buff_len %d ret %d", - __func__, desc_id, param_offset, buff_len, ret); - if (!ret) - ret = -EINVAL; + if (ret) { + dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d", + __func__, desc_id, desc_index, param_offset, ret); + + goto out; + } + + /* Sanity check */ + if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) { + dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header", + __func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]); + ret = -EINVAL; + goto out; + } + /* + * While reading variable size descriptors (like string descriptor), + * some UFS devices may report the "LENGTH" (field in "Transaction + * Specific fields" of Query Response UPIU) same as what was requested + * in Query Request UPIU instead of reporting the actual size of the + * variable size descriptor. + * Although it's safe to ignore the "LENGTH" field for variable size + * descriptors as we can always derive the length of the descriptor from + * the descriptor header fields. Hence this change impose the length + * match check only for fixed size descriptors (for which we always + * request the correct size as part of Query Request UPIU). + */ + if ((desc_id != QUERY_DESC_IDN_STRING) && + (buff_len != desc_buf[QUERY_DESC_LENGTH_OFFSET])) { + dev_err(hba->dev, "%s: desc_buf length mismatch: buff_len %d, buff_len(desc_header) %d", + __func__, buff_len, desc_buf[QUERY_DESC_LENGTH_OFFSET]); + ret = -EINVAL; goto out; } -- GitLab From be4d66d6b6f2cdfec92f1bd2fd44edd633097afd Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 5 Jan 2017 10:45:12 +0200 Subject: [PATCH 025/604] scsi: ufs: refactor device descriptor reading commit 93fdd5ac64bbe80dac6416f048405362d7ef0945 upstream. Pull device descriptor reading out of ufs quirk so it can be used also for other purposes. Revamp the fixup setup: 1. Rename ufs_device_info to ufs_dev_desc as very similar name ufs_dev_info is already in use. 2. Make the handlers static as they are not used out of the ufshdc.c file. [mkp: applied by hand] Signed-off-by: Tomas Winkler Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen Signed-off-by: Li Wei Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/ufs/ufs.h | 12 +++++++++++ drivers/scsi/ufs/ufs_quirks.h | 28 ++++++------------------ drivers/scsi/ufs/ufshcd.c | 40 +++++++++++++++++------------------ 3 files changed, 37 insertions(+), 43 deletions(-) diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 845b874e2977..377ba30c2258 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -522,4 +522,16 @@ struct ufs_dev_info { bool is_lu_power_on_wp; }; +#define MAX_MODEL_LEN 16 +/** + * ufs_dev_desc - ufs device details from the device descriptor + * + * @wmanufacturerid: card details + * @model: card model + */ +struct ufs_dev_desc { + u16 wmanufacturerid; + char model[MAX_MODEL_LEN + 1]; +}; + #endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index 08b799d4efcc..71f73d1d1ad1 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h @@ -21,41 +21,28 @@ #define UFS_ANY_VENDOR 0xFFFF #define UFS_ANY_MODEL "ANY_MODEL" -#define MAX_MODEL_LEN 16 - #define UFS_VENDOR_TOSHIBA 0x198 #define UFS_VENDOR_SAMSUNG 0x1CE #define UFS_VENDOR_SKHYNIX 0x1AD -/** - * ufs_device_info - ufs device details - * @wmanufacturerid: card details - * @model: card model - */ -struct ufs_device_info { - u16 wmanufacturerid; - char model[MAX_MODEL_LEN + 1]; -}; - /** * ufs_dev_fix - ufs device quirk info * @card: ufs card details * @quirk: device quirk */ struct ufs_dev_fix { - struct ufs_device_info card; + struct ufs_dev_desc card; unsigned int quirk; }; #define END_FIX { { 0 }, 0 } /* add specific device quirk */ -#define UFS_FIX(_vendor, _model, _quirk) \ - { \ - .card.wmanufacturerid = (_vendor),\ - .card.model = (_model), \ - .quirk = (_quirk), \ - } +#define UFS_FIX(_vendor, _model, _quirk) { \ + .card.wmanufacturerid = (_vendor),\ + .card.model = (_model), \ + .quirk = (_quirk), \ +} /* * If UFS device is having issue in processing LCC (Line Control @@ -144,7 +131,4 @@ struct ufs_dev_fix { */ #define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME (1 << 8) -struct ufs_hba; -void ufs_advertise_fixup_device(struct ufs_hba *hba); - #endif /* UFS_QUIRKS_H_ */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index a4fee1e4fdda..50aa1a5726b8 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4906,8 +4906,8 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) return ret; } -static int ufs_get_device_info(struct ufs_hba *hba, - struct ufs_device_info *card_data) +static int ufs_get_device_desc(struct ufs_hba *hba, + struct ufs_dev_desc *dev_desc) { int err; u8 model_index; @@ -4926,7 +4926,7 @@ static int ufs_get_device_info(struct ufs_hba *hba, * getting vendor (manufacturerID) and Bank Index in big endian * format */ - card_data->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | + dev_desc->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]; model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; @@ -4940,36 +4940,26 @@ static int ufs_get_device_info(struct ufs_hba *hba, } str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0'; - strlcpy(card_data->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), + strlcpy(dev_desc->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET], MAX_MODEL_LEN)); /* Null terminate the model string */ - card_data->model[MAX_MODEL_LEN] = '\0'; + dev_desc->model[MAX_MODEL_LEN] = '\0'; out: return err; } -void ufs_advertise_fixup_device(struct ufs_hba *hba) +static void ufs_fixup_device_setup(struct ufs_hba *hba, + struct ufs_dev_desc *dev_desc) { - int err; struct ufs_dev_fix *f; - struct ufs_device_info card_data; - - card_data.wmanufacturerid = 0; - - err = ufs_get_device_info(hba, &card_data); - if (err) { - dev_err(hba->dev, "%s: Failed getting device info. err = %d\n", - __func__, err); - return; - } for (f = ufs_fixups; f->quirk; f++) { - if (((f->card.wmanufacturerid == card_data.wmanufacturerid) || - (f->card.wmanufacturerid == UFS_ANY_VENDOR)) && - (STR_PRFX_EQUAL(f->card.model, card_data.model) || + if ((f->card.wmanufacturerid == dev_desc->wmanufacturerid || + f->card.wmanufacturerid == UFS_ANY_VENDOR) && + (STR_PRFX_EQUAL(f->card.model, dev_desc->model) || !strcmp(f->card.model, UFS_ANY_MODEL))) hba->dev_quirks |= f->quirk; } @@ -5147,6 +5137,7 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) */ static int ufshcd_probe_hba(struct ufs_hba *hba) { + struct ufs_dev_desc card = {0}; int ret; ret = ufshcd_link_startup(hba); @@ -5170,7 +5161,14 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) if (ret) goto out; - ufs_advertise_fixup_device(hba); + ret = ufs_get_device_desc(hba, &card); + if (ret) { + dev_err(hba->dev, "%s: Failed getting device info. err = %d\n", + __func__, ret); + goto out; + } + + ufs_fixup_device_setup(hba, &card); ufshcd_tune_unipro_params(hba); ret = ufshcd_set_vccq_rail_unused(hba, -- GitLab From e1928457073c996ffc681be2b6f9576706fbcf8d Mon Sep 17 00:00:00 2001 From: "Potomski, MichalX" Date: Thu, 23 Feb 2017 09:05:30 +0000 Subject: [PATCH 026/604] scsi: ufs: Factor out ufshcd_read_desc_param commit a4b0e8a4e92b1baa860e744847fbdb84a50a5071 upstream. Since in UFS 2.1 specification some of the descriptor lengths differs from 2.0 specification and some devices, which are reporting spec version 2.0 have different descriptor lengths we can not rely on hardcoded values taken from 2.0 specification. This patch introduces reading these lengths per each device from descriptor headers at probe time to ensure their correctness. Signed-off-by: Michal' Potomski Reviewed-by: Subhash Jadavani Signed-off-by: Martin K. Petersen [Wei Li: Slight tweaks to get the cherry-pick to apply,resolved collisions] Signed-off-by: Li Wei Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/ufs/ufs.h | 22 ++-- drivers/scsi/ufs/ufshcd.c | 231 ++++++++++++++++++++++++++++---------- drivers/scsi/ufs/ufshcd.h | 16 +++ 3 files changed, 197 insertions(+), 72 deletions(-) diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 377ba30c2258..5bb2316f60bf 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -145,7 +145,7 @@ enum attr_idn { /* Descriptor idn for Query requests */ enum desc_idn { QUERY_DESC_IDN_DEVICE = 0x0, - QUERY_DESC_IDN_CONFIGURAION = 0x1, + QUERY_DESC_IDN_CONFIGURATION = 0x1, QUERY_DESC_IDN_UNIT = 0x2, QUERY_DESC_IDN_RFU_0 = 0x3, QUERY_DESC_IDN_INTERCONNECT = 0x4, @@ -161,19 +161,13 @@ enum desc_header_offset { QUERY_DESC_DESC_TYPE_OFFSET = 0x01, }; -enum ufs_desc_max_size { - QUERY_DESC_DEVICE_MAX_SIZE = 0x1F, - QUERY_DESC_CONFIGURAION_MAX_SIZE = 0x90, - QUERY_DESC_UNIT_MAX_SIZE = 0x23, - QUERY_DESC_INTERCONNECT_MAX_SIZE = 0x06, - /* - * Max. 126 UNICODE characters (2 bytes per character) plus 2 bytes - * of descriptor header. - */ - QUERY_DESC_STRING_MAX_SIZE = 0xFE, - QUERY_DESC_GEOMETRY_MAX_SIZE = 0x44, - QUERY_DESC_POWER_MAX_SIZE = 0x62, - QUERY_DESC_RFU_MAX_SIZE = 0x00, +enum ufs_desc_def_size { + QUERY_DESC_DEVICE_DEF_SIZE = 0x40, + QUERY_DESC_CONFIGURATION_DEF_SIZE = 0x90, + QUERY_DESC_UNIT_DEF_SIZE = 0x23, + QUERY_DESC_INTERCONNECT_DEF_SIZE = 0x06, + QUERY_DESC_GEOMETRY_DEF_SIZE = 0x44, + QUERY_DESC_POWER_DEF_SIZE = 0x62, }; /* Unit descriptor parameters offsets in bytes*/ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 50aa1a5726b8..86a3110c6d75 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -98,19 +98,6 @@ _ret; \ }) -static u32 ufs_query_desc_max_size[] = { - QUERY_DESC_DEVICE_MAX_SIZE, - QUERY_DESC_CONFIGURAION_MAX_SIZE, - QUERY_DESC_UNIT_MAX_SIZE, - QUERY_DESC_RFU_MAX_SIZE, - QUERY_DESC_INTERCONNECT_MAX_SIZE, - QUERY_DESC_STRING_MAX_SIZE, - QUERY_DESC_RFU_MAX_SIZE, - QUERY_DESC_GEOMETRY_MAX_SIZE, - QUERY_DESC_POWER_MAX_SIZE, - QUERY_DESC_RFU_MAX_SIZE, -}; - enum { UFSHCD_MAX_CHANNEL = 0, UFSHCD_MAX_ID = 1, @@ -1961,7 +1948,7 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba, goto out; } - if (*buf_len <= QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) { + if (*buf_len < QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) { dev_err(hba->dev, "%s: descriptor buffer size (%d) is out of range\n", __func__, *buf_len); err = -EINVAL; @@ -2040,6 +2027,92 @@ int ufshcd_query_descriptor_retry(struct ufs_hba *hba, } EXPORT_SYMBOL(ufshcd_query_descriptor_retry); +/** + * ufshcd_read_desc_length - read the specified descriptor length from header + * @hba: Pointer to adapter instance + * @desc_id: descriptor idn value + * @desc_index: descriptor index + * @desc_length: pointer to variable to read the length of descriptor + * + * Return 0 in case of success, non-zero otherwise + */ +static int ufshcd_read_desc_length(struct ufs_hba *hba, + enum desc_idn desc_id, + int desc_index, + int *desc_length) +{ + int ret; + u8 header[QUERY_DESC_HDR_SIZE]; + int header_len = QUERY_DESC_HDR_SIZE; + + if (desc_id >= QUERY_DESC_IDN_MAX) + return -EINVAL; + + ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, + desc_id, desc_index, 0, header, + &header_len); + + if (ret) { + dev_err(hba->dev, "%s: Failed to get descriptor header id %d", + __func__, desc_id); + return ret; + } else if (desc_id != header[QUERY_DESC_DESC_TYPE_OFFSET]) { + dev_warn(hba->dev, "%s: descriptor header id %d and desc_id %d mismatch", + __func__, header[QUERY_DESC_DESC_TYPE_OFFSET], + desc_id); + ret = -EINVAL; + } + + *desc_length = header[QUERY_DESC_LENGTH_OFFSET]; + return ret; + +} + +/** + * ufshcd_map_desc_id_to_length - map descriptor IDN to its length + * @hba: Pointer to adapter instance + * @desc_id: descriptor idn value + * @desc_len: mapped desc length (out) + * + * Return 0 in case of success, non-zero otherwise + */ +int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, + enum desc_idn desc_id, int *desc_len) +{ + switch (desc_id) { + case QUERY_DESC_IDN_DEVICE: + *desc_len = hba->desc_size.dev_desc; + break; + case QUERY_DESC_IDN_POWER: + *desc_len = hba->desc_size.pwr_desc; + break; + case QUERY_DESC_IDN_GEOMETRY: + *desc_len = hba->desc_size.geom_desc; + break; + case QUERY_DESC_IDN_CONFIGURATION: + *desc_len = hba->desc_size.conf_desc; + break; + case QUERY_DESC_IDN_UNIT: + *desc_len = hba->desc_size.unit_desc; + break; + case QUERY_DESC_IDN_INTERCONNECT: + *desc_len = hba->desc_size.interc_desc; + break; + case QUERY_DESC_IDN_STRING: + *desc_len = QUERY_DESC_MAX_SIZE; + break; + case QUERY_DESC_IDN_RFU_0: + case QUERY_DESC_IDN_RFU_1: + *desc_len = 0; + break; + default: + *desc_len = 0; + return -EINVAL; + } + return 0; +} +EXPORT_SYMBOL(ufshcd_map_desc_id_to_length); + /** * ufshcd_read_desc_param - read the specified descriptor parameter * @hba: Pointer to adapter instance @@ -2054,42 +2127,49 @@ EXPORT_SYMBOL(ufshcd_query_descriptor_retry); static int ufshcd_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id, int desc_index, - u32 param_offset, + u8 param_offset, u8 *param_read_buf, - u32 param_size) + u8 param_size) { int ret; u8 *desc_buf; - u32 buff_len; + int buff_len; bool is_kmalloc = true; - /* safety checks */ - if (desc_id >= QUERY_DESC_IDN_MAX) + /* Safety check */ + if (desc_id >= QUERY_DESC_IDN_MAX || !param_size) return -EINVAL; - buff_len = ufs_query_desc_max_size[desc_id]; - if ((param_offset + param_size) > buff_len) - return -EINVAL; + /* Get the max length of descriptor from structure filled up at probe + * time. + */ + ret = ufshcd_map_desc_id_to_length(hba, desc_id, &buff_len); - if (!param_offset && (param_size == buff_len)) { - /* memory space already available to hold full descriptor */ - desc_buf = param_read_buf; - is_kmalloc = false; - } else { - /* allocate memory to hold full descriptor */ + /* Sanity checks */ + if (ret || !buff_len) { + dev_err(hba->dev, "%s: Failed to get full descriptor length", + __func__); + return ret; + } + + /* Check whether we need temp memory */ + if (param_offset != 0 || param_size < buff_len) { desc_buf = kmalloc(buff_len, GFP_KERNEL); if (!desc_buf) return -ENOMEM; + } else { + desc_buf = param_read_buf; + is_kmalloc = false; } + /* Request for full descriptor */ ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, - desc_id, desc_index, 0, desc_buf, - &buff_len); + desc_id, desc_index, 0, + desc_buf, &buff_len); if (ret) { dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d", __func__, desc_id, desc_index, param_offset, ret); - goto out; } @@ -2101,25 +2181,9 @@ static int ufshcd_read_desc_param(struct ufs_hba *hba, goto out; } - /* - * While reading variable size descriptors (like string descriptor), - * some UFS devices may report the "LENGTH" (field in "Transaction - * Specific fields" of Query Response UPIU) same as what was requested - * in Query Request UPIU instead of reporting the actual size of the - * variable size descriptor. - * Although it's safe to ignore the "LENGTH" field for variable size - * descriptors as we can always derive the length of the descriptor from - * the descriptor header fields. Hence this change impose the length - * match check only for fixed size descriptors (for which we always - * request the correct size as part of Query Request UPIU). - */ - if ((desc_id != QUERY_DESC_IDN_STRING) && - (buff_len != desc_buf[QUERY_DESC_LENGTH_OFFSET])) { - dev_err(hba->dev, "%s: desc_buf length mismatch: buff_len %d, buff_len(desc_header) %d", - __func__, buff_len, desc_buf[QUERY_DESC_LENGTH_OFFSET]); - ret = -EINVAL; - goto out; - } + /* Check wherher we will not copy more data, than available */ + if (is_kmalloc && param_size > buff_len) + param_size = buff_len; if (is_kmalloc) memcpy(param_read_buf, &desc_buf[param_offset], param_size); @@ -4812,8 +4876,8 @@ static u32 ufshcd_find_max_sup_active_icc_level(struct ufs_hba *hba, static void ufshcd_init_icc_levels(struct ufs_hba *hba) { int ret; - int buff_len = QUERY_DESC_POWER_MAX_SIZE; - u8 desc_buf[QUERY_DESC_POWER_MAX_SIZE]; + int buff_len = hba->desc_size.pwr_desc; + u8 desc_buf[hba->desc_size.pwr_desc]; ret = ufshcd_read_power_desc(hba, desc_buf, buff_len); if (ret) { @@ -4911,11 +4975,10 @@ static int ufs_get_device_desc(struct ufs_hba *hba, { int err; u8 model_index; - u8 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE + 1] = {0}; - u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE]; + u8 str_desc_buf[QUERY_DESC_MAX_SIZE + 1] = {0}; + u8 desc_buf[hba->desc_size.dev_desc]; - err = ufshcd_read_device_desc(hba, desc_buf, - QUERY_DESC_DEVICE_MAX_SIZE); + err = ufshcd_read_device_desc(hba, desc_buf, hba->desc_size.dev_desc); if (err) { dev_err(hba->dev, "%s: Failed reading Device Desc. err = %d\n", __func__, err); @@ -4932,14 +4995,14 @@ static int ufs_get_device_desc(struct ufs_hba *hba, model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; err = ufshcd_read_string_desc(hba, model_index, str_desc_buf, - QUERY_DESC_STRING_MAX_SIZE, ASCII_STD); + QUERY_DESC_MAX_SIZE, ASCII_STD); if (err) { dev_err(hba->dev, "%s: Failed reading Product Name. err = %d\n", __func__, err); goto out; } - str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0'; + str_desc_buf[QUERY_DESC_MAX_SIZE] = '\0'; strlcpy(dev_desc->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET], MAX_MODEL_LEN)); @@ -5129,6 +5192,51 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) ufshcd_vops_apply_dev_quirks(hba); } +static void ufshcd_init_desc_sizes(struct ufs_hba *hba) +{ + int err; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_DEVICE, 0, + &hba->desc_size.dev_desc); + if (err) + hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_POWER, 0, + &hba->desc_size.pwr_desc); + if (err) + hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_INTERCONNECT, 0, + &hba->desc_size.interc_desc); + if (err) + hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_CONFIGURATION, 0, + &hba->desc_size.conf_desc); + if (err) + hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_UNIT, 0, + &hba->desc_size.unit_desc); + if (err) + hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_GEOMETRY, 0, + &hba->desc_size.geom_desc); + if (err) + hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; +} + +static void ufshcd_def_desc_sizes(struct ufs_hba *hba) +{ + hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE; + hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE; + hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE; + hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE; + hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE; + hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; +} + /** * ufshcd_probe_hba - probe hba to detect device and initialize * @hba: per-adapter instance @@ -5161,6 +5269,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) if (ret) goto out; + /* Init check for device descriptor sizes */ + ufshcd_init_desc_sizes(hba); + ret = ufs_get_device_desc(hba, &card); if (ret) { dev_err(hba->dev, "%s: Failed getting device info. err = %d\n", @@ -5194,6 +5305,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) /* set the state as operational after switching to desired gear */ hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; + /* * If we are in error handling context or in power management callbacks * context, no need to scan the host @@ -6570,6 +6682,9 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) hba->mmio_base = mmio_base; hba->irq = irq; + /* Set descriptor lengths to specification defaults */ + ufshcd_def_desc_sizes(hba); + err = ufshcd_hba_init(hba); if (err) goto out_error; diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index f2170d5058a8..6dbd2e176333 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -205,6 +205,15 @@ struct ufs_dev_cmd { struct ufs_query query; }; +struct ufs_desc_size { + int dev_desc; + int pwr_desc; + int geom_desc; + int interc_desc; + int unit_desc; + int conf_desc; +}; + /** * struct ufs_clk_info - UFS clock related info * @list: list headed by hba->clk_list_head @@ -388,6 +397,7 @@ struct ufs_init_prefetch { * @clk_list_head: UFS host controller clocks list node head * @pwr_info: holds current power mode * @max_pwr_info: keeps the device max valid pwm + * @desc_size: descriptor sizes reported by device * @urgent_bkops_lvl: keeps track of urgent bkops level for device * @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level for * device is known or not. @@ -563,6 +573,8 @@ struct ufs_hba { enum bkops_status urgent_bkops_lvl; bool is_urgent_bkops_lvl_checked; + + struct ufs_desc_size desc_size; }; /* Returns true if clocks can be gated. Otherwise false */ @@ -736,6 +748,10 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, enum flag_idn idn, bool *flag_res); int ufshcd_hold(struct ufs_hba *hba, bool async); void ufshcd_release(struct ufs_hba *hba); + +int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id, + int *desc_length); + u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba); /* Wrapper functions for safely calling variant operations */ -- GitLab From fe64d7d6ab83b03c933d9f76643b810857774306 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Tue, 8 Nov 2016 13:56:20 +0000 Subject: [PATCH 027/604] arm64: Add hypervisor safe helper for checking constant capabilities commit a4023f682739439b434165b54af7cb3676a4766e upstream. The hypervisor may not have full access to the kernel data structures and hence cannot safely use cpus_have_cap() helper for checking the system capability. Add a safe helper for hypervisors to check a constant system capability, which *doesn't* fall back to checking the bitmap maintained by the kernel. With this, make the cpus_have_cap() only check the bitmask and force constant cap checks to use the new API for quicker checks. Cc: Robert Ritcher Cc: Tirumalesh Chalamarla Signed-off-by: Suzuki K Poulose Reviewed-by: Will Deacon Reviewed-by: Marc Zyngier Signed-off-by: Catalin Marinas [4.9: restore cpus_have_const_cap() to previously-backported code] Signed-off-by: Mark Rutland [v4.9 backport] Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/cpufeature.h | 19 ++++++++++++------- arch/arm64/include/asm/kvm_host.h | 2 +- arch/arm64/include/asm/kvm_mmu.h | 2 +- arch/arm64/include/asm/mmu.h | 2 +- arch/arm64/kernel/cpufeature.c | 5 +++-- arch/arm64/kernel/process.c | 2 +- drivers/irqchip/irq-gic-v3.c | 13 +------------ 7 files changed, 20 insertions(+), 25 deletions(-) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 0bc0b1de90c4..9890d20f2356 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -9,8 +9,6 @@ #ifndef __ASM_CPUFEATURE_H #define __ASM_CPUFEATURE_H -#include - #include #include #include @@ -27,6 +25,8 @@ #ifndef __ASSEMBLY__ +#include +#include #include /* CPU feature register tracking */ @@ -104,14 +104,19 @@ static inline bool cpu_have_feature(unsigned int num) return elf_hwcap & (1UL << num); } +/* System capability check for constant caps */ +static inline bool cpus_have_const_cap(int num) +{ + if (num >= ARM64_NCAPS) + return false; + return static_branch_unlikely(&cpu_hwcap_keys[num]); +} + static inline bool cpus_have_cap(unsigned int num) { if (num >= ARM64_NCAPS) return false; - if (__builtin_constant_p(num)) - return static_branch_unlikely(&cpu_hwcap_keys[num]); - else - return test_bit(num, cpu_hwcaps); + return test_bit(num, cpu_hwcaps); } static inline void cpus_set_cap(unsigned int num) @@ -200,7 +205,7 @@ static inline bool cpu_supports_mixed_endian_el0(void) static inline bool system_supports_32bit_el0(void) { - return cpus_have_cap(ARM64_HAS_32BIT_EL0); + return cpus_have_const_cap(ARM64_HAS_32BIT_EL0); } static inline bool system_supports_mixed_endian_el0(void) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 0a33ea304e63..7f402f64c744 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -398,7 +398,7 @@ static inline void __cpu_init_stage2(void) static inline bool kvm_arm_harden_branch_predictor(void) { - return cpus_have_cap(ARM64_HARDEN_BRANCH_PREDICTOR); + return cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR); } #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index eac73a640ea7..824c83db9b47 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -341,7 +341,7 @@ static inline void *kvm_get_hyp_vector(void) vect = __bp_harden_hyp_vecs_start + data->hyp_vectors_slot * SZ_2K; - if (!cpus_have_cap(ARM64_HAS_VIRT_HOST_EXTN)) + if (!cpus_have_const_cap(ARM64_HAS_VIRT_HOST_EXTN)) vect = lm_alias(vect); } diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index d51158a61892..6ac34c75f4e1 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -37,7 +37,7 @@ typedef struct { static inline bool arm64_kernel_unmapped_at_el0(void) { return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0) && - cpus_have_cap(ARM64_UNMAP_KERNEL_AT_EL0); + cpus_have_const_cap(ARM64_UNMAP_KERNEL_AT_EL0); } typedef void (*bp_hardening_cb_t)(void); diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index a0ee01202503..e28665411bd1 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -47,6 +47,7 @@ unsigned int compat_elf_hwcap2 __read_mostly; #endif DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS); +EXPORT_SYMBOL(cpu_hwcaps); DEFINE_STATIC_KEY_ARRAY_FALSE(cpu_hwcap_keys, ARM64_NCAPS); EXPORT_SYMBOL(cpu_hwcap_keys); @@ -762,7 +763,7 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, * ThunderX leads to apparent I-cache corruption of kernel text, which * ends as well as you might imagine. Don't even try. */ - if (cpus_have_cap(ARM64_WORKAROUND_CAVIUM_27456)) { + if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_27456)) { str = "ARM64_WORKAROUND_CAVIUM_27456"; __kpti_forced = -1; } @@ -1203,5 +1204,5 @@ void __init setup_cpu_features(void) static bool __maybe_unused cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry, int __unused) { - return (cpus_have_cap(ARM64_HAS_PAN) && !cpus_have_cap(ARM64_HAS_UAO)); + return (cpus_have_const_cap(ARM64_HAS_PAN) && !cpus_have_const_cap(ARM64_HAS_UAO)); } diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 0972ce58316d..e917d119490c 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -291,7 +291,7 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, memset(childregs, 0, sizeof(struct pt_regs)); childregs->pstate = PSR_MODE_EL1h; if (IS_ENABLED(CONFIG_ARM64_UAO) && - cpus_have_cap(ARM64_HAS_UAO)) + cpus_have_const_cap(ARM64_HAS_UAO)) childregs->pstate |= PSR_UAO_BIT; p->thread.cpu_context.x19 = stack_start; p->thread.cpu_context.x20 = stk_sz; diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 0b1d5bdd0862..f7b8681aed3f 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -120,11 +120,10 @@ static void gic_redist_wait_for_rwp(void) } #ifdef CONFIG_ARM64 -static DEFINE_STATIC_KEY_FALSE(is_cavium_thunderx); static u64 __maybe_unused gic_read_iar(void) { - if (static_branch_unlikely(&is_cavium_thunderx)) + if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_23154)) return gic_read_iar_cavium_thunderx(); else return gic_read_iar_common(); @@ -908,14 +907,6 @@ static const struct irq_domain_ops partition_domain_ops = { .select = gic_irq_domain_select, }; -static void gicv3_enable_quirks(void) -{ -#ifdef CONFIG_ARM64 - if (cpus_have_cap(ARM64_WORKAROUND_CAVIUM_23154)) - static_branch_enable(&is_cavium_thunderx); -#endif -} - static int __init gic_init_bases(void __iomem *dist_base, struct redist_region *rdist_regs, u32 nr_redist_regions, @@ -938,8 +929,6 @@ static int __init gic_init_bases(void __iomem *dist_base, gic_data.nr_redist_regions = nr_redist_regions; gic_data.redist_stride = redist_stride; - gicv3_enable_quirks(); - /* * Find out how many interrupts are supported. * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI) -- GitLab From b1d57084b6a2572c5f648c83dbd31100e73a4653 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Tue, 16 May 2017 15:18:05 +0100 Subject: [PATCH 028/604] arm64/cpufeature: don't use mutex in bringup path commit 63a1e1c95e60e798fa09ab3c536fb555aa5bbf2b upstream. Currently, cpus_set_cap() calls static_branch_enable_cpuslocked(), which must take the jump_label mutex. We call cpus_set_cap() in the secondary bringup path, from the idle thread where interrupts are disabled. Taking a mutex in this path "is a NONO" regardless of whether it's contended, and something we must avoid. We didn't spot this until recently, as ___might_sleep() won't warn for this case until all CPUs have been brought up. This patch avoids taking the mutex in the secondary bringup path. The poking of static keys is deferred until enable_cpu_capabilities(), which runs in a suitable context on the boot CPU. To account for the static keys being set later, cpus_have_const_cap() is updated to use another static key to check whether the const cap keys have been initialised, falling back to the caps bitmap until this is the case. This means that users of cpus_have_const_cap() gain should only gain a single additional NOP in the fast path once the const caps are initialised, but should always see the current cap value. The hyp code should never dereference the caps array, since the caps are initialized before we run the module initcall to initialise hyp. A check is added to the hyp init code to document this requirement. This change will sidestep a number of issues when the upcoming hotplug locking rework is merged. Signed-off-by: Mark Rutland Reviewed-by: Marc Zyniger Reviewed-by: Suzuki Poulose Acked-by: Will Deacon Cc: Christoffer Dall Cc: Peter Zijlstra Cc: Sebastian Sewior Cc: Thomas Gleixner Signed-off-by: Catalin Marinas [4.9: this avoids an IPI before GICv3 is up, preventing a boot time crash] Signed-off-by: Mark Rutland [v4.9 backport] Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/cpufeature.h | 12 ++++++++++-- arch/arm64/include/asm/kvm_host.h | 8 ++++++-- arch/arm64/kernel/cpufeature.c | 23 +++++++++++++++++++++-- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 9890d20f2356..4ea85ebdf4df 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -96,6 +96,7 @@ struct arm64_cpu_capabilities { extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS); extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS]; +extern struct static_key_false arm64_const_caps_ready; bool this_cpu_has_cap(unsigned int cap); @@ -105,7 +106,7 @@ static inline bool cpu_have_feature(unsigned int num) } /* System capability check for constant caps */ -static inline bool cpus_have_const_cap(int num) +static inline bool __cpus_have_const_cap(int num) { if (num >= ARM64_NCAPS) return false; @@ -119,6 +120,14 @@ static inline bool cpus_have_cap(unsigned int num) return test_bit(num, cpu_hwcaps); } +static inline bool cpus_have_const_cap(int num) +{ + if (static_branch_likely(&arm64_const_caps_ready)) + return __cpus_have_const_cap(num); + else + return cpus_have_cap(num); +} + static inline void cpus_set_cap(unsigned int num) { if (num >= ARM64_NCAPS) { @@ -126,7 +135,6 @@ static inline void cpus_set_cap(unsigned int num) num, ARM64_NCAPS); } else { __set_bit(num, cpu_hwcaps); - static_branch_enable(&cpu_hwcap_keys[num]); } } diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 7f402f64c744..2abb4493f4f6 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -358,9 +359,12 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr, unsigned long vector_ptr) { /* - * Call initialization code, and switch to the full blown - * HYP code. + * Call initialization code, and switch to the full blown HYP code. + * If the cpucaps haven't been finalized yet, something has gone very + * wrong, and hyp will crash and burn when it uses any + * cpus_have_const_cap() wrapper. */ + BUG_ON(!static_branch_likely(&arm64_const_caps_ready)); __kvm_call_hyp((void *)pgd_ptr, hyp_stack_ptr, vector_ptr); } diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index e28665411bd1..7959d2c92010 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1052,8 +1052,16 @@ void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps, */ void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) { - for (; caps->matches; caps++) - if (caps->enable && cpus_have_cap(caps->capability)) + for (; caps->matches; caps++) { + unsigned int num = caps->capability; + + if (!cpus_have_cap(num)) + continue; + + /* Ensure cpus_have_const_cap(num) works */ + static_branch_enable(&cpu_hwcap_keys[num]); + + if (caps->enable) { /* * Use stop_machine() as it schedules the work allowing * us to modify PSTATE, instead of on_each_cpu() which @@ -1061,6 +1069,8 @@ void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) * we return. */ stop_machine(caps->enable, (void *)caps, cpu_online_mask); + } + } } /* @@ -1164,6 +1174,14 @@ static void __init setup_feature_capabilities(void) enable_cpu_capabilities(arm64_features); } +DEFINE_STATIC_KEY_FALSE(arm64_const_caps_ready); +EXPORT_SYMBOL(arm64_const_caps_ready); + +static void __init mark_const_caps_ready(void) +{ + static_branch_enable(&arm64_const_caps_ready); +} + extern const struct arm64_cpu_capabilities arm64_errata[]; bool this_cpu_has_cap(unsigned int cap) @@ -1180,6 +1198,7 @@ void __init setup_cpu_features(void) /* Set the CPU feature capabilies */ setup_feature_capabilities(); enable_errata_workarounds(); + mark_const_caps_ready(); setup_elf_hwcaps(arm64_elf_hwcaps); if (system_supports_32bit_el0()) -- GitLab From 70e51fd51f00744dc9b7f017019da5d65bc32997 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 2 Jun 2018 21:08:46 +1000 Subject: [PATCH 029/604] powerpc/rfi-flush: Move out of HARDLOCKUP_DETECTOR #ifdef The backport of the RFI flush support, done by me, has a minor bug in that the code is inside an #ifdef CONFIG_HARDLOCKUP_DETECTOR, which is incorrect. This doesn't matter with common configs because we enable HARDLOCKUP_DETECTOR, but with future patches it will break the build. So fix it. Fixes: c3b82ebee6e0 ("powerpc/64s: Add support for RFI flush of L1-D cache") Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/setup_64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 5243501d95ef..1746639c4dcd 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -679,6 +679,7 @@ static int __init disable_hardlockup_detector(void) return 0; } early_initcall(disable_hardlockup_detector); +#endif /* CONFIG_HARDLOCKUP_DETECTOR */ #ifdef CONFIG_PPC_BOOK3S_64 static enum l1d_flush_type enabled_flush_types; @@ -806,4 +807,3 @@ ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, cha return sprintf(buf, "Vulnerable\n"); } #endif /* CONFIG_PPC_BOOK3S_64 */ -#endif -- GitLab From 51cbb3b34c8972e0096ed8d5cd4abfa586567852 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 2 Jun 2018 21:08:47 +1000 Subject: [PATCH 030/604] powerpc/pseries: Support firmware disable of RFI flush commit 582605a429e20ae68fd0b041b2e840af296edd08 upstream. Some versions of firmware will have a setting that can be configured to disable the RFI flush, add support for it. Fixes: 8989d56878a7 ("powerpc/pseries: Query hypervisor for RFI flush settings") Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/setup.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 1845fc611912..0982e13b2942 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -473,7 +473,8 @@ static void pseries_setup_rfi_flush(void) if (types == L1D_FLUSH_NONE) types = L1D_FLUSH_FALLBACK; - if (!(result.behaviour & H_CPU_BEHAV_L1D_FLUSH_PR)) + if ((!(result.behaviour & H_CPU_BEHAV_L1D_FLUSH_PR)) || + (!(result.behaviour & H_CPU_BEHAV_FAVOUR_SECURITY))) enable = false; } else { /* Default to fallback if case hcall is not available */ -- GitLab From 98df74652bfa95856f3ad8cf7b220b01e4a39aaf Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 2 Jun 2018 21:08:48 +1000 Subject: [PATCH 031/604] powerpc/powernv: Support firmware disable of RFI flush commit eb0a2d2620ae431c543963c8c7f08f597366fc60 upstream. Some versions of firmware will have a setting that can be configured to disable the RFI flush, add support for it. Fixes: 6e032b350cd1 ("powerpc/powernv: Check device-tree for RFI flush settings") Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powernv/setup.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 6f8b4c19373a..4764bc91570c 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -79,6 +79,10 @@ static void pnv_setup_rfi_flush(void) if (np && of_property_read_bool(np, "disabled")) enable--; + np = of_get_child_by_name(fw_features, "speculation-policy-favor-security"); + if (np && of_property_read_bool(np, "disabled")) + enable = 0; + of_node_put(np); of_node_put(fw_features); } -- GitLab From a1bbe5eb6c01fa47ab7fb2688183fd11ebc3e2bb Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 2 Jun 2018 21:08:49 +1000 Subject: [PATCH 032/604] powerpc/rfi-flush: Move the logic to avoid a redo into the debugfs code commit 1e2a9fc7496955faacbbed49461d611b704a7505 upstream. rfi_flush_enable() includes a check to see if we're already enabled (or disabled), and in that case does nothing. But that means calling setup_rfi_flush() a 2nd time doesn't actually work, which is a bit confusing. Move that check into the debugfs code, where it really belongs. Signed-off-by: Michael Ellerman Signed-off-by: Mauricio Faria de Oliveira Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/setup_64.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 1746639c4dcd..e6bed89a98ed 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -717,9 +717,6 @@ static void do_nothing(void *unused) void rfi_flush_enable(bool enable) { - if (rfi_flush == enable) - return; - if (enable) { do_rfi_flush_fixups(enabled_flush_types); on_each_cpu(do_nothing, NULL, 1); @@ -773,13 +770,19 @@ void __init setup_rfi_flush(enum l1d_flush_type types, bool enable) #ifdef CONFIG_DEBUG_FS static int rfi_flush_set(void *data, u64 val) { + bool enable; + if (val == 1) - rfi_flush_enable(true); + enable = true; else if (val == 0) - rfi_flush_enable(false); + enable = false; else return -EINVAL; + /* Only do anything if we're changing state */ + if (enable != rfi_flush) + rfi_flush_enable(enable); + return 0; } -- GitLab From 5e9ea71d85bc33f869b4d8c9b5142ac30baa9118 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 2 Jun 2018 21:08:50 +1000 Subject: [PATCH 033/604] powerpc/rfi-flush: Make it possible to call setup_rfi_flush() again commit abf110f3e1cea40f5ea15e85f5d67c39c14568a7 upstream. For PowerVM migration we want to be able to call setup_rfi_flush() again after we've migrated the partition. To support that we need to check that we're not trying to allocate the fallback flush area after memblock has gone away (i.e., boot-time only). Signed-off-by: Michael Ellerman Signed-off-by: Mauricio Faria de Oliveira Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/setup.h | 2 +- arch/powerpc/kernel/setup_64.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h index 6825a67cc3db..3f160cd20107 100644 --- a/arch/powerpc/include/asm/setup.h +++ b/arch/powerpc/include/asm/setup.h @@ -48,7 +48,7 @@ enum l1d_flush_type { L1D_FLUSH_MTTRIG = 0x8, }; -void __init setup_rfi_flush(enum l1d_flush_type, bool enable); +void setup_rfi_flush(enum l1d_flush_type, bool enable); void do_rfi_flush_fixups(enum l1d_flush_type types); #endif /* !__ASSEMBLY__ */ diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index e6bed89a98ed..568793009daa 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -731,6 +731,10 @@ static void init_fallback_flush(void) u64 l1d_size, limit; int cpu; + /* Only allocate the fallback flush area once (at boot time). */ + if (l1d_flush_fallback_area) + return; + l1d_size = ppc64_caches.dsize; limit = min(safe_stack_limit(), ppc64_rma_size); @@ -748,7 +752,7 @@ static void init_fallback_flush(void) } } -void __init setup_rfi_flush(enum l1d_flush_type types, bool enable) +void setup_rfi_flush(enum l1d_flush_type types, bool enable) { if (types & L1D_FLUSH_FALLBACK) { pr_info("rfi-flush: Using fallback displacement flush\n"); -- GitLab From 135b2c17cf252f539103fb4781133058be83a710 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 2 Jun 2018 21:08:51 +1000 Subject: [PATCH 034/604] powerpc/rfi-flush: Always enable fallback flush on pseries commit 84749a58b6e382f109abf1e734bc4dd43c2c25bb upstream. This ensures the fallback flush area is always allocated on pseries, so in case a LPAR is migrated from a patched to an unpatched system, it is possible to enable the fallback flush in the target system. Signed-off-by: Michael Ellerman Signed-off-by: Mauricio Faria de Oliveira Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/setup.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 0982e13b2942..626bf1ce1d80 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -459,26 +459,18 @@ static void pseries_setup_rfi_flush(void) /* Enable by default */ enable = true; + types = L1D_FLUSH_FALLBACK; rc = plpar_get_cpu_characteristics(&result); if (rc == H_SUCCESS) { - types = L1D_FLUSH_NONE; - if (result.character & H_CPU_CHAR_L1D_FLUSH_TRIG2) types |= L1D_FLUSH_MTTRIG; if (result.character & H_CPU_CHAR_L1D_FLUSH_ORI30) types |= L1D_FLUSH_ORI; - /* Use fallback if nothing set in hcall */ - if (types == L1D_FLUSH_NONE) - types = L1D_FLUSH_FALLBACK; - if ((!(result.behaviour & H_CPU_BEHAV_L1D_FLUSH_PR)) || (!(result.behaviour & H_CPU_BEHAV_FAVOUR_SECURITY))) enable = false; - } else { - /* Default to fallback if case hcall is not available */ - types = L1D_FLUSH_FALLBACK; } setup_rfi_flush(types, enable); -- GitLab From 2b2f103b689bb1f092ccbc5f03ce5ec77d319319 Mon Sep 17 00:00:00 2001 From: Mauricio Faria de Oliveira Date: Sat, 2 Jun 2018 21:08:52 +1000 Subject: [PATCH 035/604] powerpc/rfi-flush: Differentiate enabled and patched flush types commit 0063d61ccfc011f379a31acaeba6de7c926fed2c upstream. Currently the rfi-flush messages print 'Using flush' for all enabled_flush_types, but that is not necessarily true -- as now the fallback flush is always enabled on pseries, but the fixup function overwrites its nop/branch slot with other flush types, if available. So, replace the 'Using flush' messages with ' flush is available'. Also, print the patched flush types in the fixup function, so users can know what is (not) being used (e.g., the slower, fallback flush, or no flush type at all if flush is disabled via the debugfs switch). Suggested-by: Michael Ellerman Signed-off-by: Mauricio Faria de Oliveira Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/setup_64.c | 6 +++--- arch/powerpc/lib/feature-fixups.c | 9 ++++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 568793009daa..eaa6039edddc 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -755,15 +755,15 @@ static void init_fallback_flush(void) void setup_rfi_flush(enum l1d_flush_type types, bool enable) { if (types & L1D_FLUSH_FALLBACK) { - pr_info("rfi-flush: Using fallback displacement flush\n"); + pr_info("rfi-flush: fallback displacement flush available\n"); init_fallback_flush(); } if (types & L1D_FLUSH_ORI) - pr_info("rfi-flush: Using ori type flush\n"); + pr_info("rfi-flush: ori type flush available\n"); if (types & L1D_FLUSH_MTTRIG) - pr_info("rfi-flush: Using mttrig type flush\n"); + pr_info("rfi-flush: mttrig type flush available\n"); enabled_flush_types = types; diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c index 46c8338a61bc..d89d54fa6acc 100644 --- a/arch/powerpc/lib/feature-fixups.c +++ b/arch/powerpc/lib/feature-fixups.c @@ -153,7 +153,14 @@ void do_rfi_flush_fixups(enum l1d_flush_type types) patch_instruction(dest + 2, instrs[2]); } - printk(KERN_DEBUG "rfi-flush: patched %d locations\n", i); + printk(KERN_DEBUG "rfi-flush: patched %d locations (%s flush)\n", i, + (types == L1D_FLUSH_NONE) ? "no" : + (types == L1D_FLUSH_FALLBACK) ? "fallback displacement" : + (types & L1D_FLUSH_ORI) ? (types & L1D_FLUSH_MTTRIG) + ? "ori+mttrig type" + : "ori type" : + (types & L1D_FLUSH_MTTRIG) ? "mttrig type" + : "unknown"); } #endif /* CONFIG_PPC_BOOK3S_64 */ -- GitLab From 82bfffedbda91ffdf7cebc210185fac3f6a2096b Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 2 Jun 2018 21:08:53 +1000 Subject: [PATCH 036/604] powerpc/rfi-flush: Call setup_rfi_flush() after LPM migration commit 921bc6cf807ceb2ab8005319cf39f33494d6b100 upstream. We might have migrated to a machine that uses a different flush type, or doesn't need flushing at all. Signed-off-by: Michael Ellerman Signed-off-by: Mauricio Faria de Oliveira Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/mobility.c | 3 +++ arch/powerpc/platforms/pseries/pseries.h | 2 ++ arch/powerpc/platforms/pseries/setup.c | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index 6a5e7467445c..3784a7abfcc8 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -314,6 +314,9 @@ void post_mobility_fixup(void) printk(KERN_ERR "Post-mobility device tree update " "failed: %d\n", rc); + /* Possibly switch to a new RFI flush type */ + pseries_setup_rfi_flush(); + return; } diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index b1be7b713fe6..62ff57cf6c24 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h @@ -79,4 +79,6 @@ extern struct pci_controller_ops pseries_pci_controller_ops; unsigned long pseries_memory_block_size(void); +void pseries_setup_rfi_flush(void); + #endif /* _PSERIES_PSERIES_H */ diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 626bf1ce1d80..483aa7a70d0a 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -450,7 +450,7 @@ static void __init find_and_init_phbs(void) of_pci_check_probe_only(); } -static void pseries_setup_rfi_flush(void) +void pseries_setup_rfi_flush(void) { struct h_cpu_char_result result; enum l1d_flush_type types; -- GitLab From 45bc42bf044ab5c305d8edc935ab8bf42e5806bf Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 2 Jun 2018 21:08:54 +1000 Subject: [PATCH 037/604] powerpc/pseries: Add new H_GET_CPU_CHARACTERISTICS flags commit c4bc36628d7f8b664657d8bd6ad1c44c177880b7 upstream. Add some additional values which have been defined for the H_GET_CPU_CHARACTERISTICS hypercall. Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/hvcall.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index dc0996b9d75d..9d978102bf0d 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -313,6 +313,9 @@ #define H_CPU_CHAR_L1D_FLUSH_ORI30 (1ull << 61) // IBM bit 2 #define H_CPU_CHAR_L1D_FLUSH_TRIG2 (1ull << 60) // IBM bit 3 #define H_CPU_CHAR_L1D_THREAD_PRIV (1ull << 59) // IBM bit 4 +#define H_CPU_CHAR_BRANCH_HINTS_HONORED (1ull << 58) // IBM bit 5 +#define H_CPU_CHAR_THREAD_RECONFIG_CTRL (1ull << 57) // IBM bit 6 +#define H_CPU_CHAR_COUNT_CACHE_DISABLED (1ull << 56) // IBM bit 7 #define H_CPU_BEHAV_FAVOUR_SECURITY (1ull << 63) // IBM bit 0 #define H_CPU_BEHAV_L1D_FLUSH_PR (1ull << 62) // IBM bit 1 -- GitLab From 62dfddfaf19a36dea650c192e7f5571e76bf1c0e Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 2 Jun 2018 21:08:55 +1000 Subject: [PATCH 038/604] powerpc: Add security feature flags for Spectre/Meltdown commit 9a868f634349e62922c226834aa23e3d1329ae7f upstream. This commit adds security feature flags to reflect the settings we receive from firmware regarding Spectre/Meltdown mitigations. The feature names reflect the names we are given by firmware on bare metal machines. See the hostboot source for details. Arguably these could be firmware features, but that then requires them to be read early in boot so they're available prior to asm feature patching, but we don't actually want to use them for patching. We may also want to dynamically update them in future, which would be incompatible with the way firmware features work (at the moment at least). So for now just make them separate flags. Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/security_features.h | 65 ++++++++++++++++++++ arch/powerpc/kernel/Makefile | 2 +- arch/powerpc/kernel/security.c | 15 +++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/include/asm/security_features.h create mode 100644 arch/powerpc/kernel/security.c diff --git a/arch/powerpc/include/asm/security_features.h b/arch/powerpc/include/asm/security_features.h new file mode 100644 index 000000000000..db00ad2c72c2 --- /dev/null +++ b/arch/powerpc/include/asm/security_features.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Security related feature bit definitions. + * + * Copyright 2018, Michael Ellerman, IBM Corporation. + */ + +#ifndef _ASM_POWERPC_SECURITY_FEATURES_H +#define _ASM_POWERPC_SECURITY_FEATURES_H + + +extern unsigned long powerpc_security_features; + +static inline void security_ftr_set(unsigned long feature) +{ + powerpc_security_features |= feature; +} + +static inline void security_ftr_clear(unsigned long feature) +{ + powerpc_security_features &= ~feature; +} + +static inline bool security_ftr_enabled(unsigned long feature) +{ + return !!(powerpc_security_features & feature); +} + + +// Features indicating support for Spectre/Meltdown mitigations + +// The L1-D cache can be flushed with ori r30,r30,0 +#define SEC_FTR_L1D_FLUSH_ORI30 0x0000000000000001ull + +// The L1-D cache can be flushed with mtspr 882,r0 (aka SPRN_TRIG2) +#define SEC_FTR_L1D_FLUSH_TRIG2 0x0000000000000002ull + +// ori r31,r31,0 acts as a speculation barrier +#define SEC_FTR_SPEC_BAR_ORI31 0x0000000000000004ull + +// Speculation past bctr is disabled +#define SEC_FTR_BCCTRL_SERIALISED 0x0000000000000008ull + +// Entries in L1-D are private to a SMT thread +#define SEC_FTR_L1D_THREAD_PRIV 0x0000000000000010ull + +// Indirect branch prediction cache disabled +#define SEC_FTR_COUNT_CACHE_DISABLED 0x0000000000000020ull + + +// Features indicating need for Spectre/Meltdown mitigations + +// The L1-D cache should be flushed on MSR[HV] 1->0 transition (hypervisor to guest) +#define SEC_FTR_L1D_FLUSH_HV 0x0000000000000040ull + +// The L1-D cache should be flushed on MSR[PR] 0->1 transition (kernel to userspace) +#define SEC_FTR_L1D_FLUSH_PR 0x0000000000000080ull + +// A speculation barrier should be used for bounds checks (Spectre variant 1) +#define SEC_FTR_BNDS_CHK_SPEC_BAR 0x0000000000000100ull + +// Firmware configuration indicates user favours security over performance +#define SEC_FTR_FAVOUR_SECURITY 0x0000000000000200ull + +#endif /* _ASM_POWERPC_SECURITY_FEATURES_H */ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index adb52d101133..13885786282b 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -44,7 +44,7 @@ obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \ obj-$(CONFIG_VDSO32) += vdso32/ obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o -obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power.o +obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power.o security.o obj-$(CONFIG_PPC_BOOK3S_64) += mce.o mce_power.o obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_book3e.o obj-$(CONFIG_PPC64) += vdso64/ diff --git a/arch/powerpc/kernel/security.c b/arch/powerpc/kernel/security.c new file mode 100644 index 000000000000..4ccba00d224c --- /dev/null +++ b/arch/powerpc/kernel/security.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Security related flags and so on. +// +// Copyright 2018, Michael Ellerman, IBM Corporation. + +#include +#include + + +unsigned long powerpc_security_features __read_mostly = \ + SEC_FTR_L1D_FLUSH_HV | \ + SEC_FTR_L1D_FLUSH_PR | \ + SEC_FTR_BNDS_CHK_SPEC_BAR | \ + SEC_FTR_FAVOUR_SECURITY; -- GitLab From 7be06caae78e49812522422e3d3ed9c8b788999f Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 2 Jun 2018 21:08:56 +1000 Subject: [PATCH 039/604] powerpc/pseries: Set or clear security feature flags commit f636c14790ead6cc22cf62279b1f8d7e11a67116 upstream. Now that we have feature flags for security related things, set or clear them based on what we receive from the hypercall. Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/setup.c | 43 ++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 483aa7a70d0a..a65515abe25f 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -66,6 +66,7 @@ #include #include #include +#include #include "pseries.h" @@ -450,6 +451,40 @@ static void __init find_and_init_phbs(void) of_pci_check_probe_only(); } +static void init_cpu_char_feature_flags(struct h_cpu_char_result *result) +{ + if (result->character & H_CPU_CHAR_SPEC_BAR_ORI31) + security_ftr_set(SEC_FTR_SPEC_BAR_ORI31); + + if (result->character & H_CPU_CHAR_BCCTRL_SERIALISED) + security_ftr_set(SEC_FTR_BCCTRL_SERIALISED); + + if (result->character & H_CPU_CHAR_L1D_FLUSH_ORI30) + security_ftr_set(SEC_FTR_L1D_FLUSH_ORI30); + + if (result->character & H_CPU_CHAR_L1D_FLUSH_TRIG2) + security_ftr_set(SEC_FTR_L1D_FLUSH_TRIG2); + + if (result->character & H_CPU_CHAR_L1D_THREAD_PRIV) + security_ftr_set(SEC_FTR_L1D_THREAD_PRIV); + + if (result->character & H_CPU_CHAR_COUNT_CACHE_DISABLED) + security_ftr_set(SEC_FTR_COUNT_CACHE_DISABLED); + + /* + * The features below are enabled by default, so we instead look to see + * if firmware has *disabled* them, and clear them if so. + */ + if (!(result->character & H_CPU_BEHAV_FAVOUR_SECURITY)) + security_ftr_clear(SEC_FTR_FAVOUR_SECURITY); + + if (!(result->character & H_CPU_BEHAV_L1D_FLUSH_PR)) + security_ftr_clear(SEC_FTR_L1D_FLUSH_PR); + + if (!(result->character & H_CPU_BEHAV_BNDS_CHK_SPEC_BAR)) + security_ftr_clear(SEC_FTR_BNDS_CHK_SPEC_BAR); +} + void pseries_setup_rfi_flush(void) { struct h_cpu_char_result result; @@ -463,6 +498,8 @@ void pseries_setup_rfi_flush(void) rc = plpar_get_cpu_characteristics(&result); if (rc == H_SUCCESS) { + init_cpu_char_feature_flags(&result); + if (result.character & H_CPU_CHAR_L1D_FLUSH_TRIG2) types |= L1D_FLUSH_MTTRIG; if (result.character & H_CPU_CHAR_L1D_FLUSH_ORI30) @@ -473,6 +510,12 @@ void pseries_setup_rfi_flush(void) enable = false; } + /* + * We're the guest so this doesn't apply to us, clear it to simplify + * handling of it elsewhere. + */ + security_ftr_clear(SEC_FTR_L1D_FLUSH_HV); + setup_rfi_flush(types, enable); } -- GitLab From bdcfeadf97700af96107929a92ceaf04beb323f9 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 2 Jun 2018 21:08:57 +1000 Subject: [PATCH 040/604] powerpc/powernv: Set or clear security feature flags commit 77addf6e95c8689e478d607176b399a6242a777e upstream. Now that we have feature flags for security related things, set or clear them based on what we see in the device tree provided by firmware. Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powernv/setup.c | 56 ++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 4764bc91570c..26fbaf14f87a 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -37,9 +37,63 @@ #include #include #include +#include #include "powernv.h" + +static bool fw_feature_is(const char *state, const char *name, + struct device_node *fw_features) +{ + struct device_node *np; + bool rc = false; + + np = of_get_child_by_name(fw_features, name); + if (np) { + rc = of_property_read_bool(np, state); + of_node_put(np); + } + + return rc; +} + +static void init_fw_feat_flags(struct device_node *np) +{ + if (fw_feature_is("enabled", "inst-spec-barrier-ori31,31,0", np)) + security_ftr_set(SEC_FTR_SPEC_BAR_ORI31); + + if (fw_feature_is("enabled", "fw-bcctrl-serialized", np)) + security_ftr_set(SEC_FTR_BCCTRL_SERIALISED); + + if (fw_feature_is("enabled", "inst-spec-barrier-ori31,31,0", np)) + security_ftr_set(SEC_FTR_L1D_FLUSH_ORI30); + + if (fw_feature_is("enabled", "inst-l1d-flush-trig2", np)) + security_ftr_set(SEC_FTR_L1D_FLUSH_TRIG2); + + if (fw_feature_is("enabled", "fw-l1d-thread-split", np)) + security_ftr_set(SEC_FTR_L1D_THREAD_PRIV); + + if (fw_feature_is("enabled", "fw-count-cache-disabled", np)) + security_ftr_set(SEC_FTR_COUNT_CACHE_DISABLED); + + /* + * The features below are enabled by default, so we instead look to see + * if firmware has *disabled* them, and clear them if so. + */ + if (fw_feature_is("disabled", "speculation-policy-favor-security", np)) + security_ftr_clear(SEC_FTR_FAVOUR_SECURITY); + + if (fw_feature_is("disabled", "needs-l1d-flush-msr-pr-0-to-1", np)) + security_ftr_clear(SEC_FTR_L1D_FLUSH_PR); + + if (fw_feature_is("disabled", "needs-l1d-flush-msr-hv-1-to-0", np)) + security_ftr_clear(SEC_FTR_L1D_FLUSH_HV); + + if (fw_feature_is("disabled", "needs-spec-barrier-for-bound-checks", np)) + security_ftr_clear(SEC_FTR_BNDS_CHK_SPEC_BAR); +} + static void pnv_setup_rfi_flush(void) { struct device_node *np, *fw_features; @@ -55,6 +109,8 @@ static void pnv_setup_rfi_flush(void) of_node_put(np); if (fw_features) { + init_fw_feat_flags(fw_features); + np = of_get_child_by_name(fw_features, "inst-l1d-flush-trig2"); if (np && of_property_read_bool(np, "enabled")) type = L1D_FLUSH_MTTRIG; -- GitLab From 6f81254e77e238d04215dfa0d952f6af5819cc1d Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 2 Jun 2018 21:08:58 +1000 Subject: [PATCH 041/604] powerpc/64s: Move cpu_show_meltdown() commit 8ad33041563a10b34988800c682ada14b2612533 upstream. This landed in setup_64.c for no good reason other than we had nowhere else to put it. Now that we have a security-related file, that is a better place for it so move it. [mpe: Add extern for rfi_flush to fix bisection break] Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/security_features.h | 1 + arch/powerpc/kernel/security.c | 11 +++++++++++ arch/powerpc/kernel/setup_64.c | 8 -------- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/include/asm/security_features.h b/arch/powerpc/include/asm/security_features.h index db00ad2c72c2..400a9050e035 100644 --- a/arch/powerpc/include/asm/security_features.h +++ b/arch/powerpc/include/asm/security_features.h @@ -10,6 +10,7 @@ extern unsigned long powerpc_security_features; +extern bool rfi_flush; static inline void security_ftr_set(unsigned long feature) { diff --git a/arch/powerpc/kernel/security.c b/arch/powerpc/kernel/security.c index 4ccba00d224c..564e7f182a16 100644 --- a/arch/powerpc/kernel/security.c +++ b/arch/powerpc/kernel/security.c @@ -5,6 +5,8 @@ // Copyright 2018, Michael Ellerman, IBM Corporation. #include +#include + #include @@ -13,3 +15,12 @@ unsigned long powerpc_security_features __read_mostly = \ SEC_FTR_L1D_FLUSH_PR | \ SEC_FTR_BNDS_CHK_SPEC_BAR | \ SEC_FTR_FAVOUR_SECURITY; + + +ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) +{ + if (rfi_flush) + return sprintf(buf, "Mitigation: RFI Flush\n"); + + return sprintf(buf, "Vulnerable\n"); +} diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index eaa6039edddc..eda7eefe4927 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -805,12 +805,4 @@ static __init int rfi_flush_debugfs_init(void) } device_initcall(rfi_flush_debugfs_init); #endif - -ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) -{ - if (rfi_flush) - return sprintf(buf, "Mitigation: RFI Flush\n"); - - return sprintf(buf, "Vulnerable\n"); -} #endif /* CONFIG_PPC_BOOK3S_64 */ -- GitLab From a8f6001c701d0619abe1d266f958b131ea767890 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 2 Jun 2018 21:08:59 +1000 Subject: [PATCH 042/604] powerpc/64s: Enhance the information in cpu_show_meltdown() commit ff348355e9c72493947be337bb4fae4fc1a41eba upstream. Now that we have the security feature flags we can make the information displayed in the "meltdown" file more informative. Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/security.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/security.c b/arch/powerpc/kernel/security.c index 564e7f182a16..865db6f8bcca 100644 --- a/arch/powerpc/kernel/security.c +++ b/arch/powerpc/kernel/security.c @@ -6,6 +6,7 @@ #include #include +#include #include @@ -19,8 +20,33 @@ unsigned long powerpc_security_features __read_mostly = \ ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) { - if (rfi_flush) - return sprintf(buf, "Mitigation: RFI Flush\n"); + bool thread_priv; + + thread_priv = security_ftr_enabled(SEC_FTR_L1D_THREAD_PRIV); + + if (rfi_flush || thread_priv) { + struct seq_buf s; + seq_buf_init(&s, buf, PAGE_SIZE - 1); + + seq_buf_printf(&s, "Mitigation: "); + + if (rfi_flush) + seq_buf_printf(&s, "RFI Flush"); + + if (rfi_flush && thread_priv) + seq_buf_printf(&s, ", "); + + if (thread_priv) + seq_buf_printf(&s, "L1D private per thread"); + + seq_buf_printf(&s, "\n"); + + return s.len; + } + + if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && + !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) + return sprintf(buf, "Not affected\n"); return sprintf(buf, "Vulnerable\n"); } -- GitLab From fe1a517821084cc8c80fc4d0bd9da86323868769 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 2 Jun 2018 21:09:00 +1000 Subject: [PATCH 043/604] powerpc/powernv: Use the security flags in pnv_setup_rfi_flush() commit 37c0bdd00d3ae83369ab60a6712c28e11e6458d5 upstream. Now that we have the security flags we can significantly simplify the code in pnv_setup_rfi_flush(), because we can use the flags instead of checking device tree properties and because the security flags have pessimistic defaults. Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powernv/setup.c | 41 +++++++------------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 26fbaf14f87a..2c646f5bd144 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -65,7 +65,7 @@ static void init_fw_feat_flags(struct device_node *np) if (fw_feature_is("enabled", "fw-bcctrl-serialized", np)) security_ftr_set(SEC_FTR_BCCTRL_SERIALISED); - if (fw_feature_is("enabled", "inst-spec-barrier-ori31,31,0", np)) + if (fw_feature_is("enabled", "inst-l1d-flush-ori30,30,0", np)) security_ftr_set(SEC_FTR_L1D_FLUSH_ORI30); if (fw_feature_is("enabled", "inst-l1d-flush-trig2", np)) @@ -98,11 +98,10 @@ static void pnv_setup_rfi_flush(void) { struct device_node *np, *fw_features; enum l1d_flush_type type; - int enable; + bool enable; /* Default to fallback in case fw-features are not available */ type = L1D_FLUSH_FALLBACK; - enable = 1; np = of_find_node_by_name(NULL, "ibm,opal"); fw_features = of_get_child_by_name(np, "fw-features"); @@ -110,40 +109,20 @@ static void pnv_setup_rfi_flush(void) if (fw_features) { init_fw_feat_flags(fw_features); + of_node_put(fw_features); - np = of_get_child_by_name(fw_features, "inst-l1d-flush-trig2"); - if (np && of_property_read_bool(np, "enabled")) + if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_TRIG2)) type = L1D_FLUSH_MTTRIG; - of_node_put(np); - - np = of_get_child_by_name(fw_features, "inst-l1d-flush-ori30,30,0"); - if (np && of_property_read_bool(np, "enabled")) + if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_ORI30)) type = L1D_FLUSH_ORI; - - of_node_put(np); - - /* Enable unless firmware says NOT to */ - enable = 2; - np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-hv-1-to-0"); - if (np && of_property_read_bool(np, "disabled")) - enable--; - - of_node_put(np); - - np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-pr-0-to-1"); - if (np && of_property_read_bool(np, "disabled")) - enable--; - - np = of_get_child_by_name(fw_features, "speculation-policy-favor-security"); - if (np && of_property_read_bool(np, "disabled")) - enable = 0; - - of_node_put(np); - of_node_put(fw_features); } - setup_rfi_flush(type, enable > 0); + enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && \ + (security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR) || \ + security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV)); + + setup_rfi_flush(type, enable); } static void __init pnv_setup_arch(void) -- GitLab From 76e0b304b38764497044fb064deafd79a0d92c14 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 2 Jun 2018 21:09:01 +1000 Subject: [PATCH 044/604] powerpc/pseries: Use the security flags in pseries_setup_rfi_flush() commit 2e4a16161fcd324b1f9bf6cb6856529f7eaf0689 upstream. Now that we have the security flags we can simplify the code in pseries_setup_rfi_flush() because the security flags have pessimistic defaults. Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/setup.c | 27 ++++++++++++-------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index a65515abe25f..28d7cd2001cc 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -492,30 +492,27 @@ void pseries_setup_rfi_flush(void) bool enable; long rc; - /* Enable by default */ - enable = true; - types = L1D_FLUSH_FALLBACK; - rc = plpar_get_cpu_characteristics(&result); - if (rc == H_SUCCESS) { + if (rc == H_SUCCESS) init_cpu_char_feature_flags(&result); - if (result.character & H_CPU_CHAR_L1D_FLUSH_TRIG2) - types |= L1D_FLUSH_MTTRIG; - if (result.character & H_CPU_CHAR_L1D_FLUSH_ORI30) - types |= L1D_FLUSH_ORI; - - if ((!(result.behaviour & H_CPU_BEHAV_L1D_FLUSH_PR)) || - (!(result.behaviour & H_CPU_BEHAV_FAVOUR_SECURITY))) - enable = false; - } - /* * We're the guest so this doesn't apply to us, clear it to simplify * handling of it elsewhere. */ security_ftr_clear(SEC_FTR_L1D_FLUSH_HV); + types = L1D_FLUSH_FALLBACK; + + if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_TRIG2)) + types |= L1D_FLUSH_MTTRIG; + + if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_ORI30)) + types |= L1D_FLUSH_ORI; + + enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && \ + security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR); + setup_rfi_flush(types, enable); } -- GitLab From ed50e032f7de992352d57e3dd9dd2f8a6a235e95 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 2 Jun 2018 21:09:02 +1000 Subject: [PATCH 045/604] powerpc/64s: Wire up cpu_show_spectre_v1() commit 56986016cb8cd9050e601831fe89f332b4e3c46e upstream. Add a definition for cpu_show_spectre_v1() to override the generic version. Currently this just prints "Not affected" or "Vulnerable" based on the firmware flag. Although the kernel does have array_index_nospec() in a few places, we haven't yet audited all the powerpc code to see where it's necessary, so for now we don't list that as a mitigation. Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/security.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/powerpc/kernel/security.c b/arch/powerpc/kernel/security.c index 865db6f8bcca..0eace3cac818 100644 --- a/arch/powerpc/kernel/security.c +++ b/arch/powerpc/kernel/security.c @@ -50,3 +50,11 @@ ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, cha return sprintf(buf, "Vulnerable\n"); } + +ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf) +{ + if (!security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR)) + return sprintf(buf, "Not affected\n"); + + return sprintf(buf, "Vulnerable\n"); +} -- GitLab From 1dc0f1f17539c3931c9e3613ce59aa37d3747c94 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 2 Jun 2018 21:09:03 +1000 Subject: [PATCH 046/604] powerpc/64s: Wire up cpu_show_spectre_v2() commit d6fbe1c55c55c6937cbea3531af7da84ab7473c3 upstream. Add a definition for cpu_show_spectre_v2() to override the generic version. This has several permuations, though in practice some may not occur we cater for any combination. The most verbose is: Mitigation: Indirect branch serialisation (kernel only), Indirect branch cache disabled, ori31 speculation barrier enabled We don't treat the ori31 speculation barrier as a mitigation on its own, because it has to be *used* by code in order to be a mitigation and we don't know if userspace is doing that. So if that's all we see we say: Vulnerable, ori31 speculation barrier enabled Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/security.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/arch/powerpc/kernel/security.c b/arch/powerpc/kernel/security.c index 0eace3cac818..2cee3dcd231b 100644 --- a/arch/powerpc/kernel/security.c +++ b/arch/powerpc/kernel/security.c @@ -58,3 +58,36 @@ ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, c return sprintf(buf, "Vulnerable\n"); } + +ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf) +{ + bool bcs, ccd, ori; + struct seq_buf s; + + seq_buf_init(&s, buf, PAGE_SIZE - 1); + + bcs = security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED); + ccd = security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED); + ori = security_ftr_enabled(SEC_FTR_SPEC_BAR_ORI31); + + if (bcs || ccd) { + seq_buf_printf(&s, "Mitigation: "); + + if (bcs) + seq_buf_printf(&s, "Indirect branch serialisation (kernel only)"); + + if (bcs && ccd) + seq_buf_printf(&s, ", "); + + if (ccd) + seq_buf_printf(&s, "Indirect branch cache disabled"); + } else + seq_buf_printf(&s, "Vulnerable"); + + if (ori) + seq_buf_printf(&s, ", ori31 speculation barrier enabled"); + + seq_buf_printf(&s, "\n"); + + return s.len; +} -- GitLab From 9e337dcf2edc095971751bf55293f8a92d5e55e3 Mon Sep 17 00:00:00 2001 From: Mauricio Faria de Oliveira Date: Sat, 2 Jun 2018 21:09:04 +1000 Subject: [PATCH 047/604] powerpc/pseries: Fix clearing of security feature flags commit 0f9bdfe3c77091e8704d2e510eb7c2c2c6cde524 upstream. The H_CPU_BEHAV_* flags should be checked for in the 'behaviour' field of 'struct h_cpu_char_result' -- 'character' is for H_CPU_CHAR_* flags. Found by playing around with QEMU's implementation of the hypercall: H_CPU_CHAR=0xf000000000000000 H_CPU_BEHAV=0x0000000000000000 This clears H_CPU_BEHAV_FAVOUR_SECURITY and H_CPU_BEHAV_L1D_FLUSH_PR so pseries_setup_rfi_flush() disables 'rfi_flush'; and it also clears H_CPU_CHAR_L1D_THREAD_PRIV flag. So there is no RFI flush mitigation at all for cpu_show_meltdown() to report; but currently it does: Original kernel: # cat /sys/devices/system/cpu/vulnerabilities/meltdown Mitigation: RFI Flush Patched kernel: # cat /sys/devices/system/cpu/vulnerabilities/meltdown Not affected H_CPU_CHAR=0x0000000000000000 H_CPU_BEHAV=0xf000000000000000 This sets H_CPU_BEHAV_BNDS_CHK_SPEC_BAR so cpu_show_spectre_v1() should report vulnerable; but currently it doesn't: Original kernel: # cat /sys/devices/system/cpu/vulnerabilities/spectre_v1 Not affected Patched kernel: # cat /sys/devices/system/cpu/vulnerabilities/spectre_v1 Vulnerable Brown-paper-bag-by: Michael Ellerman Fixes: f636c14790ea ("powerpc/pseries: Set or clear security feature flags") Signed-off-by: Mauricio Faria de Oliveira Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/setup.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 28d7cd2001cc..8d9f591e7950 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -475,13 +475,13 @@ static void init_cpu_char_feature_flags(struct h_cpu_char_result *result) * The features below are enabled by default, so we instead look to see * if firmware has *disabled* them, and clear them if so. */ - if (!(result->character & H_CPU_BEHAV_FAVOUR_SECURITY)) + if (!(result->behaviour & H_CPU_BEHAV_FAVOUR_SECURITY)) security_ftr_clear(SEC_FTR_FAVOUR_SECURITY); - if (!(result->character & H_CPU_BEHAV_L1D_FLUSH_PR)) + if (!(result->behaviour & H_CPU_BEHAV_L1D_FLUSH_PR)) security_ftr_clear(SEC_FTR_L1D_FLUSH_PR); - if (!(result->character & H_CPU_BEHAV_BNDS_CHK_SPEC_BAR)) + if (!(result->behaviour & H_CPU_BEHAV_BNDS_CHK_SPEC_BAR)) security_ftr_clear(SEC_FTR_BNDS_CHK_SPEC_BAR); } -- GitLab From 4ec7e5e89fd4cdc0e2695a2e0d7541916193f6e2 Mon Sep 17 00:00:00 2001 From: Mauricio Faria de Oliveira Date: Sat, 2 Jun 2018 21:09:05 +1000 Subject: [PATCH 048/604] powerpc: Move default security feature flags commit e7347a86830f38dc3e40c8f7e28c04412b12a2e7 upstream. This moves the definition of the default security feature flags (i.e., enabled by default) closer to the security feature flags. This can be used to restore current flags to the default flags. Signed-off-by: Mauricio Faria de Oliveira Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/security_features.h | 8 ++++++++ arch/powerpc/kernel/security.c | 7 +------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/include/asm/security_features.h b/arch/powerpc/include/asm/security_features.h index 400a9050e035..fa4d2e1cf772 100644 --- a/arch/powerpc/include/asm/security_features.h +++ b/arch/powerpc/include/asm/security_features.h @@ -63,4 +63,12 @@ static inline bool security_ftr_enabled(unsigned long feature) // Firmware configuration indicates user favours security over performance #define SEC_FTR_FAVOUR_SECURITY 0x0000000000000200ull + +// Features enabled by default +#define SEC_FTR_DEFAULT \ + (SEC_FTR_L1D_FLUSH_HV | \ + SEC_FTR_L1D_FLUSH_PR | \ + SEC_FTR_BNDS_CHK_SPEC_BAR | \ + SEC_FTR_FAVOUR_SECURITY) + #endif /* _ASM_POWERPC_SECURITY_FEATURES_H */ diff --git a/arch/powerpc/kernel/security.c b/arch/powerpc/kernel/security.c index 2cee3dcd231b..bab5a27ea805 100644 --- a/arch/powerpc/kernel/security.c +++ b/arch/powerpc/kernel/security.c @@ -11,12 +11,7 @@ #include -unsigned long powerpc_security_features __read_mostly = \ - SEC_FTR_L1D_FLUSH_HV | \ - SEC_FTR_L1D_FLUSH_PR | \ - SEC_FTR_BNDS_CHK_SPEC_BAR | \ - SEC_FTR_FAVOUR_SECURITY; - +unsigned long powerpc_security_features __read_mostly = SEC_FTR_DEFAULT; ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) { -- GitLab From 9aa638676be49e9372f0b570cd729145ea122061 Mon Sep 17 00:00:00 2001 From: Mauricio Faria de Oliveira Date: Sat, 2 Jun 2018 21:09:06 +1000 Subject: [PATCH 049/604] powerpc/pseries: Restore default security feature flags on setup commit 6232774f1599028a15418179d17f7df47ede770a upstream. After migration the security feature flags might have changed (e.g., destination system with unpatched firmware), but some flags are not set/clear again in init_cpu_char_feature_flags() because it assumes the security flags to be the defaults. Additionally, if the H_GET_CPU_CHARACTERISTICS hypercall fails then init_cpu_char_feature_flags() does not run again, which potentially might leave the system in an insecure or sub-optimal configuration. So, just restore the security feature flags to the defaults assumed by init_cpu_char_feature_flags() so it can set/clear them correctly, and to ensure safe settings are in place in case the hypercall fail. Fixes: f636c14790ea ("powerpc/pseries: Set or clear security feature flags") Depends-on: 19887d6a28e2 ("powerpc: Move default security feature flags") Signed-off-by: Mauricio Faria de Oliveira Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/setup.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 8d9f591e7950..7349c05032be 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -453,6 +453,10 @@ static void __init find_and_init_phbs(void) static void init_cpu_char_feature_flags(struct h_cpu_char_result *result) { + /* + * The features below are disabled by default, so we instead look to see + * if firmware has *enabled* them, and set them if so. + */ if (result->character & H_CPU_CHAR_SPEC_BAR_ORI31) security_ftr_set(SEC_FTR_SPEC_BAR_ORI31); @@ -492,6 +496,13 @@ void pseries_setup_rfi_flush(void) bool enable; long rc; + /* + * Set features to the defaults assumed by init_cpu_char_feature_flags() + * so it can set/clear again any features that might have changed after + * migration, and in case the hypercall fails and it is not even called. + */ + powerpc_security_features = SEC_FTR_DEFAULT; + rc = plpar_get_cpu_characteristics(&result); if (rc == H_SUCCESS) init_cpu_char_feature_flags(&result); -- GitLab From 2149936d12894357af9f50cb3effb99f3b41b4ce Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sat, 2 Jun 2018 21:09:07 +1000 Subject: [PATCH 050/604] powerpc/64s: Fix section mismatch warnings from setup_rfi_flush() commit 501a78cbc17c329fabf8e9750a1e9ab810c88a0e upstream. The recent LPM changes to setup_rfi_flush() are causing some section mismatch warnings because we removed the __init annotation on setup_rfi_flush(): The function setup_rfi_flush() references the function __init ppc64_bolted_size(). the function __init memblock_alloc_base(). The references are actually in init_fallback_flush(), but that is inlined into setup_rfi_flush(). These references are safe because: - only pseries calls setup_rfi_flush() at runtime - pseries always passes L1D_FLUSH_FALLBACK at boot - so the fallback flush area will always be allocated - so the check in init_fallback_flush() will always return early: /* Only allocate the fallback flush area once (at boot time). */ if (l1d_flush_fallback_area) return; - and therefore we won't actually call the freed init routines. We should rework the code to make it safer by default rather than relying on the above, but for now as a quick-fix just add a __ref annotation to squash the warning. Fixes: abf110f3e1ce ("powerpc/rfi-flush: Make it possible to call setup_rfi_flush() again") Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/setup_64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index eda7eefe4927..fdba10695208 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -726,7 +726,7 @@ void rfi_flush_enable(bool enable) rfi_flush = enable; } -static void init_fallback_flush(void) +static void __ref init_fallback_flush(void) { u64 l1d_size, limit; int cpu; -- GitLab From e9b911a97bbd8d781d7281e913a1bc872e02f3cb Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 2 Jun 2018 21:09:08 +1000 Subject: [PATCH 051/604] powerpc/64s: Add support for a store forwarding barrier at kernel entry/exit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit a048a07d7f4535baa4cbad6bc024f175317ab938 upstream. On some CPUs we can prevent a vulnerability related to store-to-load forwarding by preventing store forwarding between privilege domains, by inserting a barrier in kernel entry and exit paths. This is known to be the case on at least Power7, Power8 and Power9 powerpc CPUs. Barriers must be inserted generally before the first load after moving to a higher privilege, and after the last store before moving to a lower privilege, HV and PR privilege transitions must be protected. Barriers are added as patch sections, with all kernel/hypervisor entry points patched, and the exit points to lower privilge levels patched similarly to the RFI flush patching. Firmware advertisement is not implemented yet, so CPU flush types are hard coded. Thanks to Michal Suchánek for bug fixes and review. Signed-off-by: Nicholas Piggin Signed-off-by: Mauricio Faria de Oliveira Signed-off-by: Michael Neuling Signed-off-by: Michal Suchánek Signed-off-by: Michael Ellerman Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/exception-64s.h | 29 ++++ arch/powerpc/include/asm/feature-fixups.h | 19 +++ arch/powerpc/include/asm/security_features.h | 11 ++ arch/powerpc/kernel/exceptions-64s.S | 16 +- arch/powerpc/kernel/security.c | 149 +++++++++++++++++++ arch/powerpc/kernel/vmlinux.lds.S | 14 ++ arch/powerpc/lib/feature-fixups.c | 115 ++++++++++++++ arch/powerpc/platforms/powernv/setup.c | 1 + arch/powerpc/platforms/pseries/setup.c | 1 + 9 files changed, 354 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 903e76a9f158..e2200100828d 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -51,6 +51,27 @@ #define EX_PPR 88 /* SMT thread status register (priority) */ #define EX_CTR 96 +#define STF_ENTRY_BARRIER_SLOT \ + STF_ENTRY_BARRIER_FIXUP_SECTION; \ + nop; \ + nop; \ + nop + +#define STF_EXIT_BARRIER_SLOT \ + STF_EXIT_BARRIER_FIXUP_SECTION; \ + nop; \ + nop; \ + nop; \ + nop; \ + nop; \ + nop + +/* + * r10 must be free to use, r13 must be paca + */ +#define INTERRUPT_TO_KERNEL \ + STF_ENTRY_BARRIER_SLOT + /* * Macros for annotating the expected destination of (h)rfid * @@ -67,16 +88,19 @@ rfid #define RFI_TO_USER \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ rfid; \ b rfi_flush_fallback #define RFI_TO_USER_OR_KERNEL \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ rfid; \ b rfi_flush_fallback #define RFI_TO_GUEST \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ rfid; \ b rfi_flush_fallback @@ -85,21 +109,25 @@ hrfid #define HRFI_TO_USER \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ hrfid; \ b hrfi_flush_fallback #define HRFI_TO_USER_OR_KERNEL \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ hrfid; \ b hrfi_flush_fallback #define HRFI_TO_GUEST \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ hrfid; \ b hrfi_flush_fallback #define HRFI_TO_UNKNOWN \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ hrfid; \ b hrfi_flush_fallback @@ -225,6 +253,7 @@ END_FTR_SECTION_NESTED(ftr,ftr,943) #define __EXCEPTION_PROLOG_1(area, extra, vec) \ OPT_SAVE_REG_TO_PACA(area+EX_PPR, r9, CPU_FTR_HAS_PPR); \ OPT_SAVE_REG_TO_PACA(area+EX_CFAR, r10, CPU_FTR_CFAR); \ + INTERRUPT_TO_KERNEL; \ SAVE_CTR(r10, area); \ mfcr r9; \ extra(vec); \ diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h index 7b332342071c..0bf8202feca6 100644 --- a/arch/powerpc/include/asm/feature-fixups.h +++ b/arch/powerpc/include/asm/feature-fixups.h @@ -189,6 +189,22 @@ void apply_feature_fixups(void); void setup_feature_keys(void); #endif +#define STF_ENTRY_BARRIER_FIXUP_SECTION \ +953: \ + .pushsection __stf_entry_barrier_fixup,"a"; \ + .align 2; \ +954: \ + FTR_ENTRY_OFFSET 953b-954b; \ + .popsection; + +#define STF_EXIT_BARRIER_FIXUP_SECTION \ +955: \ + .pushsection __stf_exit_barrier_fixup,"a"; \ + .align 2; \ +956: \ + FTR_ENTRY_OFFSET 955b-956b; \ + .popsection; + #define RFI_FLUSH_FIXUP_SECTION \ 951: \ .pushsection __rfi_flush_fixup,"a"; \ @@ -200,6 +216,9 @@ void setup_feature_keys(void); #ifndef __ASSEMBLY__ +extern long stf_barrier_fallback; +extern long __start___stf_entry_barrier_fixup, __stop___stf_entry_barrier_fixup; +extern long __start___stf_exit_barrier_fixup, __stop___stf_exit_barrier_fixup; extern long __start___rfi_flush_fixup, __stop___rfi_flush_fixup; #endif diff --git a/arch/powerpc/include/asm/security_features.h b/arch/powerpc/include/asm/security_features.h index fa4d2e1cf772..44989b22383c 100644 --- a/arch/powerpc/include/asm/security_features.h +++ b/arch/powerpc/include/asm/security_features.h @@ -12,6 +12,17 @@ extern unsigned long powerpc_security_features; extern bool rfi_flush; +/* These are bit flags */ +enum stf_barrier_type { + STF_BARRIER_NONE = 0x1, + STF_BARRIER_FALLBACK = 0x2, + STF_BARRIER_EIEIO = 0x4, + STF_BARRIER_SYNC_ORI = 0x8, +}; + +void setup_stf_barrier(void); +void do_stf_barrier_fixups(enum stf_barrier_type types); + static inline void security_ftr_set(unsigned long feature) { powerpc_security_features |= feature; diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 94b5dfb087e9..d50cc9b38b80 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -846,7 +846,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_TM) #endif -EXC_REAL_MASKABLE(decrementer, 0x900, 0x980) +EXC_REAL_OOL_MASKABLE(decrementer, 0x900, 0x980) EXC_VIRT_MASKABLE(decrementer, 0x4900, 0x4980, 0x900) TRAMP_KVM(PACA_EXGEN, 0x900) EXC_COMMON_ASYNC(decrementer_common, 0x900, timer_interrupt) @@ -884,6 +884,7 @@ BEGIN_FTR_SECTION \ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ mr r9,r13 ; \ GET_PACA(r13) ; \ + INTERRUPT_TO_KERNEL ; \ mfspr r11,SPRN_SRR0 ; \ 0: @@ -1353,6 +1354,19 @@ masked_##_H##interrupt: \ ##_H##RFI_TO_KERNEL; \ b . +TRAMP_REAL_BEGIN(stf_barrier_fallback) + std r9,PACA_EXRFI+EX_R9(r13) + std r10,PACA_EXRFI+EX_R10(r13) + sync + ld r9,PACA_EXRFI+EX_R9(r13) + ld r10,PACA_EXRFI+EX_R10(r13) + ori 31,31,0 + .rept 14 + b 1f +1: + .endr + blr + /* * Real mode exceptions actually use this too, but alternate * instruction code patches (which end up in the common .text area) diff --git a/arch/powerpc/kernel/security.c b/arch/powerpc/kernel/security.c index bab5a27ea805..2277df84ef6e 100644 --- a/arch/powerpc/kernel/security.c +++ b/arch/powerpc/kernel/security.c @@ -5,6 +5,7 @@ // Copyright 2018, Michael Ellerman, IBM Corporation. #include +#include #include #include @@ -86,3 +87,151 @@ ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, c return s.len; } + +/* + * Store-forwarding barrier support. + */ + +static enum stf_barrier_type stf_enabled_flush_types; +static bool no_stf_barrier; +bool stf_barrier; + +static int __init handle_no_stf_barrier(char *p) +{ + pr_info("stf-barrier: disabled on command line."); + no_stf_barrier = true; + return 0; +} + +early_param("no_stf_barrier", handle_no_stf_barrier); + +/* This is the generic flag used by other architectures */ +static int __init handle_ssbd(char *p) +{ + if (!p || strncmp(p, "auto", 5) == 0 || strncmp(p, "on", 2) == 0 ) { + /* Until firmware tells us, we have the barrier with auto */ + return 0; + } else if (strncmp(p, "off", 3) == 0) { + handle_no_stf_barrier(NULL); + return 0; + } else + return 1; + + return 0; +} +early_param("spec_store_bypass_disable", handle_ssbd); + +/* This is the generic flag used by other architectures */ +static int __init handle_no_ssbd(char *p) +{ + handle_no_stf_barrier(NULL); + return 0; +} +early_param("nospec_store_bypass_disable", handle_no_ssbd); + +static void stf_barrier_enable(bool enable) +{ + if (enable) + do_stf_barrier_fixups(stf_enabled_flush_types); + else + do_stf_barrier_fixups(STF_BARRIER_NONE); + + stf_barrier = enable; +} + +void setup_stf_barrier(void) +{ + enum stf_barrier_type type; + bool enable, hv; + + hv = cpu_has_feature(CPU_FTR_HVMODE); + + /* Default to fallback in case fw-features are not available */ + if (cpu_has_feature(CPU_FTR_ARCH_300)) + type = STF_BARRIER_EIEIO; + else if (cpu_has_feature(CPU_FTR_ARCH_207S)) + type = STF_BARRIER_SYNC_ORI; + else if (cpu_has_feature(CPU_FTR_ARCH_206)) + type = STF_BARRIER_FALLBACK; + else + type = STF_BARRIER_NONE; + + enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && + (security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR) || + (security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && hv)); + + if (type == STF_BARRIER_FALLBACK) { + pr_info("stf-barrier: fallback barrier available\n"); + } else if (type == STF_BARRIER_SYNC_ORI) { + pr_info("stf-barrier: hwsync barrier available\n"); + } else if (type == STF_BARRIER_EIEIO) { + pr_info("stf-barrier: eieio barrier available\n"); + } + + stf_enabled_flush_types = type; + + if (!no_stf_barrier) + stf_barrier_enable(enable); +} + +ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *attr, char *buf) +{ + if (stf_barrier && stf_enabled_flush_types != STF_BARRIER_NONE) { + const char *type; + switch (stf_enabled_flush_types) { + case STF_BARRIER_EIEIO: + type = "eieio"; + break; + case STF_BARRIER_SYNC_ORI: + type = "hwsync"; + break; + case STF_BARRIER_FALLBACK: + type = "fallback"; + break; + default: + type = "unknown"; + } + return sprintf(buf, "Mitigation: Kernel entry/exit barrier (%s)\n", type); + } + + if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && + !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) + return sprintf(buf, "Not affected\n"); + + return sprintf(buf, "Vulnerable\n"); +} + +#ifdef CONFIG_DEBUG_FS +static int stf_barrier_set(void *data, u64 val) +{ + bool enable; + + if (val == 1) + enable = true; + else if (val == 0) + enable = false; + else + return -EINVAL; + + /* Only do anything if we're changing state */ + if (enable != stf_barrier) + stf_barrier_enable(enable); + + return 0; +} + +static int stf_barrier_get(void *data, u64 *val) +{ + *val = stf_barrier ? 1 : 0; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(fops_stf_barrier, stf_barrier_get, stf_barrier_set, "%llu\n"); + +static __init int stf_barrier_debugfs_init(void) +{ + debugfs_create_file("stf_barrier", 0600, powerpc_debugfs_root, NULL, &fops_stf_barrier); + return 0; +} +device_initcall(stf_barrier_debugfs_init); +#endif /* CONFIG_DEBUG_FS */ diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index b61fb7902018..c16fddbb6ab8 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -133,6 +133,20 @@ SECTIONS RODATA #ifdef CONFIG_PPC64 + . = ALIGN(8); + __stf_entry_barrier_fixup : AT(ADDR(__stf_entry_barrier_fixup) - LOAD_OFFSET) { + __start___stf_entry_barrier_fixup = .; + *(__stf_entry_barrier_fixup) + __stop___stf_entry_barrier_fixup = .; + } + + . = ALIGN(8); + __stf_exit_barrier_fixup : AT(ADDR(__stf_exit_barrier_fixup) - LOAD_OFFSET) { + __start___stf_exit_barrier_fixup = .; + *(__stf_exit_barrier_fixup) + __stop___stf_exit_barrier_fixup = .; + } + . = ALIGN(8); __rfi_flush_fixup : AT(ADDR(__rfi_flush_fixup) - LOAD_OFFSET) { __start___rfi_flush_fixup = .; diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c index d89d54fa6acc..cf1398e3c2e0 100644 --- a/arch/powerpc/lib/feature-fixups.c +++ b/arch/powerpc/lib/feature-fixups.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -117,6 +118,120 @@ void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end) } #ifdef CONFIG_PPC_BOOK3S_64 +void do_stf_entry_barrier_fixups(enum stf_barrier_type types) +{ + unsigned int instrs[3], *dest; + long *start, *end; + int i; + + start = PTRRELOC(&__start___stf_entry_barrier_fixup), + end = PTRRELOC(&__stop___stf_entry_barrier_fixup); + + instrs[0] = 0x60000000; /* nop */ + instrs[1] = 0x60000000; /* nop */ + instrs[2] = 0x60000000; /* nop */ + + i = 0; + if (types & STF_BARRIER_FALLBACK) { + instrs[i++] = 0x7d4802a6; /* mflr r10 */ + instrs[i++] = 0x60000000; /* branch patched below */ + instrs[i++] = 0x7d4803a6; /* mtlr r10 */ + } else if (types & STF_BARRIER_EIEIO) { + instrs[i++] = 0x7e0006ac; /* eieio + bit 6 hint */ + } else if (types & STF_BARRIER_SYNC_ORI) { + instrs[i++] = 0x7c0004ac; /* hwsync */ + instrs[i++] = 0xe94d0000; /* ld r10,0(r13) */ + instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */ + } + + for (i = 0; start < end; start++, i++) { + dest = (void *)start + *start; + + pr_devel("patching dest %lx\n", (unsigned long)dest); + + patch_instruction(dest, instrs[0]); + + if (types & STF_BARRIER_FALLBACK) + patch_branch(dest + 1, (unsigned long)&stf_barrier_fallback, + BRANCH_SET_LINK); + else + patch_instruction(dest + 1, instrs[1]); + + patch_instruction(dest + 2, instrs[2]); + } + + printk(KERN_DEBUG "stf-barrier: patched %d entry locations (%s barrier)\n", i, + (types == STF_BARRIER_NONE) ? "no" : + (types == STF_BARRIER_FALLBACK) ? "fallback" : + (types == STF_BARRIER_EIEIO) ? "eieio" : + (types == (STF_BARRIER_SYNC_ORI)) ? "hwsync" + : "unknown"); +} + +void do_stf_exit_barrier_fixups(enum stf_barrier_type types) +{ + unsigned int instrs[6], *dest; + long *start, *end; + int i; + + start = PTRRELOC(&__start___stf_exit_barrier_fixup), + end = PTRRELOC(&__stop___stf_exit_barrier_fixup); + + instrs[0] = 0x60000000; /* nop */ + instrs[1] = 0x60000000; /* nop */ + instrs[2] = 0x60000000; /* nop */ + instrs[3] = 0x60000000; /* nop */ + instrs[4] = 0x60000000; /* nop */ + instrs[5] = 0x60000000; /* nop */ + + i = 0; + if (types & STF_BARRIER_FALLBACK || types & STF_BARRIER_SYNC_ORI) { + if (cpu_has_feature(CPU_FTR_HVMODE)) { + instrs[i++] = 0x7db14ba6; /* mtspr 0x131, r13 (HSPRG1) */ + instrs[i++] = 0x7db04aa6; /* mfspr r13, 0x130 (HSPRG0) */ + } else { + instrs[i++] = 0x7db243a6; /* mtsprg 2,r13 */ + instrs[i++] = 0x7db142a6; /* mfsprg r13,1 */ + } + instrs[i++] = 0x7c0004ac; /* hwsync */ + instrs[i++] = 0xe9ad0000; /* ld r13,0(r13) */ + instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */ + if (cpu_has_feature(CPU_FTR_HVMODE)) { + instrs[i++] = 0x7db14aa6; /* mfspr r13, 0x131 (HSPRG1) */ + } else { + instrs[i++] = 0x7db242a6; /* mfsprg r13,2 */ + } + } else if (types & STF_BARRIER_EIEIO) { + instrs[i++] = 0x7e0006ac; /* eieio + bit 6 hint */ + } + + for (i = 0; start < end; start++, i++) { + dest = (void *)start + *start; + + pr_devel("patching dest %lx\n", (unsigned long)dest); + + patch_instruction(dest, instrs[0]); + patch_instruction(dest + 1, instrs[1]); + patch_instruction(dest + 2, instrs[2]); + patch_instruction(dest + 3, instrs[3]); + patch_instruction(dest + 4, instrs[4]); + patch_instruction(dest + 5, instrs[5]); + } + printk(KERN_DEBUG "stf-barrier: patched %d exit locations (%s barrier)\n", i, + (types == STF_BARRIER_NONE) ? "no" : + (types == STF_BARRIER_FALLBACK) ? "fallback" : + (types == STF_BARRIER_EIEIO) ? "eieio" : + (types == (STF_BARRIER_SYNC_ORI)) ? "hwsync" + : "unknown"); +} + + +void do_stf_barrier_fixups(enum stf_barrier_type types) +{ + do_stf_entry_barrier_fixups(types); + do_stf_exit_barrier_fixups(types); +} + void do_rfi_flush_fixups(enum l1d_flush_type types) { unsigned int instrs[3], *dest; diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 2c646f5bd144..17203abf38e8 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -130,6 +130,7 @@ static void __init pnv_setup_arch(void) set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT); pnv_setup_rfi_flush(); + setup_stf_barrier(); /* Initialize SMP */ pnv_smp_init(); diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 7349c05032be..91ade7755823 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -545,6 +545,7 @@ static void __init pSeries_setup_arch(void) fwnmi_init(); pseries_setup_rfi_flush(); + setup_stf_barrier(); /* By default, only probe PCI (can be overridden by rtas_pci) */ pci_add_flags(PCI_PROBE_ONLY); -- GitLab From 5d70bd5c98d0e655bde2aae2b5251bdd44df5e71 Mon Sep 17 00:00:00 2001 From: Sarah Newman Date: Wed, 30 May 2018 18:04:05 -0700 Subject: [PATCH 052/604] net/mlx4_en: fix potential use-after-free with dma_unmap_page [ Not relevant upstream, therefore no upstream commit. ] To fix, unmap the page as soon as possible. When swiotlb is in use, calling dma_unmap_page means that the original page mapped with dma_map_page must still be valid, as swiotlb will copy data from its internal cache back to the originally requested DMA location. When GRO is enabled, before this patch all references to the original frag may be put and the page freed before dma_unmap_page in mlx4_en_free_frag is called. It is possible there is a path where the use-after-free occurs even with GRO disabled, but this has not been observed so far. The bug can be trivially detected by doing the following: * Compile the kernel with DEBUG_PAGEALLOC * Run the kernel as a Xen Dom0 * Leave GRO enabled on the interface * Run a 10 second or more test with iperf over the interface. This bug was likely introduced in commit 4cce66cdd14a ("mlx4_en: map entire pages to increase throughput"), first part of u3.6. It was incidentally fixed in commit 34db548bfb95 ("mlx4: add page recycling in receive path"), first part of v4.12. This version applies to the v4.9 series. Signed-off-by: Sarah Newman Tested-by: Sarah Newman Cc: Tariq Toukan Cc: Yishai Hadas Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 32 ++++++++++++++-------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index bcbb80ff86a7..1a92cd719e19 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -142,16 +142,17 @@ static void mlx4_en_free_frag(struct mlx4_en_priv *priv, struct mlx4_en_rx_alloc *frags, int i) { - const struct mlx4_en_frag_info *frag_info = &priv->frag_info[i]; - u32 next_frag_end = frags[i].page_offset + 2 * frag_info->frag_stride; - - - if (next_frag_end > frags[i].page_size) - dma_unmap_page(priv->ddev, frags[i].dma, frags[i].page_size, - frag_info->dma_dir); + if (frags[i].page) { + const struct mlx4_en_frag_info *frag_info = &priv->frag_info[i]; + u32 next_frag_end = frags[i].page_offset + + 2 * frag_info->frag_stride; - if (frags[i].page) + if (next_frag_end > frags[i].page_size) { + dma_unmap_page(priv->ddev, frags[i].dma, + frags[i].page_size, frag_info->dma_dir); + } put_page(frags[i].page); + } } static int mlx4_en_init_allocator(struct mlx4_en_priv *priv, @@ -586,21 +587,28 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv, int length) { struct skb_frag_struct *skb_frags_rx = skb_shinfo(skb)->frags; - struct mlx4_en_frag_info *frag_info; int nr; dma_addr_t dma; /* Collect used fragments while replacing them in the HW descriptors */ for (nr = 0; nr < priv->num_frags; nr++) { - frag_info = &priv->frag_info[nr]; + struct mlx4_en_frag_info *frag_info = &priv->frag_info[nr]; + u32 next_frag_end = frags[nr].page_offset + + 2 * frag_info->frag_stride; + if (length <= frag_info->frag_prefix_size) break; if (unlikely(!frags[nr].page)) goto fail; dma = be64_to_cpu(rx_desc->data[nr].addr); - dma_sync_single_for_cpu(priv->ddev, dma, frag_info->frag_size, - DMA_FROM_DEVICE); + if (next_frag_end > frags[nr].page_size) + dma_unmap_page(priv->ddev, frags[nr].dma, + frags[nr].page_size, frag_info->dma_dir); + else + dma_sync_single_for_cpu(priv->ddev, dma, + frag_info->frag_size, + DMA_FROM_DEVICE); /* Save page reference in skb */ __skb_frag_set_page(&skb_frags_rx[nr], frags[nr].page); -- GitLab From 8978f159e27c820c86003644be9eae4acf5255ee Mon Sep 17 00:00:00 2001 From: Martin Kelly Date: Mon, 26 Mar 2018 14:27:52 -0700 Subject: [PATCH 053/604] iio:kfifo_buf: check for uint overflow commit 3d13de4b027d5f6276c0f9d3a264f518747d83f2 upstream. Currently, the following causes a kernel OOPS in memcpy: echo 1073741825 > buffer/length echo 1 > buffer/enable Note that using 1073741824 instead of 1073741825 causes "write error: Cannot allocate memory" but no OOPS. This is because 1073741824 == 2^30 and 1073741825 == 2^30+1. Since kfifo rounds up to the nearest power of 2, it will actually call kmalloc with roundup_pow_of_two(length) * bytes_per_datum. Using length == 1073741825 and bytes_per_datum == 2, we get: kmalloc(roundup_pow_of_two(1073741825) * 2 or kmalloc(2147483648 * 2) or kmalloc(4294967296) or kmalloc(UINT_MAX + 1) so this overflows to 0, causing kmalloc to return ZERO_SIZE_PTR and subsequent memcpy to fail once the device is enabled. Fix this by checking for overflow prior to allocating a kfifo. With this check added, the above code returns -EINVAL when enabling the buffer, rather than causing an OOPS. Signed-off-by: Martin Kelly cc: Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/buffer/kfifo_buf.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/iio/buffer/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c index c5b999f0c519..7ef9b13262a8 100644 --- a/drivers/iio/buffer/kfifo_buf.c +++ b/drivers/iio/buffer/kfifo_buf.c @@ -24,6 +24,13 @@ static inline int __iio_allocate_kfifo(struct iio_kfifo *buf, if ((length == 0) || (bytes_per_datum == 0)) return -EINVAL; + /* + * Make sure we don't overflow an unsigned int after kfifo rounds up to + * the next power of 2. + */ + if (roundup_pow_of_two(length) > UINT_MAX / bytes_per_datum) + return -EINVAL; + return __kfifo_alloc((struct __kfifo *)&buf->kf, length, bytes_per_datum, GFP_KERNEL); } -- GitLab From 5826fc575b935a48c89be6a3fdc7a2f03aa76218 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Wed, 16 May 2018 16:39:58 +0100 Subject: [PATCH 054/604] MIPS: ptrace: Fix PTRACE_PEEKUSR requests for 64-bit FGRs commit c7e814628df65f424fe197dde73bfc67e4a244d7 upstream. Use 64-bit accesses for 64-bit floating-point general registers with PTRACE_PEEKUSR, removing the truncation of their upper halves in the FR=1 mode, caused by commit bbd426f542cb ("MIPS: Simplify FP context access"), which inadvertently switched them to using 32-bit accesses. The PTRACE_POKEUSR side is fine as it's never been broken and continues using 64-bit accesses. Fixes: bbd426f542cb ("MIPS: Simplify FP context access") Signed-off-by: Maciej W. Rozycki Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: # 3.15+ Patchwork: https://patchwork.linux-mips.org/patch/19334/ Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/ptrace.c | 2 +- arch/mips/kernel/ptrace32.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 8f7bf74d1c0b..4f64913b4b4c 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -838,7 +838,7 @@ long arch_ptrace(struct task_struct *child, long request, break; } #endif - tmp = get_fpr32(&fregs[addr - FPR_BASE], 0); + tmp = get_fpr64(&fregs[addr - FPR_BASE], 0); break; case PC: tmp = regs->cp0_epc; diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index bc9afbabbe14..b1e945738138 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -107,7 +107,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, addr & 1); break; } - tmp = get_fpr32(&fregs[addr - FPR_BASE], 0); + tmp = get_fpr64(&fregs[addr - FPR_BASE], 0); break; case PC: tmp = regs->cp0_epc; -- GitLab From ef1b8fbed6c717a3fa80d878bb05dec1efd94d08 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 15 May 2018 23:04:44 +0100 Subject: [PATCH 055/604] MIPS: prctl: Disallow FRE without FR with PR_SET_FP_MODE requests commit 28e4213dd331e944e7fca1954a946829162ed9d4 upstream. Having PR_FP_MODE_FRE (i.e. Config5.FRE) set without PR_FP_MODE_FR (i.e. Status.FR) is not supported as the lone purpose of Config5.FRE is to emulate Status.FR=0 handling on FPU hardware that has Status.FR=1 hardwired[1][2]. Also we do not handle this case elsewhere, and assume throughout our code that TIF_HYBRID_FPREGS and TIF_32BIT_FPREGS cannot be set both at once for a task, leading to inconsistent behaviour if this does happen. Return unsuccessfully then from prctl(2) PR_SET_FP_MODE calls requesting PR_FP_MODE_FRE to be set with PR_FP_MODE_FR clear. This corresponds to modes allowed by `mips_set_personality_fp'. References: [1] "MIPS Architecture For Programmers, Vol. III: MIPS32 / microMIPS32 Privileged Resource Architecture", Imagination Technologies, Document Number: MD00090, Revision 6.02, July 10, 2015, Table 9.69 "Config5 Register Field Descriptions", p. 262 [2] "MIPS Architecture For Programmers, Volume III: MIPS64 / microMIPS64 Privileged Resource Architecture", Imagination Technologies, Document Number: MD00091, Revision 6.03, December 22, 2015, Table 9.72 "Config5 Register Field Descriptions", p. 288 Fixes: 9791554b45a2 ("MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS") Signed-off-by: Maciej W. Rozycki Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: # 4.0+ Patchwork: https://patchwork.linux-mips.org/patch/19327/ Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/process.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 6e716a5f1173..ebb575c4231b 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -699,6 +699,10 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value) if (value & ~known_bits) return -EOPNOTSUPP; + /* Setting FRE without FR is not supported. */ + if ((value & (PR_FP_MODE_FR | PR_FP_MODE_FRE)) == PR_FP_MODE_FRE) + return -EOPNOTSUPP; + /* Avoid inadvertently triggering emulation */ if ((value & PR_FP_MODE_FR) && raw_cpu_has_fpu && !(raw_current_cpu_data.fpu_id & MIPS_FPIR_F64)) -- GitLab From 3875d1b83b19c75e2db2c25ef3dcd78e3d2c1d5f Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 21 May 2018 11:17:29 -0700 Subject: [PATCH 056/604] scsi: scsi_transport_srp: Fix shost to rport translation commit c9ddf73476ff4fffb7a87bd5107a0705bf2cf64b upstream. Since an SRP remote port is attached as a child to shost->shost_gendev and as the only child, the translation from the shost pointer into an rport pointer must happen by looking up the shost child that is an rport. This patch fixes the following KASAN complaint: BUG: KASAN: slab-out-of-bounds in srp_timed_out+0x57/0x110 [scsi_transport_srp] Read of size 4 at addr ffff880035d3fcc0 by task kworker/1:0H/19 CPU: 1 PID: 19 Comm: kworker/1:0H Not tainted 4.16.0-rc3-dbg+ #1 Workqueue: kblockd blk_mq_timeout_work Call Trace: dump_stack+0x85/0xc7 print_address_description+0x65/0x270 kasan_report+0x231/0x350 srp_timed_out+0x57/0x110 [scsi_transport_srp] scsi_times_out+0xc7/0x3f0 [scsi_mod] blk_mq_terminate_expired+0xc2/0x140 bt_iter+0xbc/0xd0 blk_mq_queue_tag_busy_iter+0x1c7/0x350 blk_mq_timeout_work+0x325/0x3f0 process_one_work+0x441/0xa50 worker_thread+0x76/0x6c0 kthread+0x1b2/0x1d0 ret_from_fork+0x24/0x30 Fixes: e68ca75200fe ("scsi_transport_srp: Reduce failover time") Signed-off-by: Bart Van Assche Cc: Hannes Reinecke Cc: Johannes Thumshirn Cc: Jason Gunthorpe Cc: Doug Ledford Cc: Laurence Oberman Cc: stable@vger.kernel.org Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_transport_srp.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c index e3cd3ece4412..c3d1891d2d3f 100644 --- a/drivers/scsi/scsi_transport_srp.c +++ b/drivers/scsi/scsi_transport_srp.c @@ -52,6 +52,8 @@ struct srp_internal { struct transport_container rport_attr_cont; }; +static int scsi_is_srp_rport(const struct device *dev); + #define to_srp_internal(tmpl) container_of(tmpl, struct srp_internal, t) #define dev_to_rport(d) container_of(d, struct srp_rport, dev) @@ -61,9 +63,24 @@ static inline struct Scsi_Host *rport_to_shost(struct srp_rport *r) return dev_to_shost(r->dev.parent); } +static int find_child_rport(struct device *dev, void *data) +{ + struct device **child = data; + + if (scsi_is_srp_rport(dev)) { + WARN_ON_ONCE(*child); + *child = dev; + } + return 0; +} + static inline struct srp_rport *shost_to_rport(struct Scsi_Host *shost) { - return transport_class_to_srp_rport(&shost->shost_gendev); + struct device *child = NULL; + + WARN_ON_ONCE(device_for_each_child(&shost->shost_gendev, &child, + find_child_rport) < 0); + return child ? dev_to_rport(child) : NULL; } /** @@ -637,7 +654,8 @@ static enum blk_eh_timer_return srp_timed_out(struct scsi_cmnd *scmd) struct srp_rport *rport = shost_to_rport(shost); pr_debug("timeout for sdev %s\n", dev_name(&sdev->sdev_gendev)); - return rport->fast_io_fail_tmo < 0 && rport->dev_loss_tmo < 0 && + return rport && rport->fast_io_fail_tmo < 0 && + rport->dev_loss_tmo < 0 && i->f->reset_timer_if_blocked && scsi_device_blocked(sdev) ? BLK_EH_RESET_TIMER : BLK_EH_NOT_HANDLED; } -- GitLab From 994347096a53d69ce5c9791627a9b5334d77c477 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Thu, 24 May 2018 11:27:26 +0300 Subject: [PATCH 057/604] stm class: Use vmalloc for the master map commit b5e2ced9bf81393034072dd4d372f6b430bc1f0a upstream. Fengguang is running into a warning from the buddy allocator: > swapper/0: page allocation failure: order:9, mode:0x14040c0(GFP_KERNEL|__GFP_COMP), nodemask=(null) > CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.17.0-rc1 #262 > Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014 > Call Trace: ... > __kmalloc+0x14b/0x180: ____cache_alloc at mm/slab.c:3127 > stm_register_device+0xf3/0x5c0: stm_register_device at drivers/hwtracing/stm/core.c:695 ... Which is basically a result of the stm class trying to allocate ~512kB for the dummy_stm with its default parameters. There's no reason, however, for it not to be vmalloc()ed instead, which is what this patch does. Reported-by: Fengguang Wu Signed-off-by: Alexander Shishkin CC: stable@vger.kernel.org # v4.4+ Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/stm/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c index 877a0ed76abf..b956305c1730 100644 --- a/drivers/hwtracing/stm/core.c +++ b/drivers/hwtracing/stm/core.c @@ -682,7 +682,7 @@ static void stm_device_release(struct device *dev) { struct stm_device *stm = to_stm_device(dev); - kfree(stm); + vfree(stm); } int stm_register_device(struct device *parent, struct stm_data *stm_data, @@ -699,7 +699,7 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data, return -EINVAL; nmasters = stm_data->sw_end - stm_data->sw_start + 1; - stm = kzalloc(sizeof(*stm) + nmasters * sizeof(void *), GFP_KERNEL); + stm = vzalloc(sizeof(*stm) + nmasters * sizeof(void *)); if (!stm) return -ENOMEM; @@ -752,7 +752,7 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data, /* matches device_initialize() above */ put_device(&stm->dev); err_free: - kfree(stm); + vfree(stm); return err; } -- GitLab From 6ba7b04c063c457691e9a30d4316035a1518b287 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 26 May 2018 08:49:24 +0200 Subject: [PATCH 058/604] hwtracing: stm: fix build error on some arches commit 806e30873f0e74d9d41b0ef761bd4d3e55c7d510 upstream. Commit b5e2ced9bf81 ("stm class: Use vmalloc for the master map") caused a build error on some arches as vmalloc.h was not explicitly included. Fix that by adding it to the list of includes. Fixes: b5e2ced9bf81 ("stm class: Use vmalloc for the master map") Reported-by: kbuild test robot Cc: Alexander Shishkin Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/stm/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c index b956305c1730..c38645106783 100644 --- a/drivers/hwtracing/stm/core.c +++ b/drivers/hwtracing/stm/core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "stm.h" #include -- GitLab From 83c0c8b7ceefeb79b4906c3d332e774f465b760c Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Sun, 27 May 2018 14:49:16 +0300 Subject: [PATCH 059/604] IB/core: Fix error code for invalid GID entry commit a840c93ca7582bb6c88df2345a33f979b7a67874 upstream. When a GID entry is invalid EAGAIN is returned. This is an incorrect error code, there is nothing that will make this GID entry valid again in bounded time. Some user space tools fail incorrectly if EAGAIN is returned here, and this represents a small ABI change from earlier kernels. The first patch in the Fixes list makes entries that were valid before to become invalid, allowing this code to trigger, while the second patch in the Fixes list introduced the wrong EAGAIN. Therefore revert the return result to EINVAL which matches the historical expectations of the ibv_query_gid_type() API of the libibverbs user space library. Cc: Fixes: 598ff6bae689 ("IB/core: Refactor GID modify code for RoCE") Fixes: 03db3a2d81e6 ("IB/core: Add RoCE GID table management") Reviewed-by: Daniel Jurgens Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index ae04826e82fc..a32dd851e712 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -437,7 +437,7 @@ static int __ib_cache_gid_get(struct ib_device *ib_dev, u8 port, int index, return -EINVAL; if (table->data_vec[index].props & GID_TABLE_ENTRY_INVALID) - return -EAGAIN; + return -EINVAL; memcpy(gid, &table->data_vec[index].gid, sizeof(*gid)); if (attr) { -- GitLab From 5ee69e647a86baf578a6571b9ba5a1869920f273 Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan Date: Fri, 11 May 2018 12:51:42 -0700 Subject: [PATCH 060/604] drm/psr: Fix missed entry in PSR setup time table. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit bdcc02cf1bb508fc700df7662f55058f651f2621 upstream. Entry corresponding to 220 us setup time was missing. I am not aware of any specific bug this fixes, but this could potentially result in enabling PSR on a panel with a higher setup time requirement than supported by the hardware. I verified the value is present in eDP spec versions 1.3, 1.4 and 1.4a. Fixes: 6608804b3d7f ("drm/dp: Add drm_dp_psr_setup_time()") Cc: stable@vger.kernel.org Cc: Ville Syrjälä Cc: Jose Roberto de Souza Cc: dri-devel@lists.freedesktop.org Reviewed-by: José Roberto de Souza Reviewed-by: Tarun Vyas Signed-off-by: Dhinakaran Pandiyan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20180511195145.3829-3-dhinakaran.pandiyan@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_dp_helper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 3e6fe82c6d64..4d49fa0911c6 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -1065,6 +1065,7 @@ int drm_dp_psr_setup_time(const u8 psr_cap[EDP_PSR_RECEIVER_CAP_SIZE]) static const u16 psr_setup_time_us[] = { PSR_SETUP_TIME(330), PSR_SETUP_TIME(275), + PSR_SETUP_TIME(220), PSR_SETUP_TIME(165), PSR_SETUP_TIME(110), PSR_SETUP_TIME(55), -- GitLab From eab90eda9d707b5c0e8648e1b4c25364538d698a Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Fri, 9 Mar 2018 23:22:04 +0100 Subject: [PATCH 061/604] drm/i915: Disable LVDS on Radiant P845 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b3fb22733ae61050f8d10a1d6a8af176c5c5db1a upstream. Radiant P845 does not have LVDS, only VGA. Cc: stable@vger.kernel.org Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105468 Signed-off-by: Ondrej Zary Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180309222204.4771-1-linux@rainbow-software.org (cherry picked from commit 7f7105f99b75aca4f8c2a748ed6b82c7f8be3293) Signed-off-by: Joonas Lahtinen Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_lvds.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 3517c0ed984a..479d64184da5 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -864,6 +864,14 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "D525MW"), }, }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "Radiant P845", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Radiant Systems Inc"), + DMI_MATCH(DMI_PRODUCT_NAME, "P845"), + }, + }, { } /* terminating entry */ }; -- GitLab From d47c9f5c4e3ec194ec98d48ed59979e851cb1daa Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 1 Jun 2017 09:42:46 -0700 Subject: [PATCH 062/604] sparc64: Fix build warnings with gcc 7. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 0fde7ad71ee371ede73b3f326e58f9e8d102feb6 upstream. arch/sparc/kernel/ds.c: In function ‘register_services’: arch/sparc/kernel/ds.c:912:3: error: ‘strcpy’: writing at least 1 byte into a region of size 0 overflows the destination Reported-by: Anatoly Pugachev Signed-off-by: David S. Miller Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- arch/sparc/kernel/ds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c index f87a55d77094..9b3f2e212b37 100644 --- a/arch/sparc/kernel/ds.c +++ b/arch/sparc/kernel/ds.c @@ -908,7 +908,7 @@ static int register_services(struct ds_info *dp) pbuf.req.handle = cp->handle; pbuf.req.major = 1; pbuf.req.minor = 0; - strcpy(pbuf.req.svc_id, cp->service_id); + strcpy(pbuf.id_buf, cp->service_id); err = __ds_send(lp, &pbuf, msg_len); if (err > 0) -- GitLab From f01d1b571458ebc8ef6311eef27c8a513038975b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 23 May 2018 22:53:22 -0400 Subject: [PATCH 063/604] fix io_destroy()/aio_complete() race commit 4faa99965e027cc057c5145ce45fa772caa04e8d upstream. If io_destroy() gets to cancelling everything that can be cancelled and gets to kiocb_cancel() calling the function driver has left in ->ki_cancel, it becomes vulnerable to a race with IO completion. At that point req is already taken off the list and aio_complete() does *NOT* spin until we (in free_ioctx_users()) releases ->ctx_lock. As the result, it proceeds to kiocb_free(), freing req just it gets passed to ->ki_cancel(). Fix is simple - remove from the list after the call of kiocb_cancel(). All instances of ->ki_cancel() already have to cope with the being called with iocb still on list - that's what happens in io_cancel(2). Cc: stable@kernel.org Fixes: 0460fef2a921 "aio: use cancellation list lazily" Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/aio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/aio.c b/fs/aio.c index 42d8c09311d1..b1170a7affe2 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -636,9 +636,8 @@ static void free_ioctx_users(struct percpu_ref *ref) while (!list_empty(&ctx->active_reqs)) { req = list_first_entry(&ctx->active_reqs, struct aio_kiocb, ki_list); - - list_del_init(&req->ki_list); kiocb_cancel(req); + list_del_init(&req->ki_list); } spin_unlock_irq(&ctx->ctx_lock); -- GitLab From 93960f9d447467b9e6d9a8ee1d6ca7b5b6eb25b6 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Fri, 1 Jun 2018 16:50:50 -0700 Subject: [PATCH 064/604] mm: fix the NULL mapping case in __isolate_lru_page() commit 145e1a71e090575c74969e3daa8136d1e5b99fc8 upstream. George Boole would have noticed a slight error in 4.16 commit 69d763fc6d3a ("mm: pin address_space before dereferencing it while isolating an LRU page"). Fix it, to match both the comment above it, and the original behaviour. Although anonymous pages are not marked PageDirty at first, we have an old habit of calling SetPageDirty when a page is removed from swap cache: so there's a category of ex-swap pages that are easily migratable, but were inadvertently excluded from compaction's async migration in 4.16. Link: http://lkml.kernel.org/r/alpine.LSU.2.11.1805302014001.12558@eggly.anvils Fixes: 69d763fc6d3a ("mm: pin address_space before dereferencing it while isolating an LRU page") Signed-off-by: Hugh Dickins Acked-by: Minchan Kim Acked-by: Mel Gorman Reported-by: Ivan Kalvachev Cc: "Huang, Ying" Cc: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/vmscan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 2d4b6478237b..f03ca5ab86b1 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1393,7 +1393,7 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode) return ret; mapping = page_mapping(page); - migrate_dirty = mapping && mapping->a_ops->migratepage; + migrate_dirty = !mapping || mapping->a_ops->migratepage; unlock_page(page); if (!migrate_dirty) return ret; -- GitLab From 1724b70c4dfef1f38d67b9e05016f6a84086a31f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 15 Aug 2017 21:32:19 -0700 Subject: [PATCH 065/604] sparc64: Don't clibber fixed registers in __multi4. commit 79db795833bf5c3e798bcd7a5aeeee3fb0505927 upstream. %g4 and %g5 are fixed registers used by the kernel for the thread pointer and the per-cpu offset. Use %o4 and %g7 instead. Diagnosis by Anthony Yznaga. Fixes: 1b4af13ff2cc ("sparc64: Add __multi3 for gcc 7.x and later.") Reported-by: Anatoly Pugachev Tested-by: Anatoly Pugachev Signed-off-by: David S. Miller Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- arch/sparc/lib/multi3.S | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/sparc/lib/multi3.S b/arch/sparc/lib/multi3.S index d6b6c97fe3c7..703127aaf4a5 100644 --- a/arch/sparc/lib/multi3.S +++ b/arch/sparc/lib/multi3.S @@ -5,26 +5,26 @@ .align 4 ENTRY(__multi3) /* %o0 = u, %o1 = v */ mov %o1, %g1 - srl %o3, 0, %g4 - mulx %g4, %g1, %o1 + srl %o3, 0, %o4 + mulx %o4, %g1, %o1 srlx %g1, 0x20, %g3 - mulx %g3, %g4, %g5 - sllx %g5, 0x20, %o5 - srl %g1, 0, %g4 + mulx %g3, %o4, %g7 + sllx %g7, 0x20, %o5 + srl %g1, 0, %o4 sub %o1, %o5, %o5 srlx %o5, 0x20, %o5 - addcc %g5, %o5, %g5 + addcc %g7, %o5, %g7 srlx %o3, 0x20, %o5 - mulx %g4, %o5, %g4 + mulx %o4, %o5, %o4 mulx %g3, %o5, %o5 sethi %hi(0x80000000), %g3 - addcc %g5, %g4, %g5 - srlx %g5, 0x20, %g5 + addcc %g7, %o4, %g7 + srlx %g7, 0x20, %g7 add %g3, %g3, %g3 movcc %xcc, %g0, %g3 - addcc %o5, %g5, %o5 - sllx %g4, 0x20, %g4 - add %o1, %g4, %o1 + addcc %o5, %g7, %o5 + sllx %o4, 0x20, %o4 + add %o1, %o4, %o1 add %o5, %g3, %g2 mulx %g1, %o2, %g1 add %g1, %g2, %g1 -- GitLab From 73172520675a093c01a95e02fcc4e00b4170065a Mon Sep 17 00:00:00 2001 From: Aleksey Makarov Date: Tue, 4 Oct 2016 10:15:32 +0300 Subject: [PATCH 066/604] serial: pl011: add console matching function commit 10879ae5f12e9cab3c4e8e9504c1aaa8a033bde7 upstream. This patch adds function pl011_console_match() that implements method match of struct console. It allows to match consoles against data specified in a string, for example taken from command line or compiled by ACPI SPCR table handler. This patch was merged to tty-next but then reverted because of conflict with commit 46e36683f433 ("serial: earlycon: Extend earlycon command line option to support 64-bit addresses") Now it is fixed. Signed-off-by: Aleksey Makarov Reviewed-by: Peter Hurley Acked-by: Russell King Tested-by: Christopher Covington Signed-off-by: Ard Biesheuvel Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 55 +++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index b42d7f1c9089..6b1863293fe1 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2320,12 +2320,67 @@ static int __init pl011_console_setup(struct console *co, char *options) return uart_set_options(&uap->port, co, baud, parity, bits, flow); } +/** + * pl011_console_match - non-standard console matching + * @co: registering console + * @name: name from console command line + * @idx: index from console command line + * @options: ptr to option string from console command line + * + * Only attempts to match console command lines of the form: + * console=pl011,mmio|mmio32,[,] + * console=pl011,0x[,] + * This form is used to register an initial earlycon boot console and + * replace it with the amba_console at pl011 driver init. + * + * Performs console setup for a match (as required by interface) + * If no are specified, then assume the h/w is already setup. + * + * Returns 0 if console matches; otherwise non-zero to use default matching + */ +static int __init pl011_console_match(struct console *co, char *name, int idx, + char *options) +{ + unsigned char iotype; + resource_size_t addr; + int i; + + if (strcmp(name, "pl011") != 0) + return -ENODEV; + + if (uart_parse_earlycon(options, &iotype, &addr, &options)) + return -ENODEV; + + if (iotype != UPIO_MEM && iotype != UPIO_MEM32) + return -ENODEV; + + /* try to match the port specified on the command line */ + for (i = 0; i < ARRAY_SIZE(amba_ports); i++) { + struct uart_port *port; + + if (!amba_ports[i]) + continue; + + port = &amba_ports[i]->port; + + if (port->mapbase != addr) + continue; + + co->index = i; + port->cons = co; + return pl011_console_setup(co, options); + } + + return -ENODEV; +} + static struct uart_driver amba_reg; static struct console amba_console = { .name = "ttyAMA", .write = pl011_console_write, .device = uart_console_device, .setup = pl011_console_setup, + .match = pl011_console_match, .flags = CON_PRINTBUFFER, .index = -1, .data = &amba_reg, -- GitLab From 3c3d05fc6e6653bdf9f7fb3fb6922b199c7ba3ec Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 6 Jun 2018 16:44:39 +0200 Subject: [PATCH 067/604] Linux 4.9.107 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 48d87e3a36c1..ac30e448e0a5 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 106 +SUBLEVEL = 107 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From c964a2ba929aaf590b012405d953a042c8095b14 Mon Sep 17 00:00:00 2001 From: Patrick Bellasi Date: Mon, 12 Feb 2018 15:56:18 +0000 Subject: [PATCH 068/604] ANDROID: sched/fair: cosmetics Change-Id: Ibbefdf1cdb4d72c7075c7b3edf6789630475a8e2 Signed-off-by: Patrick Bellasi --- kernel/sched/fair.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 52ad822d9c60..dd4f623c12ba 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6102,13 +6102,14 @@ schedtune_margin(unsigned long signal, long boost) if (boost >= 0) { margin = SCHED_CAPACITY_SCALE - signal; margin *= boost; - } else + } else { margin = -signal * boost; + } margin = reciprocal_divide(margin, schedtune_spc_rdiv); - if (boost < 0) margin *= -1; + return margin; } -- GitLab From ca17b83d9c2ba68d56155214b99b15481c434668 Mon Sep 17 00:00:00 2001 From: Patrick Bellasi Date: Mon, 12 Feb 2018 15:56:47 +0000 Subject: [PATCH 069/604] ANDROID: sched/tune: remove unused variable This value was added in: e71c4255169d ANDROID: sched/tune: Add support for negative boost values and it's likely coming from a conflict resolution or a merge of some previous patches used to track negative boost values. Change-Id: I3b63e99db9232eb6117a561aa61c527986ade8e4 Signed-off-by: Patrick Bellasi --- kernel/sched/tune.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c index d20f758522b8..4ad5a66da181 100644 --- a/kernel/sched/tune.c +++ b/kernel/sched/tune.c @@ -224,7 +224,6 @@ static struct schedtune *allocated_group[BOOSTGROUPS_COUNT] = { */ struct boost_groups { /* Maximum boost value for all RUNNABLE tasks on a CPU */ - bool idle; int boost_max; struct { /* The boost for tasks on that boost group */ -- GitLab From eafebcabecd08e7a7e71481bcda6d6f788622495 Mon Sep 17 00:00:00 2001 From: Patrick Bellasi Date: Mon, 12 Feb 2018 16:04:35 +0000 Subject: [PATCH 070/604] ANDROID: sched/tune: cleanup schedtune_boostgroup_{init,release} This update the definition of these two methods to make more clear their role. In this refactored version, the slow path entry functions: schedtune_css_alloc() schedtune_css_free() are in charge just to allocate and release the memory used to track schedtune boost groups. These two functions rely respectively on: schedtune_boostgroup_init() schedtune_boostgroup_release() for everything related to setting up data structures and properly initializing them. Change-Id: I9336102b5c6a6b5726fd466e99b7d6b28d38f455 Signed-off-by: Patrick Bellasi --- kernel/sched/tune.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c index 4ad5a66da181..62f30858e7b9 100644 --- a/kernel/sched/tune.c +++ b/kernel/sched/tune.c @@ -632,23 +632,22 @@ static struct cftype files[] = { { } /* terminate */ }; -static int -schedtune_boostgroup_init(struct schedtune *st) +static void +schedtune_boostgroup_init(struct schedtune *st, int idx) { struct boost_groups *bg; int cpu; - /* Keep track of allocated boost groups */ - allocated_group[st->idx] = st; - - /* Initialize the per CPU boost groups */ + /* Initialize per CPUs boost group support */ for_each_possible_cpu(cpu) { bg = &per_cpu(cpu_boost_groups, cpu); - bg->group[st->idx].boost = 0; - bg->group[st->idx].tasks = 0; + bg->group[idx].boost = 0; + bg->group[idx].tasks = 0; } - return 0; + /* Keep track of allocated boost groups */ + allocated_group[idx] = st; + st->idx = idx; } static struct cgroup_subsys_state * @@ -681,14 +680,10 @@ schedtune_css_alloc(struct cgroup_subsys_state *parent_css) goto out; /* Initialize per CPUs boost group support */ - st->idx = idx; - if (schedtune_boostgroup_init(st)) - goto release; + schedtune_boostgroup_init(st, idx); return &st->css; -release: - kfree(st); out: return ERR_PTR(-ENOMEM); } @@ -696,8 +691,14 @@ schedtune_css_alloc(struct cgroup_subsys_state *parent_css) static void schedtune_boostgroup_release(struct schedtune *st) { - /* Reset this boost group */ - schedtune_boostgroup_update(st->idx, 0); + struct boost_groups *bg; + int cpu; + + /* Reset per CPUs boost group support */ + for_each_possible_cpu(cpu) { + bg = &per_cpu(cpu_boost_groups, cpu); + bg->group[st->idx].boost = 0; + } /* Keep track of allocated boost groups */ allocated_group[st->idx] = NULL; @@ -708,6 +709,7 @@ schedtune_css_free(struct cgroup_subsys_state *css) { struct schedtune *st = css_st(css); + /* Release per CPUs boost group support */ schedtune_boostgroup_release(st); kfree(st); } -- GitLab From 641070d2a1c595dab539efbffb414b3b62f3889c Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Thu, 7 Jun 2018 11:36:04 -0700 Subject: [PATCH 071/604] ARM: dts: msm: Modify qdss region for sdm670/sdm845 FW supports only pages in units of 1MB hence making qdss region size to be 1MB. Change-Id: I5f616cbc84d055cc00809f75fd5a02bfe328c480 Signed-off-by: Karthik Anantha Ram --- arch/arm64/boot/dts/qcom/sdm670-camera.dtsi | 8 ++++---- arch/arm64/boot/dts/qcom/sdm845-camera.dtsi | 8 ++++---- arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi index f999cd8826fa..0ba877d0ee69 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi @@ -338,17 +338,17 @@ iova-mem-region-io { /* IO region is approximately 3 GB */ iova-region-name = "io"; - iova-region-start = <0xd911000>; - iova-region-len = <0xd26ef000>; + iova-region-start = <0xda00000>; + iova-region-len = <0xd2500000>; iova-region-id = <0x3>; status = "ok"; }; iova-mem-qdss-region { - /* qdss region is approximately 64K */ + /* qdss region is approximately 1MB */ iova-region-name = "qdss"; iova-region-start = <0xd900000>; - iova-region-len = <0x10000>; + iova-region-len = <0x100000>; iova-region-id = <0x5>; qdss-phy-addr = <0x16790000>; status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi index 2e2de74999af..4ede0bbeee6b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi @@ -311,17 +311,17 @@ iova-mem-region-io { /* IO region is approximately 3 GB */ iova-region-name = "io"; - iova-region-start = <0xd911000>; - iova-region-len = <0xd26ef000>; + iova-region-start = <0xda00000>; + iova-region-len = <0xd2500000>; iova-region-id = <0x3>; status = "ok"; }; iova-mem-qdss-region { - /* qdss region is approximately 64K */ + /* qdss region is approximately 1MB */ iova-region-name = "qdss"; iova-region-start = <0xd900000>; - iova-region-len = <0x10000>; + iova-region-len = <0x100000>; iova-region-id = <0x5>; qdss-phy-addr = <0x16790000>; status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi index 97cb9814b65d..c9669d958c2c 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi @@ -248,17 +248,17 @@ iova-mem-region-io { /* IO region is approximately 3 GB */ iova-region-name = "io"; - iova-region-start = <0xd911000>; - iova-region-len = <0xd26ef000>; + iova-region-start = <0xda00000>; + iova-region-len = <0xd2500000>; iova-region-id = <0x3>; status = "ok"; }; iova-mem-qdss-region { - /* qdss region is approximately 64K */ + /* qdss region is approximately 1MB */ iova-region-name = "qdss"; iova-region-start = <0xd900000>; - iova-region-len = <0x10000>; + iova-region-len = <0x100000>; iova-region-id = <0x5>; qdss-phy-addr = <0x16790000>; status = "ok"; -- GitLab From 663eb95118248bc5a09489b3807998004c9a2552 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Wed, 6 Jun 2018 15:22:51 -0700 Subject: [PATCH 072/604] msm: camera: sensor: Assign power settings pointer to null Power settings pointers are assigned null after being freed. This will make sure pointers do not point to some junk memory. Change-Id: I85df098fc28f0afe9f765ddf7e22cc082e437753 Signed-off-by: Vishalsingh Hajeri --- .../cam_sensor_module/cam_actuator/cam_actuator_core.c | 1 + .../cam_sensor_module/cam_actuator/cam_actuator_dev.c | 6 +++++- .../msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c | 1 + .../msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c | 6 +++++- 4 files changed, 12 insertions(+), 2 deletions(-) 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 a34d70c50a94..da8ff21cd06f 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 @@ -53,6 +53,7 @@ int32_t cam_actuator_construct_default_power_setting( free_power_settings: kfree(power_info->power_setting); + power_info->power_setting = NULL; return rc; } 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 96fdfeb1b4ba..733c9e870637 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 @@ -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 @@ -252,6 +252,8 @@ static int32_t cam_actuator_platform_remove(struct platform_device *pdev) a_ctrl->io_master_info.cci_client = NULL; kfree(power_info->power_setting); kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; kfree(a_ctrl->soc_info.soc_private); kfree(a_ctrl->i2c_data.per_frame); a_ctrl->i2c_data.per_frame = NULL; @@ -284,6 +286,8 @@ static int32_t cam_actuator_driver_i2c_remove(struct i2c_client *client) kfree(power_info->power_setting); kfree(power_info->power_down_setting); kfree(a_ctrl->soc_info.soc_private); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; a_ctrl->soc_info.soc_private = NULL; kfree(a_ctrl); return rc; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c index dfcb9fcba4b7..6f77e0ecb93e 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c @@ -55,6 +55,7 @@ int32_t cam_ois_construct_default_power_setting( free_power_settings: kfree(power_info->power_setting); + power_info->power_setting = NULL; return rc; } diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c index d742acf7813d..5d16a4e54d04 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.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 @@ -240,6 +240,8 @@ static int cam_ois_i2c_driver_remove(struct i2c_client *client) kfree(power_info->power_setting); kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; kfree(o_ctrl->soc_info.soc_private); kfree(o_ctrl); @@ -341,6 +343,8 @@ static int cam_ois_platform_driver_remove(struct platform_device *pdev) kfree(power_info->power_setting); kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; kfree(o_ctrl->soc_info.soc_private); kfree(o_ctrl->io_master_info.cci_client); kfree(o_ctrl); -- GitLab From 699626fecb85720fbb8cb0998c12c559e04e1f39 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Thu, 7 Jun 2018 16:23:14 -0700 Subject: [PATCH 073/604] msm: camera: sensor: Unlock the mutex in case of error Unlock the sensor mutext before returning from function. Change-Id: I749df402939a2483c8fb5f21fcb20f2c47ad61f0 Signed-off-by: Vishalsingh Hajeri --- .../msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c index 2133932dde57..714a3604969a 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -599,7 +599,8 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, } else { CAM_ERR(CAM_SENSOR, "Invalid Command Type: %d", cmd->handle_type); - return -EINVAL; + rc = -EINVAL; + goto release_mutex; } pu = power_info->power_setting; -- GitLab From db2c520bb56b98be3209d0fd7fe9fa2e7a25a6b5 Mon Sep 17 00:00:00 2001 From: Patrick Bellasi Date: Mon, 12 Feb 2018 16:09:28 +0000 Subject: [PATCH 074/604] ANDROID: sched/tune: fix boost_group spin_lock re-initialization In: c5616f2f874 ANDROID: sched/tune: Initialize raw_spin_lock in boosted_groups a spin_lock is initialized on each CPU every time a boost_group is activated (i.e. a cgroup created). However, those spin_lock are already initialized at boot time by schedtune_init_cgroups() which also set schedtune_initialized to true thus enabling the tasks accounting done by schedtune_{en,de}queue_task(). This means that an already initialize and used spin_lock is wrongly re-initialized thus potentially leading to a: BUG: spinlock already unlocked on CPU in the (unlikely in AOSP) case we have a race between schedtune cgroups creation and tasks enqueue/dequeue. This probably happened because the fix provided by c5616f2f874 was just the wrong cure for a different issues: the missing one-time initialization of the per-CPU spinlocks in schedtune_init_cgroups(). All these fixes happened on v4.4 and have been forward ported to the current v4.9 base. Let's better fix this by: - removing the not necessary spinlock re-initialization in: schedtune_boostgroup_init() - add a new "valid" flag to better flag which boost_groups are currently used to track a valid cgroup. This patch adds also a better documentation of the used data structures and the locking strategy in use to synchronize fast and slow paths. Change-Id: I3c2a256693b12b317373bbc032ed46e620f79ee8 Signed-off-by: Patrick Bellasi Reported-by: Stanley Shih [ The first of the two fixes listed above has been already merged by: commit f6bec4e8c771 ("Revert "ANDROID: sched/tune: Initialize raw_spin_lock in boosted_groups") which, in conjunction with: commit 751e50939134 ("ANDROID: sched: tune: Fix lacking spinlock initialization") provides the correct initialization of the boostgroups spinlocks. Let's keep the changelog as it is to better keep track of the original intended fix as well as to better document the required locking strategy. ] Signed-off-by: Patrick Bellasi --- kernel/sched/tune.c | 73 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c index 62f30858e7b9..fbdd00a7aabf 100644 --- a/kernel/sched/tune.c +++ b/kernel/sched/tune.c @@ -108,6 +108,64 @@ __schedtune_accept_deltas(int nrg_delta, int cap_delta, /* * EAS scheduler tunables for task groups. + * + * When CGroup support is enabled, we have to synchronize two different + * paths: + * - slow path: where CGroups are created/updated/removed + * - fast path: where tasks in a CGroups are accounted + * + * The slow path tracks (a limited number of) CGroups and maps each on a + * "boost_group" index. The fastpath accounts tasks currently RUNNABLE on each + * "boost_group". + * + * Once a new CGroup is created, a boost group idx is assigned and the + * corresponding "boost_group" marked as valid on each CPU. + * Once a CGroup is release, the corresponding "boost_group" is marked as + * invalid on each CPU. The CPU boost value (boost_max) is aggregated by + * considering only valid boost_groups with a non null tasks counter. + * + * .:: Locking strategy + * + * The fast path uses a spin lock for each CPU boost_group which protects the + * tasks counter. + * + * The "valid" and "boost" values of each CPU boost_group is instead + * protected by the RCU lock provided by the CGroups callbacks. Thus, only the + * slow path can access and modify the boost_group attribtues of each CPU. + * The fast path will catch up the most updated values at the next scheduling + * event (i.e. enqueue/dequeue). + * + * | + * SLOW PATH | FAST PATH + * CGroup add/update/remove | Scheduler enqueue/dequeue events + * | + * | + * | DEFINE_PER_CPU(struct boost_groups) + * | +--------------+----+---+----+----+ + * | | idle | | | | | + * | | boost_max | | | | | + * | +---->lock | | | | | + * struct schedtune allocated_groups | | | group[ ] | | | | | + * +------------------------------+ +-------+ | | +--+---------+-+----+---+----+----+ + * | idx | | | | | | valid | + * | boots / prefer_idle | | | | | | boost | + * | perf_{boost/constraints}_idx | <---------+(*) | | | | tasks | <------------+ + * | css | +-------+ | | +---------+ | + * +-+----------------------------+ | | | | | | | + * ^ | | | | | | | + * | +-------+ | | +---------+ | + * | | | | | | | | + * | | | | | | | | + * | +-------+ | | +---------+ | + * | zmalloc | | | | | | | + * | | | | | | | | + * | +-------+ | | +---------+ | + * + BOOSTGROUPS_COUNT | | BOOSTGROUPS_COUNT | + * schedtune_boostgroup_init() | + | + * | schedtune_{en,de}queue_task() | + * | + + * | schedtune_tasks_update() + * | */ /* SchdTune tunables for a group of tasks */ @@ -226,6 +284,8 @@ struct boost_groups { /* Maximum boost value for all RUNNABLE tasks on a CPU */ int boost_max; struct { + /* True when this boost group maps an actual cgroup */ + bool valid; /* The boost for tasks on that boost group */ int boost; /* Count of RUNNABLE tasks on that boost group */ @@ -250,6 +310,11 @@ schedtune_cpu_update(int cpu) /* The root boost group is always active */ boost_max = bg->group[0].boost; for (idx = 1; idx < BOOSTGROUPS_COUNT; ++idx) { + + /* Ignore non boostgroups not mapping a cgroup */ + if (!bg->group[idx].valid) + continue; + /* * A boost group affects a CPU only if it has * RUNNABLE tasks on that CPU @@ -259,6 +324,7 @@ schedtune_cpu_update(int cpu) boost_max = max(boost_max, bg->group[idx].boost); } + /* 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.*/ @@ -278,6 +344,9 @@ schedtune_boostgroup_update(int idx, int boost) for_each_possible_cpu(cpu) { bg = &per_cpu(cpu_boost_groups, cpu); + /* CGroups are never associated to non active cgroups */ + BUG_ON(!bg->group[idx].valid); + /* * Keep track of current boost values to compute the per CPU * maximum only when it has been affected by the new value of @@ -642,7 +711,7 @@ schedtune_boostgroup_init(struct schedtune *st, int idx) for_each_possible_cpu(cpu) { bg = &per_cpu(cpu_boost_groups, cpu); bg->group[idx].boost = 0; - bg->group[idx].tasks = 0; + bg->group[idx].valid = true; } /* Keep track of allocated boost groups */ @@ -697,6 +766,7 @@ schedtune_boostgroup_release(struct schedtune *st) /* Reset per CPUs boost group support */ for_each_possible_cpu(cpu) { bg = &per_cpu(cpu_boost_groups, cpu); + bg->group[st->idx].valid = false; bg->group[st->idx].boost = 0; } @@ -733,6 +803,7 @@ schedtune_init_cgroups(void) for_each_possible_cpu(cpu) { bg = &per_cpu(cpu_boost_groups, cpu); memset(bg, 0, sizeof(struct boost_groups)); + bg->group[0].valid = true; raw_spin_lock_init(&bg->lock); } -- GitLab From c268509371f7c01987053f6062db87a5c17e4018 Mon Sep 17 00:00:00 2001 From: Harsh Shah Date: Thu, 7 Jun 2018 20:32:25 -0700 Subject: [PATCH 075/604] msm: camera: isp: Initialize used_bytes to avoid corruption UBWC update does not update KMD cmd buffer, hence used_bytes should be 0. But, due to uninitialized garbage value the hw_update_entries is corrupted, causing CDM Invalid command error. Initialize used_bytes to 0, to fix this issue. Change-Id: I0f8a77f782c833623af5773d15a5c4ce84492125 Signed-off-by: Harsh Shah --- .../hw_utils/cam_isp_packet_parser.c | 56 ++++++++++++++++--- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index e869e2bdc918..1444911b7a0d 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -70,6 +70,12 @@ int cam_isp_add_change_base( hw_entry[num_ent].handle = kmd_buf_info->handle; hw_entry[num_ent].len = get_base.cmd.used_bytes; hw_entry[num_ent].offset = kmd_buf_info->offset; + CAM_DBG(CAM_ISP, + "num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); kmd_buf_info->used_bytes += get_base.cmd.used_bytes; kmd_buf_info->offset += get_base.cmd.used_bytes; @@ -184,6 +190,16 @@ int cam_isp_add_cmd_buf_update( return -EINVAL; } + cmd_update.cmd_type = hw_cmd_type; + cmd_update.cmd.cmd_buf_addr = cmd_buf_addr; + cmd_update.cmd.size = kmd_buf_remain_size; + cmd_update.cmd.used_bytes = 0; + cmd_update.data = cmd_update_data; + CAM_DBG(CAM_ISP, "cmd_type %u cmd buffer 0x%pK, size %d", + cmd_update.cmd_type, + cmd_update.cmd.cmd_buf_addr, + cmd_update.cmd.size); + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { if (!hw_mgr_res->hw_res[i]) continue; @@ -193,14 +209,7 @@ int cam_isp_add_cmd_buf_update( res = hw_mgr_res->hw_res[i]; cmd_update.res = res; - cmd_update.cmd_type = hw_cmd_type; - cmd_update.cmd.cmd_buf_addr = cmd_buf_addr; - cmd_update.cmd.size = kmd_buf_remain_size; - cmd_update.data = cmd_update_data; - - CAM_DBG(CAM_ISP, "cmd buffer 0x%pK, size %d", - cmd_update.cmd.cmd_buf_addr, - cmd_update.cmd.size); + rc = res->hw_intf->hw_ops.process_cmd( res->hw_intf->hw_priv, cmd_update.cmd_type, &cmd_update, @@ -280,6 +289,12 @@ int cam_isp_add_command_buffers( hw_entry[num_ent].handle = cmd_desc[i].mem_handle; hw_entry[num_ent].offset = cmd_desc[i].offset; + CAM_DBG(CAM_ISP, + "Meta_Left num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); if (cmd_meta_data == CAM_ISP_PACKET_META_DMI_LEFT) @@ -295,6 +310,12 @@ int cam_isp_add_command_buffers( hw_entry[num_ent].handle = cmd_desc[i].mem_handle; hw_entry[num_ent].offset = cmd_desc[i].offset; + CAM_DBG(CAM_ISP, + "Meta_Right num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); if (cmd_meta_data == CAM_ISP_PACKET_META_DMI_RIGHT) @@ -308,7 +329,12 @@ int cam_isp_add_command_buffers( hw_entry[num_ent].handle = cmd_desc[i].mem_handle; hw_entry[num_ent].offset = cmd_desc[i].offset; - + CAM_DBG(CAM_ISP, + "Meta_Common num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); if (cmd_meta_data == CAM_ISP_PACKET_META_DMI_COMMON) hw_entry[num_ent].flags = 0x1; @@ -647,6 +673,12 @@ int cam_isp_add_io_buffers( prepare->hw_update_entries[num_ent].len = io_cfg_used_bytes; prepare->hw_update_entries[num_ent].offset = kmd_buf_info->offset; + CAM_DBG(CAM_ISP, + "num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + prepare->hw_update_entries[num_ent].handle, + prepare->hw_update_entries[num_ent].len, + prepare->hw_update_entries[num_ent].offset); num_ent++; kmd_buf_info->used_bytes += io_cfg_used_bytes; @@ -741,6 +773,12 @@ int cam_isp_add_reg_update( prepare->hw_update_entries[num_ent].len = reg_update_size; prepare->hw_update_entries[num_ent].offset = kmd_buf_info->offset; + CAM_DBG(CAM_ISP, + "num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + prepare->hw_update_entries[num_ent].handle, + prepare->hw_update_entries[num_ent].len, + prepare->hw_update_entries[num_ent].offset); num_ent++; kmd_buf_info->used_bytes += reg_update_size; -- GitLab From d6313fe3ab2dbe04b7fff2c3aee55d20b1b2bdb0 Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Tue, 27 Jun 2017 12:27:24 +0200 Subject: [PATCH 076/604] tpm: do not suspend/resume if power stays on commit b5d0ebc99bf5d0801a5ecbe958caa3d68b8eaee8 upstream. The suspend/resume behavior of the TPM can be controlled by setting "powered-while-suspended" in the DTS. This is useful for the cases when hardware does not power-off the TPM. Signed-off-by: Sonny Rao Signed-off-by: Enric Balletbo i Serra Reviewed-by: Jason Gunthorpe Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm-chip.c | 13 +++++++++++++ drivers/char/tpm/tpm-interface.c | 3 +++ drivers/char/tpm/tpm.h | 1 + 3 files changed, 17 insertions(+) diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 9ff853229957..8d097d10fd13 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "tpm.h" #include "tpm_eventlog.h" @@ -388,8 +389,20 @@ static int tpm_add_legacy_sysfs(struct tpm_chip *chip) */ int tpm_chip_register(struct tpm_chip *chip) { +#ifdef CONFIG_OF + struct device_node *np; +#endif int rc; +#ifdef CONFIG_OF + np = of_find_node_by_name(NULL, "vtpm"); + if (np) { + if (of_property_read_bool(np, "powered-while-suspended")) + chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; + } + of_node_put(np); +#endif + if (chip->ops->flags & TPM_OPS_AUTO_STARTUP) { if (chip->flags & TPM_CHIP_FLAG_TPM2) rc = tpm2_auto_startup(chip); diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 830d7e30e508..5463b649bdf1 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -969,6 +969,9 @@ int tpm_pm_suspend(struct device *dev) if (chip == NULL) return -ENODEV; + if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED) + return 0; + if (chip->flags & TPM_CHIP_FLAG_TPM2) { tpm2_shutdown(chip, TPM2_SU_STATE); return 0; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index aa4299cf7e5a..a4fc2badf633 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -143,6 +143,7 @@ enum tpm_chip_flags { TPM_CHIP_FLAG_TPM2 = BIT(1), TPM_CHIP_FLAG_IRQ = BIT(2), TPM_CHIP_FLAG_VIRTUAL = BIT(3), + TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5), }; struct tpm_chip { -- GitLab From e876bfa526ce5ef8b385f1272e348d60834a0652 Mon Sep 17 00:00:00 2001 From: Chris Chiu Date: Tue, 20 Mar 2018 15:36:40 +0800 Subject: [PATCH 077/604] tpm: self test failure should not cause suspend to fail commit 0803d7befa15cab5717d667a97a66214d2a4c083 upstream. The Acer Acer Veriton X4110G has a TPM device detected as: tpm_tis 00:0b: 1.2 TPM (device-id 0xFE, rev-id 71) After the first S3 suspend, the following error appears during resume: tpm tpm0: A TPM error(38) occurred continue selftest Any following S3 suspend attempts will now fail with this error: tpm tpm0: Error (38) sending savestate before suspend PM: Device 00:0b failed to suspend: error 38 Error 38 is TPM_ERR_INVALID_POSTINIT which means the TPM is not in the correct state. This indicates that the platform BIOS is not sending the usual TPM_Startup command during S3 resume. >From this point onwards, all TPM commands will fail. The same issue was previously reported on Foxconn 6150BK8MC and Sony Vaio TX3. The platform behaviour seems broken here, but we should not break suspend/resume because of this. When the unexpected TPM state is encountered, set a flag to skip the affected TPM_SaveState command on later suspends. Cc: stable@vger.kernel.org Signed-off-by: Chris Chiu Signed-off-by: Daniel Drake Link: http://lkml.kernel.org/r/CAB4CAwfSCvj1cudi+MWaB5g2Z67d9DwY1o475YOZD64ma23UiQ@mail.gmail.com Link: https://lkml.org/lkml/2011/3/28/192 Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=591031 Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm-interface.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 5463b649bdf1..faf2db122ab9 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -803,6 +803,10 @@ int tpm_do_selftest(struct tpm_chip *chip) loops = jiffies_to_msecs(duration) / delay_msec; rc = tpm_continue_selftest(chip); + if (rc == TPM_ERR_INVALID_POSTINIT) { + chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; + dev_info(&chip->dev, "TPM not ready (%d)\n", rc); + } /* This may fail if there was no TPM driver during a suspend/resume * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST) */ -- GitLab From 7a40374c34e8c25062b0d7e2d2152ff8b7af1274 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 11 May 2018 09:52:01 -0700 Subject: [PATCH 078/604] mmap: introduce sane default mmap limits commit be83bbf806822b1b89e0a0f23cd87cddc409e429 upstream. The internal VM "mmap()" interfaces are based on the mmap target doing everything using page indexes rather than byte offsets, because traditionally (ie 32-bit) we had the situation that the byte offset didn't fit in a register. So while the mmap virtual address was limited by the word size of the architecture, the backing store was not. So we're basically passing "pgoff" around as a page index, in order to be able to describe backing store locations that are much bigger than the word size (think files larger than 4GB etc). But while this all makes a ton of sense conceptually, we've been dogged by various drivers that don't really understand this, and internally work with byte offsets, and then try to work with the page index by turning it into a byte offset with "pgoff << PAGE_SHIFT". Which obviously can overflow. Adding the size of the mapping to it to get the byte offset of the end of the backing store just exacerbates the problem, and if you then use this overflow-prone value to check various limits of your device driver mmap capability, you're just setting yourself up for problems. The correct thing for drivers to do is to do their limit math in page indices, the way the interface is designed. Because the generic mmap code _does_ test that the index doesn't overflow, since that's what the mmap code really cares about. HOWEVER. Finding and fixing various random drivers is a sisyphean task, so let's just see if we can just make the core mmap() code do the limiting for us. Realistically, the only "big" backing stores we need to care about are regular files and block devices, both of which are known to do this properly, and which have nice well-defined limits for how much data they can access. So let's special-case just those two known cases, and then limit other random mmap users to a backing store that still fits in "unsigned long". Realistically, that's not much of a limit at all on 64-bit, and on 32-bit architectures the only worry might be the GPU drivers, which can have big physical address spaces. To make it possible for drivers like that to say that they are 64-bit clean, this patch does repurpose the "FMODE_UNSIGNED_OFFSET" bit in the file flags to allow drivers to mark their file descriptors as safe in the full 64-bit mmap address space. [ The timing for doing this is less than optimal, and this should really go in a merge window. But realistically, this needs wide testing more than it needs anything else, and being main-line is the only way to do that. So the earlier the better, even if it's outside the proper development cycle - Linus ] Cc: Kees Cook Cc: Dan Carpenter Cc: Al Viro Cc: Willy Tarreau Cc: Dave Airlie Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/mmap.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/mm/mmap.c b/mm/mmap.c index 45ac5b973459..fb2b575dd86c 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1312,6 +1312,35 @@ static inline int mlock_future_check(struct mm_struct *mm, return 0; } +static inline u64 file_mmap_size_max(struct file *file, struct inode *inode) +{ + if (S_ISREG(inode->i_mode)) + return inode->i_sb->s_maxbytes; + + if (S_ISBLK(inode->i_mode)) + return MAX_LFS_FILESIZE; + + /* Special "we do even unsigned file positions" case */ + if (file->f_mode & FMODE_UNSIGNED_OFFSET) + return 0; + + /* Yes, random drivers might want more. But I'm tired of buggy drivers */ + return ULONG_MAX; +} + +static inline bool file_mmap_ok(struct file *file, struct inode *inode, + unsigned long pgoff, unsigned long len) +{ + u64 maxsize = file_mmap_size_max(file, inode); + + if (maxsize && len > maxsize) + return false; + maxsize -= len; + if (pgoff > maxsize >> PAGE_SHIFT) + return false; + return true; +} + /* * The caller must hold down_write(¤t->mm->mmap_sem). */ @@ -1384,6 +1413,9 @@ unsigned long do_mmap(struct file *file, unsigned long addr, if (file) { struct inode *inode = file_inode(file); + if (!file_mmap_ok(file, inode, pgoff, len)) + return -EOVERFLOW; + switch (flags & MAP_TYPE) { case MAP_SHARED: if ((prot&PROT_WRITE) && !(file->f_mode&FMODE_WRITE)) -- GitLab From 4be6529b71dc98696cd760984a98d1397fd90ae3 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 19 May 2018 09:29:11 -0700 Subject: [PATCH 079/604] mmap: relax file size limit for regular files commit 423913ad4ae5b3e8fb8983f70969fb522261ba26 upstream. Commit be83bbf80682 ("mmap: introduce sane default mmap limits") was introduced to catch problems in various ad-hoc character device drivers doing mmap and getting the size limits wrong. In the process, it used "known good" limits for the normal cases of mapping regular files and block device drivers. It turns out that the "s_maxbytes" limit was less "known good" than I thought. In particular, /proc doesn't set it, but exposes one regular file to mmap: /proc/vmcore. As a result, that file got limited to the default MAX_INT s_maxbytes value. This went unnoticed for a while, because apparently the only thing that needs it is the s390 kernel zfcpdump, but there might be other tools that use this too. Vasily suggested just changing s_maxbytes for all of /proc, which isn't wrong, but makes me nervous at this stage. So instead, just make the new mmap limit always be MAX_LFS_FILESIZE for regular files, which won't affect anything else. It wasn't the regular file case I was worried about. I'd really prefer for maxsize to have been per-inode, but that is not how things are today. Fixes: be83bbf80682 ("mmap: introduce sane default mmap limits") Reported-by: Vasily Gorbik Cc: Al Viro Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/mmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/mmap.c b/mm/mmap.c index fb2b575dd86c..aa97074a4a99 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1315,7 +1315,7 @@ static inline int mlock_future_check(struct mm_struct *mm, static inline u64 file_mmap_size_max(struct file *file, struct inode *inode) { if (S_ISREG(inode->i_mode)) - return inode->i_sb->s_maxbytes; + return MAX_LFS_FILESIZE; if (S_ISBLK(inode->i_mode)) return MAX_LFS_FILESIZE; -- GitLab From 8d99eb45732d331616e39740028afeb9afaf0b77 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 9 Jan 2018 09:05:41 +0800 Subject: [PATCH 080/604] btrfs: define SUPER_FLAG_METADUMP_V2 commit e2731e55884f2138a252b0a3d7b24d57e49c3c59 upstream. btrfs-progs uses super flag bit BTRFS_SUPER_FLAG_METADUMP_V2 (1ULL << 34). So just define that in kernel so that we know its been used. Signed-off-by: Anand Jain Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/disk-io.c | 3 ++- include/uapi/linux/btrfs_tree.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index c5eafcdb3664..92f3b231d5a2 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -59,7 +59,8 @@ BTRFS_HEADER_FLAG_RELOC |\ BTRFS_SUPER_FLAG_ERROR |\ BTRFS_SUPER_FLAG_SEEDING |\ - BTRFS_SUPER_FLAG_METADUMP) + BTRFS_SUPER_FLAG_METADUMP |\ + BTRFS_SUPER_FLAG_METADUMP_V2) static const struct extent_io_ops btree_extent_io_ops; static void end_workqueue_fn(struct btrfs_work *work); diff --git a/include/uapi/linux/btrfs_tree.h b/include/uapi/linux/btrfs_tree.h index d5ad15a106a7..c794c9af6c0f 100644 --- a/include/uapi/linux/btrfs_tree.h +++ b/include/uapi/linux/btrfs_tree.h @@ -452,6 +452,7 @@ struct btrfs_free_space_header { #define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32) #define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33) +#define BTRFS_SUPER_FLAG_METADUMP_V2 (1ULL << 34) /* -- GitLab From 1ec1dfba0835308ef3119fdc8be01c610da0b035 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Sat, 2 Jun 2018 09:02:09 -0700 Subject: [PATCH 081/604] kconfig: Avoid format overflow warning from GCC 8.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 2ae89c7a82ea9d81a19b4fc2df23bef4b112f24e upstream. In file included from scripts/kconfig/zconf.tab.c:2485: scripts/kconfig/confdata.c: In function ‘conf_write’: scripts/kconfig/confdata.c:773:22: warning: ‘%s’ directive writing likely 7 or more bytes into a region of size between 1 and 4097 [-Wformat-overflow=] sprintf(newname, "%s%s", dirname, basename); ^~ scripts/kconfig/confdata.c:773:19: note: assuming directive output of 7 bytes sprintf(newname, "%s%s", dirname, basename); ^~~~~~ scripts/kconfig/confdata.c:773:2: note: ‘sprintf’ output 1 or more bytes (assuming 4104) into a destination of size 4097 sprintf(newname, "%s%s", dirname, basename); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ scripts/kconfig/confdata.c:776:23: warning: ‘.tmpconfig.’ directive writing 11 bytes into a region of size between 1 and 4097 [-Wformat-overflow=] sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid()); ^~~~~~~~~~~ scripts/kconfig/confdata.c:776:3: note: ‘sprintf’ output between 13 and 4119 bytes into a destination of size 4097 sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid()); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Increase the size of tmpname and newname to make GCC happy. Signed-off-by: Nathan Chancellor Signed-off-by: Masahiro Yamada Signed-off-by: Greg Kroah-Hartman --- scripts/kconfig/confdata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 297b079ae4d9..27aac273205b 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -745,7 +745,7 @@ int conf_write(const char *name) struct menu *menu; const char *basename; const char *str; - char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; + char dirname[PATH_MAX+1], tmpname[PATH_MAX+22], newname[PATH_MAX+8]; char *env; dirname[0] = 0; -- GitLab From 8655f2847fd5d52fc22ed2d1ce00e801ab6a77c2 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 15 May 2018 13:38:15 +1000 Subject: [PATCH 082/604] drm: set FMODE_UNSIGNED_OFFSET for drm files commit 76ef6b28ea4f81c3d511866a9b31392caa833126 upstream. Since we have the ttm and gem vma managers using a subset of the file address space for objects, and these start at 0x100000000 they will overflow the new mmap checks. I've checked all the mmap routines I could see for any bad behaviour but overall most people use GEM/TTM VMA managers even the legacy drivers have a hashtable. Reported-and-Tested-by: Arthur Marsh (amarsh04 on #radeon) Fixes: be83bbf8068 (mmap: introduce sane default mmap limits) Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_fops.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index f5815e1a4390..c37b7b5f1dd3 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -198,6 +198,7 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor) return -ENOMEM; filp->private_data = priv; + filp->f_mode |= FMODE_UNSIGNED_OFFSET; priv->filp = filp; priv->pid = get_pid(task_pid(current)); priv->minor = minor; -- GitLab From 5dcfc06ba2b547441b096846027f5d30dbd749dd Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 6 Jun 2018 15:03:22 +0200 Subject: [PATCH 083/604] bnx2x: use the right constant [ Upstream commit dd612f18a49b63af8b3a5f572d999bdb197385bc ] Nearby code that also tests port suggests that the P0 constant should be used when port is zero. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression e,e1; @@ * e ? e1 : e1 // Fixes: 6c3218c6f7e5 ("bnx2x: Adjust ETS to 578xx") Signed-off-by: Julia Lawall Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 1fb80100e5e7..912900db935f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -594,7 +594,7 @@ static void bnx2x_ets_e3b0_nig_disabled(const struct link_params *params, * slots for the highest priority. */ REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS : - NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); + NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); /* Mapping between the CREDIT_WEIGHT registers and actual client * numbers */ -- GitLab From 3e146567d2bf55acaab38414b04cdf6506f8abc2 Mon Sep 17 00:00:00 2001 From: Alexey Kodanev Date: Mon, 21 May 2018 19:28:44 +0300 Subject: [PATCH 084/604] dccp: don't free ccid2_hc_tx_sock struct in dccp_disconnect() [ Upstream commit 2677d20677314101293e6da0094ede7b5526d2b1 ] Syzbot reported the use-after-free in timer_is_static_object() [1]. This can happen because the structure for the rto timer (ccid2_hc_tx_sock) is removed in dccp_disconnect(), and ccid2_hc_tx_rto_expire() can be called after that. The report [1] is similar to the one in commit 120e9dabaf55 ("dccp: defer ccid_hc_tx_delete() at dismantle time"). And the fix is the same, delay freeing ccid2_hc_tx_sock structure, so that it is freed in dccp_sk_destruct(). [1] ================================================================== BUG: KASAN: use-after-free in timer_is_static_object+0x80/0x90 kernel/time/timer.c:607 Read of size 8 at addr ffff8801bebb5118 by task syz-executor2/25299 CPU: 1 PID: 25299 Comm: syz-executor2 Not tainted 4.17.0-rc5+ #54 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+0x1b9/0x294 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 timer_is_static_object+0x80/0x90 kernel/time/timer.c:607 debug_object_activate+0x2d9/0x670 lib/debugobjects.c:508 debug_timer_activate kernel/time/timer.c:709 [inline] debug_activate kernel/time/timer.c:764 [inline] __mod_timer kernel/time/timer.c:1041 [inline] mod_timer+0x4d3/0x13b0 kernel/time/timer.c:1102 sk_reset_timer+0x22/0x60 net/core/sock.c:2742 ccid2_hc_tx_rto_expire+0x587/0x680 net/dccp/ccids/ccid2.c:147 call_timer_fn+0x230/0x940 kernel/time/timer.c:1326 expire_timers kernel/time/timer.c:1363 [inline] __run_timers+0x79e/0xc50 kernel/time/timer.c:1666 run_timer_softirq+0x4c/0x70 kernel/time/timer.c:1692 __do_softirq+0x2e0/0xaf5 kernel/softirq.c:285 invoke_softirq kernel/softirq.c:365 [inline] irq_exit+0x1d1/0x200 kernel/softirq.c:405 exiting_irq arch/x86/include/asm/apic.h:525 [inline] smp_apic_timer_interrupt+0x17e/0x710 arch/x86/kernel/apic/apic.c:1052 apic_timer_interrupt+0xf/0x20 arch/x86/entry/entry_64.S:863 ... Allocated by task 25374: 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 ccid_new+0x25b/0x3e0 net/dccp/ccid.c:151 dccp_hdlr_ccid+0x27/0x150 net/dccp/feat.c:44 __dccp_feat_activate+0x184/0x270 net/dccp/feat.c:344 dccp_feat_activate_values+0x3a7/0x819 net/dccp/feat.c:1538 dccp_create_openreq_child+0x472/0x610 net/dccp/minisocks.c:128 dccp_v4_request_recv_sock+0x12c/0xca0 net/dccp/ipv4.c:408 dccp_v6_request_recv_sock+0x125d/0x1f10 net/dccp/ipv6.c:415 dccp_check_req+0x455/0x6a0 net/dccp/minisocks.c:197 dccp_v4_rcv+0x7b8/0x1f3f net/dccp/ipv4.c:841 ip_local_deliver_finish+0x2e3/0xd80 net/ipv4/ip_input.c:215 NF_HOOK include/linux/netfilter.h:288 [inline] ip_local_deliver+0x1e1/0x720 net/ipv4/ip_input.c:256 dst_input include/net/dst.h:450 [inline] ip_rcv_finish+0x81b/0x2200 net/ipv4/ip_input.c:396 NF_HOOK include/linux/netfilter.h:288 [inline] ip_rcv+0xb70/0x143d net/ipv4/ip_input.c:492 __netif_receive_skb_core+0x26f5/0x3630 net/core/dev.c:4592 __netif_receive_skb+0x2c/0x1e0 net/core/dev.c:4657 process_backlog+0x219/0x760 net/core/dev.c:5337 napi_poll net/core/dev.c:5735 [inline] net_rx_action+0x7b7/0x1930 net/core/dev.c:5801 __do_softirq+0x2e0/0xaf5 kernel/softirq.c:285 Freed by task 25374: 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 ccid_hc_tx_delete+0xc3/0x100 net/dccp/ccid.c:190 dccp_disconnect+0x130/0xc66 net/dccp/proto.c:286 dccp_close+0x3bc/0xe60 net/dccp/proto.c:1045 inet_release+0x104/0x1f0 net/ipv4/af_inet.c:427 inet6_release+0x50/0x70 net/ipv6/af_inet6.c:460 sock_release+0x96/0x1b0 net/socket.c:594 sock_close+0x16/0x20 net/socket.c:1149 __fput+0x34d/0x890 fs/file_table.c:209 ____fput+0x15/0x20 fs/file_table.c:243 task_work_run+0x1e4/0x290 kernel/task_work.c:113 tracehook_notify_resume include/linux/tracehook.h:191 [inline] exit_to_usermode_loop+0x2bd/0x310 arch/x86/entry/common.c:166 prepare_exit_to_usermode arch/x86/entry/common.c:196 [inline] syscall_return_slowpath arch/x86/entry/common.c:265 [inline] do_syscall_64+0x6ac/0x800 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe The buggy address belongs to the object at ffff8801bebb4cc0 which belongs to the cache ccid2_hc_tx_sock of size 1240 The buggy address is located 1112 bytes inside of 1240-byte region [ffff8801bebb4cc0, ffff8801bebb5198) The buggy address belongs to the page: page:ffffea0006faed00 count:1 mapcount:0 mapping:ffff8801bebb41c0 index:0xffff8801bebb5240 compound_mapcount: 0 flags: 0x2fffc0000008100(slab|head) raw: 02fffc0000008100 ffff8801bebb41c0 ffff8801bebb5240 0000000100000003 raw: ffff8801cdba3138 ffffea0007634120 ffff8801cdbaab40 0000000000000000 page dumped because: kasan: bad access detected ... ================================================================== Reported-by: syzbot+5d47e9ec91a6f15dbd6f@syzkaller.appspotmail.com Signed-off-by: Alexey Kodanev Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/dccp/proto.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/dccp/proto.c b/net/dccp/proto.c index ff3b058cf58c..936dab12f99f 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -280,9 +280,7 @@ int dccp_disconnect(struct sock *sk, int flags) dccp_clear_xmit_timers(sk); ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); - ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); dp->dccps_hc_rx_ccid = NULL; - dp->dccps_hc_tx_ccid = NULL; __skb_queue_purge(&sk->sk_receive_queue); __skb_queue_purge(&sk->sk_write_queue); -- GitLab From fc7c872ff95799fdb5cd59a4eb879ef87fef4883 Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan Date: Wed, 23 May 2018 11:17:39 -0700 Subject: [PATCH 085/604] enic: set DMA mask to 47 bit [ Upstream commit 322eaa06d55ebc1402a4a8d140945cff536638b4 ] In commit 624dbf55a359b ("driver/net: enic: Try DMA 64 first, then failover to DMA") DMA mask was changed from 40 bits to 64 bits. Hardware actually supports only 47 bits. Fixes: 624dbf55a359b ("driver/net: enic: Try DMA 64 first, then failover to DMA") Signed-off-by: Govindarajulu Varadarajan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/cisco/enic/enic_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index dda63b26e370..99f593be26e2 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -2541,11 +2541,11 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); /* Query PCI controller on system for DMA addressing - * limitation for the device. Try 64-bit first, and + * limitation for the device. Try 47-bit first, and * fail to 32-bit. */ - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(47)); if (err) { err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { @@ -2559,10 +2559,10 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_release_regions; } } else { - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(47)); if (err) { dev_err(dev, "Unable to obtain %u-bit DMA " - "for consistent allocations, aborting\n", 64); + "for consistent allocations, aborting\n", 47); goto err_out_release_regions; } using_dac = 1; -- GitLab From ffa13b359cd1f3ef60ca5adc59ad5ea229f4cd7d Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Tue, 5 Jun 2018 15:01:59 +0200 Subject: [PATCH 086/604] ip6mr: only set ip6mr_table from setsockopt when ip6mr_new_table succeeds [ Upstream commit 848235edb5c93ed086700584c8ff64f6d7fc778d ] Currently, raw6_sk(sk)->ip6mr_table is set unconditionally during ip6_mroute_setsockopt(MRT6_TABLE). A subsequent attempt at the same setsockopt will fail with -ENOENT, since we haven't actually created that table. A similar fix for ipv4 was included in commit 5e1859fbcc3c ("ipv4: ipmr: various fixes and cleanups"). Fixes: d1db275dd3f6 ("ipv6: ip6mr: support multiple tables") Signed-off-by: Sabrina Dubroca Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6mr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index a30e7e925c9b..4b93ad4fe6d8 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1789,7 +1789,8 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns ret = 0; if (!ip6mr_new_table(net, v)) ret = -ENOMEM; - raw6_sk(sk)->ip6mr_table = v; + else + raw6_sk(sk)->ip6mr_table = v; rtnl_unlock(); return ret; } -- GitLab From d33ecd26010f1ff4d44a4c27d4c4a73cdf87dd7f Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Wed, 23 May 2018 14:29:52 -0400 Subject: [PATCH 087/604] ipv4: remove warning in ip_recv_error [ Upstream commit 730c54d59403658a62af6517338fa8d4922c1b28 ] A precondition check in ip_recv_error triggered on an otherwise benign race. Remove the warning. The warning triggers when passing an ipv6 socket to this ipv4 error handling function. RaceFuzzer was able to trigger it due to a race in setsockopt IPV6_ADDRFORM. --- CPU0 do_ipv6_setsockopt sk->sk_socket->ops = &inet_dgram_ops; --- CPU1 sk->sk_prot->recvmsg udp_recvmsg ip_recv_error WARN_ON_ONCE(sk->sk_family == AF_INET6); --- CPU0 do_ipv6_setsockopt sk->sk_family = PF_INET; This socket option converts a v6 socket that is connected to a v4 peer to an v4 socket. It updates the socket on the fly, changing fields in sk as well as other structs. This is inherently non-atomic. It races with the lockless udp_recvmsg path. No other code makes an assumption that these fields are updated atomically. It is benign here, too, as ip_recv_error cares only about the protocol of the skbs enqueued on the error queue, for which sk_family is not a precise predictor (thanks to another isue with IPV6_ADDRFORM). Link: http://lkml.kernel.org/r/20180518120826.GA19515@dragonet.kaist.ac.kr Fixes: 7ce875e5ecb8 ("ipv4: warn once on passing AF_INET6 socket to ip_recv_error") Reported-by: DaeRyong Jeong Suggested-by: Eric Dumazet Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ip_sockglue.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 5ddd64995e73..dd80276a8205 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -503,8 +503,6 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) int err; int copied; - WARN_ON_ONCE(sk->sk_family == AF_INET6); - err = -EAGAIN; skb = sock_dequeue_err_skb(sk); if (!skb) -- GitLab From f698b28afc3402c4020e6574e735f7d3857048ce Mon Sep 17 00:00:00 2001 From: Wenwen Wang Date: Mon, 21 May 2018 01:58:07 -0500 Subject: [PATCH 088/604] isdn: eicon: fix a missing-check bug [ Upstream commit 6009d1fe6ba3bb2dab55921da60465329cc1cd89 ] In divasmain.c, the function divas_write() firstly invokes the function diva_xdi_open_adapter() to open the adapter that matches with the adapter number provided by the user, and then invokes the function diva_xdi_write() to perform the write operation using the matched adapter. The two functions diva_xdi_open_adapter() and diva_xdi_write() are located in diva.c. In diva_xdi_open_adapter(), the user command is copied to the object 'msg' from the userspace pointer 'src' through the function pointer 'cp_fn', which eventually calls copy_from_user() to do the copy. Then, the adapter number 'msg.adapter' is used to find out a matched adapter from the 'adapter_queue'. A matched adapter will be returned if it is found. Otherwise, NULL is returned to indicate the failure of the verification on the adapter number. As mentioned above, if a matched adapter is returned, the function diva_xdi_write() is invoked to perform the write operation. In this function, the user command is copied once again from the userspace pointer 'src', which is the same as the 'src' pointer in diva_xdi_open_adapter() as both of them are from the 'buf' pointer in divas_write(). Similarly, the copy is achieved through the function pointer 'cp_fn', which finally calls copy_from_user(). After the successful copy, the corresponding command processing handler of the matched adapter is invoked to perform the write operation. It is obvious that there are two copies here from userspace, one is in diva_xdi_open_adapter(), and one is in diva_xdi_write(). Plus, both of these two copies share the same source userspace pointer, i.e., the 'buf' pointer in divas_write(). Given that a malicious userspace process can race to change the content pointed by the 'buf' pointer, this can pose potential security issues. For example, in the first copy, the user provides a valid adapter number to pass the verification process and a valid adapter can be found. Then the user can modify the adapter number to an invalid number. This way, the user can bypass the verification process of the adapter number and inject inconsistent data. This patch reuses the data copied in diva_xdi_open_adapter() and passes it to diva_xdi_write(). This way, the above issues can be avoided. Signed-off-by: Wenwen Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/isdn/hardware/eicon/diva.c | 22 +++++++++++++++------- drivers/isdn/hardware/eicon/diva.h | 5 +++-- drivers/isdn/hardware/eicon/divasmain.c | 18 +++++++++++------- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/drivers/isdn/hardware/eicon/diva.c b/drivers/isdn/hardware/eicon/diva.c index d91dd580e978..37aaea88a6ad 100644 --- a/drivers/isdn/hardware/eicon/diva.c +++ b/drivers/isdn/hardware/eicon/diva.c @@ -387,10 +387,10 @@ void divasa_xdi_driver_unload(void) ** Receive and process command from user mode utility */ void *diva_xdi_open_adapter(void *os_handle, const void __user *src, - int length, + int length, void *mptr, divas_xdi_copy_from_user_fn_t cp_fn) { - diva_xdi_um_cfg_cmd_t msg; + diva_xdi_um_cfg_cmd_t *msg = (diva_xdi_um_cfg_cmd_t *)mptr; diva_os_xdi_adapter_t *a = NULL; diva_os_spin_lock_magic_t old_irql; struct list_head *tmp; @@ -400,21 +400,21 @@ void *diva_xdi_open_adapter(void *os_handle, const void __user *src, length, sizeof(diva_xdi_um_cfg_cmd_t))) return NULL; } - if ((*cp_fn) (os_handle, &msg, src, sizeof(msg)) <= 0) { + if ((*cp_fn) (os_handle, msg, src, sizeof(*msg)) <= 0) { DBG_ERR(("A: A(?) open, write error")) return NULL; } diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter"); list_for_each(tmp, &adapter_queue) { a = list_entry(tmp, diva_os_xdi_adapter_t, link); - if (a->controller == (int)msg.adapter) + if (a->controller == (int)msg->adapter) break; a = NULL; } diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter"); if (!a) { - DBG_ERR(("A: A(%d) open, adapter not found", msg.adapter)) + DBG_ERR(("A: A(%d) open, adapter not found", msg->adapter)) } return (a); @@ -436,8 +436,10 @@ void diva_xdi_close_adapter(void *adapter, void *os_handle) int diva_xdi_write(void *adapter, void *os_handle, const void __user *src, - int length, divas_xdi_copy_from_user_fn_t cp_fn) + int length, void *mptr, + divas_xdi_copy_from_user_fn_t cp_fn) { + diva_xdi_um_cfg_cmd_t *msg = (diva_xdi_um_cfg_cmd_t *)mptr; diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter; void *data; @@ -458,7 +460,13 @@ diva_xdi_write(void *adapter, void *os_handle, const void __user *src, return (-2); } - length = (*cp_fn) (os_handle, data, src, length); + if (msg) { + *(diva_xdi_um_cfg_cmd_t *)data = *msg; + length = (*cp_fn) (os_handle, (char *)data + sizeof(*msg), + src + sizeof(*msg), length - sizeof(*msg)); + } else { + length = (*cp_fn) (os_handle, data, src, length); + } if (length > 0) { if ((*(a->interface.cmd_proc)) (a, (diva_xdi_um_cfg_cmd_t *) data, length)) { diff --git a/drivers/isdn/hardware/eicon/diva.h b/drivers/isdn/hardware/eicon/diva.h index e979085d1b89..a0a607c0c32e 100644 --- a/drivers/isdn/hardware/eicon/diva.h +++ b/drivers/isdn/hardware/eicon/diva.h @@ -19,10 +19,11 @@ int diva_xdi_read(void *adapter, void *os_handle, void __user *dst, int max_length, divas_xdi_copy_to_user_fn_t cp_fn); int diva_xdi_write(void *adapter, void *os_handle, const void __user *src, - int length, divas_xdi_copy_from_user_fn_t cp_fn); + int length, void *msg, + divas_xdi_copy_from_user_fn_t cp_fn); void *diva_xdi_open_adapter(void *os_handle, const void __user *src, - int length, + int length, void *msg, divas_xdi_copy_from_user_fn_t cp_fn); void diva_xdi_close_adapter(void *adapter, void *os_handle); diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c index 32f34511c416..1e8b9918bfce 100644 --- a/drivers/isdn/hardware/eicon/divasmain.c +++ b/drivers/isdn/hardware/eicon/divasmain.c @@ -591,19 +591,22 @@ static int divas_release(struct inode *inode, struct file *file) static ssize_t divas_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { + diva_xdi_um_cfg_cmd_t msg; int ret = -EINVAL; if (!file->private_data) { file->private_data = diva_xdi_open_adapter(file, buf, - count, + count, &msg, xdi_copy_from_user); - } - if (!file->private_data) { - return (-ENODEV); + if (!file->private_data) + return (-ENODEV); + ret = diva_xdi_write(file->private_data, file, + buf, count, &msg, xdi_copy_from_user); + } else { + ret = diva_xdi_write(file->private_data, file, + buf, count, NULL, xdi_copy_from_user); } - ret = diva_xdi_write(file->private_data, file, - buf, count, xdi_copy_from_user); switch (ret) { case -1: /* Message should be removed from rx mailbox first */ ret = -EBUSY; @@ -622,11 +625,12 @@ static ssize_t divas_write(struct file *file, const char __user *buf, static ssize_t divas_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { + diva_xdi_um_cfg_cmd_t msg; int ret = -EINVAL; if (!file->private_data) { file->private_data = diva_xdi_open_adapter(file, buf, - count, + count, &msg, xdi_copy_from_user); } if (!file->private_data) { -- GitLab From 0ae3ff2e4317be219575f48fd4b118b5b39b7a5e Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Fri, 1 Jun 2018 14:30:38 +0300 Subject: [PATCH 089/604] kcm: Fix use-after-free caused by clonned sockets [ Upstream commit eb7f54b90bd8f469834c5e86dcf72ebf9a629811 ] (resend for properly queueing in patchwork) kcm_clone() creates kernel socket, which does not take net counter. Thus, the net may die before the socket is completely destructed, i.e. kcm_exit_net() is executed before kcm_done(). Reported-by: syzbot+5f1a04e374a635efc426@syzkaller.appspotmail.com Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/kcm/kcmsock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index cc306defcc19..553d0ad4a2fa 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -1671,7 +1671,7 @@ static struct file *kcm_clone(struct socket *osock) __module_get(newsock->ops->owner); newsk = sk_alloc(sock_net(osock->sk), PF_KCM, GFP_KERNEL, - &kcm_proto, true); + &kcm_proto, false); if (!newsk) { sock_release(newsock); return ERR_PTR(-ENOMEM); -- GitLab From 064257ca9397eac2fcd343866e2afc9abd0b61e0 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Tue, 5 Jun 2018 09:48:13 -0700 Subject: [PATCH 090/604] netdev-FAQ: clarify DaveM's position for stable backports [ Upstream commit 75d4e704fa8d2cf33ff295e5b441317603d7f9fd ] Per discussion with David at netconf 2018, let's clarify DaveM's position of handling stable backports in netdev-FAQ. This is important for people relying on upstream -stable releases. Cc: Greg Kroah-Hartman Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- Documentation/networking/netdev-FAQ.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/networking/netdev-FAQ.txt b/Documentation/networking/netdev-FAQ.txt index a20b2fae942b..56af008e9258 100644 --- a/Documentation/networking/netdev-FAQ.txt +++ b/Documentation/networking/netdev-FAQ.txt @@ -168,6 +168,15 @@ A: No. See above answer. In short, if you think it really belongs in dash marker line as described in Documentation/SubmittingPatches to temporarily embed that information into the patch that you send. +Q: Are all networking bug fixes backported to all stable releases? + +A: Due to capacity, Dave could only take care of the backports for the last + 2 stable releases. For earlier stable releases, each stable branch maintainer + is supposed to take care of them. If you find any patch is missing from an + earlier stable branch, please notify stable@vger.kernel.org with either a + commit ID or a formal patch backported, and CC Dave and other relevant + networking developers. + Q: Someone said that the comment style and coding convention is different for the networking content. Is this true? -- GitLab From ba2ce02e0584e130c8c61c65e3c1a17fde012193 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 1 Jun 2018 09:23:02 -0700 Subject: [PATCH 091/604] net/packet: refine check for priv area size [ Upstream commit eb73190f4fbeedf762394e92d6a4ec9ace684c88 ] syzbot was able to trick af_packet again [1] Various commits tried to address the problem in the past, but failed to take into account V3 header size. [1] tpacket_rcv: packet too big, clamped from 72 to 4294967224. macoff=96 BUG: KASAN: use-after-free in prb_run_all_ft_ops net/packet/af_packet.c:1016 [inline] BUG: KASAN: use-after-free in prb_fill_curr_block.isra.59+0x4e5/0x5c0 net/packet/af_packet.c:1039 Write of size 2 at addr ffff8801cb62000e by task kworker/1:2/2106 CPU: 1 PID: 2106 Comm: kworker/1:2 Not tainted 4.17.0-rc7+ #77 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Workqueue: ipv6_addrconf addrconf_dad_work Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x1b9/0x294 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_store2_noabort+0x17/0x20 mm/kasan/report.c:436 prb_run_all_ft_ops net/packet/af_packet.c:1016 [inline] prb_fill_curr_block.isra.59+0x4e5/0x5c0 net/packet/af_packet.c:1039 __packet_lookup_frame_in_block net/packet/af_packet.c:1094 [inline] packet_current_rx_frame net/packet/af_packet.c:1117 [inline] tpacket_rcv+0x1866/0x3340 net/packet/af_packet.c:2282 dev_queue_xmit_nit+0x891/0xb90 net/core/dev.c:2018 xmit_one net/core/dev.c:3049 [inline] dev_hard_start_xmit+0x16b/0xc10 net/core/dev.c:3069 __dev_queue_xmit+0x2724/0x34c0 net/core/dev.c:3584 dev_queue_xmit+0x17/0x20 net/core/dev.c:3617 neigh_resolve_output+0x679/0xad0 net/core/neighbour.c:1358 neigh_output include/net/neighbour.h:482 [inline] ip6_finish_output2+0xc9c/0x2810 net/ipv6/ip6_output.c:120 ip6_finish_output+0x5fe/0xbc0 net/ipv6/ip6_output.c:154 NF_HOOK_COND include/linux/netfilter.h:277 [inline] ip6_output+0x227/0x9b0 net/ipv6/ip6_output.c:171 dst_output include/net/dst.h:444 [inline] NF_HOOK include/linux/netfilter.h:288 [inline] ndisc_send_skb+0x100d/0x1570 net/ipv6/ndisc.c:491 ndisc_send_ns+0x3c1/0x8d0 net/ipv6/ndisc.c:633 addrconf_dad_work+0xbef/0x1340 net/ipv6/addrconf.c:4033 process_one_work+0xc1e/0x1b50 kernel/workqueue.c:2145 worker_thread+0x1cc/0x1440 kernel/workqueue.c:2279 kthread+0x345/0x410 kernel/kthread.c:240 ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:412 The buggy address belongs to the page: page:ffffea00072d8800 count:0 mapcount:-127 mapping:0000000000000000 index:0xffff8801cb620e80 flags: 0x2fffc0000000000() raw: 02fffc0000000000 0000000000000000 ffff8801cb620e80 00000000ffffff80 raw: ffffea00072e3820 ffffea0007132d20 0000000000000002 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff8801cb61ff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ffff8801cb61ff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >ffff8801cb620000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ^ ffff8801cb620080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ffff8801cb620100: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff Fixes: 2b6867c2ce76 ("net/packet: fix overflow in check for priv area size") Fixes: dc808110bb62 ("packet: handle too big packets for PACKET_V3") Fixes: f6fb8f100b80 ("af-packet: TPACKET_V3 flexible buffer implementation.") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/packet/af_packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index b2b50756263b..2c22c2cf922d 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -4299,7 +4299,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, goto out; if (po->tp_version >= TPACKET_V3 && req->tp_block_size <= - BLK_PLUS_PRIV((u64)req_u->req3.tp_sizeof_priv)) + BLK_PLUS_PRIV((u64)req_u->req3.tp_sizeof_priv) + sizeof(struct tpacket3_hdr)) goto out; if (unlikely(req->tp_frame_size < po->tp_hdrlen + po->tp_reserve)) -- GitLab From c1d50432f2be5eab456ffd19da7b78ae475a5e39 Mon Sep 17 00:00:00 2001 From: Daniele Palmas Date: Thu, 31 May 2018 11:18:29 +0200 Subject: [PATCH 092/604] net: usb: cdc_mbim: add flag FLAG_SEND_ZLP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 9f7c728332e8966084242fcd951aa46583bc308c ] Testing Telit LM940 with ICMP packets > 14552 bytes revealed that the modem needs FLAG_SEND_ZLP to properly work, otherwise the cdc mbim data interface won't be anymore responsive. Signed-off-by: Daniele Palmas Acked-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/cdc_mbim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index 3a98f3762a4c..4c8baba72933 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c @@ -608,7 +608,7 @@ static const struct driver_info cdc_mbim_info_ndp_to_end = { */ static const struct driver_info cdc_mbim_info_avoid_altsetting_toggle = { .description = "CDC MBIM", - .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN, + .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN | FLAG_SEND_ZLP, .bind = cdc_mbim_bind, .unbind = cdc_mbim_unbind, .manage_power = cdc_mbim_manage_power, -- GitLab From 1118c60b599beddce6662aa15e557b1925f1cad9 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Thu, 24 May 2018 18:10:30 -0400 Subject: [PATCH 093/604] packet: fix reserve calculation [ Upstream commit 9aad13b087ab0a588cd68259de618f100053360e ] Commit b84bbaf7a6c8 ("packet: in packet_snd start writing at link layer allocation") ensures that packet_snd always starts writing the link layer header in reserved headroom allocated for this purpose. This is needed because packets may be shorter than hard_header_len, in which case the space up to hard_header_len may be zeroed. But that necessary padding is not accounted for in skb->len. The fix, however, is buggy. It calls skb_push, which grows skb->len when moving skb->data back. But in this case packet length should not change. Instead, call skb_reserve, which moves both skb->data and skb->tail back, without changing length. Fixes: b84bbaf7a6c8 ("packet: in packet_snd start writing at link layer allocation") Reported-by: Tariq Toukan Signed-off-by: Willem de Bruijn Acked-by: Soheil Hassas Yeganeh Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/packet/af_packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 2c22c2cf922d..2c4a47f29f36 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2918,7 +2918,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) if (unlikely(offset < 0)) goto out_free; } else if (reserve) { - skb_push(skb, reserve); + skb_reserve(skb, -reserve); } /* Returns -EFAULT on error */ -- GitLab From 46ad4d8ba44848bda813f114fe8551d7cd8c9bc5 Mon Sep 17 00:00:00 2001 From: Shahed Shaikh Date: Mon, 21 May 2018 12:31:47 -0700 Subject: [PATCH 094/604] qed: Fix mask for physical address in ILT entry [ Upstream commit fdd13dd350dda1826579eb5c333d76b14513b812 ] ILT entry requires 12 bit right shifted physical address. Existing mask for ILT entry of physical address i.e. ILT_ENTRY_PHY_ADDR_MASK is not sufficient to handle 64bit address because upper 8 bits of 64 bit address were getting masked which resulted in completer abort error on PCIe bus due to invalid address. Fix that mask to handle 64bit physical address. Fixes: fe56b9e6a8d9 ("qed: Add module with basic common support") Signed-off-by: Shahed Shaikh Signed-off-by: Ariel Elior Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/qed/qed_cxt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c index 457e30427535..f1956c4d02a0 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c @@ -54,7 +54,7 @@ #define ILT_CFG_REG(cli, reg) PSWRQ2_REG_ ## cli ## _ ## reg ## _RT_OFFSET /* ILT entry structure */ -#define ILT_ENTRY_PHY_ADDR_MASK 0x000FFFFFFFFFFFULL +#define ILT_ENTRY_PHY_ADDR_MASK (~0ULL >> 12) #define ILT_ENTRY_PHY_ADDR_SHIFT 0 #define ILT_ENTRY_VALID_MASK 0x1ULL #define ILT_ENTRY_VALID_SHIFT 52 -- GitLab From 2ed49aa1a49a3494de84041f087bcbce57a929f8 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Tue, 5 Jun 2018 12:16:58 +0800 Subject: [PATCH 095/604] sctp: not allow transport timeout value less than HZ/5 for hb_timer [ Upstream commit 1d88ba1ebb2763aa86172cd7ca05dedbeccc0d35 ] syzbot reported a rcu_sched self-detected stall on CPU which is caused by too small value set on rto_min with SCTP_RTOINFO sockopt. With this value, hb_timer will get stuck there, as in its timer handler it starts this timer again with this value, then goes to the timer handler again. This problem is there since very beginning, and thanks to Eric for the reproducer shared from a syzbot mail. This patch fixes it by not allowing sctp_transport_timeout to return a smaller value than HZ/5 for hb_timer, which is based on TCP's min rto. Note that it doesn't fix this issue by limiting rto_min, as some users are still using small rto and no proper value was found for it yet. Reported-by: syzbot+3dcd59a1f907245f891f@syzkaller.appspotmail.com Suggested-by: Marcelo Ricardo Leitner Signed-off-by: Xin Long Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/transport.c b/net/sctp/transport.c index ce54dce13ddb..03d71cd97ec0 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -608,7 +608,7 @@ unsigned long sctp_transport_timeout(struct sctp_transport *trans) trans->state != SCTP_PF) timeout += trans->hbinterval; - return timeout; + return max_t(unsigned long, timeout, HZ / 5); } /* Reset transport variables to their initial values */ -- GitLab From 3ff7364bb06ea807d8ea73206b1b5ec3b0e8a4a9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 4 Jun 2018 17:46:01 +0300 Subject: [PATCH 096/604] team: use netdev_features_t instead of u32 [ Upstream commit 25ea66544bfd1d9df1b7e1502f8717e85fa1e6e6 ] This code was introduced in 2011 around the same time that we made netdev_features_t a u64 type. These days a u32 is not big enough to hold all the potential features. Signed-off-by: Dan Carpenter Acked-by: Jiri Pirko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/team/team.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 36963685d42a..f9ec00981b1e 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1004,7 +1004,8 @@ static void team_port_disable(struct team *team, static void ___team_compute_features(struct team *team) { struct team_port *port; - u32 vlan_features = TEAM_VLAN_FEATURES & NETIF_F_ALL_FOR_ALL; + netdev_features_t vlan_features = TEAM_VLAN_FEATURES & + NETIF_F_ALL_FOR_ALL; netdev_features_t enc_features = TEAM_ENC_FEATURES; unsigned short max_hard_header_len = ETH_HLEN; unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE | -- GitLab From f833209e15bd6cf066e731463308f0058736a74b Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Tue, 22 May 2018 19:58:57 +0800 Subject: [PATCH 097/604] vhost: synchronize IOTLB message with dev cleanup [ Upstream commit 1b15ad683ab42a203f98b67045b40720e99d0e9a ] DaeRyong Jeong reports a race between vhost_dev_cleanup() and vhost_process_iotlb_msg(): Thread interleaving: CPU0 (vhost_process_iotlb_msg) CPU1 (vhost_dev_cleanup) (In the case of both VHOST_IOTLB_UPDATE and VHOST_IOTLB_INVALIDATE) ===== ===== vhost_umem_clean(dev->iotlb); if (!dev->iotlb) { ret = -EFAULT; break; } dev->iotlb = NULL; The reason is we don't synchronize between them, fixing by protecting vhost_process_iotlb_msg() with dev mutex. Reported-by: DaeRyong Jeong Fixes: 6b1e6cc7855b0 ("vhost: new device IOTLB API") Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/vhost/vhost.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index fce49ebc575d..c81bc4efe1a6 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -938,6 +938,7 @@ int vhost_process_iotlb_msg(struct vhost_dev *dev, { int ret = 0; + mutex_lock(&dev->mutex); vhost_dev_lock_vqs(dev); switch (msg->type) { case VHOST_IOTLB_UPDATE: @@ -967,6 +968,8 @@ int vhost_process_iotlb_msg(struct vhost_dev *dev, } vhost_dev_unlock_vqs(dev); + mutex_unlock(&dev->mutex); + return ret; } ssize_t vhost_chr_write_iter(struct vhost_dev *dev, -- GitLab From 869584ef0984bd88c25a0acd4757b80df7050a47 Mon Sep 17 00:00:00 2001 From: Stephen Suryaputra Date: Fri, 1 Jun 2018 00:05:21 -0400 Subject: [PATCH 098/604] vrf: check the original netdevice for generating redirect [ Upstream commit 2f17becfbea5e9a0529b51da7345783e96e69516 ] Use the right device to determine if redirect should be sent especially when using vrf. Same as well as when sending the redirect. Signed-off-by: Stephen Suryaputra Acked-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_output.c | 3 ++- net/ipv6/ndisc.c | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index e8560031a0be..eb9046eae581 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -487,7 +487,8 @@ int ip6_forward(struct sk_buff *skb) send redirects to source routed frames. We don't send redirects to frames decapsulated from IPsec. */ - if (skb->dev == dst->dev && opt->srcrt == 0 && !skb_sec_path(skb)) { + if (IP6CB(skb)->iif == dst->dev->ifindex && + opt->srcrt == 0 && !skb_sec_path(skb)) { struct in6_addr *target = NULL; struct inet_peer *peer; struct rt6_info *rt; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 3fe80e104b58..21f3bf2125f4 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1538,6 +1538,12 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) ops_data_buf[NDISC_OPS_REDIRECT_DATA_SPACE], *ops_data = NULL; bool ret; + if (netif_is_l3_master(skb->dev)) { + dev = __dev_get_by_index(dev_net(skb->dev), IPCB(skb)->iif); + if (!dev) + return; + } + if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) { ND_PRINTK(2, warn, "Redirect: no link-local address on %s\n", dev->name); -- GitLab From 1f19dd9d09c4fd1e9008c95852065789b9691a2a Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Wed, 23 May 2018 10:41:59 +0300 Subject: [PATCH 099/604] net/mlx4: Fix irq-unsafe spinlock usage [ Upstream commit d546b67cda015fb92bfee93d5dc0ceadb91deaee ] spin_lock/unlock was used instead of spin_un/lock_irq in a procedure used in process space, on a spinlock which can be grabbed in an interrupt. This caused the stack trace below to be displayed (on kernel 4.17.0-rc1 compiled with Lock Debugging enabled): [ 154.661474] WARNING: SOFTIRQ-safe -> SOFTIRQ-unsafe lock order detected [ 154.668909] 4.17.0-rc1-rdma_rc_mlx+ #3 Tainted: G I [ 154.675856] ----------------------------------------------------- [ 154.682706] modprobe/10159 [HC0[0]:SC0[0]:HE0:SE1] is trying to acquire: [ 154.690254] 00000000f3b0e495 (&(&qp_table->lock)->rlock){+.+.}, at: mlx4_qp_remove+0x20/0x50 [mlx4_core] [ 154.700927] and this task is already holding: [ 154.707461] 0000000094373b5d (&(&cq->lock)->rlock/1){....}, at: destroy_qp_common+0x111/0x560 [mlx4_ib] [ 154.718028] which would create a new lock dependency: [ 154.723705] (&(&cq->lock)->rlock/1){....} -> (&(&qp_table->lock)->rlock){+.+.} [ 154.731922] but this new dependency connects a SOFTIRQ-irq-safe lock: [ 154.740798] (&(&cq->lock)->rlock){..-.} [ 154.740800] ... which became SOFTIRQ-irq-safe at: [ 154.752163] _raw_spin_lock_irqsave+0x3e/0x50 [ 154.757163] mlx4_ib_poll_cq+0x36/0x900 [mlx4_ib] [ 154.762554] ipoib_tx_poll+0x4a/0xf0 [ib_ipoib] ... to a SOFTIRQ-irq-unsafe lock: [ 154.815603] (&(&qp_table->lock)->rlock){+.+.} [ 154.815604] ... which became SOFTIRQ-irq-unsafe at: [ 154.827718] ... [ 154.827720] _raw_spin_lock+0x35/0x50 [ 154.833912] mlx4_qp_lookup+0x1e/0x50 [mlx4_core] [ 154.839302] mlx4_flow_attach+0x3f/0x3d0 [mlx4_core] Since mlx4_qp_lookup() is called only in process space, we can simply replace the spin_un/lock calls with spin_un/lock_irq calls. Fixes: 6dc06c08bef1 ("net/mlx4: Fix the check in attaching steering rules") 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/qp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c index 474ff36b9755..71578d48efbc 100644 --- a/drivers/net/ethernet/mellanox/mlx4/qp.c +++ b/drivers/net/ethernet/mellanox/mlx4/qp.c @@ -392,11 +392,11 @@ struct mlx4_qp *mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn) struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; struct mlx4_qp *qp; - spin_lock(&qp_table->lock); + spin_lock_irq(&qp_table->lock); qp = __mlx4_qp_lookup(dev, qpn); - spin_unlock(&qp_table->lock); + spin_unlock_irq(&qp_table->lock); return qp; } -- GitLab From c591536e366109c473911d3d61582121220f5676 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 5 Jun 2018 09:25:19 -0700 Subject: [PATCH 100/604] rtnetlink: validate attributes in do_setlink() [ Upstream commit 644c7eebbfd59e72982d11ec6cc7d39af12450ae ] It seems that rtnl_group_changelink() can call do_setlink while a prior call to validate_linkmsg(dev = NULL, ...) could not validate IFLA_ADDRESS / IFLA_BROADCAST Make sure do_setlink() calls validate_linkmsg() instead of letting its callers having this responsibility. With help from Dmitry Vyukov, thanks a lot ! BUG: KMSAN: uninit-value in is_valid_ether_addr include/linux/etherdevice.h:199 [inline] BUG: KMSAN: uninit-value in eth_prepare_mac_addr_change net/ethernet/eth.c:275 [inline] BUG: KMSAN: uninit-value in eth_mac_addr+0x203/0x2b0 net/ethernet/eth.c:308 CPU: 1 PID: 8695 Comm: syz-executor3 Not tainted 4.17.0-rc5+ #103 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+0x149/0x260 mm/kmsan/kmsan.c:1084 __msan_warning_32+0x6e/0xc0 mm/kmsan/kmsan_instr.c:686 is_valid_ether_addr include/linux/etherdevice.h:199 [inline] eth_prepare_mac_addr_change net/ethernet/eth.c:275 [inline] eth_mac_addr+0x203/0x2b0 net/ethernet/eth.c:308 dev_set_mac_address+0x261/0x530 net/core/dev.c:7157 do_setlink+0xbc3/0x5fc0 net/core/rtnetlink.c:2317 rtnl_group_changelink net/core/rtnetlink.c:2824 [inline] rtnl_newlink+0x1fe9/0x37a0 net/core/rtnetlink.c:2976 rtnetlink_rcv_msg+0xa32/0x1560 net/core/rtnetlink.c:4646 netlink_rcv_skb+0x378/0x600 net/netlink/af_netlink.c:2448 rtnetlink_rcv+0x50/0x60 net/core/rtnetlink.c:4664 netlink_unicast_kernel net/netlink/af_netlink.c:1310 [inline] netlink_unicast+0x1678/0x1750 net/netlink/af_netlink.c:1336 netlink_sendmsg+0x104f/0x1350 net/netlink/af_netlink.c:1901 sock_sendmsg_nosec net/socket.c:629 [inline] sock_sendmsg net/socket.c:639 [inline] ___sys_sendmsg+0xec0/0x1310 net/socket.c:2117 __sys_sendmsg net/socket.c:2155 [inline] __do_sys_sendmsg net/socket.c:2164 [inline] __se_sys_sendmsg net/socket.c:2162 [inline] __x64_sys_sendmsg+0x331/0x460 net/socket.c:2162 do_syscall_64+0x152/0x230 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x44/0xa9 RIP: 0033:0x455a09 RSP: 002b:00007fc07480ec68 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00007fc07480f6d4 RCX: 0000000000455a09 RDX: 0000000000000000 RSI: 00000000200003c0 RDI: 0000000000000014 RBP: 000000000072bea0 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00000000ffffffff R13: 00000000000005d0 R14: 00000000006fdc20 R15: 0000000000000000 Uninit was stored to memory at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:279 [inline] kmsan_save_stack mm/kmsan/kmsan.c:294 [inline] kmsan_internal_chain_origin+0x12b/0x210 mm/kmsan/kmsan.c:685 kmsan_memcpy_origins+0x11d/0x170 mm/kmsan/kmsan.c:527 __msan_memcpy+0x109/0x160 mm/kmsan/kmsan_instr.c:478 do_setlink+0xb84/0x5fc0 net/core/rtnetlink.c:2315 rtnl_group_changelink net/core/rtnetlink.c:2824 [inline] rtnl_newlink+0x1fe9/0x37a0 net/core/rtnetlink.c:2976 rtnetlink_rcv_msg+0xa32/0x1560 net/core/rtnetlink.c:4646 netlink_rcv_skb+0x378/0x600 net/netlink/af_netlink.c:2448 rtnetlink_rcv+0x50/0x60 net/core/rtnetlink.c:4664 netlink_unicast_kernel net/netlink/af_netlink.c:1310 [inline] netlink_unicast+0x1678/0x1750 net/netlink/af_netlink.c:1336 netlink_sendmsg+0x104f/0x1350 net/netlink/af_netlink.c:1901 sock_sendmsg_nosec net/socket.c:629 [inline] sock_sendmsg net/socket.c:639 [inline] ___sys_sendmsg+0xec0/0x1310 net/socket.c:2117 __sys_sendmsg net/socket.c:2155 [inline] __do_sys_sendmsg net/socket.c:2164 [inline] __se_sys_sendmsg net/socket.c:2162 [inline] __x64_sys_sendmsg+0x331/0x460 net/socket.c:2162 do_syscall_64+0x152/0x230 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:279 [inline] kmsan_internal_poison_shadow+0xb8/0x1b0 mm/kmsan/kmsan.c:189 kmsan_kmalloc+0x94/0x100 mm/kmsan/kmsan.c:315 kmsan_slab_alloc+0x10/0x20 mm/kmsan/kmsan.c:322 slab_post_alloc_hook mm/slab.h:446 [inline] slab_alloc_node mm/slub.c:2753 [inline] __kmalloc_node_track_caller+0xb32/0x11b0 mm/slub.c:4395 __kmalloc_reserve net/core/skbuff.c:138 [inline] __alloc_skb+0x2cb/0x9e0 net/core/skbuff.c:206 alloc_skb include/linux/skbuff.h:988 [inline] netlink_alloc_large_skb net/netlink/af_netlink.c:1182 [inline] netlink_sendmsg+0x76e/0x1350 net/netlink/af_netlink.c:1876 sock_sendmsg_nosec net/socket.c:629 [inline] sock_sendmsg net/socket.c:639 [inline] ___sys_sendmsg+0xec0/0x1310 net/socket.c:2117 __sys_sendmsg net/socket.c:2155 [inline] __do_sys_sendmsg net/socket.c:2164 [inline] __se_sys_sendmsg net/socket.c:2162 [inline] __x64_sys_sendmsg+0x331/0x460 net/socket.c:2162 do_syscall_64+0x152/0x230 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Fixes: e7ed828f10bd ("netlink: support setting devgroup parameters") Signed-off-by: Eric Dumazet Reported-by: syzbot Cc: Dmitry Vyukov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/rtnetlink.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index c2339b865164..f3a0ad14b454 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1914,6 +1914,10 @@ static int do_setlink(const struct sk_buff *skb, const struct net_device_ops *ops = dev->netdev_ops; int err; + err = validate_linkmsg(dev, tb); + if (err < 0) + return err; + if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) { struct net *net = rtnl_link_get_net(dev_net(dev), tb); if (IS_ERR(net)) { @@ -2234,10 +2238,6 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh) goto errout; } - err = validate_linkmsg(dev, tb); - if (err < 0) - goto errout; - err = do_setlink(skb, dev, ifm, tb, ifname, 0); errout: return err; -- GitLab From 0e0a027873cf3c9abdbb5dcbdbcbcacccdba69d7 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 22 May 2018 17:04:49 -0700 Subject: [PATCH 101/604] net: phy: broadcom: Fix bcm_write_exp() [ Upstream commit 79fb218d97980d4fee9a64f4c8ff05289364ba25 ] On newer PHYs, we need to select the expansion register to write with setting bits [11:8] to 0xf. This was done correctly by bcm7xxx.c prior to being migrated to generic code under bcm-phy-lib.c which unfortunately used the older implementation from the BCM54xx days. Fix this by creating an inline stub: bcm_write_exp_sel() which adds the correct value (MII_BCM54XX_EXP_SEL_ER) and update both the Cygnus PHY and BCM7xxx PHY drivers which require setting these bits. broadcom.c is unchanged because some PHYs even use a different selector method, so let them specify it directly (e.g: SerDes secondary selector). Fixes: a1cba5613edf ("net: phy: Add Broadcom phy library for common interfaces") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/bcm-cygnus.c | 6 +++--- drivers/net/phy/bcm-phy-lib.h | 7 +++++++ drivers/net/phy/bcm7xxx.c | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/bcm-cygnus.c b/drivers/net/phy/bcm-cygnus.c index 49bbc6826883..9a7dca2bb618 100644 --- a/drivers/net/phy/bcm-cygnus.c +++ b/drivers/net/phy/bcm-cygnus.c @@ -61,17 +61,17 @@ static int bcm_cygnus_afe_config(struct phy_device *phydev) return rc; /* make rcal=100, since rdb default is 000 */ - rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB1, 0x10); + rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB1, 0x10); if (rc < 0) return rc; /* CORE_EXPB0, Reset R_CAL/RC_CAL Engine */ - rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB0, 0x10); + rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x10); if (rc < 0) return rc; /* CORE_EXPB0, Disable Reset R_CAL/RC_CAL Engine */ - rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB0, 0x00); + rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x00); return 0; } diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h index b2091c88b44d..ce16b26d49ff 100644 --- a/drivers/net/phy/bcm-phy-lib.h +++ b/drivers/net/phy/bcm-phy-lib.h @@ -14,11 +14,18 @@ #ifndef _LINUX_BCM_PHY_LIB_H #define _LINUX_BCM_PHY_LIB_H +#include #include int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val); int bcm_phy_read_exp(struct phy_device *phydev, u16 reg); +static inline int bcm_phy_write_exp_sel(struct phy_device *phydev, + u16 reg, u16 val) +{ + return bcm_phy_write_exp(phydev, reg | MII_BCM54XX_EXP_SEL_ER, val); +} + int bcm_phy_write_misc(struct phy_device *phydev, u16 reg, u16 chl, u16 value); int bcm_phy_read_misc(struct phy_device *phydev, diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c index 9636da0b6efc..caff474d2ee2 100644 --- a/drivers/net/phy/bcm7xxx.c +++ b/drivers/net/phy/bcm7xxx.c @@ -48,10 +48,10 @@ static void r_rc_cal_reset(struct phy_device *phydev) { /* Reset R_CAL/RC_CAL Engine */ - bcm_phy_write_exp(phydev, 0x00b0, 0x0010); + bcm_phy_write_exp_sel(phydev, 0x00b0, 0x0010); /* Disable Reset R_AL/RC_CAL Engine */ - bcm_phy_write_exp(phydev, 0x00b0, 0x0000); + bcm_phy_write_exp_sel(phydev, 0x00b0, 0x0000); } static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev) -- GitLab From 5300a1c7ecc2d676473b6ead6c5d8cbd5922dfa1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 5 Jun 2018 06:06:19 -0700 Subject: [PATCH 102/604] net: metrics: add proper netlink validation [ Upstream commit 5b5e7a0de2bbf2a1afcd9f49e940010e9fb80d53 ] Before using nla_get_u32(), better make sure the attribute is of the proper size. Code recently was changed, but bug has been there from beginning of git. BUG: KMSAN: uninit-value in rtnetlink_put_metrics+0x553/0x960 net/core/rtnetlink.c:746 CPU: 1 PID: 14139 Comm: syz-executor6 Not tainted 4.17.0-rc5+ #103 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+0x149/0x260 mm/kmsan/kmsan.c:1084 __msan_warning_32+0x6e/0xc0 mm/kmsan/kmsan_instr.c:686 rtnetlink_put_metrics+0x553/0x960 net/core/rtnetlink.c:746 fib_dump_info+0xc42/0x2190 net/ipv4/fib_semantics.c:1361 rtmsg_fib+0x65f/0x8c0 net/ipv4/fib_semantics.c:419 fib_table_insert+0x2314/0x2b50 net/ipv4/fib_trie.c:1287 inet_rtm_newroute+0x210/0x340 net/ipv4/fib_frontend.c:779 rtnetlink_rcv_msg+0xa32/0x1560 net/core/rtnetlink.c:4646 netlink_rcv_skb+0x378/0x600 net/netlink/af_netlink.c:2448 rtnetlink_rcv+0x50/0x60 net/core/rtnetlink.c:4664 netlink_unicast_kernel net/netlink/af_netlink.c:1310 [inline] netlink_unicast+0x1678/0x1750 net/netlink/af_netlink.c:1336 netlink_sendmsg+0x104f/0x1350 net/netlink/af_netlink.c:1901 sock_sendmsg_nosec net/socket.c:629 [inline] sock_sendmsg net/socket.c:639 [inline] ___sys_sendmsg+0xec0/0x1310 net/socket.c:2117 __sys_sendmsg net/socket.c:2155 [inline] __do_sys_sendmsg net/socket.c:2164 [inline] __se_sys_sendmsg net/socket.c:2162 [inline] __x64_sys_sendmsg+0x331/0x460 net/socket.c:2162 do_syscall_64+0x152/0x230 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x44/0xa9 RIP: 0033:0x455a09 RSP: 002b:00007faae5fd8c68 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00007faae5fd96d4 RCX: 0000000000455a09 RDX: 0000000000000000 RSI: 0000000020000000 RDI: 0000000000000013 RBP: 000000000072bea0 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00000000ffffffff R13: 00000000000005d0 R14: 00000000006fdc20 R15: 0000000000000000 Uninit was stored to memory at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:279 [inline] kmsan_save_stack mm/kmsan/kmsan.c:294 [inline] kmsan_internal_chain_origin+0x12b/0x210 mm/kmsan/kmsan.c:685 __msan_chain_origin+0x69/0xc0 mm/kmsan/kmsan_instr.c:529 fib_convert_metrics net/ipv4/fib_semantics.c:1056 [inline] fib_create_info+0x2d46/0x9dc0 net/ipv4/fib_semantics.c:1150 fib_table_insert+0x3e4/0x2b50 net/ipv4/fib_trie.c:1146 inet_rtm_newroute+0x210/0x340 net/ipv4/fib_frontend.c:779 rtnetlink_rcv_msg+0xa32/0x1560 net/core/rtnetlink.c:4646 netlink_rcv_skb+0x378/0x600 net/netlink/af_netlink.c:2448 rtnetlink_rcv+0x50/0x60 net/core/rtnetlink.c:4664 netlink_unicast_kernel net/netlink/af_netlink.c:1310 [inline] netlink_unicast+0x1678/0x1750 net/netlink/af_netlink.c:1336 netlink_sendmsg+0x104f/0x1350 net/netlink/af_netlink.c:1901 sock_sendmsg_nosec net/socket.c:629 [inline] sock_sendmsg net/socket.c:639 [inline] ___sys_sendmsg+0xec0/0x1310 net/socket.c:2117 __sys_sendmsg net/socket.c:2155 [inline] __do_sys_sendmsg net/socket.c:2164 [inline] __se_sys_sendmsg net/socket.c:2162 [inline] __x64_sys_sendmsg+0x331/0x460 net/socket.c:2162 do_syscall_64+0x152/0x230 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:279 [inline] kmsan_internal_poison_shadow+0xb8/0x1b0 mm/kmsan/kmsan.c:189 kmsan_kmalloc+0x94/0x100 mm/kmsan/kmsan.c:315 kmsan_slab_alloc+0x10/0x20 mm/kmsan/kmsan.c:322 slab_post_alloc_hook mm/slab.h:446 [inline] slab_alloc_node mm/slub.c:2753 [inline] __kmalloc_node_track_caller+0xb32/0x11b0 mm/slub.c:4395 __kmalloc_reserve net/core/skbuff.c:138 [inline] __alloc_skb+0x2cb/0x9e0 net/core/skbuff.c:206 alloc_skb include/linux/skbuff.h:988 [inline] netlink_alloc_large_skb net/netlink/af_netlink.c:1182 [inline] netlink_sendmsg+0x76e/0x1350 net/netlink/af_netlink.c:1876 sock_sendmsg_nosec net/socket.c:629 [inline] sock_sendmsg net/socket.c:639 [inline] ___sys_sendmsg+0xec0/0x1310 net/socket.c:2117 __sys_sendmsg net/socket.c:2155 [inline] __do_sys_sendmsg net/socket.c:2164 [inline] __se_sys_sendmsg net/socket.c:2162 [inline] __x64_sys_sendmsg+0x331/0x460 net/socket.c:2162 do_syscall_64+0x152/0x230 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Fixes: a919525ad832 ("net: Move fib_convert_metrics to metrics file") Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Reported-by: syzbot Cc: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/fib_semantics.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index e1be24416c0e..d476b7950adf 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -979,6 +979,8 @@ fib_convert_metrics(struct fib_info *fi, const struct fib_config *cfg) if (val == TCP_CA_UNSPEC) return -EINVAL; } else { + if (nla_len(nla) != sizeof(u32)) + return false; val = nla_get_u32(nla); } if (type == RTAX_ADVMSS && val > 65535 - 40) -- GitLab From 02136f325f84b5dbd5cab556daae15b25948c774 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 12 Jun 2018 01:14:34 +0100 Subject: [PATCH 103/604] KVM: VMX: Expose SSBD properly to guests, 4.9 supplement Fix an additional misuse of X86_FEATURE_SSBD in guest_cpuid_has_spec_ctrl(). This function was introduced in the backport of SSBD support to 4.9 and is not present upstream, so it was not fixed by commit 43462d908821 "KVM: VMX: Expose SSBD properly to guests." Fixes: 52817587e706 ("x86/cpufeatures: Disentangle SSBD enumeration") Signed-off-by: Ben Hutchings Cc: Konrad Rzeszutek Wilk Cc: Thomas Gleixner Cc: David Woodhouse Cc: kvm@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/cpuid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index c38369781239..8a841b9d8f84 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h @@ -179,7 +179,7 @@ static inline bool guest_cpuid_has_spec_ctrl(struct kvm_vcpu *vcpu) if (best && (best->ebx & bit(X86_FEATURE_AMD_IBRS))) return true; best = kvm_find_cpuid_entry(vcpu, 7, 0); - return best && (best->edx & (bit(X86_FEATURE_SPEC_CTRL) | bit(X86_FEATURE_SSBD))); + return best && (best->edx & (bit(X86_FEATURE_SPEC_CTRL) | bit(X86_FEATURE_SPEC_CTRL_SSBD))); } static inline bool guest_cpuid_has_arch_capabilities(struct kvm_vcpu *vcpu) -- GitLab From e1fba17e26f08a142b4cdf5c74a2113e7f895daa Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 22 Feb 2018 16:56:16 +0100 Subject: [PATCH 104/604] dm bufio: avoid false-positive Wmaybe-uninitialized warning commit 590347e4000356f55eb10b03ced2686bd74dab40 upstream. gcc-6.3 and earlier show a new warning after a seemingly unrelated change to the arm64 PAGE_KERNEL definition: In file included from drivers/md/dm-bufio.c:14:0: drivers/md/dm-bufio.c: In function 'alloc_buffer': include/linux/sched/mm.h:182:56: warning: 'noio_flag' may be used uninitialized in this function [-Wmaybe-uninitialized] current->flags = (current->flags & ~PF_MEMALLOC_NOIO) | flags; ^ The same warning happened earlier on linux-3.18 for MIPS and I did a workaround for that, but now it's come back. gcc-7 and newer are apparently smart enough to figure this out, and other architectures don't show it, so the best I could come up with is to rework the caller slightly in a way that makes it obvious enough to all arm64 compilers what is happening here. Fixes: 41acec624087 ("arm64: kpti: Make use of nG dependent on arm64_kernel_unmapped_at_el0()") Link: https://patchwork.kernel.org/patch/9692829/ Cc: stable@vger.kernel.org Signed-off-by: Arnd Bergmann [snitzer: moved declarations inside conditional, altered vmalloc return] Signed-off-by: Mike Snitzer [nc: Backport to 4.9, adjust context for lack of 19809c2da28a] Signed-off-by: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-bufio.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 3ec647e8b9c6..35fd57fdeba9 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -373,9 +373,6 @@ static void __cache_size_refresh(void) static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask, enum data_mode *data_mode) { - unsigned noio_flag; - void *ptr; - if (c->block_size <= DM_BUFIO_BLOCK_SIZE_SLAB_LIMIT) { *data_mode = DATA_MODE_SLAB; return kmem_cache_alloc(DM_BUFIO_CACHE(c), gfp_mask); @@ -399,16 +396,16 @@ static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask, * all allocations done by this process (including pagetables) are done * as if GFP_NOIO was specified. */ + if (gfp_mask & __GFP_NORETRY) { + unsigned noio_flag = memalloc_noio_save(); + void *ptr = __vmalloc(c->block_size, gfp_mask | __GFP_HIGHMEM, + PAGE_KERNEL); - if (gfp_mask & __GFP_NORETRY) - noio_flag = memalloc_noio_save(); - - ptr = __vmalloc(c->block_size, gfp_mask | __GFP_HIGHMEM, PAGE_KERNEL); - - if (gfp_mask & __GFP_NORETRY) memalloc_noio_restore(noio_flag); + return ptr; + } - return ptr; + return __vmalloc(c->block_size, gfp_mask | __GFP_HIGHMEM, PAGE_KERNEL); } /* -- GitLab From 23873aedff967436b59e478d75ca3317e4f0dfc5 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Mon, 24 Jul 2017 18:34:14 -0500 Subject: [PATCH 105/604] objtool: Fix gcov check for older versions of GCC commit 867ac9d737094e46a6c33213f16dd1ec9e8bd5d5 upstream. Objtool tries to silence 'unreachable instruction' warnings when it detects gcov is enabled, because gcov produces a lot of unreachable instructions and they don't really matter. However, the 0-day bot is still reporting some unreachable instruction warnings with CONFIG_GCOV_KERNEL=y on GCC 4.6.4. As it turns out, objtool's gcov detection doesn't work with older versions of GCC because they don't create a bunch of symbols with the 'gcov.' prefix like newer versions of GCC do. Move the gcov check out of objtool and instead just create a new '--no-unreachable' flag which can be passed in by the kernel Makefile when CONFIG_GCOV_KERNEL is defined. Also rename the 'nofp' variable to 'no_fp' for consistency with the new 'no_unreachable' variable. Reported-by: kbuild test robot Signed-off-by: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: 9cfffb116887 ("objtool: Skip all "unreachable instruction" warnings for gcov kernels") Link: http://lkml.kernel.org/r/c243dc78eb2ffdabb6e927844dea39b6033cd395.1500939244.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar [just Makefile.build as the other parts of this patch already applied - gregkh] Signed-off-by: Greg Kroah-Hartman --- scripts/Makefile.build | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 7675d11ee65e..abfd4f4b66dd 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -253,6 +253,9 @@ objtool_args = check ifndef CONFIG_FRAME_POINTER objtool_args += --no-fp endif +ifdef CONFIG_GCOV_KERNEL +objtool_args += --no-unreachable +endif # 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory # 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file -- GitLab From cd4f9f23853516102fdc5abf0c8851c646ce6471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20M=C3=BCller?= Date: Sat, 9 Jun 2018 13:42:05 +0200 Subject: [PATCH 106/604] complete e390f9a port for v4.9.106 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit objtool ports introduced in v4.9.106 were not totally complete. Therefore they resulted in issues like: module: overflow in relocation type 10 val XXXXXXXXXXX ‘usbcore’ likely not compiled with -mcmodel=kernel module: overflow in relocation type 10 val XXXXXXXXXXX ‘scsi_mod’ likely not compiled with -mcmodel=kernel Missing part was the complete backport of commit e390f9a. Original notes by Josh Poimboeuf: The '__unreachable' and '__func_stack_frame_non_standard' sections are only used at compile time. They're discarded for vmlinux but they should also be discarded for modules. Since this is a recurring pattern, prefix the section names with ".discard.". It's a nice convention and vmlinux.lds.h already discards such sections. Also remove the 'a' (allocatable) flag from the __unreachable section since it doesn't make sense for a discarded section. Signed-off-by: Philip Müller Fixes: d1091c7fa3d5 ("objtool: Improve detection of BUG() and other dead ends") Link: https://gitlab.manjaro.org/packages/core/linux49/issues/2 Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/vmlinux.lds.S | 2 -- include/linux/compiler-gcc.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 4ef267fb635a..e783a5daaab2 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -352,8 +352,6 @@ SECTIONS DISCARDS /DISCARD/ : { *(.eh_frame) - *(__func_stack_frame_non_standard) - *(__unreachable) } } diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index 2214b2f9c73c..ad793c69cc46 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -206,7 +206,7 @@ #ifdef CONFIG_STACK_VALIDATION #define annotate_unreachable() ({ \ asm("1:\t\n" \ - ".pushsection __unreachable, \"a\"\t\n" \ + ".pushsection .discard.unreachable\t\n" \ ".long 1b\t\n" \ ".popsection\t\n"); \ }) -- GitLab From 4f42dc62be92afe9863bf2598e6b0d637430f74f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 13 Jun 2018 16:16:44 +0200 Subject: [PATCH 107/604] Linux 4.9.108 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ac30e448e0a5..1fa9daf219c4 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 107 +SUBLEVEL = 108 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From 47a6aa5975a0ea4e650091cd5105ff29ca353459 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 4 Oct 2016 20:34:31 -0400 Subject: [PATCH 108/604] x86/fpu: Hard-disable lazy FPU mode commit ca6938a1cd8a1c5e861a99b67f84ac166fc2b9e7 upstream. Since commit: 58122bf1d856 ("x86/fpu: Default eagerfpu=on on all CPUs") ... in Linux 4.6, eager FPU mode has been the default on all x86 systems, and no one has reported any regressions. This patch removes the ability to enable lazy mode: use_eager_fpu() becomes "return true" and all of the FPU mode selection machinery is removed. Signed-off-by: Andy Lutomirski Signed-off-by: Rik van Riel Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Quentin Casasnovas Cc: Thomas Gleixner Cc: pbonzini@redhat.com Link: http://lkml.kernel.org/r/1475627678-20788-3-git-send-email-riel@redhat.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/cpufeatures.h | 2 +- arch/x86/include/asm/fpu/internal.h | 2 +- arch/x86/kernel/fpu/init.c | 91 +---------------------------- 3 files changed, 5 insertions(+), 90 deletions(-) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index c278f276c9b3..aea30afeddb8 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -104,7 +104,7 @@ #define X86_FEATURE_EXTD_APICID ( 3*32+26) /* has extended APICID (8 bits) */ #define X86_FEATURE_AMD_DCM ( 3*32+27) /* multi-node processor */ #define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */ -#define X86_FEATURE_EAGER_FPU ( 3*32+29) /* "eagerfpu" Non lazy FPU restore */ +/* free, was #define X86_FEATURE_EAGER_FPU ( 3*32+29) * "eagerfpu" Non lazy FPU restore */ #define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h index 2737366ea583..8852e3afa1ad 100644 --- a/arch/x86/include/asm/fpu/internal.h +++ b/arch/x86/include/asm/fpu/internal.h @@ -62,7 +62,7 @@ extern u64 fpu__get_supported_xfeatures_mask(void); */ static __always_inline __pure bool use_eager_fpu(void) { - return static_cpu_has(X86_FEATURE_EAGER_FPU); + return true; } static __always_inline __pure bool use_xsaveopt(void) diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index 6f0ab305dd5e..9f3657891b87 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c @@ -15,10 +15,7 @@ */ static void fpu__init_cpu_ctx_switch(void) { - if (!boot_cpu_has(X86_FEATURE_EAGER_FPU)) - stts(); - else - clts(); + clts(); } /* @@ -233,42 +230,6 @@ static void __init fpu__init_system_xstate_size_legacy(void) fpu_user_xstate_size = fpu_kernel_xstate_size; } -/* - * FPU context switching strategies: - * - * Against popular belief, we don't do lazy FPU saves, due to the - * task migration complications it brings on SMP - we only do - * lazy FPU restores. - * - * 'lazy' is the traditional strategy, which is based on setting - * CR0::TS to 1 during context-switch (instead of doing a full - * restore of the FPU state), which causes the first FPU instruction - * after the context switch (whenever it is executed) to fault - at - * which point we lazily restore the FPU state into FPU registers. - * - * Tasks are of course under no obligation to execute FPU instructions, - * so it can easily happen that another context-switch occurs without - * a single FPU instruction being executed. If we eventually switch - * back to the original task (that still owns the FPU) then we have - * not only saved the restores along the way, but we also have the - * FPU ready to be used for the original task. - * - * 'lazy' is deprecated because it's almost never a performance win - * and it's much more complicated than 'eager'. - * - * 'eager' switching is by default on all CPUs, there we switch the FPU - * state during every context switch, regardless of whether the task - * has used FPU instructions in that time slice or not. This is done - * because modern FPU context saving instructions are able to optimize - * state saving and restoration in hardware: they can detect both - * unused and untouched FPU state and optimize accordingly. - * - * [ Note that even in 'lazy' mode we might optimize context switches - * to use 'eager' restores, if we detect that a task is using the FPU - * frequently. See the fpu->counter logic in fpu/internal.h for that. ] - */ -static enum { ENABLE, DISABLE } eagerfpu = ENABLE; - /* * Find supported xfeatures based on cpu features and command-line input. * This must be called after fpu__init_parse_early_param() is called and @@ -276,40 +237,10 @@ static enum { ENABLE, DISABLE } eagerfpu = ENABLE; */ u64 __init fpu__get_supported_xfeatures_mask(void) { - /* Support all xfeatures known to us */ - if (eagerfpu != DISABLE) - return XCNTXT_MASK; - - /* Warning of xfeatures being disabled for no eagerfpu mode */ - if (xfeatures_mask & XFEATURE_MASK_EAGER) { - pr_err("x86/fpu: eagerfpu switching disabled, disabling the following xstate features: 0x%llx.\n", - xfeatures_mask & XFEATURE_MASK_EAGER); - } - - /* Return a mask that masks out all features requiring eagerfpu mode */ - return ~XFEATURE_MASK_EAGER; -} - -/* - * Disable features dependent on eagerfpu. - */ -static void __init fpu__clear_eager_fpu_features(void) -{ - setup_clear_cpu_cap(X86_FEATURE_MPX); + return XCNTXT_MASK; } -/* - * Pick the FPU context switching strategy: - * - * When eagerfpu is AUTO or ENABLE, we ensure it is ENABLE if either of - * the following is true: - * - * (1) the cpu has xsaveopt, as it has the optimization and doing eager - * FPU switching has a relatively low cost compared to a plain xsave; - * (2) the cpu has xsave features (e.g. MPX) that depend on eager FPU - * switching. Should the kernel boot with noxsaveopt, we support MPX - * with eager FPU switching at a higher cost. - */ +/* Legacy code to initialize eager fpu mode. */ static void __init fpu__init_system_ctx_switch(void) { static bool on_boot_cpu __initdata = 1; @@ -318,17 +249,6 @@ static void __init fpu__init_system_ctx_switch(void) on_boot_cpu = 0; WARN_ON_FPU(current->thread.fpu.fpstate_active); - - if (boot_cpu_has(X86_FEATURE_XSAVEOPT) && eagerfpu != DISABLE) - eagerfpu = ENABLE; - - if (xfeatures_mask & XFEATURE_MASK_EAGER) - eagerfpu = ENABLE; - - if (eagerfpu == ENABLE) - setup_force_cpu_cap(X86_FEATURE_EAGER_FPU); - - printk(KERN_INFO "x86/fpu: Using '%s' FPU context switches.\n", eagerfpu == ENABLE ? "eager" : "lazy"); } /* @@ -337,11 +257,6 @@ static void __init fpu__init_system_ctx_switch(void) */ static void __init fpu__init_parse_early_param(void) { - if (cmdline_find_option_bool(boot_command_line, "eagerfpu=off")) { - eagerfpu = DISABLE; - fpu__clear_eager_fpu_features(); - } - if (cmdline_find_option_bool(boot_command_line, "no387")) setup_clear_cpu_cap(X86_FEATURE_FPU); -- GitLab From c5b9d36f1e702911ab9724022c8f6c97adc37427 Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Mon, 27 Mar 2017 11:37:37 -0700 Subject: [PATCH 109/604] bonding: correctly update link status during mii-commit phase commit b5bf0f5b16b9c316c34df9f31d4be8729eb86845 upstream. bond_miimon_commit() marks the link UP after attempting to get the speed and duplex settings for the link. There is a possibility that bond_update_speed_duplex() could fail. This is another place where it could result into an inconsistent bonding link state. With this patch the link will be marked UP only if the speed and duplex values retrieved have sane values and processed further. Signed-off-by: Mahesh Bandewar Signed-off-by: David S. Miller Cc: Nate Clark Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 1a139d0f2232..349b3c26e9fa 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2140,7 +2140,12 @@ static void bond_miimon_commit(struct bonding *bond) continue; case BOND_LINK_UP: - bond_update_speed_duplex(slave); + if (bond_update_speed_duplex(slave)) { + netdev_warn(bond->dev, + "failed to get link speed/duplex for %s\n", + slave->dev->name); + continue; + } bond_set_slave_link_state(slave, BOND_LINK_UP, BOND_SLAVE_NOTIFY_NOW); slave->last_link_up = jiffies; -- GitLab From bc5ad405837a9e89595cd603a8d329ec9d96dde9 Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Mon, 3 Apr 2017 18:38:39 -0700 Subject: [PATCH 110/604] bonding: fix active-backup transition commit 3f3c278c94dd994fe0d9f21679ae19b9c0a55292 upstream. Earlier patch c4adfc822bf5 ("bonding: make speed, duplex setting consistent with link state") made an attempt to keep slave state consistent with speed and duplex settings. Unfortunately link-state transition is used to change the active link especially when used in conjunction with mii-mon. The above mentioned patch broke that logic. Also when speed and duplex settings for a link are updated during a link-event, the link-status should not be changed to invoke correct transition logic. This patch fixes this issue by moving the link-state update outside of the bond_update_speed_duplex() fn and to the places where this fn is called and update link-state selectively. Fixes: c4adfc822bf5 ("bonding: make speed, duplex setting consistent with link state") Signed-off-by: Mahesh Bandewar Reviewed-by: Andy Gospodarek Signed-off-by: David S. Miller Cc: Nate Clark Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 349b3c26e9fa..b020a0b6f25c 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -384,20 +384,15 @@ static int bond_update_speed_duplex(struct slave *slave) slave->duplex = DUPLEX_UNKNOWN; res = __ethtool_get_link_ksettings(slave_dev, &ecmd); - if (res < 0) { - slave->link = BOND_LINK_DOWN; + if (res < 0) return 1; - } - if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1)) { - slave->link = BOND_LINK_DOWN; + if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1)) return 1; - } switch (ecmd.base.duplex) { case DUPLEX_FULL: case DUPLEX_HALF: break; default: - slave->link = BOND_LINK_DOWN; return 1; } @@ -1536,7 +1531,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) new_slave->delay = 0; new_slave->link_failure_count = 0; - bond_update_speed_duplex(new_slave); + if (bond_update_speed_duplex(new_slave)) + new_slave->link = BOND_LINK_DOWN; new_slave->last_rx = jiffies - (msecs_to_jiffies(bond->params.arp_interval) + 1); @@ -2141,6 +2137,7 @@ static void bond_miimon_commit(struct bonding *bond) case BOND_LINK_UP: if (bond_update_speed_duplex(slave)) { + slave->link = BOND_LINK_DOWN; netdev_warn(bond->dev, "failed to get link speed/duplex for %s\n", slave->dev->name); -- GitLab From ae0c8eeb66045ea2e327b23d21788622ca510627 Mon Sep 17 00:00:00 2001 From: Andreas Born Date: Thu, 10 Aug 2017 06:41:44 +0200 Subject: [PATCH 111/604] bonding: require speed/duplex only for 802.3ad, alb and tlb commit ad729bc9acfb7c47112964b4877ef5404578ed13 upstream. The patch c4adfc822bf5 ("bonding: make speed, duplex setting consistent with link state") puts the link state to down if bond_update_speed_duplex() cannot retrieve speed and duplex settings. Assumably the patch was written with 802.3ad mode in mind which relies on link speed/duplex settings. For other modes like active-backup these settings are not required. Thus, only for these other modes, this patch reintroduces support for slaves that do not support reporting speed or duplex such as wireless devices. This fixes the regression reported in bug 196547 (https://bugzilla.kernel.org/show_bug.cgi?id=196547). Fixes: c4adfc822bf5 ("bonding: make speed, duplex setting consistent with link state") Signed-off-by: Andreas Born Acked-by: Mahesh Bandewar Signed-off-by: David S. Miller Cc: Nate Clark Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 6 ++++-- include/net/bonding.h | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index b020a0b6f25c..f5fcc0850dac 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1531,7 +1531,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) new_slave->delay = 0; new_slave->link_failure_count = 0; - if (bond_update_speed_duplex(new_slave)) + if (bond_update_speed_duplex(new_slave) && + bond_needs_speed_duplex(bond)) new_slave->link = BOND_LINK_DOWN; new_slave->last_rx = jiffies - @@ -2136,7 +2137,8 @@ static void bond_miimon_commit(struct bonding *bond) continue; case BOND_LINK_UP: - if (bond_update_speed_duplex(slave)) { + if (bond_update_speed_duplex(slave) && + bond_needs_speed_duplex(bond)) { slave->link = BOND_LINK_DOWN; netdev_warn(bond->dev, "failed to get link speed/duplex for %s\n", diff --git a/include/net/bonding.h b/include/net/bonding.h index 7734cc9c7d29..714428c54c68 100644 --- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -277,6 +277,11 @@ static inline bool bond_is_lb(const struct bonding *bond) BOND_MODE(bond) == BOND_MODE_ALB; } +static inline bool bond_needs_speed_duplex(const struct bonding *bond) +{ + return BOND_MODE(bond) == BOND_MODE_8023AD || bond_is_lb(bond); +} + static inline bool bond_is_nondyn_tlb(const struct bonding *bond) { return (BOND_MODE(bond) == BOND_MODE_TLB) && -- GitLab From b53761a18e71a5ce699c1e93d0f9a7c59b186f08 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 14 Sep 2017 13:54:39 -0400 Subject: [PATCH 112/604] nvme-pci: initialize queue memory before interrupts commit 161b8be2bd6abad250d4b3f674bdd5480f15beeb upstream. A spurious interrupt before the nvme driver has initialized the completion queue may inadvertently cause the driver to believe it has a completion to process. This may result in a NULL dereference since the nvmeq's tags are not set at this point. The patch initializes the host's CQ memory so that a spurious interrupt isn't mistaken for a real completion. Signed-off-by: Keith Busch Reviewed-by: Johannes Thumshirn Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/host/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 642ee00e9143..a55d112583bd 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1126,11 +1126,11 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) if (result < 0) goto release_cq; + nvme_init_queue(nvmeq, qid); result = queue_request_irq(nvmeq); if (result < 0) goto release_sq; - nvme_init_queue(nvmeq, qid); return result; release_sq: @@ -1248,6 +1248,7 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev) return result; nvmeq->cq_vector = 0; + nvme_init_queue(nvmeq, 0); result = queue_request_irq(nvmeq); if (result) { nvmeq->cq_vector = -1; @@ -1776,7 +1777,6 @@ static void nvme_reset_work(struct work_struct *work) if (result) goto out; - nvme_init_queue(dev->queues[0], 0); result = nvme_alloc_admin_tags(dev); if (result) goto out; -- GitLab From 142b79aa0ba6522c95d80a5cb053e843c98e8ae3 Mon Sep 17 00:00:00 2001 From: Kevin Easton Date: Sat, 7 Apr 2018 11:40:33 -0400 Subject: [PATCH 113/604] af_key: Always verify length of provided sadb_key commit 4b66af2d6356a00e94bcdea3e7fea324e8b5c6f4 upstream. Key extensions (struct sadb_key) include a user-specified number of key bits. The kernel uses that number to determine how much key data to copy out of the message in pfkey_msg2xfrm_state(). The length of the sadb_key message must be verified to be long enough, even in the case of SADB_X_AALG_NULL. Furthermore, the sadb_key_len value must be long enough to include both the key data and the struct sadb_key itself. Introduce a helper function verify_key_len(), and call it from parse_exthdrs() where other exthdr types are similarly checked for correctness. Signed-off-by: Kevin Easton Reported-by: syzbot+5022a34ca5a3d49b84223653fab632dfb7b4cf37@syzkaller.appspotmail.com Signed-off-by: Steffen Klassert Cc: Zubin Mithra Signed-off-by: Greg Kroah-Hartman --- net/key/af_key.c | 45 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/net/key/af_key.c b/net/key/af_key.c index 15150b412930..3ba903ff2bb0 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -437,6 +437,24 @@ static int verify_address_len(const void *p) return 0; } +static inline int sadb_key_len(const struct sadb_key *key) +{ + int key_bytes = DIV_ROUND_UP(key->sadb_key_bits, 8); + + return DIV_ROUND_UP(sizeof(struct sadb_key) + key_bytes, + sizeof(uint64_t)); +} + +static int verify_key_len(const void *p) +{ + const struct sadb_key *key = p; + + if (sadb_key_len(key) > key->sadb_key_len) + return -EINVAL; + + return 0; +} + static inline int pfkey_sec_ctx_len(const struct sadb_x_sec_ctx *sec_ctx) { return DIV_ROUND_UP(sizeof(struct sadb_x_sec_ctx) + @@ -533,16 +551,25 @@ static int parse_exthdrs(struct sk_buff *skb, const struct sadb_msg *hdr, void * return -EINVAL; if (ext_hdrs[ext_type-1] != NULL) return -EINVAL; - if (ext_type == SADB_EXT_ADDRESS_SRC || - ext_type == SADB_EXT_ADDRESS_DST || - ext_type == SADB_EXT_ADDRESS_PROXY || - ext_type == SADB_X_EXT_NAT_T_OA) { + switch (ext_type) { + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_ADDRESS_PROXY: + case SADB_X_EXT_NAT_T_OA: if (verify_address_len(p)) return -EINVAL; - } - if (ext_type == SADB_X_EXT_SEC_CTX) { + break; + case SADB_X_EXT_SEC_CTX: if (verify_sec_ctx_len(p)) return -EINVAL; + break; + case SADB_EXT_KEY_AUTH: + case SADB_EXT_KEY_ENCRYPT: + if (verify_key_len(p)) + return -EINVAL; + break; + default: + break; } ext_hdrs[ext_type-1] = (void *) p; } @@ -1111,14 +1138,12 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net, key = ext_hdrs[SADB_EXT_KEY_AUTH - 1]; if (key != NULL && sa->sadb_sa_auth != SADB_X_AALG_NULL && - ((key->sadb_key_bits+7) / 8 == 0 || - (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t))) + key->sadb_key_bits == 0) return ERR_PTR(-EINVAL); key = ext_hdrs[SADB_EXT_KEY_ENCRYPT-1]; if (key != NULL && sa->sadb_sa_encrypt != SADB_EALG_NULL && - ((key->sadb_key_bits+7) / 8 == 0 || - (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t))) + key->sadb_key_bits == 0) return ERR_PTR(-EINVAL); x = xfrm_state_alloc(net); -- GitLab From 077c9e26bb0b3ab72d987837d9297fefd7ec3cf4 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 4 Oct 2016 20:34:30 -0400 Subject: [PATCH 114/604] x86/crypto, x86/fpu: Remove X86_FEATURE_EAGER_FPU #ifdef from the crc32c code commit 02f39b2379fb81557ae864ec8f85421c0250c954 upstream. The crypto code was checking both use_eager_fpu() and defined(X86_FEATURE_EAGER_FPU). The latter was nonsensical, so remove it. This will avoid breakage when we remove X86_FEATURE_EAGER_FPU. Signed-off-by: Andy Lutomirski Signed-off-by: Rik van Riel Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Quentin Casasnovas Cc: Thomas Gleixner Cc: pbonzini@redhat.com Link: http://lkml.kernel.org/r/1475627678-20788-2-git-send-email-riel@redhat.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/crypto/crc32c-intel_glue.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/x86/crypto/crc32c-intel_glue.c b/arch/x86/crypto/crc32c-intel_glue.c index 60a391b8c4a2..dd1958436591 100644 --- a/arch/x86/crypto/crc32c-intel_glue.c +++ b/arch/x86/crypto/crc32c-intel_glue.c @@ -58,16 +58,11 @@ asmlinkage unsigned int crc_pcl(const u8 *buffer, int len, unsigned int crc_init); static int crc32c_pcl_breakeven = CRC32C_PCL_BREAKEVEN_EAGERFPU; -#if defined(X86_FEATURE_EAGER_FPU) #define set_pcl_breakeven_point() \ do { \ if (!use_eager_fpu()) \ crc32c_pcl_breakeven = CRC32C_PCL_BREAKEVEN_NOEAGERFPU; \ } while (0) -#else -#define set_pcl_breakeven_point() \ - (crc32c_pcl_breakeven = CRC32C_PCL_BREAKEVEN_NOEAGERFPU) -#endif #endif /* CONFIG_X86_64 */ static u32 crc32c_intel_le_hw_byte(u32 crc, unsigned char const *data, size_t length) -- GitLab From 1e38f8e9864f2c52775743694f0517c6bd276d83 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Fri, 14 Jul 2017 15:36:55 +0200 Subject: [PATCH 115/604] nvmet: Move serial number from controller to subsystem commit 2e7f5d2af2155084c6f7c86328d36e698cd84954 upstream. The NVMe specification defines the serial number as: "Serial Number (SN): Contains the serial number for the NVM subsystem that is assigned by the vendor as an ASCII string. Refer to section 7.10 for unique identifier requirements. Refer to section 1.5 for ASCII string requirements" So move it from the controller to the subsystem, where it belongs. Signed-off-by: Johannes Thumshirn Reviewed-by: Christoph Hellwig Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/target/admin-cmd.c | 2 +- drivers/nvme/target/core.c | 5 ++--- drivers/nvme/target/nvmet.h | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index f791d46fe50f..347a1ecb1f23 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c @@ -183,7 +183,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req) id->ssvid = 0; memset(id->sn, ' ', sizeof(id->sn)); - snprintf(id->sn, sizeof(id->sn), "%llx", ctrl->serial); + snprintf(id->sn, sizeof(id->sn), "%llx", ctrl->subsys->serial); memset(id->mn, ' ', sizeof(id->mn)); strncpy((char *)id->mn, "Linux", sizeof(id->mn)); diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 3a044922b048..64b40a12abcf 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -743,9 +743,6 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, memcpy(ctrl->subsysnqn, subsysnqn, NVMF_NQN_SIZE); memcpy(ctrl->hostnqn, hostnqn, NVMF_NQN_SIZE); - /* generate a random serial number as our controllers are ephemeral: */ - get_random_bytes(&ctrl->serial, sizeof(ctrl->serial)); - kref_init(&ctrl->ref); ctrl->subsys = subsys; @@ -904,6 +901,8 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn, return NULL; subsys->ver = NVME_VS(1, 2, 1); /* NVMe 1.2.1 */ + /* generate a random serial number as our controllers are ephemeral: */ + get_random_bytes(&subsys->serial, sizeof(subsys->serial)); switch (type) { case NVME_NQN_NVME: diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index 26b87dc843d2..0bc530cdf2b4 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h @@ -110,7 +110,6 @@ struct nvmet_ctrl { struct mutex lock; u64 cap; - u64 serial; u32 cc; u32 csts; @@ -151,6 +150,7 @@ struct nvmet_subsys { u16 max_qid; u64 ver; + u64 serial; char *subsysnqn; struct config_group group; -- GitLab From f43d8e4c8619c5ac15697ca63747737000441aca Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Fri, 14 Jul 2017 00:25:31 +0200 Subject: [PATCH 116/604] nvmet: don't report 0-bytes in serial number commit 42de82a8b544fa55670feef7d6f85085fba48fc0 upstream. The NVME standard mandates that the SN, MN, and FR fields of the Identify Controller Data Structure be "ASCII strings". That means that they may not contain 0-bytes, not even string terminators. Signed-off-by: Martin Wilck Reviewed-by: Hannes Reinecke [hch: fixed for the move of the serial field, updated description] Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/target/admin-cmd.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index 347a1ecb1f23..5cddab511ac5 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c @@ -166,11 +166,21 @@ static void nvmet_execute_get_log_page(struct nvmet_req *req) nvmet_req_complete(req, status); } +static void copy_and_pad(char *dst, int dst_len, const char *src, int src_len) +{ + int len = min(src_len, dst_len); + + memcpy(dst, src, len); + if (dst_len > len) + memset(dst + len, ' ', dst_len - len); +} + static void nvmet_execute_identify_ctrl(struct nvmet_req *req) { struct nvmet_ctrl *ctrl = req->sq->ctrl; struct nvme_id_ctrl *id; u16 status = 0; + const char model[] = "Linux"; id = kzalloc(sizeof(*id), GFP_KERNEL); if (!id) { @@ -182,8 +192,10 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req) id->vid = 0; id->ssvid = 0; - memset(id->sn, ' ', sizeof(id->sn)); - snprintf(id->sn, sizeof(id->sn), "%llx", ctrl->subsys->serial); + bin2hex(id->sn, &ctrl->subsys->serial, + min(sizeof(ctrl->subsys->serial), sizeof(id->sn) / 2)); + copy_and_pad(id->mn, sizeof(id->mn), model, sizeof(model) - 1); + copy_and_pad(id->fr, sizeof(id->fr), UTS_RELEASE, strlen(UTS_RELEASE)); memset(id->mn, ' ', sizeof(id->mn)); strncpy((char *)id->mn, "Linux", sizeof(id->mn)); -- GitLab From 1c4eb2a50e77109b3b89c57e80fce54a72f69fcf Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Mon, 14 Aug 2017 22:12:37 +0200 Subject: [PATCH 117/604] nvmet: don't overwrite identify sn/fr with 0-bytes commit 42819eb7a0957cc340ad4ed8bba736bab5ebc464 upstream. The merged version of my patch "nvmet: don't report 0-bytes in serial number" fails to remove two lines which should have been replaced, so that the space-padded strings are overwritten again with 0-bytes. Fix it. Fixes: 42de82a8b544 nvmet: don't report 0-bytes in serial number Signed-off-by: Martin Wilck Reviewed-by: Sagi Grimberg Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/target/admin-cmd.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index 5cddab511ac5..2caed285fd7b 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c @@ -197,12 +197,6 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req) copy_and_pad(id->mn, sizeof(id->mn), model, sizeof(model) - 1); copy_and_pad(id->fr, sizeof(id->fr), UTS_RELEASE, strlen(UTS_RELEASE)); - memset(id->mn, ' ', sizeof(id->mn)); - strncpy((char *)id->mn, "Linux", sizeof(id->mn)); - - memset(id->fr, ' ', sizeof(id->fr)); - strncpy((char *)id->fr, UTS_RELEASE, sizeof(id->fr)); - id->rab = 6; /* -- GitLab From be1f605bea9557a85f717e2707bc7c0c22e7ad81 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 Jan 2018 08:29:50 +0100 Subject: [PATCH 118/604] gpio: No NULL owner commit 7d18f0a14aa6a0d6bad39111c1fb655f07f71d59 upstream. Sometimes a GPIO is fetched with NULL as parent device, and that is just fine. So under these circumstances, avoid using dev_name() to provide a name for the GPIO line. Signed-off-by: Linus Walleij Cc: Daniel Rosenberg Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpiolib.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 56b24198741c..dd0076497463 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3204,6 +3204,8 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, struct gpio_desc *desc = NULL; int status; enum gpio_lookup_flags lookupflags = 0; + /* Maybe we have a device name, maybe not */ + const char *devname = dev ? dev_name(dev) : "?"; dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id); @@ -3232,8 +3234,11 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, return desc; } - /* If a connection label was passed use that, else use the device name as label */ - status = gpiod_request(desc, con_id ? con_id : dev_name(dev)); + /* + * If a connection label was passed use that, else attempt to use + * the device name as label + */ + status = gpiod_request(desc, con_id ? con_id : devname); if (status < 0) return ERR_PTR(status); -- GitLab From 00b1391f9539711945e75b856230ee751a02b385 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 6 Jun 2018 16:43:02 +0200 Subject: [PATCH 119/604] KVM: x86: introduce linear_{read,write}_system commit 79367a65743975e5cac8d24d08eccc7fdae832b0 upstream. Wrap the common invocation of ctxt->ops->read_std and ctxt->ops->write_std, so as to have a smaller patch when the functions grow another argument. Fixes: 129a72a0d3c8 ("KVM: x86: Introduce segmented_write_std", 2017-01-12) Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/emulate.c | 64 +++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index c8d573822e60..4421bdbb531d 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -802,6 +802,19 @@ static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) return assign_eip_near(ctxt, ctxt->_eip + rel); } +static int linear_read_system(struct x86_emulate_ctxt *ctxt, ulong linear, + void *data, unsigned size) +{ + return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception); +} + +static int linear_write_system(struct x86_emulate_ctxt *ctxt, + ulong linear, void *data, + unsigned int size) +{ + return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception); +} + static int segmented_read_std(struct x86_emulate_ctxt *ctxt, struct segmented_address addr, void *data, @@ -1500,8 +1513,7 @@ static int read_interrupt_descriptor(struct x86_emulate_ctxt *ctxt, return emulate_gp(ctxt, index << 3 | 0x2); addr = dt.address + index * 8; - return ctxt->ops->read_std(ctxt, addr, desc, sizeof *desc, - &ctxt->exception); + return linear_read_system(ctxt, addr, desc, sizeof *desc); } static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt, @@ -1564,8 +1576,7 @@ static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt, if (rc != X86EMUL_CONTINUE) return rc; - return ctxt->ops->read_std(ctxt, *desc_addr_p, desc, sizeof(*desc), - &ctxt->exception); + return linear_read_system(ctxt, *desc_addr_p, desc, sizeof(*desc)); } /* allowed just for 8 bytes segments */ @@ -1579,8 +1590,7 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt, if (rc != X86EMUL_CONTINUE) return rc; - return ctxt->ops->write_std(ctxt, addr, desc, sizeof *desc, - &ctxt->exception); + return linear_write_system(ctxt, addr, desc, sizeof *desc); } static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, @@ -1741,8 +1751,7 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, return ret; } } else if (ctxt->mode == X86EMUL_MODE_PROT64) { - ret = ctxt->ops->read_std(ctxt, desc_addr+8, &base3, - sizeof(base3), &ctxt->exception); + ret = linear_read_system(ctxt, desc_addr+8, &base3, sizeof(base3)); if (ret != X86EMUL_CONTINUE) return ret; if (is_noncanonical_address(get_desc_base(&seg_desc) | @@ -2055,11 +2064,11 @@ static int __emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq) eip_addr = dt.address + (irq << 2); cs_addr = dt.address + (irq << 2) + 2; - rc = ops->read_std(ctxt, cs_addr, &cs, 2, &ctxt->exception); + rc = linear_read_system(ctxt, cs_addr, &cs, 2); if (rc != X86EMUL_CONTINUE) return rc; - rc = ops->read_std(ctxt, eip_addr, &eip, 2, &ctxt->exception); + rc = linear_read_system(ctxt, eip_addr, &eip, 2); if (rc != X86EMUL_CONTINUE) return rc; @@ -3037,35 +3046,30 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt, u16 tss_selector, u16 old_tss_sel, ulong old_tss_base, struct desc_struct *new_desc) { - const struct x86_emulate_ops *ops = ctxt->ops; struct tss_segment_16 tss_seg; int ret; u32 new_tss_base = get_desc_base(new_desc); - ret = ops->read_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg, - &ctxt->exception); + ret = linear_read_system(ctxt, old_tss_base, &tss_seg, sizeof tss_seg); if (ret != X86EMUL_CONTINUE) return ret; save_state_to_tss16(ctxt, &tss_seg); - ret = ops->write_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg, - &ctxt->exception); + ret = linear_write_system(ctxt, old_tss_base, &tss_seg, sizeof tss_seg); if (ret != X86EMUL_CONTINUE) return ret; - ret = ops->read_std(ctxt, new_tss_base, &tss_seg, sizeof tss_seg, - &ctxt->exception); + ret = linear_read_system(ctxt, new_tss_base, &tss_seg, sizeof tss_seg); if (ret != X86EMUL_CONTINUE) return ret; if (old_tss_sel != 0xffff) { tss_seg.prev_task_link = old_tss_sel; - ret = ops->write_std(ctxt, new_tss_base, - &tss_seg.prev_task_link, - sizeof tss_seg.prev_task_link, - &ctxt->exception); + ret = linear_write_system(ctxt, new_tss_base, + &tss_seg.prev_task_link, + sizeof tss_seg.prev_task_link); if (ret != X86EMUL_CONTINUE) return ret; } @@ -3181,38 +3185,34 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt, u16 tss_selector, u16 old_tss_sel, ulong old_tss_base, struct desc_struct *new_desc) { - const struct x86_emulate_ops *ops = ctxt->ops; struct tss_segment_32 tss_seg; int ret; u32 new_tss_base = get_desc_base(new_desc); u32 eip_offset = offsetof(struct tss_segment_32, eip); u32 ldt_sel_offset = offsetof(struct tss_segment_32, ldt_selector); - ret = ops->read_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg, - &ctxt->exception); + ret = linear_read_system(ctxt, old_tss_base, &tss_seg, sizeof tss_seg); if (ret != X86EMUL_CONTINUE) return ret; save_state_to_tss32(ctxt, &tss_seg); /* Only GP registers and segment selectors are saved */ - ret = ops->write_std(ctxt, old_tss_base + eip_offset, &tss_seg.eip, - ldt_sel_offset - eip_offset, &ctxt->exception); + ret = linear_write_system(ctxt, old_tss_base + eip_offset, &tss_seg.eip, + ldt_sel_offset - eip_offset); if (ret != X86EMUL_CONTINUE) return ret; - ret = ops->read_std(ctxt, new_tss_base, &tss_seg, sizeof tss_seg, - &ctxt->exception); + ret = linear_read_system(ctxt, new_tss_base, &tss_seg, sizeof tss_seg); if (ret != X86EMUL_CONTINUE) return ret; if (old_tss_sel != 0xffff) { tss_seg.prev_task_link = old_tss_sel; - ret = ops->write_std(ctxt, new_tss_base, - &tss_seg.prev_task_link, - sizeof tss_seg.prev_task_link, - &ctxt->exception); + ret = linear_write_system(ctxt, new_tss_base, + &tss_seg.prev_task_link, + sizeof tss_seg.prev_task_link); if (ret != X86EMUL_CONTINUE) return ret; } -- GitLab From 838b0e900a7e16799dbecc031739de1ee40741af Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 6 Jun 2018 17:37:49 +0200 Subject: [PATCH 120/604] KVM: x86: pass kvm_vcpu to kvm_read_guest_virt and kvm_write_guest_virt_system commit ce14e868a54edeb2e30cb7a7b104a2fc4b9d76ca upstream. Int the next patch the emulator's .read_std and .write_std callbacks will grow another argument, which is not needed in kvm_read_guest_virt and kvm_write_guest_virt_system's callers. Since we have to make separate functions, let's give the currently existing names a nicer interface, too. Fixes: 129a72a0d3c8 ("KVM: x86: Introduce segmented_write_std", 2017-01-12) Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/vmx.c | 23 ++++++++++------------- arch/x86/kvm/x86.c | 39 ++++++++++++++++++++++++++------------- arch/x86/kvm/x86.h | 4 ++-- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 4a66a620fc17..4e0292e0aafb 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -6928,8 +6928,7 @@ static int nested_vmx_check_vmptr(struct kvm_vcpu *vcpu, int exit_reason, vmcs_read32(VMX_INSTRUCTION_INFO), false, &gva)) return 1; - if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, &vmptr, - sizeof(vmptr), &e)) { + if (kvm_read_guest_virt(vcpu, gva, &vmptr, sizeof(vmptr), &e)) { kvm_inject_page_fault(vcpu, &e); return 1; } @@ -7469,8 +7468,8 @@ static int handle_vmread(struct kvm_vcpu *vcpu) vmx_instruction_info, true, &gva)) return 1; /* _system ok, as nested_vmx_check_permission verified cpl=0 */ - kvm_write_guest_virt_system(&vcpu->arch.emulate_ctxt, gva, - &field_value, (is_long_mode(vcpu) ? 8 : 4), NULL); + kvm_write_guest_virt_system(vcpu, gva, &field_value, + (is_long_mode(vcpu) ? 8 : 4), NULL); } nested_vmx_succeed(vcpu); @@ -7505,8 +7504,8 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu) if (get_vmx_mem_address(vcpu, exit_qualification, vmx_instruction_info, false, &gva)) return 1; - if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, - &field_value, (is_64_bit_mode(vcpu) ? 8 : 4), &e)) { + if (kvm_read_guest_virt(vcpu, gva, &field_value, + (is_64_bit_mode(vcpu) ? 8 : 4), &e)) { kvm_inject_page_fault(vcpu, &e); return 1; } @@ -7603,9 +7602,9 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu) vmx_instruction_info, true, &vmcs_gva)) return 1; /* ok to use *_system, as nested_vmx_check_permission verified cpl=0 */ - if (kvm_write_guest_virt_system(&vcpu->arch.emulate_ctxt, vmcs_gva, - (void *)&to_vmx(vcpu)->nested.current_vmptr, - sizeof(u64), &e)) { + if (kvm_write_guest_virt_system(vcpu, vmcs_gva, + (void *)&to_vmx(vcpu)->nested.current_vmptr, + sizeof(u64), &e)) { kvm_inject_page_fault(vcpu, &e); return 1; } @@ -7659,8 +7658,7 @@ static int handle_invept(struct kvm_vcpu *vcpu) if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION), vmx_instruction_info, false, &gva)) return 1; - if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, &operand, - sizeof(operand), &e)) { + if (kvm_read_guest_virt(vcpu, gva, &operand, sizeof(operand), &e)) { kvm_inject_page_fault(vcpu, &e); return 1; } @@ -7723,8 +7721,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu) if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION), vmx_instruction_info, false, &gva)) return 1; - if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, &vpid, - sizeof(u32), &e)) { + if (kvm_read_guest_virt(vcpu, gva, &vpid, sizeof(u32), &e)) { kvm_inject_page_fault(vcpu, &e); return 1; } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 4aa265ae8cf7..95d2709879f3 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4395,11 +4395,10 @@ static int kvm_fetch_guest_virt(struct x86_emulate_ctxt *ctxt, return X86EMUL_CONTINUE; } -int kvm_read_guest_virt(struct x86_emulate_ctxt *ctxt, +int kvm_read_guest_virt(struct kvm_vcpu *vcpu, gva_t addr, void *val, unsigned int bytes, struct x86_exception *exception) { - struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0; return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access, @@ -4407,9 +4406,9 @@ int kvm_read_guest_virt(struct x86_emulate_ctxt *ctxt, } EXPORT_SYMBOL_GPL(kvm_read_guest_virt); -static int kvm_read_guest_virt_system(struct x86_emulate_ctxt *ctxt, - gva_t addr, void *val, unsigned int bytes, - struct x86_exception *exception) +static int emulator_read_std(struct x86_emulate_ctxt *ctxt, + gva_t addr, void *val, unsigned int bytes, + struct x86_exception *exception) { struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, exception); @@ -4424,18 +4423,16 @@ static int kvm_read_guest_phys_system(struct x86_emulate_ctxt *ctxt, return r < 0 ? X86EMUL_IO_NEEDED : X86EMUL_CONTINUE; } -int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt, - gva_t addr, void *val, - unsigned int bytes, - struct x86_exception *exception) +static int kvm_write_guest_virt_helper(gva_t addr, void *val, unsigned int bytes, + struct kvm_vcpu *vcpu, u32 access, + struct x86_exception *exception) { - struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); void *data = val; int r = X86EMUL_CONTINUE; while (bytes) { gpa_t gpa = vcpu->arch.walk_mmu->gva_to_gpa(vcpu, addr, - PFERR_WRITE_MASK, + access, exception); unsigned offset = addr & (PAGE_SIZE-1); unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset); @@ -4456,6 +4453,22 @@ int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt, out: return r; } + +static int emulator_write_std(struct x86_emulate_ctxt *ctxt, gva_t addr, void *val, + unsigned int bytes, struct x86_exception *exception) +{ + struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); + + return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, + PFERR_WRITE_MASK, exception); +} + +int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, gva_t addr, void *val, + unsigned int bytes, struct x86_exception *exception) +{ + return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, + PFERR_WRITE_MASK, exception); +} EXPORT_SYMBOL_GPL(kvm_write_guest_virt_system); static int vcpu_mmio_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva, @@ -5180,8 +5193,8 @@ static void emulator_set_hflags(struct x86_emulate_ctxt *ctxt, unsigned emul_fla static const struct x86_emulate_ops emulate_ops = { .read_gpr = emulator_read_gpr, .write_gpr = emulator_write_gpr, - .read_std = kvm_read_guest_virt_system, - .write_std = kvm_write_guest_virt_system, + .read_std = emulator_read_std, + .write_std = emulator_write_std, .read_phys = kvm_read_guest_phys_system, .fetch = kvm_fetch_guest_virt, .read_emulated = emulator_read_emulated, diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index e8ff3e4ce38a..2133a18f2d36 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -161,11 +161,11 @@ int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip); void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr); u64 get_kvmclock_ns(struct kvm *kvm); -int kvm_read_guest_virt(struct x86_emulate_ctxt *ctxt, +int kvm_read_guest_virt(struct kvm_vcpu *vcpu, gva_t addr, void *val, unsigned int bytes, struct x86_exception *exception); -int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt, +int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, gva_t addr, void *val, unsigned int bytes, struct x86_exception *exception); -- GitLab From 8da07ee9e433f3af74f126c5bfd1a1a44d0aaeef Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Mon, 14 May 2018 14:35:09 -0700 Subject: [PATCH 121/604] staging: android: ion: Switch to pr_warn_once in ion_buffer_destroy commit 45ad559a29629cb1c64ee636563c69b71524f077 upstream. Syzbot reported yet another warning with Ion: WARNING: CPU: 0 PID: 1467 at drivers/staging/android/ion/ion.c:122 ion_buffer_destroy+0xd4/0x190 drivers/staging/android/ion/ion.c:122 Kernel panic - not syncing: panic_on_warn set ... This is catching that a buffer was freed with an existing kernel mapping still present. This can be easily be triggered from userspace by calling DMA_BUF_SYNC_START without calling DMA_BUF_SYNC_END. Switch to a single pr_warn_once to indicate the error without being disruptive. Reported-by: syzbot+cd8bcd40cb049efa2770@syzkaller.appspotmail.com Reported-by: syzbot Signed-off-by: Laura Abbott Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 209a8f7ef02b..6f9974cb0e15 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -192,8 +192,11 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, void ion_buffer_destroy(struct ion_buffer *buffer) { - if (WARN_ON(buffer->kmap_cnt > 0)) + if (buffer->kmap_cnt > 0) { + pr_warn_once("%s: buffer still mapped in the kernel\n", + __func__); buffer->heap->ops->unmap_kernel(buffer->heap, buffer); + } buffer->heap->ops->free(buffer); vfree(buffer->pages); kfree(buffer); -- GitLab From 14450abb38eb72e5a37743cb0e67cd005173d9a0 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 18 May 2018 20:13:42 -0500 Subject: [PATCH 122/604] usbip: vhci_sysfs: fix potential Spectre v1 commit a0d6ec88090d7b1b008429c44532a388e29bb1bd upstream. pdev_nr and rhport can be 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/usb/usbip/vhci_sysfs.c:238 detach_store() warn: potential spectre issue 'vhcis' drivers/usb/usbip/vhci_sysfs.c:328 attach_store() warn: potential spectre issue 'vhcis' drivers/usb/usbip/vhci_sysfs.c:338 attach_store() warn: potential spectre issue 'vhci->vhci_hcd_ss->vdev' drivers/usb/usbip/vhci_sysfs.c:340 attach_store() warn: potential spectre issue 'vhci->vhci_hcd_hs->vdev' Fix this by sanitizing pdev_nr and rhport before using them to index vhcis and vhci->vhci_hcd_ss->vdev respectively. 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 Acked-by: Shuah Khan (Samsung OSG) Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/vhci_sysfs.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c index c287ccc78fde..e8a008de8dbc 100644 --- a/drivers/usb/usbip/vhci_sysfs.c +++ b/drivers/usb/usbip/vhci_sysfs.c @@ -24,6 +24,9 @@ #include #include +/* Hardening for Spectre-v1 */ +#include + #include "usbip_common.h" #include "vhci.h" @@ -181,16 +184,20 @@ static int vhci_port_disconnect(struct vhci_hcd *vhci, __u32 rhport) return 0; } -static int valid_port(__u32 pdev_nr, __u32 rhport) +static int valid_port(__u32 *pdev_nr, __u32 *rhport) { - if (pdev_nr >= vhci_num_controllers) { - pr_err("pdev %u\n", pdev_nr); + if (*pdev_nr >= vhci_num_controllers) { + pr_err("pdev %u\n", *pdev_nr); return 0; } - if (rhport >= VHCI_HC_PORTS) { - pr_err("rhport %u\n", rhport); + *pdev_nr = array_index_nospec(*pdev_nr, vhci_num_controllers); + + if (*rhport >= VHCI_HC_PORTS) { + pr_err("rhport %u\n", *rhport); return 0; } + *rhport = array_index_nospec(*rhport, VHCI_HC_PORTS); + return 1; } @@ -207,7 +214,7 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr, pdev_nr = port_to_pdev_nr(port); rhport = port_to_rhport(port); - if (!valid_port(pdev_nr, rhport)) + if (!valid_port(&pdev_nr, &rhport)) return -EINVAL; hcd = platform_get_drvdata(*(vhci_pdevs + pdev_nr)); @@ -226,7 +233,8 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach); -static int valid_args(__u32 pdev_nr, __u32 rhport, enum usb_device_speed speed) +static int valid_args(__u32 *pdev_nr, __u32 *rhport, + enum usb_device_speed speed) { if (!valid_port(pdev_nr, rhport)) { return 0; @@ -288,7 +296,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, sockfd, devid, speed); /* check received parameters */ - if (!valid_args(pdev_nr, rhport, speed)) + if (!valid_args(&pdev_nr, &rhport, speed)) return -EINVAL; hcd = platform_get_drvdata(*(vhci_pdevs + pdev_nr)); -- GitLab From 187941e50587da64e5172d8d91e35b8ebfc26756 Mon Sep 17 00:00:00 2001 From: Alexander Kappner Date: Fri, 18 May 2018 21:50:15 -0700 Subject: [PATCH 123/604] usb-storage: Add support for FL_ALWAYS_SYNC flag in the UAS driver commit 8c4e97ddfe73a0958bb0abf7e6a3bc4cc3e04936 upstream. The ALWAYS_SYNC flag is currently honored by the usb-storage driver but not UAS and is required to work around devices that become unstable upon being queried for cache. This code is taken straight from: drivers/usb/storage/scsiglue.c:284 Signed-off-by: Alexander Kappner Acked-by: Alan Stern Cc: stable Acked-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/uas.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index a96dcc660d0f..8dd200f92020 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -836,6 +836,12 @@ static int uas_slave_configure(struct scsi_device *sdev) if (devinfo->flags & US_FL_BROKEN_FUA) sdev->broken_fua = 1; + /* UAS also needs to support FL_ALWAYS_SYNC */ + if (devinfo->flags & US_FL_ALWAYS_SYNC) { + sdev->skip_ms_page_3f = 1; + sdev->skip_ms_page_8 = 1; + sdev->wce_default_on = 1; + } scsi_change_queue_depth(sdev, devinfo->qdepth - 2); return 0; } -- GitLab From 244eb27f960004666813c75a324e35b26a30ecf7 Mon Sep 17 00:00:00 2001 From: Alexander Kappner Date: Fri, 18 May 2018 21:50:16 -0700 Subject: [PATCH 124/604] usb-storage: Add compatibility quirk flags for G-Technologies G-Drive commit ca7d9515d0e6825351ce106066cea1f60e40b1c8 upstream. The "G-Drive" (sold by G-Technology) external USB 3.0 drive hangs on write access under UAS and usb-storage: [ 136.079121] sd 15:0:0:0: [sdi] tag#0 FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE [ 136.079144] sd 15:0:0:0: [sdi] tag#0 Sense Key : Illegal Request [current] [ 136.079152] sd 15:0:0:0: [sdi] tag#0 Add. Sense: Invalid field in cdb [ 136.079176] sd 15:0:0:0: [sdi] tag#0 CDB: Write(16) 8a 08 00 00 00 00 00 00 00 00 00 00 00 08 00 00 [ 136.079180] print_req_error: critical target error, dev sdi, sector 0 [ 136.079183] Buffer I/O error on dev sdi, logical block 0, lost sync page write [ 136.173148] EXT4-fs (sdi): mounted filesystem with ordered data mode. Opts: (null) [ 140.583998] sd 15:0:0:0: [sdi] tag#0 FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE [ 140.584010] sd 15:0:0:0: [sdi] tag#0 Sense Key : Illegal Request [current] [ 140.584016] sd 15:0:0:0: [sdi] tag#0 Add. Sense: Invalid field in cdb [ 140.584022] sd 15:0:0:0: [sdi] tag#0 CDB: Write(16) 8a 08 00 00 00 00 e8 c4 00 18 00 00 00 08 00 00 [ 140.584025] print_req_error: critical target error, dev sdi, sector 3905159192 [ 140.584044] print_req_error: critical target error, dev sdi, sector 3905159192 [ 140.584052] Aborting journal on device sdi-8. The proposed patch adds compatibility quirks. Because the drive requires two quirks (one to work with UAS, and another to work with usb-storage), adding this under unusual_devs.h and not just unusual_uas.h so kernels compiled without UAS receive the quirk. With the patch, the drive works reliably on UAS and usb- storage. (tested on NEC Corporation uPD720200 USB 3.0 host controller). Signed-off-by: Alexander Kappner Acked-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 9 +++++++++ drivers/usb/storage/unusual_uas.h | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index ca3a5d430ae1..fc5ed351defb 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -2340,6 +2340,15 @@ UNUSUAL_DEV( 0x4146, 0xba01, 0x0100, 0x0100, "Micro Mini 1GB", USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ), +/* "G-DRIVE" external HDD hangs on write without these. + * Patch submitted by Alexander Kappner + */ +UNUSUAL_DEV(0x4971, 0x8024, 0x0000, 0x9999, + "SimpleTech", + "External HDD", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_ALWAYS_SYNC), + /* * Nick Bowler * SCSI stack spams (otherwise harmless) error messages. diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index 719ec68ae309..f15aa47c54a9 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -183,3 +183,12 @@ UNUSUAL_DEV(0x4971, 0x8017, 0x0000, 0x9999, "External HDD", USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_REPORT_OPCODES), + +/* "G-DRIVE" external HDD hangs on write without these. + * Patch submitted by Alexander Kappner + */ +UNUSUAL_DEV(0x4971, 0x8024, 0x0000, 0x9999, + "SimpleTech", + "External HDD", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_ALWAYS_SYNC), -- GitLab From bc62b33d5fafde32ee1ad5e2d39152b3da7fdcda Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 10 Apr 2018 14:38:54 +0900 Subject: [PATCH 125/604] usb: gadget: udc: renesas_usb3: disable the controller's irqs for reconnecting commit bd6bce004d78b867ba0c6d3712f1c5b50398af9a upstream. This patch fixes an issue that reconnection is possible to fail because unexpected state handling happens by the irqs. To fix the issue, the driver disables the controller's irqs when disconnected. Fixes: 746bfe63bba3 ("usb: gadget: renesas_usb3: add support for Renesas USB3.0 peripheral controller") Cc: # v4.5+ Reviewed-by: Simon Horman Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/renesas_usb3.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 2197a50ed2ab..b1ae944c83a9 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -521,6 +521,13 @@ static void usb3_disconnect(struct renesas_usb3 *usb3) usb3_usb2_pullup(usb3, 0); usb3_clear_bit(usb3, USB30_CON_B3_CONNECT, USB3_USB30_CON); usb3_reset_epc(usb3); + usb3_disable_irq_1(usb3, USB_INT_1_B2_RSUM | USB_INT_1_B3_PLLWKUP | + USB_INT_1_B3_LUPSUCS | USB_INT_1_B3_DISABLE | + USB_INT_1_SPEED | USB_INT_1_B3_WRMRST | + USB_INT_1_B3_HOTRST | USB_INT_1_B2_SPND | + USB_INT_1_B2_L1SPND | USB_INT_1_B2_USBRST); + usb3_clear_bit(usb3, USB_COM_CON_SPD_MODE, USB3_USB_COM_CON); + usb3_init_epc_registers(usb3); if (usb3->driver) usb3->driver->disconnect(&usb3->gadget); -- GitLab From 70f0a59bbdb4f7dd46255fd17060213a32af6302 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 1 Jun 2018 11:28:21 +0200 Subject: [PATCH 126/604] serial: sh-sci: Stop using printk format %pCr commit d63c16f8e1ab761775275adcf54f4bef7c330295 upstream. Printk format "%pCr" will be removed soon, as clk_get_rate() must not be called in atomic context. Replace it by open-coding the operation. This is safe here, as the code runs in task context. Link: http://lkml.kernel.org/r/1527845302-12159-4-git-send-email-geert+renesas@glider.be To: Jia-Ju Bai To: Jonathan Corbet To: Michael Turquette To: Stephen Boyd To: Zhang Rui To: Eduardo Valentin To: Eric Anholt To: Stefan Wahren To: Greg Kroah-Hartman Cc: Sergey Senozhatsky Cc: Petr Mladek Cc: Linus Torvalds Cc: Steven Rostedt Cc: linux-doc@vger.kernel.org Cc: linux-clk@vger.kernel.org Cc: linux-pm@vger.kernel.org Cc: linux-serial@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-renesas-soc@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: Geert Uytterhoeven Cc: stable@vger.kernel.org # 4.5+ Signed-off-by: Geert Uytterhoeven Signed-off-by: Petr Mladek Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 107f0d194ac5..da46f0fba5da 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2626,8 +2626,8 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev) dev_dbg(dev, "failed to get %s (%ld)\n", clk_names[i], PTR_ERR(clk)); else - dev_dbg(dev, "clk %s is %pC rate %pCr\n", clk_names[i], - clk, clk); + dev_dbg(dev, "clk %s is %pC rate %lu\n", clk_names[i], + clk, clk_get_rate(clk)); sci_port->clks[i] = IS_ERR(clk) ? NULL : clk; } return 0; -- GitLab From 41bdf9702caea0bfa9e578977f13a566e3fc428b Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 7 May 2018 19:11:30 +0200 Subject: [PATCH 127/604] tty/serial: atmel: use port->name as name in request_irq() commit 9594b5be7ec110ed11acec58fa94f3f293668c85 upstream. I was puzzled while looking at /proc/interrupts and random things showed up between reboots. This occurred more often but I realised it later. The "correct" output should be: |38: 11861 atmel-aic5 2 Level ttyS0 but I saw sometimes |38: 6426 atmel-aic5 2 Level tty1 and accounted it wrongly as correct. This is use after free and the former example randomly got the "old" pointer which pointed to the same content. With SLAB_FREELIST_RANDOM and HARDENED I even got |38: 7067 atmel-aic5 2 Level E=Started User Manager for UID 0 or other nonsense. As it turns out the tty, pointer that is accessed in atmel_startup(), is freed() before atmel_shutdown(). It seems to happen quite often that the tty for ttyS0 is allocated and freed while ->shutdown is not invoked. I don't do anything special - just a systemd boot :) Use dev_name(&pdev->dev) as the IRQ name for request_irq(). This exists as long as the driver is loaded so no use-after-free here. Cc: stable@vger.kernel.org Fixes: 761ed4a94582 ("tty: serial_core: convert uart_close to use tty_port_close") Acked-by: Richard Genoud Acked-by: Rob Herring Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index addb287cacea..5a341b1c65c3 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1803,7 +1803,6 @@ static int atmel_startup(struct uart_port *port) { struct platform_device *pdev = to_platform_device(port->dev); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct tty_struct *tty = port->state->port.tty; int retval; /* @@ -1818,8 +1817,8 @@ static int atmel_startup(struct uart_port *port) * Allocate the IRQ */ retval = request_irq(port->irq, atmel_interrupt, - IRQF_SHARED | IRQF_COND_SUSPEND, - tty ? tty->name : "atmel_serial", port); + IRQF_SHARED | IRQF_COND_SUSPEND, + dev_name(&pdev->dev), port); if (retval) { dev_err(port->dev, "atmel_startup - Can't get irq\n"); return retval; -- GitLab From 5b91ae57b5cb612ad68516e70d517b303dd604d1 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 10 May 2018 08:41:13 +0200 Subject: [PATCH 128/604] serial: samsung: fix maxburst parameter for DMA transactions commit aa2f80e752c75e593b3820f42c416ed9458fa73e upstream. The best granularity of residue that DMA engine can report is in the BURST units, so the serial driver must use MAXBURST = 1 and DMA_SLAVE_BUSWIDTH_1_BYTE if it relies on exact number of bytes transferred by DMA engine. Fixes: 62c37eedb74c ("serial: samsung: add dma reqest/release functions") Signed-off-by: Marek Szyprowski Acked-by: Krzysztof Kozlowski Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index f2ab6d8aab41..5609305b3676 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -866,15 +866,12 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p) dma->rx_conf.direction = DMA_DEV_TO_MEM; dma->rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma->rx_conf.src_addr = p->port.mapbase + S3C2410_URXH; - dma->rx_conf.src_maxburst = 16; + dma->rx_conf.src_maxburst = 1; dma->tx_conf.direction = DMA_MEM_TO_DEV; dma->tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma->tx_conf.dst_addr = p->port.mapbase + S3C2410_UTXH; - if (dma_get_cache_alignment() >= 16) - dma->tx_conf.dst_maxburst = 16; - else - dma->tx_conf.dst_maxburst = 1; + dma->tx_conf.dst_maxburst = 1; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); -- GitLab From f6e6f0c5423ab4b92b11544a4a6dec29ebd9ade2 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 4 May 2018 10:44:09 -0700 Subject: [PATCH 129/604] serial: 8250: omap: Fix idling of clocks for unused uarts commit 13dc04d0e5fdc25c8f713ad23fdce51cf2bf96ba upstream. I noticed that unused UARTs won't necessarily idle properly always unless at least one byte tx transfer is done first. After some debugging I narrowed down the problem to the scr register dma configuration bits that need to be set before softreset for the clocks to idle. Unless we do this, the module clkctrl idlest bits may be set to 1 instead of 3 meaning the clock will never idle and is blocking deeper idle states for the whole domain. This might be related to the configuration done by the bootloader or kexec booting where certain configurations cause the 8250 or the clkctrl clock to jam in a way where setting of the scr bits and reset is needed to clear it. I've tried diffing the 8250 registers for the various modes, but did not see anything specific. So far I've only seen this on omap4 but I'm suspecting this might also happen on the other clkctrl using SoCs considering they already have a quirk enabled for UART_ERRATA_CLOCK_DISABLE. Let's fix the issue by configuring scr before reset for basic dma even if we don't use it. The scr register will be reset when we do softreset few lines after, and we restore scr on resume. We should do this for all the SoCs with UART_ERRATA_CLOCK_DISABLE quirk flag set since the ones with UART_ERRATA_CLOCK_DISABLE are all based using clkctrl similar to omap4. Looks like both OMAP_UART_SCR_DMAMODE_1 | OMAP_UART_SCR_DMAMODE_CTL bits are needed for the clkctrl to idle after a softreset. And we need to add omap4 to also use the UART_ERRATA_CLOCK_DISABLE for the related workaround to be enabled. This same compatible value will also be used for omap5. Fixes: cdb929e4452a ("serial: 8250_omap: workaround errata around idling UART after using DMA") Cc: Keerthy Cc: Matthijs van Duin Cc: Sekhar Nori Cc: Tero Kristo Signed-off-by: Tony Lindgren Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index e8b34f16ba2c..a3adf21f9dce 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1078,13 +1078,14 @@ static int omap8250_no_handle_irq(struct uart_port *port) return 0; } +static const u8 omap4_habit = UART_ERRATA_CLOCK_DISABLE; static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE; static const u8 dra742_habit = UART_ERRATA_CLOCK_DISABLE; static const struct of_device_id omap8250_dt_ids[] = { { .compatible = "ti,omap2-uart" }, { .compatible = "ti,omap3-uart" }, - { .compatible = "ti,omap4-uart" }, + { .compatible = "ti,omap4-uart", .data = &omap4_habit, }, { .compatible = "ti,am3352-uart", .data = &am3352_habit, }, { .compatible = "ti,am4372-uart", .data = &am3352_habit, }, { .compatible = "ti,dra742-uart", .data = &dra742_habit, }, @@ -1326,6 +1327,19 @@ static int omap8250_soft_reset(struct device *dev) int sysc; int syss; + /* + * At least on omap4, unused uarts may not idle after reset without + * a basic scr dma configuration even with no dma in use. The + * module clkctrl status bits will be 1 instead of 3 blocking idle + * for the whole clockdomain. The softreset below will clear scr, + * and we restore it on resume so this is safe to do on all SoCs + * needing omap8250_soft_reset() quirk. Do it in two writes as + * recommended in the comment for omap8250_update_scr(). + */ + serial_out(up, UART_OMAP_SCR, OMAP_UART_SCR_DMAMODE_1); + serial_out(up, UART_OMAP_SCR, + OMAP_UART_SCR_DMAMODE_1 | OMAP_UART_SCR_DMAMODE_CTL); + sysc = serial_in(up, UART_OMAP_SYSC); /* softreset the UART */ -- GitLab From d9bc59c44d8990b69aafbff42717c2daa22ffb36 Mon Sep 17 00:00:00 2001 From: Gil Kupfer Date: Fri, 1 Jun 2018 00:47:47 -0700 Subject: [PATCH 130/604] vmw_balloon: fixing double free when batching mode is off commit b23220fe054e92f616b82450fae8cd3ab176cc60 upstream. The balloon.page field is used for two different purposes if batching is on or off. If batching is on, the field point to the page which is used to communicate with with the hypervisor. If it is off, balloon.page points to the page that is about to be (un)locked. Unfortunately, this dual-purpose of the field introduced a bug: when the balloon is popped (e.g., when the machine is reset or the balloon driver is explicitly removed), the balloon driver frees, unconditionally, the page that is held in balloon.page. As a result, if batching is disabled, this leads to double freeing the last page that is sent to the hypervisor. The following error occurs during rmmod when kernel checkers are on, and the balloon is not empty: [ 42.307653] ------------[ cut here ]------------ [ 42.307657] Kernel BUG at ffffffffba1e4b28 [verbose debug info unavailable] [ 42.307720] invalid opcode: 0000 [#1] SMP DEBUG_PAGEALLOC [ 42.312512] Modules linked in: vmw_vsock_vmci_transport vsock ppdev joydev vmw_balloon(-) input_leds serio_raw vmw_vmci parport_pc shpchp parport i2c_piix4 nfit mac_hid autofs4 vmwgfx drm_kms_helper hid_generic syscopyarea sysfillrect usbhid sysimgblt fb_sys_fops hid ttm mptspi scsi_transport_spi ahci mptscsih drm psmouse vmxnet3 libahci mptbase pata_acpi [ 42.312766] CPU: 10 PID: 1527 Comm: rmmod Not tainted 4.12.0+ #5 [ 42.312803] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 09/30/2016 [ 42.313042] task: ffff9bf9680f8000 task.stack: ffffbfefc1638000 [ 42.313290] RIP: 0010:__free_pages+0x38/0x40 [ 42.313510] RSP: 0018:ffffbfefc163be98 EFLAGS: 00010246 [ 42.313731] RAX: 000000000000003e RBX: ffffffffc02b9720 RCX: 0000000000000006 [ 42.313972] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff9bf97e08e0a0 [ 42.314201] RBP: ffffbfefc163be98 R08: 0000000000000000 R09: 0000000000000000 [ 42.314435] R10: 0000000000000000 R11: 0000000000000000 R12: ffffffffc02b97e4 [ 42.314505] R13: ffffffffc02b9748 R14: ffffffffc02b9728 R15: 0000000000000200 [ 42.314550] FS: 00007f3af5fec700(0000) GS:ffff9bf97e080000(0000) knlGS:0000000000000000 [ 42.314599] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 42.314635] CR2: 00007f44f6f4ab24 CR3: 00000003a7d12000 CR4: 00000000000006e0 [ 42.314864] Call Trace: [ 42.315774] vmballoon_pop+0x102/0x130 [vmw_balloon] [ 42.315816] vmballoon_exit+0x42/0xd64 [vmw_balloon] [ 42.315853] SyS_delete_module+0x1e2/0x250 [ 42.315891] entry_SYSCALL_64_fastpath+0x23/0xc2 [ 42.315924] RIP: 0033:0x7f3af5b0e8e7 [ 42.315949] RSP: 002b:00007fffe6ce0148 EFLAGS: 00000206 ORIG_RAX: 00000000000000b0 [ 42.315996] RAX: ffffffffffffffda RBX: 000055be676401e0 RCX: 00007f3af5b0e8e7 [ 42.316951] RDX: 000000000000000a RSI: 0000000000000800 RDI: 000055be67640248 [ 42.317887] RBP: 0000000000000003 R08: 0000000000000000 R09: 1999999999999999 [ 42.318845] R10: 0000000000000883 R11: 0000000000000206 R12: 00007fffe6cdf130 [ 42.319755] R13: 0000000000000000 R14: 0000000000000000 R15: 000055be676401e0 [ 42.320606] Code: c0 74 1c f0 ff 4f 1c 74 02 5d c3 85 f6 74 07 e8 0f d8 ff ff 5d c3 31 f6 e8 c6 fb ff ff 5d c3 48 c7 c6 c8 0f c5 ba e8 58 be 02 00 <0f> 0b 66 0f 1f 44 00 00 66 66 66 66 90 48 85 ff 75 01 c3 55 48 [ 42.323462] RIP: __free_pages+0x38/0x40 RSP: ffffbfefc163be98 [ 42.325735] ---[ end trace 872e008e33f81508 ]--- To solve the bug, we eliminate the dual purpose of balloon.page. Fixes: f220a80f0c2e ("VMware balloon: add batching to the vmw_balloon.") Cc: stable@vger.kernel.org Reported-by: Oleksandr Natalenko Signed-off-by: Gil Kupfer Signed-off-by: Nadav Amit Reviewed-by: Xavier Deguillard Tested-by: Oleksandr Natalenko Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 1e688bfec567..fe90b7e04427 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -576,15 +576,9 @@ static void vmballoon_pop(struct vmballoon *b) } } - if (b->batch_page) { - vunmap(b->batch_page); - b->batch_page = NULL; - } - - if (b->page) { - __free_page(b->page); - b->page = NULL; - } + /* Clearing the batch_page unconditionally has no adverse effect */ + free_page((unsigned long)b->batch_page); + b->batch_page = NULL; } /* @@ -991,16 +985,13 @@ static const struct vmballoon_ops vmballoon_batched_ops = { static bool vmballoon_init_batching(struct vmballoon *b) { - b->page = alloc_page(VMW_PAGE_ALLOC_NOSLEEP); - if (!b->page) - return false; + struct page *page; - b->batch_page = vmap(&b->page, 1, VM_MAP, PAGE_KERNEL); - if (!b->batch_page) { - __free_page(b->page); + page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!page) return false; - } + b->batch_page = page_address(page); return true; } -- GitLab From 018e5191c6e0b046bf0d2942f402627162c6b29a Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Thu, 10 May 2018 18:08:23 +0100 Subject: [PATCH 131/604] tty: pl011: Avoid spuriously stuck-off interrupts commit 4a7e625ce50412a7711efa0f2ef0b96ce3826759 upstream. Commit 9b96fbacda34 ("serial: PL011: clear pending interrupts") clears the RX and receive timeout interrupts on pl011 startup, to avoid a screaming-interrupt scenario that can occur when the firmware or bootloader leaves these interrupts asserted. This has been noted as an issue when running Linux on qemu [1]. Unfortunately, the above fix seems to lead to potential misbehaviour if the RX FIFO interrupt is asserted _non_ spuriously on driver startup, if the RX FIFO is also already full to the trigger level. Clearing the RX FIFO interrupt does not change the FIFO fill level. In this scenario, because the interrupt is now clear and because the FIFO is already full to the trigger level, no new assertion of the RX FIFO interrupt can occur unless the FIFO is drained back below the trigger level. This never occurs because the pl011 driver is waiting for an RX FIFO interrupt to tell it that there is something to read, and does not read the FIFO at all until that interrupt occurs. Thus, simply clearing "spurious" interrupts on startup may be misguided, since there is no way to be sure that the interrupts are truly spurious, and things can go wrong if they are not. This patch instead clears the interrupt condition by draining the RX FIFO during UART startup, after clearing any potentially spurious interrupt. This should ensure that an interrupt will definitely be asserted if the RX FIFO subsequently becomes sufficiently full. The drain is done at the point of enabling interrupts only. This means that it will occur any time the UART is newly opened through the tty layer. It will not apply to polled-mode use of the UART by kgdboc: since that scenario cannot use interrupts by design, this should not matter. kgdboc will interact badly with "normal" use of the UART in any case: this patch makes no attempt to paper over such issues. This patch does not attempt to address the case where the RX FIFO fills faster than it can be drained: that is a pathological hardware design problem that is beyond the scope of the driver to work around. As a failsafe, the number of poll iterations for draining the FIFO is limited to twice the FIFO size. This will ensure that the kernel at least boots even if it is impossible to drain the FIFO for some reason. [1] [Qemu-devel] [Qemu-arm] [PATCH] pl011: do not put into fifo before enabled the interruption https://lists.gnu.org/archive/html/qemu-devel/2018-01/msg06446.html Reported-by: Wei Xu Cc: Russell King Cc: Linus Walleij Cc: Peter Maydell Fixes: 9b96fbacda34 ("serial: PL011: clear pending interrupts") Signed-off-by: Dave Martin Cc: stable Tested-by: Wei Xu Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 6b1863293fe1..41b0dd67fcce 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1726,10 +1726,26 @@ static int pl011_allocate_irq(struct uart_amba_port *uap) */ static void pl011_enable_interrupts(struct uart_amba_port *uap) { + unsigned int i; + spin_lock_irq(&uap->port.lock); /* Clear out any spuriously appearing RX interrupts */ pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR); + + /* + * RXIS is asserted only when the RX FIFO transitions from below + * to above the trigger threshold. If the RX FIFO is already + * full to the threshold this can't happen and RXIS will now be + * stuck off. Drain the RX FIFO explicitly to fix this: + */ + for (i = 0; i < uap->fifosize * 2; ++i) { + if (pl011_read(uap, REG_FR) & UART01x_FR_RXFE) + break; + + pl011_read(uap, REG_DR); + } + uap->im = UART011_RTIM; if (!pl011_dma_rx_running(uap)) uap->im |= UART011_RXIM; -- GitLab From 13d1c5b17d127afbd947210c5cdd80eaded5d9f4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 6 Jun 2018 17:38:09 +0200 Subject: [PATCH 132/604] kvm: x86: use correct privilege level for sgdt/sidt/fxsave/fxrstor access commit 3c9fa24ca7c9c47605672916491f79e8ccacb9e6 upstream. The functions that were used in the emulation of fxrstor, fxsave, sgdt and sidt were originally meant for task switching, and as such they did not check privilege levels. This is very bad when the same functions are used in the emulation of unprivileged instructions. This is CVE-2018-10853. The obvious fix is to add a new argument to ops->read_std and ops->write_std, which decides whether the access is a "system" access or should use the processor's CPL. Fixes: 129a72a0d3c8 ("KVM: x86: Introduce segmented_write_std", 2017-01-12) Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/kvm_emulate.h | 6 ++++-- arch/x86/kvm/emulate.c | 12 ++++++------ arch/x86/kvm/x86.c | 18 ++++++++++++++---- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index fc3c7e49c8e4..ae357d0afc91 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h @@ -105,11 +105,12 @@ struct x86_emulate_ops { * @addr: [IN ] Linear address from which to read. * @val: [OUT] Value read from memory, zero-extended to 'u_long'. * @bytes: [IN ] Number of bytes to read from memory. + * @system:[IN ] Whether the access is forced to be at CPL0. */ int (*read_std)(struct x86_emulate_ctxt *ctxt, unsigned long addr, void *val, unsigned int bytes, - struct x86_exception *fault); + struct x86_exception *fault, bool system); /* * read_phys: Read bytes of standard (non-emulated/special) memory. @@ -127,10 +128,11 @@ struct x86_emulate_ops { * @addr: [IN ] Linear address to which to write. * @val: [OUT] Value write to memory, zero-extended to 'u_long'. * @bytes: [IN ] Number of bytes to write to memory. + * @system:[IN ] Whether the access is forced to be at CPL0. */ int (*write_std)(struct x86_emulate_ctxt *ctxt, unsigned long addr, void *val, unsigned int bytes, - struct x86_exception *fault); + struct x86_exception *fault, bool system); /* * fetch: Read bytes of standard (non-emulated/special) memory. * Used for instruction fetch. diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 4421bdbb531d..510cfc06701a 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -805,14 +805,14 @@ static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) static int linear_read_system(struct x86_emulate_ctxt *ctxt, ulong linear, void *data, unsigned size) { - return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception); + return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception, true); } static int linear_write_system(struct x86_emulate_ctxt *ctxt, ulong linear, void *data, unsigned int size) { - return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception); + return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception, true); } static int segmented_read_std(struct x86_emulate_ctxt *ctxt, @@ -826,7 +826,7 @@ static int segmented_read_std(struct x86_emulate_ctxt *ctxt, rc = linearize(ctxt, addr, size, false, &linear); if (rc != X86EMUL_CONTINUE) return rc; - return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception); + return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception, false); } static int segmented_write_std(struct x86_emulate_ctxt *ctxt, @@ -840,7 +840,7 @@ static int segmented_write_std(struct x86_emulate_ctxt *ctxt, rc = linearize(ctxt, addr, size, true, &linear); if (rc != X86EMUL_CONTINUE) return rc; - return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception); + return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception, false); } /* @@ -2912,12 +2912,12 @@ static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt, #ifdef CONFIG_X86_64 base |= ((u64)base3) << 32; #endif - r = ops->read_std(ctxt, base + 102, &io_bitmap_ptr, 2, NULL); + r = ops->read_std(ctxt, base + 102, &io_bitmap_ptr, 2, NULL, true); if (r != X86EMUL_CONTINUE) return false; if (io_bitmap_ptr + port/8 > desc_limit_scaled(&tr_seg)) return false; - r = ops->read_std(ctxt, base + io_bitmap_ptr + port/8, &perm, 2, NULL); + r = ops->read_std(ctxt, base + io_bitmap_ptr + port/8, &perm, 2, NULL, true); if (r != X86EMUL_CONTINUE) return false; if ((perm >> bit_idx) & mask) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 95d2709879f3..5ca23af44c81 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4408,10 +4408,15 @@ EXPORT_SYMBOL_GPL(kvm_read_guest_virt); static int emulator_read_std(struct x86_emulate_ctxt *ctxt, gva_t addr, void *val, unsigned int bytes, - struct x86_exception *exception) + struct x86_exception *exception, bool system) { struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); - return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, exception); + u32 access = 0; + + if (!system && kvm_x86_ops->get_cpl(vcpu) == 3) + access |= PFERR_USER_MASK; + + return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access, exception); } static int kvm_read_guest_phys_system(struct x86_emulate_ctxt *ctxt, @@ -4455,12 +4460,17 @@ static int kvm_write_guest_virt_helper(gva_t addr, void *val, unsigned int bytes } static int emulator_write_std(struct x86_emulate_ctxt *ctxt, gva_t addr, void *val, - unsigned int bytes, struct x86_exception *exception) + unsigned int bytes, struct x86_exception *exception, + bool system) { struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); + u32 access = PFERR_WRITE_MASK; + + if (!system && kvm_x86_ops->get_cpl(vcpu) == 3) + access |= PFERR_USER_MASK; return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, - PFERR_WRITE_MASK, exception); + access, exception); } int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, gva_t addr, void *val, -- GitLab From 78e7bbf60c181e0cfcc4e50695ac52bb84d3432a Mon Sep 17 00:00:00 2001 From: Ethan Lee Date: Thu, 31 May 2018 16:13:17 -0700 Subject: [PATCH 133/604] Input: goodix - add new ACPI id for GPD Win 2 touch screen commit 5ca4d1ae9bad0f59bd6f851c39b19f5366953666 upstream. GPD Win 2 Website: http://www.gpd.hk/gpdwin2.asp Tested on a unit from the first production run sent to Indiegogo backers Signed-off-by: Ethan Lee Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/touchscreen/goodix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index 5907fddcc966..c599b5a2373b 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -858,6 +858,7 @@ MODULE_DEVICE_TABLE(i2c, goodix_ts_id); #ifdef CONFIG_ACPI static const struct acpi_device_id goodix_acpi_match[] = { { "GDIX1001", 0 }, + { "GDIX1002", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, goodix_acpi_match); -- GitLab From 05ca7fe5a78933444d46df221b16217713de5840 Mon Sep 17 00:00:00 2001 From: Johannes Wienke Date: Mon, 4 Jun 2018 13:37:26 -0700 Subject: [PATCH 134/604] Input: elan_i2c - add ELAN0612 (Lenovo v330 14IKB) ACPI ID commit e6e7e9cd8eed0e18217c899843bffbe8c7dae564 upstream. Add ELAN0612 to the list of supported touchpads; this ID is used in Lenovo v330 14IKB devices. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=199253 Signed-off-by: Johannes Wienke 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 3851d5715772..aeb8250ab079 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1249,6 +1249,7 @@ static const struct acpi_device_id elan_acpi_id[] = { { "ELAN060B", 0 }, { "ELAN060C", 0 }, { "ELAN0611", 0 }, + { "ELAN0612", 0 }, { "ELAN1000", 0 }, { } }; -- GitLab From ef2aa9f3a78403cd4a50b0e7626b010ca0b71627 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 3 May 2018 22:29:29 +1000 Subject: [PATCH 135/604] crypto: vmx - Remove overly verbose printk from AES init routines commit 1411b5218adbcf1d45ddb260db5553c52e8d917c upstream. In the vmx AES init routines we do a printk(KERN_INFO ...) to report the fallback implementation we're using. However with a slow console this can significantly affect the speed of crypto operations. Using 'cryptsetup benchmark' the removal of the printk() leads to a ~5x speedup for aes-cbc decryption. So remove them. Fixes: 8676590a1593 ("crypto: vmx - Adding AES routines for VMX module") Fixes: 8c755ace357c ("crypto: vmx - Adding CBC routines for VMX module") Fixes: 4f7f60d312b3 ("crypto: vmx - Adding CTR routines for VMX module") Fixes: cc333cd68dfa ("crypto: vmx - Adding GHASH routines for VMX module") Cc: stable@vger.kernel.org # v4.1+ Signed-off-by: Michael Ellerman Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/vmx/aes.c | 2 -- drivers/crypto/vmx/aes_cbc.c | 2 -- drivers/crypto/vmx/aes_ctr.c | 2 -- drivers/crypto/vmx/ghash.c | 2 -- 4 files changed, 8 deletions(-) diff --git a/drivers/crypto/vmx/aes.c b/drivers/crypto/vmx/aes.c index 022c7ab7351a..b0cd5aff3822 100644 --- a/drivers/crypto/vmx/aes.c +++ b/drivers/crypto/vmx/aes.c @@ -53,8 +53,6 @@ static int p8_aes_init(struct crypto_tfm *tfm) alg, PTR_ERR(fallback)); return PTR_ERR(fallback); } - printk(KERN_INFO "Using '%s' as fallback implementation.\n", - crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback)); crypto_cipher_set_flags(fallback, crypto_cipher_get_flags((struct diff --git a/drivers/crypto/vmx/aes_cbc.c b/drivers/crypto/vmx/aes_cbc.c index 94ad5c0adbcb..46131701c378 100644 --- a/drivers/crypto/vmx/aes_cbc.c +++ b/drivers/crypto/vmx/aes_cbc.c @@ -55,8 +55,6 @@ static int p8_aes_cbc_init(struct crypto_tfm *tfm) alg, PTR_ERR(fallback)); return PTR_ERR(fallback); } - printk(KERN_INFO "Using '%s' as fallback implementation.\n", - crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback)); crypto_blkcipher_set_flags( fallback, diff --git a/drivers/crypto/vmx/aes_ctr.c b/drivers/crypto/vmx/aes_ctr.c index 7cf6d31c1123..6ef7548c5c87 100644 --- a/drivers/crypto/vmx/aes_ctr.c +++ b/drivers/crypto/vmx/aes_ctr.c @@ -53,8 +53,6 @@ static int p8_aes_ctr_init(struct crypto_tfm *tfm) alg, PTR_ERR(fallback)); return PTR_ERR(fallback); } - printk(KERN_INFO "Using '%s' as fallback implementation.\n", - crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback)); crypto_blkcipher_set_flags( fallback, diff --git a/drivers/crypto/vmx/ghash.c b/drivers/crypto/vmx/ghash.c index 27a94a119009..1c4b5b889fba 100644 --- a/drivers/crypto/vmx/ghash.c +++ b/drivers/crypto/vmx/ghash.c @@ -64,8 +64,6 @@ static int p8_ghash_init_tfm(struct crypto_tfm *tfm) alg, PTR_ERR(fallback)); return PTR_ERR(fallback); } - printk(KERN_INFO "Using '%s' as fallback implementation.\n", - crypto_tfm_alg_driver_name(crypto_shash_tfm(fallback))); crypto_shash_set_flags(fallback, crypto_shash_get_flags((struct crypto_shash -- GitLab From 20f4d771b3098d5d559c0d7c65092f90da4352c1 Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Tue, 17 Apr 2018 14:53:13 -0500 Subject: [PATCH 136/604] crypto: omap-sham - fix memleak commit 9dbc8a0328efa485a6f5b68b867f9f523a3fbeff upstream. Fixes: 8043bb1ae03cb ("crypto: omap-sham - convert driver logic to use sgs for data xmit") The memory pages freed in omap_sham_finish_req() were less than those allocated in omap_sham_copy_sgs(). Cc: stable@vger.kernel.org Signed-off-by: Bin Liu Acked-by: Tero Kristo Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/omap-sham.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index d8305ddf87d0..ff6ac4e824b5 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -1081,7 +1081,7 @@ static void omap_sham_finish_req(struct ahash_request *req, int err) if (test_bit(FLAGS_SGS_COPIED, &dd->flags)) free_pages((unsigned long)sg_virt(ctx->sg), - get_order(ctx->sg->length)); + get_order(ctx->sg->length + ctx->bufcnt)); if (test_bit(FLAGS_SGS_ALLOCED, &dd->flags)) kfree(ctx->sg); -- GitLab From f09a7b0eead737b33d940bf5c2509ca1441e9590 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 14 Jun 2018 15:23:19 +0200 Subject: [PATCH 137/604] perf: sync up x86/.../cpufeatures.h The x86 copy of cpufeatures.h is now out of sync, so fix that. Signed-off-by: Greg Kroah-Hartman --- tools/arch/x86/include/asm/cpufeatures.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index c278f276c9b3..aea30afeddb8 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -104,7 +104,7 @@ #define X86_FEATURE_EXTD_APICID ( 3*32+26) /* has extended APICID (8 bits) */ #define X86_FEATURE_AMD_DCM ( 3*32+27) /* multi-node processor */ #define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */ -#define X86_FEATURE_EAGER_FPU ( 3*32+29) /* "eagerfpu" Non lazy FPU restore */ +/* free, was #define X86_FEATURE_EAGER_FPU ( 3*32+29) * "eagerfpu" Non lazy FPU restore */ #define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ -- GitLab From 8e52b94e19d82e2be4f3bf3699c8f39f4c6cc478 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 16 Jun 2018 09:52:35 +0200 Subject: [PATCH 138/604] Linux 4.9.109 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1fa9daf219c4..1570cc85313d 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 108 +SUBLEVEL = 109 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From e1815b3eba5b56be2a210409b5df13d9e32221b6 Mon Sep 17 00:00:00 2001 From: Lianjun Huang Date: Sat, 16 Jun 2018 22:59:46 +0800 Subject: [PATCH 139/604] ANDROID: sdcardfs: fix potential crash when reserved_mb is not zero sdcardfs_mkdir() calls check_min_free_space(). When reserved_mb is not zero, a negative dentry will be passed to ext4_statfs() at last and ext4_statfs() will crash. The parent dentry is positive. So we use the parent dentry to check free space. Change-Id: I80ab9623fe59ba911f4cc9f0e029a1c6f7ee421b Signed-off-by: Lianjun Huang --- fs/sdcardfs/inode.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 9cdb396d9d37..81fe9e61a792 100644 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -270,6 +270,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode struct dentry *lower_dentry; struct vfsmount *lower_mnt; struct dentry *lower_parent_dentry = NULL; + struct dentry *parent_dentry = NULL; struct path lower_path; struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; @@ -289,11 +290,14 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); /* check disk space */ - if (!check_min_free_space(dentry, 0, 1)) { + parent_dentry = dget_parent(dentry); + if (!check_min_free_space(parent_dentry, 0, 1)) { pr_err("sdcardfs: No minimum free space.\n"); err = -ENOSPC; + dput(parent_dentry); goto out_revert; } + dput(parent_dentry); /* the lower_dentry is negative here */ sdcardfs_get_lower_path(dentry, &lower_path); -- GitLab From 25b2c7e06213dcc9634b30f7309efe330ce9d2c1 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Fri, 1 Jun 2018 20:30:25 +0530 Subject: [PATCH 140/604] msm: camera: util: validate patch offset value While processing the packet patches, validate the destination and source offset value against the destination buffer length and source buffer length. If offset value is greater than buffer length return error. Change-Id: I4a82630558ff4ba0a28891ccec0497346ee904d1 Signed-off-by: Ravikishore Pampana --- .../msm/camera/cam_utils/cam_packet_util.c | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c index 30ab0754c47f..db2629d2a2f9 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c +++ b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.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 @@ -171,6 +171,24 @@ int cam_packet_util_process_patches(struct cam_packet *packet, patch_desc[i].dst_buf_hdl, patch_desc[i].dst_offset, patch_desc[i].src_buf_hdl, patch_desc[i].src_offset); + if (patch_desc[i].src_offset >= src_buf_size) { + CAM_ERR_RATE_LIMIT(CAM_UTIL, + "Inval src offset:0x%x src len:0x%x reqid:%lld", + patch_desc[i].src_offset, + (unsigned int)src_buf_size, + packet->header.request_id); + return -EINVAL; + } + + if (patch_desc[i].dst_offset >= dst_buf_len) { + CAM_ERR_RATE_LIMIT(CAM_UTIL, + "Inval dst offset:0x%x dst len:0x%x reqid:%lld", + patch_desc[i].dst_offset, + (unsigned int)dst_buf_len, + packet->header.request_id); + return -EINVAL; + } + dst_cpu_addr = (uint32_t *)((uint8_t *)dst_cpu_addr + patch_desc[i].dst_offset); temp += patch_desc[i].src_offset; -- GitLab From b4f4aa3fe8d856ab19265d701401f8c07f73b8b3 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Thu, 26 Apr 2018 14:41:10 -0700 Subject: [PATCH 141/604] msm: camera: ife: Changes CSID acquire resource logic The current CSID acquire resource logic assumes that RDI paths need to be acquired from the same HW that IPP path was acquired from. This change modifies the logic such that RDI and IPP paths can be acquired independent of each other i.e. from any HW that has that particular resource available. Change-Id: I0ac64749532ae647736d356c9085964560420ffc Signed-off-by: Venkat Chinta Signed-off-by: Vishalsingh Hajeri --- .../cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 373 ++++++++++-------- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 172 ++++---- 2 files changed, 305 insertions(+), 240 deletions(-) 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 c1aa501e229d..0901962f87df 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 @@ -225,6 +225,8 @@ static int cam_ife_hw_mgr_start_hw_res( CAM_ERR(CAM_ISP, "Can not start HW resources"); goto err; } + CAM_DBG(CAM_ISP, "Start HW %d Res %d", hw_intf->hw_idx, + isp_hw_res->hw_res[i]->res_id); } else { CAM_ERR(CAM_ISP, "function null"); goto err; @@ -366,7 +368,8 @@ static int cam_ife_mgr_csid_stop_hw( isp_res = hw_mgr_res->hw_res[i]; if (isp_res->hw_intf->hw_idx != base_idx) continue; - + CAM_DBG(CAM_ISP, "base_idx %d res_id %d cnt %u", + base_idx, isp_res->res_id, cnt); stop_res[cnt] = isp_res; cnt++; } @@ -483,8 +486,8 @@ static void cam_ife_mgr_add_base_info( "Add split id = %d for base idx = %d num_base=%d", split_id, base_idx, ctx->num_base); } else { - /*Check if base index is alreay exist in the list */ - for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + /*Check if base index already exists in the list */ + for (i = 0; i < ctx->num_base; i++) { if (ctx->base[i].idx == base_idx) { if (split_id != CAM_ISP_HW_SPLIT_MAX && ctx->base[i].split_id == @@ -495,7 +498,7 @@ static void cam_ife_mgr_add_base_info( } } - if (i == CAM_IFE_HW_NUM_MAX) { + if (i == ctx->num_base) { ctx->base[ctx->num_base].split_id = split_id; ctx->base[ctx->num_base].idx = base_idx; ctx->num_base++; @@ -845,7 +848,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( } ife_src_res->hw_res[i] = vfe_acquire.vfe_in.rsrc_node; CAM_DBG(CAM_ISP, - "acquire success res type :0x%x res id:0x%x", + "acquire success IFE:%d res type :0x%x res id:0x%x", + hw_intf->hw_idx, ife_src_res->hw_res[i]->res_type, ife_src_res->hw_res[i]->res_id); @@ -871,29 +875,75 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( static int cam_ife_mgr_acquire_cid_res( struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_isp_in_port_info *in_port, - uint32_t *cid_res_id, + struct cam_ife_hw_mgr_res **cid_res, enum cam_ife_pix_path_res_id csid_path) { int rc = -1; int i, j; struct cam_ife_hw_mgr *ife_hw_mgr; - struct cam_ife_hw_mgr_res *cid_res; struct cam_hw_intf *hw_intf; + struct cam_ife_hw_mgr_res *cid_res_temp, *cid_res_iterator; struct cam_csid_hw_reserve_resource_args csid_acquire; + uint32_t acquired_cnt = 0; ife_hw_mgr = ife_ctx->hw_mgr; + *cid_res = NULL; - rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &cid_res); + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, cid_res); if (rc) { CAM_ERR(CAM_ISP, "No more free hw mgr resource"); - goto err; + goto end; } - cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_cid, &cid_res); + + cid_res_temp = *cid_res; csid_acquire.res_type = CAM_ISP_RESOURCE_CID; csid_acquire.in_port = in_port; csid_acquire.res_id = csid_path; + CAM_DBG(CAM_ISP, "path %d", csid_path); + + /* Try acquiring CID resource from previously acquired HW */ + list_for_each_entry(cid_res_iterator, &ife_ctx->res_list_ife_cid, + list) { + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!cid_res_iterator->hw_res[i]) + continue; + hw_intf = cid_res_iterator->hw_res[i]->hw_intf; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) { + CAM_DBG(CAM_ISP, + "No ife cid resource from hw %d", + hw_intf->hw_idx); + continue; + } + + cid_res_temp->hw_res[acquired_cnt++] = + csid_acquire.node_res; + + CAM_DBG(CAM_ISP, + "acquired csid(%s)=%d CID rsrc successfully", + (i == 0) ? "left" : "right", + hw_intf->hw_idx); + + if (in_port->usage_type && acquired_cnt == 1 && + csid_path == CAM_IFE_PIX_PATH_RES_IPP) + /* Continue to acquire Right */ + continue; + + if (acquired_cnt) + /* + * If successfully acquired CID from + * previously acquired HW, skip the next + * part + */ + goto acquire_successful; + } + } + + /* Acquire Left if not already acquired */ for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { if (!ife_hw_mgr->csid_devices[i]) continue; @@ -903,31 +953,45 @@ static int cam_ife_mgr_acquire_cid_res( sizeof(csid_acquire)); if (rc) continue; - else + else { + cid_res_temp->hw_res[acquired_cnt++] = + csid_acquire.node_res; break; + } } if (i == CAM_IFE_CSID_HW_NUM_MAX || !csid_acquire.node_res) { - CAM_ERR(CAM_ISP, "Can not acquire ife csid rdi resource"); - goto err; + CAM_ERR(CAM_ISP, "Can not acquire ife cid resource for path %d", + csid_path); + goto put_res; } - cid_res->res_type = CAM_IFE_HW_MGR_RES_CID; - cid_res->res_id = csid_acquire.node_res->res_id; - cid_res->is_dual_vfe = in_port->usage_type; - cid_res->hw_res[0] = csid_acquire.node_res; - cid_res->hw_res[1] = NULL; +acquire_successful: + CAM_DBG(CAM_ISP, "CID left acquired success is_dual %d", + in_port->usage_type); + + cid_res_temp->res_type = CAM_IFE_HW_MGR_RES_CID; /* CID(DT_ID) value of acquire device, require for path */ - *cid_res_id = csid_acquire.node_res->res_id; + cid_res_temp->res_id = csid_acquire.node_res->res_id; + cid_res_temp->is_dual_vfe = in_port->usage_type; + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_cid, cid_res); - if (cid_res->is_dual_vfe) { + /* + * Acquire Right if not already acquired. + * Dual IFE for RDI is not currently supported. + */ + if (cid_res_temp->is_dual_vfe && csid_path + == CAM_IFE_PIX_PATH_RES_IPP && acquired_cnt == 1) { csid_acquire.node_res = NULL; csid_acquire.res_type = CAM_ISP_RESOURCE_CID; csid_acquire.in_port = in_port; - for (j = i + 1; j < CAM_IFE_CSID_HW_NUM_MAX; j++) { + for (j = 0; j < CAM_IFE_CSID_HW_NUM_MAX; j++) { if (!ife_hw_mgr->csid_devices[j]) continue; + if (j == cid_res_temp->hw_res[0]->hw_intf->hw_idx) + continue; + hw_intf = ife_hw_mgr->csid_devices[j]; rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &csid_acquire, sizeof(csid_acquire)); @@ -940,16 +1004,20 @@ static int cam_ife_mgr_acquire_cid_res( if (j == CAM_IFE_CSID_HW_NUM_MAX) { CAM_ERR(CAM_ISP, "Can not acquire ife csid rdi resource"); - goto err; + goto end; } - cid_res->hw_res[1] = csid_acquire.node_res; + cid_res_temp->hw_res[1] = csid_acquire.node_res; + CAM_DBG(CAM_ISP, "CID right acquired success is_dual %d", + in_port->usage_type); } - cid_res->parent = &ife_ctx->res_list_ife_in; + cid_res_temp->parent = &ife_ctx->res_list_ife_in; ife_ctx->res_list_ife_in.child[ - ife_ctx->res_list_ife_in.num_children++] = cid_res; + ife_ctx->res_list_ife_in.num_children++] = cid_res_temp; return 0; -err: +put_res: + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, cid_res); +end: return rc; } @@ -966,35 +1034,25 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_ipp( struct cam_ife_hw_mgr_res *csid_res; struct cam_ife_hw_mgr_res *cid_res; struct cam_hw_intf *hw_intf; - uint32_t cid_res_id; struct cam_csid_hw_reserve_resource_args csid_acquire; + ife_hw_mgr = ife_ctx->hw_mgr; /* get cid resource */ - rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res_id, + rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res, CAM_IFE_PIX_PATH_RES_IPP); if (rc) { CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed"); - goto err; + goto end; } - ife_hw_mgr = ife_ctx->hw_mgr; - rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &csid_res); if (rc) { CAM_ERR(CAM_ISP, "No more free hw mgr resource"); - goto err; + goto end; } - cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); - - csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; - csid_acquire.res_id = CAM_IFE_PIX_PATH_RES_IPP; - csid_acquire.cid = cid_res_id; - csid_acquire.in_port = in_port; - csid_acquire.out_port = in_port->data; csid_res->res_type = CAM_ISP_RESOURCE_PIX_PATH; csid_res->res_id = CAM_IFE_PIX_PATH_RES_IPP; - csid_res->is_dual_vfe = in_port->usage_type; if (in_port->usage_type) csid_res->is_dual_vfe = 1; @@ -1003,66 +1061,60 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_ipp( csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; } - list_for_each_entry(cid_res, &ife_ctx->res_list_ife_cid, - list) { - if (cid_res->res_id != cid_res_id) - continue; - - for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { - if (!cid_res->hw_res[i]) - continue; + /* IPP resource needs to be from same HW as CID resource */ + for (i = 0; i <= csid_res->is_dual_vfe; i++) { + CAM_DBG(CAM_ISP, "i %d is_dual %d", i, csid_res->is_dual_vfe); + csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; + csid_acquire.res_id = CAM_IFE_PIX_PATH_RES_IPP; + csid_acquire.cid = cid_res->hw_res[i]->res_id; + csid_acquire.in_port = in_port; + csid_acquire.out_port = in_port->data; + csid_acquire.node_res = NULL; - hw_intf = ife_hw_mgr->csid_devices[ - cid_res->hw_res[i]->hw_intf->hw_idx]; + hw_intf = cid_res->hw_res[i]->hw_intf; - csid_acquire.node_res = NULL; - if (csid_res->is_dual_vfe) { - if (i == CAM_ISP_HW_SPLIT_LEFT) { - master_idx = hw_intf->hw_idx; - csid_acquire.sync_mode = - CAM_ISP_HW_SYNC_MASTER; - } else { - if (master_idx == -1) { - CAM_ERR(CAM_ISP, - "No Master found"); - goto err; - } - csid_acquire.sync_mode = - CAM_ISP_HW_SYNC_SLAVE; - csid_acquire.master_idx = master_idx; + if (csid_res->is_dual_vfe) { + if (i == CAM_ISP_HW_SPLIT_LEFT) { + master_idx = hw_intf->hw_idx; + csid_acquire.sync_mode = + CAM_ISP_HW_SYNC_MASTER; + } else { + if (master_idx == -1) { + CAM_ERR(CAM_ISP, + "No Master found"); + goto put_res; } + csid_acquire.sync_mode = + CAM_ISP_HW_SYNC_SLAVE; + csid_acquire.master_idx = master_idx; } - - rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, - &csid_acquire, sizeof(csid_acquire)); - if (rc) { - CAM_ERR(CAM_ISP, - "Cannot acquire ife csid ipp resource"); - goto err; - } - - csid_res->hw_res[i] = csid_acquire.node_res; - CAM_DBG(CAM_ISP, - "acquired csid(%s)=%d ipp rsrc successfully", - (i == 0) ? "left" : "right", - hw_intf->hw_idx); - } - if (i == CAM_IFE_CSID_HW_NUM_MAX) { + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) { CAM_ERR(CAM_ISP, - "Can not acquire ife csid ipp resource"); - goto err; + "Cannot acquire ife csid ipp resource"); + goto put_res; } - csid_res->parent = cid_res; - cid_res->child[cid_res->num_children++] = csid_res; + csid_res->hw_res[i] = csid_acquire.node_res; + CAM_DBG(CAM_ISP, + "acquired csid(%s)=%d ipp rsrc successfully", + (i == 0) ? "left" : "right", + hw_intf->hw_idx); } + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); + + csid_res->parent = cid_res; + cid_res->child[cid_res->num_children++] = csid_res; CAM_DBG(CAM_ISP, "acquire res %d", csid_acquire.res_id); return 0; -err: +put_res: + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &csid_res); +end: return rc; } @@ -1099,111 +1151,88 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_isp_in_port_info *in_port) { - int rc = -1; - int i, j; + int rc = -EINVAL; + int i; struct cam_ife_hw_mgr *ife_hw_mgr; struct cam_ife_hw_mgr_res *csid_res; struct cam_ife_hw_mgr_res *cid_res; struct cam_hw_intf *hw_intf; struct cam_isp_out_port_info *out_port; - uint32_t cid_res_id; struct cam_csid_hw_reserve_resource_args csid_acquire; + enum cam_ife_pix_path_res_id path_type; ife_hw_mgr = ife_ctx->hw_mgr; for (i = 0; i < in_port->num_out_res; i++) { out_port = &in_port->data[i]; - if (!cam_ife_hw_mgr_is_rdi_res(out_port->res_type)) + path_type = cam_ife_hw_mgr_get_ife_csid_rdi_res_type( + out_port->res_type); + if (path_type == CAM_IFE_PIX_PATH_RES_MAX) continue; - /* get cid resource */ - rc = cam_ife_mgr_acquire_cid_res(ife_ctx, - in_port, &cid_res_id, - cam_ife_hw_mgr_get_ife_csid_rdi_res_type( - out_port->res_type)); - if (rc) { - CAM_ERR(CAM_ISP, - "Acquire IFE CID resource Failed"); - goto err; + /* get cid resource */ + rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res, + path_type); + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed"); + goto end; } + /* For each RDI we need CID + PATH resource */ rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &csid_res); if (rc) { CAM_ERR(CAM_ISP, "No more free hw mgr resource"); - goto err; + goto end; } - cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); - - /* - * no need to check since we are doing one to one mapping - * between the csid rdi type and out port rdi type - */ memset(&csid_acquire, 0, sizeof(csid_acquire)); - csid_acquire.res_id = - cam_ife_hw_mgr_get_ife_csid_rdi_res_type( - out_port->res_type); + csid_acquire.res_id = path_type; csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; - csid_acquire.cid = cid_res_id; + csid_acquire.cid = cid_res->hw_res[0]->res_id; csid_acquire.in_port = in_port; csid_acquire.out_port = out_port; csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; + csid_acquire.node_res = NULL; - list_for_each_entry(cid_res, &ife_ctx->res_list_ife_cid, - list) { - if (cid_res->res_id != cid_res_id) - continue; - - for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { - if (!cid_res->hw_res[j]) - continue; - - csid_acquire.node_res = NULL; - - hw_intf = ife_hw_mgr->csid_devices[ - cid_res->hw_res[j]->hw_intf->hw_idx]; - rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, - &csid_acquire, sizeof(csid_acquire)); - if (rc) { - CAM_DBG(CAM_ISP, - "CSID Path reserve failed hw=%d rc=%d", - hw_intf->hw_idx, rc); - continue; - } + hw_intf = cid_res->hw_res[0]->hw_intf; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) { + CAM_ERR(CAM_ISP, + "CSID Path reserve failed hw=%d rc=%d cid=%d", + hw_intf->hw_idx, rc, + cid_res->hw_res[0]->res_id); - /* RDI does not need Dual ISP. Break */ - break; - } + goto put_res; + } - if (j == CAM_ISP_HW_SPLIT_MAX && - csid_acquire.node_res == NULL) { - CAM_ERR(CAM_ISP, - "acquire csid rdi rsrc failed, cid %d", - cid_res_id); - goto err; - } + if (csid_acquire.node_res == NULL) { + CAM_ERR(CAM_ISP, "Acquire CSID RDI rsrc failed"); - csid_res->res_type = CAM_ISP_RESOURCE_PIX_PATH; - csid_res->res_id = csid_acquire.res_id; - csid_res->is_dual_vfe = 0; - csid_res->hw_res[0] = csid_acquire.node_res; - csid_res->hw_res[1] = NULL; - CAM_DBG(CAM_ISP, "acquire res %d", - csid_acquire.res_id); - csid_res->parent = cid_res; - cid_res->child[cid_res->num_children++] = - csid_res; - - /* Done with cid_res_id. Break */ - break; + goto put_res; } + + csid_res->res_type = (enum cam_ife_hw_mgr_res_type) + CAM_ISP_RESOURCE_PIX_PATH; + csid_res->res_id = csid_acquire.res_id; + csid_res->is_dual_vfe = 0; + csid_res->hw_res[0] = csid_acquire.node_res; + csid_res->hw_res[1] = NULL; + CAM_DBG(CAM_ISP, "acquire res %d", + csid_acquire.res_id); + csid_res->parent = cid_res; + cid_res->child[cid_res->num_children++] = + csid_res; + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); } return 0; -err: +put_res: + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &csid_res); +end: return rc; } @@ -1870,33 +1899,39 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) */ if (i == ctx->num_base) master_base_idx = ctx->base[0].idx; + CAM_DBG(CAM_ISP, "Stopping master CSID idx %d", master_base_idx); - /* Stop the master CIDs first */ - cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid, - master_base_idx, csid_halt_type); + /* Stop the master CSID path first */ + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, + master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY); - /* stop rest of the CIDs */ + /* stop rest of the CSID paths */ for (i = 0; i < ctx->num_base; i++) { - if (i == master_base_idx) + if (ctx->base[i].idx == master_base_idx) continue; - cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid, - ctx->base[i].idx, csid_halt_type); + CAM_DBG(CAM_ISP, "Stopping CSID idx %d i %d master %d", + ctx->base[i].idx, i, master_base_idx); + + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, + ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY); } - /* Stop the master CSID path first */ - cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, + CAM_DBG(CAM_ISP, "Stopping master CID idx %d", master_base_idx); + + /* Stop the master CIDs first */ + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid, master_base_idx, csid_halt_type); - /* stop rest of the CSID paths */ + /* stop rest of the CIDs */ for (i = 0; i < ctx->num_base; i++) { - if (i == master_base_idx) + if (ctx->base[i].idx == master_base_idx) continue; - - cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, + CAM_DBG(CAM_ISP, "Stopping CID idx %d i %d master %d", + ctx->base[i].idx, i, master_base_idx); + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid, 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__); 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 3edae4a53d28..794a6545f53a 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 @@ -20,6 +20,7 @@ #include "cam_soc_util.h" #include "cam_io_util.h" #include "cam_debug_util.h" +#include "cam_cpas_api.h" /* Timeout value in msec */ #define IFE_CSID_TIMEOUT 1000 @@ -293,6 +294,7 @@ static int cam_ife_csid_cid_get(struct cam_ife_csid_hw *csid_hw, struct cam_ife_csid_cid_data *cid_data; uint32_t i = 0, j = 0; + /* Return already reserved CID if the VC/DT matches */ for (i = 0; i < CAM_IFE_CSID_CID_RES_MAX; i++) { if (csid_hw->cid_res[i].res_state >= CAM_ISP_RESOURCE_STATE_RESERVED) { @@ -547,6 +549,7 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, { int rc = 0; struct cam_ife_csid_cid_data *cid_data; + uint32_t camera_hw_version; CAM_DBG(CAM_ISP, "CSID:%d res_sel:0x%x Lane type:%d lane_num:%d dt:%d vc:%d", @@ -614,12 +617,40 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, goto end; } - if (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_PHY_3 && - csid_hw->hw_intf->hw_idx != 2) { + if (csid_hw->csi2_reserve_cnt == UINT_MAX) { + CAM_ERR(CAM_ISP, + "CSID%d reserve cnt reached max", + csid_hw->hw_intf->hw_idx); rc = -EINVAL; goto end; } + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc); + goto end; + } + CAM_DBG(CAM_ISP, "HW version: %d", camera_hw_version); + + switch (camera_hw_version) { + case CAM_CPAS_TITAN_NONE: + case CAM_CPAS_TITAN_MAX: + CAM_ERR(CAM_ISP, "Invalid HW version: %d", camera_hw_version); + break; + case CAM_CPAS_TITAN_170_V100: + case CAM_CPAS_TITAN_170_V110: + case CAM_CPAS_TITAN_170_V120: + if (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_PHY_3 && + csid_hw->hw_intf->hw_idx != 2) { + rc = -EINVAL; + goto end; + } + break; + default: + break; + } + CAM_DBG(CAM_ISP, "Reserve_cnt %u", csid_hw->csi2_reserve_cnt); + if (csid_hw->csi2_reserve_cnt) { /* current configure res type should match requested res type */ if (csid_hw->res_type != cid_reserv->in_port->res_type) { @@ -652,12 +683,54 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, } } + switch (cid_reserv->res_id) { + case CAM_IFE_PIX_PATH_RES_IPP: + if (csid_hw->ipp_res.res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_DBG(CAM_ISP, + "CSID:%d IPP resource not available", + csid_hw->hw_intf->hw_idx); + rc = -EINVAL; + goto end; + } + break; + case CAM_IFE_PIX_PATH_RES_RDI_0: + case CAM_IFE_PIX_PATH_RES_RDI_1: + case CAM_IFE_PIX_PATH_RES_RDI_2: + case CAM_IFE_PIX_PATH_RES_RDI_3: + if (csid_hw->rdi_res[cid_reserv->res_id].res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "CSID:%d RDI:%d resource not available", + csid_hw->hw_intf->hw_idx, + cid_reserv->res_id); + rc = -EINVAL; + goto end; + } + break; + default: + CAM_ERR(CAM_ISP, "CSID%d: Invalid csid path", + csid_hw->hw_intf->hw_idx); + rc = -EINVAL; + goto end; + } + + rc = cam_ife_csid_cid_get(csid_hw, + &cid_reserv->node_res, + cid_reserv->in_port->vc, + cid_reserv->in_port->dt, + cid_reserv->in_port->res_type); + if (rc) { + CAM_ERR(CAM_ISP, "CSID:%d CID Reserve failed res_type %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->res_type); + goto end; + } + cid_data = (struct cam_ife_csid_cid_data *) + cid_reserv->node_res->res_priv; + if (!csid_hw->csi2_reserve_cnt) { csid_hw->res_type = cid_reserv->in_port->res_type; - /* Take the first CID resource*/ - csid_hw->cid_res[0].res_state = CAM_ISP_RESOURCE_STATE_RESERVED; - cid_data = (struct cam_ife_csid_cid_data *) - csid_hw->cid_res[0].res_priv; csid_hw->csi2_rx_cfg.lane_cfg = cid_reserv->in_port->lane_cfg; @@ -699,71 +772,13 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, csid_hw->csi2_rx_cfg.phy_sel = (cid_reserv->in_port->res_type & 0xFF) - 1; } - - cid_data->vc = cid_reserv->in_port->vc; - cid_data->dt = cid_reserv->in_port->dt; - cid_data->cnt = 1; - cid_reserv->node_res = &csid_hw->cid_res[0]; - csid_hw->csi2_reserve_cnt++; - - CAM_DBG(CAM_ISP, - "CSID:%d CID :%d resource acquired successfully", - csid_hw->hw_intf->hw_idx, - cid_reserv->node_res->res_id); - } else { - switch (cid_reserv->res_id) { - case CAM_IFE_PIX_PATH_RES_IPP: - if (csid_hw->ipp_res.res_state != - CAM_ISP_RESOURCE_STATE_AVAILABLE) { - CAM_DBG(CAM_ISP, - "CSID:%d IPP resource not available", - csid_hw->hw_intf->hw_idx); - rc = -EINVAL; - goto end; - } - break; - case CAM_IFE_PIX_PATH_RES_RDI_0: - case CAM_IFE_PIX_PATH_RES_RDI_1: - case CAM_IFE_PIX_PATH_RES_RDI_2: - case CAM_IFE_PIX_PATH_RES_RDI_3: - if (csid_hw->rdi_res[cid_reserv->res_id].res_state != - CAM_ISP_RESOURCE_STATE_AVAILABLE) { - CAM_DBG(CAM_ISP, - "CSID:%d RDI:%d resource not available", - csid_hw->hw_intf->hw_idx, - cid_reserv->res_id); - rc = -EINVAL; - goto end; - } - break; - default: - CAM_ERR(CAM_ISP, "CSID%d: Invalid csid path", - csid_hw->hw_intf->hw_idx); - rc = -EINVAL; - goto end; - } - - rc = cam_ife_csid_cid_get(csid_hw, - &cid_reserv->node_res, - cid_reserv->in_port->vc, - cid_reserv->in_port->dt, - cid_reserv->in_port->res_type); - /* if success then increment the reserve count */ - if (!rc) { - if (csid_hw->csi2_reserve_cnt == UINT_MAX) { - CAM_ERR(CAM_ISP, - "CSID%d reserve cnt reached max", - csid_hw->hw_intf->hw_idx); - rc = -EINVAL; - } else { - csid_hw->csi2_reserve_cnt++; - CAM_DBG(CAM_ISP, "CSID:%d CID:%d acquired", - csid_hw->hw_intf->hw_idx, - cid_reserv->node_res->res_id); - } - } } + csid_hw->csi2_reserve_cnt++; + CAM_DBG(CAM_ISP, "CSID:%d CID:%d acquired", + csid_hw->hw_intf->hw_idx, + cid_reserv->node_res->res_id); + end: return rc; } @@ -2415,12 +2430,24 @@ static int cam_ife_csid_stop(void *hw_priv, return -EINVAL; } csid_stop = (struct cam_csid_hw_stop_args *) stop_args; + + if (!csid_stop->num_res) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + csid_hw_info = (struct cam_hw_info *)hw_priv; csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + CAM_DBG(CAM_ISP, "CSID:%d num_res %d", + csid_hw->hw_intf->hw_idx, + csid_stop->num_res); /* Stop the resource first */ for (i = 0; i < csid_stop->num_res; i++) { res = csid_stop->node_res[i]; + CAM_DBG(CAM_ISP, "CSID:%d res_type %d res_id %d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id); switch (res->res_type) { case CAM_ISP_RESOURCE_CID: if (csid_hw->res_type == CAM_ISP_IFE_IN_RES_TPG) @@ -2777,6 +2804,7 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, { int rc = -EINVAL; uint32_t i; + uint32_t num_paths; struct cam_ife_csid_path_cfg *path_data; struct cam_ife_csid_cid_data *cid_data; struct cam_hw_info *csid_hw_info; @@ -2828,8 +2856,10 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, ife_csid_hw->hw_intf->hw_ops.write = cam_ife_csid_write; ife_csid_hw->hw_intf->hw_ops.process_cmd = cam_ife_csid_process_cmd; - /*Initialize the CID resoure */ - for (i = 0; i < CAM_IFE_CSID_CID_RES_MAX; i++) { + num_paths = ife_csid_hw->csid_info->csid_reg->cmn_reg->no_pix + + ife_csid_hw->csid_info->csid_reg->cmn_reg->no_rdis; + /* Initialize the CID resource */ + for (i = 0; i < num_paths; i++) { ife_csid_hw->cid_res[i].res_type = CAM_ISP_RESOURCE_CID; ife_csid_hw->cid_res[i].res_id = i; ife_csid_hw->cid_res[i].res_state = -- GitLab From 7d48a28e71e3e56b4c63d420268e4761ee58d992 Mon Sep 17 00:00:00 2001 From: Harsh Shah Date: Wed, 13 Jun 2018 17:38:25 -0700 Subject: [PATCH 142/604] msm: camera: isp: Fix TPG acquire error There was an incorrect check causing a TPG resource failing to acquire. This change will resolve that issue. Change-Id: Ibe332926a826324bd7a613f0c12dbfae04d53676 Signed-off-by: Harsh Shah Signed-off-by: Vishalsingh Hajeri --- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 76 +++++++------------ 1 file changed, 28 insertions(+), 48 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 794a6545f53a..29b9e11a9365 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 @@ -287,12 +287,12 @@ static int cam_ife_csid_get_format_ipp( } static int cam_ife_csid_cid_get(struct cam_ife_csid_hw *csid_hw, - struct cam_isp_resource_node **res, int32_t vc, uint32_t dt, - uint32_t res_type) + struct cam_isp_resource_node **res, int32_t vc, uint32_t dt) { - int rc = 0; struct cam_ife_csid_cid_data *cid_data; - uint32_t i = 0, j = 0; + uint32_t i = 0; + + *res = NULL; /* Return already reserved CID if the VC/DT matches */ for (i = 0; i < CAM_IFE_CSID_CID_RES_MAX; i++) { @@ -300,55 +300,36 @@ static int cam_ife_csid_cid_get(struct cam_ife_csid_hw *csid_hw, CAM_ISP_RESOURCE_STATE_RESERVED) { cid_data = (struct cam_ife_csid_cid_data *) csid_hw->cid_res[i].res_priv; - if (res_type == CAM_ISP_IFE_IN_RES_TPG) { - if (cid_data->tpg_set) { - cid_data->cnt++; - *res = &csid_hw->cid_res[i]; - break; - } - } else { - if (cid_data->vc == vc && cid_data->dt == dt) { - cid_data->cnt++; - *res = &csid_hw->cid_res[i]; - break; - } + if (cid_data->vc == vc && cid_data->dt == dt) { + cid_data->cnt++; + *res = &csid_hw->cid_res[i]; + return 0; } } } - if (i == CAM_IFE_CSID_CID_RES_MAX) { - if (res_type == CAM_ISP_IFE_IN_RES_TPG) { - CAM_ERR(CAM_ISP, "CSID:%d TPG CID not available", - csid_hw->hw_intf->hw_idx); - rc = -EINVAL; - } - - for (j = 0; j < CAM_IFE_CSID_CID_RES_MAX; j++) { - if (csid_hw->cid_res[j].res_state == - CAM_ISP_RESOURCE_STATE_AVAILABLE) { - cid_data = (struct cam_ife_csid_cid_data *) - csid_hw->cid_res[j].res_priv; - cid_data->vc = vc; - cid_data->dt = dt; - cid_data->cnt = 1; - csid_hw->cid_res[j].res_state = - CAM_ISP_RESOURCE_STATE_RESERVED; - *res = &csid_hw->cid_res[j]; - CAM_DBG(CAM_ISP, "CSID:%d CID %d allocated", - csid_hw->hw_intf->hw_idx, - csid_hw->cid_res[j].res_id); - break; - } - } - - if (j == CAM_IFE_CSID_CID_RES_MAX) { - CAM_ERR(CAM_ISP, "CSID:%d Free cid is not available", - csid_hw->hw_intf->hw_idx); - rc = -EINVAL; + for (i = 0; i < CAM_IFE_CSID_CID_RES_MAX; i++) { + if (csid_hw->cid_res[i].res_state == + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + cid_data = (struct cam_ife_csid_cid_data *) + csid_hw->cid_res[i].res_priv; + cid_data->vc = vc; + cid_data->dt = dt; + cid_data->cnt = 1; + csid_hw->cid_res[i].res_state = + CAM_ISP_RESOURCE_STATE_RESERVED; + *res = &csid_hw->cid_res[i]; + CAM_DBG(CAM_ISP, "CSID:%d CID %d allocated", + csid_hw->hw_intf->hw_idx, + csid_hw->cid_res[i].res_id); + return 0; } } - return rc; + CAM_ERR(CAM_ISP, "CSID:%d Free cid is not available", + csid_hw->hw_intf->hw_idx); + + return -EINVAL; } @@ -718,8 +699,7 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, rc = cam_ife_csid_cid_get(csid_hw, &cid_reserv->node_res, cid_reserv->in_port->vc, - cid_reserv->in_port->dt, - cid_reserv->in_port->res_type); + cid_reserv->in_port->dt); if (rc) { CAM_ERR(CAM_ISP, "CSID:%d CID Reserve failed res_type %d", csid_hw->hw_intf->hw_idx, -- GitLab From 664d21537d890234b147eeba563d8e59f70f0467 Mon Sep 17 00:00:00 2001 From: Shubhashree Dhar Date: Tue, 29 May 2018 17:47:16 +0530 Subject: [PATCH 143/604] ARM: dts: msm: update sleep vote node for sdm670 Display module keeps fix sleep vote on mnoc, ebi and llcc. This does not need the split vote because it is same for all three clients. Single node creation also reduces the bus vote latency. Change-Id: I5fd1d32d8301893134c3b5e776b19a1fc8f18491 Signed-off-by: Shubhashree Dhar --- arch/arm64/boot/dts/qcom/sdm670-sde.dtsi | 28 ++++-------------------- 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi index 4ca400157b60..fb717f3f392f 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi @@ -249,33 +249,13 @@ /* data and reg bus scale settings */ qcom,sde-data-bus { - qcom,msm-bus,name = "mdss_sde_mnoc"; + qcom,msm-bus,name = "mdss_sde"; qcom,msm-bus,num-cases = <3>; qcom,msm-bus,num-paths = <2>; qcom,msm-bus,vectors-KBps = - <22 773 0 0>, <23 773 0 0>, - <22 773 0 6400000>, <23 773 0 6400000>, - <22 773 0 6400000>, <23 773 0 6400000>; - }; - - qcom,sde-llcc-bus { - qcom,msm-bus,name = "mdss_sde_llcc"; - qcom,msm-bus,num-cases = <3>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - <132 770 0 0>, - <132 770 0 6400000>, - <132 770 0 6400000>; - }; - - qcom,sde-ebi-bus { - qcom,msm-bus,name = "mdss_sde_ebi"; - qcom,msm-bus,num-cases = <3>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - <129 512 0 0>, - <129 512 0 6400000>, - <129 512 0 6400000>; + <22 512 0 0>, <23 512 0 0>, + <22 512 0 6400000>, <23 512 0 6400000>, + <22 512 0 6400000>, <23 512 0 6400000>; }; qcom,sde-reg-bus { -- GitLab From e7fd5b18769d5b807f2beb1c9045c059bccbd7ce Mon Sep 17 00:00:00 2001 From: Juri Lelli Date: Wed, 3 May 2017 14:30:48 +0100 Subject: [PATCH 144/604] UPSTREAM: cpufreq: schedutil: use now as reference when aggregating shared policy requests Currently, sugov_next_freq_shared() uses last_freq_update_time as a reference to decide when to start considering CPU contributions as stale. However, since last_freq_update_time is set by the last CPU that issued a frequency transition, this might cause problems in certain cases. In practice, the detection of stale utilization values fails whenever the CPU with such values was the last to update the policy. For example (and please note again that the SCHED_CPUFREQ_RT flag is not the problem here, but only the detection of after how much time that flag has to be considered stale), suppose a policy with 2 CPUs: CPU0 | CPU1 | | RT task scheduled | SCHED_CPUFREQ_RT is set | CPU1->last_update = now | freq transition to max | last_freq_update_time = now | more than TICK_NSEC nsecs | a small CFS wakes up | CPU0->last_update = now1 | delta_ns(CPU0) < TICK_NSEC* | CPU0's util is considered | delta_ns(CPU1) = | last_freq_update_time - | CPU1->last_update = 0 | < TICK_NSEC | CPU1 is still considered | CPU1->SCHED_CPUFREQ_RT is set | we stay at max (until CPU1 | exits from idle) | * delta_ns is actually negative as now1 > last_freq_update_time While last_freq_update_time is a sensible reference for rate limiting, it doesn't seem to be useful for working around stale CPU states. Fix the problem by always considering now (time) as the reference for deciding when CPUs have stale contributions. Bug: 109836581 Signed-off-by: Juri Lelli Acked-by: Vincent Guittot Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki (cherry picked from commit d86ab9cff8b936aadde444d0e263a8db5ff0349b) --- kernel/sched/cpufreq_schedutil.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index 3edb2bbee896..0526dc0365db 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -304,11 +304,10 @@ static void sugov_update_single(struct update_util_data *hook, u64 time, sugov_update_commit(sg_policy, time, next_f); } -static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu) +static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu, u64 time) { struct sugov_policy *sg_policy = sg_cpu->sg_policy; struct cpufreq_policy *policy = sg_policy->policy; - u64 last_freq_update_time = sg_policy->last_freq_update_time; unsigned long util = 0, max = 1; unsigned int j; @@ -324,7 +323,7 @@ static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu) * enough, don't take the CPU into account as it probably is * idle now (and clear iowait_boost for it). */ - delta_ns = last_freq_update_time - j_sg_cpu->last_update; + delta_ns = time - j_sg_cpu->last_update; if (delta_ns > TICK_NSEC) { j_sg_cpu->iowait_boost = 0; continue; @@ -368,7 +367,7 @@ static void sugov_update_shared(struct update_util_data *hook, u64 time, if (flags & SCHED_CPUFREQ_DL) next_f = sg_policy->policy->cpuinfo.max_freq; else - next_f = sugov_next_freq_shared(sg_cpu); + next_f = sugov_next_freq_shared(sg_cpu, time); sugov_update_commit(sg_policy, time, next_f); } -- GitLab From 7cecc756ceae616e7c8ea1dbe59c5ed71b4966a4 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Sat, 31 Mar 2018 20:56:23 -0700 Subject: [PATCH 145/604] ANDROID: xt_qtaguid: Remove unnecessary null checks to device's name 'name' will never be NULL since it isn't a plain pointer but an array of char values. ../net/netfilter/xt_qtaguid.c:1195:27: warning: address of array '(*el_dev)->name' will always evaluate to 'true' [-Wpointer-bool-conversion] if (unlikely(!(*el_dev)->name)) { ~~~~~~~~~~~~^~~~ Change-Id: If3b25f17829b43e8a639193fb9cd04ae45947200 Signed-off-by: Nathan Chancellor (cherry picked from android-4.4 commit 207b579e3db6fd0cb6fe40ba3e929635ad748d89) Signed-off-by: Chenbo Feng --- net/netfilter/xt_qtaguid.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c index 3dfa5a000853..d6779099d453 100644 --- a/net/netfilter/xt_qtaguid.c +++ b/net/netfilter/xt_qtaguid.c @@ -1191,11 +1191,6 @@ static void get_dev_and_dir(const struct sk_buff *skb, par->hooknum, __func__); BUG(); } - if (unlikely(!(*el_dev)->name)) { - pr_err("qtaguid[%d]: %s(): no dev->name?!!\n", - par->hooknum, __func__); - BUG(); - } if (skb->dev && *el_dev != skb->dev) { MT_DEBUG("qtaguid[%d]: skb->dev=%p %s vs par->%s=%p %s\n", par->hooknum, skb->dev, skb->dev->name, -- GitLab From f0cd36183bb40e455689f0cf22775d54c32f7109 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Wed, 20 Jun 2018 10:32:09 -0700 Subject: [PATCH 146/604] msm: camera: flash: Optimizing flash off operation Currently Flash off operation clearing torch and flash node current first, which is adding overhead time for off operation. Removing clearing operation make flash off operation quicker. Change-Id: I148cfd82f7d0654792d81cd0d19d89184c4dc152 Signed-off-by: Jigarkumar Zala --- .../cam_sensor_module/cam_flash/cam_flash_core.c | 14 -------------- 1 file changed, 14 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 9b748268a448..f0efd4cd41cf 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 @@ -191,25 +191,11 @@ static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl, int cam_flash_off(struct cam_flash_ctrl *flash_ctrl) { - int i = 0; - if (!flash_ctrl) { CAM_ERR(CAM_FLASH, "Flash control Null"); return -EINVAL; } - for (i = 0; i < flash_ctrl->flash_num_sources; i++) - if (flash_ctrl->flash_trigger[i]) - cam_res_mgr_led_trigger_event( - flash_ctrl->flash_trigger[i], - LED_OFF); - - for (i = 0; i < flash_ctrl->torch_num_sources; i++) - if (flash_ctrl->torch_trigger[i]) - cam_res_mgr_led_trigger_event( - flash_ctrl->torch_trigger[i], - LED_OFF); - if (flash_ctrl->switch_trigger) cam_res_mgr_led_trigger_event(flash_ctrl->switch_trigger, LED_SWITCH_OFF); -- GitLab From d114a20773143767f4c37adc293474b0b2e696ff Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Tue, 19 Jun 2018 12:51:45 -0700 Subject: [PATCH 147/604] msm: camera: reqmgr: Create workq based on driver requirement Currently all workqueues are created as high priority and unbounded, this change allows the driver to set the necessary flags while creating workq. Change-Id: I8bcc4c29419f19c326ca34a6927af9a04480ae40 Signed-off-by: Karthik Anantha Ram --- .../msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c | 4 ++-- .../cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 7 ++++--- .../camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 2 +- .../camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 4 ++-- .../cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c | 3 ++- .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c | 6 ++---- .../msm/camera/cam_req_mgr/cam_req_mgr_core.c | 4 +++- .../msm/camera/cam_req_mgr/cam_req_mgr_workq.c | 14 +++++++++++--- .../msm/camera/cam_req_mgr/cam_req_mgr_workq.h | 16 ++++++++++++++-- 9 files changed, 41 insertions(+), 19 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index a15ccdcf2dcc..d3c39f940f05 100644 --- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.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 @@ -1884,7 +1884,7 @@ int cam_fd_hw_mgr_init(struct device_node *of_node, } rc = cam_req_mgr_workq_create("cam_fd_worker", CAM_FD_WORKQ_NUM_TASK, - &g_fd_hw_mgr.work, CRM_WORKQ_USAGE_IRQ); + &g_fd_hw_mgr.work, CRM_WORKQ_USAGE_IRQ, 0); if (rc) { CAM_ERR(CAM_FD, "Unable to create a worker, rc=%d", rc); goto detach_smmu; 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 16e97ea1f813..c4552f9f0a18 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 @@ -4134,21 +4134,22 @@ static int cam_icp_mgr_create_wq(void) int i; rc = cam_req_mgr_workq_create("icp_command_queue", ICP_WORKQ_NUM_TASK, - &icp_hw_mgr.cmd_work, CRM_WORKQ_USAGE_NON_IRQ); + &icp_hw_mgr.cmd_work, CRM_WORKQ_USAGE_NON_IRQ, + 0); if (rc) { CAM_ERR(CAM_ICP, "unable to create a command worker"); goto cmd_work_failed; } rc = cam_req_mgr_workq_create("icp_message_queue", ICP_WORKQ_NUM_TASK, - &icp_hw_mgr.msg_work, CRM_WORKQ_USAGE_IRQ); + &icp_hw_mgr.msg_work, CRM_WORKQ_USAGE_IRQ, 0); if (rc) { CAM_ERR(CAM_ICP, "unable to create a message worker"); goto msg_work_failed; } rc = cam_req_mgr_workq_create("icp_timer_queue", ICP_WORKQ_NUM_TASK, - &icp_hw_mgr.timer_work, CRM_WORKQ_USAGE_IRQ); + &icp_hw_mgr.timer_work, CRM_WORKQ_USAGE_IRQ, 0); if (rc) { CAM_ERR(CAM_ICP, "unable to create a timer worker"); goto timer_work_failed; 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 c1aa501e229d..4068997905d8 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 @@ -4218,7 +4218,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf) /* Create Worker for ife_hw_mgr with 10 tasks */ rc = cam_req_mgr_workq_create("cam_ife_worker", 10, - &g_ife_hw_mgr.workq, CRM_WORKQ_USAGE_NON_IRQ); + &g_ife_hw_mgr.workq, CRM_WORKQ_USAGE_NON_IRQ, 0); if (rc < 0) { CAM_ERR(CAM_ISP, "Unable to create worker"); goto end; 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 97d076a78c04..fdeee545bc6c 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 @@ -1171,7 +1171,7 @@ static int cam_jpeg_setup_workqs(void) "jpeg_command_queue", CAM_JPEG_WORKQ_NUM_TASK, &g_jpeg_hw_mgr.work_process_frame, - CRM_WORKQ_USAGE_NON_IRQ); + CRM_WORKQ_USAGE_NON_IRQ, 0); if (rc) { CAM_ERR(CAM_JPEG, "unable to create a worker %d", rc); goto work_process_frame_failed; @@ -1181,7 +1181,7 @@ static int cam_jpeg_setup_workqs(void) "jpeg_message_queue", CAM_JPEG_WORKQ_NUM_TASK, &g_jpeg_hw_mgr.work_process_irq_cb, - CRM_WORKQ_USAGE_IRQ); + CRM_WORKQ_USAGE_IRQ, 0); if (rc) { CAM_ERR(CAM_JPEG, "unable to create a worker %d", rc); goto work_process_irq_cb_failed; diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c index a60661e04cd3..0f34c9f15b56 100644 --- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c @@ -989,7 +989,8 @@ int cam_lrme_mgr_register_device( CAM_DBG(CAM_LRME, "Create submit workq for %s", buf); rc = cam_req_mgr_workq_create(buf, CAM_LRME_WORKQ_NUM_TASK, - &hw_device->work, CRM_WORKQ_USAGE_NON_IRQ); + &hw_device->work, CRM_WORKQ_USAGE_NON_IRQ, + 0); if (rc) { CAM_ERR(CAM_LRME, "Unable to create a worker, rc=%d", rc); 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 da42c84f3835..ec392f5d0752 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 @@ -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 @@ -28,8 +28,6 @@ #include "cam_mem_mgr_api.h" #include "cam_smmu_api.h" -#define CAM_LRME_HW_WORKQ_NUM_TASK 30 - static int cam_lrme_hw_dev_util_cdm_acquire(struct cam_lrme_core *lrme_core, struct cam_hw_info *lrme_hw) { @@ -122,7 +120,7 @@ static int cam_lrme_hw_dev_probe(struct platform_device *pdev) rc = cam_req_mgr_workq_create("cam_lrme_hw_worker", CAM_LRME_HW_WORKQ_NUM_TASK, - &lrme_core->work, CRM_WORKQ_USAGE_IRQ); + &lrme_core->work, CRM_WORKQ_USAGE_IRQ, 0); if (rc) { CAM_ERR(CAM_LRME, "Unable to create a workq, rc=%d", rc); goto free_memory; 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 4602d6c135a5..060aaf2c3268 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 @@ -2324,6 +2324,7 @@ int cam_req_mgr_destroy_session( int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) { int rc = 0; + int wq_flag = 0; char buf[128]; struct cam_create_dev_hdl root_dev; struct cam_req_mgr_core_session *cam_session; @@ -2394,8 +2395,9 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) /* Create worker for current link */ snprintf(buf, sizeof(buf), "%x-%x", link_info->session_hdl, link->link_hdl); + wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL; rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS, - &link->workq, CRM_WORKQ_USAGE_NON_IRQ); + &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag); if (rc < 0) { CAM_ERR(CAM_CRM, "FATAL: unable to create worker"); __cam_req_mgr_destroy_link_info(link); diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c index 066efd6fa3e7..3798ef8e6d5f 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c @@ -178,9 +178,10 @@ int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task, } int cam_req_mgr_workq_create(char *name, int32_t num_tasks, - struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq) + struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq, + int flags) { - int32_t i; + int32_t i, wq_flags = 0, max_active_tasks = 0; struct crm_workq_task *task; struct cam_req_mgr_core_workq *crm_workq = NULL; char buf[128] = "crm_workq-"; @@ -192,10 +193,17 @@ int cam_req_mgr_workq_create(char *name, int32_t num_tasks, if (crm_workq == NULL) return -ENOMEM; + wq_flags |= WQ_UNBOUND; + if (flags & CAM_WORKQ_FLAG_HIGH_PRIORITY) + wq_flags |= WQ_HIGHPRI; + + if (flags & CAM_WORKQ_FLAG_SERIAL) + max_active_tasks = 1; + strlcat(buf, name, sizeof(buf)); CAM_DBG(CAM_CRM, "create workque crm_workq-%s", name); crm_workq->job = alloc_workqueue(buf, - WQ_HIGHPRI | WQ_UNBOUND, 0, NULL); + wq_flags, max_active_tasks, NULL); if (!crm_workq->job) { kfree(crm_workq); return -ENOMEM; diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h index eb3b804f97a9..af76ae467346 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h @@ -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 @@ -23,6 +23,15 @@ #include "cam_req_mgr_core.h" +/* Flag to create a high priority workq */ +#define CAM_WORKQ_FLAG_HIGH_PRIORITY (1 << 0) + +/* This flag ensures only one task from a given + * workq will execute at any given point on any + * given CPU. + */ +#define CAM_WORKQ_FLAG_SERIAL (1 << 1) + /* Task priorities, lower the number higher the priority*/ enum crm_task_priority { CRM_TASK_PRIORITY_0, @@ -101,11 +110,14 @@ struct cam_req_mgr_core_workq { * @num_task : Num_tasks to be allocated for workq * @workq : Double pointer worker * @in_irq : Set to one if workq might be used in irq context + * @flags : Bitwise OR of Flags for workq behavior. + * e.g. CAM_REQ_MGR_WORKQ_HIGH_PRIORITY | CAM_REQ_MGR_WORKQ_SERIAL * This function will allocate and create workqueue and pass * the workq pointer to caller. */ int cam_req_mgr_workq_create(char *name, int32_t num_tasks, - struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq); + struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq, + int flags); /** * cam_req_mgr_workq_destroy() -- GitLab From dfb92858fda3c724a401616de2871b38bcd1509c Mon Sep 17 00:00:00 2001 From: Anurag Chouhan Date: Thu, 31 May 2018 12:15:21 +0530 Subject: [PATCH 148/604] icnss: Set iommu attribute DOMAIN_ATTR_CB_STALL_DISABLE The NOC error interrupt to be generated as soon as S1 fault occurs and not dependent on APPS interrupt to be handled first and resume IOMMU by terminating fault transaction. Set iommu DOMAIN_ATTR_CB_STALL_DISABLE attribute this will make sure NOC error will occur before the interrupt handler gets processed by APPS, so Q6 will immediately handle WNOC error interrupt. CRs-Fixed: 2266947 Change-Id: I54fcb2371166e6d1656993e9277463716177761d Signed-off-by: Anurag Chouhan --- drivers/soc/qcom/icnss.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index b8e9268cd55e..49719decd6ec 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -3525,6 +3525,7 @@ static int icnss_smmu_init(struct icnss_priv *priv) int atomic_ctx = 1; int s1_bypass = 1; int fast = 1; + int stall_disable = 1; int ret = 0; icnss_pr_dbg("Initializing SMMU\n"); @@ -3568,6 +3569,16 @@ static int icnss_smmu_init(struct icnss_priv *priv) goto set_attr_fail; } icnss_pr_dbg("SMMU FAST map set\n"); + + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_CB_STALL_DISABLE, + &stall_disable); + if (ret < 0) { + icnss_pr_err("Set stall disable map attribute failed, err = %d\n", + ret); + goto set_attr_fail; + } + icnss_pr_dbg("SMMU STALL DISABLE map set\n"); } ret = arm_iommu_attach_device(&priv->pdev->dev, mapping); -- GitLab From c555f976c80d9eeef61dc8859a35982e8837f768 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Sun, 24 Jun 2018 19:16:11 -0700 Subject: [PATCH 149/604] ARM: dts: msm: Add register base address for sdm670/sdm845 Add register base address for ipe0, ipe1 & bps HW blocks. Change-Id: I81d22abc485512c43b50b3e7e360431ed439a769 Signed-off-by: Karthik Anantha Ram --- arch/arm64/boot/dts/qcom/sdm670-camera.dtsi | 9 +++++++++ arch/arm64/boot/dts/qcom/sdm845-camera.dtsi | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi index 0ba877d0ee69..3311495c1d6e 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi @@ -908,6 +908,9 @@ cam_ipe0: qcom,ipe0 { cell-index = <0>; compatible = "qcom,cam-ipe"; + reg = <0xac87000 0x3000>; + reg-names = "ipe0_top"; + reg-cam-base = <0x87000>; regulator-names = "ipe0-vdd"; ipe0-vdd-supply = <&ipe_0_gdsc>; clock-names = "ipe_0_ahb_clk", @@ -935,6 +938,9 @@ cam_ipe1: qcom,ipe1 { cell-index = <1>; compatible = "qcom,cam-ipe"; + reg = <0xac91000 0x3000>; + reg-names = "ipe1_top"; + reg-cam-base = <0x91000>; regulator-names = "ipe1-vdd"; ipe1-vdd-supply = <&ipe_1_gdsc>; clock-names = "ipe_1_ahb_clk", @@ -962,6 +968,9 @@ cam_bps: qcom,bps { cell-index = <0>; compatible = "qcom,cam-bps"; + reg = <0xac6f000 0x3000>; + reg-names = "bps_top"; + reg-cam-base = <0x6f000>; regulator-names = "bps-vdd"; bps-vdd-supply = <&bps_gdsc>; clock-names = "bps_ahb_clk", diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi index 4ede0bbeee6b..e77dcc357dea 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi @@ -881,6 +881,9 @@ cam_ipe0: qcom,ipe0 { cell-index = <0>; compatible = "qcom,cam-ipe"; + reg = <0xac87000 0x3000>; + reg-names = "ipe0_top"; + reg-cam-base = <0x87000>; regulator-names = "ipe0-vdd"; ipe0-vdd-supply = <&ipe_0_gdsc>; clock-names = "ipe_0_ahb_clk", @@ -908,6 +911,9 @@ cam_ipe1: qcom,ipe1 { cell-index = <1>; compatible = "qcom,cam-ipe"; + reg = <0xac91000 0x3000>; + reg-names = "ipe1_top"; + reg-cam-base = <0x91000>; regulator-names = "ipe1-vdd"; ipe1-vdd-supply = <&ipe_1_gdsc>; clock-names = "ipe_1_ahb_clk", @@ -935,6 +941,9 @@ cam_bps: qcom,bps { cell-index = <0>; compatible = "qcom,cam-bps"; + reg = <0xac6f000 0x3000>; + reg-names = "bps_top"; + reg-cam-base = <0x6f000>; regulator-names = "bps-vdd"; bps-vdd-supply = <&bps_gdsc>; clock-names = "bps_ahb_clk", -- GitLab From 7143cbff9ce1f8bc6ba18eebbca29527677b8382 Mon Sep 17 00:00:00 2001 From: Patrik Torstensson Date: Fri, 13 Apr 2018 15:34:48 -0700 Subject: [PATCH 150/604] ANDROID: Add kconfig to make dm-verity check_at_most_once default enabled This change adds a kernel config for default enable the check_at_most_once dm-verity option. This is to give us the ability to enforce the usage of at_most_once for entry-level phones. Change-Id: Id40416672c4c2209a9866997d8c164b5de5dc7dc Signed-off-by: Patrik Torstensson Bug: 72664474 --- drivers/md/Kconfig | 20 ++++++++++++++++++++ drivers/md/dm-verity-target.c | 8 ++++++++ 2 files changed, 28 insertions(+) diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index e7b8f49e060f..72c45c356054 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -534,4 +534,24 @@ config DM_ANDROID_VERITY of the metadata contents are verified against the key included in the system keyring. Upon success, the underlying verity target is setup. + +config DM_ANDROID_VERITY_AT_MOST_ONCE_DEFAULT_ENABLED + bool "Verity will validate blocks at most once" + 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 + data device, rather than every time. This reduces the overhead + of dm-verity so that it can be used on systems that are memory + and/or CPU constrained. However, it provides a reduced level + of security because only offline tampering of the data device's + content will be detected, not online tampering. + + Hash blocks are still verified each time they are read from the + hash device, since verification of hash blocks is less performance + critical than data blocks, and a hash block will not be verified + any more after all the data blocks it covers have been verified anyway. + + If unsure, say N. endif # MD diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c index d96aa84cacd2..0a7a8287e58c 100644 --- a/drivers/md/dm-verity-target.c +++ b/drivers/md/dm-verity-target.c @@ -1049,6 +1049,14 @@ int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) goto bad; } +#ifdef CONFIG_DM_ANDROID_VERITY_AT_MOST_ONCE_DEFAULT_ENABLED + if (!v->validated_blocks) { + r = verity_alloc_most_once(v); + if (r) + goto bad; + } +#endif + v->hash_per_block_bits = __fls((1 << v->hash_dev_block_bits) / v->digest_size); -- GitLab From 3d95175b586fb47b0da8fa2bee8a0c047fccd148 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 14 Mar 2018 14:48:43 -0700 Subject: [PATCH 151/604] msm: camera: sync: Protect row state read As part of the merge process, ensure we read the correct state of the sync object. Change-Id: Ifbf7932756b6ee50f5c0d983568bfc2e2870819f Signed-off-by: Karthik Anantha Ram --- drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c | 4 ++++ 1 file changed, 4 insertions(+) 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 cb02dd268ac9..43bce513bff2 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 @@ -75,9 +75,11 @@ uint32_t cam_sync_util_get_group_object_state(struct sync_table_row *table, * counts of error, active and success states of all children objects */ 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_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); return CAM_SYNC_STATE_SIGNALED_ERROR; case CAM_SYNC_STATE_SIGNALED_SUCCESS: success_count++; @@ -88,8 +90,10 @@ uint32_t cam_sync_util_get_group_object_state(struct sync_table_row *table, 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; } + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); } if (active_count) -- GitLab From ccd19d3a38032cdc0f83006f95236b6dfb06a951 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 16 Jun 2018 11:27:56 +0200 Subject: [PATCH 152/604] objtool: update .gitignore file With the recent sync with objtool from 4.14.y, the objtool .gitignore file was forgotten. Fix that up now to properly handle the change in where the autogenerated files live. Signed-off-by: Greg Kroah-Hartman --- tools/objtool/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/objtool/.gitignore b/tools/objtool/.gitignore index d3102c865a95..914cff12899b 100644 --- a/tools/objtool/.gitignore +++ b/tools/objtool/.gitignore @@ -1,3 +1,3 @@ -arch/x86/insn/inat-tables.c +arch/x86/lib/inat-tables.c objtool fixdep -- GitLab From c8197f96bcbe89bb108c0741ce5864bb7734486e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 12 May 2018 02:49:30 -0700 Subject: [PATCH 153/604] xfrm6: avoid potential infinite loop in _decode_session6() [ Upstream commit d9f92772e8ec388d070752ee8f187ef8fa18621f ] syzbot found a way to trigger an infinitie loop by overflowing @offset variable that has been forced to use u16 for some very obscure reason in the past. We probably want to look at NEXTHDR_FRAGMENT handling which looks wrong, in a separate patch. In net-next, we shall try to use skb_header_pointer() instead of pskb_may_pull(). watchdog: BUG: soft lockup - CPU#1 stuck for 134s! [syz-executor738:4553] Modules linked in: irq event stamp: 13885653 hardirqs last enabled at (13885652): [] restore_regs_and_return_to_kernel+0x0/0x2b hardirqs last disabled at (13885653): [] interrupt_entry+0xb5/0xf0 arch/x86/entry/entry_64.S:625 softirqs last enabled at (13614028): [] tun_napi_alloc_frags drivers/net/tun.c:1478 [inline] softirqs last enabled at (13614028): [] tun_get_user+0x1dd9/0x4290 drivers/net/tun.c:1825 softirqs last disabled at (13614032): [] tun_get_user+0x313f/0x4290 drivers/net/tun.c:1942 CPU: 1 PID: 4553 Comm: syz-executor738 Not tainted 4.17.0-rc3+ #40 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:check_kcov_mode kernel/kcov.c:67 [inline] RIP: 0010:__sanitizer_cov_trace_pc+0x20/0x50 kernel/kcov.c:101 RSP: 0018:ffff8801d8cfe250 EFLAGS: 00000246 ORIG_RAX: ffffffffffffff13 RAX: ffff8801d88a8080 RBX: ffff8801d7389e40 RCX: 0000000000000006 RDX: 0000000000000000 RSI: ffffffff868da4ad RDI: ffff8801c8a53277 RBP: ffff8801d8cfe250 R08: ffff8801d88a8080 R09: ffff8801d8cfe3e8 R10: ffffed003b19fc87 R11: ffff8801d8cfe43f R12: ffff8801c8a5327f R13: 0000000000000000 R14: ffff8801c8a4e5fe R15: ffff8801d8cfe3e8 FS: 0000000000d88940(0000) GS:ffff8801daf00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffffffffff600400 CR3: 00000001acab3000 CR4: 00000000001406e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: _decode_session6+0xc1d/0x14f0 net/ipv6/xfrm6_policy.c:150 __xfrm_decode_session+0x71/0x140 net/xfrm/xfrm_policy.c:2368 xfrm_decode_session_reverse include/net/xfrm.h:1213 [inline] icmpv6_route_lookup+0x395/0x6e0 net/ipv6/icmp.c:372 icmp6_send+0x1982/0x2da0 net/ipv6/icmp.c:551 icmpv6_send+0x17a/0x300 net/ipv6/ip6_icmp.c:43 ip6_input_finish+0x14e1/0x1a30 net/ipv6/ip6_input.c:305 NF_HOOK include/linux/netfilter.h:288 [inline] ip6_input+0xe1/0x5e0 net/ipv6/ip6_input.c:327 dst_input include/net/dst.h:450 [inline] ip6_rcv_finish+0x29c/0xa10 net/ipv6/ip6_input.c:71 NF_HOOK include/linux/netfilter.h:288 [inline] ipv6_rcv+0xeb8/0x2040 net/ipv6/ip6_input.c:208 __netif_receive_skb_core+0x2468/0x3650 net/core/dev.c:4646 __netif_receive_skb+0x2c/0x1e0 net/core/dev.c:4711 netif_receive_skb_internal+0x126/0x7b0 net/core/dev.c:4785 napi_frags_finish net/core/dev.c:5226 [inline] napi_gro_frags+0x631/0xc40 net/core/dev.c:5299 tun_get_user+0x3168/0x4290 drivers/net/tun.c:1951 tun_chr_write_iter+0xb9/0x154 drivers/net/tun.c:1996 call_write_iter include/linux/fs.h:1784 [inline] do_iter_readv_writev+0x859/0xa50 fs/read_write.c:680 do_iter_write+0x185/0x5f0 fs/read_write.c:959 vfs_writev+0x1c7/0x330 fs/read_write.c:1004 do_writev+0x112/0x2f0 fs/read_write.c:1039 __do_sys_writev fs/read_write.c:1112 [inline] __se_sys_writev fs/read_write.c:1109 [inline] __x64_sys_writev+0x75/0xb0 fs/read_write.c:1109 do_syscall_64+0x1b1/0x800 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x49/0xbe Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Cc: Steffen Klassert Cc: Nicolas Dichtel Reported-by: syzbot+0053c8...@syzkaller.appspotmail.com Signed-off-by: Steffen Klassert Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv6/xfrm6_policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index e0f71c01d728..0c7f27a1725f 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -121,7 +121,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) struct flowi6 *fl6 = &fl->u.ip6; int onlyproto = 0; const struct ipv6hdr *hdr = ipv6_hdr(skb); - u16 offset = sizeof(*hdr); + u32 offset = sizeof(*hdr); struct ipv6_opt_hdr *exthdr; const unsigned char *nh = skb_network_header(skb); u16 nhoff = IP6CB(skb)->nhoff; -- GitLab From 8268afc568de4f84e2ea29640ea7229b32b47639 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Fri, 27 Apr 2018 10:45:31 +0200 Subject: [PATCH 154/604] netfilter: ebtables: handle string from userspace with care [ Upstream commit 94c752f99954797da583a84c4907ff19e92550a4 ] strlcpy() can't be safely used on a user-space provided string, as it can try to read beyond the buffer's end, if the latter is not NULL terminated. Leveraging the above, syzbot has been able to trigger the following splat: BUG: KASAN: stack-out-of-bounds in strlcpy include/linux/string.h:300 [inline] BUG: KASAN: stack-out-of-bounds in compat_mtw_from_user net/bridge/netfilter/ebtables.c:1957 [inline] BUG: KASAN: stack-out-of-bounds in ebt_size_mwt net/bridge/netfilter/ebtables.c:2059 [inline] BUG: KASAN: stack-out-of-bounds in size_entry_mwt net/bridge/netfilter/ebtables.c:2155 [inline] BUG: KASAN: stack-out-of-bounds in compat_copy_entries+0x96c/0x14a0 net/bridge/netfilter/ebtables.c:2194 Write of size 33 at addr ffff8801b0abf888 by task syz-executor0/4504 CPU: 0 PID: 4504 Comm: syz-executor0 Not tainted 4.17.0-rc2+ #40 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+0x1b9/0x294 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 check_memory_region_inline mm/kasan/kasan.c:260 [inline] check_memory_region+0x13e/0x1b0 mm/kasan/kasan.c:267 memcpy+0x37/0x50 mm/kasan/kasan.c:303 strlcpy include/linux/string.h:300 [inline] compat_mtw_from_user net/bridge/netfilter/ebtables.c:1957 [inline] ebt_size_mwt net/bridge/netfilter/ebtables.c:2059 [inline] size_entry_mwt net/bridge/netfilter/ebtables.c:2155 [inline] compat_copy_entries+0x96c/0x14a0 net/bridge/netfilter/ebtables.c:2194 compat_do_replace+0x483/0x900 net/bridge/netfilter/ebtables.c:2285 compat_do_ebt_set_ctl+0x2ac/0x324 net/bridge/netfilter/ebtables.c:2367 compat_nf_sockopt net/netfilter/nf_sockopt.c:144 [inline] compat_nf_setsockopt+0x9b/0x140 net/netfilter/nf_sockopt.c:156 compat_ip_setsockopt+0xff/0x140 net/ipv4/ip_sockglue.c:1279 inet_csk_compat_setsockopt+0x97/0x120 net/ipv4/inet_connection_sock.c:1041 compat_tcp_setsockopt+0x49/0x80 net/ipv4/tcp.c:2901 compat_sock_common_setsockopt+0xb4/0x150 net/core/sock.c:3050 __compat_sys_setsockopt+0x1ab/0x7c0 net/compat.c:403 __do_compat_sys_setsockopt net/compat.c:416 [inline] __se_compat_sys_setsockopt net/compat.c:413 [inline] __ia32_compat_sys_setsockopt+0xbd/0x150 net/compat.c:413 do_syscall_32_irqs_on arch/x86/entry/common.c:323 [inline] do_fast_syscall_32+0x345/0xf9b arch/x86/entry/common.c:394 entry_SYSENTER_compat+0x70/0x7f arch/x86/entry/entry_64_compat.S:139 RIP: 0023:0xf7fb3cb9 RSP: 002b:00000000fff0c26c EFLAGS: 00000282 ORIG_RAX: 000000000000016e RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 0000000000000000 RDX: 0000000000000080 RSI: 0000000020000300 RDI: 00000000000005f4 RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 The buggy address belongs to the page: page:ffffea0006c2afc0 count:0 mapcount:0 mapping:0000000000000000 index:0x0 flags: 0x2fffc0000000000() raw: 02fffc0000000000 0000000000000000 0000000000000000 00000000ffffffff raw: 0000000000000000 ffffea0006c20101 0000000000000000 0000000000000000 page dumped because: kasan: bad access detected Fix the issue replacing the unsafe function with strscpy() and taking care of possible errors. Fixes: 81e675c227ec ("netfilter: ebtables: add CONFIG_COMPAT support") Reported-and-tested-by: syzbot+4e42a04e0bc33cb6c087@syzkaller.appspotmail.com Signed-off-by: Paolo Abeni Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/bridge/netfilter/ebtables.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 0a9222ef904c..da3d373eb5bd 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1923,7 +1923,8 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt, int off, pad = 0; unsigned int size_kern, match_size = mwt->match_size; - strlcpy(name, mwt->u.name, sizeof(name)); + if (strscpy(name, mwt->u.name, sizeof(name)) < 0) + return -EINVAL; if (state->buf_kern_start) dst = state->buf_kern_start + state->buf_kern_offset; -- GitLab From 0063faaa86ddd392c7e870da911d1065a25be423 Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Sat, 19 May 2018 18:22:35 +0300 Subject: [PATCH 155/604] ipvs: fix buffer overflow with sync daemon and service [ Upstream commit 52f96757905bbf0edef47f3ee6c7c784e7f8ff8a ] syzkaller reports for buffer overflow for interface name when starting sync daemons [1] What we do is that we copy user structure into larger stack buffer but later we search NUL past the stack buffer. The same happens for sched_name when adding/editing virtual server. We are restricted by IP_VS_SCHEDNAME_MAXLEN and IP_VS_IFNAME_MAXLEN being used as size in include/uapi/linux/ip_vs.h, so they include the space for NUL. As using strlcpy is wrong for unsafe source, replace it with strscpy and add checks to return EINVAL if source string is not NUL-terminated. The incomplete strlcpy fix comes from 2.6.13. For the netlink interface reduce the len parameter for IPVS_DAEMON_ATTR_MCAST_IFN and IPVS_SVC_ATTR_SCHED_NAME, so that we get proper EINVAL. [1] kernel BUG at lib/string.c:1052! invalid opcode: 0000 [#1] SMP KASAN Dumping ftrace buffer: (ftrace buffer empty) Modules linked in: CPU: 1 PID: 373 Comm: syz-executor936 Not tainted 4.17.0-rc4+ #45 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:fortify_panic+0x13/0x20 lib/string.c:1051 RSP: 0018:ffff8801c976f800 EFLAGS: 00010282 RAX: 0000000000000022 RBX: 0000000000000040 RCX: 0000000000000000 RDX: 0000000000000022 RSI: ffffffff8160f6f1 RDI: ffffed00392edef6 RBP: ffff8801c976f800 R08: ffff8801cf4c62c0 R09: ffffed003b5e4fb0 R10: ffffed003b5e4fb0 R11: ffff8801daf27d87 R12: ffff8801c976fa20 R13: ffff8801c976fae4 R14: ffff8801c976fae0 R15: 000000000000048b FS: 00007fd99f75e700(0000) GS:ffff8801daf00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000200001c0 CR3: 00000001d6843000 CR4: 00000000001406e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: strlen include/linux/string.h:270 [inline] strlcpy include/linux/string.h:293 [inline] do_ip_vs_set_ctl+0x31c/0x1d00 net/netfilter/ipvs/ip_vs_ctl.c:2388 nf_sockopt net/netfilter/nf_sockopt.c:106 [inline] nf_setsockopt+0x7d/0xd0 net/netfilter/nf_sockopt.c:115 ip_setsockopt+0xd8/0xf0 net/ipv4/ip_sockglue.c:1253 udp_setsockopt+0x62/0xa0 net/ipv4/udp.c:2487 ipv6_setsockopt+0x149/0x170 net/ipv6/ipv6_sockglue.c:917 tcp_setsockopt+0x93/0xe0 net/ipv4/tcp.c:3057 sock_common_setsockopt+0x9a/0xe0 net/core/sock.c:3046 __sys_setsockopt+0x1bd/0x390 net/socket.c:1903 __do_sys_setsockopt net/socket.c:1914 [inline] __se_sys_setsockopt net/socket.c:1911 [inline] __x64_sys_setsockopt+0xbe/0x150 net/socket.c:1911 do_syscall_64+0x1b1/0x800 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x447369 RSP: 002b:00007fd99f75dda8 EFLAGS: 00000246 ORIG_RAX: 0000000000000036 RAX: ffffffffffffffda RBX: 00000000006e39e4 RCX: 0000000000447369 RDX: 000000000000048b RSI: 0000000000000000 RDI: 0000000000000003 RBP: 0000000000000000 R08: 0000000000000018 R09: 0000000000000000 R10: 00000000200001c0 R11: 0000000000000246 R12: 00000000006e39e0 R13: 75a1ff93f0896195 R14: 6f745f3168746576 R15: 0000000000000001 Code: 08 5b 41 5c 41 5d 41 5e 41 5f 5d c3 0f 0b 48 89 df e8 d2 8f 48 fa eb de 55 48 89 fe 48 c7 c7 60 65 64 88 48 89 e5 e8 91 dd f3 f9 <0f> 0b 90 90 90 90 90 90 90 90 90 90 90 55 48 89 e5 41 57 41 56 RIP: fortify_panic+0x13/0x20 lib/string.c:1051 RSP: ffff8801c976f800 Reported-and-tested-by: syzbot+aac887f77319868646df@syzkaller.appspotmail.com Fixes: e4ff67513096 ("ipvs: add sync_maxlen parameter for the sync daemon") Fixes: 4da62fc70d7c ("[IPVS]: Fix for overflows") Signed-off-by: Julian Anastasov Acked-by: Simon Horman Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/netfilter/ipvs/ip_vs_ctl.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index c5f2350a2b50..079b3c426720 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -2390,8 +2390,10 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) struct ipvs_sync_daemon_cfg cfg; memset(&cfg, 0, sizeof(cfg)); - strlcpy(cfg.mcast_ifn, dm->mcast_ifn, - sizeof(cfg.mcast_ifn)); + ret = -EINVAL; + if (strscpy(cfg.mcast_ifn, dm->mcast_ifn, + sizeof(cfg.mcast_ifn)) <= 0) + goto out_dec; cfg.syncid = dm->syncid; ret = start_sync_thread(ipvs, &cfg, dm->state); } else { @@ -2429,12 +2431,19 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) } } + if ((cmd == IP_VS_SO_SET_ADD || cmd == IP_VS_SO_SET_EDIT) && + strnlen(usvc.sched_name, IP_VS_SCHEDNAME_MAXLEN) == + IP_VS_SCHEDNAME_MAXLEN) { + ret = -EINVAL; + goto out_unlock; + } + /* Check for valid protocol: TCP or UDP or SCTP, even for fwmark!=0 */ if (usvc.protocol != IPPROTO_TCP && usvc.protocol != IPPROTO_UDP && usvc.protocol != IPPROTO_SCTP) { - pr_err("set_ctl: invalid protocol: %d %pI4:%d %s\n", + pr_err("set_ctl: invalid protocol: %d %pI4:%d\n", usvc.protocol, &usvc.addr.ip, - ntohs(usvc.port), usvc.sched_name); + ntohs(usvc.port)); ret = -EFAULT; goto out_unlock; } @@ -2863,7 +2872,7 @@ static const struct nla_policy ip_vs_cmd_policy[IPVS_CMD_ATTR_MAX + 1] = { static const struct nla_policy ip_vs_daemon_policy[IPVS_DAEMON_ATTR_MAX + 1] = { [IPVS_DAEMON_ATTR_STATE] = { .type = NLA_U32 }, [IPVS_DAEMON_ATTR_MCAST_IFN] = { .type = NLA_NUL_STRING, - .len = IP_VS_IFNAME_MAXLEN }, + .len = IP_VS_IFNAME_MAXLEN - 1 }, [IPVS_DAEMON_ATTR_SYNC_ID] = { .type = NLA_U32 }, [IPVS_DAEMON_ATTR_SYNC_MAXLEN] = { .type = NLA_U16 }, [IPVS_DAEMON_ATTR_MCAST_GROUP] = { .type = NLA_U32 }, @@ -2881,7 +2890,7 @@ static const struct nla_policy ip_vs_svc_policy[IPVS_SVC_ATTR_MAX + 1] = { [IPVS_SVC_ATTR_PORT] = { .type = NLA_U16 }, [IPVS_SVC_ATTR_FWMARK] = { .type = NLA_U32 }, [IPVS_SVC_ATTR_SCHED_NAME] = { .type = NLA_NUL_STRING, - .len = IP_VS_SCHEDNAME_MAXLEN }, + .len = IP_VS_SCHEDNAME_MAXLEN - 1 }, [IPVS_SVC_ATTR_PE_NAME] = { .type = NLA_NUL_STRING, .len = IP_VS_PENAME_MAXLEN }, [IPVS_SVC_ATTR_FLAGS] = { .type = NLA_BINARY, -- GitLab From 46bada0a9367ad54eda95669bec8efc078ecce51 Mon Sep 17 00:00:00 2001 From: Hao Wei Tee Date: Tue, 29 May 2018 10:25:17 +0300 Subject: [PATCH 156/604] iwlwifi: pcie: compare with number of IRQs requested for, not number of CPUs [ Upstream commit ab1068d6866e28bf6427ceaea681a381e5870a4a ] When there are 16 or more logical CPUs, we request for `IWL_MAX_RX_HW_QUEUES` (16) IRQs only as we limit to that number of IRQs, but later on we compare the number of IRQs returned to nr_online_cpus+2 instead of max_irqs, the latter being what we actually asked for. This ends up setting num_rx_queues to 17 which causes lots of out-of-bounds array accesses later on. Compare to max_irqs instead, and also add an assertion in case num_rx_queues > IWM_MAX_RX_HW_QUEUES. This fixes https://bugzilla.kernel.org/show_bug.cgi?id=199551 Fixes: 2e5d4a8f61dc ("iwlwifi: pcie: Add new configuration to enable MSIX") Signed-off-by: Hao Wei Tee Tested-by: Sara Sharon Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index fe32de252e6b..e7b873018dca 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1509,14 +1509,13 @@ static void iwl_pcie_set_interrupt_capa(struct pci_dev *pdev, struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - int max_irqs, num_irqs, i, ret, nr_online_cpus; + int max_irqs, num_irqs, i, ret; u16 pci_cmd; if (!trans->cfg->mq_rx_supported) goto enable_msi; - nr_online_cpus = num_online_cpus(); - max_irqs = min_t(u32, nr_online_cpus + 2, IWL_MAX_RX_HW_QUEUES); + max_irqs = min_t(u32, num_online_cpus() + 2, IWL_MAX_RX_HW_QUEUES); for (i = 0; i < max_irqs; i++) trans_pcie->msix_entries[i].entry = i; @@ -1542,16 +1541,17 @@ static void iwl_pcie_set_interrupt_capa(struct pci_dev *pdev, * Two interrupts less: non rx causes shared with FBQ and RSS. * More than two interrupts: we will use fewer RSS queues. */ - if (num_irqs <= nr_online_cpus) { + if (num_irqs <= max_irqs - 2) { trans_pcie->trans->num_rx_queues = num_irqs + 1; trans_pcie->shared_vec_mask = IWL_SHARED_IRQ_NON_RX | IWL_SHARED_IRQ_FIRST_RSS; - } else if (num_irqs == nr_online_cpus + 1) { + } else if (num_irqs == max_irqs - 1) { trans_pcie->trans->num_rx_queues = num_irqs; trans_pcie->shared_vec_mask = IWL_SHARED_IRQ_NON_RX; } else { trans_pcie->trans->num_rx_queues = num_irqs - 1; } + WARN_ON(trans_pcie->trans->num_rx_queues > IWL_MAX_RX_HW_QUEUES); trans_pcie->alloc_vecs = num_irqs; trans_pcie->msix_enabled = true; -- GitLab From 5dbffe420164137f8b6b733de3d801019d777fa4 Mon Sep 17 00:00:00 2001 From: Ivan Bornyakov Date: Fri, 25 May 2018 20:49:52 +0300 Subject: [PATCH 157/604] atm: zatm: fix memcmp casting [ Upstream commit f9c6442a8f0b1dde9e755eb4ff6fa22bcce4eabc ] memcmp() returns int, but eprom_try_esi() cast it to unsigned char. One can lose significant bits and get 0 from non-0 value returned by the memcmp(). Signed-off-by: Ivan Bornyakov Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/atm/zatm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index 81bfeec67b77..d0fac641e717 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -1151,8 +1151,8 @@ static void eprom_get_byte(struct zatm_dev *zatm_dev, unsigned char *byte, } -static unsigned char eprom_try_esi(struct atm_dev *dev, unsigned short cmd, - int offset, int swap) +static int eprom_try_esi(struct atm_dev *dev, unsigned short cmd, int offset, + int swap) { unsigned char buf[ZEPROM_SIZE]; struct zatm_dev *zatm_dev; -- GitLab From baa3a68614a24bd3e92ad87b6ac31c0a135d342f Mon Sep 17 00:00:00 2001 From: Josh Hill Date: Sun, 27 May 2018 20:10:41 -0400 Subject: [PATCH 158/604] net: qmi_wwan: Add Netgear Aircard 779S MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 2415f3bd059fe050eb98aedf93664d000ceb4e92 ] Add support for Netgear Aircard 779S Signed-off-by: Josh Hill Acked-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Sasha Levin 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 1d56c73574e8..85bc0ca61389 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -808,6 +808,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x05c6, 0x920d, 5)}, {QMI_QUIRK_SET_DTR(0x05c6, 0x9625, 4)}, /* YUGA CLM920-NC5 */ {QMI_FIXED_INTF(0x0846, 0x68a2, 8)}, + {QMI_FIXED_INTF(0x0846, 0x68d3, 8)}, /* Netgear Aircard 779S */ {QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */ {QMI_FIXED_INTF(0x12d1, 0x14ac, 1)}, /* Huawei E1820 */ {QMI_FIXED_INTF(0x1435, 0xd181, 3)}, /* Wistron NeWeb D18Q1 */ -- GitLab From 2fe56703ee8463b0922734a1c94a475790de40aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Rechi=20Vita?= Date: Tue, 22 May 2018 14:30:15 -0700 Subject: [PATCH 159/604] platform/x86: asus-wmi: Fix NULL pointer dereference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 32ffd6e8d1f6cef94bedca15dfcdebdeb590499d ] Do not perform the rfkill cleanup routine when (asus->driver->wlan_ctrl_by_user && ashs_present()) is true, since nothing is registered with the rfkill subsystem in that case. Doing so leads to the following kernel NULL pointer dereference: BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] __mutex_lock_slowpath+0x98/0x120 PGD 1a3aa8067 PUD 1a3b3d067 PMD 0 Oops: 0002 [#1] PREEMPT SMP Modules linked in: bnep ccm binfmt_misc uvcvideo videobuf2_vmalloc videobuf2_memops videobuf2_v4l2 videobuf2_core hid_a4tech videodev x86_pkg_temp_thermal intel_powerclamp coretemp ath3k btusb btrtl btintel bluetooth kvm_intel snd_hda_codec_hdmi kvm snd_hda_codec_realtek snd_hda_codec_generic irqbypass crc32c_intel arc4 i915 snd_hda_intel snd_hda_codec ath9k ath9k_common ath9k_hw ath i2c_algo_bit snd_hwdep mac80211 ghash_clmulni_intel snd_hda_core snd_pcm snd_timer cfg80211 ehci_pci xhci_pci drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops drm xhci_hcd ehci_hcd asus_nb_wmi(-) asus_wmi sparse_keymap r8169 rfkill mxm_wmi serio_raw snd mii mei_me lpc_ich i2c_i801 video soundcore mei i2c_smbus wmi i2c_core mfd_core CPU: 3 PID: 3275 Comm: modprobe Not tainted 4.9.34-gentoo #34 Hardware name: ASUSTeK COMPUTER INC. K56CM/K56CM, BIOS K56CM.206 08/21/2012 task: ffff8801a639ba00 task.stack: ffffc900014cc000 RIP: 0010:[] [] __mutex_lock_slowpath+0x98/0x120 RSP: 0018:ffffc900014cfce0 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffff8801a54315b0 RCX: 00000000c0000100 RDX: 0000000000000001 RSI: 0000000000000000 RDI: ffff8801a54315b4 RBP: ffffc900014cfd30 R08: 0000000000000000 R09: 0000000000000002 R10: 0000000000000000 R11: 0000000000000000 R12: ffff8801a54315b4 R13: ffff8801a639ba00 R14: 00000000ffffffff R15: ffff8801a54315b8 FS: 00007faa254fb700(0000) GS:ffff8801aef80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 00000001a3b1b000 CR4: 00000000001406e0 Stack: ffff8801a54315b8 0000000000000000 ffffffff814733ae ffffc900014cfd28 ffffffff8146a28c ffff8801a54315b0 0000000000000000 ffff8801a54315b0 ffff8801a66f3820 0000000000000000 ffffc900014cfd48 ffffffff816c73e7 Call Trace: [] ? acpi_ut_release_mutex+0x5d/0x61 [] ? acpi_ns_get_node+0x49/0x52 [] mutex_lock+0x17/0x30 [] asus_rfkill_hotplug+0x24/0x1a0 [asus_wmi] [] asus_wmi_rfkill_exit+0x61/0x150 [asus_wmi] [] asus_wmi_remove+0x61/0xb0 [asus_wmi] [] platform_drv_remove+0x28/0x40 [] __device_release_driver+0xa1/0x160 [] device_release_driver+0x23/0x30 [] bus_remove_device+0xfd/0x170 [] device_del+0x139/0x270 [] platform_device_del+0x28/0x90 [] platform_device_unregister+0x12/0x30 [] asus_wmi_unregister_driver+0x19/0x30 [asus_wmi] [] asus_nb_wmi_exit+0x10/0xf26 [asus_nb_wmi] [] SyS_delete_module+0x192/0x270 [] ? exit_to_usermode_loop+0x92/0xa0 [] entry_SYSCALL_64_fastpath+0x13/0x94 Code: e8 5e 30 00 00 8b 03 83 f8 01 0f 84 93 00 00 00 48 8b 43 10 4c 8d 7b 08 48 89 63 10 41 be ff ff ff ff 4c 89 3c 24 48 89 44 24 08 <48> 89 20 4c 89 6c 24 10 eb 1d 4c 89 e7 49 c7 45 08 02 00 00 00 RIP [] __mutex_lock_slowpath+0x98/0x120 RSP CR2: 0000000000000000 ---[ end trace 8d484233fa7cb512 ]--- note: modprobe[3275] exited with preempt_count 2 https://bugzilla.kernel.org/show_bug.cgi?id=196467 Reported-by: red.f0xyz@gmail.com Signed-off-by: João Paulo Rechi Vita Signed-off-by: Andy Shevchenko Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/asus-wmi.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 8a1bfd489c26..ed277685da1d 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -161,6 +161,16 @@ MODULE_LICENSE("GPL"); static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL }; +static bool ashs_present(void) +{ + int i = 0; + while (ashs_ids[i]) { + if (acpi_dev_found(ashs_ids[i++])) + return true; + } + return false; +} + struct bios_args { u32 arg0; u32 arg1; @@ -966,6 +976,9 @@ static int asus_new_rfkill(struct asus_wmi *asus, static void asus_wmi_rfkill_exit(struct asus_wmi *asus) { + if (asus->driver->wlan_ctrl_by_user && ashs_present()) + return; + asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P5"); asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P6"); asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P7"); @@ -2062,16 +2075,6 @@ static int asus_wmi_fan_init(struct asus_wmi *asus) return 0; } -static bool ashs_present(void) -{ - int i = 0; - while (ashs_ids[i]) { - if (acpi_dev_found(ashs_ids[i++])) - return true; - } - return false; -} - /* * WMI Driver */ -- GitLab From 1249ccd806e04a4029d1f3b37143131bfe4850ec Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Wed, 30 May 2018 13:03:51 +1000 Subject: [PATCH 160/604] net/sonic: Use dma_mapping_error() [ Upstream commit 26de0b76d9ba3200f09c6cb9d9618bda338be5f7 ] With CONFIG_DMA_API_DEBUG=y, calling sonic_open() produces the message, "DMA-API: device driver failed to check map error". Add the missing dma_mapping_error() call. Cc: Thomas Bogendoerfer Signed-off-by: Finn Thain Acked-by: Thomas Bogendoerfer Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/natsemi/sonic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/natsemi/sonic.c b/drivers/net/ethernet/natsemi/sonic.c index 612c7a44b26c..23821540ab07 100644 --- a/drivers/net/ethernet/natsemi/sonic.c +++ b/drivers/net/ethernet/natsemi/sonic.c @@ -71,7 +71,7 @@ static int sonic_open(struct net_device *dev) for (i = 0; i < SONIC_NUM_RRS; i++) { dma_addr_t laddr = dma_map_single(lp->device, skb_put(lp->rx_skb[i], SONIC_RBSIZE), SONIC_RBSIZE, DMA_FROM_DEVICE); - if (!laddr) { + if (dma_mapping_error(lp->device, laddr)) { while(i > 0) { /* free any that were mapped successfully */ i--; dma_unmap_single(lp->device, lp->rx_laddr[i], SONIC_RBSIZE, DMA_FROM_DEVICE); -- GitLab From 60649dacb3da3a757a99c9a7e6dd42867e1eb825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damien=20Th=C3=A9bault?= Date: Thu, 31 May 2018 07:04:01 +0000 Subject: [PATCH 161/604] net: dsa: b53: Add BCM5389 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit a95691bc54af1ac4b12c354f91e9cabf1cb068df ] This patch adds support for the BCM5389 switch connected through MDIO. Signed-off-by: Damien Thébault Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/net/dsa/b53.txt | 1 + drivers/net/dsa/b53/b53_common.c | 13 +++++++++++++ drivers/net/dsa/b53/b53_mdio.c | 5 ++++- drivers/net/dsa/b53/b53_priv.h | 1 + 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/dsa/b53.txt b/Documentation/devicetree/bindings/net/dsa/b53.txt index d6c6e41648d4..6192f02af2a9 100644 --- a/Documentation/devicetree/bindings/net/dsa/b53.txt +++ b/Documentation/devicetree/bindings/net/dsa/b53.txt @@ -10,6 +10,7 @@ Required properties: "brcm,bcm53128" "brcm,bcm5365" "brcm,bcm5395" + "brcm,bcm5389" "brcm,bcm5397" "brcm,bcm5398" diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index c26debc531ee..71525950c641 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1515,6 +1515,18 @@ static const struct b53_chip_data b53_switch_chips[] = { .cpu_port = B53_CPU_PORT_25, .duplex_reg = B53_DUPLEX_STAT_FE, }, + { + .chip_id = BCM5389_DEVICE_ID, + .dev_name = "BCM5389", + .vlans = 4096, + .enabled_ports = 0x1f, + .arl_entries = 4, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + }, { .chip_id = BCM5395_DEVICE_ID, .dev_name = "BCM5395", @@ -1825,6 +1837,7 @@ int b53_switch_detect(struct b53_device *dev) else dev->chip_id = BCM5365_DEVICE_ID; break; + case BCM5389_DEVICE_ID: case BCM5395_DEVICE_ID: case BCM5397_DEVICE_ID: case BCM5398_DEVICE_ID: diff --git a/drivers/net/dsa/b53/b53_mdio.c b/drivers/net/dsa/b53/b53_mdio.c index 477a16b5660a..6f47ff1a7952 100644 --- a/drivers/net/dsa/b53/b53_mdio.c +++ b/drivers/net/dsa/b53/b53_mdio.c @@ -285,6 +285,7 @@ static const struct b53_io_ops b53_mdio_ops = { #define B53_BRCM_OUI_1 0x0143bc00 #define B53_BRCM_OUI_2 0x03625c00 #define B53_BRCM_OUI_3 0x00406000 +#define B53_BRCM_OUI_4 0x01410c00 static int b53_mdio_probe(struct mdio_device *mdiodev) { @@ -311,7 +312,8 @@ static int b53_mdio_probe(struct mdio_device *mdiodev) */ if ((phy_id & 0xfffffc00) != B53_BRCM_OUI_1 && (phy_id & 0xfffffc00) != B53_BRCM_OUI_2 && - (phy_id & 0xfffffc00) != B53_BRCM_OUI_3) { + (phy_id & 0xfffffc00) != B53_BRCM_OUI_3 && + (phy_id & 0xfffffc00) != B53_BRCM_OUI_4) { dev_err(&mdiodev->dev, "Unsupported device: 0x%08x\n", phy_id); return -ENODEV; } @@ -360,6 +362,7 @@ static const struct of_device_id b53_of_match[] = { { .compatible = "brcm,bcm53125" }, { .compatible = "brcm,bcm53128" }, { .compatible = "brcm,bcm5365" }, + { .compatible = "brcm,bcm5389" }, { .compatible = "brcm,bcm5395" }, { .compatible = "brcm,bcm5397" }, { .compatible = "brcm,bcm5398" }, diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index f192a673caba..68ab20baa631 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -47,6 +47,7 @@ struct b53_io_ops { enum { BCM5325_DEVICE_ID = 0x25, BCM5365_DEVICE_ID = 0x65, + BCM5389_DEVICE_ID = 0x89, BCM5395_DEVICE_ID = 0x95, BCM5397_DEVICE_ID = 0x97, BCM5398_DEVICE_ID = 0x98, -- GitLab From 1fab25ce8db367f0d6a22baba96bbe49e68ba5c7 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Fri, 15 Jun 2018 02:39:13 +0000 Subject: [PATCH 162/604] Revert "Btrfs: fix scrub to repair raid6 corruption" This reverts commit 186a6519dc94964a4c5c68fca482f20f71551f26. This commit used an incorrect log message. Reported-by: Ben Hutchings Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/raid56.c | 18 ++++-------------- fs/btrfs/volumes.c | 9 +-------- 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index af6a776fa18c..d016d4a79864 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -2161,21 +2161,11 @@ int raid56_parity_recover(struct btrfs_root *root, struct bio *bio, } /* - * Loop retry: - * for 'mirror == 2', reconstruct from all other stripes. - * for 'mirror_num > 2', select a stripe to fail on every retry. + * reconstruct from the q stripe if they are + * asking for mirror 3 */ - if (mirror_num > 2) { - /* - * 'mirror == 3' is to fail the p stripe and - * reconstruct from the q stripe. 'mirror > 3' is to - * fail a data stripe and reconstruct from p+q stripe. - */ - rbio->failb = rbio->real_stripes - (mirror_num - 1); - ASSERT(rbio->failb > 0); - if (rbio->failb <= rbio->faila) - rbio->failb--; - } + if (mirror_num == 3) + rbio->failb = rbio->real_stripes - 2; ret = lock_stripe_add(rbio); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 76017e1b3c0f..c2495cde26f6 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -5186,14 +5186,7 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len) else if (map->type & BTRFS_BLOCK_GROUP_RAID5) ret = 2; else if (map->type & BTRFS_BLOCK_GROUP_RAID6) - /* - * There could be two corrupted data stripes, we need - * to loop retry in order to rebuild the correct data. - * - * Fail a stripe at a time on every retry except the - * stripe under reconstruction. - */ - ret = map->num_stripes; + ret = 3; else ret = 1; free_extent_map(em); -- GitLab From 4e43b6a8b40fcb4a1773857f4610796cf4aa207c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 10 Dec 2017 17:55:02 -0800 Subject: [PATCH 163/604] tcp: do not overshoot window_clamp in tcp_rcv_space_adjust() commit 02db55718d53f9d426cee504c27fb768e9ed4ffe upstream. While rcvbuf is properly clamped by tcp_rmem[2], rcvwin is left to a potentially too big value. It has no serious effect, since : 1) tcp_grow_window() has very strict checks. 2) window_clamp can be mangled by user space to any value anyway. tcp_init_buffer_space() and companions use tcp_full_space(), we use tcp_win_from_space() to avoid reloading sk->sk_rcvbuf Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Acked-by: Wei Wang Acked-by: Neal Cardwell Signed-off-by: David S. Miller Cc: Benjamin Gilbert Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 94a55b83e48c..8999e25fd0e1 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -636,7 +636,7 @@ void tcp_rcv_space_adjust(struct sock *sk) sk->sk_rcvbuf = rcvbuf; /* Make the window clamp follow along. */ - tp->window_clamp = rcvwin; + tp->window_clamp = tcp_win_from_space(rcvbuf); } } tp->rcvq_space.space = copied; -- GitLab From 42ff36e9cb95662ff8a0a0ac1aea54f386068fa4 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Fri, 15 Jun 2018 02:39:14 +0000 Subject: [PATCH 164/604] Btrfs: make raid6 rebuild retry more [ Upstream commit 8810f7517a3bc4ca2d41d022446d3f5fd6b77c09 ] There is a scenario that can end up with rebuild process failing to return good content, i.e. suppose that all disks can be read without problems and if the content that was read out doesn't match its checksum, currently for raid6 btrfs at most retries twice, - the 1st retry is to rebuild with all other stripes, it'll eventually be a raid5 xor rebuild, - if the 1st fails, the 2nd retry will deliberately fail parity p so that it will do raid6 style rebuild, however, the chances are that another non-parity stripe content also has something corrupted, so that the above retries are not able to return correct content, and users will think of this as data loss. More seriouly, if the loss happens on some important internal btree roots, it could refuse to mount. This extends btrfs to do more retries and each retry fails only one stripe. Since raid6 can tolerate 2 disk failures, if there is one more failure besides the failure on which we're recovering, this can always work. The worst case is to retry as many times as the number of raid6 disks, but given the fact that such a scenario is really rare in practice, it's still acceptable. Signed-off-by: Liu Bo Signed-off-by: David Sterba Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/raid56.c | 18 ++++++++++++++---- fs/btrfs/volumes.c | 9 ++++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index d016d4a79864..af6a776fa18c 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -2161,11 +2161,21 @@ int raid56_parity_recover(struct btrfs_root *root, struct bio *bio, } /* - * reconstruct from the q stripe if they are - * asking for mirror 3 + * Loop retry: + * for 'mirror == 2', reconstruct from all other stripes. + * for 'mirror_num > 2', select a stripe to fail on every retry. */ - if (mirror_num == 3) - rbio->failb = rbio->real_stripes - 2; + if (mirror_num > 2) { + /* + * 'mirror == 3' is to fail the p stripe and + * reconstruct from the q stripe. 'mirror > 3' is to + * fail a data stripe and reconstruct from p+q stripe. + */ + rbio->failb = rbio->real_stripes - (mirror_num - 1); + ASSERT(rbio->failb > 0); + if (rbio->failb <= rbio->faila) + rbio->failb--; + } ret = lock_stripe_add(rbio); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index c2495cde26f6..76017e1b3c0f 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -5186,7 +5186,14 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len) else if (map->type & BTRFS_BLOCK_GROUP_RAID5) ret = 2; else if (map->type & BTRFS_BLOCK_GROUP_RAID6) - ret = 3; + /* + * There could be two corrupted data stripes, we need + * to loop retry in order to rebuild the correct data. + * + * Fail a stripe at a time on every retry except the + * stripe under reconstruction. + */ + ret = map->num_stripes; else ret = 1; free_extent_map(em); -- GitLab From c4f24a093f02bc43a602c08550d828ce34477380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gl=C3=B6ckner?= Date: Mon, 14 May 2018 09:40:05 -0500 Subject: [PATCH 165/604] usb: musb: fix remote wakeup racing with suspend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit ebc3dd688cd988754a304147753b13e58de1b5a1 ] It has been observed that writing 0xF2 to the power register while it reads as 0xF4 results in the register having the value 0xF0, i.e. clearing RESUME and setting SUSPENDM in one go does not work. It might also violate the USB spec to transition directly from resume to suspend, especially when not taking T_DRSMDN into account. But this is what happens when a remote wakeup occurs between SetPortFeature USB_PORT_FEAT_SUSPEND on the root hub and musb_bus_suspend being called. This commit returns -EBUSY when musb_bus_suspend is called while remote wakeup is signalled and thus avoids to reset the RESUME bit. Ignoring this error when musb_port_suspend is called from musb_hub_control is ok. Signed-off-by: Daniel Glöckner Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_host.c | 5 ++++- drivers/usb/musb/musb_host.h | 7 +++++-- drivers/usb/musb/musb_virthub.c | 25 +++++++++++++++---------- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index e2bc91585b4f..19b5f08cb423 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -2554,8 +2554,11 @@ static int musb_bus_suspend(struct usb_hcd *hcd) { struct musb *musb = hcd_to_musb(hcd); u8 devctl; + int ret; - musb_port_suspend(musb, true); + ret = musb_port_suspend(musb, true); + if (ret) + return ret; if (!is_host_active(musb)) return 0; diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h index 7bbf01bf4bb0..54d02ed032df 100644 --- a/drivers/usb/musb/musb_host.h +++ b/drivers/usb/musb/musb_host.h @@ -92,7 +92,7 @@ extern void musb_host_rx(struct musb *, u8); extern void musb_root_disconnect(struct musb *musb); extern void musb_host_resume_root_hub(struct musb *musb); extern void musb_host_poke_root_hub(struct musb *musb); -extern void musb_port_suspend(struct musb *musb, bool do_suspend); +extern int musb_port_suspend(struct musb *musb, bool do_suspend); extern void musb_port_reset(struct musb *musb, bool do_reset); extern void musb_host_finish_resume(struct work_struct *work); #else @@ -124,7 +124,10 @@ static inline void musb_root_disconnect(struct musb *musb) {} static inline void musb_host_resume_root_hub(struct musb *musb) {} static inline void musb_host_poll_rh_status(struct musb *musb) {} static inline void musb_host_poke_root_hub(struct musb *musb) {} -static inline void musb_port_suspend(struct musb *musb, bool do_suspend) {} +static inline int musb_port_suspend(struct musb *musb, bool do_suspend) +{ + return 0; +} static inline void musb_port_reset(struct musb *musb, bool do_reset) {} static inline void musb_host_finish_resume(struct work_struct *work) {} #endif diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index 61b5f1c3c5bc..71678a487be2 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -73,14 +73,14 @@ void musb_host_finish_resume(struct work_struct *work) spin_unlock_irqrestore(&musb->lock, flags); } -void musb_port_suspend(struct musb *musb, bool do_suspend) +int musb_port_suspend(struct musb *musb, bool do_suspend) { struct usb_otg *otg = musb->xceiv->otg; u8 power; void __iomem *mbase = musb->mregs; if (!is_host_active(musb)) - return; + return 0; /* NOTE: this doesn't necessarily put PHY into low power mode, * turning off its clock; that's a function of PHY integration and @@ -91,16 +91,20 @@ void musb_port_suspend(struct musb *musb, bool do_suspend) if (do_suspend) { int retries = 10000; - power &= ~MUSB_POWER_RESUME; - power |= MUSB_POWER_SUSPENDM; - musb_writeb(mbase, MUSB_POWER, power); + if (power & MUSB_POWER_RESUME) + return -EBUSY; - /* Needed for OPT A tests */ - power = musb_readb(mbase, MUSB_POWER); - while (power & MUSB_POWER_SUSPENDM) { + if (!(power & MUSB_POWER_SUSPENDM)) { + power |= MUSB_POWER_SUSPENDM; + musb_writeb(mbase, MUSB_POWER, power); + + /* Needed for OPT A tests */ power = musb_readb(mbase, MUSB_POWER); - if (retries-- < 1) - break; + while (power & MUSB_POWER_SUSPENDM) { + power = musb_readb(mbase, MUSB_POWER); + if (retries-- < 1) + break; + } } musb_dbg(musb, "Root port suspended, power %02x", power); @@ -137,6 +141,7 @@ void musb_port_suspend(struct musb *musb, bool do_suspend) schedule_delayed_work(&musb->finish_resume_work, msecs_to_jiffies(USB_RESUME_TIMEOUT)); } + return 0; } void musb_port_reset(struct musb *musb, bool do_reset) -- GitLab From 780617b249e469750a49d38d0cdc845ba7398ea1 Mon Sep 17 00:00:00 2001 From: Xiangning Yu Date: Thu, 7 Jun 2018 13:39:59 +0800 Subject: [PATCH 166/604] bonding: re-evaluate force_primary when the primary slave name changes [ Upstream commit eb55bbf865d9979098c6a7a17cbdb41237ece951 ] There is a timing issue under active-standy mode, when bond_enslave() is called, bond->params.primary might not be initialized yet. Any time the primary slave string changes, bond->force_primary should be set to true to make sure the primary becomes the active slave. Signed-off-by: Xiangning Yu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_options.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 577e57cad1dc..473da3bf10c6 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -1114,6 +1114,7 @@ static int bond_option_primary_set(struct bonding *bond, slave->dev->name); rcu_assign_pointer(bond->primary_slave, slave); strcpy(bond->params.primary, slave->dev->name); + bond->force_primary = true; bond_select_active_slave(bond); goto out; } -- GitLab From c66919125757e2d336de0ac467f8358aca0c1c5b Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Mon, 11 Jun 2018 02:02:54 +0300 Subject: [PATCH 167/604] ipv6: allow PMTU exceptions to local routes [ Upstream commit 0975764684487bf3f7a47eef009e750ea41bd514 ] IPVS setups with local client and remote tunnel server need to create exception for the local virtual IP. What we do is to change PMTU from 64KB (on "lo") to 1460 in the common case. Suggested-by: Martin KaFai Lau Fixes: 45e4fd26683c ("ipv6: Only create RTF_CACHE routes after encountering pmtu exception") Fixes: 7343ff31ebf0 ("ipv6: Don't create clones of host routes.") Signed-off-by: Julian Anastasov Acked-by: David Ahern Acked-by: Martin KaFai Lau Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/route.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index f6ac472acd0f..70fa31e37360 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1373,9 +1373,6 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk, { struct rt6_info *rt6 = (struct rt6_info *)dst; - if (rt6->rt6i_flags & RTF_LOCAL) - return; - if (dst_metric_locked(dst, RTAX_MTU)) return; -- GitLab From 2d34743a2c90361efc91ce626eda2af91f96727d Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Fri, 8 Jun 2018 05:02:31 +0200 Subject: [PATCH 168/604] net/sched: act_simple: fix parsing of TCA_DEF_DATA [ Upstream commit 8d499533e0bc02d44283dbdab03142b599b8ba16 ] use nla_strlcpy() to avoid copying data beyond the length of TCA_DEF_DATA netlink attribute, in case it is less than SIMP_MAX_DATA and it does not end with '\0' character. v2: fix errors in the commit message, thanks Hangbin Liu Fixes: fa1b1cff3d06 ("net_cls_act: Make act_simple use of netlink policy.") Signed-off-by: Davide Caratti Reviewed-by: Simon Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/act_simple.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 289af6f9bb3b..8b2e87e4493e 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -55,22 +55,22 @@ static void tcf_simp_release(struct tc_action *a, int bind) kfree(d->tcfd_defdata); } -static int alloc_defdata(struct tcf_defact *d, char *defdata) +static int alloc_defdata(struct tcf_defact *d, const struct nlattr *defdata) { d->tcfd_defdata = kzalloc(SIMP_MAX_DATA, GFP_KERNEL); if (unlikely(!d->tcfd_defdata)) return -ENOMEM; - strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); + nla_strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); return 0; } -static void reset_policy(struct tcf_defact *d, char *defdata, +static void reset_policy(struct tcf_defact *d, const struct nlattr *defdata, struct tc_defact *p) { spin_lock_bh(&d->tcf_lock); d->tcf_action = p->action; memset(d->tcfd_defdata, 0, SIMP_MAX_DATA); - strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); + nla_strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); spin_unlock_bh(&d->tcf_lock); } @@ -89,7 +89,6 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, struct tcf_defact *d; bool exists = false; int ret = 0, err; - char *defdata; if (nla == NULL) return -EINVAL; @@ -112,8 +111,6 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, return -EINVAL; } - defdata = nla_data(tb[TCA_DEF_DATA]); - if (!exists) { ret = tcf_hash_create(tn, parm->index, est, a, &act_simp_ops, bind, false); @@ -121,7 +118,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, return ret; d = to_defact(*a); - ret = alloc_defdata(d, defdata); + ret = alloc_defdata(d, tb[TCA_DEF_DATA]); if (ret < 0) { tcf_hash_cleanup(*a, est); return ret; @@ -135,7 +132,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, if (!ovr) return -EEXIST; - reset_policy(d, defdata, parm); + reset_policy(d, tb[TCA_DEF_DATA], parm); } if (ret == ACT_P_CREATED) -- GitLab From 6caca347e4b007a645aa6b8bb950fa27b5e221d5 Mon Sep 17 00:00:00 2001 From: Frank van der Linden Date: Tue, 12 Jun 2018 23:09:37 +0000 Subject: [PATCH 169/604] tcp: verify the checksum of the first data segment in a new connection [ Upstream commit 4fd44a98ffe0d048246efef67ed640fdf2098a62 ] commit 079096f103fa ("tcp/dccp: install syn_recv requests into ehash table") introduced an optimization for the handling of child sockets created for a new TCP connection. But this optimization passes any data associated with the last ACK of the connection handshake up the stack without verifying its checksum, because it calls tcp_child_process(), which in turn calls tcp_rcv_state_process() directly. These lower-level processing functions do not do any checksum verification. Insert a tcp_checksum_complete call in the TCP_NEW_SYN_RECEIVE path to fix this. Fixes: 079096f103fa ("tcp/dccp: install syn_recv requests into ehash table") Signed-off-by: Frank van der Linden Signed-off-by: Eric Dumazet Tested-by: Balbir Singh Reviewed-by: Balbir Singh Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_ipv4.c | 4 ++++ net/ipv6/tcp_ipv6.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index b3960738464e..504cdae41013 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1661,6 +1661,10 @@ int tcp_v4_rcv(struct sk_buff *skb) reqsk_put(req); goto discard_it; } + if (tcp_checksum_complete(skb)) { + reqsk_put(req); + goto csum_error; + } if (unlikely(sk->sk_state != TCP_LISTEN)) { inet_csk_reqsk_queue_drop_and_put(sk, req); goto lookup; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index eb624547382f..0a69d39880f2 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1433,6 +1433,10 @@ static int tcp_v6_rcv(struct sk_buff *skb) reqsk_put(req); goto discard_it; } + if (tcp_checksum_complete(skb)) { + reqsk_put(req); + goto csum_error; + } if (unlikely(sk->sk_state != TCP_LISTEN)) { inet_csk_reqsk_queue_drop_and_put(sk, req); goto lookup; -- GitLab From 2435d6b11057c8b02d6a8932501cb980c23e2d05 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Tue, 5 Dec 2017 15:38:24 +0800 Subject: [PATCH 170/604] ALSA: hda/realtek - New codec support for ALC257 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f429e7e494afaded76e62c6f98211a635aa03098 upstream. Add new support for ALC257 codec. [ It's supposed to be almost equivalent with other ALC25x variants, just adding another type and id -- tiwai ] Signed-off-by: Kailang Yang Cc: Signed-off-by: Takashi Iwai Tested-by: Pali Rohár Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 39cd35f6a6df..183436e4a8c1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -333,6 +333,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) case 0x10ec0236: case 0x10ec0255: case 0x10ec0256: + case 0x10ec0257: case 0x10ec0282: case 0x10ec0283: case 0x10ec0286: @@ -2663,6 +2664,7 @@ enum { ALC269_TYPE_ALC298, ALC269_TYPE_ALC255, ALC269_TYPE_ALC256, + ALC269_TYPE_ALC257, ALC269_TYPE_ALC225, ALC269_TYPE_ALC294, ALC269_TYPE_ALC700, @@ -2695,6 +2697,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) case ALC269_TYPE_ALC298: case ALC269_TYPE_ALC255: case ALC269_TYPE_ALC256: + case ALC269_TYPE_ALC257: case ALC269_TYPE_ALC225: case ALC269_TYPE_ALC294: case ALC269_TYPE_ALC700: @@ -6375,6 +6378,10 @@ static int patch_alc269(struct hda_codec *codec) spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */ alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/ break; + case 0x10ec0257: + spec->codec_variant = ALC269_TYPE_ALC257; + spec->gen.mixer_nid = 0; + break; case 0x10ec0225: case 0x10ec0295: case 0x10ec0299: @@ -7361,6 +7368,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = { HDA_CODEC_ENTRY(0x10ec0236, "ALC236", patch_alc269), HDA_CODEC_ENTRY(0x10ec0255, "ALC255", patch_alc269), HDA_CODEC_ENTRY(0x10ec0256, "ALC256", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0257, "ALC257", patch_alc269), HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260), HDA_CODEC_ENTRY(0x10ec0262, "ALC262", patch_alc262), HDA_CODEC_ENTRY(0x10ec0267, "ALC267", patch_alc268), -- GitLab From 42cc42eabafb6bd4e5ea4cbde72f7fb4d24cc7bd Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Sat, 12 May 2018 19:55:00 -0400 Subject: [PATCH 171/604] ext4: fix hole length detection in ext4_ind_map_blocks() commit 2ee3ee06a8fd792765fa3267ddf928997797eec5 upstream. When ext4_ind_map_blocks() computes a length of a hole, it doesn't count with the fact that mapped offset may be somewhere in the middle of the completely empty subtree. In such case it will return too large length of the hole which then results in lseek(SEEK_DATA) to end up returning an incorrect offset beyond the end of the hole. Fix the problem by correctly taking offset within a subtree into account when computing a length of a hole. Fixes: facab4d9711e7aa3532cb82643803e8f1b9518e8 CC: stable@vger.kernel.org Reported-by: Jeff Mahoney Signed-off-by: Jan Kara Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- fs/ext4/indirect.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c index bc15c2c17633..58229c1b4a3d 100644 --- a/fs/ext4/indirect.c +++ b/fs/ext4/indirect.c @@ -560,10 +560,16 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, unsigned epb = inode->i_sb->s_blocksize / sizeof(u32); int i; - /* Count number blocks in a subtree under 'partial' */ - count = 1; - for (i = 0; partial + i != chain + depth - 1; i++) - count *= epb; + /* + * Count number blocks in a subtree under 'partial'. At each + * level we count number of complete empty subtrees beyond + * current offset and then descend into the subtree only + * partially beyond current offset. + */ + count = 0; + for (i = partial - chain + 1; i < depth; i++) + count = count * epb + (epb - offsets[i] - 1); + count++; /* Fill in size of a hole we found */ map->m_pblk = 0; map->m_len = min_t(unsigned int, map->m_len, count); -- GitLab From ade6e140df5c380dbb95605534e400fe27dbc5c0 Mon Sep 17 00:00:00 2001 From: Lukas Czerner Date: Sun, 13 May 2018 19:28:35 -0400 Subject: [PATCH 172/604] ext4: update mtime in ext4_punch_hole even if no blocks are released commit eee597ac931305eff3d3fd1d61d6aae553bc0984 upstream. Currently in ext4_punch_hole we're going to skip the mtime update if there are no actual blocks to release. However we've actually modified the file by zeroing the partial block so the mtime should be updated. Moreover the sync and datasync handling is skipped as well, which is also wrong. Fix it. Signed-off-by: Lukas Czerner Signed-off-by: Theodore Ts'o Reported-by: Joe Habermann Cc: Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inode.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 340428274532..7c025ee1276f 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4038,28 +4038,28 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) EXT4_BLOCK_SIZE_BITS(sb); stop_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb); - /* If there are no blocks to remove, return now */ - if (first_block >= stop_block) - goto out_stop; + /* If there are blocks to remove, do it */ + if (stop_block > first_block) { - down_write(&EXT4_I(inode)->i_data_sem); - ext4_discard_preallocations(inode); + down_write(&EXT4_I(inode)->i_data_sem); + ext4_discard_preallocations(inode); - ret = ext4_es_remove_extent(inode, first_block, - stop_block - first_block); - if (ret) { - up_write(&EXT4_I(inode)->i_data_sem); - goto out_stop; - } + ret = ext4_es_remove_extent(inode, first_block, + stop_block - first_block); + if (ret) { + up_write(&EXT4_I(inode)->i_data_sem); + goto out_stop; + } - if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) - ret = ext4_ext_remove_space(inode, first_block, - stop_block - 1); - else - ret = ext4_ind_remove_space(handle, inode, first_block, - stop_block); + if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) + ret = ext4_ext_remove_space(inode, first_block, + stop_block - 1); + else + ret = ext4_ind_remove_space(handle, inode, first_block, + stop_block); - up_write(&EXT4_I(inode)->i_data_sem); + up_write(&EXT4_I(inode)->i_data_sem); + } if (IS_SYNC(inode)) ext4_handle_sync(handle); -- GitLab From e45ab2d6a89f9c31647efcb368a9c4378f2d76a9 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 25 May 2018 12:51:25 -0400 Subject: [PATCH 173/604] ext4: fix fencepost error in check for inode count overflow during resize commit 4f2f76f751433908364ccff82f437a57d0e6e9b7 upstream. ext4_resize_fs() has an off-by-one bug when checking whether growing of a filesystem will not overflow inode count. As a result it allows a filesystem with 8192 inodes per group to grow to 64TB which overflows inode count to 0 and makes filesystem unusable. Fix it. Cc: stable@vger.kernel.org Fixes: 3f8a6411fbada1fa482276591e037f3b1adcf55b Reported-by: Jaco Kroon Signed-off-by: Jan Kara Signed-off-by: Theodore Ts'o Reviewed-by: Andreas Dilger Signed-off-by: Greg Kroah-Hartman --- fs/ext4/resize.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 95bf46654153..eb720d9e2953 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -1903,7 +1903,7 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count) return 0; n_group = ext4_get_group_number(sb, n_blocks_count - 1); - if (n_group > (0xFFFFFFFFUL / EXT4_INODES_PER_GROUP(sb))) { + if (n_group >= (0xFFFFFFFFUL / EXT4_INODES_PER_GROUP(sb))) { ext4_warning(sb, "resize would cause inodes_count overflow"); return -EINVAL; } -- GitLab From 4f65ebcffa53ae01ffded87f83d92fd0caaafc5d Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Mon, 7 May 2018 19:10:31 +0900 Subject: [PATCH 174/604] driver core: Don't ignore class_dir_create_and_add() failure. commit 84d0c27d6233a9ba0578b20f5a09701eb66cee42 upstream. syzbot is hitting WARN() at kernfs_add_one() [1]. This is because kernfs_create_link() is confused by previous device_add() call which continued without setting dev->kobj.parent field when get_device_parent() failed by memory allocation fault injection. Fix this by propagating the error from class_dir_create_and_add() to the calllers of get_device_parent(). [1] https://syzkaller.appspot.com/bug?id=fae0fb607989ea744526d1c082a5b8de6529116f Signed-off-by: Tetsuo Handa Reported-by: syzbot Cc: Greg Kroah-Hartman Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 03a82d017cf1..a0ed957d738f 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -759,7 +759,7 @@ class_dir_create_and_add(struct class *class, struct kobject *parent_kobj) dir = kzalloc(sizeof(*dir), GFP_KERNEL); if (!dir) - return NULL; + return ERR_PTR(-ENOMEM); dir->class = class; kobject_init(&dir->kobj, &class_dir_ktype); @@ -769,7 +769,7 @@ class_dir_create_and_add(struct class *class, struct kobject *parent_kobj) retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name); if (retval < 0) { kobject_put(&dir->kobj); - return NULL; + return ERR_PTR(retval); } return &dir->kobj; } @@ -1076,6 +1076,10 @@ int device_add(struct device *dev) parent = get_device(dev->parent); kobj = get_device_parent(dev, parent); + if (IS_ERR(kobj)) { + error = PTR_ERR(kobj); + goto parent_error; + } if (kobj) dev->kobj.parent = kobj; @@ -1174,6 +1178,7 @@ int device_add(struct device *dev) kobject_del(&dev->kobj); Error: cleanup_glue_dir(dev, glue_dir); +parent_error: put_device(parent); name_error: kfree(dev->p); @@ -1991,6 +1996,11 @@ int device_move(struct device *dev, struct device *new_parent, device_pm_lock(); new_parent = get_device(new_parent); new_parent_kobj = get_device_parent(dev, new_parent); + if (IS_ERR(new_parent_kobj)) { + error = PTR_ERR(new_parent_kobj); + put_device(new_parent); + goto out; + } pr_debug("device: '%s': %s: moving to '%s'\n", dev_name(dev), __func__, new_parent ? dev_name(new_parent) : ""); -- GitLab From 52ea25b2b88587302a03b2ae8f2dd9b546337cc5 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Tue, 22 May 2018 15:02:12 -0700 Subject: [PATCH 175/604] Btrfs: fix clone vs chattr NODATASUM race commit b5c40d598f5408bd0ca22dfffa82f03cd9433f23 upstream. In btrfs_clone_files(), we must check the NODATASUM flag while the inodes are locked. Otherwise, it's possible that btrfs_ioctl_setflags() will change the flags after we check and we can end up with a party checksummed file. The race window is only a few instructions in size, between the if and the locks which is: 3834 if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode)) 3835 return -EISDIR; where the setflags must be run and toggle the NODATASUM flag (provided the file size is 0). The clone will block on the inode lock, segflags takes the inode lock, changes flags, releases log and clone continues. Not impossible but still needs a lot of bad luck to hit unintentionally. Fixes: 0e7b824c4ef9 ("Btrfs: don't make a file partly checksummed through file clone") CC: stable@vger.kernel.org # 4.4+ Signed-off-by: Omar Sandoval Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba [ update changelog ] Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/ioctl.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index d3dd631432eb..9ac8f3ded704 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -3887,11 +3887,6 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, src->i_sb != inode->i_sb) return -EXDEV; - /* don't make the dst file partly checksummed */ - if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) != - (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) - return -EINVAL; - if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode)) return -EISDIR; @@ -3901,6 +3896,13 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, inode_lock(src); } + /* don't make the dst file partly checksummed */ + if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) != + (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) { + ret = -EINVAL; + goto out_unlock; + } + /* determine range to clone */ ret = -EINVAL; if (off + len > src->i_size || off + len < off) -- GitLab From 9bb94d81206b4980f5c547c07dfdf7a912b73f7b Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Tue, 22 May 2018 15:44:01 -0700 Subject: [PATCH 176/604] Btrfs: fix memory and mount leak in btrfs_ioctl_rm_dev_v2() commit fd4e994bd1f9dc9628e168a7f619bf69f6984635 upstream. If we have invalid flags set, when we error out we must drop our writer counter and free the buffer we allocated for the arguments. This bug is trivially reproduced with the following program on 4.7+: #include #include #include #include #include #include #include #include #include #include int main(int argc, char **argv) { struct btrfs_ioctl_vol_args_v2 vol_args = { .flags = UINT64_MAX, }; int ret; int fd; if (argc != 2) { fprintf(stderr, "usage: %s PATH\n", argv[0]); return EXIT_FAILURE; } fd = open(argv[1], O_WRONLY); if (fd == -1) { perror("open"); return EXIT_FAILURE; } ret = ioctl(fd, BTRFS_IOC_RM_DEV_V2, &vol_args); if (ret == -1) perror("ioctl"); close(fd); return EXIT_SUCCESS; } When unmounting the filesystem, we'll hit the WARN_ON(mnt_get_writers(mnt)) in cleanup_mnt() and also may prevent the filesystem to be remounted read-only as the writer count will stay lifted. Fixes: 6b526ed70cf1 ("btrfs: introduce device delete by devid") CC: stable@vger.kernel.org # 4.9+ Signed-off-by: Omar Sandoval Reviewed-by: Su Yue Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/ioctl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 9ac8f3ded704..cbf512b64597 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -2708,8 +2708,10 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg) } /* Check for compatibility reject unknown flags */ - if (vol_args->flags & ~BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED) - return -EOPNOTSUPP; + if (vol_args->flags & ~BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED) { + ret = -EOPNOTSUPP; + goto out; + } if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, 1)) { -- GitLab From 2102637c85a37f2420751a1cc817c01189a61970 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 5 Jun 2018 12:36:56 +0800 Subject: [PATCH 177/604] btrfs: scrub: Don't use inode pages for device replace commit ac0b4145d662a3b9e34085dea460fb06ede9b69b upstream. [BUG] Btrfs can create compressed extent without checksum (even though it shouldn't), and if we then try to replace device containing such extent, the result device will contain all the uncompressed data instead of the compressed one. Test case already submitted to fstests: https://patchwork.kernel.org/patch/10442353/ [CAUSE] When handling compressed extent without checksum, device replace will goe into copy_nocow_pages() function. In that function, btrfs will get all inodes referring to this data extents and then use find_or_create_page() to get pages direct from that inode. The problem here is, pages directly from inode are always uncompressed. And for compressed data extent, they mismatch with on-disk data. Thus this leads to corrupted compressed data extent written to replace device. [FIX] In this attempt, we could just remove the "optimization" branch, and let unified scrub_pages() to handle it. Although scrub_pages() won't bother reusing page cache, it will be a little slower, but it does the correct csum checking and won't cause such data corruption caused by "optimization". Note about the fix: this is the minimal fix that can be backported to older stable trees without conflicts. The whole callchain from copy_nocow_pages() can be deleted, and will be in followup patches. Fixes: ff023aac3119 ("Btrfs: add code to scrub to copy read data to another disk") CC: stable@vger.kernel.org # 4.4+ Reported-by: James Harvey Reviewed-by: James Harvey Signed-off-by: Qu Wenruo [ remove code removal, add note why ] Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/scrub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index fffb9ab8526e..16c0585cd81c 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -2519,7 +2519,7 @@ static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len, have_csum = scrub_find_csum(sctx, logical, csum); if (have_csum == 0) ++sctx->stat.no_csum; - if (sctx->is_dev_replace && !have_csum) { + if (0 && sctx->is_dev_replace && !have_csum) { ret = copy_nocow_pages(sctx, logical, l, mirror_num, physical_for_dev_replace); -- GitLab From 5514389fb21c9d52c636411ce1cd5c5b83905434 Mon Sep 17 00:00:00 2001 From: Bo Chen Date: Thu, 31 May 2018 15:35:18 -0700 Subject: [PATCH 178/604] ALSA: hda - Handle kzalloc() failure in snd_hda_attach_pcm_stream() commit a3aa60d511746bd6c0d0366d4eb90a7998bcde8b upstream. When 'kzalloc()' fails in 'snd_hda_attach_pcm_stream()', a new pcm instance is created without setting its operators via 'snd_pcm_set_ops()'. Following operations on the new pcm instance can trigger kernel null pointer dereferences and cause kernel oops. This bug was found with my work on building a gray-box fault-injection tool for linux-kernel-module binaries. A kernel null pointer dereference was confirmed from line 'substream->ops->open()' in function 'snd_pcm_open_substream()' in file 'sound/core/pcm_native.c'. This patch fixes the bug by calling 'snd_device_free()' in the error handling path of 'kzalloc()', which removes the new pcm instance from the snd card before returns with an error code. Signed-off-by: Bo Chen Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_controller.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 0af1132a869e..56af7308a2fd 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -748,8 +748,10 @@ int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec, return err; strlcpy(pcm->name, cpcm->name, sizeof(pcm->name)); apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); - if (apcm == NULL) + if (apcm == NULL) { + snd_device_free(chip->card, pcm); return -ENOMEM; + } apcm->chip = chip; apcm->pcm = pcm; apcm->codec = codec; -- GitLab From 594790ef9fb264a4294ceb04602762225a8eda63 Mon Sep 17 00:00:00 2001 From: Dennis Wassenberg Date: Tue, 12 Jun 2018 07:10:59 +0200 Subject: [PATCH 179/604] ALSA: hda: add dock and led support for HP EliteBook 830 G5 commit 2861751f67b91e1d24e68010ced96614fb3140f4 upstream. This patch adds missing initialisation for HP 2013 UltraSlim Dock Line-In/Out PINs and activates keyboard mute/micmute leds for HP EliteBook 830 G5 Signed-off-by: Dennis Wassenberg 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 b3851b991120..38246c670990 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -851,6 +851,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK), + SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE), SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC), SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), -- GitLab From 2c6707ce9a0daba6609d87a714f866d4f1db8937 Mon Sep 17 00:00:00 2001 From: Dennis Wassenberg Date: Tue, 12 Jun 2018 07:11:11 +0200 Subject: [PATCH 180/604] ALSA: hda: add dock and led support for HP ProBook 640 G4 commit 7eef32c1ef895a3a96463f9cbd04203007cd5555 upstream. This patch adds missing initialisation for HP 2013 UltraSlim Dock Line-In/Out PINs and activates keyboard mute/micmute leds for HP ProBook 640 G4 Signed-off-by: Dennis Wassenberg 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 38246c670990..6b5804e063a3 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -852,6 +852,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK), + SND_PCI_QUIRK(0x103c, 0x83d3, "HP ProBook 640 G4", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE), SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC), SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), -- GitLab From a6c9a62e0f9f0153ea5f0a2a8d4879b3bafe096a Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 31 May 2018 15:19:25 -0500 Subject: [PATCH 181/604] smb3: on reconnect set PreviousSessionId field commit b2adf22fdfba85a6701c481faccdbbb3a418ccfc upstream. The server detects reconnect by the (non-zero) value in PreviousSessionId of SMB2/SMB3 SessionSetup request, but this behavior regressed due to commit 166cea4dc3a4f66f020cfb9286225ecd228ab61d ("SMB2: Separate RawNTLMSSP authentication from SMB2_sess_setup") CC: Stable CC: Sachin Prabhu Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg Signed-off-by: Greg Kroah-Hartman --- fs/cifs/smb2pdu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 44b7ccbe4b08..e0214334769b 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1004,6 +1004,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, sess_data->ses = ses; sess_data->buf0_type = CIFS_NO_BUFFER; sess_data->nls_cp = (struct nls_table *) nls_cp; + sess_data->previous_session = ses->Suid; while (sess_data->func) sess_data->func(sess_data); -- GitLab From 5930589d3f85484611a9084169c8e86a8c183284 Mon Sep 17 00:00:00 2001 From: Tao Wang Date: Sat, 26 May 2018 15:16:48 +0800 Subject: [PATCH 182/604] cpufreq: Fix new policy initialization during limits updates via sysfs commit c7d1f119c48f64bebf0fa1e326af577c6152fe30 upstream. If the policy limits are updated via cpufreq_update_policy() and subsequently via sysfs, the limits stored in user_policy may be set incorrectly. For example, if both min and max are set via sysfs to the maximum available frequency, user_policy.min and user_policy.max will also be the maximum. If a policy notifier triggered by cpufreq_update_policy() lowers both the min and the max at this point, that change is not reflected by the user_policy limits, so if the max is updated again via sysfs to the same lower value, then user_policy.max will be lower than user_policy.min which shouldn't happen. In particular, if one of the policy CPUs is then taken offline and back online, cpufreq_set_policy() will fail for it due to a failing limits check. To prevent that from happening, initialize the min and max fields of the new_policy object to the ones stored in user_policy that were previously set via sysfs. Signed-off-by: Kevin Wangtao Acked-by: Viresh Kumar [ rjw: Subject & changelog ] Cc: All applicable Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/cpufreq/cpufreq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 7523929becdc..af5eff6835a8 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -657,6 +657,8 @@ static ssize_t store_##file_name \ struct cpufreq_policy new_policy; \ \ memcpy(&new_policy, policy, sizeof(*policy)); \ + new_policy.min = policy->user_policy.min; \ + new_policy.max = policy->user_policy.max; \ \ ret = sscanf(buf, "%u", &new_policy.object); \ if (ret != 1) \ -- GitLab From 21e6919834360389b6f3db6a04603b6aba0c6219 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 6 Sep 2017 09:56:29 +0100 Subject: [PATCH 183/604] libata: zpodd: make arrays cdb static, reduces object code size commit 795ef788145ed2fa023efdf11e8d5d7bedc21462 upstream. Don't populate the arrays cdb on the stack, instead make them static. Makes the object code smaller by 230 bytes: Before: text data bss dec hex filename 3797 240 0 4037 fc5 drivers/ata/libata-zpodd.o After: text data bss dec hex filename 3407 400 0 3807 edf drivers/ata/libata-zpodd.o Signed-off-by: Colin Ian King Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-zpodd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c index f3a65a3140d3..db64f81a4840 100644 --- a/drivers/ata/libata-zpodd.c +++ b/drivers/ata/libata-zpodd.c @@ -34,7 +34,7 @@ struct zpodd { static int eject_tray(struct ata_device *dev) { struct ata_taskfile tf; - const char cdb[] = { GPCMD_START_STOP_UNIT, + static const char cdb[] = { GPCMD_START_STOP_UNIT, 0, 0, 0, 0x02, /* LoEj */ 0, 0, 0, 0, 0, 0, 0, @@ -55,7 +55,7 @@ static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev) unsigned int ret; struct rm_feature_desc *desc = (void *)(buf + 8); struct ata_taskfile tf; - char cdb[] = { GPCMD_GET_CONFIGURATION, + static const char cdb[] = { GPCMD_GET_CONFIGURATION, 2, /* only 1 feature descriptor requested */ 0, 3, /* 3, removable medium feature */ 0, 0, 0,/* reserved */ -- GitLab From 0e9806ec7376e1a285d7b9ee634a782f10155540 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 29 May 2018 12:13:24 +0300 Subject: [PATCH 184/604] libata: zpodd: small read overflow in eject_tray() commit 18c9a99bce2a57dfd7e881658703b5d7469cc7b9 upstream. We read from the cdb[] buffer in ata_exec_internal_sg(). It has to be ATAPI_CDB_LEN (16) bytes long, but this buffer is only 12 bytes. Fixes: 213342053db5 ("libata: handle power transition of ODD") Signed-off-by: Dan Carpenter Signed-off-by: Tejun Heo Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-zpodd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c index db64f81a4840..0ad96c647541 100644 --- a/drivers/ata/libata-zpodd.c +++ b/drivers/ata/libata-zpodd.c @@ -34,7 +34,7 @@ struct zpodd { static int eject_tray(struct ata_device *dev) { struct ata_taskfile tf; - static const char cdb[] = { GPCMD_START_STOP_UNIT, + static const char cdb[ATAPI_CDB_LEN] = { GPCMD_START_STOP_UNIT, 0, 0, 0, 0x02, /* LoEj */ 0, 0, 0, 0, 0, 0, 0, -- GitLab From 139cd53baf08d80db81eb32a72dc24501cb8f296 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 31 May 2018 13:21:07 +0200 Subject: [PATCH 185/604] libata: Drop SanDisk SD7UB3Q*G1001 NOLPM quirk commit 2cfce3a86b64b53f0a70e92a6a659c720c319b45 upstream. Commit 184add2ca23c ("libata: Apply NOLPM quirk for SanDisk SD7UB3Q*G1001 SSDs") disabled LPM for SanDisk SD7UB3Q*G1001 SSDs. This has lead to several reports of users of that SSD where LPM was working fine and who know have a significantly increased idle power consumption on their laptops. Likely there is another problem on the T450s from the original reporter which gets exposed by the uncore reaching deeper sleep states (higher PC-states) due to LPM being enabled. The problem as reported, a hardfreeze about once a day, already did not sound like it would be caused by LPM and the reports of the SSD working fine confirm this. The original reporter is ok with dropping the quirk. A X250 user has reported the same hard freeze problem and for him the problem went away after unrelated updates, I suspect some GPU driver stack changes fixed things. TL;DR: The original reporters problem were triggered by LPM but not an LPM issue, so drop the quirk for the SSD in question. BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1583207 Cc: stable@vger.kernel.org Cc: Richard W.M. Jones Cc: Lorenzo Dalrio Reported-by: Lorenzo Dalrio Signed-off-by: Hans de Goede Signed-off-by: Tejun Heo Acked-by: "Richard W.M. Jones" Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-core.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 0e2c0ac5792d..82c59a143a14 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4426,9 +4426,6 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { ATA_HORKAGE_ZERO_AFTER_TRIM | ATA_HORKAGE_NOLPM, }, - /* Sandisk devices which are known to not handle LPM well */ - { "SanDisk SD7UB3Q*G1001", NULL, ATA_HORKAGE_NOLPM, }, - /* devices that don't properly handle queued TRIM commands */ { "Micron_M500IT_*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, -- GitLab From aec3dd5ef1f0fb570027fe3a42bbc1d3d1f1828f Mon Sep 17 00:00:00 2001 From: Stefan Potyra Date: Wed, 2 May 2018 10:55:31 +0200 Subject: [PATCH 186/604] w1: mxc_w1: Enable clock before calling clk_get_rate() on it commit 955bc61328dc0a297fb3baccd84e9d3aee501ed8 upstream. According to the API, you may only call clk_get_rate() after actually enabling it. Found by Linux Driver Verification project (linuxtesting.org). Fixes: a5fd9139f74c ("w1: add 1-wire master driver for i.MX27 / i.MX31") Signed-off-by: Stefan Potyra Acked-by: Evgeniy Polyakov Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/w1/masters/mxc_w1.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c index a4621757a47f..dacb5919970c 100644 --- a/drivers/w1/masters/mxc_w1.c +++ b/drivers/w1/masters/mxc_w1.c @@ -113,6 +113,10 @@ static int mxc_w1_probe(struct platform_device *pdev) if (IS_ERR(mdev->clk)) return PTR_ERR(mdev->clk); + err = clk_prepare_enable(mdev->clk); + if (err) + return err; + clkrate = clk_get_rate(mdev->clk); if (clkrate < 10000000) dev_warn(&pdev->dev, @@ -126,12 +130,10 @@ static int mxc_w1_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mdev->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(mdev->regs)) - return PTR_ERR(mdev->regs); - - err = clk_prepare_enable(mdev->clk); - if (err) - return err; + if (IS_ERR(mdev->regs)) { + err = PTR_ERR(mdev->regs); + goto out_disable_clk; + } /* Software reset 1-Wire module */ writeb(MXC_W1_RESET_RST, mdev->regs + MXC_W1_RESET); @@ -147,8 +149,12 @@ static int mxc_w1_probe(struct platform_device *pdev) err = w1_add_master_device(&mdev->bus_master); if (err) - clk_disable_unprepare(mdev->clk); + goto out_disable_clk; + return 0; + +out_disable_clk: + clk_disable_unprepare(mdev->clk); return err; } -- GitLab From 88f36d1b4f0b8163a6b9155e75d9be7d0074d834 Mon Sep 17 00:00:00 2001 From: Martin Brandenburg Date: Thu, 31 May 2018 16:36:58 +0000 Subject: [PATCH 187/604] orangefs: set i_size on new symlink commit f6a4b4c9d07dda90c7c29dae96d6119ac6425dca upstream. As long as a symlink inode remains in-core, the destination (and therefore size) will not be re-fetched from the server, as it cannot change. The original implementation of the attribute cache assumed that setting the expiry time in the past was sufficient to cause a re-fetch of all attributes on the next getattr. That does not work in this case. The bug manifested itself as follows. When the command sequence touch foo; ln -s foo bar; ls -l bar is run, the output was lrwxrwxrwx. 1 fedora fedora 4906 Apr 24 19:10 bar -> foo However, after a re-mount, ls -l bar produces lrwxrwxrwx. 1 fedora fedora 3 Apr 24 19:10 bar -> foo After this commit, even before a re-mount, the output is lrwxrwxrwx. 1 fedora fedora 3 Apr 24 19:10 bar -> foo Reported-by: Becky Ligon Signed-off-by: Martin Brandenburg Fixes: 71680c18c8f2 ("orangefs: Cache getattr results.") Cc: stable@vger.kernel.org Cc: hubcap@omnibond.com Signed-off-by: Mike Marshall Signed-off-by: Greg Kroah-Hartman --- fs/orangefs/namei.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c index 561497a7a247..5fe458628e00 100644 --- a/fs/orangefs/namei.c +++ b/fs/orangefs/namei.c @@ -312,6 +312,13 @@ static int orangefs_symlink(struct inode *dir, ret = PTR_ERR(inode); goto out; } + /* + * This is necessary because orangefs_inode_getattr will not + * re-read symlink size as it is impossible for it to change. + * Invalidating the cache does not help. orangefs_new_inode + * does not set the correct size (it does not know symname). + */ + inode->i_size = strlen(symname); gossip_debug(GOSSIP_NAME_DEBUG, "Assigned symlink inode new number of %pU\n", -- GitLab From a875bc1c9ec116b7b2b2f15f8edc2a2ac3c51f99 Mon Sep 17 00:00:00 2001 From: Even Xu Date: Fri, 12 Feb 2016 04:11:34 +0800 Subject: [PATCH 188/604] HID: intel_ish-hid: ipc: register more pm callbacks to support hibernation commit ebeaa367548e9e92dd9374b9464ff6e7d157117b upstream. Current ISH driver only registers suspend/resume PM callbacks which don't support hibernation (suspend to disk). Basically after hiberation, the ISH can't resume properly and user may not see sensor events (for example: screen rotation may not work). User will not see a crash or panic or anything except the following message in log: hid-sensor-hub 001F:8086:22D8.0001: timeout waiting for response from ISHTP device So this patch adds support for S4/hiberbation to ISH by using the SIMPLE_DEV_PM_OPS() MACRO instead of struct dev_pm_ops directly. The suspend and resume functions will now be used for both suspend to RAM and hibernation. If power management is disabled, SIMPLE_DEV_PM_OPS will do nothing, the suspend and resume related functions won't be used, so mark them as __maybe_unused to clarify that this is the intended behavior, and remove #ifdefs for power management. Cc: stable@vger.kernel.org Signed-off-by: Even Xu Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/intel-ish-hid/ipc/pci-ish.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index 20d647d2dd2c..00aafe032e58 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -202,8 +202,7 @@ static void ish_remove(struct pci_dev *pdev) kfree(ishtp_dev); } -#ifdef CONFIG_PM -static struct device *ish_resume_device; +static struct device __maybe_unused *ish_resume_device; /** * ish_resume_handler() - Work function to complete resume @@ -214,7 +213,7 @@ static struct device *ish_resume_device; * in that case a simple resume message is enough, others we need * a reset sequence. */ -static void ish_resume_handler(struct work_struct *work) +static void __maybe_unused ish_resume_handler(struct work_struct *work) { struct pci_dev *pdev = to_pci_dev(ish_resume_device); struct ishtp_device *dev = pci_get_drvdata(pdev); @@ -245,7 +244,7 @@ static void ish_resume_handler(struct work_struct *work) * * Return: 0 to the pm core */ -static int ish_suspend(struct device *device) +static int __maybe_unused ish_suspend(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct ishtp_device *dev = pci_get_drvdata(pdev); @@ -271,7 +270,7 @@ static int ish_suspend(struct device *device) return 0; } -static DECLARE_WORK(resume_work, ish_resume_handler); +static __maybe_unused DECLARE_WORK(resume_work, ish_resume_handler); /** * ish_resume() - ISH resume callback * @device: device pointer @@ -280,7 +279,7 @@ static DECLARE_WORK(resume_work, ish_resume_handler); * * Return: 0 to the pm core */ -static int ish_resume(struct device *device) +static int __maybe_unused ish_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct ishtp_device *dev = pci_get_drvdata(pdev); @@ -294,21 +293,14 @@ static int ish_resume(struct device *device) return 0; } -static const struct dev_pm_ops ish_pm_ops = { - .suspend = ish_suspend, - .resume = ish_resume, -}; -#define ISHTP_ISH_PM_OPS (&ish_pm_ops) -#else -#define ISHTP_ISH_PM_OPS NULL -#endif /* CONFIG_PM */ +static SIMPLE_DEV_PM_OPS(ish_pm_ops, ish_suspend, ish_resume); static struct pci_driver ish_driver = { .name = KBUILD_MODNAME, .id_table = ish_pci_tbl, .probe = ish_probe, .remove = ish_remove, - .driver.pm = ISHTP_ISH_PM_OPS, + .driver.pm = &ish_pm_ops, }; module_pci_driver(ish_driver); -- GitLab From 9681c3bdb098f6c87a0422b6b63912c1b90ad197 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Sat, 12 May 2018 00:33:10 +0300 Subject: [PATCH 189/604] vhost: fix info leak due to uninitialized memory commit 670ae9caaca467ea1bfd325cb2a5c98ba87f94ad upstream. struct vhost_msg within struct vhost_msg_node is copied to userspace. Unfortunately it turns out on 64 bit systems vhost_msg has padding after type which gcc doesn't initialize, leaking 4 uninitialized bytes to userspace. This padding also unfortunately means 32 bit users of this interface are broken on a 64 bit kernel which will need to be fixed separately. Fixes: CVE-2018-1118 Cc: stable@vger.kernel.org Reported-by: Kevin Easton Signed-off-by: Michael S. Tsirkin Reported-by: syzbot+87cfa083e727a224754b@syzkaller.appspotmail.com Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/vhost/vhost.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index c81bc4efe1a6..8b6489ae74eb 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -2295,6 +2295,9 @@ struct vhost_msg_node *vhost_new_msg(struct vhost_virtqueue *vq, int type) struct vhost_msg_node *node = kmalloc(sizeof *node, GFP_KERNEL); if (!node) return NULL; + + /* Make sure all padding within the structure is initialized. */ + memset(&node->msg, 0, sizeof node->msg); node->vq = vq; node->msg.type = type; return node; -- GitLab From f3e7234932eb6a459963b13899241357306fae32 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Thu, 7 Jun 2018 17:11:01 -0700 Subject: [PATCH 190/604] fs/binfmt_misc.c: do not allow offset overflow commit 5cc41e099504b77014358b58567c5ea6293dd220 upstream. WHen registering a new binfmt_misc handler, it is possible to overflow the offset to get a negative value, which might crash the system, or possibly leak kernel data. Here is a crash log when 2500000000 was used as an offset: BUG: unable to handle kernel paging request at ffff989cfd6edca0 IP: load_misc_binary+0x22b/0x470 [binfmt_misc] PGD 1ef3e067 P4D 1ef3e067 PUD 0 Oops: 0000 [#1] SMP NOPTI Modules linked in: binfmt_misc kvm_intel ppdev kvm irqbypass joydev input_leds serio_raw mac_hid parport_pc qemu_fw_cfg parpy CPU: 0 PID: 2499 Comm: bash Not tainted 4.15.0-22-generic #24-Ubuntu Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.11.1-1 04/01/2014 RIP: 0010:load_misc_binary+0x22b/0x470 [binfmt_misc] Call Trace: search_binary_handler+0x97/0x1d0 do_execveat_common.isra.34+0x667/0x810 SyS_execve+0x31/0x40 do_syscall_64+0x73/0x130 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Use kstrtoint instead of simple_strtoul. It will work as the code already set the delimiter byte to '\0' and we only do it when the field is not empty. Tested with offsets -1, 2500000000, UINT_MAX and INT_MAX. Also tested with examples documented at Documentation/admin-guide/binfmt-misc.rst and other registrations from packages on Ubuntu. Link: http://lkml.kernel.org/r/20180529135648.14254-1-cascardo@canonical.com Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Thadeu Lima de Souza Cascardo Reviewed-by: Andrew Morton Cc: Alexander Viro Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/binfmt_misc.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 9b4688ab1d8e..f842261ce973 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -384,8 +384,13 @@ static Node *create_entry(const char __user *buffer, size_t count) s = strchr(p, del); if (!s) goto einval; - *s++ = '\0'; - e->offset = simple_strtoul(p, &p, 10); + *s = '\0'; + if (p != s) { + int r = kstrtoint(p, 10, &e->offset); + if (r != 0 || e->offset < 0) + goto einval; + } + p = s; if (*p++) goto einval; pr_debug("register: offset: %#x\n", e->offset); @@ -425,7 +430,8 @@ static Node *create_entry(const char __user *buffer, size_t count) if (e->mask && string_unescape_inplace(e->mask, UNESCAPE_HEX) != e->size) goto einval; - if (e->size + e->offset > BINPRM_BUF_SIZE) + if (e->size > BINPRM_BUF_SIZE || + BINPRM_BUF_SIZE - e->size < e->offset) goto einval; pr_debug("register: magic/mask length: %i\n", e->size); if (USE_DEBUG) { -- GitLab From c806e0856941597f058b4a527d77dbc0000c513c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 26 Jun 2018 08:08:09 +0800 Subject: [PATCH 191/604] Linux 4.9.110 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1570cc85313d..2fcfe1147eaa 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 109 +SUBLEVEL = 110 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From d4eba5de6cbc6eb35d0130cef887955b0241c342 Mon Sep 17 00:00:00 2001 From: Junzhe Zou Date: Thu, 17 May 2018 14:42:44 -0700 Subject: [PATCH 192/604] msm: camera: icp: allow reconfig io during streaming Get io config settings in BLOB, and submit to FW during streaming to support MFSR. Change-Id: Ic884e0e48352293737d1e45f42e27e74970b9e24 Signed-off-by: Junzhe Zou --- .../media/platform/msm/camera/cam_icp/hfi.c | 3 +- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 214 +++++++++++++----- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h | 19 ++ include/uapi/media/cam_icp.h | 3 +- 4 files changed, 183 insertions(+), 56 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c index a0752f596c96..a9a133537071 100644 --- a/drivers/media/platform/msm/camera/cam_icp/hfi.c +++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c @@ -92,7 +92,8 @@ int hfi_write_cmd(void *cmd_ptr) (q->qhdr_q_size - (q->qhdr_write_idx - read_idx)) : (read_idx - q->qhdr_write_idx); if (empty_space <= size_in_words) { - CAM_ERR(CAM_HFI, "failed"); + CAM_ERR(CAM_HFI, "failed: empty space %u, size_in_words %u", + empty_space, size_in_words); rc = -EIO; goto err; } 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 16e97ea1f813..7ac7722697b4 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 @@ -1833,7 +1833,7 @@ static int32_t cam_icp_mgr_process_msg(void *priv, void *data) rc = hfi_read_message(icp_hw_mgr.msg_buf, Q_MSG, &read_len); if (rc) { - CAM_DBG(CAM_ICP, "Unable to read msg q"); + CAM_DBG(CAM_ICP, "Unable to read msg q rc %d", rc); } else { read_len = read_len << BYTE_WORD_SHIFT; msg_ptr = (uint32_t *)icp_hw_mgr.msg_buf; @@ -2858,8 +2858,10 @@ static int cam_icp_mgr_enqueue_config(struct cam_icp_hw_mgr *hw_mgr, struct hfi_cmd_work_data *task_data; struct hfi_cmd_ipebps_async *hfi_cmd; struct cam_hw_update_entry *hw_update_entries; + struct icp_frame_info *frame_info = NULL; - request_id = *(uint64_t *)config_args->priv; + frame_info = (struct icp_frame_info *)config_args->priv; + request_id = frame_info->request_id; hw_update_entries = config_args->hw_update_entries; CAM_DBG(CAM_ICP, "req_id = %lld %pK", request_id, config_args->priv); @@ -2881,6 +2883,81 @@ static int cam_icp_mgr_enqueue_config(struct cam_icp_hw_mgr *hw_mgr, return rc; } +static int cam_icp_mgr_send_config_io(struct cam_icp_hw_ctx_data *ctx_data, + uint32_t io_buf_addr) +{ + int rc = 0; + struct hfi_cmd_work_data *task_data; + struct hfi_cmd_ipebps_async ioconfig_cmd; + unsigned long rem_jiffies; + int timeout = 5000; + struct crm_workq_task *task; + uint32_t size_in_words; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) + return -ENOMEM; + + ioconfig_cmd.size = sizeof(struct hfi_cmd_ipebps_async); + ioconfig_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT; + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO; + else + ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO; + + reinit_completion(&ctx_data->wait_complete); + + ioconfig_cmd.num_fw_handles = 1; + ioconfig_cmd.fw_handles[0] = ctx_data->fw_handle; + ioconfig_cmd.payload.indirect = io_buf_addr; + ioconfig_cmd.user_data1 = (uint64_t)ctx_data; + ioconfig_cmd.user_data2 = (uint64_t)0x0; + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)&ioconfig_cmd; + task_data->request_id = 0; + task_data->type = ICP_WORKQ_TASK_MSG_TYPE; + task->process_cb = cam_icp_mgr_process_cmd; + size_in_words = (*(uint32_t *)task_data->data) >> 2; + CAM_INFO(CAM_ICP, "size_in_words %u", size_in_words); + rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + if (rc) + return rc; + + rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + } + + return rc; +} + +static int cam_icp_mgr_send_recfg_io(struct cam_icp_hw_ctx_data *ctx_data, + struct hfi_cmd_ipebps_async *ioconfig_cmd, uint64_t req_id) +{ + int rc = 0; + struct hfi_cmd_work_data *task_data; + struct crm_workq_task *task; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) + return -ENOMEM; + + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)ioconfig_cmd; + task_data->request_id = req_id; + task_data->type = ICP_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_icp_mgr_process_cmd; + rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + if (rc) + return rc; + + return rc; +} + static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) { int rc = 0; @@ -2889,6 +2966,7 @@ static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; struct cam_hw_config_args *config_args = config_hw_args; struct cam_icp_hw_ctx_data *ctx_data = NULL; + struct icp_frame_info *frame_info = NULL; if (!hw_mgr || !config_args) { CAM_ERR(CAM_ICP, "Invalid arguments %pK %pK", @@ -2912,11 +2990,23 @@ static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) return -EINVAL; } - req_id = *(uint64_t *)config_args->priv; + 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); + CAM_DBG(CAM_ICP, "req_id %llu, io config %llu", req_id, + frame_info->io_config); + + if (frame_info->io_config != 0) { + CAM_INFO(CAM_ICP, "Send recfg io"); + rc = cam_icp_mgr_send_recfg_io(ctx_data, + &frame_info->hfi_cfg_io_cmd, req_id); + if (rc) + CAM_ERR(CAM_ICP, "Fail to send reconfig io cmd"); + } + rc = cam_icp_mgr_enqueue_config(hw_mgr, config_args); if (rc) goto config_err; @@ -3147,7 +3237,9 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, struct icp_cmd_generic_blob *blob; struct cam_icp_hw_ctx_data *ctx_data; uint32_t index; + size_t io_buf_size; int rc = 0; + uint64_t pResource; if (!blob_data || (blob_size == 0)) { CAM_ERR(CAM_ICP, "Invalid blob info %pK %d", blob_data, @@ -3176,6 +3268,28 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, clk_info->compressed_bw); break; + case CAM_ICP_CMD_GENERIC_BLOB_CFG_IO: + CAM_DBG(CAM_ICP, "CAM_ICP_CMD_GENERIC_BLOB_CFG_IO"); + pResource = *((uint32_t *)blob_data); + if (copy_from_user(&ctx_data->icp_dev_io_info, + (void __user *)pResource, + sizeof(struct cam_icp_acquire_dev_info))) { + CAM_ERR(CAM_ICP, "Failed in copy from user"); + return -EFAULT; + } + CAM_DBG(CAM_ICP, "buf handle %d", + ctx_data->icp_dev_io_info.io_config_cmd_handle); + rc = cam_mem_get_io_buf( + ctx_data->icp_dev_io_info.io_config_cmd_handle, + icp_hw_mgr.iommu_hdl, + blob->io_buf_addr, &io_buf_size); + if (rc) + CAM_ERR(CAM_ICP, "Failed in blob update"); + else + CAM_DBG(CAM_ICP, "io buf addr %llu", + *blob->io_buf_addr); + break; + default: CAM_WARN(CAM_ICP, "Invalid blob type %d", blob_type); break; @@ -3186,7 +3300,8 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, static int cam_icp_process_generic_cmd_buffer( struct cam_packet *packet, struct cam_icp_hw_ctx_data *ctx_data, - int32_t index) + int32_t index, + uint64_t *io_buf_addr) { int i, rc = 0; struct cam_cmd_buf_desc *cmd_desc = NULL; @@ -3194,6 +3309,7 @@ static int cam_icp_process_generic_cmd_buffer( cmd_generic_blob.ctx = ctx_data; cmd_generic_blob.frame_info_idx = index; + cmd_generic_blob.io_buf_addr = io_buf_addr; cmd_desc = (struct cam_cmd_buf_desc *) ((uint32_t *) &packet->payload + packet->cmd_buf_offset/4); @@ -3213,6 +3329,28 @@ static int cam_icp_process_generic_cmd_buffer( return rc; } +static int cam_icp_mgr_process_cfg_io_cmd( + struct cam_icp_hw_ctx_data *ctx_data, + struct hfi_cmd_ipebps_async *ioconfig_cmd, + uint64_t request_id, + uint64_t io_config) +{ + ioconfig_cmd->size = sizeof(struct hfi_cmd_ipebps_async); + ioconfig_cmd->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT; + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + ioconfig_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO; + else + ioconfig_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO; + + ioconfig_cmd->num_fw_handles = 1; + ioconfig_cmd->fw_handles[0] = ctx_data->fw_handle; + ioconfig_cmd->payload.indirect = io_config; + ioconfig_cmd->user_data1 = (uint64_t)ctx_data; + ioconfig_cmd->user_data2 = request_id; + + return 0; +} + static int cam_icp_mgr_update_hfi_frame_process( struct cam_icp_hw_ctx_data *ctx_data, struct cam_packet *packet, @@ -3220,6 +3358,7 @@ static int cam_icp_mgr_update_hfi_frame_process( int32_t *idx) { int32_t index, rc; + struct hfi_cmd_ipebps_async *hfi_cmd = NULL; index = find_first_zero_bit(ctx_data->hfi_frame_process.bitmap, ctx_data->hfi_frame_process.bits); @@ -3231,15 +3370,27 @@ static int cam_icp_mgr_update_hfi_frame_process( ctx_data->hfi_frame_process.request_id[index] = packet->header.request_id; - rc = cam_icp_process_generic_cmd_buffer(packet, ctx_data, index); + ctx_data->hfi_frame_process.frame_info[index].request_id = + packet->header.request_id; + ctx_data->hfi_frame_process.frame_info[index].io_config = 0; + rc = cam_icp_process_generic_cmd_buffer(packet, ctx_data, index, + &ctx_data->hfi_frame_process.frame_info[index].io_config); if (rc) { clear_bit(index, ctx_data->hfi_frame_process.bitmap); ctx_data->hfi_frame_process.request_id[index] = -1; return rc; } + + if (ctx_data->hfi_frame_process.frame_info[index].io_config) { + hfi_cmd = (struct hfi_cmd_ipebps_async *)&ctx_data-> + hfi_frame_process.frame_info[index].hfi_cfg_io_cmd; + rc = cam_icp_mgr_process_cfg_io_cmd(ctx_data, hfi_cmd, + packet->header.request_id, ctx_data-> + hfi_frame_process.frame_info[index].io_config); + } *idx = index; - return 0; + return rc; } static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv, @@ -3320,7 +3471,7 @@ static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv, prepare_args->num_hw_update_entries = 1; prepare_args->hw_update_entries[0].addr = (uint64_t)hfi_cmd; - prepare_args->priv = &ctx_data->hfi_frame_process.request_id[idx]; + prepare_args->priv = &ctx_data->hfi_frame_process.frame_info[idx]; CAM_DBG(CAM_ICP, "X: req id = %lld ctx_id = %u", packet->header.request_id, ctx_data->ctx_id); @@ -3584,53 +3735,6 @@ static int cam_icp_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) return rc; } -static int cam_icp_mgr_send_config_io(struct cam_icp_hw_ctx_data *ctx_data, - uint32_t io_buf_addr) -{ - int rc = 0; - struct hfi_cmd_work_data *task_data; - struct hfi_cmd_ipebps_async ioconfig_cmd; - unsigned long rem_jiffies; - int timeout = 5000; - struct crm_workq_task *task; - - task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); - if (!task) - return -ENOMEM; - - ioconfig_cmd.size = sizeof(struct hfi_cmd_ipebps_async); - ioconfig_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT; - if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) - ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO; - else - ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO; - - reinit_completion(&ctx_data->wait_complete); - ioconfig_cmd.num_fw_handles = 1; - ioconfig_cmd.fw_handles[0] = ctx_data->fw_handle; - ioconfig_cmd.payload.indirect = io_buf_addr; - ioconfig_cmd.user_data1 = (uint64_t)ctx_data; - ioconfig_cmd.user_data2 = (uint64_t)0x0; - task_data = (struct hfi_cmd_work_data *)task->payload; - task_data->data = (void *)&ioconfig_cmd; - task_data->request_id = 0; - task_data->type = ICP_WORKQ_TASK_CMD_TYPE; - task->process_cb = cam_icp_mgr_process_cmd; - rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, - CRM_TASK_PRIORITY_0); - if (rc) - return rc; - - rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, - msecs_to_jiffies((timeout))); - if (!rem_jiffies) { - rc = -ETIMEDOUT; - CAM_ERR(CAM_ICP, "FW response timed out %d", rc); - } - - return rc; -} - static int cam_icp_mgr_create_handle(uint32_t dev_type, struct cam_icp_hw_ctx_data *ctx_data) { @@ -3843,6 +3947,8 @@ static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) icp_dev_acquire_info = ctx_data->icp_dev_acquire_info; + CAM_DBG(CAM_ICP, "acquire io buf handle %d", + icp_dev_acquire_info->io_config_cmd_handle); rc = cam_mem_get_io_buf( icp_dev_acquire_info->io_config_cmd_handle, hw_mgr->iommu_hdl, diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index 8746ee264f31..3e3c0e08e187 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -125,6 +125,19 @@ struct clk_work_data { void *data; }; +/** + * struct icp_frame_info + * @request_id: request id + * @io_config: the address of io config + * @hfi_cfg_io_cmd: command struct to be sent to hfi + */ +struct icp_frame_info { + uint64_t request_id; + uint64_t io_config; + struct hfi_cmd_ipebps_async hfi_cfg_io_cmd; +}; + + /** * struct hfi_frame_process_info * @hfi_frame_cmd: Frame process command info @@ -136,6 +149,7 @@ struct clk_work_data { * @out_resource: Out sync info * @fw_process_flag: Frame process flag * @clk_info: Clock information for a request + * @frame_info: information needed to process request */ struct hfi_frame_process_info { struct hfi_cmd_ipebps_async hfi_frame_cmd[CAM_FRAME_CMD_MAX]; @@ -149,6 +163,7 @@ struct hfi_frame_process_info { uint32_t in_free_resource[CAM_FRAME_CMD_MAX]; uint32_t fw_process_flag[CAM_FRAME_CMD_MAX]; struct cam_icp_clk_bw_request clk_info[CAM_FRAME_CMD_MAX]; + struct icp_frame_info frame_info[CAM_FRAME_CMD_MAX]; }; /** @@ -189,6 +204,7 @@ struct cam_ctx_clk_info { * @clk_info: Current clock info of a context * @watch_dog: watchdog timer handle * @watch_dog_reset_counter: Counter for watch dog reset + * @icp_dev_io_info: io config resource */ struct cam_icp_hw_ctx_data { void *context_priv; @@ -208,16 +224,19 @@ struct cam_icp_hw_ctx_data { struct cam_ctx_clk_info clk_info; struct cam_req_mgr_timer *watch_dog; uint32_t watch_dog_reset_counter; + struct cam_icp_acquire_dev_info icp_dev_io_info; }; /** * struct icp_cmd_generic_blob * @ctx: Current context info * @frame_info_idx: Index used for frame process info + * @io_buf_addr: pointer to io buffer address */ struct icp_cmd_generic_blob { struct cam_icp_hw_ctx_data *ctx; uint32_t frame_info_idx; + uint64_t *io_buf_addr; }; /** diff --git a/include/uapi/media/cam_icp.h b/include/uapi/media/cam_icp.h index cd2d2d297003..680d05b630a6 100644 --- a/include/uapi/media/cam_icp.h +++ b/include/uapi/media/cam_icp.h @@ -59,8 +59,9 @@ /* Command meta types */ #define CAM_ICP_CMD_META_GENERIC_BLOB 0x1 -/* Generic blon types */ +/* Generic blob types */ #define CAM_ICP_CMD_GENERIC_BLOB_CLK 0x1 +#define CAM_ICP_CMD_GENERIC_BLOB_CFG_IO 0x2 /** * struct cam_icp_clk_bw_request -- GitLab From 42045b3df393c9f0852310925d9e2409f2c8e15f Mon Sep 17 00:00:00 2001 From: "vchinta@codeaurora.org" Date: Thu, 21 Jun 2018 12:08:03 -0700 Subject: [PATCH 193/604] msm: camera: sensor: Correct spelling error This change corrects spelling error in sensor probe success log. Change-Id: I9c19560ef2eba48abb0e949e854d028d22c3f959 Signed-off-by: vchinta@codeaurora.org Signed-off-by: Vishalsingh Hajeri --- .../msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c index 714a3604969a..6fe051aa048c 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -654,7 +654,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, } CAM_INFO(CAM_SENSOR, - "Probe Succees,slot:%d,slave_addr:0x%x,sensor_id:0x%x", + "Probe success,slot:%d,slave_addr:0x%x,sensor_id:0x%x", s_ctrl->soc_info.index, s_ctrl->sensordata->slave_info.sensor_slave_addr, s_ctrl->sensordata->slave_info.sensor_id); -- GitLab From 39560caaa360555f54179ad0ab297b96c40423e1 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 25 Jun 2018 14:27:20 -0700 Subject: [PATCH 194/604] msm: camera: Correct check for rdi res_id Correct check for RDI res_id max value, so it cannot access wrong index for rdi resource. Also remove unnecessary check in jpeg hw manager. Change-Id: I579cddfc5a57535be79e6c2fb138eb01a43fe341 Signed-off-by: Jigarkumar Zala --- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 4 ++-- .../msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 13 +++++++------ 2 files changed, 9 insertions(+), 8 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 29b9e11a9365..dd1b7b9dcbe6 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 @@ -1851,8 +1851,8 @@ static int cam_ife_csid_disable_rdi_path( soc_info = &csid_hw->hw_info->soc_info; id = res->res_id; - if (res->res_id >= CAM_IFE_PIX_PATH_RES_MAX || - !csid_reg->rdi_reg[res->res_id]) { + if ((res->res_id > CAM_IFE_PIX_PATH_RES_RDI_3) || + (!csid_reg->rdi_reg[res->res_id])) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d Invalid res id%d", csid_hw->hw_intf->hw_idx, res->res_id); return -EINVAL; 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 fdeee545bc6c..d240b53b7164 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 @@ -802,8 +802,8 @@ static int cam_jpeg_mgr_flush(void *hw_mgr_priv, list_for_each_entry_safe(cfg_req, req_temp, &hw_mgr->hw_config_req_list, list) { - if ((cfg_req) && ((struct cam_jpeg_hw_ctx_data *) - cfg_req->hw_cfg_args.ctxt_to_hw_map != ctx_data)) + if ((struct cam_jpeg_hw_ctx_data *) + cfg_req->hw_cfg_args.ctxt_to_hw_map != ctx_data) continue; list_del_init(&cfg_req->list); @@ -820,7 +820,8 @@ static int cam_jpeg_mgr_flush_req(void *hw_mgr_priv, struct cam_hw_flush_args *flush_args) { struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; - struct cam_jpeg_hw_cfg_req *cfg_req, *req_temp; + struct cam_jpeg_hw_cfg_req *cfg_req = NULL; + struct cam_jpeg_hw_cfg_req *req_temp = NULL; int64_t request_id; CAM_DBG(CAM_JPEG, "E: JPEG flush req"); @@ -836,8 +837,8 @@ static int cam_jpeg_mgr_flush_req(void *hw_mgr_priv, request_id = *(int64_t *)flush_args->flush_req_active[0]; list_for_each_entry_safe(cfg_req, req_temp, &hw_mgr->hw_config_req_list, list) { - if ((cfg_req) && (cfg_req->hw_cfg_args.ctxt_to_hw_map - != ctx_data)) + if ((struct cam_jpeg_hw_ctx_data *) + cfg_req->hw_cfg_args.ctxt_to_hw_map != ctx_data) continue; if (cfg_req->req_id != request_id) @@ -989,7 +990,7 @@ static int cam_jpeg_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) static int cam_jpeg_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) { - int rc; + int rc = 0; int32_t ctx_id = 0; struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; struct cam_jpeg_hw_ctx_data *ctx_data = NULL; -- GitLab From 6fe599d93c0dc496492e3682d30d8a1b2987e78f Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 4 Jun 2018 14:56:44 -0700 Subject: [PATCH 195/604] msm: camera: icp: Dump hfi queues in case of FW timeout This changes dumps the contents of the cmd & msg queues in case of a FW timeout. This will help isolate if the issue is on the host/FW side. Change-Id: I4ae6ef95bcbcfcce03b980df67e85fedaad30fec Signed-off-by: Karthik Anantha Ram --- .../msm/camera/cam_icp/fw_inc/hfi_intf.h | 6 +++ .../media/platform/msm/camera/cam_icp/hfi.c | 43 +++++++++++++++++++ .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 6 +++ 3 files changed, 55 insertions(+) diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h index 2c364e0181e6..4256064dc1bb 100644 --- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h +++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h @@ -153,4 +153,10 @@ int hfi_cmd_ubwc_config(uint32_t *ubwc_cfg); int cam_hfi_resume(struct hfi_mem_info *hfi_mem, void __iomem *icp_base, bool debug); +/** + * cam_hfi_queue_dump() - utility function to dump hfi queues + */ +void cam_hfi_queue_dump(void); + + #endif /* _HFI_INTF_H_ */ diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c index a9a133537071..de72e85358d0 100644 --- a/drivers/media/platform/msm/camera/cam_icp/hfi.c +++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c @@ -47,6 +47,49 @@ unsigned int g_icp_mmu_hdl; static DEFINE_MUTEX(hfi_cmd_q_mutex); static DEFINE_MUTEX(hfi_msg_q_mutex); +void cam_hfi_queue_dump(void) +{ + struct hfi_qtbl *qtbl; + struct hfi_qtbl_hdr *qtbl_hdr; + struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr; + struct hfi_mem_info *hfi_mem = NULL; + uint32_t *read_q, *read_ptr; + int i; + + hfi_mem = &g_hfi->map; + if (!hfi_mem) { + CAM_ERR(CAM_HFI, "Unable to dump queues hfi memory is NULL"); + return; + } + + qtbl = (struct hfi_qtbl *)hfi_mem->qtbl.kva; + qtbl_hdr = &qtbl->q_tbl_hdr; + CAM_INFO(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", + 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"); + 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]); + + msg_q_hdr = &qtbl->q_hdr[Q_MSG]; + CAM_INFO(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"); + 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]); +} + int hfi_write_cmd(void *cmd_ptr) { uint32_t size_in_words, empty_space, new_write_idx, read_idx, temp; 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 18162a196cdd..3c5690d00070 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 @@ -2323,6 +2323,7 @@ static int cam_icp_mgr_abort_handle( if (!rem_jiffies) { rc = -ETIMEDOUT; CAM_ERR(CAM_ICP, "FW timeout/err in abort handle command"); + cam_hfi_queue_dump(); } kfree(abort_cmd); @@ -2379,6 +2380,7 @@ static int cam_icp_mgr_destroy_handle( if (icp_hw_mgr.a5_debug_type == HFI_DEBUG_MODE_QUEUE) cam_icp_mgr_process_dbg_buf(); + cam_hfi_queue_dump(); } kfree(destroy_cmd); return rc; @@ -2680,6 +2682,7 @@ static int cam_icp_mgr_send_fw_init(struct cam_icp_hw_mgr *hw_mgr) if (!rem_jiffies) { rc = -ETIMEDOUT; CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_hfi_queue_dump(); } CAM_DBG(CAM_ICP, "Done Waiting for INIT DONE Message"); @@ -2929,6 +2932,7 @@ static int cam_icp_mgr_send_config_io(struct cam_icp_hw_ctx_data *ctx_data, if (!rem_jiffies) { rc = -ETIMEDOUT; CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_hfi_queue_dump(); } return rc; @@ -3769,6 +3773,7 @@ static int cam_icp_mgr_create_handle(uint32_t dev_type, if (!rem_jiffies) { rc = -ETIMEDOUT; CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_hfi_queue_dump(); } if (ctx_data->fw_handle == 0) { @@ -3814,6 +3819,7 @@ static int cam_icp_mgr_send_ping(struct cam_icp_hw_ctx_data *ctx_data) if (!rem_jiffies) { rc = -ETIMEDOUT; CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_hfi_queue_dump(); } return rc; -- GitLab From f637ee8d26c2808de53f5ccc07e9d19602639520 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Wed, 27 Jun 2018 13:50:38 +0300 Subject: [PATCH 196/604] cfg80211: fix rcu in cfg80211_unregister_wdev Callers of cfg80211_unregister_wdev can free the wdev object immediately after this function returns. This may cause instability because this wdev object is still in use by other threads. Add synchronize_rcu() after list_del_rcu to make sure wdev object can be safely freed. Change-Id: Id73921888bed032312b133e94fbfe06537e06b92 Signed-off-by: Dedy Lansky Signed-off-by: Johannes Berg Git-commit: bf2b61a6838f19cbc33f6732715012c483fa3795 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git --- net/wireless/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/wireless/core.c b/net/wireless/core.c index c88874f2f6b1..0a67d80d2470 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -949,6 +949,7 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev) nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE); list_del_rcu(&wdev->list); + synchronize_rcu(); rdev->devlist_generation++; switch (wdev->iftype) { -- GitLab From 13c7d6c7643abca4257be11fb2901e02d4092251 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 27 Jun 2018 15:40:02 -0700 Subject: [PATCH 197/604] msm: camera: reqmgr: Change state check in callbacks Currently certain callbacks are processed only if the link is in ready state. This change allows them to processed if the link is either in ready or error state. Change-Id: I7a8294c943a10dea968530cb38bfd153146ae86b Signed-off-by: Karthik Anantha Ram --- .../media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 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 060aaf2c3268..cc4c4c59a266 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 @@ -1860,7 +1860,7 @@ static int cam_req_mgr_cb_add_req(struct cam_req_mgr_add_request *add_req) mutex_lock(&link->lock); spin_lock_bh(&link->link_state_spin_lock); - if (link->state != CAM_CRM_LINK_STATE_READY) { + if (link->state < CAM_CRM_LINK_STATE_READY) { CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); rc = -EPERM; spin_unlock_bh(&link->link_state_spin_lock); @@ -1997,7 +1997,7 @@ static int cam_req_mgr_cb_notify_trigger( } spin_lock_bh(&link->link_state_spin_lock); - if (link->state != CAM_CRM_LINK_STATE_READY) { + if (link->state < CAM_CRM_LINK_STATE_READY) { CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); spin_unlock_bh(&link->link_state_spin_lock); rc = -EPERM; -- GitLab From e7ce207b798f690225703aa16ab72c22f9aec613 Mon Sep 17 00:00:00 2001 From: Alok Pandey Date: Mon, 19 Mar 2018 17:46:17 +0530 Subject: [PATCH 198/604] msm: camera: icp: Handle Watchdog/subsystem failures This change provides provision to capture fatal errors reported by FW and enables WD interrupt from A5. In such cases FW will be downloaded again before next USECASE starts, even if power collpase is enabled. Change-Id: I04aef9a55a7e1312344bdec5221e1c318cf1ef82 Signed-off-by: Alok Pandey Signed-off-by: Karthik Anantha Ram --- .../msm/camera/cam_icp/fw_inc/hfi_intf.h | 2 + .../msm/camera/cam_icp/fw_inc/hfi_reg.h | 18 +- .../media/platform/msm/camera/cam_icp/hfi.c | 15 +- .../msm/camera/cam_icp/icp_hw/a5_hw/a5_core.h | 6 +- .../camera/cam_icp/icp_hw/bps_hw/bps_core.c | 82 ++++++- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 226 ++++++++++++++++-- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h | 6 + .../icp_hw_mgr/include/cam_bps_hw_intf.h | 12 +- .../icp_hw_mgr/include/cam_ipe_hw_intf.h | 12 +- .../camera/cam_icp/icp_hw/ipe_hw/ipe_core.c | 82 ++++++- .../platform/msm/camera/cam_utils/cam_trace.h | 12 +- 11 files changed, 435 insertions(+), 38 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h index 4256064dc1bb..3e636c65138d 100644 --- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h +++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h @@ -35,6 +35,7 @@ struct hfi_mem { * @cmd_q: command queue hfi memory for host to firmware communication * @msg_q: message queue hfi memory for firmware to host communication * @dbg_q: debug queue hfi memory for firmware debug information + * @sfr_buf: buffer for subsystem failure reason[SFR] * @sec_heap: secondary heap hfi memory for firmware * @qdss: qdss mapped memory for fw * @icp_base: icp base address @@ -44,6 +45,7 @@ struct hfi_mem_info { struct hfi_mem cmd_q; struct hfi_mem msg_q; struct hfi_mem dbg_q; + struct hfi_mem sfr_buf; struct hfi_mem sec_heap; struct hfi_mem shmem; struct hfi_mem qdss; diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h index 2153ceacbb83..f652cfa3d2a3 100644 --- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h +++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h @@ -43,6 +43,7 @@ #define HFI_REG_UNCACHED_HEAP_SIZE 0x60 #define HFI_REG_QDSS_IOVA 0x6C #define HFI_REG_QDSS_IOVA_SIZE 0x70 +#define HFI_REG_SFR_PTR 0x68 /* end of ICP CSR registers */ /* flags for ICP CSR registers */ @@ -72,6 +73,7 @@ #define ICP_CMD_Q_SIZE_IN_BYTES 4096 #define ICP_MSG_Q_SIZE_IN_BYTES 4096 #define ICP_DBG_Q_SIZE_IN_BYTES 102400 +#define ICP_MSG_SFR_SIZE_IN_BYTES 4096 #define ICP_SHARED_MEM_IN_BYTES (1024 * 1024) #define ICP_UNCACHED_HEAP_SIZE_IN_BYTES (2 * 1024 * 1024) @@ -128,10 +130,14 @@ enum reg_settings { /** * @INTR_DISABLE: Disable interrupt * @INTR_ENABLE: Enable interrupt + * @INTR_ENABLE_WD0: Enable WD0 + * @INTR_ENABLE_WD1: Enable WD1 */ enum intr_status { INTR_DISABLE, - INTR_ENABLE + INTR_ENABLE, + INTR_ENABLE_WD0, + INTR_ENABLE_WD1 = 0x4 }; /** @@ -285,6 +291,16 @@ struct hfi_q_hdr { uint32_t dummy14[15]; }; +/** + * struct sfr_buf + * @size: Number of characters + * @msg : Subsystem failure reason + */ +struct sfr_buf { + uint32_t size; + char msg[ICP_MSG_SFR_SIZE_IN_BYTES]; +}; + /** * struct hfi_q_tbl * @q_tbl_hdr: Queue table header diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c index de72e85358d0..14a3e656e76d 100644 --- a/drivers/media/platform/msm/camera/cam_icp/hfi.c +++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c @@ -600,7 +600,7 @@ int cam_hfi_resume(struct hfi_mem_info *hfi_mem, return -EINVAL; } - cam_io_w_mb((uint32_t)INTR_ENABLE, + cam_io_w_mb((uint32_t)(INTR_ENABLE|INTR_ENABLE_WD0), icp_base + HFI_REG_A5_CSR_A2HOSTINTEN); fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION); @@ -610,6 +610,8 @@ int cam_hfi_resume(struct hfi_mem_info *hfi_mem, CAM_DBG(CAM_HFI, "wfi status = %x", (int)data); cam_io_w_mb((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR); + cam_io_w_mb((uint32_t)hfi_mem->sfr_buf.iova, + icp_base + HFI_REG_SFR_PTR); cam_io_w_mb((uint32_t)hfi_mem->shmem.iova, icp_base + HFI_REG_SHARED_MEM_PTR); cam_io_w_mb((uint32_t)hfi_mem->shmem.len, @@ -635,6 +637,7 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr, *dbg_q_hdr; uint32_t hw_version, soc_version, fw_version, status = 0; uint32_t retry_cnt = 0; + struct sfr_buf *sfr_buffer; mutex_lock(&hfi_cmd_q_mutex); mutex_lock(&hfi_msg_q_mutex); @@ -716,6 +719,9 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, dbg_q_hdr->qhdr_read_idx = RESET; dbg_q_hdr->qhdr_write_idx = RESET; + sfr_buffer = (struct sfr_buf *)hfi_mem->sfr_buf.kva; + sfr_buffer->size = ICP_MSG_SFR_SIZE_IN_BYTES; + switch (event_driven_mode) { case INTR_MODE: cmd_q_hdr->qhdr_type = Q_CMD; @@ -788,7 +794,10 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, break; } - cam_io_w_mb((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR); + cam_io_w_mb((uint32_t)hfi_mem->qtbl.iova, + icp_base + HFI_REG_QTBL_PTR); + cam_io_w_mb((uint32_t)hfi_mem->sfr_buf.iova, + icp_base + HFI_REG_SFR_PTR); cam_io_w_mb((uint32_t)hfi_mem->shmem.iova, icp_base + HFI_REG_SHARED_MEM_PTR); cam_io_w_mb((uint32_t)hfi_mem->shmem.len, @@ -845,7 +854,7 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, g_hfi->hfi_state = HFI_READY; g_hfi->cmd_q_state = true; g_hfi->msg_q_state = true; - cam_io_w_mb((uint32_t)INTR_ENABLE, + cam_io_w_mb((uint32_t)(INTR_ENABLE|INTR_ENABLE_WD0), icp_base + HFI_REG_A5_CSR_A2HOSTINTEN); mutex_unlock(&hfi_cmd_q_mutex); diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.h index 4aa6b4bd570e..f4bc813353a8 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.h +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.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 @@ -25,8 +25,8 @@ #define A5_CSR_BASE 2 #define A5_HOST_INT 0x1 -#define A5_WDT_0 0x10 -#define A5_WDT_1 0x100 +#define A5_WDT_0 0x2 +#define A5_WDT_1 0x4 #define ELF_GUARD_PAGE (2 * 1024 * 1024) diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c index 5bd7f1c91729..d01637436a51 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.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 @@ -18,6 +18,7 @@ #include #include #include +#include #include "cam_io_util.h" #include "cam_hw.h" #include "cam_hw_intf.h" @@ -30,6 +31,9 @@ #include "cam_icp_hw_mgr_intf.h" #include "cam_cpas_api.h" #include "cam_debug_util.h" +#include "hfi_reg.h" + +#define HFI_MAX_POLL_TRY 5 static int cam_bps_cpas_vote(struct cam_bps_device_core_info *core_info, struct cam_icp_cpas_vote *cpas_vote) @@ -210,6 +214,77 @@ static int cam_bps_handle_resume(struct cam_hw_info *bps_dev) return rc; } +static int cam_bps_cmd_reset(struct cam_hw_soc_info *soc_info, + struct cam_bps_device_core_info *core_info) +{ + uint32_t retry_cnt = 0; + uint32_t status = 0; + int pwr_ctrl, pwr_status, rc = 0; + bool reset_bps_cdm_fail = false; + bool reset_bps_top_fail = false; + + CAM_DBG(CAM_ICP, "CAM_ICP_BPS_CMD_RESET"); + /* Reset BPS CDM core*/ + cam_io_w_mb((uint32_t)0xF, + soc_info->reg_map[0].mem_base + BPS_CDM_RST_CMD); + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((soc_info->reg_map[0].mem_base + + BPS_CDM_IRQ_STATUS), + status, ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1), + 100, 10000); + + CAM_DBG(CAM_ICP, "bps_cdm_irq_status = %u", status); + + if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1) + break; + retry_cnt++; + } + status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + BPS_CDM_IRQ_STATUS); + if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) != 0x1) { + CAM_ERR(CAM_ICP, "BPS CDM rst failed status 0x%x", status); + reset_bps_cdm_fail = true; + } + + /* Reset BPS core*/ + status = 0; + cam_io_w_mb((uint32_t)0x3, + soc_info->reg_map[0].mem_base + BPS_TOP_RST_CMD); + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((soc_info->reg_map[0].mem_base + + BPS_TOP_IRQ_STATUS), + status, ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1), + 100, 10000); + + CAM_DBG(CAM_ICP, "bps_top_irq_status = %u", status); + + if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1) + break; + retry_cnt++; + } + status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + BPS_TOP_IRQ_STATUS); + if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) != 0x1) { + CAM_ERR(CAM_ICP, "BPS top rst failed status 0x%x", status); + reset_bps_top_fail = true; + } + + cam_bps_get_gdsc_control(soc_info); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, core_info->bps_hw_info->pwr_ctrl, + true, &pwr_ctrl); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, core_info->bps_hw_info->pwr_status, + true, &pwr_status); + CAM_DBG(CAM_ICP, "(After) pwr_ctrl = %x pwr_status = %x", + pwr_ctrl, pwr_status); + + if (reset_bps_cdm_fail || reset_bps_top_fail) + rc = -EAGAIN; + + return rc; +} + int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -311,7 +386,12 @@ int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, cam_bps_toggle_clk(soc_info, false); core_info->clk_enable = false; break; + case CAM_ICP_BPS_CMD_RESET: + rc = cam_bps_cmd_reset(soc_info, core_info); + break; default: + CAM_ERR(CAM_ICP, "Invalid Cmd Type:%u", cmd_type); + rc = -EINVAL; break; } return rc; 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 3c5690d00070..c73c25fef428 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 @@ -1179,7 +1179,7 @@ static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr, if (hw_mgr->bps_ctxt_cnt) goto end; - if (icp_hw_mgr.ipe_bps_pc_flag) { + if (icp_hw_mgr.ipe_bps_pc_flag && !hw_mgr->recovery) { rc = bps_dev_intf->hw_ops.process_cmd( bps_dev_intf->hw_priv, CAM_ICP_BPS_CMD_POWER_COLLAPSE, @@ -1201,11 +1201,10 @@ static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr, if (hw_mgr->ipe_ctxt_cnt) goto end; - if (icp_hw_mgr.ipe_bps_pc_flag) { + if (icp_hw_mgr.ipe_bps_pc_flag && !hw_mgr->recovery) { rc = ipe0_dev_intf->hw_ops.process_cmd( ipe0_dev_intf->hw_priv, CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0); - } if (hw_mgr->ipe_clk_state) @@ -1213,7 +1212,7 @@ static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr, ipe0_dev_intf->hw_priv, NULL, 0); if (ipe1_dev_intf) { - if (icp_hw_mgr.ipe_bps_pc_flag) { + if (icp_hw_mgr.ipe_bps_pc_flag && !hw_mgr->recovery) { rc = ipe1_dev_intf->hw_ops.process_cmd( ipe1_dev_intf->hw_priv, CAM_ICP_IPE_CMD_POWER_COLLAPSE, @@ -1226,7 +1225,7 @@ static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr, } hw_mgr->ipe_clk_state = false; - if (icp_hw_mgr.ipe_bps_pc_flag) { + if (icp_hw_mgr.ipe_bps_pc_flag && !hw_mgr->recovery) { hw_mgr->core_info = hw_mgr->core_info & (~(ICP_PWR_CLP_IPE0 | ICP_PWR_CLP_IPE1)); } @@ -1317,7 +1316,6 @@ static int cam_icp_hw_mgr_create_debugfs_entry(void) rc = -ENOMEM; goto err; } - icp_hw_mgr.icp_pc_flag = false; if (!debugfs_create_bool("ipe_bps_pc", 0644, @@ -1328,8 +1326,6 @@ static int cam_icp_hw_mgr_create_debugfs_entry(void) goto err; } - icp_hw_mgr.ipe_bps_pc_flag = false; - if (!debugfs_create_file("icp_debug_clk", 0644, icp_hw_mgr.dentry, NULL, @@ -1718,11 +1714,121 @@ static int cam_icp_mgr_process_direct_ack_msg(uint32_t *msg_ptr) return rc; } +static int cam_icp_ipebps_reset(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc = 0; + struct cam_hw_intf *ipe0_dev_intf; + struct cam_hw_intf *ipe1_dev_intf; + struct cam_hw_intf *bps_dev_intf; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + rc = bps_dev_intf->hw_ops.process_cmd( + bps_dev_intf->hw_priv, + CAM_ICP_BPS_CMD_RESET, + NULL, 0); + if (rc) + CAM_ERR(CAM_ICP, "bps reset failed"); + + rc = ipe0_dev_intf->hw_ops.process_cmd( + ipe0_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_RESET, + NULL, 0); + if (rc) + CAM_ERR(CAM_ICP, "ipe0 reset failed"); + + if (ipe1_dev_intf) { + rc = ipe1_dev_intf->hw_ops.process_cmd( + ipe1_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_RESET, + NULL, 0); + if (rc) + CAM_ERR(CAM_ICP, "ipe1 reset failed"); + } + + return 0; +} + +static int cam_icp_mgr_trigger_recovery(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc = 0; + int i = 0; + struct sfr_buf *sfr_buffer = NULL; + + CAM_DBG(CAM_ICP, "Enter"); + + mutex_lock(&hw_mgr->hw_mgr_mutex); + if (hw_mgr->recovery) { + CAM_ERR(CAM_ICP, "Recovery is set"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; + } + + sfr_buffer = (struct sfr_buf *)icp_hw_mgr.hfi_mem.sfr_buf.kva; + CAM_WARN(CAM_ICP, "SFR:%s", sfr_buffer->msg); + + cam_icp_ipebps_reset(hw_mgr); + + hw_mgr->recovery = true; + + if (hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog) { + hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog_reset_counter = 0; + crm_timer_exit(&hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog); + hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog = NULL; + } + if (hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog) { + hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog_reset_counter = 0; + crm_timer_exit(&hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog); + hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog = NULL; + } + + for (i = 0; i < CAM_ICP_CTX_MAX; i++) { + mutex_lock(&hw_mgr->ctx_data[i].ctx_mutex); + if (hw_mgr->ctx_data[i].state != CAM_ICP_CTX_STATE_RELEASE) + cam_icp_ctx_timer_stop(&hw_mgr->ctx_data[i]); + mutex_unlock(&hw_mgr->ctx_data[i].ctx_mutex); + } + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + CAM_DBG(CAM_ICP, "Done"); + return rc; +} +static int cam_icp_mgr_process_fatal_error( + struct cam_icp_hw_mgr *hw_mgr, uint32_t *msg_ptr) +{ + struct hfi_msg_event_notify *event_notify; + int rc = 0; + + CAM_DBG(CAM_ICP, "Enter"); + + event_notify = (struct hfi_msg_event_notify *)msg_ptr; + if (!event_notify) { + CAM_ERR(CAM_ICP, "Empty event message"); + return -EINVAL; + } + + CAM_DBG(CAM_ICP, "evt_id: %u evt_data1: %u evt_data2: %u", + event_notify->event_id, + event_notify->event_data1, + event_notify->event_data2); + + if (event_notify->event_id == HFI_EVENT_SYS_ERROR) { + CAM_INFO(CAM_ICP, "received HFI_EVENT_SYS_ERROR"); + rc = cam_icp_mgr_trigger_recovery(hw_mgr); + } + + return rc; +} + static void cam_icp_mgr_process_dbg_buf(void) { uint32_t *msg_ptr = NULL, *pkt_ptr = NULL; struct hfi_msg_debug *dbg_msg; uint32_t read_len, size_processed = 0; + uint64_t timestamp = 0; char *dbg_buf; int rc = 0; @@ -1736,7 +1842,9 @@ static void cam_icp_mgr_process_dbg_buf(void) if (pkt_ptr[ICP_PACKET_TYPE] == HFI_MSG_SYS_DEBUG) { dbg_msg = (struct hfi_msg_debug *)pkt_ptr; dbg_buf = (char *)&dbg_msg->msg_data; - trace_cam_icp_fw_dbg(dbg_buf); + timestamp = ((((uint64_t)(dbg_msg->timestamp_hi) << 32) + | dbg_msg->timestamp_lo) >> 16); + trace_cam_icp_fw_dbg(dbg_buf, timestamp/2); } size_processed += (pkt_ptr[ICP_PACKET_SIZE] >> BYTE_WORD_SHIFT); @@ -1802,6 +1910,10 @@ static int cam_icp_process_msg_pkt_type( CAM_DBG(CAM_ICP, "received EVENT_NOTIFY"); size_processed = ( (struct hfi_msg_event_notify *)msg_ptr)->size; + rc = cam_icp_mgr_process_fatal_error(hw_mgr, msg_ptr); + if (rc) + CAM_ERR(CAM_ICP, "failed in processing evt notify"); + break; default: @@ -1862,6 +1974,13 @@ static int32_t cam_icp_mgr_process_msg(void *priv, void *data) HFI_DEBUG_MODE_QUEUE) cam_icp_mgr_process_dbg_buf(); + if ((task_data->irq_status & A5_WDT_0) || + (task_data->irq_status & A5_WDT_1)) { + CAM_ERR_RATE_LIMIT(CAM_ICP, "watch dog interrupt from A5"); + + rc = cam_icp_mgr_trigger_recovery(hw_mgr); + } + return rc; } @@ -1945,6 +2064,31 @@ static int cam_icp_alloc_secheap_mem(struct cam_mem_mgr_memory_desc *secheap) return rc; } +static int cam_icp_alloc_sfr_mem(struct cam_mem_mgr_memory_desc *sfr) +{ + int rc; + struct cam_mem_mgr_request_desc alloc; + struct cam_mem_mgr_memory_desc out; + + memset(&alloc, 0, sizeof(alloc)); + memset(&out, 0, sizeof(out)); + alloc.size = SZ_8K; + alloc.align = 0; + alloc.flags = CAM_MEM_FLAG_HW_READ_WRITE | + CAM_MEM_FLAG_HW_SHARED_ACCESS; + + alloc.smmu_hdl = icp_hw_mgr.iommu_hdl; + rc = cam_mem_mgr_request_mem(&alloc, &out); + if (rc) + return rc; + + *sfr = out; + CAM_DBG(CAM_ICP, "kva: %llX, iova: %x, hdl: %x, len: %lld", + out.kva, out.iova, out.mem_handle, out.len); + + return rc; +} + static int cam_icp_alloc_shared_mem(struct cam_mem_mgr_memory_desc *qtbl) { int rc; @@ -2060,6 +2204,12 @@ static int cam_icp_allocate_hfi_mem(void) goto dbg_q_alloc_failed; } + rc = cam_icp_alloc_sfr_mem(&icp_hw_mgr.hfi_mem.sfr_buf); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to allocate sfr buffer"); + goto sfr_buf_alloc_failed; + } + rc = cam_icp_alloc_secheap_mem(&icp_hw_mgr.hfi_mem.sec_heap); if (rc) { CAM_ERR(CAM_ICP, "Unable to allocate sec heap memory"); @@ -2068,6 +2218,8 @@ static int cam_icp_allocate_hfi_mem(void) return rc; sec_heap_alloc_failed: + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.sfr_buf); +sfr_buf_alloc_failed: cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.dbg_q); dbg_q_alloc_failed: cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.msg_q); @@ -2212,7 +2364,7 @@ static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr) } a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv; - if (!hw_mgr->icp_pc_flag) { + if (!hw_mgr->icp_pc_flag || hw_mgr->recovery) { cam_hfi_disable_cpu( a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); rc = cam_icp_mgr_hw_close_k(hw_mgr, NULL); @@ -2243,27 +2395,34 @@ static int cam_icp_mgr_hfi_resume(struct cam_icp_hw_mgr *hw_mgr) hfi_mem.qtbl.kva = icp_hw_mgr.hfi_mem.qtbl.kva; hfi_mem.qtbl.iova = icp_hw_mgr.hfi_mem.qtbl.iova; hfi_mem.qtbl.len = icp_hw_mgr.hfi_mem.qtbl.len; - CAM_DBG(CAM_ICP, "kva = %llX IOVA = %X length = %lld\n", + CAM_DBG(CAM_ICP, "qtbl kva = %llX IOVA = %X length = %lld\n", hfi_mem.qtbl.kva, hfi_mem.qtbl.iova, hfi_mem.qtbl.len); hfi_mem.cmd_q.kva = icp_hw_mgr.hfi_mem.cmd_q.kva; hfi_mem.cmd_q.iova = icp_hw_mgr.hfi_mem.cmd_q.iova; hfi_mem.cmd_q.len = icp_hw_mgr.hfi_mem.cmd_q.len; - CAM_DBG(CAM_ICP, "kva = %llX IOVA = %X length = %lld\n", + CAM_DBG(CAM_ICP, "cmd_q kva = %llX IOVA = %X length = %lld\n", hfi_mem.cmd_q.kva, hfi_mem.cmd_q.iova, hfi_mem.cmd_q.len); hfi_mem.msg_q.kva = icp_hw_mgr.hfi_mem.msg_q.kva; hfi_mem.msg_q.iova = icp_hw_mgr.hfi_mem.msg_q.iova; hfi_mem.msg_q.len = icp_hw_mgr.hfi_mem.msg_q.len; - CAM_DBG(CAM_ICP, "kva = %llX IOVA = %X length = %lld\n", + CAM_DBG(CAM_ICP, "msg_q kva = %llX IOVA = %X length = %lld\n", hfi_mem.msg_q.kva, hfi_mem.msg_q.iova, hfi_mem.msg_q.len); hfi_mem.dbg_q.kva = icp_hw_mgr.hfi_mem.dbg_q.kva; hfi_mem.dbg_q.iova = icp_hw_mgr.hfi_mem.dbg_q.iova; hfi_mem.dbg_q.len = icp_hw_mgr.hfi_mem.dbg_q.len; - CAM_DBG(CAM_ICP, "kva = %llX IOVA = %X length = %lld\n", + CAM_DBG(CAM_ICP, "dbg_q kva = %llX IOVA = %X length = %lld\n", hfi_mem.dbg_q.kva, hfi_mem.dbg_q.iova, hfi_mem.dbg_q.len); + hfi_mem.sfr_buf.kva = icp_hw_mgr.hfi_mem.sfr_buf.kva; + hfi_mem.sfr_buf.iova = icp_hw_mgr.hfi_mem.sfr_buf.iova; + hfi_mem.sfr_buf.len = icp_hw_mgr.hfi_mem.sfr_buf.len; + CAM_DBG(CAM_ICP, "sfr kva = %llX IOVA = %X length = %lld\n", + hfi_mem.sfr_buf.kva, hfi_mem.sfr_buf.iova, + hfi_mem.sfr_buf.len); + hfi_mem.sec_heap.kva = icp_hw_mgr.hfi_mem.sec_heap.kva; hfi_mem.sec_heap.iova = icp_hw_mgr.hfi_mem.sec_heap.iova; hfi_mem.sec_heap.len = icp_hw_mgr.hfi_mem.sec_heap.len; @@ -2407,7 +2566,8 @@ static int cam_icp_mgr_release_ctx(struct cam_icp_hw_mgr *hw_mgr, int ctx_id) cam_icp_mgr_ipe_bps_power_collapse(hw_mgr, &hw_mgr->ctx_data[ctx_id], 0); hw_mgr->ctx_data[ctx_id].state = CAM_ICP_CTX_STATE_RELEASE; - CAM_DBG(CAM_ICP, "E: ctx_id = %d", ctx_id); + CAM_DBG(CAM_ICP, "E: ctx_id = %d recovery = %d", + ctx_id, hw_mgr->recovery); cam_icp_mgr_abort_handle(&hw_mgr->ctx_data[ctx_id]); cam_icp_mgr_destroy_handle(&hw_mgr->ctx_data[ctx_id]); cam_icp_mgr_cleanup_ctx(&hw_mgr->ctx_data[ctx_id]); @@ -2640,6 +2800,10 @@ static int cam_icp_mgr_hfi_init(struct cam_icp_hw_mgr *hw_mgr) hfi_mem.dbg_q.iova = icp_hw_mgr.hfi_mem.dbg_q.iova; hfi_mem.dbg_q.len = icp_hw_mgr.hfi_mem.dbg_q.len; + hfi_mem.sfr_buf.kva = icp_hw_mgr.hfi_mem.sfr_buf.kva; + hfi_mem.sfr_buf.iova = icp_hw_mgr.hfi_mem.sfr_buf.iova; + hfi_mem.sfr_buf.len = icp_hw_mgr.hfi_mem.sfr_buf.len; + hfi_mem.sec_heap.kva = icp_hw_mgr.hfi_mem.sec_heap.kva; hfi_mem.sec_heap.iova = icp_hw_mgr.hfi_mem.sec_heap.iova; hfi_mem.sec_heap.len = icp_hw_mgr.hfi_mem.sec_heap.len; @@ -2800,6 +2964,7 @@ static int cam_icp_mgr_hw_open(void *hw_mgr_priv, void *download_fw_args) hw_mgr->ctxt_cnt = 0; hw_mgr->fw_download = true; + hw_mgr->recovery = false; CAM_INFO(CAM_ICP, "FW download done successfully"); @@ -3635,6 +3800,7 @@ static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) { struct cam_hw_flush_args *flush_args = hw_flush_args; struct cam_icp_hw_ctx_data *ctx_data; + struct cam_icp_hw_mgr *hw_mgr = hw_priv; if ((!hw_priv) || (!hw_flush_args)) { CAM_ERR(CAM_ICP, "Input params are Null:"); @@ -3656,8 +3822,15 @@ static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) switch (flush_args->flush_type) { case CAM_FLUSH_TYPE_ALL: - if (flush_args->num_req_active) - cam_icp_mgr_abort_handle(ctx_data); + 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); + } + } else { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + } mutex_lock(&ctx_data->ctx_mutex); cam_icp_mgr_flush_all(ctx_data, flush_args); mutex_unlock(&ctx_data->ctx_mutex); @@ -3695,7 +3868,7 @@ static int cam_icp_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) return -EINVAL; } - CAM_DBG(CAM_ICP, "Enter"); + CAM_DBG(CAM_ICP, "Enter recovery set %d", hw_mgr->recovery); ctx_data = release_hw->ctxt_to_hw_map; if (!ctx_data) { CAM_ERR(CAM_ICP, "NULL ctx data"); @@ -3716,9 +3889,15 @@ static int cam_icp_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) } mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex); - if (release_hw->active_req) { - cam_icp_mgr_abort_handle(ctx_data); - cam_icp_mgr_send_abort_status(ctx_data); + mutex_lock(&hw_mgr->hw_mgr_mutex); + if (!hw_mgr->recovery) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + if (release_hw->active_req) { + cam_icp_mgr_abort_handle(ctx_data); + cam_icp_mgr_send_abort_status(ctx_data); + } + } else { + mutex_unlock(&hw_mgr->hw_mgr_mutex); } mutex_lock(&hw_mgr->hw_mgr_mutex); @@ -3732,7 +3911,7 @@ static int cam_icp_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) } mutex_unlock(&hw_mgr->hw_mgr_mutex); - if (!hw_mgr->bps_ctxt_cnt || !hw_mgr->ipe_ctxt_cnt) + if ((!hw_mgr->bps_ctxt_cnt || !hw_mgr->ipe_ctxt_cnt)) cam_icp_device_timer_stop(hw_mgr); CAM_DBG(CAM_ICP, "Exit"); @@ -4289,6 +4468,9 @@ static int cam_icp_mgr_create_wq(void) if (rc) goto debugfs_create_failed; + icp_hw_mgr.icp_pc_flag = true; + icp_hw_mgr.ipe_bps_pc_flag = true; + for (i = 0; i < ICP_WORKQ_NUM_TASK; i++) icp_hw_mgr.msg_work->task.pool[i].payload = &icp_hw_mgr.msg_work_data[i]; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index 3e3c0e08e187..0b931f3c7636 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -79,6 +79,7 @@ * @sec_heap: Memory info of secondary heap * @fw_buf: Memory info of firmware * @qdss_buf: Memory info of qdss + * @sfr_buf: Memory info for sfr buffer */ struct icp_hfi_mem_info { struct cam_mem_mgr_memory_desc qtbl; @@ -88,6 +89,7 @@ struct icp_hfi_mem_info { struct cam_mem_mgr_memory_desc sec_heap; struct cam_mem_mgr_memory_desc fw_buf; struct cam_mem_mgr_memory_desc qdss_buf; + struct cam_mem_mgr_memory_desc sfr_buf; struct cam_smmu_region_info shmem; }; @@ -309,6 +311,9 @@ struct cam_icp_clk_info { * @bps_dev_intf: Device interface for BPS * @ipe_clk_state: IPE clock state flag * @bps_clk_state: BPS clock state flag + * @recovery: Flag to validate if in previous session FW + * reported a fatal error or wdt. If set FW is + * re-downloaded for new camera session. */ struct cam_icp_hw_mgr { struct mutex hw_mgr_mutex; @@ -356,6 +361,7 @@ struct cam_icp_hw_mgr { struct cam_hw_intf *bps_dev_intf; bool ipe_clk_state; bool bps_clk_state; + bool recovery; }; static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args); diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h index 4f0717290b06..0f76a057c687 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.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 @@ -18,6 +18,15 @@ #include "cam_hw_mgr_intf.h" #include "cam_icp_hw_intf.h" +/* BPS register */ +#define BPS_TOP_RST_CMD 0x1008 +#define BPS_CDM_RST_CMD 0x10 +#define BPS_CDM_IRQ_STATUS 0x44 +#define BPS_TOP_IRQ_STATUS 0x100C + +/* BPS CDM/TOP status register */ +#define BPS_RST_DONE_IRQ_STATUS_BIT 0x1 + enum cam_icp_bps_cmd_type { CAM_ICP_BPS_CMD_FW_DOWNLOAD, CAM_ICP_BPS_CMD_POWER_COLLAPSE, @@ -28,6 +37,7 @@ enum cam_icp_bps_cmd_type { CAM_ICP_BPS_CMD_CPAS_STOP, CAM_ICP_BPS_CMD_UPDATE_CLK, CAM_ICP_BPS_CMD_DISABLE_CLK, + CAM_ICP_BPS_CMD_RESET, CAM_ICP_BPS_CMD_MAX, }; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h index 0943bef0836d..d1e3b9a9ae0d 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.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 @@ -18,6 +18,15 @@ #include "cam_hw_mgr_intf.h" #include "cam_icp_hw_intf.h" +/* IPE registers */ +#define IPE_TOP_RST_CMD 0x1008 +#define IPE_CDM_RST_CMD 0x10 +#define IPE_CDM_IRQ_STATUS 0x44 +#define IPE_TOP_IRQ_STATUS 0x100C + +/* IPE CDM/TOP status register */ +#define IPE_RST_DONE_IRQ_STATUS_BIT 0x1 + enum cam_icp_ipe_cmd_type { CAM_ICP_IPE_CMD_FW_DOWNLOAD, CAM_ICP_IPE_CMD_POWER_COLLAPSE, @@ -28,6 +37,7 @@ enum cam_icp_ipe_cmd_type { CAM_ICP_IPE_CMD_CPAS_STOP, CAM_ICP_IPE_CMD_UPDATE_CLK, CAM_ICP_IPE_CMD_DISABLE_CLK, + CAM_ICP_IPE_CMD_RESET, CAM_ICP_IPE_CMD_MAX, }; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c index 87478af551b7..620a4bd4943b 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.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 @@ -18,6 +18,7 @@ #include #include #include +#include #include "cam_io_util.h" #include "cam_hw.h" #include "cam_hw_intf.h" @@ -29,6 +30,9 @@ #include "cam_icp_hw_mgr_intf.h" #include "cam_cpas_api.h" #include "cam_debug_util.h" +#include "hfi_reg.h" + +#define HFI_MAX_POLL_TRY 5 static int cam_ipe_caps_vote(struct cam_ipe_device_core_info *core_info, struct cam_icp_cpas_vote *cpas_vote) @@ -206,6 +210,77 @@ static int cam_ipe_handle_resume(struct cam_hw_info *ipe_dev) return rc; } +static int cam_ipe_cmd_reset(struct cam_hw_soc_info *soc_info, + struct cam_ipe_device_core_info *core_info) +{ + int pwr_ctrl, pwr_status, rc = 0; + uint32_t status = 0, retry_cnt = 0; + bool reset_ipe_cdm_fail = false; + bool reset_ipe_top_fail = false; + + CAM_DBG(CAM_ICP, "CAM_ICP_IPE_CMD_RESET"); + /* IPE CDM core reset*/ + cam_io_w_mb((uint32_t)0xF, + soc_info->reg_map[0].mem_base + IPE_CDM_RST_CMD); + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((soc_info->reg_map[0].mem_base + + IPE_CDM_IRQ_STATUS), + status, ((status & IPE_RST_DONE_IRQ_STATUS_BIT) == 0x1), + 100, 10000); + + CAM_DBG(CAM_HFI, "ipe_cdm_irq_status = %u", status); + + if ((status & IPE_RST_DONE_IRQ_STATUS_BIT) == 0x1) + break; + retry_cnt++; + } + status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + IPE_CDM_IRQ_STATUS); + if ((status & IPE_RST_DONE_IRQ_STATUS_BIT) != 0x1) { + CAM_ERR(CAM_ICP, "IPE CDM rst failed status 0x%x", status); + reset_ipe_cdm_fail = true; + } + + /* IPE reset*/ + status = 0; + cam_io_w_mb((uint32_t)0x3, + soc_info->reg_map[0].mem_base + IPE_TOP_RST_CMD); + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((soc_info->reg_map[0].mem_base + + IPE_TOP_IRQ_STATUS), + status, ((status & IPE_RST_DONE_IRQ_STATUS_BIT) == 0x1), + 100, 10000); + + CAM_DBG(CAM_HFI, "ipe_top_irq_status = %u", status); + + + if ((status & IPE_RST_DONE_IRQ_STATUS_BIT) == 0x1) + break; + retry_cnt++; + } + status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + IPE_TOP_IRQ_STATUS); + if ((status & IPE_RST_DONE_IRQ_STATUS_BIT) != 0x1) { + CAM_ERR(CAM_ICP, "IPE top rst failed status 0x%x", status); + reset_ipe_top_fail = true; + } + + cam_ipe_get_gdsc_control(soc_info); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, core_info->ipe_hw_info->pwr_ctrl, + true, &pwr_ctrl); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, core_info->ipe_hw_info->pwr_status, + true, &pwr_status); + CAM_DBG(CAM_ICP, "(After)pwr_ctrl = %x pwr_status = %x", + pwr_ctrl, pwr_status); + + if (reset_ipe_cdm_fail || reset_ipe_top_fail) + rc = -EAGAIN; + + return rc; +} + int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -302,7 +377,12 @@ int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, cam_ipe_toggle_clk(soc_info, false); core_info->clk_enable = false; break; + case CAM_ICP_IPE_CMD_RESET: + rc = cam_ipe_cmd_reset(soc_info, core_info); + break; default: + CAM_ERR(CAM_ICP, "Invalid Cmd Type:%u", cmd_type); + rc = -EINVAL; break; } return rc; diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_trace.h b/drivers/media/platform/msm/camera/cam_utils/cam_trace.h index 90ec5666941e..c7dc0b6b2d00 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_trace.h +++ b/drivers/media/platform/msm/camera/cam_utils/cam_trace.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 @@ -72,17 +72,19 @@ TRACE_EVENT(cam_isp_activated_irq, ); TRACE_EVENT(cam_icp_fw_dbg, - TP_PROTO(char *dbg_message), - TP_ARGS(dbg_message), + TP_PROTO(char *dbg_message, uint64_t timestamp), + TP_ARGS(dbg_message, timestamp), TP_STRUCT__entry( __string(dbg_message, dbg_message) + __field(uint64_t, timestamp) ), TP_fast_assign( __assign_str(dbg_message, dbg_message); + __entry->timestamp = timestamp; ), TP_printk( - "%s: ", - __get_str(dbg_message) + "%llu %s: ", + __entry->timestamp, __get_str(dbg_message) ) ); -- GitLab From 9e97f18911846900a4dda4f73e762b7f4f298e51 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Thu, 3 May 2018 15:21:30 -0700 Subject: [PATCH 199/604] msm: camera: sensor: Add support to vote for PWM mode Camera image sensor needs to vote to BoB regualtor to switch into PWM operation mode in order to reduce analog voltage noise. This change votes for PWM operational mode switch at the time of power on camera image sensor and Auto mode switch at the time of power off. Change-Id: Iea3e5642e3ef6a06b0916a36fa118e22a4c48573 Signed-off-by: Jigarkumar Zala --- .../bindings/media/video/msm-cam-cci.txt | 1074 ++++++++++++----- .../cam_sensor/cam_sensor_core.c | 21 +- .../cam_sensor/cam_sensor_dev.h | 4 + .../cam_sensor/cam_sensor_soc.c | 30 +- .../cam_sensor_utils/cam_sensor_util.c | 18 + .../cam_sensor_utils/cam_sensor_util.h | 3 + 6 files changed, 813 insertions(+), 337 deletions(-) diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cam-cci.txt index cd4d222021c4..59651a354157 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-cci.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-cci.txt @@ -1,355 +1,752 @@ * Qualcomm Technologies, Inc. MSM CCI -[First level nodes] -Required properties: +CCI (Camera Control Interface) is module that is use for camera sensor module +I2C communication. + +======================= +Required Node Structure +======================= +The camera CCI node must be described in two levels of device nodes. The +first level describe the overall CCI node structure. Second level nodes +describe camera sensor submodule nodes which is using CCI for +i2c communication. + +====================================== +First Level Node - CCI device +====================================== + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cci". + - cell-index: cci hardware core index -- compatible : - - "qcom,cci" -- reg : offset and length of the register set for the device - for the cci operating in compatible mode. -- reg-names : should specify relevant names to each reg property defined. -- interrupts : should contain the cci interrupt. -- interrupt-names : should specify relevant names to each interrupts - property defined. -- gpios : should contain phandle to gpio controller node and array of - #gpio-cells specifying specific gpio (controller specific) -- gpio-req-tbl-num : should contain index to gpios specific to this sensor -- gpio-req-tbl-flags : should contain direction of gpios present in - gpio-req-tbl-num property (in the same order) -- gpio-req-tbl-label : should contain name of gpios present in - gpio-req-tbl-num property (in the same order) -- clock-names: name of the clocks required for the device -- clock-rates: clock rate in Hz - -Optional properties: -- regulator-names : name of the voltage regulators required for the device. -- gdscr-supply : should contain gdsr regulator used for cci clocks. -- mmagic-supply : should contain mmagic regulator used for mmagic clocks. + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the cci operating in + compatible mode. + +- reg-names + Usage: required + Value type: + Definition: Should specify relevant names to each + reg property defined. + +- interrupts + Usage: required + Value type: + Definition: Interrupt associated with CCI HW. + +- interrupt-names + Usage: required + Value type: + Definition: Name of the interrupt. + +- gpios + Usage: required + Value type: + Definition: should specify the gpios to be used for the CCI. + +- gpio-req-tbl-num + Usage: required + Value type: + Definition: should specify the gpio table index. + +- gpio-req-tbl-flags + Usage: required + Value type: + Definition: should specify the gpio functions. + +- gpio-req-tbl-label + Usage: required + Value type: + Definition: should specify the gpio labels in + gpio-req-tbl-num property (in the same order) + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for CCI HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clock rates in Hz for CCI HW. + +- clock-cntl-level + Usage: required + Value type: + Definition: All different clock level node can support. + +- clocks + Usage: required + Value type: + Definition: all clock phandle and source clocks. +- src-clock-name + Usage: required + Value type: + Definition: name for the source clock. + +- regulator-names + Usage: required + Value type: + Definition: name of the voltage regulators required for the device. + +- gdscr-supply + Usage: required + Value type: + Definition: should contain gdsr regulator used for cci clocks. + +- mmagic-supply + Usage: optional + Value type: + Definition: should contain mmagic regulator used for mmagic clocks. + +========================= +CCI clock settings +========================= - I2c speed settings (*) - - i2c_freq_100Khz: qcom,i2c_standard_mode - node should contain clock settings for - 100Khz - - i2c_freq_400Khz: qcom,i2c_fast_mode - node should contain clock settings for - 400Khz - - i2c_freq_custom: qcom,i2c_custom_mode - node can contain clock settings for - frequencies other than 100Khz and 400Khz which is specific to usecase. - Currently it has settings for 375Khz. - - i2c_freq_1Mhz: qcom,i2c_fast_plus_mode - node should contain clock - settings for 1Mhz + Usage: required + Definition: List of i2c rates for CCI HW. + - i2c_freq_100Khz + Definition: qcom,i2c_standard_mode - node should contain clock settings for + 100Khz + - i2c_freq_400Khz + Definition: qcom,i2c_fast_mode - node should contain clock settings for + 400Khz + - i2c_freq_custom + Definition: qcom,i2c_custom_mode - node can contain clock settings for + frequencies other than 100Khz and 400Khz which is specific to usecase. + Currently it has settings for 375Khz. + - i2c_freq_1Mhz + Definition: qcom,i2c_fast_plus_mode - node should contain clock + settings for 1Mhz * if speed settings is not defined the low level driver can use "i2c_freq_custom" like default -[Second level nodes] -* Qualcomm Technologies, Inc. CCI clock settings + - hw-thigh + Definition: should contain high period of the SCL clock in terms of CCI clock cycle + - hw-tlow + Definition: should contain high period of the SCL clock in terms of CCI clock cycle + - hw-tsu-sto + Definition: should contain setup time for STOP condition + - hw-tsu-sta + Definition: should contain setup time for Repeated START condition + - hw-thd-dat + Definition: should contain hold time for the data + - hw-thd-sta + Definition: should contain hold time for START condition + - hw-tbuf + Definition: should contain free time between a STOP and a START condition + - hw-scl-stretch-en + Definition: should contain enable or disable clock stretching + - hw-trdhld + Definition: should contain internal hold time for SDA + - hw-tsp + Definition: should contain filtering of glitches -Optional properties: -- hw-thigh : should contain high period of the SCL clock in terms of CCI clock cycle -- hw-tlow : should contain high period of the SCL clock in terms of CCI clock cycle -- hw-tsu-sto : should contain setup time for STOP condition -- hw-tsu-sta : should contain setup time for Repeated START condition -- hw-thd-dat : should contain hold time for the data -- hw-thd-sta : should contain hold time for START condition -- hw-tbuf : should contain free time between a STOP and a START condition -- hw-scl-stretch-en : should contain enable or disable clock stretching -- hw-trdhld : should contain internal hold time for SDA -- hw-tsp : should contain filtering of glitches +Example: + + qcom,cci@0xfda0c000 { + cell-index = <0>; + compatible = "qcom,cci"; + reg = <0xfda0c000 0x300>; + reg-names = "cci"; + interrupts = <0 50 0>; + interrupt-names = "cci"; + clock-names = "camnoc_axi_clk", "soc_ahb_clk", + "slow_ahb_src_clk", "cpas_ahb_clk", + "cci_clk", "cci_clk_src"; + clock-rates = <0 0 80000000 0 0 37500000>; + clock-cntl-level = "turbo"; + gpios = <&tlmm 17 0>, + <&tlmm 18 0>, + <&tlmm 19 0>, + <&tlmm 20 0>; + gpio-tbl-num = <0 1 2 3>; + gpio-tbl-flags = <1 1 1 1>; + gpio-tbl-label = "CCI_I2C_DATA0", + "CCI_I2C_CLK0", + "CCI_I2C_DATA1", + "CCI_I2C_CLK1"; + i2c_freq_100Khz: qcom,i2c_standard_mode { + hw-thigh = <78>; + hw-tlow = <114>; + hw-tsu-sto = <28>; + hw-tsu-sta = <28>; + hw-thd-dat = <10>; + hw-thd-sta = <77>; + hw-tbuf = <118>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <1>; + status = "ok"; + }; + i2c_freq_400Khz: qcom,i2c_fast_mode { + hw-thigh = <20>; + hw-tlow = <28>; + hw-tsu-sto = <21>; + hw-tsu-sta = <21>; + hw-thd-dat = <13>; + hw-thd-sta = <18>; + hw-tbuf = <25>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + status = "ok"; + }; + i2c_freq_custom: qcom,i2c_custom_mode { + hw-thigh = <15>; + hw-tlow = <28>; + hw-tsu-sto = <21>; + hw-tsu-sta = <21>; + hw-thd-dat = <13>; + hw-thd-sta = <18>; + hw-tbuf = <25>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + 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 = <19>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; -* Qualcomm Technologies, Inc. MSM Camera Sensor Resource Manager +======================================= +Second Level Node - CAM SENSOR MODULES +======================================= -MSM camera sensor resource manager node contains properties of shared camera +======================================= +CAM SENSOR RESOURCE MANAGER +======================================= +Camera Sensor Resource manager node contains properties of shared camera sensor resource. -Required properties: -- compatible : should be manufacturer name followed by sensor name - - "qcom,cam-res-mgr" -Optional properties: -- shared-gpios : should contain the gpios which are used by two or more - cameras, and these cameras may be opened together. -- pinctrl-names: List of names to assign the shared pin state defined in pinctrl device node -- pinctrl-<0..n>: Lists phandles each pointing to the pin configuration node within a pin - controller. These pin configurations are installed in the pinctrl device node. - -* Qualcomm Technologies, Inc. MSM Sensor - -MSM sensor node contains properties of camera sensor - -Required properties: -- compatible : should be manufacturer name followed by sensor name - - "qcom,camera" -- reg : should contain i2c slave address of the device -- csiphy-sd-index : should contain csiphy instance that will used to - receive sensor data - - 0, 1, 2 -- cam_vdig-supply : should contain regulator from which digital voltage is - supplied -- cam_vana-supply : should contain regulator from which analog voltage is - supplied -- cam_vio-supply : should contain regulator from which IO voltage is supplied -- regulator-names : should contain names of all regulators needed by this - sensor - - "cam_vdig", "cam_vana", "cam_vio", "cam_vaf" -- rgltr-cntrl-support : It is booloean property. This property is required - if the code and regulator control parameters e.g. rgltr-min-voltage -- rgltr-min-voltage : should contain minimum voltage level for - regulators mentioned in regulator-names property (in the same order) -- rgltr-max-voltage : should contain maximum voltage level for - regulators mentioned in regulator-names property (in the same order) -- rgltr-load-current : should contain optimum voltage level for regulators - mentioned in regulator-names property (in the same order) -- sensor-position-roll : should contain sensor rotational angle with respect - to axis of reference - - 0, 90, 180, 360 -- sensor-position-pitch : should contain sensor rotational angle with respect - to axis of reference - - 0, 90, 180, 360 -- sensor-position-yaw : should contain sensor rotational angle with respect - to axis of reference - - 0, 90, 180, 360 -Optional properties: -- slave-id : should contain i2c slave address, device id address, expected - id read value and device id mask -- sensor-name : should contain unique sensor name to differentiate from - other sensor - - "s5k3l1yx" -- sensor-mode : should contain sensor mode supported - - 0 -> back camera 2D - - 1 -> front camera 2D - - 2 -> back camera 3D - - 3 -> back camera int 3D -- sensor-type : should contain format of data that sensor streams - - 0 -> bayer format - - 1 -> yuv format -- qcom,secure : should be enabled to operate the camera in secure mode - - 0, 1 -- gpio-no-mux : should contain field to indicate whether gpio mux table is - available - - 1 if gpio mux is not available, 0 otherwise -- cam_vaf-supply : should contain regulator from which AF voltage is supplied -- gpios : should contain phandle to gpio controller node and array of - #gpio-cells specifying specific gpio (controller specific) -- gpio-reset : should contain index to gpio used by sensors reset_n -- gpio-standby : should contain index to gpio used by sensors standby_n -- gpio-vio : should contain index to gpio used by sensors io vreg enable -- gpio-vana : should contain index to gpio used by sensors analog vreg enable -- gpio-vdig : should contain index to gpio used by sensors digital vreg enable -- gpio-vaf : should contain index to gpio used by sensors af vreg enable -- gpio-af-pwdm : should contain index to gpio used by sensors af pwdm_n -- gpio-req-tbl-num : should contain index to gpios specific to this sensor -- gpio-req-tbl-flags : should contain direction of gpios present in - gpio-req-tbl-num property (in the same order) -- gpio-req-tbl-label : should contain name of gpios present in - gpio-req-tbl-num property (in the same order) -- gpio-set-tbl-num : should contain index of gpios that need to be - configured by msm -- gpio-set-tbl-flags : should contain value to be configured for the gpios - present in gpio-set-tbl-num property (in the same order) -- gpio-set-tbl-delay : should contain amount of delay after configuring - gpios as specified in gpio_set_tbl_flags property (in the same order) -- csi-phy-sel : should contain CSIPHY core instance from which CSID should - receive data -- actuator-cam-name : should contain actuator cam name associated with - this sensor - - If actuator does not exist, this property should not be initialized - - If actuator exist, this field should indicate the index of actuator to - be used -- qcom,actuator-vcm-pwd : should contain the gpio pin of vcm power to be enabled - for actuator -- qcom,actuator-vcm-enable : should contain value to be set for actuator vcm - gpio -- sensor-position : should contain the mount angle of the camera sensor - - 0 -> back camera - - 1 -> front camera -- cci-master : should contain i2c master id to be used for this camera - sensor - - 0 -> MASTER 0 - - 1 -> MASTER 1 -- actuator-src : if auto focus is supported by this sensor, this - property should contain phandle of respective actuator node -- led-flash-src : if LED flash is supported by this sensor, this - property should contain phandle of respective LED flash node -- qcom,vdd-cx-supply : should contain regulator from which cx voltage is - supplied -- qcom,vdd-cx-name : should contain names of cx regulator -- eeprom-src : if eeprom memory is supported by this sensor, this - property should contain phandle of respective eeprom nodes -- ois-src : if optical image stabilization is supported by this sensor, - this property should contain phandle of respective ois node -- ir-led-src : if ir led is supported by this sensor, this property - should contain phandle of respective ir-led node -- qcom,ir-cut-src : if ir cut is supported by this sensor, this property - should contain phandle of respective ir-cut node -- qcom,special-support-sensors: if only some special sensors are supported - on this board, add sensor name in this property. -- use-shared-clk : It is booloean property. This property is required - if the clk is shared clk between different sensor and ois, if this - device need to be opened together. -- clock-rates: clock rate in Hz. -- clock-cntl-level: says what all different cloc level node has. -- clock-cntl-support: Says whether clock control support is present or not -- clock-control: The valid fields are "NO_SET_RATE", "INIT_RATE" and - "SET_RATE". "NO_SET_RATE" the corresponding clock is enabled without setting - the rate assuming some other driver has already set it to appropriate rate. - "INIT_RATE" clock rate is not queried assuming some other driver has set - the clock rate and ispif will set the the clock to this rate. - "SET_RATE" clock is enabled and the rate is set to the value specified - in the property clock-rates. - -* Qualcomm Technologies, Inc. MSM ACTUATOR - -Required properties: -- cell-index : should contain unique identifier to differentiate - between multiple actuators -- reg : should contain i2c slave address of the actuator and length of - data field which is 0x0 -- compatible : - - "qcom,actuator" -- cci-master : should contain i2c master id to be used for this camera - sensor - - 0 -> MASTER 0 - - 1 -> MASTER 1 -Optional properties: -- regulator-names : should contain names of all regulators needed by this - actuator - - "cam_vaf" -- rgltr-cntrl-support : It is booloean property. This property is required - if the code and regulator control parameters e.g. rgltr-min-voltage -- rgltr-min-voltage : should contain minimum voltage level in mcrovolts - for regulators mentioned in regulator-names property (in the same order) -- rgltr-max-voltage : should contain maximum voltage level in mcrovolts - for regulators mentioned in regulator-names property (in the same order) -- rgltr-load-current : should contain the maximum current in microamps - required from the regulators mentioned in the regulator-names property - (in the same order). -- cam_vaf-supply : should contain regulator from which AF voltage is supplied - -* Qualcomm Technologies, Inc. MSM OIS - -Required properties: -- cell-index : should contain unique identifier to differentiate - between multiple ois drivers -- reg : should contain i2c slave address of the ois and length of - data field which is 0x0 -- compatible : - - "qcom,ois" -- cci-master : should contain i2c master id to be used for this camera - sensor - - 0 -> MASTER 0 - - 1 -> MASTER 1 -- clock-rates: clock rate in Hz. - -Optional properties: -- regulator-names : should contain names of all regulators needed by this - ois - - "cam_vaf" -- rgltr-cntrl-support : It is booloean property. This property is required - if the code and regulator control parameters e.g. rgltr-min-voltage -- rgltr-min-voltage : should contain minimum voltage level in mcrovolts - for regulators mentioned in regulator-names property (in the same order) -- rgltr-max-voltage : should contain maximum voltage level in mcrovolts - for regulators mentioned in regulator-names property (in the same order) -- rgltr-load-current : should contain the maximum current in microamps - required from the regulators mentioned in the regulator-names property - (in the same order). -- cam_vaf-supply : should contain regulator from which ois voltage is supplied -- use-shared-clk : It is booloean property. This property is required - if the clk is shared clk between different sensor and ois, if this - device need to be opened together. +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-res-mgr". -Example: +- shared-gpios + Usage: optional + Value type: + Definition: should contain the gpios which are used by two or more + cameras, and these cameras may be opened together. -led_flash0: qcom,camera-flash@0 { - cell-index = <0>; - compatible = "qcom,camera-flash"; - flash-source = <&pmi8994_flash0 &pmi8994_flash1>; - torch-source = <&pmi8998_torch0 &pmi8998_torch1>; - switch-source = <&pmi8998_switch>; - status = "ok"; -} - -qcom,cci@0xfda0c000 { - cell-index = <0>; - compatible = "qcom,cci"; - reg = <0xfda0c000 0x300>; - reg-names = "cci"; - interrupts = <0 50 0>; - interrupt-names = "cci"; - clock-names = "camnoc_axi_clk", "soc_ahb_clk", - "slow_ahb_src_clk", "cpas_ahb_clk", - "cci_clk", "cci_clk_src"; - clock-rates = <0 0 80000000 0 0 37500000>; - clock-cntl-level = "turbo"; - gpios = <&tlmm 17 0>, - <&tlmm 18 0>, - <&tlmm 19 0>, - <&tlmm 20 0>; - gpio-tbl-num = <0 1 2 3>; - gpio-tbl-flags = <1 1 1 1>; - gpio-tbl-label = "CCI_I2C_DATA0", - "CCI_I2C_CLK0", - "CCI_I2C_DATA1", - "CCI_I2C_CLK1"; - i2c_freq_100Khz: qcom,i2c_standard_mode { - hw-thigh = <78>; - hw-tlow = <114>; - hw-tsu-sto = <28>; - hw-tsu-sta = <28>; - hw-thd-dat = <10>; - hw-thd-sta = <77>; - hw-tbuf = <118>; - hw-scl-stretch-en = <0>; - hw-trdhld = <6>; - hw-tsp = <1>; - status = "ok"; - }; - i2c_freq_400Khz: qcom,i2c_fast_mode { - hw-thigh = <20>; - hw-tlow = <28>; - hw-tsu-sto = <21>; - hw-tsu-sta = <21>; - hw-thd-dat = <13>; - hw-thd-sta = <18>; - hw-tbuf = <25>; - hw-scl-stretch-en = <0>; - hw-trdhld = <6>; - hw-tsp = <3>; - status = "ok"; - }; - i2c_freq_custom: qcom,i2c_custom_mode { - hw-thigh = <15>; - hw-tlow = <28>; - hw-tsu-sto = <21>; - hw-tsu-sta = <21>; - hw-thd-dat = <13>; - hw-thd-sta = <18>; - hw-tbuf = <25>; - hw-scl-stretch-en = <1>; - hw-trdhld = <6>; - hw-tsp = <3>; - 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 = <19>; - hw-scl-stretch-en = <1>; - hw-trdhld = <3>; - hw-tsp = <3>; - cci-clk-src = <37500000>; +- pinctrl-names + Usage: optional + Value type: + Definition: List of names to assign the shared pin state defined in pinctrl device node + +- pinctrl-<0..n> + Usage: optional + Value type: + Definition: Lists phandles each pointing to the pin configuration node within a pin + controller. These pin configurations are installed in the pinctrl device node. + + +============================= +CAMERA IMAGE SENSOR MODULE +============================= +Image sensor node contains properties of camera image sensor + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-sensor". + +- cell-index: cci hardware core index + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the cci operating in + compatible mode. + +- cci-device + Usage: required + Value type: + Definition: should contain i2c device id to be used for this camera + sensor + +- cci-master + Usage: required + Value type: + Definition: should contain i2c master id to be used for this camera + sensor + - 0 -> MASTER 0 + - 1 -> MASTER 1 + +- csiphy-sd-index + Usage: required + Value type: + Definition: should contain csiphy instance that will used to + receive sensor data (0, 1, 2, 3). + +- cam_vdig-supply + Usage: required + Value type: + Definition: should contain regulator from which digital voltage is + supplied + +- cam_vana-supply + Usage: required + Value type: + Definition: should contain regulator from which analog voltage is + supplied + +- cam_vio-supply + Usage: required + Value type: + Definition: should contain regulator from which IO voltage is supplied + +- cam_bob-supply + Usage: optional + Value type: + Definition: should contain regulator from which BoB voltage is supplied + +- regulator-names + Usage: required + Value type: + Definition: should contain names of all regulators needed by this + sensor + +- rgltr-cntrl-support + Usage: required + Value type: + Definition: This property is required if the sw control regulator parameters + e.g. rgltr-min-voltage + +- rgltr-min-voltage + Usage: required + Value type: + Definition: should contain minimum voltage level for regulators mentioned + in regulator-names property (in the same order) + +- rgltr-max-voltage + Usage: required + Value type: + Definition: should contain maximum voltage level for regulators mentioned + in regulator-names property (in the same order) + +- rgltr-load-current + Usage: required + Value type: + Definition: should contain optimum voltage level for regulators mentioned + in regulator-names property (in the same order) + +- sensor-position-roll + Usage: required + Value type: + Definition: should contain sensor rotational angle with respect to axis of + reference. i.e. 0, 90, 180, 360 + +- sensor-position-pitch + Usage: required + Value type: + Definition: should contain sensor rotational angle with respect to axis of + reference. i.e. 0, 90, 180, 360 + +- sensor-position-yaw + Usage: required + Value type: + Definition: should contain sensor rotational angle with respect to axis of + reference. i.e. 0, 90, 180, 360 + +- qcom,secure + Usage: optional + Value type: + Definition: should be enabled to operate the camera in secure mode + +- gpio-no-mux + Usage: optional + Value type: + Definition: should contain field to indicate whether gpio mux table is + available. i.e. 1 if gpio mux is not available, 0 otherwise + +- cam_vaf-supply + Usage: optional + Value type: + Definition: should contain regulator from which AF voltage is supplied + +- pwm-switch + Usage: optional + Value type: + Definition: This property is required for regulator to switch into PWM mode. + +- gpios + Usage: required + Value type: + Definition: should contain phandle to gpio controller node and array of + #gpio-cells specifying specific gpio (controller specific) + +- gpio-reset + Usage: required + Value type: + Definition: should contain index to gpio used by sensors reset_n + +- gpio-standby + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors standby_n + +- gpio-vio + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors io vreg enable + +- gpio-vana + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors analog vreg enable + +- gpio-vdig + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors digital vreg enable + +- gpio-vaf + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors af vreg enable + +- gpio-af-pwdm + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors af pwdm_n + +- gpio-req-tbl-num + Usage: optional + Value type: + Definition: should contain index to gpios specific to this sensor + +- gpio-req-tbl-flags + Usage: optional + Value type: + Definition: should contain direction of gpios present in + gpio-req-tbl-num property (in the same order) + +- gpio-req-tbl-label + Usage: optional + Value type: + Definition: should contain name of gpios present in + gpio-req-tbl-num property (in the same order) + +- gpio-set-tbl-num + Usage: optional + Value type: + Definition: should contain index of gpios that need to be + configured by msm + +- gpio-set-tbl-flags + Usage: optional + Value type: + Definition: should contain value to be configured for the gpios + present in gpio-set-tbl-num property (in the same order) + +- gpio-set-tbl-delay + Usage: optional + Value type: + Definition: should contain amount of delay after configuring + gpios as specified in gpio_set_tbl_flags property (in the same order) + +- actuator-src + Usage: optional + Value type: + Definition: if auto focus is supported by this sensor, this + property should contain phandle of respective actuator node + +- led-flash-src + Usage: optional + Value type: + Definition: if LED flash is supported by this sensor, this + property should contain phandle of respective LED flash node + +- qcom,vdd-cx-supply + Usage: optional + Value type: + Definition: should contain regulator from which cx voltage is supplied + +- qcom,vdd-cx-name + Usage: optional + Value type: + Definition: should contain names of cx regulator + +- eeprom-src + Usage: optional + Value type: + Definition: if eeprom memory is supported by this sensor, this + property should contain phandle of respective eeprom nodes + +- ois-src + Usage: optional + Value type: + Definition: if optical image stabilization is supported by this sensor, + this property should contain phandle of respective ois node + +- ir-led-src + Usage: optional + Value type: + Definition: if ir led is supported by this sensor, this property + should contain phandle of respective ir-led node + +- qcom,ir-cut-src + Usage: optional + Value type: + Definition: if ir cut is supported by this sensor, this property + should contain phandle of respective ir-cut node + +- qcom,special-support-sensors + Usage: required + Value type: + Definition: if only some special sensors are supported + on this board, add sensor name in this property. + +- use-shared-clk + Usage: optional + Value type: + Definition: It is booloean property. This property is required + if the clk is shared clk between different sensor and ois, if this + device need to be opened together. + +- clock-rates + Usage: required + Value type: + Definition: clock rate in Hz. + +- clock-cntl-level + Usage: required + Value type: + Definition: All different clock level node can support. + +- clock-cntl-support + Usage: optional + Value type: + Definition: Says whether clock control support is present or not + +- clocks + Usage: required + Value type: + Definition: all clock phandle and source clocks. + +- clock-control + Usage: optional + Value type: + Definition: The valid fields are "NO_SET_RATE", "INIT_RATE" and + "SET_RATE". "NO_SET_RATE" the corresponding clock is enabled without setting + the rate assuming some other driver has already set it to appropriate rate. + "INIT_RATE" clock rate is not queried assuming some other driver has set + the clock rate and ispif will set the the clock to this rate. + "SET_RATE" clock is enabled and the rate is set to the value specified + in the property clock-rates. + +============================= +ACTUATOR MODULE +============================= + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,actuator". + +- cell-index: cci hardware core index + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the cci operating in + compatible mode. + +- cci-device + Usage: required + Value type: + Definition: should contain i2c device id to be used for this camera + sensor + +- cci-master + Usage: required + Value type: + Definition: should contain i2c master id to be used for this camera + sensor + - 0 -> MASTER 0 + - 1 -> MASTER 1 + +- cam_vaf-supply + Usage: required + Value type: + Definition: should contain regulator from which AF voltage is supplied + +- regulator-names + Usage: required + Value type: + Definition: should contain names of all regulators needed by this + actuator. i.e. "cam_vaf" + +- rgltr-cntrl-support + Usage: optional + Value type: + Definition: It is booloean property. This property is required + if the code and regulator control parameters e.g. rgltr-min-voltage + +- rgltr-min-voltage + Usage: optional + Value type: + Definition: should contain minimum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) + +- rgltr-max-voltage + Usage: optional + Value type: + Definition: should contain maximum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) + +- rgltr-load-current + Usage: optional + Value type: + Definition: should contain the maximum current in microamps + required from the regulators mentioned in the regulator-names property + (in the same order). + +============================= +OIS MODULE +============================= + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,ois". + +- cell-index: cci hardware core index + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the cci operating in + compatible mode. + +- cci-device + Usage: required + Value type: + Definition: should contain i2c device id to be used for this camera + sensor + +- cci-master + Usage: required + Value type: + Definition: should contain i2c master id to be used for this camera + sensor + - 0 -> MASTER 0 + - 1 -> MASTER 1 + +- cam_vaf-supply + Usage: required + Value type: + Definition: should contain regulator from which AF voltage is supplied + +- regulator-names + Usage: required + Value type: + Definition: should contain names of all regulators needed by this + actuator. i.e. "cam_vaf" + +- rgltr-cntrl-support + Usage: optional + Value type: + Definition: It is booloean property. This property is required + if the code and regulator control parameters e.g. rgltr-min-voltage + +- rgltr-min-voltage + Usage: optional + Value type: + Definition: should contain minimum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) + +- rgltr-max-voltage + Usage: optional + Value type: + Definition: should contain maximum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) + +- rgltr-load-current + Usage: optional + Value type: + Definition: should contain the maximum current in microamps + required from the regulators mentioned in the regulator-names property + (in the same order). + +- use-shared-clk + Usage: optional + Value type: + Definition: This property is required if the clk is shared clk between different + sensor and ois, if this device need to be opened together. + +Example: +&soc { + led_flash0: qcom,camera-flash@0 { + cell-index = <0>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8994_flash0 &pmi8994_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch>; status = "ok"; }; +}; +&cam_cci0 { actuator0: qcom,actuator@0 { cell-index = <0>; reg = <0x0>; compatible = "qcom,actuator"; + cci-device = <0>; cci-master = <0>; cam_vaf-supply = <&pmi8998_bob>; regulator-names = "cam_vaf"; - rgltr-cntrl-support; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + }; + + ois0: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + cci-device = <0>; + cci-master = <0>; + cam_vaf-supply = <&pmi8998_bob>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; rgltr-min-voltage = <2800000>; rgltr-max-voltage = <2800000>; rgltr-load-current = <100000>; @@ -375,15 +772,20 @@ qcom,cci@0xfda0c000 { secure = <1>; led-flash-src = <&led_flash0>; actuator-src = <&actuator0>; + ois-src = <&ois0>; eeprom-src = <&eeprom0>; - cam_vdig-supply = <&pm845_s3>; - cam_vio-supply = <&pm845_lvs1>; - cam_vana-supply = <&pmi8998_bob>; - regulator-names = "cam_vdig", "cam_vio", "cam_vana"; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009l_l1>; + cam_vana-supply = <&pm8009l_l5>; + cam_bob-supply = <&pm8150l_bob>; + cam_clk-supply = <&tital_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; rgltr-cntrl-support; - rgltr-min-voltage = <0 3312000 1352000>; - rgltr-max-voltage = <0 3312000 1352000>; - rgltr-load-current = <0 80000 105000>; + pwm-switch; + rgltr-min-voltage = <0 2800000 1200000 0 3008000>; + rgltr-max-voltage = <0 2800000 1200000 0 4000000>; + rgltr-load-current = <0 80000 1200000 0 2000000>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active @@ -402,12 +804,14 @@ qcom,cci@0xfda0c000 { "CAM_VANA"; sensor-position = <0>; sensor-mode = <0>; + cci-device = <0>; cci-master = <0>; status = "ok"; use-shared-clk; clocks = <&clock_mmss clk_mclk0_clk_src>, <&clock_mmss clk_camss_mclk0_clk>; clock-names = "cam_src_clk", "cam_clk"; - clock-cntl-level; + clock-cntl-leveli = "turbo"; + clock-rates = <24000000>; }; }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c index 6fe051aa048c..223aba42372f 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -17,7 +17,6 @@ #include "cam_soc_util.h" #include "cam_trace.h" - static void cam_sensor_update_req_mgr( struct cam_sensor_ctrl_t *s_ctrl, struct cam_packet *csl_packet) @@ -962,6 +961,16 @@ int cam_sensor_power_up(struct cam_sensor_ctrl_t *s_ctrl) return -EINVAL; } + if (s_ctrl->bob_pwm_switch) { + rc = cam_sensor_bob_pwm_mode_switch(soc_info, + s_ctrl->bob_reg_index, true); + if (rc) { + CAM_WARN(CAM_SENSOR, + "BoB PWM setup failed rc: %d", rc); + rc = 0; + } + } + rc = cam_sensor_core_power_up(power_info, soc_info); if (rc < 0) { CAM_ERR(CAM_SENSOR, "power up the core is failed:%d", rc); @@ -999,6 +1008,16 @@ int cam_sensor_power_down(struct cam_sensor_ctrl_t *s_ctrl) return rc; } + if (s_ctrl->bob_pwm_switch) { + rc = cam_sensor_bob_pwm_mode_switch(soc_info, + s_ctrl->bob_reg_index, false); + if (rc) { + CAM_WARN(CAM_SENSOR, + "BoB PWM setup failed rc: %d", rc); + rc = 0; + } + } + camera_io_release(&(s_ctrl->io_master_info)); return rc; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h index cc6070cdc1b6..34f8b8dba696 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h @@ -92,6 +92,8 @@ struct intf_params { * @device_name: Sensor device structure * @streamon_count: Count to hold the number of times stream on called * @streamoff_count: Count to hold the number of times stream off called + * @bob_reg_index: Hold to BoB regulator index + * @bob_pwm_switch: Boolean flag to switch into PWM mode for BoB regulator */ struct cam_sensor_ctrl_t { struct platform_device *pdev; @@ -113,6 +115,8 @@ struct cam_sensor_ctrl_t { char device_name[20]; uint32_t streamon_count; uint32_t streamoff_count; + int bob_reg_index; + bool bob_pwm_switch; }; #endif /* _CAM_SENSOR_DEV_H_ */ diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c index 1c3ead0c25bf..e997419359c5 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.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 @@ -104,6 +104,7 @@ int32_t cam_sensor_get_sub_module_index(struct device_node *of_node, static int32_t cam_sensor_driver_get_dt_data(struct cam_sensor_ctrl_t *s_ctrl) { int32_t rc = 0; + int i = 0; struct cam_sensor_board_info *sensordata = NULL; struct device_node *of_node = s_ctrl->of_node; struct cam_hw_soc_info *soc_info = &s_ctrl->soc_info; @@ -135,6 +136,33 @@ static int32_t cam_sensor_driver_get_dt_data(struct cam_sensor_ctrl_t *s_ctrl) goto FREE_SENSOR_DATA; } + /* Store the index of BoB regulator if it is available */ + for (i = 0; i < soc_info->num_rgltr; i++) { + if (!strcmp(soc_info->rgltr_name[i], + "cam_bob")) { + CAM_DBG(CAM_SENSOR, + "i: %d cam_bob", i); + s_ctrl->bob_reg_index = i; + soc_info->rgltr[i] = devm_regulator_get(soc_info->dev, + soc_info->rgltr_name[i]); + if (IS_ERR_OR_NULL(soc_info->rgltr[i])) { + CAM_WARN(CAM_SENSOR, + "Regulator: %s get failed", + soc_info->rgltr_name[i]); + soc_info->rgltr[i] = NULL; + } else { + if (!of_property_read_bool(of_node, + "pwm-switch")) { + CAM_DBG(CAM_SENSOR, + "No BoB PWM switch param defined"); + s_ctrl->bob_pwm_switch = false; + } else { + s_ctrl->bob_pwm_switch = true; + } + } + } + } + /* Read subdev info */ rc = cam_sensor_get_sub_module_index(of_node, sensordata); if (rc < 0) { diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index 73a0cf71071e..498112e4236f 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -1218,6 +1218,24 @@ int msm_camera_pinctrl_init( return 0; } +int cam_sensor_bob_pwm_mode_switch(struct cam_hw_soc_info *soc_info, + int bob_reg_idx, bool flag) +{ + int rc = 0; + uint32_t op_current = + (flag == true) ? soc_info->rgltr_op_mode[bob_reg_idx] : 0; + + if (soc_info->rgltr[bob_reg_idx] != NULL) { + rc = regulator_set_load(soc_info->rgltr[bob_reg_idx], + op_current); + if (rc) + CAM_WARN(CAM_SENSOR, + "BoB PWM SetLoad failed rc: %d", rc); + } + + return rc; +} + int msm_cam_sensor_handle_reg_gpio(int seq_type, struct msm_camera_gpio_num_info *gpio_num_info, int val) { diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h index c9ccc5c0cd7c..6c0287e48487 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h @@ -58,4 +58,7 @@ int msm_camera_fill_vreg_params(struct cam_hw_soc_info *soc_info, int32_t cam_sensor_update_power_settings(void *cmd_buf, int cmd_length, struct cam_sensor_power_ctrl_t *power_info); + +int cam_sensor_bob_pwm_mode_switch(struct cam_hw_soc_info *soc_info, + int bob_reg_idx, bool flag); #endif /* _CAM_SENSOR_UTIL_H_ */ -- GitLab From fdcd472bc44372acb6e46fc83e131910d297d05d Mon Sep 17 00:00:00 2001 From: Junzhe Zou Date: Mon, 11 Jun 2018 18:05:33 -0700 Subject: [PATCH 200/604] msm: camera: isp: improve flush logic to prevent race condition Race condition can happen if flush is called when there is a request applied and waits for regupd. Add the request to wait list after apply to track it correctly. Also remove flush state to let context to get notified by regupd after flush is called. Change-Id: Ib9c5a4b9e7a103d05fb023b442df76d4d3f30cac Signed-off-by: Junzhe Zou --- .../msm/camera/cam_isp/cam_isp_context.c | 96 +++---------------- .../msm/camera/cam_isp/cam_isp_context.h | 3 - 2 files changed, 11 insertions(+), 88 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 7b02aac2ad0a..f6fe85071300 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 @@ -524,11 +524,11 @@ static int __cam_isp_ctx_reg_upd_in_activated_state( struct cam_context *ctx = ctx_isp->base; struct cam_isp_ctx_req *req_isp; - if (list_empty(&ctx->pending_req_list)) { - CAM_ERR(CAM_ISP, "Reg upd ack with no pending request"); + if (list_empty(&ctx->wait_req_list)) { + CAM_ERR(CAM_ISP, "Reg upd ack with no waiting request"); goto end; } - req = list_first_entry(&ctx->pending_req_list, + req = list_first_entry(&ctx->wait_req_list, struct cam_ctx_request, list); list_del_init(&req->list); @@ -1078,30 +1078,6 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, return rc; } -static int __cam_isp_ctx_sof_in_flush( - struct cam_isp_context *ctx_isp, void *evt_data) -{ - int rc = 0; - struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; - - if (!evt_data) { - CAM_ERR(CAM_ISP, "in valid sof event data"); - return -EINVAL; - } - ctx_isp->frame_id++; - ctx_isp->sof_timestamp_val = sof_event_data->timestamp; - ctx_isp->boot_timestamp = sof_event_data->boot_time; - CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", - ctx_isp->frame_id, ctx_isp->sof_timestamp_val); - - if (--ctx_isp->frame_skip_count == 0) - ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; - else - CAM_ERR(CAM_ISP, "Skip currect SOF"); - - return rc; -} - static struct cam_isp_ctx_irq_ops cam_isp_ctx_activated_state_machine_irq[CAM_ISP_CTX_ACTIVATED_MAX] = { /* SOF */ @@ -1173,17 +1149,6 @@ static struct cam_isp_ctx_irq_ops /* HALT */ { }, - /* FLUSH */ - { - .irq_ops = { - NULL, - __cam_isp_ctx_sof_in_flush, - NULL, - NULL, - NULL, - __cam_isp_ctx_buf_done_in_applied, - }, - }, }; static int __cam_isp_ctx_apply_req_in_activated_state( @@ -1265,6 +1230,8 @@ static int __cam_isp_ctx_apply_req_in_activated_state( spin_lock_bh(&ctx->lock); ctx_isp->substate_activated = next_state; ctx_isp->last_applied_req_id = apply->request_id; + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->wait_req_list); CAM_DBG(CAM_ISP, "new substate state %d, applied req %lld", next_state, ctx_isp->last_applied_req_id); spin_unlock_bh(&ctx->lock); @@ -1339,7 +1306,11 @@ static int __cam_isp_ctx_flush_req(struct cam_context *ctx, INIT_LIST_HEAD(&flush_list); if (list_empty(req_list)) { CAM_DBG(CAM_ISP, "request list is empty"); - return 0; + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { + CAM_ERR(CAM_ISP, "no request to cancel"); + return -EINVAL; + } else + return 0; } list_for_each_entry_safe(req, req_temp, req_list, list) { @@ -1402,28 +1373,6 @@ static int __cam_isp_ctx_flush_req_in_top_state( return rc; } -static int __cam_isp_ctx_flush_req_in_activated( - struct cam_context *ctx, - struct cam_req_mgr_flush_request *flush_req) -{ - int rc = 0; - struct cam_isp_context *ctx_isp; - - ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; - - CAM_DBG(CAM_ISP, "Flush request in state %d", ctx->state); - rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); - - /* only if request is found in pending queue, move to flush state*/ - if (!rc) { - spin_lock_bh(&ctx->lock); - ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_FLUSH; - ctx_isp->frame_skip_count = 2; - spin_unlock_bh(&ctx->lock); - } - return rc; -} - static int __cam_isp_ctx_flush_req_in_ready( struct cam_context *ctx, struct cam_req_mgr_flush_request *flush_req) @@ -1496,12 +1445,6 @@ static struct cam_ctx_ops .crm_ops = {}, .irq_ops = NULL, }, - /* FLUSH */ - { - .ioctl_ops = {}, - .crm_ops = {}, - .irq_ops = NULL, - }, }; static int __cam_isp_ctx_rdi_only_sof_in_top_state( @@ -1886,17 +1829,6 @@ static struct cam_isp_ctx_irq_ops /* HALT */ { }, - /* FLUSH */ - { - .irq_ops = { - NULL, - __cam_isp_ctx_sof_in_flush, - NULL, - NULL, - NULL, - __cam_isp_ctx_buf_done_in_applied, - }, - }, }; static int __cam_isp_ctx_rdi_only_apply_req_top_state( @@ -1964,12 +1896,6 @@ static struct cam_ctx_ops .crm_ops = {}, .irq_ops = NULL, }, - /* FLUSHED */ - { - .ioctl_ops = {}, - .crm_ops = {}, - .irq_ops = NULL, - }, }; /* top level state machine */ @@ -2715,7 +2641,7 @@ static struct cam_ctx_ops .crm_ops = { .unlink = __cam_isp_ctx_unlink_in_activated, .apply_req = __cam_isp_ctx_apply_req, - .flush_req = __cam_isp_ctx_flush_req_in_activated, + .flush_req = __cam_isp_ctx_flush_req_in_top_state, .process_evt = __cam_isp_ctx_process_evt, }, .irq_ops = __cam_isp_ctx_handle_irq_in_activated, diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h index a939f2d80b34..4592e42932d8 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h @@ -57,7 +57,6 @@ enum cam_isp_ctx_activated_substate { CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED, CAM_ISP_CTX_ACTIVATED_HW_ERROR, CAM_ISP_CTX_ACTIVATED_HALT, - CAM_ISP_CTX_ACTIVATED_FLUSH, CAM_ISP_CTX_ACTIVATED_MAX, }; @@ -155,7 +154,6 @@ struct cam_isp_context_state_monitor { * @subscribe_event: The irq event mask that CRM subscribes to, IFE * will invoke CRM cb at those event. * @last_applied_req_id: Last applied request id - * @frame_skip_count: Number of frame to skip before change state * @state_monitor_head: Write index to the state monitoring array * @cam_isp_ctx_state_monitor: State monitoring array * @rdi_only_context: Get context type information. @@ -180,7 +178,6 @@ struct cam_isp_context { int64_t reported_req_id; uint32_t subscribe_event; int64_t last_applied_req_id; - uint32_t frame_skip_count; atomic64_t state_monitor_head; struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[ CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES]; -- GitLab From 5b52f25d38dab7d4790dbaeae8f76170f1c3bb63 Mon Sep 17 00:00:00 2001 From: Alok Pandey Date: Fri, 1 Jun 2018 15:19:24 +0530 Subject: [PATCH 201/604] msm: camera: icp: removes reference input depedency Removed reference input buffer dependency for a request to submit to firmware. Due to this dependency in KMD, any request is submitted to firmware only after previous request is done. This impacts the performance for high frame rate use cases. Change-Id: Iefd3dcbc141b93d27eac34ca4fe6899b8fca8c61 Signed-off-by: Alok Pandey --- .../cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 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 c73c25fef428..8248adf841ea 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 @@ -3340,6 +3340,15 @@ static int cam_icp_mgr_process_cmd_desc(struct cam_icp_hw_mgr *hw_mgr, return rc; } +static bool cam_icp_mgr_is_input_reference_buffer(uint32_t resource_type) +{ + if (resource_type == CAM_ICP_IPE_INPUT_IMAGE_FULL_REF || + resource_type == CAM_ICP_IPE_INPUT_IMAGE_DS4_REF || + resource_type == CAM_ICP_IPE_INPUT_IMAGE_DS16_REF) + return true; + else + return false; +} static int cam_icp_mgr_process_io_cfg(struct cam_icp_hw_mgr *hw_mgr, struct cam_icp_hw_ctx_data *ctx_data, @@ -3359,6 +3368,9 @@ static int cam_icp_mgr_process_io_cfg(struct cam_icp_hw_mgr *hw_mgr, for (i = 0, j = 0, k = 0; i < packet->num_io_configs; i++) { if (io_cfg_ptr[i].direction == CAM_BUF_INPUT) { + if (cam_icp_mgr_is_input_reference_buffer( + io_cfg_ptr[i].resource_type)) + continue; sync_in_obj[j++] = io_cfg_ptr[i].fence; prepare_args->num_in_map_entries++; } else { @@ -3366,8 +3378,9 @@ static int cam_icp_mgr_process_io_cfg(struct cam_icp_hw_mgr *hw_mgr, io_cfg_ptr[i].fence; prepare_args->num_out_map_entries++; } - CAM_DBG(CAM_ICP, "dir[%d]: %u, fence: %u", - i, io_cfg_ptr[i].direction, io_cfg_ptr[i].fence); + CAM_DBG(CAM_ICP, "dir[%d]: %u, fence: %u resource_type = %u", + i, io_cfg_ptr[i].direction, io_cfg_ptr[i].fence, + io_cfg_ptr[i].resource_type); } if (prepare_args->num_in_map_entries > 1) { -- GitLab From 8c0b21557a25cb7353c7dc5e030c34ae8ffd8170 Mon Sep 17 00:00:00 2001 From: Blagovest Kolenichev Date: Wed, 20 Jun 2018 04:58:16 -0700 Subject: [PATCH 202/604] Revert "scsi: ufs: Factor out ufshcd_read_desc_param" This reverts commit e1928457073c996ffc681be2b6f9576706fbcf8d. Equivalent code delta is already presented on msm-4.9 as part of commit [1]. Motivation to revert the change is because it is causing merge conflicts on importing android-4.9.107 (42a730a) into msm-4.9, hence let's remove it before the merge. [1] 833ea2a scsi: ufs: Factor out ufshcd_read_desc_param Change-Id: I584d0de65c687f97cf69f75c68613bb15d89d21d [bkolenichev@codeaurora.org: resolve trivial conflict] Signed-off-by: Blagovest Kolenichev --- drivers/scsi/ufs/ufs.h | 22 ++-- drivers/scsi/ufs/ufshcd.c | 231 ++++++++++---------------------------- drivers/scsi/ufs/ufshcd.h | 17 --- 3 files changed, 72 insertions(+), 198 deletions(-) diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 5bb2316f60bf..377ba30c2258 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -145,7 +145,7 @@ enum attr_idn { /* Descriptor idn for Query requests */ enum desc_idn { QUERY_DESC_IDN_DEVICE = 0x0, - QUERY_DESC_IDN_CONFIGURATION = 0x1, + QUERY_DESC_IDN_CONFIGURAION = 0x1, QUERY_DESC_IDN_UNIT = 0x2, QUERY_DESC_IDN_RFU_0 = 0x3, QUERY_DESC_IDN_INTERCONNECT = 0x4, @@ -161,13 +161,19 @@ enum desc_header_offset { QUERY_DESC_DESC_TYPE_OFFSET = 0x01, }; -enum ufs_desc_def_size { - QUERY_DESC_DEVICE_DEF_SIZE = 0x40, - QUERY_DESC_CONFIGURATION_DEF_SIZE = 0x90, - QUERY_DESC_UNIT_DEF_SIZE = 0x23, - QUERY_DESC_INTERCONNECT_DEF_SIZE = 0x06, - QUERY_DESC_GEOMETRY_DEF_SIZE = 0x44, - QUERY_DESC_POWER_DEF_SIZE = 0x62, +enum ufs_desc_max_size { + QUERY_DESC_DEVICE_MAX_SIZE = 0x1F, + QUERY_DESC_CONFIGURAION_MAX_SIZE = 0x90, + QUERY_DESC_UNIT_MAX_SIZE = 0x23, + QUERY_DESC_INTERCONNECT_MAX_SIZE = 0x06, + /* + * Max. 126 UNICODE characters (2 bytes per character) plus 2 bytes + * of descriptor header. + */ + QUERY_DESC_STRING_MAX_SIZE = 0xFE, + QUERY_DESC_GEOMETRY_MAX_SIZE = 0x44, + QUERY_DESC_POWER_MAX_SIZE = 0x62, + QUERY_DESC_RFU_MAX_SIZE = 0x00, }; /* Unit descriptor parameters offsets in bytes*/ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index f53f84fd9cbb..d4484c78e563 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -99,6 +99,19 @@ _ret; \ }) +static u32 ufs_query_desc_max_size[] = { + QUERY_DESC_DEVICE_MAX_SIZE, + QUERY_DESC_CONFIGURAION_MAX_SIZE, + QUERY_DESC_UNIT_MAX_SIZE, + QUERY_DESC_RFU_MAX_SIZE, + QUERY_DESC_INTERCONNECT_MAX_SIZE, + QUERY_DESC_STRING_MAX_SIZE, + QUERY_DESC_RFU_MAX_SIZE, + QUERY_DESC_GEOMETRY_MAX_SIZE, + QUERY_DESC_POWER_MAX_SIZE, + QUERY_DESC_RFU_MAX_SIZE, +}; + enum { UFSHCD_MAX_CHANNEL = 0, UFSHCD_MAX_ID = 1, @@ -1960,7 +1973,7 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba, goto out; } - if (*buf_len < QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) { + if (*buf_len <= QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) { dev_err(hba->dev, "%s: descriptor buffer size (%d) is out of range\n", __func__, *buf_len); err = -EINVAL; @@ -2039,92 +2052,6 @@ int ufshcd_query_descriptor_retry(struct ufs_hba *hba, } EXPORT_SYMBOL(ufshcd_query_descriptor_retry); -/** - * ufshcd_read_desc_length - read the specified descriptor length from header - * @hba: Pointer to adapter instance - * @desc_id: descriptor idn value - * @desc_index: descriptor index - * @desc_length: pointer to variable to read the length of descriptor - * - * Return 0 in case of success, non-zero otherwise - */ -static int ufshcd_read_desc_length(struct ufs_hba *hba, - enum desc_idn desc_id, - int desc_index, - int *desc_length) -{ - int ret; - u8 header[QUERY_DESC_HDR_SIZE]; - int header_len = QUERY_DESC_HDR_SIZE; - - if (desc_id >= QUERY_DESC_IDN_MAX) - return -EINVAL; - - ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, - desc_id, desc_index, 0, header, - &header_len); - - if (ret) { - dev_err(hba->dev, "%s: Failed to get descriptor header id %d", - __func__, desc_id); - return ret; - } else if (desc_id != header[QUERY_DESC_DESC_TYPE_OFFSET]) { - dev_warn(hba->dev, "%s: descriptor header id %d and desc_id %d mismatch", - __func__, header[QUERY_DESC_DESC_TYPE_OFFSET], - desc_id); - ret = -EINVAL; - } - - *desc_length = header[QUERY_DESC_LENGTH_OFFSET]; - return ret; - -} - -/** - * ufshcd_map_desc_id_to_length - map descriptor IDN to its length - * @hba: Pointer to adapter instance - * @desc_id: descriptor idn value - * @desc_len: mapped desc length (out) - * - * Return 0 in case of success, non-zero otherwise - */ -int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, - enum desc_idn desc_id, int *desc_len) -{ - switch (desc_id) { - case QUERY_DESC_IDN_DEVICE: - *desc_len = hba->desc_size.dev_desc; - break; - case QUERY_DESC_IDN_POWER: - *desc_len = hba->desc_size.pwr_desc; - break; - case QUERY_DESC_IDN_GEOMETRY: - *desc_len = hba->desc_size.geom_desc; - break; - case QUERY_DESC_IDN_CONFIGURATION: - *desc_len = hba->desc_size.conf_desc; - break; - case QUERY_DESC_IDN_UNIT: - *desc_len = hba->desc_size.unit_desc; - break; - case QUERY_DESC_IDN_INTERCONNECT: - *desc_len = hba->desc_size.interc_desc; - break; - case QUERY_DESC_IDN_STRING: - *desc_len = QUERY_DESC_MAX_SIZE; - break; - case QUERY_DESC_IDN_RFU_0: - case QUERY_DESC_IDN_RFU_1: - *desc_len = 0; - break; - default: - *desc_len = 0; - return -EINVAL; - } - return 0; -} -EXPORT_SYMBOL(ufshcd_map_desc_id_to_length); - /** * ufshcd_read_desc_param - read the specified descriptor parameter * @hba: Pointer to adapter instance @@ -2139,49 +2066,42 @@ EXPORT_SYMBOL(ufshcd_map_desc_id_to_length); static int ufshcd_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id, int desc_index, - u8 param_offset, + u32 param_offset, u8 *param_read_buf, - u8 param_size) + u32 param_size) { int ret; u8 *desc_buf; - int buff_len; + u32 buff_len; bool is_kmalloc = true; - /* Safety check */ - if (desc_id >= QUERY_DESC_IDN_MAX || !param_size) + /* safety checks */ + if (desc_id >= QUERY_DESC_IDN_MAX) return -EINVAL; - /* Get the max length of descriptor from structure filled up at probe - * time. - */ - ret = ufshcd_map_desc_id_to_length(hba, desc_id, &buff_len); - - /* Sanity checks */ - if (ret || !buff_len) { - dev_err(hba->dev, "%s: Failed to get full descriptor length", - __func__); - return ret; - } + buff_len = ufs_query_desc_max_size[desc_id]; + if ((param_offset + param_size) > buff_len) + return -EINVAL; - /* Check whether we need temp memory */ - if (param_offset != 0 || param_size < buff_len) { + if (!param_offset && (param_size == buff_len)) { + /* memory space already available to hold full descriptor */ + desc_buf = param_read_buf; + is_kmalloc = false; + } else { + /* allocate memory to hold full descriptor */ desc_buf = kmalloc(buff_len, GFP_KERNEL); if (!desc_buf) return -ENOMEM; - } else { - desc_buf = param_read_buf; - is_kmalloc = false; } - /* Request for full descriptor */ ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, - desc_id, desc_index, 0, - desc_buf, &buff_len); + desc_id, desc_index, 0, desc_buf, + &buff_len); if (ret) { dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d", __func__, desc_id, desc_index, param_offset, ret); + goto out; } @@ -2193,9 +2113,25 @@ static int ufshcd_read_desc_param(struct ufs_hba *hba, goto out; } - /* Check wherher we will not copy more data, than available */ - if (is_kmalloc && param_size > buff_len) - param_size = buff_len; + /* + * While reading variable size descriptors (like string descriptor), + * some UFS devices may report the "LENGTH" (field in "Transaction + * Specific fields" of Query Response UPIU) same as what was requested + * in Query Request UPIU instead of reporting the actual size of the + * variable size descriptor. + * Although it's safe to ignore the "LENGTH" field for variable size + * descriptors as we can always derive the length of the descriptor from + * the descriptor header fields. Hence this change impose the length + * match check only for fixed size descriptors (for which we always + * request the correct size as part of Query Request UPIU). + */ + if ((desc_id != QUERY_DESC_IDN_STRING) && + (buff_len != desc_buf[QUERY_DESC_LENGTH_OFFSET])) { + dev_err(hba->dev, "%s: desc_buf length mismatch: buff_len %d, buff_len(desc_header) %d", + __func__, buff_len, desc_buf[QUERY_DESC_LENGTH_OFFSET]); + ret = -EINVAL; + goto out; + } if (is_kmalloc) memcpy(param_read_buf, &desc_buf[param_offset], param_size); @@ -4905,8 +4841,8 @@ static u32 ufshcd_find_max_sup_active_icc_level(struct ufs_hba *hba, static void ufshcd_init_icc_levels(struct ufs_hba *hba) { int ret; - int buff_len = hba->desc_size.pwr_desc; - u8 desc_buf[hba->desc_size.pwr_desc]; + int buff_len = QUERY_DESC_POWER_MAX_SIZE; + u8 desc_buf[QUERY_DESC_POWER_MAX_SIZE]; ret = ufshcd_read_power_desc(hba, desc_buf, buff_len); if (ret) { @@ -5004,10 +4940,11 @@ static int ufs_get_device_desc(struct ufs_hba *hba, { int err; u8 model_index; - u8 str_desc_buf[QUERY_DESC_MAX_SIZE + 1] = {0}; - u8 desc_buf[hba->desc_size.dev_desc]; + u8 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE + 1] = {0}; + u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE]; - err = ufshcd_read_device_desc(hba, desc_buf, hba->desc_size.dev_desc); + err = ufshcd_read_device_desc(hba, desc_buf, + QUERY_DESC_DEVICE_MAX_SIZE); if (err) { dev_err(hba->dev, "%s: Failed reading Device Desc. err = %d\n", __func__, err); @@ -5024,14 +4961,14 @@ static int ufs_get_device_desc(struct ufs_hba *hba, model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; err = ufshcd_read_string_desc(hba, model_index, str_desc_buf, - QUERY_DESC_MAX_SIZE, ASCII_STD); + QUERY_DESC_STRING_MAX_SIZE, ASCII_STD); if (err) { dev_err(hba->dev, "%s: Failed reading Product Name. err = %d\n", __func__, err); goto out; } - str_desc_buf[QUERY_DESC_MAX_SIZE] = '\0'; + str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0'; strlcpy(dev_desc->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET], MAX_MODEL_LEN)); @@ -5221,51 +5158,6 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) ufshcd_vops_apply_dev_quirks(hba); } -static void ufshcd_init_desc_sizes(struct ufs_hba *hba) -{ - int err; - - err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_DEVICE, 0, - &hba->desc_size.dev_desc); - if (err) - hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE; - - err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_POWER, 0, - &hba->desc_size.pwr_desc); - if (err) - hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE; - - err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_INTERCONNECT, 0, - &hba->desc_size.interc_desc); - if (err) - hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE; - - err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_CONFIGURATION, 0, - &hba->desc_size.conf_desc); - if (err) - hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE; - - err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_UNIT, 0, - &hba->desc_size.unit_desc); - if (err) - hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE; - - err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_GEOMETRY, 0, - &hba->desc_size.geom_desc); - if (err) - hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; -} - -static void ufshcd_def_desc_sizes(struct ufs_hba *hba) -{ - hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE; - hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE; - hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE; - hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE; - hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE; - hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; -} - /** * ufshcd_probe_hba - probe hba to detect device and initialize * @hba: per-adapter instance @@ -5298,9 +5190,6 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) if (ret) goto out; - /* Init check for device descriptor sizes */ - ufshcd_init_desc_sizes(hba); - ret = ufs_get_device_desc(hba, &card); if (ret) { dev_err(hba->dev, "%s: Failed getting device info. err = %d\n", @@ -5334,7 +5223,6 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) /* set the state as operational after switching to desired gear */ hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; - /* * If we are in error handling context or in power management callbacks * context, no need to scan the host @@ -6767,9 +6655,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) hba->mmio_base = mmio_base; hba->irq = irq; - /* Set descriptor lengths to specification defaults */ - ufshcd_def_desc_sizes(hba); - err = ufshcd_hba_init(hba); if (err) goto out_error; diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 096e6673f29b..b35a5b999412 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -205,15 +205,6 @@ struct ufs_dev_cmd { struct ufs_query query; }; -struct ufs_desc_size { - int dev_desc; - int pwr_desc; - int geom_desc; - int interc_desc; - int unit_desc; - int conf_desc; -}; - /** * struct ufs_clk_info - UFS clock related info * @list: list headed by hba->clk_list_head @@ -397,7 +388,6 @@ struct ufs_init_prefetch { * @clk_list_head: UFS host controller clocks list node head * @pwr_info: holds current power mode * @max_pwr_info: keeps the device max valid pwm - * @desc_size: descriptor sizes reported by device * @urgent_bkops_lvl: keeps track of urgent bkops level for device * @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level for * device is known or not. @@ -573,9 +563,6 @@ struct ufs_hba { enum bkops_status urgent_bkops_lvl; bool is_urgent_bkops_lvl_checked; - - struct ufs_desc_size desc_size; - int latency_hist_enabled; struct io_latency_state io_lat_read; struct io_latency_state io_lat_write; @@ -752,10 +739,6 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, enum flag_idn idn, bool *flag_res); int ufshcd_hold(struct ufs_hba *hba, bool async); void ufshcd_release(struct ufs_hba *hba); - -int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id, - int *desc_length); - u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba); /* Wrapper functions for safely calling variant operations */ -- GitLab From d77f49565d787f150edeb244a0b63ee91a175bf4 Mon Sep 17 00:00:00 2001 From: Blagovest Kolenichev Date: Wed, 20 Jun 2018 05:03:46 -0700 Subject: [PATCH 203/604] Revert "scsi: ufs: refactor device descriptor reading" This reverts commit be4d66d6b6f2cdfec92f1bd2fd44edd633097afd. [Sayali Lokhande] Equivalent code delta is already presented on msm-4.9 as part of commit [1]. There are few function/structure names different as compared to the change which is reverted, but even that, modifications are still doing the same thing. Motivation to revert the change is because it is causing merge conflicts on importing android-4.9.107 (42a730a) into msm-4.9, hence let's remove it before the merge. [1] 344c16c scsi: ufs: read device descriptor once Change-Id: I35d74c2663d98a9e5e8a4090f16e8054d2409896 Signed-off-by: Blagovest Kolenichev --- drivers/scsi/ufs/ufs.h | 12 ----------- drivers/scsi/ufs/ufs_quirks.h | 28 ++++++++++++++++++------ drivers/scsi/ufs/ufshcd.c | 40 ++++++++++++++++++----------------- 3 files changed, 43 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 377ba30c2258..845b874e2977 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -522,16 +522,4 @@ struct ufs_dev_info { bool is_lu_power_on_wp; }; -#define MAX_MODEL_LEN 16 -/** - * ufs_dev_desc - ufs device details from the device descriptor - * - * @wmanufacturerid: card details - * @model: card model - */ -struct ufs_dev_desc { - u16 wmanufacturerid; - char model[MAX_MODEL_LEN + 1]; -}; - #endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index 71f73d1d1ad1..08b799d4efcc 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h @@ -21,28 +21,41 @@ #define UFS_ANY_VENDOR 0xFFFF #define UFS_ANY_MODEL "ANY_MODEL" +#define MAX_MODEL_LEN 16 + #define UFS_VENDOR_TOSHIBA 0x198 #define UFS_VENDOR_SAMSUNG 0x1CE #define UFS_VENDOR_SKHYNIX 0x1AD +/** + * ufs_device_info - ufs device details + * @wmanufacturerid: card details + * @model: card model + */ +struct ufs_device_info { + u16 wmanufacturerid; + char model[MAX_MODEL_LEN + 1]; +}; + /** * ufs_dev_fix - ufs device quirk info * @card: ufs card details * @quirk: device quirk */ struct ufs_dev_fix { - struct ufs_dev_desc card; + struct ufs_device_info card; unsigned int quirk; }; #define END_FIX { { 0 }, 0 } /* add specific device quirk */ -#define UFS_FIX(_vendor, _model, _quirk) { \ - .card.wmanufacturerid = (_vendor),\ - .card.model = (_model), \ - .quirk = (_quirk), \ -} +#define UFS_FIX(_vendor, _model, _quirk) \ + { \ + .card.wmanufacturerid = (_vendor),\ + .card.model = (_model), \ + .quirk = (_quirk), \ + } /* * If UFS device is having issue in processing LCC (Line Control @@ -131,4 +144,7 @@ struct ufs_dev_fix { */ #define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME (1 << 8) +struct ufs_hba; +void ufs_advertise_fixup_device(struct ufs_hba *hba); + #endif /* UFS_QUIRKS_H_ */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index d4484c78e563..88fee5e7365c 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4935,8 +4935,8 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) return ret; } -static int ufs_get_device_desc(struct ufs_hba *hba, - struct ufs_dev_desc *dev_desc) +static int ufs_get_device_info(struct ufs_hba *hba, + struct ufs_device_info *card_data) { int err; u8 model_index; @@ -4955,7 +4955,7 @@ static int ufs_get_device_desc(struct ufs_hba *hba, * getting vendor (manufacturerID) and Bank Index in big endian * format */ - dev_desc->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | + card_data->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]; model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; @@ -4969,26 +4969,36 @@ static int ufs_get_device_desc(struct ufs_hba *hba, } str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0'; - strlcpy(dev_desc->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), + strlcpy(card_data->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET], MAX_MODEL_LEN)); /* Null terminate the model string */ - dev_desc->model[MAX_MODEL_LEN] = '\0'; + card_data->model[MAX_MODEL_LEN] = '\0'; out: return err; } -static void ufs_fixup_device_setup(struct ufs_hba *hba, - struct ufs_dev_desc *dev_desc) +void ufs_advertise_fixup_device(struct ufs_hba *hba) { + int err; struct ufs_dev_fix *f; + struct ufs_device_info card_data; + + card_data.wmanufacturerid = 0; + + err = ufs_get_device_info(hba, &card_data); + if (err) { + dev_err(hba->dev, "%s: Failed getting device info. err = %d\n", + __func__, err); + return; + } for (f = ufs_fixups; f->quirk; f++) { - if ((f->card.wmanufacturerid == dev_desc->wmanufacturerid || - f->card.wmanufacturerid == UFS_ANY_VENDOR) && - (STR_PRFX_EQUAL(f->card.model, dev_desc->model) || + if (((f->card.wmanufacturerid == card_data.wmanufacturerid) || + (f->card.wmanufacturerid == UFS_ANY_VENDOR)) && + (STR_PRFX_EQUAL(f->card.model, card_data.model) || !strcmp(f->card.model, UFS_ANY_MODEL))) hba->dev_quirks |= f->quirk; } @@ -5166,7 +5176,6 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) */ static int ufshcd_probe_hba(struct ufs_hba *hba) { - struct ufs_dev_desc card = {0}; int ret; ret = ufshcd_link_startup(hba); @@ -5190,14 +5199,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) if (ret) goto out; - ret = ufs_get_device_desc(hba, &card); - if (ret) { - dev_err(hba->dev, "%s: Failed getting device info. err = %d\n", - __func__, ret); - goto out; - } - - ufs_fixup_device_setup(hba, &card); + ufs_advertise_fixup_device(hba); ufshcd_tune_unipro_params(hba); ret = ufshcd_set_vccq_rail_unused(hba, -- GitLab From 29be492d1f3874bf47aa84e7020f8be6ddb3f98d Mon Sep 17 00:00:00 2001 From: Blagovest Kolenichev Date: Wed, 20 Jun 2018 05:03:57 -0700 Subject: [PATCH 204/604] Revert "scsi: ufs: fix failure to read the string descriptor" This reverts commit b0a12b452a082ee2b29dfe9ce3818b3690c6f596. Content added by the commit that is reverted is already presented into msm-4.9 as part of change [1], where the delta was taken from msm-4.4 change [2]. Note that [2] is created on a slightly extended code as compared with the reverted change done with changes [3] and [4]. In summary, change [2] is upstreamed as b0a12b4. Motivation to revert the change is because it is causing merge conflicts on importing android-4.9.107 (42a730a) into msm-4.9, hence let's remove it before the merge. [1] cce6fbc ufs: snapshot of UFS driver [2] 878c98c scsi: ufs: fix failure to read the string descriptor [3] a7da3b2 scsi: ufs: add descriptor read support [4] cb6bbbd scsi: ufs: add index details to query error messages Change-Id: Ie07fe42a8f08b5e67fe7737be34e299e3edad062 Signed-off-by: Blagovest Kolenichev --- drivers/scsi/ufs/ufshcd.c | 39 ++++++++------------------------------- 1 file changed, 8 insertions(+), 31 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 88fee5e7365c..70bc3ba10b88 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2098,38 +2098,15 @@ static int ufshcd_read_desc_param(struct ufs_hba *hba, desc_id, desc_index, 0, desc_buf, &buff_len); - if (ret) { - dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d", - __func__, desc_id, desc_index, param_offset, ret); - - goto out; - } - - /* Sanity check */ - if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) { - dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header", - __func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]); - ret = -EINVAL; - goto out; - } + if (ret || (buff_len < ufs_query_desc_max_size[desc_id]) || + (desc_buf[QUERY_DESC_LENGTH_OFFSET] != + ufs_query_desc_max_size[desc_id]) + || (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id)) { + dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d param_offset %d buff_len %d ret %d", + __func__, desc_id, param_offset, buff_len, ret); + if (!ret) + ret = -EINVAL; - /* - * While reading variable size descriptors (like string descriptor), - * some UFS devices may report the "LENGTH" (field in "Transaction - * Specific fields" of Query Response UPIU) same as what was requested - * in Query Request UPIU instead of reporting the actual size of the - * variable size descriptor. - * Although it's safe to ignore the "LENGTH" field for variable size - * descriptors as we can always derive the length of the descriptor from - * the descriptor header fields. Hence this change impose the length - * match check only for fixed size descriptors (for which we always - * request the correct size as part of Query Request UPIU). - */ - if ((desc_id != QUERY_DESC_IDN_STRING) && - (buff_len != desc_buf[QUERY_DESC_LENGTH_OFFSET])) { - dev_err(hba->dev, "%s: desc_buf length mismatch: buff_len %d, buff_len(desc_header) %d", - __func__, buff_len, desc_buf[QUERY_DESC_LENGTH_OFFSET]); - ret = -EINVAL; goto out; } -- GitLab From 995cddcc3337088b2129dddc7d59fe0282d15d5f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 7 Jun 2018 09:13:48 -0700 Subject: [PATCH 205/604] x86/spectre_v1: Disable compiler optimizations over array_index_mask_nospec() commit eab6870fee877258122a042bfd99ee7908c40280 upstream. Mark Rutland noticed that GCC optimization passes have the potential to elide necessary invocations of the array_index_mask_nospec() instruction sequence, so mark the asm() volatile. Mark explains: "The volatile will inhibit *some* cases where the compiler could lift the array_index_nospec() call out of a branch, e.g. where there are multiple invocations of array_index_nospec() with the same arguments: if (idx < foo) { idx1 = array_idx_nospec(idx, foo) do_something(idx1); } < some other code > if (idx < foo) { idx2 = array_idx_nospec(idx, foo); do_something_else(idx2); } ... since the compiler can determine that the two invocations yield the same result, and reuse the first result (likely the same register as idx was in originally) for the second branch, effectively re-writing the above as: if (idx < foo) { idx = array_idx_nospec(idx, foo); do_something(idx); } < some other code > if (idx < foo) { do_something_else(idx); } ... if we don't take the first branch, then speculatively take the second, we lose the nospec protection. There's more info on volatile asm in the GCC docs: https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Volatile " Reported-by: Mark Rutland Signed-off-by: Dan Williams Acked-by: Mark Rutland Acked-by: Thomas Gleixner Acked-by: Linus Torvalds Cc: Cc: Peter Zijlstra Fixes: babdde2698d4 ("x86: Implement array_index_mask_nospec") Link: https://lkml.kernel.org/lkml/152838798950.14521.4893346294059739135.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/barrier.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h index 78d1c6a3d221..eb53c2c78a1f 100644 --- a/arch/x86/include/asm/barrier.h +++ b/arch/x86/include/asm/barrier.h @@ -37,7 +37,7 @@ static inline unsigned long array_index_mask_nospec(unsigned long index, { unsigned long mask; - asm ("cmp %1,%2; sbb %0,%0;" + asm volatile ("cmp %1,%2; sbb %0,%0;" :"=r" (mask) :"g"(size),"r" (index) :"cc"); -- GitLab From b4eb80a751d3f9ece95255dbcb38539f2c96acac Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 25 May 2018 14:41:39 -0700 Subject: [PATCH 206/604] x86/mce: Improve error message when kernel cannot recover commit c7d606f560e4c698884697fef503e4abacdd8c25 upstream. Since we added support to add recovery from some errors inside the kernel in: commit b2f9d678e28c ("x86/mce: Check for faults tagged in EXTABLE_CLASS_FAULT exception table entries") we have done a less than stellar job at reporting the cause of recoverable machine checks that occur in other parts of the kernel. The user just gets the unhelpful message: mce: [Hardware Error]: Machine check: Action required: unknown MCACOD doubly unhelpful when they check the manual for the reported IA32_MSR_STATUS.MCACOD and see that it is listed as one of the standard recoverable values. Add an extra rule to the MCE severity table to catch this case and report it as: mce: [Hardware Error]: Machine check: Data load in unrecoverable area of kernel Fixes: b2f9d678e28c ("x86/mce: Check for faults tagged in EXTABLE_CLASS_FAULT exception table entries") Signed-off-by: Tony Luck Signed-off-by: Thomas Gleixner Cc: Qiuxu Zhuo Cc: Ashok Raj Cc: stable@vger.kernel.org # 4.6+ Cc: Dan Williams Cc: Borislav Petkov Link: https://lkml.kernel.org/r/4cc7c465150a9a48b8b9f45d0b840278e77eb9b5.1527283897.git.tony.luck@intel.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/mcheck/mce-severity.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c index f46071cb2c90..3e0199ee5a2f 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-severity.c +++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c @@ -143,6 +143,11 @@ static struct severity { SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_INSTR), USER ), + MCESEV( + PANIC, "Data load in unrecoverable area of kernel", + SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_DATA), + KERNEL + ), #endif MCESEV( PANIC, "Action required: unknown MCACOD", -- GitLab From e7905a78ad570760210192307d9dc69051a072bd Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 25 May 2018 14:42:09 -0700 Subject: [PATCH 207/604] x86/mce: Check for alternate indication of machine check recovery on Skylake commit 4c5717da1d021cf368eabb3cb1adcaead56c0d1e upstream. Currently we just check the "CAPID0" register to see whether the CPU can recover from machine checks. But there are also some special SKUs which do not have all advanced RAS features, but do enable machine check recovery for use with NVDIMMs. Add a check for any of bits {8:5} in the "CAPID5" register (each reports some NVDIMM mode available, if any of them are set, then the system supports memory machine check recovery). Signed-off-by: Tony Luck Signed-off-by: Thomas Gleixner Cc: Qiuxu Zhuo Cc: Ashok Raj Cc: stable@vger.kernel.org # 4.9 Cc: Dan Williams Cc: Borislav Petkov Link: https://lkml.kernel.org/r/03cbed6e99ddafb51c2eadf9a3b7c8d7a0cc204e.1527283897.git.tony.luck@intel.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/quirks.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c index 0bee04d41bed..b57100a2c834 100644 --- a/arch/x86/kernel/quirks.c +++ b/arch/x86/kernel/quirks.c @@ -643,12 +643,19 @@ static void quirk_intel_brickland_xeon_ras_cap(struct pci_dev *pdev) /* Skylake */ static void quirk_intel_purley_xeon_ras_cap(struct pci_dev *pdev) { - u32 capid0; + u32 capid0, capid5; pci_read_config_dword(pdev, 0x84, &capid0); + pci_read_config_dword(pdev, 0x98, &capid5); - if ((capid0 & 0xc0) == 0xc0) + /* + * CAPID0{7:6} indicate whether this is an advanced RAS SKU + * CAPID5{8:5} indicate that various NVDIMM usage modes are + * enabled, so memory machine check recovery is also enabled. + */ + if ((capid0 & 0xc0) == 0xc0 || (capid5 & 0x1e0)) static_branch_inc(&mcsafe_key); + } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0ec3, quirk_intel_brickland_xeon_ras_cap); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2fc0, quirk_intel_brickland_xeon_ras_cap); -- GitLab From c267eaaceb58e0acf0132a509ce58649add44f5e Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 22 Jun 2018 11:54:23 +0200 Subject: [PATCH 208/604] x86/mce: Fix incorrect "Machine check from unknown source" message commit 40c36e2741d7fe1e66d6ec55477ba5fd19c9c5d2 upstream. Some injection testing resulted in the following console log: mce: [Hardware Error]: CPU 22: Machine Check Exception: f Bank 1: bd80000000100134 mce: [Hardware Error]: RIP 10: {pmem_do_bvec+0x11d/0x330 [nd_pmem]} mce: [Hardware Error]: TSC c51a63035d52 ADDR 3234bc4000 MISC 88 mce: [Hardware Error]: PROCESSOR 0:50654 TIME 1526502199 SOCKET 0 APIC 38 microcode 2000043 mce: [Hardware Error]: Run the above through 'mcelog --ascii' Kernel panic - not syncing: Machine check from unknown source This confused everybody because the first line quite clearly shows that we found a logged error in "Bank 1", while the last line says "unknown source". The problem is that the Linux code doesn't do the right thing for a local machine check that results in a fatal error. It turns out that we know very early in the handler whether the machine check is fatal. The call to mce_no_way_out() has checked all the banks for the CPU that took the local machine check. If it says we must crash, we can do so right away with the right messages. We do scan all the banks again. This means that we might initially not see a problem, but during the second scan find something fatal. If this happens we print a slightly different message (so I can see if it actually every happens). [ bp: Remove unneeded severity assignment. ] Signed-off-by: Tony Luck Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Cc: Ashok Raj Cc: Dan Williams Cc: Qiuxu Zhuo Cc: linux-edac Cc: stable@vger.kernel.org # 4.2 Link: http://lkml.kernel.org/r/52e049a497e86fd0b71c529651def8871c804df0.1527283897.git.tony.luck@intel.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/mcheck/mce.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 7bbd50fa72ad..886a44a1ecea 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -1140,13 +1140,18 @@ void do_machine_check(struct pt_regs *regs, long error_code) lmce = m.mcgstatus & MCG_STATUS_LMCES; /* + * Local machine check may already know that we have to panic. + * Broadcast machine check begins rendezvous in mce_start() * Go through all banks in exclusion of the other CPUs. This way we * don't report duplicated events on shared banks because the first one - * to see it will clear it. If this is a Local MCE, then no need to - * perform rendezvous. + * to see it will clear it. */ - if (!lmce) + if (lmce) { + if (no_way_out) + mce_panic("Fatal local machine check", &m, msg); + } else { order = mce_start(&no_way_out); + } for (i = 0; i < cfg->banks; i++) { __clear_bit(i, toclear); @@ -1222,12 +1227,17 @@ void do_machine_check(struct pt_regs *regs, long error_code) no_way_out = worst >= MCE_PANIC_SEVERITY; } else { /* - * Local MCE skipped calling mce_reign() - * If we found a fatal error, we need to panic here. + * If there was a fatal machine check we should have + * already called mce_panic earlier in this function. + * Since we re-read the banks, we might have found + * something new. Check again to see if we found a + * fatal error. We call "mce_severity()" again to + * make sure we have the right "msg". */ - if (worst >= MCE_PANIC_SEVERITY && mca_cfg.tolerant < 3) - mce_panic("Machine check from unknown source", - NULL, NULL); + if (worst >= MCE_PANIC_SEVERITY && mca_cfg.tolerant < 3) { + mce_severity(&m, cfg->tolerant, &msg, true); + mce_panic("Local fatal machine check!", &m, msg); + } } /* -- GitLab From 5a48f6084de709dbc55c56d91fc78011ae6c4b0e Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 22 Jun 2018 11:54:28 +0200 Subject: [PATCH 209/604] x86/mce: Do not overwrite MCi_STATUS in mce_no_way_out() commit 1f74c8a64798e2c488f86efc97e308b85fb7d7aa upstream. mce_no_way_out() does a quick check during #MC to see whether some of the MCEs logged would require the kernel to panic immediately. And it passes a struct mce where MCi_STATUS gets written. However, after having saved a valid status value, the next iteration of the loop which goes over the MCA banks on the CPU, overwrites the valid status value because we're using struct mce as storage instead of a temporary variable. Which leads to MCE records with an empty status value: mce: [Hardware Error]: CPU 0: Machine Check Exception: 6 Bank 0: 0000000000000000 mce: [Hardware Error]: RIP 10: {trigger_mce+0x7/0x10} In order to prevent the loss of the status register value, return immediately when severity is a panic one so that we can panic immediately with the first fatal MCE logged. This is also the intention of this function and not to noodle over the banks while a fatal MCE is already logged. Tony: read the rest of the MCA bank to populate the struct mce fully. Suggested-by: Tony Luck Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Cc: Link: https://lkml.kernel.org/r/20180622095428.626-8-bp@alien8.de Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/mcheck/mce.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 886a44a1ecea..c49e146d4332 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -738,23 +738,25 @@ EXPORT_SYMBOL_GPL(machine_check_poll); static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp, struct pt_regs *regs) { - int i, ret = 0; char *tmp; + int i; for (i = 0; i < mca_cfg.banks; i++) { m->status = mce_rdmsrl(msr_ops.status(i)); - if (m->status & MCI_STATUS_VAL) { - __set_bit(i, validp); - if (quirk_no_way_out) - quirk_no_way_out(i, m, regs); - } + if (!(m->status & MCI_STATUS_VAL)) + continue; + + __set_bit(i, validp); + if (quirk_no_way_out) + quirk_no_way_out(i, m, regs); if (mce_severity(m, mca_cfg.tolerant, &tmp, true) >= MCE_PANIC_SEVERITY) { + mce_read_aux(m, i); *msg = tmp; - ret = 1; + return 1; } } - return ret; + return 0; } /* -- GitLab From 7a68dcdc9d22080c974bb5472cae7d1799ec8607 Mon Sep 17 00:00:00 2001 From: Siarhei Liakh Date: Thu, 14 Jun 2018 19:36:07 +0000 Subject: [PATCH 210/604] x86: Call fixup_exception() before notify_die() in math_error() commit 3ae6295ccb7cf6d344908209701badbbbb503e40 upstream. fpu__drop() has an explicit fwait which under some conditions can trigger a fixable FPU exception while in kernel. Thus, we should attempt to fixup the exception first, and only call notify_die() if the fixup failed just like in do_general_protection(). The original call sequence incorrectly triggers KDB entry on debug kernels under particular FPU-intensive workloads. Andy noted, that this makes the whole conditional irq enable thing even more inconsistent, but fixing that it outside the scope of this. Signed-off-by: Siarhei Liakh Signed-off-by: Thomas Gleixner Reviewed-by: Andy Lutomirski Cc: "H. Peter Anvin" Cc: "Borislav Petkov" Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/DM5PR11MB201156F1CAB2592B07C79A03B17D0@DM5PR11MB2011.namprd11.prod.outlook.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/traps.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index f2142932ff0b..5bbfa2f63b8c 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -799,16 +799,18 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr) char *str = (trapnr == X86_TRAP_MF) ? "fpu exception" : "simd exception"; - if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, SIGFPE) == NOTIFY_STOP) - return; cond_local_irq_enable(regs); if (!user_mode(regs)) { - if (!fixup_exception(regs, trapnr)) { - task->thread.error_code = error_code; - task->thread.trap_nr = trapnr; + if (fixup_exception(regs, trapnr)) + return; + + task->thread.error_code = error_code; + task->thread.trap_nr = trapnr; + + if (notify_die(DIE_TRAP, str, regs, error_code, + trapnr, SIGFPE) != NOTIFY_STOP) die(str, regs, error_code); - } return; } -- GitLab From 5692dcf90e6907e6ea09707b6c7426f36f905772 Mon Sep 17 00:00:00 2001 From: Michael Schmitz Date: Mon, 14 May 2018 23:10:53 +1200 Subject: [PATCH 211/604] m68k/mm: Adjust VM area to be unmapped by gap size for __iounmap() commit 3f90f9ef2dda316d64e420d5d51ba369587ccc55 upstream. If 020/030 support is enabled, get_io_area() leaves an IO_SIZE gap between mappings which is added to the vm_struct representing the mapping. __ioremap() uses the actual requested size (after alignment), while __iounmap() is passed the size from the vm_struct. On 020/030, early termination descriptors are used to set up mappings of extent 'size', which are validated on unmapping. The unmapped gap of size IO_SIZE defeats the sanity check of the pmd tables, causing __iounmap() to loop forever on 030. On 040/060, unmapping of page table entries does not check for a valid mapping, so the umapping loop always completes there. Adjust size to be unmapped by the gap that had been added in the vm_struct prior. This fixes the hang in atari_platform_init() reported a long time ago, and a similar one reported by Finn recently (addressed by removing ioremap() use from the SWIM driver. Tested on my Falcon in 030 mode - untested but should work the same on 040/060 (the extra page tables cleared there would never have been set up anyway). Signed-off-by: Michael Schmitz [geert: Minor commit description improvements] [geert: This was fixed in 2.4.23, but not in 2.5.x] Signed-off-by: Geert Uytterhoeven Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- arch/m68k/mm/kmap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c index 6e4955bc542b..fcd52cefee29 100644 --- a/arch/m68k/mm/kmap.c +++ b/arch/m68k/mm/kmap.c @@ -88,7 +88,8 @@ static inline void free_io_area(void *addr) for (p = &iolist ; (tmp = *p) ; p = &tmp->next) { if (tmp->addr == addr) { *p = tmp->next; - __iounmap(tmp->addr, tmp->size); + /* remove gap added in get_io_area() */ + __iounmap(tmp->addr, tmp->size - IO_SIZE); kfree(tmp); return; } -- GitLab From d9c202b269dd752c977fb1eb3cc6875a69899648 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Tue, 8 May 2018 10:55:09 +0200 Subject: [PATCH 212/604] serial: sh-sci: Use spin_{try}lock_irqsave instead of open coding version commit 8afb1d2c12163f77777f84616a8e9444d0050ebe upstream. Commit 40f70c03e33a ("serial: sh-sci: add locking to console write function to avoid SMP lockup") copied the strategy to avoid locking problems in conjuncture with the console from the UART8250 driver. Instead using directly spin_{try}lock_irqsave(), local_irq_save() followed by spin_{try}lock() was used. While this is correct on mainline, for -rt it is a problem. spin_{try}lock() will check if it is running in a valid context. Since the local_irq_save() has already been executed, the context has changed and spin_{try}lock() will complain. The reason why spin_{try}lock() complains is that on -rt the spin locks are turned into mutexes and therefore can sleep. Sleeping with interrupts disabled is not valid. BUG: sleeping function called from invalid context at /home/wagi/work/rt/v4.4-cip-rt/kernel/locking/rtmutex.c:995 in_atomic(): 0, irqs_disabled(): 128, pid: 778, name: irq/76-eth0 CPU: 0 PID: 778 Comm: irq/76-eth0 Not tainted 4.4.126-test-cip22-rt14-00403-gcd03665c8318 #12 Hardware name: Generic RZ/G1 (Flattened Device Tree) Backtrace: [] (dump_backtrace) from [] (show_stack+0x18/0x1c) r7:c06b01f0 r6:60010193 r5:00000000 r4:c06b01f0 [] (show_stack) from [] (dump_stack+0x78/0x94) [] (dump_stack) from [] (___might_sleep+0x134/0x194) r7:60010113 r6:c06d3559 r5:00000000 r4:ffffe000 [] (___might_sleep) from [] (rt_spin_lock+0x20/0x74) r5:c06f4d60 r4:c06f4d60 [] (rt_spin_lock) from [] (serial_console_write+0x100/0x118) r5:c06f4d60 r4:c06f4d60 [] (serial_console_write) from [] (call_console_drivers.constprop.15+0x10c/0x124) r10:c06d2894 r9:c04e18b0 r8:00000028 r7:00000000 r6:c06d3559 r5:c06d2798 r4:c06b9914 r3:c02576e4 [] (call_console_drivers.constprop.15) from [] (console_unlock+0x32c/0x430) r10:c06d30d8 r9:00000028 r8:c06dd518 r7:00000005 r6:00000000 r5:c06d2798 r4:c06d2798 r3:00000028 [] (console_unlock) from [] (vprintk_emit+0x394/0x4f0) r10:c06d2798 r9:c06d30ee r8:00000006 r7:00000005 r6:c06a78fc r5:00000027 r4:00000003 [] (vprintk_emit) from [] (vprintk+0x28/0x30) r10:c060bd46 r9:00001000 r8:c06b9a90 r7:c06b9a90 r6:c06b994c r5:c06b9a3c r4:c0062fa8 [] (vprintk) from [] (vprintk_default+0x10/0x14) [] (vprintk_default) from [] (printk+0x78/0x84) [] (printk) from [] (credit_entropy_bits+0x17c/0x2cc) r3:00000001 r2:decade60 r1:c061a5ee r0:c061a523 r4:00000006 [] (credit_entropy_bits) from [] (add_interrupt_randomness+0x160/0x178) r10:466e7196 r9:1f536000 r8:fffeef74 r7:00000000 r6:c06b9a60 r5:c06b9a3c r4:dfbcf680 [] (add_interrupt_randomness) from [] (irq_thread+0x1e8/0x248) r10:c006537c r9:c06cdf21 r8:c0064fcc r7:df791c24 r6:df791c00 r5:ffffe000 r4:df525180 [] (irq_thread) from [] (kthread+0x108/0x11c) r10:00000000 r9:00000000 r8:c0065184 r7:df791c00 r6:00000000 r5:df791d00 r4:decac000 [] (kthread) from [] (ret_from_fork+0x14/0x3c) r8:00000000 r7:00000000 r6:00000000 r5:c003fa9c r4:df791d00 Cc: Sebastian Andrzej Siewior Signed-off-by: Daniel Wagner Reviewed-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index da46f0fba5da..6ff53b604ff6 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2807,16 +2807,15 @@ static void serial_console_write(struct console *co, const char *s, unsigned long flags; int locked = 1; - local_irq_save(flags); #if defined(SUPPORT_SYSRQ) if (port->sysrq) locked = 0; else #endif if (oops_in_progress) - locked = spin_trylock(&port->lock); + locked = spin_trylock_irqsave(&port->lock, flags); else - spin_lock(&port->lock); + spin_lock_irqsave(&port->lock, flags); /* first save SCSCR then disable interrupts, keep clock source */ ctrl = serial_port_in(port, SCSCR); @@ -2835,8 +2834,7 @@ static void serial_console_write(struct console *co, const char *s, serial_port_out(port, SCSCR, ctrl); if (locked) - spin_unlock(&port->lock); - local_irq_restore(flags); + spin_unlock_irqrestore(&port->lock, flags); } static int serial_console_setup(struct console *co, char *options) -- GitLab From c82ccd7122be45daa107244240a2ede87e562b86 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 20 Apr 2018 09:14:56 -0500 Subject: [PATCH 213/604] signal/xtensa: Consistenly use SIGBUS in do_unaligned_user commit 7de712ccc096b81d23cc0a941cd9b8cb3956605d upstream. While working on changing this code to use force_sig_fault I discovered that do_unaliged_user is sets si_signo to SIGBUS and passes SIGSEGV to force_sig_info. Which is just b0rked. The code is reporting a SIGBUS error so replace the SIGSEGV with SIGBUS. Cc: Chris Zankel Cc: Max Filippov Cc: linux-xtensa@linux-xtensa.org Cc: stable@vger.kernel.org Acked-by: Max Filippov Fixes: 5a0015d62668 ("[PATCH] xtensa: Architecture support for Tensilica Xtensa Part 3") Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman --- arch/xtensa/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c index ce37d5b899fe..44bd9a377ad1 100644 --- a/arch/xtensa/kernel/traps.c +++ b/arch/xtensa/kernel/traps.c @@ -334,7 +334,7 @@ do_unaligned_user (struct pt_regs *regs) info.si_errno = 0; info.si_code = BUS_ADRALN; info.si_addr = (void *) regs->excvaddr; - force_sig_info(SIGSEGV, &info, current); + force_sig_info(SIGBUS, &info, current); } #endif -- GitLab From 55365ad775af75e1ea56a496e845bd43cbf276bf Mon Sep 17 00:00:00 2001 From: Maxim Moseychuk Date: Thu, 4 Jan 2018 21:43:03 +0300 Subject: [PATCH 214/604] usb: do not reset if a low-speed or full-speed device timed out commit 6e01827ed93947895680fbdad68c072a0f4e2450 upstream. Some low-speed and full-speed devices (for example, bluetooth) do not have time to initialize. For them, ETIMEDOUT is a valid error. We need to give them another try. Otherwise, they will never be initialized correctly and in dmesg will be messages "Bluetooth: hci0 command 0x1002 tx timeout" or similars. Fixes: 264904ccc33c ("usb: retry reset if a device times out") Cc: stable Signed-off-by: Maxim Moseychuk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index d8d992b73e88..8bf0090218dd 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -4509,7 +4509,9 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, * reset. But only on the first attempt, * lest we get into a time out/reset loop */ - if (r == 0 || (r == -ETIMEDOUT && retries == 0)) + if (r == 0 || (r == -ETIMEDOUT && + retries == 0 && + udev->speed > USB_SPEED_FULL)) break; } udev->descriptor.bMaxPacketSize0 = -- GitLab From cf05568cb828cbbe7c36c19187ff68aa1c2bd512 Mon Sep 17 00:00:00 2001 From: Ingo Flaschberger Date: Tue, 1 May 2018 16:10:33 +0200 Subject: [PATCH 215/604] 1wire: family module autoload fails because of upper/lower case mismatch. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 065c09563c872e52813a17218c52cd642be1dca6 upstream. 1wire family module autoload fails because of upper/lower  case mismatch. Signed-off-by: Ingo Flaschberger Acked-by: Evgeniy Polyakov Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/w1/w1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index ab0931e7a9bb..aa458f2fced1 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -741,7 +741,7 @@ int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) /* slave modules need to be loaded in a context with unlocked mutex */ mutex_unlock(&dev->mutex); - request_module("w1-family-0x%02x", rn->family); + request_module("w1-family-0x%02X", rn->family); mutex_lock(&dev->mutex); spin_lock(&w1_flock); -- GitLab From 1a1b2790f0bc991fcd21ad2e781dc7c1690446a8 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 4 Jun 2018 12:13:26 +0100 Subject: [PATCH 216/604] ASoC: dapm: delete dapm_kcontrol_data paths list before freeing it commit ff2faf1289c1f81b5b26b9451dd1c2006aac8db8 upstream. dapm_kcontrol_data is freed as part of dapm_kcontrol_free(), leaving the paths pointer dangling in the list. This leads to system crash when we try to unload and reload sound card. I hit this bug during ADSP crash/reboot test case on Dragon board DB410c. Without this patch, on SLAB Poisoning enabled build, kernel crashes with "BUG kmalloc-128 (Tainted: G W ): Poison overwritten" Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- sound/soc/soc-dapm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 6780eba55ec2..0b5d132bc3dd 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -425,6 +425,8 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, static void dapm_kcontrol_free(struct snd_kcontrol *kctl) { struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl); + + list_del(&data->paths); kfree(data->wlist); kfree(data); } -- GitLab From d6aa7326e812915f84098164f0699fdc2ace6a0c Mon Sep 17 00:00:00 2001 From: Alexander Sverdlin Date: Sat, 28 Apr 2018 22:51:38 +0200 Subject: [PATCH 217/604] ASoC: cirrus: i2s: Fix LRCLK configuration commit 2d534113be9a2aa532a1ae127a57e83558aed358 upstream. The bit responsible for LRCLK polarity is i2s_tlrs (0), not i2s_trel (2) (refer to "EP93xx User's Guide"). Previously card drivers which specified SND_SOC_DAIFMT_NB_IF actually got SND_SOC_DAIFMT_NB_NF, an adaptation is necessary to retain the old behavior. Signed-off-by: Alexander Sverdlin Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- sound/soc/cirrus/edb93xx.c | 2 +- sound/soc/cirrus/ep93xx-i2s.c | 8 ++++---- sound/soc/cirrus/snappercl15.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/cirrus/edb93xx.c b/sound/soc/cirrus/edb93xx.c index 85962657aabe..517963ef4847 100644 --- a/sound/soc/cirrus/edb93xx.c +++ b/sound/soc/cirrus/edb93xx.c @@ -67,7 +67,7 @@ static struct snd_soc_dai_link edb93xx_dai = { .cpu_dai_name = "ep93xx-i2s", .codec_name = "spi0.0", .codec_dai_name = "cs4271-hifi", - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF | + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, .ops = &edb93xx_ops, }; diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index 934f8aefdd90..38c240c97041 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@ -213,24 +213,24 @@ static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: /* Negative bit clock, lrclk low on left word */ - clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL); + clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_LRS); break; case SND_SOC_DAIFMT_NB_IF: /* Negative bit clock, lrclk low on right word */ clk_cfg &= ~EP93XX_I2S_CLKCFG_CKP; - clk_cfg |= EP93XX_I2S_CLKCFG_REL; + clk_cfg |= EP93XX_I2S_CLKCFG_LRS; break; case SND_SOC_DAIFMT_IB_NF: /* Positive bit clock, lrclk low on left word */ clk_cfg |= EP93XX_I2S_CLKCFG_CKP; - clk_cfg &= ~EP93XX_I2S_CLKCFG_REL; + clk_cfg &= ~EP93XX_I2S_CLKCFG_LRS; break; case SND_SOC_DAIFMT_IB_IF: /* Positive bit clock, lrclk low on right word */ - clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL; + clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_LRS; break; } diff --git a/sound/soc/cirrus/snappercl15.c b/sound/soc/cirrus/snappercl15.c index 98089df08df6..c6737a573bc0 100644 --- a/sound/soc/cirrus/snappercl15.c +++ b/sound/soc/cirrus/snappercl15.c @@ -72,7 +72,7 @@ static struct snd_soc_dai_link snappercl15_dai = { .codec_dai_name = "tlv320aic23-hifi", .codec_name = "tlv320aic23-codec.0-001a", .platform_name = "ep93xx-i2s", - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF | + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, .ops = &snappercl15_ops, }; -- GitLab From a879f6c232029d08aac63865c4779117d5114d5e Mon Sep 17 00:00:00 2001 From: Alexander Sverdlin Date: Sat, 28 Apr 2018 22:51:39 +0200 Subject: [PATCH 218/604] ASoC: cirrus: i2s: Fix {TX|RX}LinCtrlData setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 5d302ed3cc80564fb835bed5fdba1e1250ecc9e5 upstream. According to "EP93xx User’s Guide", I2STXLinCtrlData and I2SRXLinCtrlData registers actually have different format. The only currently used bit (Left_Right_Justify) has different position. Fix this and simplify the whole setup taking into account the fact that both registers have zero default value. The practical effect of the above is repaired SND_SOC_DAIFMT_RIGHT_J support (currently unused). Signed-off-by: Alexander Sverdlin Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- sound/soc/cirrus/ep93xx-i2s.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index 38c240c97041..0dc3852c4621 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@ -51,7 +51,9 @@ #define EP93XX_I2S_WRDLEN_24 (1 << 0) #define EP93XX_I2S_WRDLEN_32 (2 << 0) -#define EP93XX_I2S_LINCTRLDATA_R_JUST (1 << 2) /* Right justify */ +#define EP93XX_I2S_RXLINCTRLDATA_R_JUST BIT(1) /* Right justify */ + +#define EP93XX_I2S_TXLINCTRLDATA_R_JUST BIT(2) /* Right justify */ #define EP93XX_I2S_CLKCFG_LRS (1 << 0) /* lrclk polarity */ #define EP93XX_I2S_CLKCFG_CKP (1 << 1) /* Bit clock polarity */ @@ -170,25 +172,25 @@ static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(cpu_dai); - unsigned int clk_cfg, lin_ctrl; + unsigned int clk_cfg; + unsigned int txlin_ctrl = 0; + unsigned int rxlin_ctrl = 0; clk_cfg = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG); - lin_ctrl = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXLINCTRLDATA); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: clk_cfg |= EP93XX_I2S_CLKCFG_REL; - lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST; break; case SND_SOC_DAIFMT_LEFT_J: clk_cfg &= ~EP93XX_I2S_CLKCFG_REL; - lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST; break; case SND_SOC_DAIFMT_RIGHT_J: clk_cfg &= ~EP93XX_I2S_CLKCFG_REL; - lin_ctrl |= EP93XX_I2S_LINCTRLDATA_R_JUST; + rxlin_ctrl |= EP93XX_I2S_RXLINCTRLDATA_R_JUST; + txlin_ctrl |= EP93XX_I2S_TXLINCTRLDATA_R_JUST; break; default: @@ -237,8 +239,8 @@ static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, /* Write new register values */ ep93xx_i2s_write_reg(info, EP93XX_I2S_RXCLKCFG, clk_cfg); ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCLKCFG, clk_cfg); - ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, lin_ctrl); - ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, lin_ctrl); + ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, rxlin_ctrl); + ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, txlin_ctrl); return 0; } -- GitLab From 676b002f26f98214856dfebd3bba2673ed9037c9 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 1 Jun 2018 11:28:19 +0200 Subject: [PATCH 219/604] clk: renesas: cpg-mssr: Stop using printk format %pCr commit ef4b0be62641d296cf4c0ad8f75ab83ab066ed51 upstream. Printk format "%pCr" will be removed soon, as clk_get_rate() must not be called in atomic context. Replace it by open-coding the operation. This is safe here, as the code runs in task context. Link: http://lkml.kernel.org/r/1527845302-12159-2-git-send-email-geert+renesas@glider.be To: Jia-Ju Bai To: Jonathan Corbet To: Michael Turquette To: Stephen Boyd To: Zhang Rui To: Eduardo Valentin To: Eric Anholt To: Stefan Wahren To: Greg Kroah-Hartman Cc: Sergey Senozhatsky Cc: Petr Mladek Cc: Linus Torvalds Cc: Steven Rostedt Cc: linux-doc@vger.kernel.org Cc: linux-clk@vger.kernel.org Cc: linux-pm@vger.kernel.org Cc: linux-serial@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-renesas-soc@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: Geert Uytterhoeven Cc: stable@vger.kernel.org # 4.5+ Signed-off-by: Geert Uytterhoeven Acked-by: Stephen Boyd Signed-off-by: Petr Mladek Signed-off-by: Greg Kroah-Hartman --- drivers/clk/renesas/renesas-cpg-mssr.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index 25c41cd9cdfc..7ecc5eac3d7f 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -243,8 +243,9 @@ struct clk *cpg_mssr_clk_src_twocell_get(struct of_phandle_args *clkspec, dev_err(dev, "Cannot get %s clock %u: %ld", type, clkidx, PTR_ERR(clk)); else - dev_dbg(dev, "clock (%u, %u) is %pC at %pCr Hz\n", - clkspec->args[0], clkspec->args[1], clk, clk); + dev_dbg(dev, "clock (%u, %u) is %pC at %lu Hz\n", + clkspec->args[0], clkspec->args[1], clk, + clk_get_rate(clk)); return clk; } @@ -304,7 +305,7 @@ static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core, if (IS_ERR_OR_NULL(clk)) goto fail; - dev_dbg(dev, "Core clock %pC at %pCr Hz\n", clk, clk); + dev_dbg(dev, "Core clock %pC at %lu Hz\n", clk, clk_get_rate(clk)); priv->clks[id] = clk; return; @@ -372,7 +373,7 @@ static void __init cpg_mssr_register_mod_clk(const struct mssr_mod_clk *mod, if (IS_ERR(clk)) goto fail; - dev_dbg(dev, "Module clock %pC at %pCr Hz\n", clk, clk); + dev_dbg(dev, "Module clock %pC at %lu Hz\n", clk, clk_get_rate(clk)); priv->clks[id] = clk; return; -- GitLab From ec7bea37c833616b63a740d1ba54d2a030b62b32 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 1 Jun 2018 11:28:22 +0200 Subject: [PATCH 220/604] lib/vsprintf: Remove atomic-unsafe support for %pCr commit 666902e42fd8344b923c02dc5b0f37948ff4f225 upstream. "%pCr" formats the current rate of a clock, and calls clk_get_rate(). The latter obtains a mutex, hence it must not be called from atomic context. Remove support for this rarely-used format, as vsprintf() (and e.g. printk()) must be callable from any context. Any remaining out-of-tree users will start seeing the clock's name printed instead of its rate. Reported-by: Jia-Ju Bai Fixes: 900cca2944254edd ("lib/vsprintf: add %pC{,n,r} format specifiers for clocks") Link: http://lkml.kernel.org/r/1527845302-12159-5-git-send-email-geert+renesas@glider.be To: Jia-Ju Bai To: Jonathan Corbet To: Michael Turquette To: Stephen Boyd To: Zhang Rui To: Eduardo Valentin To: Eric Anholt To: Stefan Wahren To: Greg Kroah-Hartman Cc: Sergey Senozhatsky Cc: Petr Mladek Cc: Linus Torvalds Cc: Steven Rostedt Cc: linux-doc@vger.kernel.org Cc: linux-clk@vger.kernel.org Cc: linux-pm@vger.kernel.org Cc: linux-serial@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-renesas-soc@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: Geert Uytterhoeven Cc: stable@vger.kernel.org # 4.1+ Signed-off-by: Geert Uytterhoeven Signed-off-by: Petr Mladek Signed-off-by: Greg Kroah-Hartman --- Documentation/printk-formats.txt | 3 +-- lib/vsprintf.c | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt index 5962949944fd..d2fbeeb29582 100644 --- a/Documentation/printk-formats.txt +++ b/Documentation/printk-formats.txt @@ -279,11 +279,10 @@ struct clk: %pC pll1 %pCn pll1 - %pCr 1560000000 For printing struct clk structures. '%pC' and '%pCn' print the name (Common Clock Framework) or address (legacy clock framework) of the - structure; '%pCr' prints the current clock rate. + structure. Passed by reference. diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 0967771d8f7f..79ba3cc07026 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -1391,9 +1391,6 @@ char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec, return string(buf, end, NULL, spec); switch (fmt[1]) { - case 'r': - return number(buf, end, clk_get_rate(clk), spec); - case 'n': default: #ifdef CONFIG_COMMON_CLK -- GitLab From 95f871342295f2a616fb28d5e0cf72939fe5db5d Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 24 Mar 2018 17:57:49 +0100 Subject: [PATCH 221/604] mips: ftrace: fix static function graph tracing commit 6fb8656646f996d1eef42e6d56203c4915cb9e08 upstream. ftrace_graph_caller was never run after calling ftrace_trace_function, breaking the function graph tracer. Fix this, bringing it in line with the x86 implementation. While we're at it, also streamline the control flow of _mcount a bit to reduce the number of branches. This issue was reported before: https://www.linux-mips.org/archives/linux-mips/2014-11/msg00295.html Signed-off-by: Matthias Schiffer Tested-by: Matt Redfearn Patchwork: https://patchwork.linux-mips.org/patch/18929/ Signed-off-by: Paul Burton Cc: stable@vger.kernel.org # v3.17+ Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/mcount.S | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S index 2f7c734771f4..0df911e772ae 100644 --- a/arch/mips/kernel/mcount.S +++ b/arch/mips/kernel/mcount.S @@ -116,10 +116,20 @@ ftrace_stub: NESTED(_mcount, PT_SIZE, ra) PTR_LA t1, ftrace_stub PTR_L t2, ftrace_trace_function /* Prepare t2 for (1) */ - bne t1, t2, static_trace + beq t1, t2, fgraph_trace nop + MCOUNT_SAVE_REGS + + move a0, ra /* arg1: self return address */ + jalr t2 /* (1) call *ftrace_trace_function */ + move a1, AT /* arg2: parent's return address */ + + MCOUNT_RESTORE_REGS + +fgraph_trace: #ifdef CONFIG_FUNCTION_GRAPH_TRACER + PTR_LA t1, ftrace_stub PTR_L t3, ftrace_graph_return bne t1, t3, ftrace_graph_caller nop @@ -128,24 +138,11 @@ NESTED(_mcount, PT_SIZE, ra) bne t1, t3, ftrace_graph_caller nop #endif - b ftrace_stub -#ifdef CONFIG_32BIT - addiu sp, sp, 8 -#else - nop -#endif -static_trace: - MCOUNT_SAVE_REGS - - move a0, ra /* arg1: self return address */ - jalr t2 /* (1) call *ftrace_trace_function */ - move a1, AT /* arg2: parent's return address */ - - MCOUNT_RESTORE_REGS #ifdef CONFIG_32BIT addiu sp, sp, 8 #endif + .globl ftrace_stub ftrace_stub: RETURN_BACK -- GitLab From 3e4fab744be24bf88dac651c5878c831743c0fbe Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 30 May 2018 08:19:22 -0400 Subject: [PATCH 222/604] branch-check: fix long->int truncation when profiling branches commit 2026d35741f2c3ece73c11eb7e4a15d7c2df9ebe upstream. The function __builtin_expect returns long type (see the gcc documentation), and so do macros likely and unlikely. Unfortunatelly, when CONFIG_PROFILE_ANNOTATED_BRANCHES is selected, the macros likely and unlikely expand to __branch_check__ and __branch_check__ truncates the long type to int. This unintended truncation may cause bugs in various kernel code (we found a bug in dm-writecache because of it), so it's better to fix __branch_check__ to return long. Link: http://lkml.kernel.org/r/alpine.LRH.2.02.1805300818140.24812@file01.intranet.prod.int.rdu2.redhat.com Cc: Ingo Molnar Cc: stable@vger.kernel.org Fixes: 1f0d69a9fc815 ("tracing: profile likely and unlikely annotations") Signed-off-by: Mikulas Patocka Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- include/linux/compiler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 5ce911db7d88..4f3dfabb680f 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -113,7 +113,7 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); #define unlikely_notrace(x) __builtin_expect(!!(x), 0) #define __branch_check__(x, expect) ({ \ - int ______r; \ + long ______r; \ static struct ftrace_branch_data \ __attribute__((__aligned__(4))) \ __attribute__((section("_ftrace_annotated_branch"))) \ -- GitLab From d11ec041b2c4fddd7d963cf09895fbcbe14fec2d Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 22 May 2018 08:14:51 -0500 Subject: [PATCH 223/604] ipmi:bt: Set the timeout before doing a capabilities check commit fe50a7d0393a552e4539da2d31261a59d6415950 upstream. There was one place where the timeout value for an operation was not being set, if a capabilities request was done from idle. Move the timeout value setting to before where that change might be requested. IMHO the cause here is the invisible returns in the macros. Maybe that's a job for later, though. Reported-by: Nordmark Claes Signed-off-by: Corey Minyard Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/char/ipmi/ipmi_bt_sm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index feafdab734ae..4835b588b783 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -522,11 +522,12 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) if (status & BT_H_BUSY) /* clear a leftover H_BUSY */ BT_CONTROL(BT_H_BUSY); + bt->timeout = bt->BT_CAP_req2rsp; + /* Read BT capabilities if it hasn't been done yet */ if (!bt->BT_CAP_outreqs) BT_STATE_CHANGE(BT_STATE_CAPABILITIES_BEGIN, SI_SM_CALL_WITHOUT_DELAY); - bt->timeout = bt->BT_CAP_req2rsp; BT_SI_SM_RETURN(SI_SM_IDLE); case BT_STATE_XACTION_START: -- GitLab From f1e9a633e660cbb792c2bc8409e7defd964bae95 Mon Sep 17 00:00:00 2001 From: Amit Pundir Date: Mon, 16 Apr 2018 12:10:24 +0530 Subject: [PATCH 224/604] Bluetooth: hci_qca: Avoid missing rampatch failure with userspace fw loader commit 7dc5fe0814c35ec4e7d2e8fa30abab72e0e6a172 upstream. AOSP use userspace firmware loader to load firmwares, which will return -EAGAIN in case qca/rampatch_00440302.bin is not found. Since there is no rampatch for dragonboard820c QCA controller revision, just make it work as is. CC: Loic Poulain CC: Nicolas Dechesne CC: Marcel Holtmann CC: Johan Hedberg CC: Stable Signed-off-by: Amit Pundir Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/hci_qca.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 74b2f4a14643..3a8b9aef96a6 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -939,6 +939,12 @@ static int qca_setup(struct hci_uart *hu) } else if (ret == -ENOENT) { /* No patch/nvm-config found, run with original fw/config */ ret = 0; + } else if (ret == -EAGAIN) { + /* + * Userspace firmware loader will return -EAGAIN in case no + * patch/nvm-config is found, so run with original fw/config. + */ + ret = 0; } /* Setup bdaddr */ -- GitLab From ebdc37febe594035d8cf3f5424ce97a926d2cddf Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 8 Feb 2018 15:17:38 +0100 Subject: [PATCH 225/604] fuse: atomic_o_trunc should truncate pagecache commit df0e91d488276086bc07da2e389986cae0048c37 upstream. Fuse has an "atomic_o_trunc" mode, where userspace filesystem uses the O_TRUNC flag in the OPEN request to truncate the file atomically with the open. In this mode there's no need to send a SETATTR request to userspace after the open, so fuse_do_setattr() checks this mode and returns. But this misses the important step of truncating the pagecache. Add the missing parts of truncation to the ATTR_OPEN branch. Reported-by: Chad Austin Fixes: 6ff958edbf39 ("fuse: add atomic open+truncate support") Signed-off-by: Miklos Szeredi Cc: Signed-off-by: Greg Kroah-Hartman --- fs/fuse/dir.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 4bbad745415a..cca8dd3bda09 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1633,8 +1633,19 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, return err; if (attr->ia_valid & ATTR_OPEN) { - if (fc->atomic_o_trunc) + /* This is coming from open(..., ... | O_TRUNC); */ + WARN_ON(!(attr->ia_valid & ATTR_SIZE)); + WARN_ON(attr->ia_size != 0); + if (fc->atomic_o_trunc) { + /* + * No need to send request to userspace, since actual + * truncation has already been done by OPEN. But still + * need to truncate page cache. + */ + i_size_write(inode, 0); + truncate_pagecache(inode, 0); return 0; + } file = NULL; } -- GitLab From a0fbcaf9993ea291955ead3dac4b52457b3ec799 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 1 May 2018 13:12:14 +0900 Subject: [PATCH 226/604] fuse: don't keep dead fuse_conn at fuse_fill_super(). commit 543b8f8662fe6d21f19958b666ab0051af9db21a upstream. syzbot is reporting use-after-free at fuse_kill_sb_blk() [1]. Since sb->s_fs_info field is not cleared after fc was released by fuse_conn_put() when initialization failed, fuse_kill_sb_blk() finds already released fc and tries to hold the lock. Fix this by clearing sb->s_fs_info field after calling fuse_conn_put(). [1] https://syzkaller.appspot.com/bug?id=a07a680ed0a9290585ca424546860464dd9658db Signed-off-by: Tetsuo Handa Reported-by: syzbot Fixes: 3b463ae0c626 ("fuse: invalidation reverse calls") Cc: John Muir Cc: Csaba Henk Cc: Anand Avati Cc: # v2.6.31 Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/fuse/inode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 6fe6a88ecb4a..f95e1d49b048 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -1184,6 +1184,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) err_put_conn: fuse_bdi_destroy(fc); fuse_conn_put(fc); + sb->s_fs_info = NULL; err_fput: fput(file); err: -- GitLab From 12715f3ef147e56cb3c570ec169de80f6717838e Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 31 May 2018 12:26:10 +0200 Subject: [PATCH 227/604] fuse: fix control dir setup and teardown commit 6becdb601bae2a043d7fb9762c4d48699528ea6e upstream. syzbot is reporting NULL pointer dereference at fuse_ctl_remove_conn() [1]. Since fc->ctl_ndents is incremented by fuse_ctl_add_conn() when new_inode() failed, fuse_ctl_remove_conn() reaches an inode-less dentry and tries to clear d_inode(dentry)->i_private field. Fix by only adding the dentry to the array after being fully set up. When tearing down the control directory, do d_invalidate() on it to get rid of any mounts that might have been added. [1] https://syzkaller.appspot.com/bug?id=f396d863067238959c91c0b7cfc10b163638cac6 Reported-by: syzbot Fixes: bafa96541b25 ("[PATCH] fuse: add control filesystem") Cc: # v2.6.18 Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/fuse/control.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/fs/fuse/control.c b/fs/fuse/control.c index 6e22748b0704..e25c40c10f4f 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c @@ -211,10 +211,11 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent, if (!dentry) return NULL; - fc->ctl_dentry[fc->ctl_ndents++] = dentry; inode = new_inode(fuse_control_sb); - if (!inode) + if (!inode) { + dput(dentry); return NULL; + } inode->i_ino = get_next_ino(); inode->i_mode = mode; @@ -228,6 +229,9 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent, set_nlink(inode, nlink); inode->i_private = fc; d_add(dentry, inode); + + fc->ctl_dentry[fc->ctl_ndents++] = dentry; + return dentry; } @@ -284,7 +288,10 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc) for (i = fc->ctl_ndents - 1; i >= 0; i--) { struct dentry *dentry = fc->ctl_dentry[i]; d_inode(dentry)->i_private = NULL; - d_drop(dentry); + if (!i) { + /* Get rid of submounts: */ + d_invalidate(dentry); + } dput(dentry); } drop_nlink(d_inode(fuse_control_sb->s_root)); -- GitLab From 10e46042f27d6bebcba97fe1a17af1eb7add7db9 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Wed, 30 May 2018 18:48:04 +0530 Subject: [PATCH 228/604] powerpc/mm/hash: Add missing isync prior to kernel stack SLB switch commit 91d06971881f71d945910de128658038513d1b24 upstream. Currently we do not have an isync, or any other context synchronizing instruction prior to the slbie/slbmte in _switch() that updates the SLB entry for the kernel stack. However that is not correct as outlined in the ISA. From Power ISA Version 3.0B, Book III, Chapter 11, page 1133: "Changing the contents of ... the contents of SLB entries ... can have the side effect of altering the context in which data addresses and instruction addresses are interpreted, and in which instructions are executed and data accesses are performed. ... These side effects need not occur in program order, and therefore may require explicit synchronization by software. ... The synchronizing instruction before the context-altering instruction ensures that all instructions up to and including that synchronizing instruction are fetched and executed in the context that existed before the alteration." And page 1136: "For data accesses, the context synchronizing instruction before the slbie, slbieg, slbia, slbmte, tlbie, or tlbiel instruction ensures that all preceding instructions that access data storage have completed to a point at which they have reported all exceptions they will cause." We're not aware of any bugs caused by this, but it should be fixed regardless. Add the missing isync when updating kernel stack SLB entry. Cc: stable@vger.kernel.org Signed-off-by: Aneesh Kumar K.V [mpe: Flesh out change log with more ISA text & explanation] Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/entry_64.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 2dc52e6d2af4..e24ae0fa80ed 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -586,6 +586,7 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) * actually hit this code path. */ + isync slbie r6 slbie r6 /* Workaround POWER5 < DD2.1 issue */ slbmte r7,r0 -- GitLab From 5ea3b9bddf844e72f701ae8a8ebe75e431249435 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Thu, 17 May 2018 15:37:15 +1000 Subject: [PATCH 229/604] powerpc/ptrace: Fix setting 512B aligned breakpoints with PTRACE_SET_DEBUGREG commit 4f7c06e26ec9cf7fe9f0c54dc90079b6a4f4b2c3 upstream. In commit e2a800beaca1 ("powerpc/hw_brk: Fix off by one error when validating DAWR region end") we fixed setting the DAWR end point to its max value via PPC_PTRACE_SETHWDEBUG. Unfortunately we broke PTRACE_SET_DEBUGREG when setting a 512 byte aligned breakpoint. PTRACE_SET_DEBUGREG currently sets the length of the breakpoint to zero (memset() in hw_breakpoint_init()). This worked with arch_validate_hwbkpt_settings() before the above patch was applied but is now broken if the breakpoint is 512byte aligned. This sets the length of the breakpoint to 8 bytes when using PTRACE_SET_DEBUGREG. Fixes: e2a800beaca1 ("powerpc/hw_brk: Fix off by one error when validating DAWR region end") Cc: stable@vger.kernel.org # v3.11+ Signed-off-by: Michael Neuling Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/ptrace.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index d97370866a5f..adfa63e7df8c 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -2380,6 +2380,7 @@ static int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, /* Create a new breakpoint request if one doesn't exist already */ hw_breakpoint_init(&attr); attr.bp_addr = hw_brk.address; + attr.bp_len = 8; arch_bp_generic_fields(hw_brk.type, &attr.bp_type); -- GitLab From 90f88f05d8775d30c68f7cd2058d55c1a9d868da Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Thu, 17 May 2018 15:37:14 +1000 Subject: [PATCH 230/604] powerpc/ptrace: Fix enforcement of DAWR constraints commit cd6ef7eebf171bfcba7dc2df719c2a4958775040 upstream. Back when we first introduced the DAWR, in commit 4ae7ebe9522a ("powerpc: Change hardware breakpoint to allow longer ranges"), we screwed up the constraint making it a 1024 byte boundary rather than a 512. This makes the check overly permissive. Fortunately GDB is the only real user and it always did they right thing, so we never noticed. This fixes the constraint to 512 bytes. Fixes: 4ae7ebe9522a ("powerpc: Change hardware breakpoint to allow longer ranges") Cc: stable@vger.kernel.org # v3.9+ Signed-off-by: Michael Neuling Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/hw_breakpoint.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index 469d86d1c2a5..532c585ec24b 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -175,8 +175,8 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) if (cpu_has_feature(CPU_FTR_DAWR)) { length_max = 512 ; /* 64 doublewords */ /* DAWR region can't cross 512 boundary */ - if ((bp->attr.bp_addr >> 10) != - ((bp->attr.bp_addr + bp->attr.bp_len - 1) >> 10)) + if ((bp->attr.bp_addr >> 9) != + ((bp->attr.bp_addr + bp->attr.bp_len - 1) >> 9)) return -EINVAL; } if (info->len > -- GitLab From f9b25660d64bd8f86db67b7cfa6d5c30f53627a0 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 30 May 2018 19:22:50 +1000 Subject: [PATCH 231/604] powerpc/powernv/ioda2: Remove redundant free of TCE pages commit 98fd72fe82527fd26618062b60cfd329451f2329 upstream. When IODA2 creates a PE, it creates an IOMMU table with it_ops::free set to pnv_ioda2_table_free() which calls pnv_pci_ioda2_table_free_pages(). Since iommu_tce_table_put() calls it_ops::free when the last reference to the table is released, explicit call to pnv_pci_ioda2_table_free_pages() is not needed so let's remove it. This should fix double free in the case of PCI hotuplug as pnv_pci_ioda2_table_free_pages() does not reset neither iommu_table::it_base nor ::it_size. This was not exposed by SRIOV as it uses different code path via pnv_pcibios_sriov_disable(). IODA1 does not inialize it_ops::free so it does not have this issue. Fixes: c5f7700bbd2e ("powerpc/powernv: Dynamically release PE") Cc: stable@vger.kernel.org # v4.8+ Signed-off-by: Alexey Kardashevskiy Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powernv/pci-ioda.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index f602307a4386..9ed90c502005 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -3424,7 +3424,6 @@ static void pnv_pci_ioda2_release_pe_dma(struct pnv_ioda_pe *pe) WARN_ON(pe->table_group.group); } - pnv_pci_ioda2_table_free_pages(tbl); iommu_free_table(tbl, "pnv"); } -- GitLab From 443004a666ede252f85bcdf8faab85d8174f0367 Mon Sep 17 00:00:00 2001 From: "Gautham R. Shenoy" Date: Thu, 31 May 2018 17:45:09 +0530 Subject: [PATCH 232/604] cpuidle: powernv: Fix promotion from snooze if next state disabled commit 0a4ec6aa035a52c422eceb2ed51ed88392a3d6c2 upstream. The commit 78eaa10f027c ("cpuidle: powernv/pseries: Auto-promotion of snooze to deeper idle state") introduced a timeout for the snooze idle state so that it could be eventually be promoted to a deeper idle state. The snooze timeout value is static and set to the target residency of the next idle state, which would train the cpuidle governor to pick the next idle state eventually. The unfortunate side-effect of this is that if the next idle state(s) is disabled, the CPU will forever remain in snooze, despite the fact that the system is completely idle, and other deeper idle states are available. This patch fixes the issue by dynamically setting the snooze timeout to the target residency of the next enabled state on the device. Before Patch: POWER8 : Only nap disabled. $ cpupower monitor sleep 30 sleep took 30.01297 seconds and exited with status 0 |Idle_Stats PKG |CORE|CPU | snoo | Nap | Fast 0| 8| 0| 96.41| 0.00| 0.00 0| 8| 1| 96.43| 0.00| 0.00 0| 8| 2| 96.47| 0.00| 0.00 0| 8| 3| 96.35| 0.00| 0.00 0| 8| 4| 96.37| 0.00| 0.00 0| 8| 5| 96.37| 0.00| 0.00 0| 8| 6| 96.47| 0.00| 0.00 0| 8| 7| 96.47| 0.00| 0.00 POWER9: Shallow states (stop0lite, stop1lite, stop2lite, stop0, stop1, stop2) disabled: $ cpupower monitor sleep 30 sleep took 30.05033 seconds and exited with status 0 |Idle_Stats PKG |CORE|CPU | snoo | stop | stop | stop | stop | stop | stop | stop | stop 0| 16| 0| 89.79| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00 0| 16| 1| 90.12| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00 0| 16| 2| 90.21| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00 0| 16| 3| 90.29| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00 After Patch: POWER8 : Only nap disabled. $ cpupower monitor sleep 30 sleep took 30.01200 seconds and exited with status 0 |Idle_Stats PKG |CORE|CPU | snoo | Nap | Fast 0| 8| 0| 16.58| 0.00| 77.21 0| 8| 1| 18.42| 0.00| 75.38 0| 8| 2| 4.70| 0.00| 94.09 0| 8| 3| 17.06| 0.00| 81.73 0| 8| 4| 3.06| 0.00| 95.73 0| 8| 5| 7.00| 0.00| 96.80 0| 8| 6| 1.00| 0.00| 98.79 0| 8| 7| 5.62| 0.00| 94.17 POWER9: Shallow states (stop0lite, stop1lite, stop2lite, stop0, stop1, stop2) disabled: $ cpupower monitor sleep 30 sleep took 30.02110 seconds and exited with status 0 |Idle_Stats PKG |CORE|CPU | snoo | stop | stop | stop | stop | stop | stop | stop | stop 0| 0| 0| 0.69| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 9.39| 89.70 0| 0| 1| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.05| 93.21 0| 0| 2| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 89.93 0| 0| 3| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 93.26 Fixes: 78eaa10f027c ("cpuidle: powernv/pseries: Auto-promotion of snooze to deeper idle state") Cc: stable@vger.kernel.org # v4.2+ Signed-off-by: Gautham R. Shenoy Reviewed-by: Balbir Singh Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- drivers/cpuidle/cpuidle-powernv.c | 32 +++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c index 854a56781100..fd96af1d2ef0 100644 --- a/drivers/cpuidle/cpuidle-powernv.c +++ b/drivers/cpuidle/cpuidle-powernv.c @@ -32,9 +32,31 @@ static struct cpuidle_state *cpuidle_state_table; static u64 stop_psscr_table[CPUIDLE_STATE_MAX]; -static u64 snooze_timeout; +static u64 default_snooze_timeout; static bool snooze_timeout_en; +static u64 get_snooze_timeout(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + int i; + + if (unlikely(!snooze_timeout_en)) + return default_snooze_timeout; + + for (i = index + 1; i < drv->state_count; i++) { + struct cpuidle_state *s = &drv->states[i]; + struct cpuidle_state_usage *su = &dev->states_usage[i]; + + if (s->disabled || su->disable) + continue; + + return s->target_residency * tb_ticks_per_usec; + } + + return default_snooze_timeout; +} + static int snooze_loop(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) @@ -44,7 +66,7 @@ static int snooze_loop(struct cpuidle_device *dev, local_irq_enable(); set_thread_flag(TIF_POLLING_NRFLAG); - snooze_exit_time = get_tb() + snooze_timeout; + snooze_exit_time = get_tb() + get_snooze_timeout(dev, drv, index); ppc64_runlatch_off(); while (!need_resched()) { HMT_low(); @@ -337,11 +359,9 @@ static int powernv_idle_probe(void) cpuidle_state_table = powernv_states; /* Device tree can indicate more idle states */ max_idle_state = powernv_add_idle_states(); - if (max_idle_state > 1) { + default_snooze_timeout = TICK_USEC * tb_ticks_per_usec; + if (max_idle_state > 1) snooze_timeout_en = true; - snooze_timeout = powernv_states[1].target_residency * - tb_ticks_per_usec; - } } else return -ENODEV; -- GitLab From 81d6e715d16124862aaeb4b9d9648fb40e9ae779 Mon Sep 17 00:00:00 2001 From: Mahesh Salgaonkar Date: Fri, 27 Apr 2018 11:53:18 +0530 Subject: [PATCH 233/604] powerpc/fadump: Unregister fadump on kexec down path. commit 722cde76d68e8cc4f3de42e71c82fd40dea4f7b9 upstream. Unregister fadump on kexec down path otherwise the fadump registration in new kexec-ed kernel complains that fadump is already registered. This makes new kernel to continue using fadump registered by previous kernel which may lead to invalid vmcore generation. Hence this patch fixes this issue by un-registering fadump in fadump_cleanup() which is called during kexec path so that new kernel can register fadump with new valid values. Fixes: b500afff11f6 ("fadump: Invalidate registration and release reserved memory for general use.") Cc: stable@vger.kernel.org # v3.4+ Signed-off-by: Mahesh Salgaonkar Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/fadump.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index 8f0c7c5d93f2..93a6eeba3ace 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -1033,6 +1033,9 @@ void fadump_cleanup(void) init_fadump_mem_struct(&fdm, be64_to_cpu(fdm_active->cpu_state_data.destination_address)); fadump_invalidate_dump(&fdm); + } else if (fw_dump.dump_registered) { + /* Un-register Firmware-assisted dump if it was registered. */ + fadump_unregister_dump(&fdm); } } -- GitLab From 8f27499338a23a9e6eada6ab3a126c0616b21296 Mon Sep 17 00:00:00 2001 From: David Rivshin Date: Wed, 25 Apr 2018 21:15:01 +0100 Subject: [PATCH 234/604] ARM: 8764/1: kgdb: fix NUMREGBYTES so that gdb_regs[] is the correct size commit 76ed0b803a2ab793a1b27d1dfe0de7955282cd34 upstream. NUMREGBYTES (which is used as the size for gdb_regs[]) is incorrectly based on DBG_MAX_REG_NUM instead of GDB_MAX_REGS. DBG_MAX_REG_NUM is the number of total registers, while GDB_MAX_REGS is the number of 'unsigned longs' it takes to serialize those registers. Since FP registers require 3 'unsigned longs' each, DBG_MAX_REG_NUM is smaller than GDB_MAX_REGS. This causes GDB 8.0 give the following error on connect: "Truncated register 19 in remote 'g' packet" This also causes the register serialization/deserialization logic to overflow gdb_regs[], overwriting whatever follows. Fixes: 834b2964b7ab ("kgdb,arm: fix register dump") Cc: # 2.6.37+ Signed-off-by: David Rivshin Acked-by: Rabin Vincent Tested-by: Daniel Thompson Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/kgdb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h index 0a9d5dd93294..6949c7d4481c 100644 --- a/arch/arm/include/asm/kgdb.h +++ b/arch/arm/include/asm/kgdb.h @@ -76,7 +76,7 @@ extern int kgdb_fault_expected; #define KGDB_MAX_NO_CPUS 1 #define BUFMAX 400 -#define NUMREGBYTES (DBG_MAX_REG_NUM << 2) +#define NUMREGBYTES (GDB_MAX_REGS << 2) #define NUMCRITREGBYTES (32 << 2) #define _R0 0 -- GitLab From 12942d52f23d79df25814730f559c54150ab3e84 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 22 Jun 2018 10:25:25 +0100 Subject: [PATCH 235/604] arm64: kpti: Use early_param for kpti= command-line option commit b5b7dd647f2d21b93f734ce890671cd908e69b0a upstream. We inspect __kpti_forced early on as part of the cpufeature enable callback which remaps the swapper page table using non-global entries. Ensure that __kpti_forced has been updated to reflect the kpti= command-line option before we start using it. Fixes: ea1e3de85e94 ("arm64: entry: Add fake CPU feature for unmapping the kernel at EL0") Cc: # 4.16.x- Reported-by: Wei Xu Tested-by: Sudeep Holla Tested-by: Wei Xu Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/cpufeature.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 7959d2c92010..625c2b240ffb 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -826,7 +826,7 @@ static int __init parse_kpti(char *str) __kpti_forced = enabled ? 1 : -1; return 0; } -__setup("kpti=", parse_kpti); +early_param("kpti", parse_kpti); #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */ static const struct arm64_cpu_capabilities arm64_features[] = { -- GitLab From fb6786ce77ac4d65351832412703b8793e122f12 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 22 Jun 2018 16:23:45 +0100 Subject: [PATCH 236/604] arm64: mm: Ensure writes to swapper are ordered wrt subsequent cache maintenance commit 71c8fc0c96abf8e53e74ed4d891d671e585f9076 upstream. When rewriting swapper using nG mappings, we must performance cache maintenance around each page table access in order to avoid coherency problems with the host's cacheable alias under KVM. To ensure correct ordering of the maintenance with respect to Device memory accesses made with the Stage-1 MMU disabled, DMBs need to be added between the maintenance and the corresponding memory access. This patch adds a missing DMB between writing a new page table entry and performing a clean+invalidate on the same line. Fixes: f992b4dfd58b ("arm64: kpti: Add ->enable callback to remap swapper using nG mappings") Cc: # 4.16.x- Acked-by: Mark Rutland Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman --- arch/arm64/mm/proc.S | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index 66cce2138f95..18d96d349a8b 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -186,8 +186,9 @@ ENDPROC(idmap_cpu_replace_ttbr1) .macro __idmap_kpti_put_pgtable_ent_ng, type orr \type, \type, #PTE_NG // Same bit for blocks and pages - str \type, [cur_\()\type\()p] // Update the entry and ensure it - dc civac, cur_\()\type\()p // is visible to all CPUs. + str \type, [cur_\()\type\()p] // Update the entry and ensure + dmb sy // that it is visible to all + dc civac, cur_\()\type\()p // CPUs. .endm /* -- GitLab From f92ec84c49f91756cbdd048c1a3136f15810cd94 Mon Sep 17 00:00:00 2001 From: Stefan M Schaeckeler Date: Mon, 21 May 2018 16:26:14 -0700 Subject: [PATCH 237/604] of: unittest: for strings, account for trailing \0 in property length field commit 3b9cf7905fe3ab35ab437b5072c883e609d3498d upstream. For strings, account for trailing \0 in property length field: This is consistent with how dtc builds string properties. Function __of_prop_dup() would misbehave on such properties as it duplicates properties based on the property length field creating new string values without trailing \0s. Signed-off-by: Stefan M Schaeckeler Reviewed-by: Frank Rowand Tested-by: Frank Rowand Cc: Signed-off-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/of/unittest.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 53c83d66eb7e..90b5a898d6b1 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -155,20 +155,20 @@ static void __init of_unittest_dynamic(void) /* Add a new property - should pass*/ prop->name = "new-property"; prop->value = "new-property-data"; - prop->length = strlen(prop->value); + prop->length = strlen(prop->value) + 1; unittest(of_add_property(np, prop) == 0, "Adding a new property failed\n"); /* Try to add an existing property - should fail */ prop++; prop->name = "new-property"; prop->value = "new-property-data-should-fail"; - prop->length = strlen(prop->value); + prop->length = strlen(prop->value) + 1; unittest(of_add_property(np, prop) != 0, "Adding an existing property should have failed\n"); /* Try to modify an existing property - should pass */ prop->value = "modify-property-data-should-pass"; - prop->length = strlen(prop->value); + prop->length = strlen(prop->value) + 1; unittest(of_update_property(np, prop) == 0, "Updating an existing property should have passed\n"); @@ -176,7 +176,7 @@ static void __init of_unittest_dynamic(void) prop++; prop->name = "modify-property"; prop->value = "modify-missing-property-data-should-pass"; - prop->length = strlen(prop->value); + prop->length = strlen(prop->value) + 1; unittest(of_update_property(np, prop) == 0, "Updating a missing property should have passed\n"); -- GitLab From 9321e8303406e2a194ba8e88fa8b57ee360f3f00 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Fri, 18 May 2018 17:07:01 -0700 Subject: [PATCH 238/604] IB/qib: Fix DMA api warning with debug kernel commit 0252f73334f9ef68868e4684200bea3565a4fcee upstream. The following error occurs in a debug build when running MPI PSM: [ 307.415911] WARNING: CPU: 4 PID: 23867 at lib/dma-debug.c:1158 check_unmap+0x4ee/0xa20 [ 307.455661] ib_qib 0000:05:00.0: DMA-API: device driver failed to check map error[device address=0x00000000df82b000] [size=4096 bytes] [mapped as page] [ 307.517494] Modules linked in: [ 307.531584] ib_isert iscsi_target_mod ib_srpt target_core_mod rpcrdma sunrpc ib_srp scsi_transport_srp scsi_tgt ib_iser libiscsi ib_ipoib scsi_transport_iscsi rdma_ucm ib_ucm ib_uverbs ib_umad rdma_cm ib_cm iw_cm ib_qib intel_powerclamp coretemp rdmavt intel_rapl iosf_mbi kvm_intel kvm irqbypass crc32_pclmul ghash_clmulni_intel ipmi_ssif ib_core aesni_intel sg ipmi_si lrw gf128mul dca glue_helper ipmi_devintf iTCO_wdt gpio_ich hpwdt iTCO_vendor_support ablk_helper hpilo acpi_power_meter cryptd ipmi_msghandler ie31200_edac shpchp pcc_cpufreq lpc_ich pcspkr ip_tables xfs libcrc32c sd_mod crc_t10dif crct10dif_generic mgag200 i2c_algo_bit drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops ttm ahci crct10dif_pclmul crct10dif_common drm crc32c_intel libahci tg3 libata serio_raw ptp i2c_core [ 307.846113] pps_core dm_mirror dm_region_hash dm_log dm_mod [ 307.866505] CPU: 4 PID: 23867 Comm: mpitests-IMB-MP Kdump: loaded Not tainted 3.10.0-862.el7.x86_64.debug #1 [ 307.911178] Hardware name: HP ProLiant DL320e Gen8, BIOS J05 11/09/2013 [ 307.944206] Call Trace: [ 307.956973] [] dump_stack+0x19/0x1b [ 307.982201] [] __warn+0xd8/0x100 [ 308.005999] [] warn_slowpath_fmt+0x5f/0x80 [ 308.034260] [] check_unmap+0x4ee/0xa20 [ 308.060801] [] ? page_add_file_rmap+0x2a/0x1d0 [ 308.090689] [] debug_dma_unmap_page+0x9d/0xb0 [ 308.120155] [] ? might_fault+0xa0/0xb0 [ 308.146656] [] qib_tid_free.isra.14+0x215/0x2a0 [ib_qib] [ 308.180739] [] qib_write+0x894/0x1280 [ib_qib] [ 308.210733] [] ? __inode_security_revalidate+0x70/0x80 [ 308.244837] [] ? security_file_permission+0x27/0xb0 [ 308.266025] qib_ib0.8006: multicast join failed for ff12:401b:8006:0000:0000:0000:ffff:ffff, status -22 [ 308.323421] [] vfs_write+0xc3/0x1f0 [ 308.347077] [] ? fget_light+0xfc/0x510 [ 308.372533] [] SyS_write+0x8a/0x100 [ 308.396456] [] system_call_fastpath+0x1c/0x21 The code calls a qib_map_page() which has never correctly tested for a mapping error. Fix by testing for pci_dma_mapping_error() in all cases and properly handling the failure in the caller. Additionally, streamline qib_map_page() arguments to satisfy just the single caller. Cc: Reviewed-by: Alex Estrin Tested-by: Don Dutile Reviewed-by: Don Dutile Signed-off-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/qib/qib.h | 3 +-- drivers/infiniband/hw/qib/qib_file_ops.c | 10 +++++++--- drivers/infiniband/hw/qib/qib_user_pages.c | 20 ++++++++++++-------- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h index a3e21a25cea5..0078f2ad9b92 100644 --- a/drivers/infiniband/hw/qib/qib.h +++ b/drivers/infiniband/hw/qib/qib.h @@ -1448,8 +1448,7 @@ u64 qib_sps_ints(void); /* * dma_addr wrappers - all 0's invalid for hw */ -dma_addr_t qib_map_page(struct pci_dev *, struct page *, unsigned long, - size_t, int); +int qib_map_page(struct pci_dev *d, struct page *p, dma_addr_t *daddr); const char *qib_get_unit_name(int unit); const char *qib_get_card_name(struct rvt_dev_info *rdi); struct pci_dev *qib_get_pci_dev(struct rvt_dev_info *rdi); diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index 382466a90da7..cc6a92316c7c 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -364,6 +364,8 @@ static int qib_tid_update(struct qib_ctxtdata *rcd, struct file *fp, goto done; } for (i = 0; i < cnt; i++, vaddr += PAGE_SIZE) { + dma_addr_t daddr; + for (; ntids--; tid++) { if (tid == tidcnt) tid = 0; @@ -380,12 +382,14 @@ static int qib_tid_update(struct qib_ctxtdata *rcd, struct file *fp, ret = -ENOMEM; break; } + ret = qib_map_page(dd->pcidev, pagep[i], &daddr); + if (ret) + break; + tidlist[i] = tid + tidoff; /* we "know" system pages and TID pages are same size */ dd->pageshadow[ctxttid + tid] = pagep[i]; - dd->physshadow[ctxttid + tid] = - qib_map_page(dd->pcidev, pagep[i], 0, PAGE_SIZE, - PCI_DMA_FROMDEVICE); + dd->physshadow[ctxttid + tid] = daddr; /* * don't need atomic or it's overhead */ diff --git a/drivers/infiniband/hw/qib/qib_user_pages.c b/drivers/infiniband/hw/qib/qib_user_pages.c index 75f08624ac05..4715edff5488 100644 --- a/drivers/infiniband/hw/qib/qib_user_pages.c +++ b/drivers/infiniband/hw/qib/qib_user_pages.c @@ -98,23 +98,27 @@ static int __qib_get_user_pages(unsigned long start_page, size_t num_pages, * * I'm sure we won't be so lucky with other iommu's, so FIXME. */ -dma_addr_t qib_map_page(struct pci_dev *hwdev, struct page *page, - unsigned long offset, size_t size, int direction) +int qib_map_page(struct pci_dev *hwdev, struct page *page, dma_addr_t *daddr) { dma_addr_t phys; - phys = pci_map_page(hwdev, page, offset, size, direction); + phys = pci_map_page(hwdev, page, 0, PAGE_SIZE, PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(hwdev, phys)) + return -ENOMEM; - if (phys == 0) { - pci_unmap_page(hwdev, phys, size, direction); - phys = pci_map_page(hwdev, page, offset, size, direction); + if (!phys) { + pci_unmap_page(hwdev, phys, PAGE_SIZE, PCI_DMA_FROMDEVICE); + phys = pci_map_page(hwdev, page, 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(hwdev, phys)) + return -ENOMEM; /* * FIXME: If we get 0 again, we should keep this page, * map another, then free the 0 page. */ } - - return phys; + *daddr = phys; + return 0; } /** -- GitLab From 9cac0a08e476775df3ae5f90730a766ea01b6232 Mon Sep 17 00:00:00 2001 From: Alex Estrin Date: Wed, 2 May 2018 06:43:15 -0700 Subject: [PATCH 239/604] IB/{hfi1, qib}: Add handling of kernel restart commit 8d3e71136a080d007620472f50c7b3e63ba0f5cf upstream. A warm restart will fail to unload the driver, leaving link state potentially flapping up to the point the BIOS resets the adapter. Correct the issue by hooking the shutdown pci method, which will bring port down. Cc: # 4.9.x Reviewed-by: Mike Marciniszyn Signed-off-by: Alex Estrin Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/hfi1/hfi.h | 1 + drivers/infiniband/hw/hfi1/init.c | 13 +++++++++++++ drivers/infiniband/hw/qib/qib.h | 1 + drivers/infiniband/hw/qib/qib_init.c | 13 +++++++++++++ 4 files changed, 28 insertions(+) diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index a3279f3d2578..a79d9b340cfa 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -1631,6 +1631,7 @@ struct cc_state *get_cc_state_protected(struct hfi1_pportdata *ppd) #define HFI1_HAS_SDMA_TIMEOUT 0x8 #define HFI1_HAS_SEND_DMA 0x10 /* Supports Send DMA */ #define HFI1_FORCED_FREEZE 0x80 /* driver forced freeze mode */ +#define HFI1_SHUTDOWN 0x100 /* device is shutting down */ /* IB dword length mask in PBC (lower 11 bits); same for all chips */ #define HFI1_PBC_LENGTH_MASK ((1 << 11) - 1) diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c index ae1f90ddd4e8..c81c44525dd5 100644 --- a/drivers/infiniband/hw/hfi1/init.c +++ b/drivers/infiniband/hw/hfi1/init.c @@ -857,6 +857,10 @@ static void shutdown_device(struct hfi1_devdata *dd) unsigned pidx; int i; + if (dd->flags & HFI1_SHUTDOWN) + return; + dd->flags |= HFI1_SHUTDOWN; + for (pidx = 0; pidx < dd->num_pports; ++pidx) { ppd = dd->pport + pidx; @@ -1168,6 +1172,7 @@ void hfi1_disable_after_error(struct hfi1_devdata *dd) static void remove_one(struct pci_dev *); static int init_one(struct pci_dev *, const struct pci_device_id *); +static void shutdown_one(struct pci_dev *); #define DRIVER_LOAD_MSG "Intel " DRIVER_NAME " loaded: " #define PFX DRIVER_NAME ": " @@ -1184,6 +1189,7 @@ static struct pci_driver hfi1_pci_driver = { .name = DRIVER_NAME, .probe = init_one, .remove = remove_one, + .shutdown = shutdown_one, .id_table = hfi1_pci_tbl, .err_handler = &hfi1_pci_err_handler, }; @@ -1590,6 +1596,13 @@ static void remove_one(struct pci_dev *pdev) postinit_cleanup(dd); } +static void shutdown_one(struct pci_dev *pdev) +{ + struct hfi1_devdata *dd = pci_get_drvdata(pdev); + + shutdown_device(dd); +} + /** * hfi1_create_rcvhdrq - create a receive header queue * @dd: the hfi1_ib device diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h index 0078f2ad9b92..ef092cca092e 100644 --- a/drivers/infiniband/hw/qib/qib.h +++ b/drivers/infiniband/hw/qib/qib.h @@ -1250,6 +1250,7 @@ static inline struct qib_ibport *to_iport(struct ib_device *ibdev, u8 port) #define QIB_BADINTR 0x8000 /* severe interrupt problems */ #define QIB_DCA_ENABLED 0x10000 /* Direct Cache Access enabled */ #define QIB_HAS_QSFP 0x20000 /* device (card instance) has QSFP */ +#define QIB_SHUTDOWN 0x40000 /* device is shutting down */ /* * values for ppd->lflags (_ib_port_ related flags) diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index 1730aa839a47..caf7c5120b0a 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -878,6 +878,10 @@ static void qib_shutdown_device(struct qib_devdata *dd) struct qib_pportdata *ppd; unsigned pidx; + if (dd->flags & QIB_SHUTDOWN) + return; + dd->flags |= QIB_SHUTDOWN; + for (pidx = 0; pidx < dd->num_pports; ++pidx) { ppd = dd->pport + pidx; @@ -1223,6 +1227,7 @@ void qib_disable_after_error(struct qib_devdata *dd) static void qib_remove_one(struct pci_dev *); static int qib_init_one(struct pci_dev *, const struct pci_device_id *); +static void qib_shutdown_one(struct pci_dev *); #define DRIVER_LOAD_MSG "Intel " QIB_DRV_NAME " loaded: " #define PFX QIB_DRV_NAME ": " @@ -1240,6 +1245,7 @@ static struct pci_driver qib_driver = { .name = QIB_DRV_NAME, .probe = qib_init_one, .remove = qib_remove_one, + .shutdown = qib_shutdown_one, .id_table = qib_pci_tbl, .err_handler = &qib_pci_err_handler, }; @@ -1591,6 +1597,13 @@ static void qib_remove_one(struct pci_dev *pdev) qib_postinit_cleanup(dd); } +static void qib_shutdown_one(struct pci_dev *pdev) +{ + struct qib_devdata *dd = pci_get_drvdata(pdev); + + qib_shutdown_device(dd); +} + /** * qib_create_rcvhdrq - create a receive header queue * @dd: the qlogic_ib device -- GitLab From e355402cf19cf30e5f659ac21ddf40ccd7e5bcf0 Mon Sep 17 00:00:00 2001 From: Erez Shitrit Date: Mon, 21 May 2018 11:41:01 +0300 Subject: [PATCH 240/604] IB/mlx5: Fetch soft WQE's on fatal error state commit 7b74a83cf54a3747e22c57e25712bd70eef8acee upstream. On fatal error the driver simulates CQE's for ULPs that rely on completion of all their posted work-request. For the GSI traffic, the mlx5 has its own mechanism that sends the completions via software CQE's directly to the relevant CQ. This should be kept in fatal error too, so the driver should simulate such CQE's with the specified error state in order to complete GSI QP work requests. Without the fix the next deadlock might appears: schedule_timeout+0x274/0x350 wait_for_common+0xec/0x240 mcast_remove_one+0xd0/0x120 [ib_core] ib_unregister_device+0x12c/0x230 [ib_core] mlx5_ib_remove+0xc4/0x270 [mlx5_ib] mlx5_detach_device+0x184/0x1a0 [mlx5_core] mlx5_unload_one+0x308/0x340 [mlx5_core] mlx5_pci_err_detected+0x74/0xe0 [mlx5_core] Cc: # 4.7 Fixes: 89ea94a7b6c4 ("IB/mlx5: Reset flow support for IB kernel ULPs") Signed-off-by: Erez Shitrit Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx5/cq.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index fc62a7ded734..a19ebb19952e 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -645,7 +645,7 @@ static int mlx5_poll_one(struct mlx5_ib_cq *cq, } static int poll_soft_wc(struct mlx5_ib_cq *cq, int num_entries, - struct ib_wc *wc) + struct ib_wc *wc, bool is_fatal_err) { struct mlx5_ib_dev *dev = to_mdev(cq->ibcq.device); struct mlx5_ib_wc *soft_wc, *next; @@ -658,6 +658,10 @@ static int poll_soft_wc(struct mlx5_ib_cq *cq, int num_entries, mlx5_ib_dbg(dev, "polled software generated completion on CQ 0x%x\n", cq->mcq.cqn); + if (unlikely(is_fatal_err)) { + soft_wc->wc.status = IB_WC_WR_FLUSH_ERR; + soft_wc->wc.vendor_err = MLX5_CQE_SYNDROME_WR_FLUSH_ERR; + } wc[npolled++] = soft_wc->wc; list_del(&soft_wc->list); kfree(soft_wc); @@ -678,12 +682,17 @@ int mlx5_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) spin_lock_irqsave(&cq->lock, flags); if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) { - mlx5_ib_poll_sw_comp(cq, num_entries, wc, &npolled); + /* make sure no soft wqe's are waiting */ + if (unlikely(!list_empty(&cq->wc_list))) + soft_polled = poll_soft_wc(cq, num_entries, wc, true); + + mlx5_ib_poll_sw_comp(cq, num_entries - soft_polled, + wc + soft_polled, &npolled); goto out; } if (unlikely(!list_empty(&cq->wc_list))) - soft_polled = poll_soft_wc(cq, num_entries, wc); + soft_polled = poll_soft_wc(cq, num_entries, wc, false); for (npolled = 0; npolled < num_entries - soft_polled; npolled++) { if (mlx5_poll_one(cq, &cur_qp, wc + soft_polled + npolled)) -- GitLab From a664281b85e01066336a0eb46bd09054c0705009 Mon Sep 17 00:00:00 2001 From: Alex Estrin Date: Tue, 15 May 2018 18:31:39 -0700 Subject: [PATCH 241/604] IB/isert: Fix for lib/dma_debug check_sync warning commit 763b69654bfb88ea3230d015e7d755ee8339f8ee upstream. The following error message occurs on a target host in a debug build during session login: [ 3524.411874] WARNING: CPU: 5 PID: 12063 at lib/dma-debug.c:1207 check_sync+0x4ec/0x5b0 [ 3524.421057] infiniband hfi1_0: DMA-API: device driver tries to sync DMA memory it has not allocated [device address=0x0000000000000000] [size=76 bytes] ......snip ..... [ 3524.535846] CPU: 5 PID: 12063 Comm: iscsi_np Kdump: loaded Not tainted 3.10.0-862.el7.x86_64.debug #1 [ 3524.546764] Hardware name: Dell Inc. PowerEdge R430/03XKDV, BIOS 1.2.6 06/08/2015 [ 3524.555740] Call Trace: [ 3524.559102] [] dump_stack+0x19/0x1b [ 3524.565477] [] __warn+0xd8/0x100 [ 3524.571557] [] warn_slowpath_fmt+0x5f/0x80 [ 3524.578610] [] check_sync+0x4ec/0x5b0 [ 3524.585177] [] ? set_cpus_allowed_ptr+0x5f/0x1c0 [ 3524.592812] [] debug_dma_sync_single_for_cpu+0x80/0x90 [ 3524.601029] [] ? x2apic_send_IPI_mask+0x13/0x20 [ 3524.608574] [] ? native_smp_send_reschedule+0x5b/0x80 [ 3524.616699] [] ? resched_curr+0xf6/0x140 [ 3524.623567] [] isert_create_send_desc.isra.26+0xe0/0x110 [ib_isert] [ 3524.633060] [] isert_put_login_tx+0x55/0x8b0 [ib_isert] [ 3524.641383] [] ? try_to_wake_up+0x1a4/0x430 [ 3524.648561] [] iscsi_target_do_tx_login_io+0xdd/0x230 [iscsi_target_mod] [ 3524.658557] [] iscsi_target_do_login+0x1a7/0x600 [iscsi_target_mod] [ 3524.668084] [] ? kstrdup+0x49/0x60 [ 3524.674420] [] iscsi_target_start_negotiation+0x56/0xc0 [iscsi_target_mod] [ 3524.684656] [] __iscsi_target_login_thread+0x90e/0x1070 [iscsi_target_mod] [ 3524.694901] [] ? __iscsi_target_login_thread+0x1070/0x1070 [iscsi_target_mod] [ 3524.705446] [] ? __iscsi_target_login_thread+0x1070/0x1070 [iscsi_target_mod] [ 3524.715976] [] iscsi_target_login_thread+0x28/0x60 [iscsi_target_mod] [ 3524.725739] [] kthread+0xef/0x100 [ 3524.732007] [] ? insert_kthread_work+0x80/0x80 [ 3524.739540] [] ret_from_fork_nospec_begin+0x21/0x21 [ 3524.747558] [] ? insert_kthread_work+0x80/0x80 [ 3524.755088] ---[ end trace 23f8bf9238bd1ed8 ]--- [ 3595.510822] iSCSI/iqn.1994-05.com.redhat:537fa56299: Unsupported SCSI Opcode 0xa3, sending CHECK_CONDITION. The code calls dma_sync on login_tx_desc->dma_addr prior to initializing it with dma-mapped address. login_tx_desc is a part of iser_conn structure and is used only once during login negotiation, so the issue is fixed by eliminating dma_sync call for this buffer using a special case routine. Cc: Reviewed-by: Mike Marciniszyn Reviewed-by: Don Dutile Signed-off-by: Alex Estrin Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/isert/ib_isert.c | 26 ++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index b879d21b7548..16e56bfd4e2f 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -879,15 +879,9 @@ isert_login_post_send(struct isert_conn *isert_conn, struct iser_tx_desc *tx_des } static void -isert_create_send_desc(struct isert_conn *isert_conn, - struct isert_cmd *isert_cmd, - struct iser_tx_desc *tx_desc) +__isert_create_send_desc(struct isert_device *device, + struct iser_tx_desc *tx_desc) { - struct isert_device *device = isert_conn->device; - struct ib_device *ib_dev = device->ib_device; - - ib_dma_sync_single_for_cpu(ib_dev, tx_desc->dma_addr, - ISER_HEADERS_LEN, DMA_TO_DEVICE); memset(&tx_desc->iser_header, 0, sizeof(struct iser_ctrl)); tx_desc->iser_header.flags = ISCSI_CTRL; @@ -900,6 +894,20 @@ isert_create_send_desc(struct isert_conn *isert_conn, } } +static void +isert_create_send_desc(struct isert_conn *isert_conn, + struct isert_cmd *isert_cmd, + struct iser_tx_desc *tx_desc) +{ + struct isert_device *device = isert_conn->device; + struct ib_device *ib_dev = device->ib_device; + + ib_dma_sync_single_for_cpu(ib_dev, tx_desc->dma_addr, + ISER_HEADERS_LEN, DMA_TO_DEVICE); + + __isert_create_send_desc(device, tx_desc); +} + static int isert_init_tx_hdrs(struct isert_conn *isert_conn, struct iser_tx_desc *tx_desc) @@ -987,7 +995,7 @@ isert_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login, struct iser_tx_desc *tx_desc = &isert_conn->login_tx_desc; int ret; - isert_create_send_desc(isert_conn, NULL, tx_desc); + __isert_create_send_desc(device, tx_desc); memcpy(&tx_desc->iscsi_header, &login->rsp[0], sizeof(struct iscsi_hdr)); -- GitLab From 52e167187be8b584673204f6d87b07aff7725e47 Mon Sep 17 00:00:00 2001 From: Max Gurtovoy Date: Thu, 31 May 2018 11:05:23 +0300 Subject: [PATCH 242/604] IB/isert: fix T10-pi check mask setting commit 0e12af84cdd3056460f928adc164f9e87f4b303b upstream. A copy/paste bug (probably) caused setting of an app_tag check mask in case where a ref_tag check was needed. Fixes: 38a2d0d429f1 ("IB/isert: convert to the generic RDMA READ/WRITE API") Fixes: 9e961ae73c2c ("IB/isert: Support T10-PI protected transactions") Cc: stable@vger.kernel.org Reviewed-by: Christoph Hellwig Reviewed-by: Sagi Grimberg Reviewed-by: Martin K. Petersen Signed-off-by: Max Gurtovoy Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/isert/ib_isert.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 16e56bfd4e2f..02a5e2d7e574 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -2090,7 +2090,7 @@ isert_set_sig_attrs(struct se_cmd *se_cmd, struct ib_sig_attrs *sig_attrs) sig_attrs->check_mask = (se_cmd->prot_checks & TARGET_DIF_CHECK_GUARD ? 0xc0 : 0) | - (se_cmd->prot_checks & TARGET_DIF_CHECK_REFTAG ? 0x30 : 0) | + (se_cmd->prot_checks & TARGET_DIF_CHECK_APPTAG ? 0x30 : 0) | (se_cmd->prot_checks & TARGET_DIF_CHECK_REFTAG ? 0x0f : 0); return 0; } -- GitLab From afe249e3e38d51e58eba9b6992646a1f8070883d Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 29 May 2018 14:56:14 +0300 Subject: [PATCH 243/604] RDMA/mlx4: Discard unknown SQP work requests commit 6b1ca7ece15e94251d1d0d919f813943e4a58059 upstream. There is no need to crash the machine if unknown work request was received in SQP MAD. Cc: # 3.6 Fixes: 37bfc7c1e83f ("IB/mlx4: SR-IOV multiplex and demultiplex MADs") Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx4/mad.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index 18d309e40f1b..d9323d7c479c 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -1897,7 +1897,6 @@ static void mlx4_ib_sqp_comp_worker(struct work_struct *work) "buf:%lld\n", wc.wr_id); break; default: - BUG_ON(1); break; } } else { -- GitLab From e9dc5dce0925ea4412345ca034bba9a252de2783 Mon Sep 17 00:00:00 2001 From: Tokunori Ikegami Date: Wed, 30 May 2018 18:32:26 +0900 Subject: [PATCH 244/604] mtd: cfi_cmdset_0002: Change write buffer to check correct value commit dfeae1073583dc35c33b32150e18b7048bbb37e6 upstream. For the word write it is checked if the chip has the correct value. But it is not checked for the write buffer as only checked if ready. To make sure for the write buffer change to check the value. It is enough as this patch is only checking the last written word. Since it is described by data sheets to check the operation status. Signed-off-by: Tokunori Ikegami Reviewed-by: Joakim Tjernlund Cc: Chris Packham Cc: Brian Norris Cc: David Woodhouse Cc: Boris Brezillon Cc: Marek Vasut Cc: Richard Weinberger Cc: Cyrille Pitchen Cc: linux-mtd@lists.infradead.org Cc: stable@vger.kernel.org Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/chips/cfi_cmdset_0002.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 107c05b3ddbb..68eaa5eb15d5 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -1876,7 +1876,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, if (time_after(jiffies, timeo) && !chip_ready(map, adr)) break; - if (chip_ready(map, adr)) { + if (chip_good(map, adr, datum)) { xip_enable(map, chip, adr); goto op_done; } -- GitLab From 552eacd58ee4c930f313f8e01f4cee75fc48afed Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Wed, 6 Jun 2018 12:13:27 +0200 Subject: [PATCH 245/604] mtd: cfi_cmdset_0002: Use right chip in do_ppb_xxlock() commit f93aa8c4de307069c270b2d81741961162bead6c upstream. do_ppb_xxlock() fails to add chip->start when querying for lock status (and chip_ready test), which caused false status reports. Fix that by adding adr += chip->start and adjust call sites accordingly. Fixes: 1648eaaa1575 ("mtd: cfi_cmdset_0002: Support Persistent Protection Bits (PPB) locking") Cc: stable@vger.kernel.org Signed-off-by: Joakim Tjernlund Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/chips/cfi_cmdset_0002.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 68eaa5eb15d5..2132bd76f972 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -2549,8 +2549,9 @@ static int __maybe_unused do_ppb_xxlock(struct map_info *map, unsigned long timeo; int ret; + adr += chip->start; mutex_lock(&chip->mutex); - ret = get_chip(map, chip, adr + chip->start, FL_LOCKING); + ret = get_chip(map, chip, adr, FL_LOCKING); if (ret) { mutex_unlock(&chip->mutex); return ret; @@ -2568,8 +2569,8 @@ static int __maybe_unused do_ppb_xxlock(struct map_info *map, if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) { chip->state = FL_LOCKING; - map_write(map, CMD(0xA0), chip->start + adr); - map_write(map, CMD(0x00), chip->start + adr); + map_write(map, CMD(0xA0), adr); + map_write(map, CMD(0x00), adr); } else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) { /* * Unlocking of one specific sector is not supported, so we @@ -2607,7 +2608,7 @@ static int __maybe_unused do_ppb_xxlock(struct map_info *map, map_write(map, CMD(0x00), chip->start); chip->state = FL_READY; - put_chip(map, chip, adr + chip->start); + put_chip(map, chip, adr); mutex_unlock(&chip->mutex); return ret; -- GitLab From 0bf4e48c20ca447e577c77bfc9205f1c8890c65d Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Wed, 6 Jun 2018 12:13:28 +0200 Subject: [PATCH 246/604] mtd: cfi_cmdset_0002: fix SEGV unlocking multiple chips commit 5fdfc3dbad099281bf027a353d5786c09408a8e5 upstream. cfi_ppb_unlock() tries to relock all sectors that were locked before unlocking the whole chip. This locking used the chip start address + the FULL offset from the first flash chip, thereby forming an illegal address. Fix that by using the chip offset(adr). Fixes: 1648eaaa1575 ("mtd: cfi_cmdset_0002: Support Persistent Protection Bits (PPB) locking") Cc: stable@vger.kernel.org Signed-off-by: Joakim Tjernlund Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/chips/cfi_cmdset_0002.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 2132bd76f972..57b7fd8b930b 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -2531,7 +2531,7 @@ static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) struct ppb_lock { struct flchip *chip; - loff_t offset; + unsigned long adr; int locked; }; @@ -2667,7 +2667,7 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, */ if ((adr < ofs) || (adr >= (ofs + len))) { sect[sectors].chip = &cfi->chips[chipnum]; - sect[sectors].offset = offset; + sect[sectors].adr = adr; sect[sectors].locked = do_ppb_xxlock( map, &cfi->chips[chipnum], adr, 0, DO_XXLOCK_ONEBLOCK_GETLOCK); @@ -2711,7 +2711,7 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, */ for (i = 0; i < sectors; i++) { if (sect[i].locked) - do_ppb_xxlock(map, sect[i].chip, sect[i].offset, 0, + do_ppb_xxlock(map, sect[i].chip, sect[i].adr, 0, DO_XXLOCK_ONEBLOCK_LOCK); } -- GitLab From b4e24c2842e15f221ac3527af781d7b8940b5cfb Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Wed, 6 Jun 2018 12:13:29 +0200 Subject: [PATCH 247/604] mtd: cfi_cmdset_0002: Fix unlocking requests crossing a chip boudary commit 0cd8116f172eed018907303dbff5c112690eeb91 upstream. The "sector is in requested range" test used to determine whether sectors should be re-locked or not is done on a variable that is reset everytime we cross a chip boundary, which can lead to some blocks being re-locked while the caller expect them to be unlocked. Fix the check to make sure this cannot happen. Fixes: 1648eaaa1575 ("mtd: cfi_cmdset_0002: Support Persistent Protection Bits (PPB) locking") Cc: stable@vger.kernel.org Signed-off-by: Joakim Tjernlund Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/chips/cfi_cmdset_0002.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 57b7fd8b930b..6c042a2439e8 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -2665,7 +2665,7 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, * sectors shall be unlocked, so lets keep their locking * status at "unlocked" (locked=0) for the final re-locking. */ - if ((adr < ofs) || (adr >= (ofs + len))) { + if ((offset < ofs) || (offset >= (ofs + len))) { sect[sectors].chip = &cfi->chips[chipnum]; sect[sectors].adr = adr; sect[sectors].locked = do_ppb_xxlock( -- GitLab From 5fdb3c468b515694159583d01a3154e0ffa4a81f Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Wed, 6 Jun 2018 12:13:30 +0200 Subject: [PATCH 248/604] mtd: cfi_cmdset_0002: Avoid walking all chips when unlocking. commit f1ce87f6080b1dda7e7b1eda3da332add19d87b9 upstream. cfi_ppb_unlock() walks all flash chips when unlocking sectors, avoid walking chips unaffected by the unlock operation. Fixes: 1648eaaa1575 ("mtd: cfi_cmdset_0002: Support Persistent Protection Bits (PPB) locking") Cc: stable@vger.kernel.org Signed-off-by: Joakim Tjernlund Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/chips/cfi_cmdset_0002.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 6c042a2439e8..33d025e42793 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -2681,6 +2681,8 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, i++; if (adr >> cfi->chipshift) { + if (offset >= (ofs + len)) + break; adr = 0; chipnum++; -- GitLab From 83f9549d650b477b46fc070461f82ef536eae702 Mon Sep 17 00:00:00 2001 From: Tokunori Ikegami Date: Sun, 3 Jun 2018 23:02:01 +0900 Subject: [PATCH 249/604] MIPS: BCM47XX: Enable 74K Core ExternalSync for PCIe erratum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 2a027b47dba6b77ab8c8e47b589ae9bbc5ac6175 upstream. The erratum and workaround are described by BCM5300X-ES300-RDS.pdf as below. R10: PCIe Transactions Periodically Fail Description: The BCM5300X PCIe does not maintain transaction ordering. This may cause PCIe transaction failure. Fix Comment: Add a dummy PCIe configuration read after a PCIe configuration write to ensure PCIe configuration access ordering. Set ES bit of CP0 configu7 register to enable sync function so that the sync instruction is functional. Resolution: hndpci.c: extpci_write_config() hndmips.c: si_mips_init() mipsinc.h CONF7_ES This is fixed by the CFE MIPS bcmsi chipset driver also for BCM47XX. Also the dummy PCIe configuration read is already implemented in the Linux BCMA driver. Enable ExternalSync in Config7 when CONFIG_BCMA_DRIVER_PCI_HOSTMODE=y too so that the sync instruction is externalised. Signed-off-by: Tokunori Ikegami Reviewed-by: Paul Burton Acked-by: Hauke Mehrtens Cc: Chris Packham Cc: RafaÅ‚ MiÅ‚ecki Cc: linux-mips@linux-mips.org Cc: stable@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/19461/ Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman --- arch/mips/bcm47xx/setup.c | 6 ++++++ arch/mips/include/asm/mipsregs.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 6054d49e608e..8c9cbf13d32a 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -212,6 +212,12 @@ static int __init bcm47xx_cpu_fixes(void) */ if (bcm47xx_bus.bcma.bus.chipinfo.id == BCMA_CHIP_ID_BCM4706) cpu_wait = NULL; + + /* + * BCM47XX Erratum "R10: PCIe Transactions Periodically Fail" + * Enable ExternalSync for sync instruction to take effect + */ + set_c0_config7(MIPS_CONF7_ES); break; #endif } diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index df78b2ca70eb..22a6782f84f5 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -663,6 +663,8 @@ #define MIPS_CONF7_WII (_ULCAST_(1) << 31) #define MIPS_CONF7_RPS (_ULCAST_(1) << 2) +/* ExternalSync */ +#define MIPS_CONF7_ES (_ULCAST_(1) << 8) #define MIPS_CONF7_IAR (_ULCAST_(1) << 10) #define MIPS_CONF7_AR (_ULCAST_(1) << 16) @@ -2641,6 +2643,7 @@ __BUILD_SET_C0(status) __BUILD_SET_C0(cause) __BUILD_SET_C0(config) __BUILD_SET_C0(config5) +__BUILD_SET_C0(config7) __BUILD_SET_C0(intcontrol) __BUILD_SET_C0(intctl) __BUILD_SET_C0(srsmap) -- GitLab From 5e1deade6064d088ad4852f9a2299eeeefdfe3d2 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Wed, 25 Apr 2018 14:27:37 -0600 Subject: [PATCH 250/604] PCI: Add ACS quirk for Intel 7th & 8th Gen mobile commit e8440f4bfedc623bee40c84797ac78d9303d0db6 upstream. The specification update indicates these have the same errata for implementing non-standard ACS capabilities. Signed-off-by: Alex Williamson Signed-off-by: Bjorn Helgaas CC: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index b55f9179c94e..c7a695c2303a 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4225,11 +4225,24 @@ static int pci_quirk_qcom_rp_acs(struct pci_dev *dev, u16 acs_flags) * 0xa290-0xa29f PCI Express Root port #{0-16} * 0xa2e7-0xa2ee PCI Express Root port #{17-24} * + * Mobile chipsets are also affected, 7th & 8th Generation + * Specification update confirms ACS errata 22, status no fix: (7th Generation + * Intel Processor Family I/O for U/Y Platforms and 8th Generation Intel + * Processor Family I/O for U Quad Core Platforms Specification Update, + * August 2017, Revision 002, Document#: 334660-002)[6] + * Device IDs from I/O datasheet: (7th Generation Intel Processor Family I/O + * for U/Y Platforms and 8th Generation Intel ® Processor Family I/O for U + * Quad Core Platforms, Vol 1 of 2, August 2017, Document#: 334658-003)[7] + * + * 0x9d10-0x9d1b PCI Express Root port #{1-12} + * * [1] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-2.html * [2] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-1.html * [3] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-spec-update.html * [4] http://www.intel.com/content/www/us/en/chipsets/200-series-chipset-pch-spec-update.html * [5] http://www.intel.com/content/www/us/en/chipsets/200-series-chipset-pch-datasheet-vol-1.html + * [6] https://www.intel.com/content/www/us/en/processors/core/7th-gen-core-family-mobile-u-y-processor-lines-i-o-spec-update.html + * [7] https://www.intel.com/content/www/us/en/processors/core/7th-gen-core-family-mobile-u-y-processor-lines-i-o-datasheet-vol-1.html */ static bool pci_quirk_intel_spt_pch_acs_match(struct pci_dev *dev) { @@ -4239,6 +4252,7 @@ static bool pci_quirk_intel_spt_pch_acs_match(struct pci_dev *dev) switch (dev->device) { case 0xa110 ... 0xa11f: case 0xa167 ... 0xa16a: /* Sunrise Point */ case 0xa290 ... 0xa29f: case 0xa2e7 ... 0xa2ee: /* Union Point */ + case 0x9d10 ... 0x9d1b: /* 7th & 8th Gen Mobile */ return true; } -- GitLab From 0d3d58337d4bd414d069c1f4d6330e02ef2ecd1e Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 27 Apr 2018 13:06:30 -0500 Subject: [PATCH 251/604] PCI: Add ACS quirk for Intel 300 series commit f154a718e6cc0d834f5ac4dc4c3b174e65f3659e upstream. Intel 300 series chipset still has the same ACS issue as the previous generations so extend the ACS quirk to cover it as well. Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas CC: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index c7a695c2303a..a05d143ac43b 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4236,6 +4236,11 @@ static int pci_quirk_qcom_rp_acs(struct pci_dev *dev, u16 acs_flags) * * 0x9d10-0x9d1b PCI Express Root port #{1-12} * + * The 300 series chipset suffers from the same bug so include those root + * ports here as well. + * + * 0xa32c-0xa343 PCI Express Root port #{0-24} + * * [1] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-2.html * [2] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-1.html * [3] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-spec-update.html @@ -4253,6 +4258,7 @@ static bool pci_quirk_intel_spt_pch_acs_match(struct pci_dev *dev) case 0xa110 ... 0xa11f: case 0xa167 ... 0xa16a: /* Sunrise Point */ case 0xa290 ... 0xa29f: case 0xa2e7 ... 0xa2ee: /* Union Point */ case 0x9d10 ... 0x9d1b: /* 7th & 8th Gen Mobile */ + case 0xa32c ... 0xa343: /* 300 series */ return true; } -- GitLab From ca558fb836d3b04fbda144fa22e295d5f41bc2de Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 23 May 2018 17:14:39 -0500 Subject: [PATCH 252/604] PCI: pciehp: Clear Presence Detect and Data Link Layer Status Changed on resume commit 13c65840feab8109194f9490c9870587173cb29d upstream. After a suspend/resume cycle the Presence Detect or Data Link Layer Status Changed bits might be set. If we don't clear them those events will not fire anymore and nothing happens for instance when a device is now hot-unplugged. Fix this by clearing those bits in a newly introduced function pcie_reenable_notification(). This should be fine because immediately after, we check if the adapter is still present by reading directly from the status register. Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp.h | 2 +- drivers/pci/hotplug/pciehp_core.c | 2 +- drivers/pci/hotplug/pciehp_hpc.c | 13 ++++++++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 37d70b5ad22f..2bba8481beb1 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -134,7 +134,7 @@ struct controller *pcie_init(struct pcie_device *dev); int pcie_init_notification(struct controller *ctrl); int pciehp_enable_slot(struct slot *p_slot); int pciehp_disable_slot(struct slot *p_slot); -void pcie_enable_notification(struct controller *ctrl); +void pcie_reenable_notification(struct controller *ctrl); int pciehp_power_on_slot(struct slot *slot); void pciehp_power_off_slot(struct slot *slot); void pciehp_get_power_status(struct slot *slot, u8 *status); diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 7d32fa33dcef..6620b1095046 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -297,7 +297,7 @@ static int pciehp_resume(struct pcie_device *dev) ctrl = get_service_data(dev); /* reinitialize the chipset's event detection logic */ - pcie_enable_notification(ctrl); + pcie_reenable_notification(ctrl); slot = ctrl->slot; diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index d08dfc8b9ba9..8d811ea353c8 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -673,7 +673,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) return handled; } -void pcie_enable_notification(struct controller *ctrl) +static void pcie_enable_notification(struct controller *ctrl) { u16 cmd, mask; @@ -711,6 +711,17 @@ void pcie_enable_notification(struct controller *ctrl) pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd); } +void pcie_reenable_notification(struct controller *ctrl) +{ + /* + * Clear both Presence and Data Link Layer Changed to make sure + * those events still fire after we have re-enabled them. + */ + pcie_capability_write_word(ctrl->pcie->port, PCI_EXP_SLTSTA, + PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC); + pcie_enable_notification(ctrl); +} + static void pcie_disable_notification(struct controller *ctrl) { u16 mask; -- GitLab From db2baeef79d1d0ff0fac4589f8d7dc215ea36889 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Fri, 11 May 2018 19:54:19 +0900 Subject: [PATCH 253/604] printk: fix possible reuse of va_list variable commit 988a35f8da1dec5a8cd2788054d1e717be61bf25 upstream. I noticed that there is a possibility that printk_safe_log_store() causes kernel oops because "args" parameter is passed to vsnprintf() again when atomic_cmpxchg() detected that we raced. Fix this by using va_copy(). Link: http://lkml.kernel.org/r/201805112002.GIF21216.OFVHFOMLJtQFSO@I-love.SAKURA.ne.jp Cc: Peter Zijlstra Cc: Steven Rostedt Cc: dvyukov@google.com Cc: syzkaller@googlegroups.com Cc: fengguang.wu@intel.com Cc: linux-kernel@vger.kernel.org Signed-off-by: Tetsuo Handa Fixes: 42a0bb3f71383b45 ("printk/nmi: generic solution for safe printk in NMI") Cc: 4.7+ # v4.7+ Reviewed-by: Sergey Senozhatsky Signed-off-by: Petr Mladek Signed-off-by: Greg Kroah-Hartman --- kernel/printk/nmi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/printk/nmi.c b/kernel/printk/nmi.c index 16bab471c7e2..5fa65aa904d3 100644 --- a/kernel/printk/nmi.c +++ b/kernel/printk/nmi.c @@ -63,6 +63,7 @@ static int vprintk_nmi(const char *fmt, va_list args) struct nmi_seq_buf *s = this_cpu_ptr(&nmi_print_seq); int add = 0; size_t len; + va_list ap; again: len = atomic_read(&s->len); @@ -79,7 +80,9 @@ static int vprintk_nmi(const char *fmt, va_list args) if (!len) smp_rmb(); - add = vsnprintf(s->buffer + len, sizeof(s->buffer) - len, fmt, args); + va_copy(ap, args); + add = vsnprintf(s->buffer + len, sizeof(s->buffer) - len, fmt, ap); + va_end(ap); /* * Do it once again if the buffer has been flushed in the meantime. -- GitLab From 344d6159fede9a3f7c7b846c662d3744ae89d132 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Tue, 12 Jun 2018 17:54:42 +0800 Subject: [PATCH 254/604] MIPS: io: Add barrier after register read in inX() commit 18f3e95b90b28318ef35910d21c39908de672331 upstream. While a barrier is present in the outX() functions before the register write, a similar barrier is missing in the inX() functions after the register read. This could allow memory accesses following inX() to observe stale data. This patch is very similar to commit a1cc7034e33d12dc1 ("MIPS: io: Add barrier after register read in readX()"). Because war_io_reorder_wmb() is both used by writeX() and outX(), if readX() need a barrier then so does inX(). Cc: stable@vger.kernel.org Signed-off-by: Huacai Chen Patchwork: https://patchwork.linux-mips.org/patch/19516/ Signed-off-by: Paul Burton Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Cc: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/io.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index ecabc00c1e66..853b2f4954fa 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -412,6 +412,8 @@ static inline type pfx##in##bwlq##p(unsigned long port) \ __val = *__addr; \ slow; \ \ + /* prevent prefetching of coherent DMA data prematurely */ \ + rmb(); \ return pfx##ioswab##bwlq(__addr, __val); \ } -- GitLab From 8fd86587ea975c2dc324c7c5bf804619bcea22b6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 22 Jun 2018 16:33:57 +0200 Subject: [PATCH 255/604] time: Make sure jiffies_to_msecs() preserves non-zero time periods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit abcbcb80cd09cd40f2089d912764e315459b71f7 upstream. For the common cases where 1000 is a multiple of HZ, or HZ is a multiple of 1000, jiffies_to_msecs() never returns zero when passed a non-zero time period. However, if HZ > 1000 and not an integer multiple of 1000 (e.g. 1024 or 1200, as used on alpha and DECstation), jiffies_to_msecs() may return zero for small non-zero time periods. This may break code that relies on receiving back a non-zero value. jiffies_to_usecs() does not need such a fix: one jiffy can only be less than one µs if HZ > 1000000, and such large values of HZ are already rejected at build time, twice: - include/linux/jiffies.h does #error if HZ >= 12288, - kernel/time/time.c has BUILD_BUG_ON(HZ > USEC_PER_SEC). Broken since forever. Signed-off-by: Geert Uytterhoeven Signed-off-by: Thomas Gleixner Reviewed-by: Arnd Bergmann Cc: John Stultz Cc: Stephen Boyd Cc: linux-alpha@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/20180622143357.7495-1-geert@linux-m68k.org Signed-off-by: Greg Kroah-Hartman --- kernel/time/time.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/time/time.c b/kernel/time/time.c index bd62fb8e8e77..39468651a064 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -28,6 +28,7 @@ */ #include +#include #include #include #include @@ -258,9 +259,10 @@ unsigned int jiffies_to_msecs(const unsigned long j) return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC); #else # if BITS_PER_LONG == 32 - return (HZ_TO_MSEC_MUL32 * j) >> HZ_TO_MSEC_SHR32; + return (HZ_TO_MSEC_MUL32 * j + (1ULL << HZ_TO_MSEC_SHR32) - 1) >> + HZ_TO_MSEC_SHR32; # else - return (j * HZ_TO_MSEC_NUM) / HZ_TO_MSEC_DEN; + return DIV_ROUND_UP(j * HZ_TO_MSEC_NUM, HZ_TO_MSEC_DEN); # endif #endif } -- GitLab From 41b1d57a672f45f1d3a158cf28c24f1885201c9e Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Sat, 19 May 2018 14:23:54 +0200 Subject: [PATCH 256/604] X.509: unpack RSA signatureValue field from BIT STRING commit b65c32ec5a942ab3ada93a048089a938918aba7f upstream. The signatureValue field of a X.509 certificate is encoded as a BIT STRING. For RSA signatures this BIT STRING is of so-called primitive subtype, which contains a u8 prefix indicating a count of unused bits in the encoding. We have to strip this prefix from signature data, just as we already do for key data in x509_extract_key_data() function. This wasn't noticed earlier because this prefix byte is zero for RSA key sizes divisible by 8. Since BIT STRING is a big-endian encoding adding zero prefixes has no bearing on its value. The signature length, however was incorrect, which is a problem for RSA implementations that need it to be exactly correct (like AMD CCP). Signed-off-by: Maciej S. Szmigiero Fixes: c26fd69fa009 ("X.509: Add a crypto key parser for binary (DER) X.509 certificates") Cc: stable@vger.kernel.org Signed-off-by: James Morris Signed-off-by: Greg Kroah-Hartman --- crypto/asymmetric_keys/x509_cert_parser.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index ce2df8c9c583..7e6a43ffdcbe 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -249,6 +249,15 @@ int x509_note_signature(void *context, size_t hdrlen, return -EINVAL; } + if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0) { + /* Discard the BIT STRING metadata */ + if (vlen < 1 || *(const u8 *)value != 0) + return -EBADMSG; + + value++; + vlen--; + } + ctx->cert->raw_sig = value; ctx->cert->raw_sig_size = vlen; return 0; -- GitLab From 77c82917d533ce49fff2731ddaa1dbc3fbfd9551 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Mon, 11 Jun 2018 19:24:16 +0100 Subject: [PATCH 257/604] Btrfs: fix return value on rename exchange failure commit c5b4a50b74018b3677098151ec5f4fce07d5e6a0 upstream. If we failed during a rename exchange operation after starting/joining a transaction, we would end up replacing the return value, stored in the local 'ret' variable, with the return value from btrfs_end_transaction(). So this could end up returning 0 (success) to user space despite the operation having failed and aborted the transaction, because if there are multiple tasks having a reference on the transaction at the time btrfs_end_transaction() is called by the rename exchange, that function returns 0 (otherwise it returns -EIO and not the original error value). So fix this by not overwriting the return value on error after getting a transaction handle. Fixes: cdd1fedf8261 ("btrfs: add support for RENAME_EXCHANGE and RENAME_WHITEOUT") CC: stable@vger.kernel.org # 4.9+ Signed-off-by: Filipe Manana Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/inode.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index f073de65e818..23ffe27e4851 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -9561,6 +9561,7 @@ static int btrfs_rename_exchange(struct inode *old_dir, u64 new_idx = 0; u64 root_objectid; int ret; + int ret2; bool root_log_pinned = false; bool dest_log_pinned = false; @@ -9751,7 +9752,8 @@ static int btrfs_rename_exchange(struct inode *old_dir, dest_log_pinned = false; } } - ret = btrfs_end_transaction(trans, root); + ret2 = btrfs_end_transaction(trans, root); + ret = ret ? ret : ret2; out_notrans: if (new_ino == BTRFS_FIRST_FREE_OBJECTID) up_read(&dest->fs_info->subvol_sem); -- GitLab From 3fd6a73da159049bade087487256af9030423975 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Wed, 31 Jan 2018 17:09:13 -0700 Subject: [PATCH 258/604] Btrfs: fix unexpected cow in run_delalloc_nocow commit 5811375325420052fcadd944792a416a43072b7f upstream. Fstests generic/475 provides a way to fail metadata reads while checking if checksum exists for the inode inside run_delalloc_nocow(), and csum_exist_in_range() interprets error (-EIO) as inode having checksum and makes its caller enter the cow path. In case of free space inode, this ends up with a warning in cow_file_range(). The same problem applies to btrfs_cross_ref_exist() since it may also read metadata in between. With this, run_delalloc_nocow() bails out when errors occur at the two places. cc: v2.6.28+ Fixes: 17d217fe970d ("Btrfs: fix nodatasum handling in balancing code") Signed-off-by: Liu Bo Signed-off-by: David Sterba Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/inode.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 23ffe27e4851..bd036557c6bc 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1230,6 +1230,8 @@ static noinline int csum_exist_in_range(struct btrfs_root *root, list_del(&sums->list); kfree(sums); } + if (ret < 0) + return ret; return 1; } @@ -1381,10 +1383,23 @@ static noinline int run_delalloc_nocow(struct inode *inode, goto out_check; if (btrfs_extent_readonly(root, disk_bytenr)) goto out_check; - if (btrfs_cross_ref_exist(trans, root, ino, + ret = btrfs_cross_ref_exist(trans, root, ino, found_key.offset - - extent_offset, disk_bytenr)) + extent_offset, disk_bytenr); + if (ret) { + /* + * ret could be -EIO if the above fails to read + * metadata. + */ + if (ret < 0) { + if (cow_start != (u64)-1) + cur_offset = cow_start; + goto error; + } + + WARN_ON_ONCE(nolock); goto out_check; + } disk_bytenr += extent_offset; disk_bytenr += cur_offset - found_key.offset; num_bytes = min(end + 1, extent_end) - cur_offset; @@ -1402,8 +1417,20 @@ static noinline int run_delalloc_nocow(struct inode *inode, * this ensure that csum for a given extent are * either valid or do not exist. */ - if (csum_exist_in_range(root, disk_bytenr, num_bytes)) + ret = csum_exist_in_range(root, disk_bytenr, num_bytes); + if (ret) { + /* + * ret could be -EIO if the above fails to read + * metadata. + */ + if (ret < 0) { + if (cow_start != (u64)-1) + cur_offset = cow_start; + goto error; + } + WARN_ON_ONCE(nolock); goto out_check; + } if (!btrfs_inc_nocow_writers(root->fs_info, disk_bytenr)) goto out_check; -- GitLab From 0400b066ea2f8730456e607bda3896e3985c2a1a Mon Sep 17 00:00:00 2001 From: Martin Kelly Date: Mon, 26 Mar 2018 14:27:51 -0700 Subject: [PATCH 259/604] iio:buffer: make length types match kfifo types commit c043ec1ca5baae63726aae32abbe003192bc6eec upstream. Currently, we use int for buffer length and bytes_per_datum. However, kfifo uses unsigned int for length and size_t for element size. We need to make sure these matches or we will have bugs related to overflow (in the range between INT_MAX and UINT_MAX for length, for example). In addition, set_bytes_per_datum uses size_t while bytes_per_datum is an int, which would cause bugs for large values of bytes_per_datum. Change buffer length to use unsigned int and bytes_per_datum to use size_t. Signed-off-by: Martin Kelly Cc: Signed-off-by: Jonathan Cameron [bwh: Backported to 4.9: - Drop change to iio_dma_buffer_set_length() - Adjust filename, context] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/iio/buffer/kfifo_buf.c | 4 ++-- include/linux/iio/buffer.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/iio/buffer/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c index 7ef9b13262a8..e44181f9eb36 100644 --- a/drivers/iio/buffer/kfifo_buf.c +++ b/drivers/iio/buffer/kfifo_buf.c @@ -19,7 +19,7 @@ struct iio_kfifo { #define iio_to_kfifo(r) container_of(r, struct iio_kfifo, buffer) static inline int __iio_allocate_kfifo(struct iio_kfifo *buf, - int bytes_per_datum, int length) + size_t bytes_per_datum, unsigned int length) { if ((length == 0) || (bytes_per_datum == 0)) return -EINVAL; @@ -71,7 +71,7 @@ static int iio_set_bytes_per_datum_kfifo(struct iio_buffer *r, size_t bpd) return 0; } -static int iio_set_length_kfifo(struct iio_buffer *r, int length) +static int iio_set_length_kfifo(struct iio_buffer *r, unsigned int length) { /* Avoid an invalid state */ if (length < 2) diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h index 70a5164f4728..821965c90070 100644 --- a/include/linux/iio/buffer.h +++ b/include/linux/iio/buffer.h @@ -61,7 +61,7 @@ struct iio_buffer_access_funcs { int (*request_update)(struct iio_buffer *buffer); int (*set_bytes_per_datum)(struct iio_buffer *buffer, size_t bpd); - int (*set_length)(struct iio_buffer *buffer, int length); + int (*set_length)(struct iio_buffer *buffer, unsigned int length); int (*enable)(struct iio_buffer *buffer, struct iio_dev *indio_dev); int (*disable)(struct iio_buffer *buffer, struct iio_dev *indio_dev); @@ -96,8 +96,8 @@ struct iio_buffer_access_funcs { * @watermark: [INTERN] number of datums to wait for poll/read. */ struct iio_buffer { - int length; - int bytes_per_datum; + unsigned int length; + size_t bytes_per_datum; struct attribute_group *scan_el_attrs; long *scan_mask; bool scan_timestamp; -- GitLab From f0c543159a4abad4412e55db33ac730c9f21684d Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Sun, 3 Jun 2018 22:09:53 -0700 Subject: [PATCH 260/604] scsi: qla2xxx: Fix setting lower transfer speed if GPSC fails commit 413c2f33489b134e3cc65d9c3ff7861e8fdfe899 upstream. This patch prevents driver from setting lower default speed of 1 GB/sec, if the switch does not support Get Port Speed Capabilities (GPSC) command. Setting this default speed results into much lower write performance for large sequential WRITE. This patch modifies driver to check for gpsc_supported flags and prevents driver from issuing MBC_SET_PORT_PARAM (001Ah) to set default speed of 1 GB/sec. If driver does not send this mailbox command, firmware assumes maximum supported link speed and will operate at the max speed. Cc: stable@vger.kernel.org Signed-off-by: Himanshu Madhani Reported-by: Eda Zhou Reviewed-by: Ewan D. Milne Tested-by: Ewan D. Milne Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla2xxx/qla_init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 4441a559f139..34bbcfcae67c 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -3319,7 +3319,8 @@ qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) return; if (fcport->fp_speed == PORT_SPEED_UNKNOWN || - fcport->fp_speed > ha->link_data_rate) + fcport->fp_speed > ha->link_data_rate || + !ha->flags.gpsc_supported) return; rval = qla2x00_set_idma_speed(vha, fcport->loop_id, fcport->fp_speed, -- GitLab From 9779f499d88f55df72cc504b830115aecea9cfbe Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Thu, 17 May 2018 19:14:43 +0200 Subject: [PATCH 261/604] scsi: zfcp: fix missing SCSI trace for result of eh_host_reset_handler commit df30781699f53e4fd4c494c6f7dd16e3d5c21d30 upstream. For problem determination we need to see whether and why we were successful or not. This allows deduction of scsi_eh escalation. Example trace record formatted with zfcpdbf from s390-tools: Timestamp : ... Area : SCSI Subarea : 00 Level : 1 Exception : - CPU ID : .. Caller : 0x... Record ID : 1 Tag : schrh_r SCSI host reset handler result Request ID : 0x0000000000000000 none (invalid) SCSI ID : 0xffffffff none (invalid) SCSI LUN : 0xffffffff none (invalid) SCSI LUN high : 0xffffffff none (invalid) SCSI result : 0x00002002 field re-used for midlayer value: SUCCESS or in other cases: 0x2009 == FAST_IO_FAIL SCSI retries : 0xff none (invalid) SCSI allowed : 0xff none (invalid) SCSI scribble : 0xffffffffffffffff none (invalid) SCSI opcode : ffffffff ffffffff ffffffff ffffffff none (invalid) FCP rsp inf cod: 0xff none (invalid) FCP rsp IU : 00000000 00000000 00000000 00000000 none (invalid) 00000000 00000000 v2.6.35 commit a1dbfddd02d2 ("[SCSI] zfcp: Pass return code from fc_block_scsi_eh to scsi eh") introduced the first return with something other than the previously hardcoded single SUCCESS return path. Signed-off-by: Steffen Maier Fixes: a1dbfddd02d2 ("[SCSI] zfcp: Pass return code from fc_block_scsi_eh to scsi eh") Cc: #2.6.38+ Reviewed-by: Jens Remus Reviewed-by: Benjamin Block Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/s390/scsi/zfcp_dbf.c | 40 +++++++++++++++++++++++++++++++++++ drivers/s390/scsi/zfcp_ext.h | 2 ++ drivers/s390/scsi/zfcp_scsi.c | 11 +++++----- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 4534a7ce77b8..b6caad0fee24 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -625,6 +625,46 @@ void zfcp_dbf_scsi(char *tag, int level, struct scsi_cmnd *sc, spin_unlock_irqrestore(&dbf->scsi_lock, flags); } +/** + * zfcp_dbf_scsi_eh() - Trace event for special cases of scsi_eh callbacks. + * @tag: Identifier for event. + * @adapter: Pointer to zfcp adapter as context for this event. + * @scsi_id: SCSI ID/target to indicate scope of task management function (TMF). + * @ret: Return value of calling function. + * + * This SCSI trace variant does not depend on any of: + * scsi_cmnd, zfcp_fsf_req, scsi_device. + */ +void zfcp_dbf_scsi_eh(char *tag, struct zfcp_adapter *adapter, + unsigned int scsi_id, int ret) +{ + struct zfcp_dbf *dbf = adapter->dbf; + struct zfcp_dbf_scsi *rec = &dbf->scsi_buf; + unsigned long flags; + static int const level = 1; + + if (unlikely(!debug_level_enabled(adapter->dbf->scsi, level))) + return; + + spin_lock_irqsave(&dbf->scsi_lock, flags); + memset(rec, 0, sizeof(*rec)); + + memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); + rec->id = ZFCP_DBF_SCSI_CMND; + rec->scsi_result = ret; /* re-use field, int is 4 bytes and fits */ + rec->scsi_retries = ~0; + rec->scsi_allowed = ~0; + rec->fcp_rsp_info = ~0; + rec->scsi_id = scsi_id; + rec->scsi_lun = (u32)ZFCP_DBF_INVALID_LUN; + rec->scsi_lun_64_hi = (u32)(ZFCP_DBF_INVALID_LUN >> 32); + rec->host_scribble = ~0; + memset(rec->scsi_opcode, 0xff, ZFCP_DBF_SCSI_OPCODE); + + debug_event(dbf->scsi, level, rec, sizeof(*rec)); + spin_unlock_irqrestore(&dbf->scsi_lock, flags); +} + static debug_info_t *zfcp_dbf_reg(const char *name, int size, int rec_size) { struct debug_info *d; diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 7a7984a50683..7eaa2e13721f 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -52,6 +52,8 @@ extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *); extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *); extern void zfcp_dbf_scsi(char *, int, struct scsi_cmnd *, struct zfcp_fsf_req *); +extern void zfcp_dbf_scsi_eh(char *tag, struct zfcp_adapter *adapter, + unsigned int scsi_id, int ret); /* zfcp_erp.c */ extern void zfcp_erp_set_adapter_status(struct zfcp_adapter *, u32); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index bb99db2948ab..fbabf7e15cb7 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -322,15 +322,16 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; - int ret; + int ret = SUCCESS, fc_ret; zfcp_erp_adapter_reopen(adapter, 0, "schrh_1"); zfcp_erp_wait(adapter); - ret = fc_block_scsi_eh(scpnt); - if (ret) - return ret; + fc_ret = fc_block_scsi_eh(scpnt); + if (fc_ret) + ret = fc_ret; - return SUCCESS; + zfcp_dbf_scsi_eh("schrh_r", adapter, ~0, ret); + return ret; } struct scsi_transport_template *zfcp_scsi_transport_template; -- GitLab From 97d3625bdd43e6816b179ea56a7aa58060069eee Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Thu, 17 May 2018 19:14:44 +0200 Subject: [PATCH 262/604] scsi: zfcp: fix missing SCSI trace for retry of abort / scsi_eh TMF commit 81979ae63e872ef650a7197f6ce6590059d37172 upstream. We already have a SCSI trace for the end of abort and scsi_eh TMF. Due to zfcp_erp_wait() and fc_block_scsi_eh() time can pass between the start of our eh callback and an actual send/recv of an abort / TMF request. In order to see the temporal sequence including any abort / TMF send retries, add a trace before the above two blocking functions. This supports problem determination with scsi_eh and parallel zfcp ERP. No need to explicitly trace the beginning of our eh callback, since we typically can send an abort / TMF and see its HBA response (in the worst case, it's a pseudo response on dismiss all of adapter recovery, e.g. due to an FSF request timeout [fsrth_1] of the abort / TMF). If we cannot send, we now get a trace record for the first "abrt_wt" or "[lt]r_wait" which denotes almost the beginning of the callback. No need to explicitly trace the wakeup after the above two blocking functions because the next retry loop causes another trace in any case and that is sufficient. Example trace records formatted with zfcpdbf from s390-tools: Timestamp : ... Area : SCSI Subarea : 00 Level : 1 Exception : - CPU ID : .. Caller : 0x... Record ID : 1 Tag : abrt_wt abort, before zfcp_erp_wait() Request ID : 0x0000000000000000 none (invalid) SCSI ID : 0x SCSI LUN : 0x SCSI LUN high : 0x SCSI result : 0x SCSI retries : 0x SCSI allowed : 0x SCSI scribble : 0x SCSI opcode : FCP rsp inf cod: 0x.. none (invalid) FCP rsp IU : ... none (invalid) Timestamp : ... Area : SCSI Subarea : 00 Level : 1 Exception : - CPU ID : .. Caller : 0x... Record ID : 1 Tag : lr_wait LUN reset, before zfcp_erp_wait() Request ID : 0x0000000000000000 none (invalid) SCSI ID : 0x SCSI LUN : 0x SCSI LUN high : 0x SCSI result : 0x... unrelated SCSI retries : 0x.. unrelated SCSI allowed : 0x.. unrelated SCSI scribble : 0x... unrelated SCSI opcode : ... unrelated FCP rsp inf cod: 0x.. none (invalid) FCP rsp IU : ... none (invalid) Signed-off-by: Steffen Maier Fixes: 63caf367e1c9 ("[SCSI] zfcp: Improve reliability of SCSI eh handlers in zfcp") Fixes: af4de36d911a ("[SCSI] zfcp: Block scsi_eh thread for rport state BLOCKED") Cc: #2.6.38+ Reviewed-by: Benjamin Block Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/s390/scsi/zfcp_scsi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index fbabf7e15cb7..e7a36109c79c 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -180,6 +180,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) if (abrt_req) break; + zfcp_dbf_scsi_abort("abrt_wt", scpnt, NULL); zfcp_erp_wait(adapter); ret = fc_block_scsi_eh(scpnt); if (ret) { @@ -276,6 +277,7 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) if (fsf_req) break; + zfcp_dbf_scsi_devreset("wait", scpnt, tm_flags, NULL); zfcp_erp_wait(adapter); ret = fc_block_scsi_eh(scpnt); if (ret) { -- GitLab From b0c2fc11ced965b01f174f69ecfac7feca48bc84 Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Thu, 17 May 2018 19:14:45 +0200 Subject: [PATCH 263/604] scsi: zfcp: fix misleading REC trigger trace where erp_action setup failed commit 512857a795cbbda5980efa4cdb3c0b6602330408 upstream. If a SCSI device is deleted during scsi_eh host reset, we cannot get a reference to the SCSI device anymore since scsi_device_get returns !=0 by design. Assuming the recovery of adapter and port(s) was successful, zfcp_erp_strategy_followup_success() attempts to trigger a LUN reset for the half-gone SCSI device. Unfortunately, it causes the following confusing trace record which states that zfcp will do a LUN recovery as "ERP need" is ZFCP_ERP_ACTION_REOPEN_LUN == 1 and equals "ERP want". Old example trace record formatted with zfcpdbf from s390-tools: Tag: : ersfs_3 ERP, trigger, unit reopen, port reopen succeeded LUN : 0x WWPN : 0x D_ID : 0x Adapter status : 0x5400050b Port status : 0x54000001 LUN status : 0x40000000 ZFCP_STATUS_COMMON_RUNNING but not ZFCP_STATUS_COMMON_UNBLOCKED as it was closed on close part of adapter reopen ERP want : 0x01 ERP need : 0x01 misleading However, zfcp_erp_setup_act() returns NULL as it cannot get the reference. Hence, zfcp_erp_action_enqueue() takes an early goto out and _NO_ recovery actually happens. We always do want the recovery trigger trace record even if no erp_action could be enqueued as in this case. For other cases where we did not enqueue an erp_action, 'need' has always been zero to indicate this. In order to indicate above goto out, introduce an eyecatcher "flag" to mark the "ERP need" as 'not needed' but still keep the information which erp_action type, that zfcp_erp_required_act() had decided upon, is needed. 0xc_ is chosen to be visibly different from 0x0_ in "ERP want". New example trace record formatted with zfcpdbf from s390-tools: Tag: : ersfs_3 ERP, trigger, unit reopen, port reopen succeeded LUN : 0x WWPN : 0x D_ID : 0x Adapter status : 0x5400050b Port status : 0x54000001 LUN status : 0x40000000 ERP want : 0x01 ERP need : 0xc1 would need LUN ERP, but no action set up ^ Before v2.6.38 commit ae0904f60fab ("[SCSI] zfcp: Redesign of the debug tracing for recovery actions.") we could detect this case because the "erp_action" field in the trace was NULL. The rework removed erp_action as argument and field from the trace. This patch here is for tracing. A fix to allow LUN recovery in the case at hand is a topic for a separate patch. See also commit fdbd1c5e27da ("[SCSI] zfcp: Allow running unit/LUN shutdown without acquiring reference") for a similar case and background info. Signed-off-by: Steffen Maier Fixes: ae0904f60fab ("[SCSI] zfcp: Redesign of the debug tracing for recovery actions.") Cc: #2.6.38+ Reviewed-by: Benjamin Block Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/s390/scsi/zfcp_erp.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 3b23d6754598..ae624789a6c4 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -34,11 +34,23 @@ enum zfcp_erp_steps { ZFCP_ERP_STEP_LUN_OPENING = 0x2000, }; +/** + * enum zfcp_erp_act_type - Type of ERP action object. + * @ZFCP_ERP_ACTION_REOPEN_LUN: LUN recovery. + * @ZFCP_ERP_ACTION_REOPEN_PORT: Port recovery. + * @ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: Forced port recovery. + * @ZFCP_ERP_ACTION_REOPEN_ADAPTER: Adapter recovery. + * @ZFCP_ERP_ACTION_NONE: Eyecatcher pseudo flag to bitwise or-combine with + * either of the other enum values. + * Used to indicate that an ERP action could not be + * set up despite a detected need for some recovery. + */ enum zfcp_erp_act_type { ZFCP_ERP_ACTION_REOPEN_LUN = 1, ZFCP_ERP_ACTION_REOPEN_PORT = 2, ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3, ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4, + ZFCP_ERP_ACTION_NONE = 0xc0, }; enum zfcp_erp_act_state { @@ -256,8 +268,10 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, goto out; act = zfcp_erp_setup_act(need, act_status, adapter, port, sdev); - if (!act) + if (!act) { + need |= ZFCP_ERP_ACTION_NONE; /* marker for trace */ goto out; + } atomic_or(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); ++adapter->erp_total_count; list_add_tail(&act->list, &adapter->erp_ready_head); -- GitLab From 48ae373c57f009b32a03637e0809fabd9132fe81 Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Thu, 17 May 2018 19:14:46 +0200 Subject: [PATCH 264/604] scsi: zfcp: fix missing REC trigger trace on terminate_rport_io early return commit 96d9270499471545048ed8a6d7f425a49762283d upstream. get_device() and its internally used kobject_get() only return NULL if they get passed NULL as argument. zfcp_get_port_by_wwpn() loops over adapter->port_list so the iteration variable port is always non-NULL. Struct device is embedded in struct zfcp_port so &port->dev is always non-NULL. This is the argument to get_device(). However, if we get an fc_rport in terminate_rport_io() for which we cannot find a match within zfcp_get_port_by_wwpn(), the latter can return NULL. v2.6.30 commit 70932935b61e ("[SCSI] zfcp: Fix oops when port disappears") introduced an early return without adding a trace record for this case. Even if we don't need recovery in this case, for debugging we should still see that our callback was invoked originally by scsi_transport_fc. Example trace record formatted with zfcpdbf from s390-tools: Timestamp : ... Area : REC Subarea : 00 Level : 1 Exception : - CPU ID : .. Caller : 0x... Record ID : 1 Tag : sctrpin SCSI terminate rport I/O, no zfcp port LUN : 0xffffffffffffffff none (invalid) WWPN : 0x WWPN D_ID : 0x N_Port-ID Adapter status : 0x... Port status : 0xffffffff unknown (-1) LUN status : 0x00000000 none (invalid) Ready count : 0x... Running count : 0x... ERP want : 0x03 ZFCP_ERP_ACTION_REOPEN_PORT_FORCED ERP need : 0xc0 ZFCP_ERP_ACTION_NONE Signed-off-by: Steffen Maier Fixes: 70932935b61e ("[SCSI] zfcp: Fix oops when port disappears") Cc: #2.6.38+ Reviewed-by: Benjamin Block Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/s390/scsi/zfcp_erp.c | 20 ++++++++++++++++++++ drivers/s390/scsi/zfcp_ext.h | 3 +++ drivers/s390/scsi/zfcp_scsi.c | 5 +++++ 3 files changed, 28 insertions(+) diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index ae624789a6c4..e60c16b2ba45 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -282,6 +282,26 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, return retval; } +void zfcp_erp_port_forced_no_port_dbf(char *id, struct zfcp_adapter *adapter, + u64 port_name, u32 port_id) +{ + unsigned long flags; + static /* don't waste stack */ struct zfcp_port tmpport; + + write_lock_irqsave(&adapter->erp_lock, flags); + /* Stand-in zfcp port with fields just good enough for + * zfcp_dbf_rec_trig() and zfcp_dbf_set_common(). + * Under lock because tmpport is static. + */ + atomic_set(&tmpport.status, -1); /* unknown */ + tmpport.wwpn = port_name; + tmpport.d_id = port_id; + zfcp_dbf_rec_trig(id, adapter, &tmpport, NULL, + ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, + ZFCP_ERP_ACTION_NONE); + write_unlock_irqrestore(&adapter->erp_lock, flags); +} + static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear_mask, char *id) { diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 7eaa2e13721f..b326f05c7f89 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -58,6 +58,9 @@ extern void zfcp_dbf_scsi_eh(char *tag, struct zfcp_adapter *adapter, /* zfcp_erp.c */ extern void zfcp_erp_set_adapter_status(struct zfcp_adapter *, u32); extern void zfcp_erp_clear_adapter_status(struct zfcp_adapter *, u32); +extern void zfcp_erp_port_forced_no_port_dbf(char *id, + struct zfcp_adapter *adapter, + u64 port_name, u32 port_id); extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, char *); extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, char *); extern void zfcp_erp_set_port_status(struct zfcp_port *, u32); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index e7a36109c79c..3afb200b2829 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -603,6 +603,11 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) if (port) { zfcp_erp_port_forced_reopen(port, 0, "sctrpi1"); put_device(&port->dev); + } else { + zfcp_erp_port_forced_no_port_dbf( + "sctrpin", adapter, + rport->port_name /* zfcp_scsi_rport_register */, + rport->port_id /* zfcp_scsi_rport_register */); } } -- GitLab From 21224f6f135ab267b07729f3274fcfc028b3ace0 Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Thu, 17 May 2018 19:14:47 +0200 Subject: [PATCH 265/604] scsi: zfcp: fix missing REC trigger trace on terminate_rport_io for ERP_FAILED commit d70aab55924b44f213fec2b900b095430b33eec6 upstream. For problem determination we always want to see when we were invoked on the terminate_rport_io callback whether we perform something or not. Temporal event sequence of interest with a long fast_io_fail_tmo of 27 sec: loose remote port t workqueue [s] zfcp_q_ IRQ zfcperp === ================== =================== ============================ 0 recv RSCN q p.test_link_work block rport start fast_io_fail_tmo send ADISC ELS 4 recv ADISC fail block zfcp_port port forced reopen send open port 12 recv open port fail q p.gid_pn_work zfcp_erp_wakeup (zfcp_erp_wait would return) GID_PN fail Before this point, we got a SCSI trace with tag "sctrpi1" on fast_io_fail, e.g. with the typical 5 sec setting. port.status |= ERP_FAILED If fast_io_fail_tmo triggers after this point, we missed a SCSI trace. workqueue fc_dl_ ================== 27 fc_timeout_fail_rport_io fc_terminate_rport_io zfcp_scsi_terminate_rport_io zfcp_erp_port_forced_reopen _zfcp_erp_port_forced_reopen if (port.status & ERP_FAILED) return; Therefore, write a trace before above early return. Example trace record formatted with zfcpdbf from s390-tools: Timestamp : ... Area : REC Subarea : 00 Level : 1 Exception : - CPU ID : .. Caller : 0x... Record ID : 1 ZFCP_DBF_REC_TRIG Tag : sctrpi1 SCSI terminate rport I/O LUN : 0xffffffffffffffff none (invalid) WWPN : 0x D_ID : 0x Adapter status : 0x... Port status : 0x... LUN status : 0x00000000 none (invalid) Ready count : 0x... Running count : 0x... ERP want : 0x03 ZFCP_ERP_ACTION_REOPEN_PORT_FORCED ERP need : 0xe0 ZFCP_ERP_ACTION_FAILED Signed-off-by: Steffen Maier Cc: #2.6.38+ Reviewed-by: Benjamin Block Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/s390/scsi/zfcp_erp.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index e60c16b2ba45..e695f95ac3c2 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -41,9 +41,13 @@ enum zfcp_erp_steps { * @ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: Forced port recovery. * @ZFCP_ERP_ACTION_REOPEN_ADAPTER: Adapter recovery. * @ZFCP_ERP_ACTION_NONE: Eyecatcher pseudo flag to bitwise or-combine with - * either of the other enum values. + * either of the first four enum values. * Used to indicate that an ERP action could not be * set up despite a detected need for some recovery. + * @ZFCP_ERP_ACTION_FAILED: Eyecatcher pseudo flag to bitwise or-combine with + * either of the first four enum values. + * Used to indicate that ERP not needed because + * the object has ZFCP_STATUS_COMMON_ERP_FAILED. */ enum zfcp_erp_act_type { ZFCP_ERP_ACTION_REOPEN_LUN = 1, @@ -51,6 +55,7 @@ enum zfcp_erp_act_type { ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3, ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4, ZFCP_ERP_ACTION_NONE = 0xc0, + ZFCP_ERP_ACTION_FAILED = 0xe0, }; enum zfcp_erp_act_state { @@ -378,8 +383,12 @@ static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, zfcp_erp_port_block(port, clear); zfcp_scsi_schedule_rport_block(port); - if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) + if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { + zfcp_dbf_rec_trig(id, port->adapter, port, NULL, + ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, + ZFCP_ERP_ACTION_FAILED); return; + } zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, port->adapter, port, NULL, id, 0); -- GitLab From 2df7e6f33c64c61e9a33dbbed6bed4af78e94d67 Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Thu, 17 May 2018 19:14:48 +0200 Subject: [PATCH 266/604] scsi: zfcp: fix missing REC trigger trace for all objects in ERP_FAILED commit 8c3d20aada70042a39c6a6625be037c1472ca610 upstream. That other commit introduced an inconsistency because it would trace on ERP_FAILED for all callers of port forced reopen triggers (not just terminate_rport_io), but it would not trace on ERP_FAILED for all callers of other ERP triggers such as adapter, port regular, LUN. Therefore, generalize that other commit. zfcp_erp_action_enqueue() already had two early outs which re-used the one zfcp_dbf_rec_trig() call. All ERP trigger functions finally run through zfcp_erp_action_enqueue(). So move the special handling for ZFCP_STATUS_COMMON_ERP_FAILED into zfcp_erp_action_enqueue() and add another early out with new trace marker for pseudo ERP need in this case. This removes all early returns from all ERP trigger functions so we always end up at zfcp_dbf_rec_trig(). Example trace record formatted with zfcpdbf from s390-tools: Timestamp : ... Area : REC Subarea : 00 Level : 1 Exception : - CPU ID : .. Caller : 0x... Record ID : 1 ZFCP_DBF_REC_TRIG Tag : ....... LUN : 0x... WWPN : 0x... D_ID : 0x... Adapter status : 0x... Port status : 0x... LUN status : 0x... Ready count : 0x... Running count : 0x... ERP want : 0x0. ZFCP_ERP_ACTION_REOPEN_... ERP need : 0xe0 ZFCP_ERP_ACTION_FAILED Signed-off-by: Steffen Maier Cc: #2.6.38+ Reviewed-by: Benjamin Block Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/s390/scsi/zfcp_erp.c | 79 +++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index e695f95ac3c2..0ac35f8e4429 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -142,6 +142,49 @@ static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) } } +static int zfcp_erp_handle_failed(int want, struct zfcp_adapter *adapter, + struct zfcp_port *port, + struct scsi_device *sdev) +{ + int need = want; + struct zfcp_scsi_dev *zsdev; + + switch (want) { + case ZFCP_ERP_ACTION_REOPEN_LUN: + zsdev = sdev_to_zfcp(sdev); + if (atomic_read(&zsdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) + need = 0; + break; + case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: + if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) + need = 0; + break; + case ZFCP_ERP_ACTION_REOPEN_PORT: + if (atomic_read(&port->status) & + ZFCP_STATUS_COMMON_ERP_FAILED) { + need = 0; + /* ensure propagation of failed status to new devices */ + zfcp_erp_set_port_status( + port, ZFCP_STATUS_COMMON_ERP_FAILED); + } + break; + case ZFCP_ERP_ACTION_REOPEN_ADAPTER: + if (atomic_read(&adapter->status) & + ZFCP_STATUS_COMMON_ERP_FAILED) { + need = 0; + /* ensure propagation of failed status to new devices */ + zfcp_erp_set_adapter_status( + adapter, ZFCP_STATUS_COMMON_ERP_FAILED); + } + break; + default: + need = 0; + break; + } + + return need; +} + static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, struct zfcp_port *port, struct scsi_device *sdev) @@ -265,6 +308,12 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, int retval = 1, need; struct zfcp_erp_action *act; + need = zfcp_erp_handle_failed(want, adapter, port, sdev); + if (!need) { + need = ZFCP_ERP_ACTION_FAILED; /* marker for trace */ + goto out; + } + if (!adapter->erp_thread) return -EIO; @@ -313,12 +362,6 @@ static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, zfcp_erp_adapter_block(adapter, clear_mask); zfcp_scsi_schedule_rports_block(adapter); - /* ensure propagation of failed status to new devices */ - if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { - zfcp_erp_set_adapter_status(adapter, - ZFCP_STATUS_COMMON_ERP_FAILED); - return -EIO; - } return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter, NULL, NULL, id, 0); } @@ -337,12 +380,8 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, char *id) zfcp_scsi_schedule_rports_block(adapter); write_lock_irqsave(&adapter->erp_lock, flags); - if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) - zfcp_erp_set_adapter_status(adapter, - ZFCP_STATUS_COMMON_ERP_FAILED); - else - zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter, - NULL, NULL, id, 0); + zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter, + NULL, NULL, id, 0); write_unlock_irqrestore(&adapter->erp_lock, flags); } @@ -383,13 +422,6 @@ static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, zfcp_erp_port_block(port, clear); zfcp_scsi_schedule_rport_block(port); - if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { - zfcp_dbf_rec_trig(id, port->adapter, port, NULL, - ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, - ZFCP_ERP_ACTION_FAILED); - return; - } - zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, port->adapter, port, NULL, id, 0); } @@ -415,12 +447,6 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id) zfcp_erp_port_block(port, clear); zfcp_scsi_schedule_rport_block(port); - if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { - /* ensure propagation of failed status to new devices */ - zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED); - return -EIO; - } - return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, port->adapter, port, NULL, id, 0); } @@ -460,9 +486,6 @@ static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id, zfcp_erp_lun_block(sdev, clear); - if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) - return; - zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter, zfcp_sdev->port, sdev, id, act_status); } -- GitLab From c6751cb1e828d7aa93cedfcee65534318278713e Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Thu, 17 May 2018 19:14:49 +0200 Subject: [PATCH 267/604] scsi: zfcp: fix missing REC trigger trace on enqueue without ERP thread commit 6a76550841d412330bd86aed3238d1888ba70f0e upstream. Example trace record formatted with zfcpdbf from s390-tools: Timestamp : ... Area : REC Subarea : 00 Level : 1 Exception : - CPU ID : .. Caller : 0x... Record ID : 1 ZFCP_DBF_REC_TRIG Tag : ....... LUN : 0x... WWPN : 0x... D_ID : 0x... Adapter status : 0x... Port status : 0x... LUN status : 0x... Ready count : 0x... Running count : 0x... ERP want : 0x0. ZFCP_ERP_ACTION_REOPEN_... ERP need : 0xc0 ZFCP_ERP_ACTION_NONE Signed-off-by: Steffen Maier Cc: #2.6.38+ Reviewed-by: Benjamin Block Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/s390/scsi/zfcp_erp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 0ac35f8e4429..2abcd331b05d 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -314,8 +314,11 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, goto out; } - if (!adapter->erp_thread) - return -EIO; + if (!adapter->erp_thread) { + need = ZFCP_ERP_ACTION_NONE; /* marker for trace */ + retval = -EIO; + goto out; + } need = zfcp_erp_required_act(want, adapter, port, sdev); if (!need) -- GitLab From f216d1e9339dfb2981d2a0e44a15501cfa76f4ad Mon Sep 17 00:00:00 2001 From: Robert Elliott Date: Thu, 31 May 2018 18:36:36 -0500 Subject: [PATCH 268/604] linvdimm, pmem: Preserve read-only setting for pmem devices commit 254a4cd50b9fe2291a12b8902e08e56dcc4e9b10 upstream. The pmem driver does not honor a forced read-only setting for very long: $ blockdev --setro /dev/pmem0 $ blockdev --getro /dev/pmem0 1 followed by various commands like these: $ blockdev --rereadpt /dev/pmem0 or $ mkfs.ext4 /dev/pmem0 results in this in the kernel serial log: nd_pmem namespace0.0: region0 read-write, marking pmem0 read-write with the read-only setting lost: $ blockdev --getro /dev/pmem0 0 That's from bus.c nvdimm_revalidate_disk(), which always applies the setting from nd_region (which is initially based on the ACPI NFIT NVDIMM state flags not_armed bit). In contrast, commit 20bd1d026aac ("scsi: sd: Keep disk read-only when re-reading partition") fixed this issue for SCSI devices to preserve the previous setting if it was set to read-only. This patch modifies bus.c to preserve any previous read-only setting. It also eliminates the kernel serial log print except for cases where read-write is changed to read-only, so it doesn't print read-only to read-only non-changes. Cc: Fixes: 581388209405 ("libnvdimm, nfit: handle unarmed dimms, mark namespaces read-only") Signed-off-by: Robert Elliott Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/nvdimm/bus.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 8311a93cabd8..c1a65ce31243 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -505,14 +505,18 @@ int nvdimm_revalidate_disk(struct gendisk *disk) { struct device *dev = disk_to_dev(disk)->parent; struct nd_region *nd_region = to_nd_region(dev->parent); - const char *pol = nd_region->ro ? "only" : "write"; + int disk_ro = get_disk_ro(disk); - if (nd_region->ro == get_disk_ro(disk)) + /* + * Upgrade to read-only if the region is read-only preserve as + * read-only if the disk is already read-only. + */ + if (disk_ro || nd_region->ro == disk_ro) return 0; - dev_info(dev, "%s read-%s, marking %s read-%s\n", - dev_name(&nd_region->dev), pol, disk->disk_name, pol); - set_disk_ro(disk, nd_region->ro); + dev_info(dev, "%s read-only, marking %s read-only\n", + dev_name(&nd_region->dev), disk->disk_name); + set_disk_ro(disk, 1); return 0; -- GitLab From c0eb205dfe159d02bd7821288765ac0a40a0695c Mon Sep 17 00:00:00 2001 From: Marcin Ziemianowicz Date: Sun, 29 Apr 2018 15:01:11 -0400 Subject: [PATCH 269/604] clk: at91: PLL recalc_rate() now using cached MUL and DIV values commit a982e45dc150da3a08907b6dd676b735391704b4 upstream. When a USB device is connected to the USB host port on the SAM9N12 then you get "-62" error which seems to indicate USB replies from the device are timing out. Based on a logic sniffer, I saw the USB bus was running at half speed. The PLL code uses cached MUL and DIV values which get set in set_rate() and applied in prepare(), but the recalc_rate() function instead queries the hardware instead of using these cached values. Therefore, if recalc_rate() is called between a set_rate() and prepare(), the wrong frequency is calculated and later the USB clock divider for the SAM9N12 SOC will be configured for an incorrect clock. In my case, the PLL hardware was set to 96 Mhz before the OHCI driver loads, and therefore the usb clock divider was being set to /2 even though the OHCI driver set the PLL to 48 Mhz. As an alternative explanation, I noticed this was fixed in the past by 87e2ed338f1b ("clk: at91: fix recalc_rate implementation of PLL driver") but the bug was later re-introduced by 1bdf02326b71 ("clk: at91: make use of syscon/regmap internally"). Fixes: 1bdf02326b71 ("clk: at91: make use of syscon/regmap internally) Cc: Signed-off-by: Marcin Ziemianowicz Acked-by: Boris Brezillon Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/clk/at91/clk-pll.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c index 45ad168e1496..2bb2551c6245 100644 --- a/drivers/clk/at91/clk-pll.c +++ b/drivers/clk/at91/clk-pll.c @@ -132,19 +132,8 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_pll *pll = to_clk_pll(hw); - unsigned int pllr; - u16 mul; - u8 div; - - regmap_read(pll->regmap, PLL_REG(pll->id), &pllr); - - div = PLL_DIV(pllr); - mul = PLL_MUL(pllr, pll->layout); - - if (!div || !mul) - return 0; - return (parent_rate / div) * (mul + 1); + return (parent_rate / pll->div) * (pll->mul + 1); } static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate, -- GitLab From 486684887ab588309c3497785412bb67e162b7a6 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 26 Apr 2018 14:46:29 +1000 Subject: [PATCH 270/604] md: fix two problems with setting the "re-add" device state. commit 011abdc9df559ec75779bb7c53a744c69b2a94c6 upstream. If "re-add" is written to the "state" file for a device which is faulty, this has an effect similar to removing and re-adding the device. It should take up the same slot in the array that it previously had, and an accelerated (e.g. bitmap-based) rebuild should happen. The slot that "it previously had" is determined by rdev->saved_raid_disk. However this is not set when a device fails (only when a device is added), and it is cleared when resync completes. This means that "re-add" will normally work once, but may not work a second time. This patch includes two fixes. 1/ when a device fails, record the ->raid_disk value in ->saved_raid_disk before clearing ->raid_disk 2/ when "re-add" is written to a device for which ->saved_raid_disk is not set, fail. I think this is suitable for stable as it can cause re-adding a device to be forced to do a full resync which takes a lot longer and so puts data at more risk. Cc: (v4.1) Fixes: 97f6cd39da22 ("md-cluster: re-add capabilities") Signed-off-by: NeilBrown Reviewed-by: Goldwyn Rodrigues Signed-off-by: Shaohua Li Signed-off-by: Greg Kroah-Hartman --- drivers/md/md.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index cae8f3c12e32..3bb985679f34 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2694,7 +2694,8 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len) err = 0; } } else if (cmd_match(buf, "re-add")) { - if (test_bit(Faulty, &rdev->flags) && (rdev->raid_disk == -1)) { + if (test_bit(Faulty, &rdev->flags) && (rdev->raid_disk == -1) && + rdev->saved_raid_disk >= 0) { /* clear_bit is performed _after_ all the devices * have their local Faulty bit cleared. If any writes * happen in the meantime in the local node, they @@ -8272,6 +8273,7 @@ static int remove_and_add_spares(struct mddev *mddev, if (mddev->pers->hot_remove_disk( mddev, rdev) == 0) { sysfs_unlink_rdev(mddev, rdev); + rdev->saved_raid_disk = rdev->raid_disk; rdev->raid_disk = -1; removed++; } -- GitLab From ec7ee4d60f25f9a4ba264090b2671346d078ed2a Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 4 Jun 2018 10:39:01 +0100 Subject: [PATCH 271/604] rpmsg: smd: do not use mananged resources for endpoints and channels commit 4a2e84c6ed85434ce7843e4844b4d3263f7e233b upstream. All the managed resources would be freed by the time release function is invoked. Handling such memory in qcom_smd_edge_release() would do bad things. Found this issue while testing Audio usecase where the dsp is started up and shutdown in a loop. This patch fixes this issue by using simple kzalloc for allocating channel->name and channel which is then freed in qcom_smd_edge_release(). Without this patch restarting a remoteproc would crash the system. Fixes: 53e2822e56c7 ("rpmsg: Introduce Qualcomm SMD backend") Cc: Signed-off-by: Srinivas Kandagatla Signed-off-by: Bjorn Andersson Signed-off-by: Greg Kroah-Hartman --- drivers/rpmsg/qcom_smd.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c index 1d4770c02e57..fd3d9419c468 100644 --- a/drivers/rpmsg/qcom_smd.c +++ b/drivers/rpmsg/qcom_smd.c @@ -1006,12 +1006,12 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed void *info; int ret; - channel = devm_kzalloc(&edge->dev, sizeof(*channel), GFP_KERNEL); + channel = kzalloc(sizeof(*channel), GFP_KERNEL); if (!channel) return ERR_PTR(-ENOMEM); channel->edge = edge; - channel->name = devm_kstrdup(&edge->dev, name, GFP_KERNEL); + channel->name = kstrdup(name, GFP_KERNEL); if (!channel->name) return ERR_PTR(-ENOMEM); @@ -1061,8 +1061,8 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed return channel; free_name_and_channel: - devm_kfree(&edge->dev, channel->name); - devm_kfree(&edge->dev, channel); + kfree(channel->name); + kfree(channel); return ERR_PTR(ret); } @@ -1279,13 +1279,13 @@ static int qcom_smd_parse_edge(struct device *dev, */ static void qcom_smd_edge_release(struct device *dev) { - struct qcom_smd_channel *channel; + struct qcom_smd_channel *channel, *tmp; struct qcom_smd_edge *edge = to_smd_edge(dev); - list_for_each_entry(channel, &edge->channels, list) { - SET_RX_CHANNEL_INFO(channel, state, SMD_CHANNEL_CLOSED); - SET_RX_CHANNEL_INFO(channel, head, 0); - SET_RX_CHANNEL_INFO(channel, tail, 0); + list_for_each_entry_safe(channel, tmp, &edge->channels, list) { + list_del(&channel->list); + kfree(channel->name); + kfree(channel); } kfree(edge); -- GitLab From 9eb99e738beb405cb69ce0c244e6bb0ee9666588 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 16 May 2018 22:17:03 +0200 Subject: [PATCH 272/604] ubi: fastmap: Cancel work upon detach commit 6e7d80161066c99d12580d1b985cb1408bb58cf1 upstream. Ben Hutchings pointed out that 29b7a6fa1ec0 ("ubi: fastmap: Don't flush fastmap work on detach") does not really fix the problem, it just reduces the risk to hit the race window where fastmap work races against free()'ing ubi->volumes[]. The correct approach is making sure that no more fastmap work is in progress before we free ubi data structures. So we cancel fastmap work right after the ubi background thread is stopped. By setting ubi->thread_enabled to zero we make sure that no further work tries to wake the thread. Fixes: 29b7a6fa1ec0 ("ubi: fastmap: Don't flush fastmap work on detach") Fixes: 74cdaf24004a ("UBI: Fastmap: Fix memory leaks while closing the WL sub-system") Cc: stable@vger.kernel.org Cc: Ben Hutchings Cc: Martin Townsend Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/build.c | 3 +++ drivers/mtd/ubi/wl.c | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 6cb5ca52cb5a..ad2b57c6b13f 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -1137,6 +1137,9 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) */ get_device(&ubi->dev); +#ifdef CONFIG_MTD_UBI_FASTMAP + cancel_work_sync(&ubi->fm_work); +#endif ubi_debugfs_exit_dev(ubi); uif_close(ubi); diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 668b46202507..23a6986d512b 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -1505,6 +1505,7 @@ int ubi_thread(void *u) } dbg_wl("background thread \"%s\" is killed", ubi->bgt_name); + ubi->thread_enabled = 0; return 0; } @@ -1514,9 +1515,6 @@ int ubi_thread(void *u) */ static void shutdown_work(struct ubi_device *ubi) { -#ifdef CONFIG_MTD_UBI_FASTMAP - flush_work(&ubi->fm_work); -#endif while (!list_empty(&ubi->works)) { struct ubi_work *wrk; -- GitLab From df15c6eeab46aac3622821e2659677c3eb4abf9d Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Mon, 28 May 2018 22:04:32 +0200 Subject: [PATCH 273/604] ubi: fastmap: Correctly handle interrupted erasures in EBA commit 781932375ffc6411713ee0926ccae8596ed0261c upstream. Fastmap cannot track the LEB unmap operation, therefore it can happen that after an interrupted erasure the mapping still looks good from Fastmap's point of view, while reading from the PEB will cause an ECC error and confuses the upper layer. Instead of teaching users of UBI how to deal with that, we read back the VID header and check for errors. If the PEB is empty or shows ECC errors we fixup the mapping and schedule the PEB for erasure. Fixes: dbb7d2a88d2a ("UBI: Add fastmap core") Cc: Reported-by: martin bayern Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/eba.c | 90 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 388e46be6ad9..d0884bd9d955 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -490,6 +490,82 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, return err; } +#ifdef CONFIG_MTD_UBI_FASTMAP +/** + * check_mapping - check and fixup a mapping + * @ubi: UBI device description object + * @vol: volume description object + * @lnum: logical eraseblock number + * @pnum: physical eraseblock number + * + * Checks whether a given mapping is valid. Fastmap cannot track LEB unmap + * operations, if such an operation is interrupted the mapping still looks + * good, but upon first read an ECC is reported to the upper layer. + * Normaly during the full-scan at attach time this is fixed, for Fastmap + * we have to deal with it while reading. + * If the PEB behind a LEB shows this symthom we change the mapping to + * %UBI_LEB_UNMAPPED and schedule the PEB for erasure. + * + * Returns 0 on success, negative error code in case of failure. + */ +static int check_mapping(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, + int *pnum) +{ + int err; + struct ubi_vid_io_buf *vidb; + + if (!ubi->fast_attach) + return 0; + + vidb = ubi_alloc_vid_buf(ubi, GFP_NOFS); + if (!vidb) + return -ENOMEM; + + err = ubi_io_read_vid_hdr(ubi, *pnum, vidb, 0); + if (err > 0 && err != UBI_IO_BITFLIPS) { + int torture = 0; + + switch (err) { + case UBI_IO_FF: + case UBI_IO_FF_BITFLIPS: + case UBI_IO_BAD_HDR: + case UBI_IO_BAD_HDR_EBADMSG: + break; + default: + ubi_assert(0); + } + + if (err == UBI_IO_BAD_HDR_EBADMSG || err == UBI_IO_FF_BITFLIPS) + torture = 1; + + down_read(&ubi->fm_eba_sem); + vol->eba_tbl->entries[lnum].pnum = UBI_LEB_UNMAPPED; + up_read(&ubi->fm_eba_sem); + ubi_wl_put_peb(ubi, vol->vol_id, lnum, *pnum, torture); + + *pnum = UBI_LEB_UNMAPPED; + } else if (err < 0) { + ubi_err(ubi, "unable to read VID header back from PEB %i: %i", + *pnum, err); + + goto out_free; + } + + err = 0; + +out_free: + ubi_free_vid_buf(vidb); + + return err; +} +#else +static int check_mapping(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, + int *pnum) +{ + return 0; +} +#endif + /** * ubi_eba_read_leb - read data. * @ubi: UBI device description object @@ -522,7 +598,13 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, return err; pnum = vol->eba_tbl->entries[lnum].pnum; - if (pnum < 0) { + if (pnum >= 0) { + err = check_mapping(ubi, vol, lnum, &pnum); + if (err < 0) + goto out_unlock; + } + + if (pnum == UBI_LEB_UNMAPPED) { /* * The logical eraseblock is not mapped, fill the whole buffer * with 0xFF bytes. The exception is static volumes for which @@ -930,6 +1012,12 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, return err; pnum = vol->eba_tbl->entries[lnum].pnum; + if (pnum >= 0) { + err = check_mapping(ubi, vol, lnum, &pnum); + if (err < 0) + goto out; + } + if (pnum >= 0) { dbg_eba("write %d bytes at offset %d of LEB %d:%d, PEB %d", len, offset, vol_id, lnum, pnum); -- GitLab From da05be555697c3fdd3f1507b59917c1cc3b03566 Mon Sep 17 00:00:00 2001 From: Silvio Cesare Date: Fri, 4 May 2018 13:44:02 +1000 Subject: [PATCH 274/604] UBIFS: Fix potential integer overflow in allocation commit 353748a359f1821ee934afc579cf04572406b420 upstream. There is potential for the size and len fields in ubifs_data_node to be too large causing either a negative value for the length fields or an integer overflow leading to an incorrect memory allocation. Likewise, when the len field is small, an integer underflow may occur. Signed-off-by: Silvio Cesare Fixes: 1e51764a3c2ac ("UBIFS: add new flash file system") Cc: stable@vger.kernel.org Signed-off-by: Kees Cook Signed-off-by: Greg Kroah-Hartman --- fs/ubifs/journal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c index 7d764e3b6c79..504658fd0d08 100644 --- a/fs/ubifs/journal.c +++ b/fs/ubifs/journal.c @@ -1265,7 +1265,7 @@ static int recomp_data_node(const struct ubifs_info *c, int err, len, compr_type, out_len; out_len = le32_to_cpu(dn->size); - buf = kmalloc(out_len * WORST_COMPR_FACTOR, GFP_NOFS); + buf = kmalloc_array(out_len, WORST_COMPR_FACTOR, GFP_NOFS); if (!buf) return -ENOMEM; -- GitLab From 47f764c65c561ba1dcf7c6a9688c82202ede58ca Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Nov 2017 11:45:44 +0100 Subject: [PATCH 275/604] backlight: as3711_bl: Fix Device Tree node lookup commit 4a9c8bb2aca5b5a2a15744333729745dd9903562 upstream. Fix child-node lookup during probe, which ended up searching the whole device tree depth-first starting at the parent rather than just matching on its children. To make things worse, the parent mfd node was also prematurely freed. Cc: stable # 3.10 Fixes: 59eb2b5e57ea ("drivers/video/backlight/as3711_bl.c: add OF support") Signed-off-by: Johan Hovold Acked-by: Daniel Thompson Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman --- drivers/video/backlight/as3711_bl.c | 33 ++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/video/backlight/as3711_bl.c b/drivers/video/backlight/as3711_bl.c index 734a9158946b..e55304d5cf07 100644 --- a/drivers/video/backlight/as3711_bl.c +++ b/drivers/video/backlight/as3711_bl.c @@ -262,10 +262,10 @@ static int as3711_bl_register(struct platform_device *pdev, static int as3711_backlight_parse_dt(struct device *dev) { struct as3711_bl_pdata *pdata = dev_get_platdata(dev); - struct device_node *bl = - of_find_node_by_name(dev->parent->of_node, "backlight"), *fb; + struct device_node *bl, *fb; int ret; + bl = of_get_child_by_name(dev->parent->of_node, "backlight"); if (!bl) { dev_dbg(dev, "backlight node not found\n"); return -ENODEV; @@ -279,7 +279,7 @@ static int as3711_backlight_parse_dt(struct device *dev) if (pdata->su1_max_uA <= 0) ret = -EINVAL; if (ret < 0) - return ret; + goto err_put_bl; } fb = of_parse_phandle(bl, "su2-dev", 0); @@ -292,7 +292,7 @@ static int as3711_backlight_parse_dt(struct device *dev) if (pdata->su2_max_uA <= 0) ret = -EINVAL; if (ret < 0) - return ret; + goto err_put_bl; if (of_find_property(bl, "su2-feedback-voltage", NULL)) { pdata->su2_feedback = AS3711_SU2_VOLTAGE; @@ -314,8 +314,10 @@ static int as3711_backlight_parse_dt(struct device *dev) pdata->su2_feedback = AS3711_SU2_CURR_AUTO; count++; } - if (count != 1) - return -EINVAL; + if (count != 1) { + ret = -EINVAL; + goto err_put_bl; + } count = 0; if (of_find_property(bl, "su2-fbprot-lx-sd4", NULL)) { @@ -334,8 +336,10 @@ static int as3711_backlight_parse_dt(struct device *dev) pdata->su2_fbprot = AS3711_SU2_GPIO4; count++; } - if (count != 1) - return -EINVAL; + if (count != 1) { + ret = -EINVAL; + goto err_put_bl; + } count = 0; if (of_find_property(bl, "su2-auto-curr1", NULL)) { @@ -355,11 +359,20 @@ static int as3711_backlight_parse_dt(struct device *dev) * At least one su2-auto-curr* must be specified iff * AS3711_SU2_CURR_AUTO is used */ - if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO)) - return -EINVAL; + if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO)) { + ret = -EINVAL; + goto err_put_bl; + } } + of_node_put(bl); + return 0; + +err_put_bl: + of_node_put(bl); + + return ret; } static int as3711_backlight_probe(struct platform_device *pdev) -- GitLab From a89e596f129117b902210c57599e198d1441ee93 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Nov 2017 11:45:45 +0100 Subject: [PATCH 276/604] backlight: max8925_bl: Fix Device Tree node lookup commit d1cc0ec3da23e44c23712579515494b374f111c9 upstream. Fix child-node lookup during probe, which ended up searching the whole device tree depth-first starting at the parent rather than just matching on its children. To make things worse, the parent mfd node was also prematurely freed, while the child backlight node was leaked. Cc: stable # 3.9 Fixes: 47ec340cb8e2 ("mfd: max8925: Support dt for backlight") Signed-off-by: Johan Hovold Acked-by: Daniel Thompson Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman --- drivers/video/backlight/max8925_bl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index 7b738d60ecc2..f3aa6088f1d9 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -116,7 +116,7 @@ static void max8925_backlight_dt_init(struct platform_device *pdev) if (!pdata) return; - np = of_find_node_by_name(nproot, "backlight"); + np = of_get_child_by_name(nproot, "backlight"); if (!np) { dev_err(&pdev->dev, "failed to find backlight node\n"); return; @@ -125,6 +125,8 @@ static void max8925_backlight_dt_init(struct platform_device *pdev) if (!of_property_read_u32(np, "maxim,max8925-dual-string", &val)) pdata->dual_string = val; + of_node_put(np); + pdev->dev.platform_data = pdata; } -- GitLab From 099fae46d8dfed70744321bbbd265cc7af2982f3 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 20 Nov 2017 11:45:46 +0100 Subject: [PATCH 277/604] backlight: tps65217_bl: Fix Device Tree node lookup commit 2b12dfa124dbadf391cb9a616aaa6b056823bf75 upstream. Fix child-node lookup during probe, which ended up searching the whole device tree depth-first starting at the parent rather than just matching on its children. This would only cause trouble if the child node is missing while there is an unrelated node named "backlight" elsewhere in the tree. Cc: stable # 3.7 Fixes: eebfdc17cc6c ("backlight: Add TPS65217 WLED driver") Signed-off-by: Johan Hovold Acked-by: Daniel Thompson Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman --- drivers/video/backlight/tps65217_bl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c index fd524ad860a5..f45d0c9467db 100644 --- a/drivers/video/backlight/tps65217_bl.c +++ b/drivers/video/backlight/tps65217_bl.c @@ -184,11 +184,11 @@ static struct tps65217_bl_pdata * tps65217_bl_parse_dt(struct platform_device *pdev) { struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); - struct device_node *node = of_node_get(tps->dev->of_node); + struct device_node *node; struct tps65217_bl_pdata *pdata, *err; u32 val; - node = of_find_node_by_name(node, "backlight"); + node = of_get_child_by_name(tps->dev->of_node, "backlight"); if (!node) return ERR_PTR(-ENODEV); -- GitLab From 49d98a8e1f55f8406c45ce2b88eb4912d9877f67 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 24 Apr 2018 18:00:10 +0300 Subject: [PATCH 278/604] mfd: intel-lpss: Program REMAP register in PIO mode commit d28b62520830b2d0bffa2d98e81afc9f5e537e8b upstream. According to documentation REMAP register has to be programmed in either DMA or PIO mode of the slice. Move the DMA capability check below to let REMAP register be programmed in PIO mode. Cc: stable@vger.kernel.org # 4.3+ Fixes: 4b45efe85263 ("mfd: Add support for Intel Sunrisepoint LPSS devices") Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/intel-lpss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index 70c646b0097d..19ac8bc8e7ea 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c @@ -275,11 +275,11 @@ static void intel_lpss_init_dev(const struct intel_lpss *lpss) intel_lpss_deassert_reset(lpss); + intel_lpss_set_remap_addr(lpss); + if (!intel_lpss_has_idma(lpss)) return; - intel_lpss_set_remap_addr(lpss); - /* Make sure that SPI multiblock DMA transfers are re-enabled */ if (lpss->type == LPSS_DEV_SPI) writel(value, lpss->priv + LPSS_PRIV_SSP_REG); -- GitLab From dfd2eff6f457f2193f0dfd0de5cb3aa49df3d3e9 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 4 Jun 2018 15:56:54 +0300 Subject: [PATCH 279/604] perf tools: Fix symbol and object code resolution for vdso32 and vdsox32 commit aef4feace285f27c8ed35830a5d575bec7f3e90a upstream. Fix __kmod_path__parse() so that perf tools does not treat vdso32 and vdsox32 as kernel modules and fail to find the object. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: Wang Nan Cc: stable@vger.kernel.org Fixes: 1f121b03d058 ("perf tools: Deal with kernel module names in '[]' correctly") Link: http://lkml.kernel.org/r/1528117014-30032-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/dso.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index d2c6cdd9d42b..8bec05365aae 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -253,6 +253,8 @@ int __kmod_path__parse(struct kmod_path *m, const char *path, if ((strncmp(name, "[kernel.kallsyms]", 17) == 0) || (strncmp(name, "[guest.kernel.kallsyms", 22) == 0) || (strncmp(name, "[vdso]", 6) == 0) || + (strncmp(name, "[vdso32]", 8) == 0) || + (strncmp(name, "[vdsox32]", 9) == 0) || (strncmp(name, "[vsyscall]", 10) == 0)) { m->kmod = false; -- GitLab From 31606f7f56de573470f0b7037b764df381a87fa6 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 31 May 2018 13:23:42 +0300 Subject: [PATCH 280/604] perf intel-pt: Fix sync_switch INTEL_PT_SS_NOT_TRACING commit dbcb82b93f3e8322891e47472c89e63058b81e99 upstream. sync_switch is a facility to synchronize decoding more closely with the point in the kernel when the context actually switched. In one case, INTEL_PT_SS_NOT_TRACING state was not correctly transitioning to INTEL_PT_SS_TRACING state due to a missing case clause. Add it. Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1527762225-26024-2-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/intel-pt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index b1161d725ce9..5fb78b661fd3 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -1344,6 +1344,7 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) if (intel_pt_is_switch_ip(ptq, state->to_ip)) { switch (ptq->switch_state) { + case INTEL_PT_SS_NOT_TRACING: case INTEL_PT_SS_UNKNOWN: case INTEL_PT_SS_EXPECTING_SWITCH_IP: err = intel_pt_next_tid(pt, ptq); -- GitLab From 282f1f66b5a0f4875f2562144f5e5c80bc86dfc1 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 31 May 2018 13:23:43 +0300 Subject: [PATCH 281/604] perf intel-pt: Fix decoding to accept CBR between FUP and corresponding TIP commit bd2e49ec48feb1855f7624198849eea4610e2286 upstream. It is possible to have a CBR packet between a FUP packet and corresponding TIP packet. Stop treating it as an error. Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1527762225-26024-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index cac39532c057..0fd7697b9d35 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -1517,7 +1517,6 @@ static int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder) case INTEL_PT_PSB: case INTEL_PT_TSC: case INTEL_PT_TMA: - case INTEL_PT_CBR: case INTEL_PT_MODE_TSX: case INTEL_PT_BAD: case INTEL_PT_PSBEND: @@ -1526,6 +1525,10 @@ static int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder) decoder->pkt_step = 0; return -ENOENT; + case INTEL_PT_CBR: + intel_pt_calc_cbr(decoder); + break; + case INTEL_PT_OVF: return intel_pt_overflow(decoder); -- GitLab From 4213d9b8cdb10d4d29fd232898692a1a56c1fd58 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 31 May 2018 13:23:44 +0300 Subject: [PATCH 282/604] perf intel-pt: Fix MTC timing after overflow commit dd27b87ab5fcf3ea1c060b5e3ab5d31cc78e9f4c upstream. On some platforms, overflows will clear before MTC wraparound, and there is no following TSC/TMA packet. In that case the previous TMA is valid. Since there will be a valid TMA either way, stop setting 'have_tma' to false upon overflow. Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1527762225-26024-4-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 0fd7697b9d35..21c81da190b2 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -1298,7 +1298,6 @@ static int intel_pt_overflow(struct intel_pt_decoder *decoder) { intel_pt_log("ERROR: Buffer overflow\n"); intel_pt_clear_tx_flags(decoder); - decoder->have_tma = false; decoder->cbr = 0; decoder->timestamp_insn_cnt = 0; decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC; -- GitLab From d129ab791de910a81bb53f0053d3476c26982aea Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 31 May 2018 13:23:45 +0300 Subject: [PATCH 283/604] perf intel-pt: Fix "Unexpected indirect branch" error commit 9fb523363f6e3984457fee95bb7019395384ffa7 upstream. Some Atom CPUs can produce FUP packets that contain NLIP (next linear instruction pointer) instead of CLIP (current linear instruction pointer). That will result in "Unexpected indirect branch" errors. Fix by comparing IP to NLIP in that case. Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1527762225-26024-5-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- .../util/intel-pt-decoder/intel-pt-decoder.c | 17 +++++++++++++++-- .../util/intel-pt-decoder/intel-pt-decoder.h | 9 +++++++++ tools/perf/util/intel-pt.c | 4 ++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 21c81da190b2..d27715ff9a5f 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -112,6 +112,7 @@ struct intel_pt_decoder { bool have_cyc; bool fixup_last_mtc; bool have_last_ip; + enum intel_pt_param_flags flags; uint64_t pos; uint64_t last_ip; uint64_t ip; @@ -215,6 +216,8 @@ struct intel_pt_decoder *intel_pt_decoder_new(struct intel_pt_params *params) decoder->data = params->data; decoder->return_compression = params->return_compression; + decoder->flags = params->flags; + decoder->period = params->period; decoder->period_type = params->period_type; @@ -1012,6 +1015,15 @@ static int intel_pt_walk_insn(struct intel_pt_decoder *decoder, return err; } +static inline bool intel_pt_fup_with_nlip(struct intel_pt_decoder *decoder, + struct intel_pt_insn *intel_pt_insn, + uint64_t ip, int err) +{ + return decoder->flags & INTEL_PT_FUP_WITH_NLIP && !err && + intel_pt_insn->branch == INTEL_PT_BR_INDIRECT && + ip == decoder->ip + intel_pt_insn->length; +} + static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) { struct intel_pt_insn intel_pt_insn; @@ -1024,7 +1036,8 @@ static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) err = intel_pt_walk_insn(decoder, &intel_pt_insn, ip); if (err == INTEL_PT_RETURN) return 0; - if (err == -EAGAIN) { + if (err == -EAGAIN || + intel_pt_fup_with_nlip(decoder, &intel_pt_insn, ip, err)) { if (decoder->set_fup_tx_flags) { decoder->set_fup_tx_flags = false; decoder->tx_flags = decoder->fup_tx_flags; @@ -1034,7 +1047,7 @@ static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) decoder->state.flags = decoder->fup_tx_flags; return 0; } - return err; + return -EAGAIN; } decoder->set_fup_tx_flags = false; if (err) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h index 9ae4df1dcedc..2fe8f4c5aeb5 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h @@ -53,6 +53,14 @@ enum { INTEL_PT_ERR_MAX, }; +enum intel_pt_param_flags { + /* + * FUP packet can contain next linear instruction pointer instead of + * current linear instruction pointer. + */ + INTEL_PT_FUP_WITH_NLIP = 1 << 0, +}; + struct intel_pt_state { enum intel_pt_sample_type type; int err; @@ -92,6 +100,7 @@ struct intel_pt_params { unsigned int mtc_period; uint32_t tsc_ctc_ratio_n; uint32_t tsc_ctc_ratio_d; + enum intel_pt_param_flags flags; }; struct intel_pt_decoder; diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 5fb78b661fd3..d40ab4cf8932 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -752,6 +752,7 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, unsigned int queue_nr) { struct intel_pt_params params = { .get_trace = 0, }; + struct perf_env *env = pt->machine->env; struct intel_pt_queue *ptq; ptq = zalloc(sizeof(struct intel_pt_queue)); @@ -832,6 +833,9 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, } } + if (env->cpuid && !strncmp(env->cpuid, "GenuineIntel,6,92,", 18)) + params.flags |= INTEL_PT_FUP_WITH_NLIP; + ptq->decoder = intel_pt_decoder_new(¶ms); if (!ptq->decoder) goto out_free; -- GitLab From d6a267b4c5f9bb3db42e3fe6092d1059f08d03bf Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 7 Jun 2018 14:30:02 +0300 Subject: [PATCH 284/604] perf intel-pt: Fix packet decoding of CYC packets commit 621a5a327c1e36ffd7bb567f44a559f64f76358f upstream. Use a 64-bit type so that the cycle count is not limited to 32-bits. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1528371002-8862-1-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c index 7528ae4f7e28..e5c6caf913f3 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c @@ -281,7 +281,7 @@ static int intel_pt_get_cyc(unsigned int byte, const unsigned char *buf, if (len < offs) return INTEL_PT_NEED_MORE_BYTES; byte = buf[offs++]; - payload |= (byte >> 1) << shift; + payload |= ((uint64_t)byte >> 1) << shift; } packet->type = INTEL_PT_CYC; -- GitLab From 1e6b50b6b68e25a8ff972a1e1279a40cd7adc4fd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 11 Apr 2018 11:47:32 -0400 Subject: [PATCH 285/604] media: v4l2-compat-ioctl32: prevent go past max size commit ea72fbf588ac9c017224dcdaa2019ff52ca56fee upstream. As warned by smatch: drivers/media/v4l2-core/v4l2-compat-ioctl32.c:879 put_v4l2_ext_controls32() warn: check for integer overflow 'count' The access_ok() logic should check for too big arrays too. Cc: stable@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index a9fc64557c53..f1f697296ca0 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -864,7 +864,7 @@ static int put_v4l2_ext_controls32(struct file *file, get_user(kcontrols, &kp->controls)) return -EFAULT; - if (!count) + if (!count || count > (U32_MAX/sizeof(*ucontrols))) return 0; if (get_user(p, &up->controls)) return -EFAULT; -- GitLab From 1a4726ba1dedcdb92bc15a70e65150e9222ceed1 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Mon, 26 Mar 2018 02:06:16 -0400 Subject: [PATCH 286/604] media: cx231xx: Add support for AverMedia DVD EZMaker 7 commit 29e61d6ef061b012d320327af7dbb3990e75be45 upstream. User reports AverMedia DVD EZMaker 7 can be driven by VIDEO_GRABBER. Add the device to the id_table to make it work. BugLink: https://bugs.launchpad.net/bugs/1620762 Cc: stable@vger.kernel.org Signed-off-by: Kai-Heng Feng Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/cx231xx/cx231xx-cards.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index 921cf1edb3b1..69156affd0ae 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -864,6 +864,9 @@ struct usb_device_id cx231xx_id_table[] = { .driver_info = CX231XX_BOARD_CNXT_RDE_250}, {USB_DEVICE(0x0572, 0x58A0), .driver_info = CX231XX_BOARD_CNXT_RDU_250}, + /* AverMedia DVD EZMaker 7 */ + {USB_DEVICE(0x07ca, 0xc039), + .driver_info = CX231XX_BOARD_CNXT_VIDEO_GRABBER}, {USB_DEVICE(0x2040, 0xb110), .driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL}, {USB_DEVICE(0x2040, 0xb111), -- GitLab From dc00f08645be1f6a1319af6c6c1117137f787efc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 5 Apr 2018 05:30:52 -0400 Subject: [PATCH 287/604] media: dvb_frontend: fix locking issues at dvb_frontend_get_event() commit 76d81243a487c09619822ef8e7201a756e58a87d upstream. As warned by smatch: drivers/media/dvb-core/dvb_frontend.c:314 dvb_frontend_get_event() warn: inconsistent returns 'sem:&fepriv->sem'. Locked on: line 288 line 295 line 306 line 314 Unlocked on: line 303 The lock implementation for get event is wrong, as, if an interrupt occurs, down_interruptible() will fail, and the routine will call up() twice when userspace calls the ioctl again. The bad code is there since when Linux migrated to git, in 2005. Cc: stable@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/dvb-core/dvb_frontend.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 01511e5a5566..2f054db8807b 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -251,8 +251,20 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, wake_up_interruptible (&events->wait_queue); } +static int dvb_frontend_test_event(struct dvb_frontend_private *fepriv, + struct dvb_fe_events *events) +{ + int ret; + + up(&fepriv->sem); + ret = events->eventw != events->eventr; + down(&fepriv->sem); + + return ret; +} + static int dvb_frontend_get_event(struct dvb_frontend *fe, - struct dvb_frontend_event *event, int flags) + struct dvb_frontend_event *event, int flags) { struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_fe_events *events = &fepriv->events; @@ -270,13 +282,8 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, if (flags & O_NONBLOCK) return -EWOULDBLOCK; - up(&fepriv->sem); - - ret = wait_event_interruptible (events->wait_queue, - events->eventw != events->eventr); - - if (down_interruptible (&fepriv->sem)) - return -ERESTARTSYS; + ret = wait_event_interruptible(events->wait_queue, + dvb_frontend_test_event(fepriv, events)); if (ret < 0) return ret; -- GitLab From 40d79a61957a7d59b079d30fbbc5e51c3b9b239a Mon Sep 17 00:00:00 2001 From: Scott Mayhew Date: Mon, 7 May 2018 09:01:08 -0400 Subject: [PATCH 288/604] nfsd: restrict rd_maxcount to svc_max_payload in nfsd_encode_readdir commit 9c2ece6ef67e9d376f32823086169b489c422ed0 upstream. nfsd4_readdir_rsize restricts rd_maxcount to svc_max_payload when estimating the size of the readdir reply, but nfsd_encode_readdir restricts it to INT_MAX when encoding the reply. This can result in log messages like "kernel: RPC request reserved 32896 but used 1049444". Restrict rd_dircount similarly (no reason it should be larger than svc_max_payload). Signed-off-by: Scott Mayhew Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4xdr.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 2c4f7a22e128..bdbd9e6d1ace 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3638,7 +3638,8 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 nfserr = nfserr_resource; goto err_no_verf; } - maxcount = min_t(u32, readdir->rd_maxcount, INT_MAX); + maxcount = svc_max_payload(resp->rqstp); + maxcount = min_t(u32, readdir->rd_maxcount, maxcount); /* * Note the rfc defines rd_maxcount as the size of the * READDIR4resok structure, which includes the verifier above @@ -3652,7 +3653,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 /* RFC 3530 14.2.24 allows us to ignore dircount when it's 0: */ if (!readdir->rd_dircount) - readdir->rd_dircount = INT_MAX; + readdir->rd_dircount = svc_max_payload(resp->rqstp); readdir->xdr = xdr; readdir->rd_maxcount = maxcount; -- GitLab From 5b7f582e808d6b39eb0751deb1b6685813b05847 Mon Sep 17 00:00:00 2001 From: Dave Wysochanski Date: Tue, 29 May 2018 17:47:30 -0400 Subject: [PATCH 289/604] NFSv4: Fix possible 1-byte stack overflow in nfs_idmap_read_and_verify_message commit d68894800ec5712d7ddf042356f11e36f87d7f78 upstream. In nfs_idmap_read_and_verify_message there is an incorrect sprintf '%d' that converts the __u32 'im_id' from struct idmap_msg to 'id_str', which is a stack char array variable of length NFS_UINT_MAXLEN == 11. If a uid or gid value is > 2147483647 = 0x7fffffff, the conversion overflows into a negative value, for example: crash> p (unsigned) (0x80000000) $1 = 2147483648 crash> p (signed) (0x80000000) $2 = -2147483648 The '-' sign is written to the buffer and this causes a 1 byte overflow when the NULL byte is written, which corrupts kernel stack memory. If CONFIG_CC_STACKPROTECTOR_STRONG is set we see a stack-protector panic: [11558053.616565] Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: ffffffffa05b8a8c [11558053.639063] CPU: 6 PID: 9423 Comm: rpc.idmapd Tainted: G W ------------ T 3.10.0-514.el7.x86_64 #1 [11558053.641990] Hardware name: Red Hat OpenStack Compute, BIOS 1.10.2-3.el7_4.1 04/01/2014 [11558053.644462] ffffffff818c7bc0 00000000b1f3aec1 ffff880de0f9bd48 ffffffff81685eac [11558053.646430] ffff880de0f9bdc8 ffffffff8167f2b3 ffffffff00000010 ffff880de0f9bdd8 [11558053.648313] ffff880de0f9bd78 00000000b1f3aec1 ffffffff811dcb03 ffffffffa05b8a8c [11558053.650107] Call Trace: [11558053.651347] [] dump_stack+0x19/0x1b [11558053.653013] [] panic+0xe3/0x1f2 [11558053.666240] [] ? kfree+0x103/0x140 [11558053.682589] [] ? idmap_pipe_downcall+0x1cc/0x1e0 [nfsv4] [11558053.689710] [] __stack_chk_fail+0x1b/0x30 [11558053.691619] [] idmap_pipe_downcall+0x1cc/0x1e0 [nfsv4] [11558053.693867] [] rpc_pipe_write+0x56/0x70 [sunrpc] [11558053.695763] [] vfs_write+0xbd/0x1e0 [11558053.702236] [] ? task_work_run+0xac/0xe0 [11558053.704215] [] SyS_write+0x7f/0xe0 [11558053.709674] [] system_call_fastpath+0x16/0x1b Fix this by calling the internally defined nfs_map_numeric_to_string() function which properly uses '%u' to convert this __u32. For consistency, also replace the one other place where snprintf is called. Signed-off-by: Dave Wysochanski Reported-by: Stephen Johnston Fixes: cf4ab538f1516 ("NFSv4: Fix the string length returned by the idmapper") Cc: stable@vger.kernel.org # v3.4+ Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4idmap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c index f1160cdd4682..3d4602d66068 100644 --- a/fs/nfs/nfs4idmap.c +++ b/fs/nfs/nfs4idmap.c @@ -343,7 +343,7 @@ static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, int id_len; ssize_t ret; - id_len = snprintf(id_str, sizeof(id_str), "%u", id); + id_len = nfs_map_numeric_to_string(id, id_str, sizeof(id_str)); ret = nfs_idmap_get_key(id_str, id_len, type, buf, buflen, idmap); if (ret < 0) return -EINVAL; @@ -626,7 +626,8 @@ static int nfs_idmap_read_and_verify_message(struct idmap_msg *im, if (strcmp(upcall->im_name, im->im_name) != 0) break; /* Note: here we store the NUL terminator too */ - len = sprintf(id_str, "%d", im->im_id) + 1; + len = 1 + nfs_map_numeric_to_string(im->im_id, id_str, + sizeof(id_str)); ret = nfs_idmap_instantiate(key, authkey, id_str, len); break; case IDMAP_CONV_IDTONAME: -- GitLab From cdc83c366977044d7717d56f6bb1aa247e1dc582 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 9 Jun 2018 12:43:06 -0400 Subject: [PATCH 290/604] NFSv4: Revert commit 5f83d86cf531d ("NFSv4.x: Fix wraparound issues..") commit fc40724fc6731d90cc7fb6d62d66135f85a33dd2 upstream. The correct behaviour for NFSv4 sequence IDs is to wrap around to the value 0 after 0xffffffff. See https://tools.ietf.org/html/rfc5661#section-2.10.6.1 Fixes: 5f83d86cf531d ("NFSv4.x: Fix wraparound issues when validing...") Cc: stable@vger.kernel.org # 4.6+ Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/callback_proc.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index e9aa235e9d10..2e7ebd9d7168 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -402,11 +402,8 @@ validate_seqid(const struct nfs4_slot_table *tbl, const struct nfs4_slot *slot, return htonl(NFS4ERR_SEQ_FALSE_RETRY); } - /* Wraparound */ - if (unlikely(slot->seq_nr == 0xFFFFFFFFU)) { - if (args->csa_sequenceid == 1) - return htonl(NFS4_OK); - } else if (likely(args->csa_sequenceid == slot->seq_nr + 1)) + /* Note: wraparound relies on seq_nr being of type u32 */ + if (likely(args->csa_sequenceid == slot->seq_nr + 1)) return htonl(NFS4_OK); /* Misordered request */ -- GitLab From 7673ca3c93414faf90fa2a3c339f1f625415fecb Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 11 May 2018 18:24:12 +1000 Subject: [PATCH 291/604] video: uvesafb: Fix integer overflow in allocation commit 9f645bcc566a1e9f921bdae7528a01ced5bc3713 upstream. cmap->len can get close to INT_MAX/2, allowing for an integer overflow in allocation. This uses kmalloc_array() instead to catch the condition. Reported-by: Dr Silvio Cesare of InfoSect Fixes: 8bdb3a2d7df48 ("uvesafb: the driver core") Cc: stable@vger.kernel.org Signed-off-by: Kees Cook Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbdev/uvesafb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/uvesafb.c b/drivers/video/fbdev/uvesafb.c index 98af9e02959b..9fe0d0bcdf62 100644 --- a/drivers/video/fbdev/uvesafb.c +++ b/drivers/video/fbdev/uvesafb.c @@ -1059,7 +1059,8 @@ static int uvesafb_setcmap(struct fb_cmap *cmap, struct fb_info *info) info->cmap.len || cmap->start < info->cmap.start) return -EINVAL; - entries = kmalloc(sizeof(*entries) * cmap->len, GFP_KERNEL); + entries = kmalloc_array(cmap->len, sizeof(*entries), + GFP_KERNEL); if (!entries) return -ENOMEM; -- GitLab From c38bac75d1c21b09764a882b520b0ad33749ac10 Mon Sep 17 00:00:00 2001 From: Alexandr Savca Date: Thu, 21 Jun 2018 17:12:54 -0700 Subject: [PATCH 292/604] Input: elan_i2c - add ELAN0618 (Lenovo v330 15IKB) ACPI ID commit 8938fc7b8fe9ccfa11751ead502a8d385b607967 upstream. Add ELAN0618 to the list of supported touchpads; this ID is used in Lenovo v330 15IKB devices. Signed-off-by: Alexandr Savca 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 aeb8250ab079..2d6481f3e89b 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1250,6 +1250,7 @@ static const struct acpi_device_id elan_acpi_id[] = { { "ELAN060C", 0 }, { "ELAN0611", 0 }, { "ELAN0612", 0 }, + { "ELAN0618", 0 }, { "ELAN1000", 0 }, { } }; -- GitLab From 037aca0e2fc22dcff17c38b38d9efab5e0d4b96e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 26 Apr 2018 14:10:23 +0200 Subject: [PATCH 293/604] pwm: lpss: platform: Save/restore the ctrl register over a suspend/resume commit 1d375b58c12f08d8570b30b865def4734517f04f upstream. On some devices the contents of the ctrl register get lost over a suspend/resume and the PWM comes back up disabled after the resume. This is seen on some Bay Trail devices with the PWM in ACPI enumerated mode, so it shows up as a platform device instead of a PCI device. If we still think it is enabled and then try to change the duty-cycle after this, we end up with a "PWM_SW_UPDATE was not cleared" error and the PWM is stuck in that state from then on. This commit adds suspend and resume pm callbacks to the pwm-lpss-platform code, which save/restore the ctrl register over a suspend/resume, fixing this. Note that: 1) There is no need to do this over a runtime suspend, since we only runtime suspend when disabled and then we properly set the enable bit and reprogram the timings when we re-enable the PWM. 2) This may be happening on more systems then we realize, but has been covered up sofar by a bug in the acpi-lpss.c code which was save/restoring the regular device registers instead of the lpss private registers due to lpss_device_desc.prv_offset not being set. This is fixed by a later patch in this series. Cc: stable@vger.kernel.org Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Thierry Reding Signed-off-by: Greg Kroah-Hartman --- drivers/pwm/pwm-lpss-platform.c | 5 +++++ drivers/pwm/pwm-lpss.c | 30 ++++++++++++++++++++++++++++++ drivers/pwm/pwm-lpss.h | 2 ++ 3 files changed, 37 insertions(+) diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c index 54433fc6d1a4..e4eaefc2a2ef 100644 --- a/drivers/pwm/pwm-lpss-platform.c +++ b/drivers/pwm/pwm-lpss-platform.c @@ -52,6 +52,10 @@ static int pwm_lpss_remove_platform(struct platform_device *pdev) return pwm_lpss_remove(lpwm); } +static SIMPLE_DEV_PM_OPS(pwm_lpss_platform_pm_ops, + pwm_lpss_suspend, + pwm_lpss_resume); + static const struct acpi_device_id pwm_lpss_acpi_match[] = { { "80860F09", (unsigned long)&pwm_lpss_byt_info }, { "80862288", (unsigned long)&pwm_lpss_bsw_info }, @@ -64,6 +68,7 @@ static struct platform_driver pwm_lpss_driver_platform = { .driver = { .name = "pwm-lpss", .acpi_match_table = pwm_lpss_acpi_match, + .pm = &pwm_lpss_platform_pm_ops, }, .probe = pwm_lpss_probe_platform, .remove = pwm_lpss_remove_platform, diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index 72c0bce5a75c..5208b3f80ad8 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -31,10 +31,13 @@ /* Size of each PWM register space if multiple */ #define PWM_SIZE 0x400 +#define MAX_PWMS 4 + struct pwm_lpss_chip { struct pwm_chip chip; void __iomem *regs; const struct pwm_lpss_boardinfo *info; + u32 saved_ctrl[MAX_PWMS]; }; /* BayTrail */ @@ -168,6 +171,9 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, unsigned long c; int ret; + if (WARN_ON(info->npwm > MAX_PWMS)) + return ERR_PTR(-ENODEV); + lpwm = devm_kzalloc(dev, sizeof(*lpwm), GFP_KERNEL); if (!lpwm) return ERR_PTR(-ENOMEM); @@ -203,6 +209,30 @@ int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) } EXPORT_SYMBOL_GPL(pwm_lpss_remove); +int pwm_lpss_suspend(struct device *dev) +{ + struct pwm_lpss_chip *lpwm = dev_get_drvdata(dev); + int i; + + for (i = 0; i < lpwm->info->npwm; i++) + lpwm->saved_ctrl[i] = readl(lpwm->regs + i * PWM_SIZE + PWM); + + return 0; +} +EXPORT_SYMBOL_GPL(pwm_lpss_suspend); + +int pwm_lpss_resume(struct device *dev) +{ + struct pwm_lpss_chip *lpwm = dev_get_drvdata(dev); + int i; + + for (i = 0; i < lpwm->info->npwm; i++) + writel(lpwm->saved_ctrl[i], lpwm->regs + i * PWM_SIZE + PWM); + + return 0; +} +EXPORT_SYMBOL_GPL(pwm_lpss_resume); + MODULE_DESCRIPTION("PWM driver for Intel LPSS"); MODULE_AUTHOR("Mika Westerberg "); MODULE_LICENSE("GPL v2"); diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h index 04766e0d41aa..27d5081ec218 100644 --- a/drivers/pwm/pwm-lpss.h +++ b/drivers/pwm/pwm-lpss.h @@ -31,5 +31,7 @@ extern const struct pwm_lpss_boardinfo pwm_lpss_bxt_info; struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, const struct pwm_lpss_boardinfo *info); int pwm_lpss_remove(struct pwm_lpss_chip *lpwm); +int pwm_lpss_suspend(struct device *dev); +int pwm_lpss_resume(struct device *dev); #endif /* __PWM_LPSS_H */ -- GitLab From 1f00b1fc77752bb27b6b696fd7fceeda921ac0fa Mon Sep 17 00:00:00 2001 From: Dongsheng Yang Date: Mon, 4 Jun 2018 06:24:37 -0400 Subject: [PATCH 294/604] rbd: flush rbd_dev->watch_dwork after watch is unregistered commit 23edca864951250af845a11da86bb3ea63522ed2 upstream. There is a problem if we are going to unmap a rbd device and the watch_dwork is going to queue delayed work for watch: unmap Thread watch Thread timer do_rbd_remove cancel_tasks_sync(rbd_dev) queue_delayed_work for watch destroy_workqueue(rbd_dev->task_wq) drain_workqueue(wq) destroy other resources in wq call_timer_fn __queue_work() Then the delayed work escape the cancel_tasks_sync() and destroy_workqueue() and we will get an user-after-free call trace: BUG: unable to handle kernel NULL pointer dereference at 0000000000000000 PGD 0 P4D 0 Oops: 0000 [#1] SMP PTI Modules linked in: CPU: 7 PID: 0 Comm: swapper/7 Tainted: G OE 4.17.0-rc6+ #13 Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 RIP: 0010:__queue_work+0x6a/0x3b0 RSP: 0018:ffff9427df1c3e90 EFLAGS: 00010086 RAX: ffff9427deca8400 RBX: 0000000000000000 RCX: 0000000000000000 RDX: ffff9427deca8400 RSI: ffff9427df1c3e50 RDI: 0000000000000000 RBP: ffff942783e39e00 R08: ffff9427deca8400 R09: ffff9427df1c3f00 R10: 0000000000000004 R11: 0000000000000005 R12: ffff9427cfb85970 R13: 0000000000002000 R14: 000000000001eca0 R15: 0000000000000007 FS: 0000000000000000(0000) GS:ffff9427df1c0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 00000004c900a005 CR4: 00000000000206e0 Call Trace: ? __queue_work+0x3b0/0x3b0 call_timer_fn+0x2d/0x130 run_timer_softirq+0x16e/0x430 ? tick_sched_timer+0x37/0x70 __do_softirq+0xd2/0x280 irq_exit+0xd5/0xe0 smp_apic_timer_interrupt+0x6c/0x130 apic_timer_interrupt+0xf/0x20 [ Move rbd_dev->watch_dwork cancellation so that rbd_reregister_watch() either bails out early because the watch is UNREGISTERED at that point or just gets cancelled. ] Cc: stable@vger.kernel.org Fixes: 99d1694310df ("rbd: retry watch re-registration periodically") Signed-off-by: Dongsheng Yang Reviewed-by: Ilya Dryomov Signed-off-by: Ilya Dryomov Signed-off-by: Greg Kroah-Hartman --- drivers/block/rbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 343cad9bf7e7..ef3016a467a0 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3900,7 +3900,6 @@ static void cancel_tasks_sync(struct rbd_device *rbd_dev) { dout("%s rbd_dev %p\n", __func__, rbd_dev); - cancel_delayed_work_sync(&rbd_dev->watch_dwork); cancel_work_sync(&rbd_dev->acquired_lock_work); cancel_work_sync(&rbd_dev->released_lock_work); cancel_delayed_work_sync(&rbd_dev->lock_dwork); @@ -3918,6 +3917,7 @@ static void rbd_unregister_watch(struct rbd_device *rbd_dev) rbd_dev->watch_state = RBD_WATCH_STATE_UNREGISTERED; mutex_unlock(&rbd_dev->watch_mutex); + cancel_delayed_work_sync(&rbd_dev->watch_dwork); ceph_osdc_flush_notifies(&rbd_dev->rbd_client->client->osdc); } -- GitLab From 6d28f2d64cf5ddf6c55f7a3a954dd9a34b72862b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 14 Jun 2018 15:26:24 -0700 Subject: [PATCH 295/604] mm: fix devmem_is_allowed() for sub-page System RAM intersections commit 2bdce74412c249ac01dfe36b6b0043ffd7a5361e upstream. Hussam reports: I was poking around and for no real reason, I did cat /dev/mem and strings /dev/mem. Then I saw the following warning in dmesg. I saved it and rebooted immediately. memremap attempted on mixed range 0x000000000009c000 size: 0x1000 ------------[ cut here ]------------ WARNING: CPU: 0 PID: 11810 at kernel/memremap.c:98 memremap+0x104/0x170 [..] Call Trace: xlate_dev_mem_ptr+0x25/0x40 read_mem+0x89/0x1a0 __vfs_read+0x36/0x170 The memremap() implementation checks for attempts to remap System RAM with MEMREMAP_WB and instead redirects those mapping attempts to the linear map. However, that only works if the physical address range being remapped is page aligned. In low memory we have situations like the following: 00000000-00000fff : Reserved 00001000-0009fbff : System RAM 0009fc00-0009ffff : Reserved ...where System RAM intersects Reserved ranges on a sub-page page granularity. Given that devmem_is_allowed() special cases any attempt to map System RAM in the first 1MB of memory, replace page_is_ram() with the more precise region_intersects() to trap attempts to map disallowed ranges. Link: https://bugzilla.kernel.org/show_bug.cgi?id=199999 Link: http://lkml.kernel.org/r/152856436164.18127.2847888121707136898.stgit@dwillia2-desk3.amr.corp.intel.com Fixes: 92281dee825f ("arch: introduce memremap()") Signed-off-by: Dan Williams Reported-by: Hussam Al-Tayeb Tested-by: Hussam Al-Tayeb Cc: Christoph Hellwig Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/mm/init.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index f92bdb9f4e46..ae9b84cae57c 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -653,7 +653,9 @@ void __init init_mem_mapping(void) */ int devmem_is_allowed(unsigned long pagenr) { - if (page_is_ram(pagenr)) { + if (region_intersects(PFN_PHYS(pagenr), PAGE_SIZE, + IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE) + != REGION_DISJOINT) { /* * For disallowed memory regions in the low 1MB range, * request that the page be shown as all zeros. -- GitLab From 3cac26f2a2c66f755e033ca944d02433be684556 Mon Sep 17 00:00:00 2001 From: Boris Ostrovsky Date: Thu, 21 Jun 2018 13:29:44 -0400 Subject: [PATCH 296/604] xen: Remove unnecessary BUG_ON from __unbind_from_irq() commit eef04c7b3786ff0c9cb1019278b6c6c2ea0ad4ff upstream. Commit 910f8befdf5b ("xen/pirq: fix error path cleanup when binding MSIs") fixed a couple of errors in error cleanup path of xen_bind_pirq_msi_to_irq(). This cleanup allowed a call to __unbind_from_irq() with an unbound irq, which would result in triggering the BUG_ON there. Since there is really no reason for the BUG_ON (xen_free_irq() can operate on unbound irqs) we can remove it. Reported-by: Ben Hutchings Signed-off-by: Boris Ostrovsky Cc: stable@vger.kernel.org Reviewed-by: Juergen Gross Signed-off-by: Juergen Gross Signed-off-by: Greg Kroah-Hartman --- drivers/xen/events/events_base.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 6d3b32ccc2c4..1435d8c58ea0 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -637,8 +637,6 @@ static void __unbind_from_irq(unsigned int irq) xen_irq_info_cleanup(info); } - BUG_ON(info_for_irq(irq)->type == IRQT_UNBOUND); - xen_free_irq(irq); } -- GitLab From 2a1b1234d0502237872f6a11016061328528b86d Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 13 Jun 2018 12:09:22 +0200 Subject: [PATCH 297/604] udf: Detect incorrect directory size commit fa65653e575fbd958bdf5fb9c4a71a324e39510d upstream. Detect when a directory entry is (possibly partially) beyond directory size and return EIO in that case since it means the filesystem is corrupted. Otherwise directory operations can further corrupt the directory and possibly also oops the kernel. CC: Anatoly Trosinenko CC: stable@vger.kernel.org Reported-and-tested-by: Anatoly Trosinenko Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/udf/directory.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/udf/directory.c b/fs/udf/directory.c index 988d5352bdb8..48ef184929ec 100644 --- a/fs/udf/directory.c +++ b/fs/udf/directory.c @@ -150,6 +150,9 @@ struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos, sizeof(struct fileIdentDesc)); } } + /* Got last entry outside of dir size - fs is corrupted! */ + if (*nf_pos > dir->i_size) + return NULL; return fi; } -- GitLab From 54ae564b35423f25b763bc9e01b489d9f11c034e Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 19 Jun 2018 11:17:32 -0700 Subject: [PATCH 298/604] Input: elan_i2c_smbus - fix more potential stack buffer overflows commit 50fc7b61959af4b95fafce7fe5dd565199e0b61a upstream. Commit 40f7090bb1b4 ("Input: elan_i2c_smbus - fix corrupted stack") fixed most of the functions using i2c_smbus_read_block_data() to allocate a buffer with the maximum block size. However three functions were left unchanged: * In elan_smbus_initialize(), increase the buffer size in the same way. * In elan_smbus_calibrate_result(), the buffer is provided by the caller (calibrate_store()), so introduce a bounce buffer. Also name the result buffer size. * In elan_smbus_get_report(), the buffer is provided by the caller but happens to be the right length. Add a compile-time assertion to ensure this remains the case. Cc: # 3.19+ Signed-off-by: Ben Hutchings Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/mouse/elan_i2c.h | 2 ++ drivers/input/mouse/elan_i2c_core.c | 2 +- drivers/input/mouse/elan_i2c_smbus.c | 10 ++++++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h index c0ec26118732..83dd0ce3ad2a 100644 --- a/drivers/input/mouse/elan_i2c.h +++ b/drivers/input/mouse/elan_i2c.h @@ -27,6 +27,8 @@ #define ETP_DISABLE_POWER 0x0001 #define ETP_PRESSURE_OFFSET 25 +#define ETP_CALIBRATE_MAX_LEN 3 + /* IAP Firmware handling */ #define ETP_PRODUCT_ID_FORMAT_STRING "%d.0" #define ETP_FW_NAME "elan_i2c_" ETP_PRODUCT_ID_FORMAT_STRING ".bin" diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 2d6481f3e89b..97f6e05cffce 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -595,7 +595,7 @@ static ssize_t calibrate_store(struct device *dev, int tries = 20; int retval; int error; - u8 val[3]; + u8 val[ETP_CALIBRATE_MAX_LEN]; retval = mutex_lock_interruptible(&data->sysfs_mutex); if (retval) diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c index 05b8695a6369..d21bd55f3c42 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c @@ -56,7 +56,7 @@ static int elan_smbus_initialize(struct i2c_client *client) { u8 check[ETP_SMBUS_HELLOPACKET_LEN] = { 0x55, 0x55, 0x55, 0x55, 0x55 }; - u8 values[ETP_SMBUS_HELLOPACKET_LEN] = { 0, 0, 0, 0, 0 }; + u8 values[I2C_SMBUS_BLOCK_MAX] = {0}; int len, error; /* Get hello packet */ @@ -117,12 +117,16 @@ static int elan_smbus_calibrate(struct i2c_client *client) static int elan_smbus_calibrate_result(struct i2c_client *client, u8 *val) { int error; + u8 buf[I2C_SMBUS_BLOCK_MAX] = {0}; + + BUILD_BUG_ON(ETP_CALIBRATE_MAX_LEN > sizeof(buf)); error = i2c_smbus_read_block_data(client, - ETP_SMBUS_CALIBRATE_QUERY, val); + ETP_SMBUS_CALIBRATE_QUERY, buf); if (error < 0) return error; + memcpy(val, buf, ETP_CALIBRATE_MAX_LEN); return 0; } @@ -470,6 +474,8 @@ static int elan_smbus_get_report(struct i2c_client *client, u8 *report) { int len; + BUILD_BUG_ON(I2C_SMBUS_BLOCK_MAX > ETP_SMBUS_REPORT_LEN); + len = i2c_smbus_read_block_data(client, ETP_SMBUS_PACKET_QUERY, &report[ETP_SMBUS_REPORT_OFFSET]); -- GitLab From 465e965f64358fdeeb35287bd7a6dc06b261fb7b Mon Sep 17 00:00:00 2001 From: Aaron Ma Date: Thu, 21 Jun 2018 17:14:01 -0700 Subject: [PATCH 299/604] Input: elantech - enable middle button of touchpads on ThinkPad P52 commit 24bb555e6e46d96e2a954aa0295029a81cc9bbaa upstream. PNPID is better way to identify the type of touchpads. Enable middle button support on 2 types of touchpads on Lenovo P52. Cc: stable@vger.kernel.org Signed-off-by: Aaron Ma Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/mouse/elantech.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index c519c0b09568..a6333f942e12 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1173,6 +1173,12 @@ static const struct dmi_system_id elantech_dmi_has_middle_button[] = { { } }; +static const char * const middle_button_pnp_ids[] = { + "LEN2131", /* ThinkPad P52 w/ NFC */ + "LEN2132", /* ThinkPad P52 */ + NULL +}; + /* * Set the appropriate event bits for the input subsystem */ @@ -1192,7 +1198,8 @@ static int elantech_set_input_params(struct psmouse *psmouse) __clear_bit(EV_REL, dev->evbit); __set_bit(BTN_LEFT, dev->keybit); - if (dmi_check_system(elantech_dmi_has_middle_button)) + if (dmi_check_system(elantech_dmi_has_middle_button) || + psmouse_matches_pnp_id(psmouse, middle_button_pnp_ids)) __set_bit(BTN_MIDDLE, dev->keybit); __set_bit(BTN_RIGHT, dev->keybit); -- GitLab From 58d8103113ea911ed23cfd31c866f14c43773fb7 Mon Sep 17 00:00:00 2001 From: ??? Date: Thu, 21 Jun 2018 17:15:32 -0700 Subject: [PATCH 300/604] Input: elantech - fix V4 report decoding for module with middle key commit e0ae2519ca004a628fa55aeef969c37edce522d3 upstream. Some touchpad has middle key and it will be indicated in bit 2 of packet[0]. We need to fix V4 formation's byte mask to prevent error decoding. Signed-off-by: KT Liao Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/mouse/elantech.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index a6333f942e12..4e77adbfa835 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -800,7 +800,7 @@ static int elantech_packet_check_v4(struct psmouse *psmouse) else if (ic_version == 7 && etd->samples[1] == 0x2A) sanity_check = ((packet[3] & 0x1c) == 0x10); else - sanity_check = ((packet[0] & 0x0c) == 0x04 && + sanity_check = ((packet[0] & 0x08) == 0x00 && (packet[3] & 0x1c) == 0x10); if (!sanity_check) -- GitLab From 6008de291a2beab8028d04df9b0ea930e4fe4ce0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 13 Jun 2018 12:43:10 +0200 Subject: [PATCH 301/604] ALSA: hda/realtek - Fix pop noise on Lenovo P50 & co commit d5a6cabf02210b896a60eee7c04c670ee9ba6dca upstream. Some Lenovo laptops, e.g. Lenovo P50, showed the pop noise at resume or runtime resume. It turned out to be reduced by applying alc_no_shutup() just like TPT440 quirk does. Since there are many Lenovo models showing the same behavior, put this workaround in ALC269_FIXUP_THINKPAD_ACPI entry so that it's applied commonly to all such Lenovo machines. Reported-by: Hans de Goede Tested-by: Benjamin Berg Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 183436e4a8c1..60b989e20203 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4473,7 +4473,6 @@ static void alc_fixup_tpt440_dock(struct hda_codec *codec, struct alc_spec *spec = codec->spec; if (action == HDA_FIXUP_ACT_PRE_PROBE) { - spec->shutup = alc_no_shutup; /* reduce click noise */ spec->reboot_notify = alc_d3_at_reboot; /* reduce noise */ spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP; codec->power_save_node = 0; /* avoid click noises */ @@ -4835,6 +4834,13 @@ static void alc280_fixup_hp_9480m(struct hda_codec *codec, /* for hda_fixup_thinkpad_acpi() */ #include "thinkpad_helper.c" +static void alc_fixup_thinkpad_acpi(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + alc_fixup_no_shutup(codec, fix, action); /* reduce click noise */ + hda_fixup_thinkpad_acpi(codec, fix, action); +} + /* for dell wmi mic mute led */ #include "dell_wmi_helper.c" @@ -5350,7 +5356,7 @@ static const struct hda_fixup alc269_fixups[] = { }, [ALC269_FIXUP_THINKPAD_ACPI] = { .type = HDA_FIXUP_FUNC, - .v.func = hda_fixup_thinkpad_acpi, + .v.func = alc_fixup_thinkpad_acpi, .chained = true, .chain_id = ALC269_FIXUP_SKU_IGNORE, }, -- GitLab From afd82d0757b37a346fbc557c5974c0f0de1bb0d2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 22 Jun 2018 12:17:45 +0200 Subject: [PATCH 302/604] ALSA: hda/realtek - Add a quirk for FSC ESPRIMO U9210 commit 275ec0cb946cb75ac8977f662e608fce92f8b8a8 upstream. Fujitsu Seimens ESPRIMO Mobile U9210 requires the same fixup as H270 for the correct pin configs. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=200107 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 60b989e20203..f03a1430a3cb 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2448,6 +2448,7 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = { SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110), SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ), SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN), + SND_PCI_QUIRK(0x1734, 0x1141, "FSC ESPRIMO U9210", ALC262_FIXUP_FSC_H270), SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270), SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000), SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ), -- GitLab From 17057c59bd11911cff0f62715efcb556bab05ade Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Tue, 26 Jun 2018 09:14:58 -0600 Subject: [PATCH 303/604] block: Fix transfer when chunk sectors exceeds max commit 15bfd21fbc5d35834b9ea383dc458a1f0c9e3434 upstream. A device may have boundary restrictions where the number of sectors between boundaries exceeds its max transfer size. In this case, we need to cap the max size to the smaller of the two limits. Reported-by: Jitendra Bhivare Tested-by: Jitendra Bhivare Cc: Reviewed-by: Martin K. Petersen Signed-off-by: Keith Busch Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- include/linux/blkdev.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index f6a816129856..bd738aafd432 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -901,8 +901,8 @@ static inline unsigned int blk_max_size_offset(struct request_queue *q, if (!q->limits.chunk_sectors) return q->limits.max_sectors; - return q->limits.chunk_sectors - - (offset & (q->limits.chunk_sectors - 1)); + return min(q->limits.max_sectors, (unsigned int)(q->limits.chunk_sectors - + (offset & (q->limits.chunk_sectors - 1)))); } static inline unsigned int blk_rq_get_max_sectors(struct request *rq, -- GitLab From f2bc5d18d26350423446fcc073ad8750c20ec498 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Tue, 26 Jun 2018 12:04:23 -0400 Subject: [PATCH 304/604] dm thin: handle running out of data space vs concurrent discard commit a685557fbbc3122ed11e8ad3fa63a11ebc5de8c3 upstream. Discards issued to a DM thin device can complete to userspace (via fstrim) _before_ the metadata changes associated with the discards is reflected in the thinp superblock (e.g. free blocks). As such, if a user constructs a test that loops repeatedly over these steps, block allocation can fail due to discards not having completed yet: 1) fill thin device via filesystem file 2) remove file 3) fstrim From initial report, here: https://www.redhat.com/archives/dm-devel/2018-April/msg00022.html "The root cause of this issue is that dm-thin will first remove mapping and increase corresponding blocks' reference count to prevent them from being reused before DISCARD bios get processed by the underlying layers. However. increasing blocks' reference count could also increase the nr_allocated_this_transaction in struct sm_disk which makes smd->old_ll.nr_allocated + smd->nr_allocated_this_transaction bigger than smd->old_ll.nr_blocks. In this case, alloc_data_block() will never commit metadata to reset the begin pointer of struct sm_disk, because sm_disk_get_nr_free() always return an underflow value." While there is room for improvement to the space-map accounting that thinp is making use of: the reality is this test is inherently racey and will result in the previous iteration's fstrim's discard(s) completing vs concurrent block allocation, via dd, in the next iteration of the loop. No amount of space map accounting improvements will be able to allow user's to use a block before a discard of that block has completed. So the best we can really do is allow DM thinp to gracefully handle such aggressive use of all the pool's data by degrading the pool into out-of-data-space (OODS) mode. We _should_ get that behaviour already (if space map accounting didn't falsely cause alloc_data_block() to believe free space was available).. but short of that we handle the current reality that dm_pool_alloc_data_block() can return -ENOSPC. Reported-by: Dennis Yang Cc: stable@vger.kernel.org Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-thin.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 0b678b5da4c4..0f0374a4ac6e 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -1384,6 +1384,8 @@ static void schedule_external_copy(struct thin_c *tc, dm_block_t virt_block, static void set_pool_mode(struct pool *pool, enum pool_mode new_mode); +static void requeue_bios(struct pool *pool); + static void check_for_space(struct pool *pool) { int r; @@ -1396,8 +1398,10 @@ static void check_for_space(struct pool *pool) if (r) return; - if (nr_free) + if (nr_free) { set_pool_mode(pool, PM_WRITE); + requeue_bios(pool); + } } /* @@ -1474,7 +1478,10 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result) r = dm_pool_alloc_data_block(pool->pmd, result); if (r) { - metadata_operation_failed(pool, "dm_pool_alloc_data_block", r); + if (r == -ENOSPC) + set_pool_mode(pool, PM_OUT_OF_DATA_SPACE); + else + metadata_operation_failed(pool, "dm_pool_alloc_data_block", r); return r; } -- GitLab From 35fd10aeb2248cc7f8d3d48ccc2eff1cf19918f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Fri, 8 Jun 2018 09:15:24 +0200 Subject: [PATCH 305/604] cdc_ncm: avoid padding beyond end of skb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 49c2c3f246e2fc3009039e31a826333dcd0283cd upstream. Commit 4a0e3e989d66 ("cdc_ncm: Add support for moving NDP to end of NCM frame") added logic to reserve space for the NDP at the end of the NTB/skb. This reservation did not take the final alignment of the NDP into account, causing us to reserve too little space. Additionally the padding prior to NDP addition did not ensure there was enough space for the NDP. The NTB/skb with the NDP appended would then exceed the configured max size. This caused the final padding of the NTB to use a negative count, padding to almost INT_MAX, and resulting in: [60103.825970] BUG: unable to handle kernel paging request at ffff9641f2004000 [60103.825998] IP: __memset+0x24/0x30 [60103.826001] PGD a6a06067 P4D a6a06067 PUD 4f65a063 PMD 72003063 PTE 0 [60103.826013] Oops: 0002 [#1] SMP NOPTI [60103.826018] Modules linked in: (removed( [60103.826158] CPU: 0 PID: 5990 Comm: Chrome_DevTools Tainted: G O 4.14.0-3-amd64 #1 Debian 4.14.17-1 [60103.826162] Hardware name: LENOVO 20081 BIOS 41CN28WW(V2.04) 05/03/2012 [60103.826166] task: ffff964193484fc0 task.stack: ffffb2890137c000 [60103.826171] RIP: 0010:__memset+0x24/0x30 [60103.826174] RSP: 0000:ffff964316c03b68 EFLAGS: 00010216 [60103.826178] RAX: 0000000000000000 RBX: 00000000fffffffd RCX: 000000001ffa5000 [60103.826181] RDX: 0000000000000005 RSI: 0000000000000000 RDI: ffff9641f2003ffc [60103.826184] RBP: ffff964192f6c800 R08: 00000000304d434e R09: ffff9641f1d2c004 [60103.826187] R10: 0000000000000002 R11: 00000000000005ae R12: ffff9642e6957a80 [60103.826190] R13: ffff964282ff2ee8 R14: 000000000000000d R15: ffff9642e4843900 [60103.826194] FS: 00007f395aaf6700(0000) GS:ffff964316c00000(0000) knlGS:0000000000000000 [60103.826197] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [60103.826200] CR2: ffff9641f2004000 CR3: 0000000013b0c000 CR4: 00000000000006f0 [60103.826204] Call Trace: [60103.826212] [60103.826225] cdc_ncm_fill_tx_frame+0x5e3/0x740 [cdc_ncm] [60103.826236] cdc_ncm_tx_fixup+0x57/0x70 [cdc_ncm] [60103.826246] usbnet_start_xmit+0x5d/0x710 [usbnet] [60103.826254] ? netif_skb_features+0x119/0x250 [60103.826259] dev_hard_start_xmit+0xa1/0x200 [60103.826267] sch_direct_xmit+0xf2/0x1b0 [60103.826273] __dev_queue_xmit+0x5e3/0x7c0 [60103.826280] ? ip_finish_output2+0x263/0x3c0 [60103.826284] ip_finish_output2+0x263/0x3c0 [60103.826289] ? ip_output+0x6c/0xe0 [60103.826293] ip_output+0x6c/0xe0 [60103.826298] ? ip_forward_options+0x1a0/0x1a0 [60103.826303] tcp_transmit_skb+0x516/0x9b0 [60103.826309] tcp_write_xmit+0x1aa/0xee0 [60103.826313] ? sch_direct_xmit+0x71/0x1b0 [60103.826318] tcp_tasklet_func+0x177/0x180 [60103.826325] tasklet_action+0x5f/0x110 [60103.826332] __do_softirq+0xde/0x2b3 [60103.826337] irq_exit+0xae/0xb0 [60103.826342] do_IRQ+0x81/0xd0 [60103.826347] common_interrupt+0x98/0x98 [60103.826351] [60103.826355] RIP: 0033:0x7f397bdf2282 [60103.826358] RSP: 002b:00007f395aaf57d8 EFLAGS: 00000206 ORIG_RAX: ffffffffffffff6e [60103.826362] RAX: 0000000000000000 RBX: 00002f07bc6d0900 RCX: 00007f39752d7fe7 [60103.826365] RDX: 0000000000000022 RSI: 0000000000000147 RDI: 00002f07baea02c0 [60103.826368] RBP: 0000000000000001 R08: 0000000000000000 R09: 0000000000000000 [60103.826371] R10: 00000000ffffffff R11: 0000000000000000 R12: 00002f07baea02c0 [60103.826373] R13: 00002f07bba227a0 R14: 00002f07bc6d090c R15: 0000000000000000 [60103.826377] Code: 90 90 90 90 90 90 90 0f 1f 44 00 00 49 89 f9 48 89 d1 83 e2 07 48 c1 e9 03 40 0f b6 f6 48 b8 01 01 01 01 01 01 01 01 48 0f af c6 48 ab 89 d1 f3 aa 4c 89 c8 c3 90 49 89 f9 40 88 f0 48 89 d1 [60103.826442] RIP: __memset+0x24/0x30 RSP: ffff964316c03b68 [60103.826444] CR2: ffff9641f2004000 Commit e1069bbfcf3b ("net: cdc_ncm: Reduce memory use when kernel memory low") made this bug much more likely to trigger by reducing the NTB size under memory pressure. Link: https://bugs.debian.org/893393 Reported-by: Горбешко Богдан Reported-and-tested-by: Dennis Wassenberg Cc: Enrico Mioso Fixes: 4a0e3e989d66 ("cdc_ncm: Add support for moving NDP to end of NCM frame") [ bmork: tx_curr_size => tx_max and context fixup for v4.12 and older ] Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/cdc_ncm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index feb61eaffe32..3086cae62fdc 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1124,7 +1124,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) * accordingly. Otherwise, we should check here. */ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) - delayed_ndp_size = ctx->max_ndp_size; + delayed_ndp_size = ALIGN(ctx->max_ndp_size, ctx->tx_ndp_modulus); else delayed_ndp_size = 0; @@ -1257,7 +1257,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) /* If requested, put NDP at end of frame. */ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) { nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data; - cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_max); + cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_max - ctx->max_ndp_size); nth16->wNdpIndex = cpu_to_le16(skb_out->len); memcpy(skb_put(skb_out, ctx->max_ndp_size), ctx->delayed_ndp16, ctx->max_ndp_size); -- GitLab From e692f66fab3019ca8f45463df165177505f38caa Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 3 Jul 2018 11:23:18 +0200 Subject: [PATCH 306/604] Linux 4.9.111 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2fcfe1147eaa..b10646531fcd 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 110 +SUBLEVEL = 111 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From ae3d0eeaf80619127cddca86bb6eb113d6ff0526 Mon Sep 17 00:00:00 2001 From: Teng Fei Fan Date: Tue, 5 Jun 2018 10:50:32 +0800 Subject: [PATCH 307/604] arm: Add BTB invalidation on switch_mm for Cortex-A73 Invalidate the BTB when switching from one user context to another, to avoid aliasing attacks against the branch predictor. Change-Id: I175931afda9b81f961e6c0831da299d2f79aa175 Signed-off-by: Teng Fei Fan --- arch/arm/include/asm/cputype.h | 2 ++ arch/arm/include/asm/mmu_context.h | 16 +++++++++++++- arch/arm/kernel/setup.c | 35 ++++++++++++++++++++++++++++++ arch/arm/kernel/smp.c | 2 ++ arch/arm/mm/Kconfig | 17 +++++++++++++++ arch/arm/mm/context.c | 1 + 6 files changed, 72 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h index b62eaeb147aa..174346bcdc34 100644 --- a/arch/arm/include/asm/cputype.h +++ b/arch/arm/include/asm/cputype.h @@ -76,6 +76,8 @@ #define ARM_CPU_PART_CORTEX_A12 0x4100c0d0 #define ARM_CPU_PART_CORTEX_A17 0x4100c0e0 #define ARM_CPU_PART_CORTEX_A15 0x4100c0f0 +#define ARM_CPU_PART_CORTEX_A73 0x4100d090 +#define ARM_CPU_PART_KRYO2XX_GOLD 0x51008000 #define ARM_CPU_PART_MASK 0xff00fff0 /* DEC implemented cores */ diff --git a/arch/arm/include/asm/mmu_context.h b/arch/arm/include/asm/mmu_context.h index 3cc14dd8587c..0c835ee0f04b 100644 --- a/arch/arm/include/asm/mmu_context.h +++ b/arch/arm/include/asm/mmu_context.h @@ -24,6 +24,18 @@ void __check_vmalloc_seq(struct mm_struct *mm); +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR +void arm_init_bp_hardening(void); +void arm_apply_bp_hardening(void); +#else +static inline void arm_init_bp_hardening(void) +{ +} +static inline void arm_apply_bp_hardening(void) +{ +} +#endif + #ifdef CONFIG_CPU_HAS_ASID void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk); @@ -63,8 +75,10 @@ static inline void check_and_switch_context(struct mm_struct *mm, * finish_arch_post_lock_switch() call. */ mm->context.switch_pending = 1; - else + else { + arm_apply_bp_hardening(); cpu_switch_mm(mm->pgd, mm); + } } #ifndef MODULE diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 09dd8ff379cb..4f451ce92164 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -243,6 +243,40 @@ static const char *proc_arch[] = { "?(17)", }; +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR +struct arm_btbinv { + void (*apply_bp_hardening)(void); +}; +static DEFINE_PER_CPU_READ_MOSTLY(struct arm_btbinv, arm_btbinv); + +static void arm_a73_apply_bp_hardening(void) +{ + asm("mov r2, #0"); + asm("mcr p15, 0, r2, c7, c5, 6"); +} + +void arm_apply_bp_hardening(void) +{ + if (this_cpu_ptr(&arm_btbinv)->apply_bp_hardening) + this_cpu_ptr(&arm_btbinv)->apply_bp_hardening(); +} + +void arm_init_bp_hardening(void) +{ + switch (read_cpuid_part()) { + case ARM_CPU_PART_CORTEX_A73: + case ARM_CPU_PART_KRYO2XX_GOLD: + per_cpu(arm_btbinv.apply_bp_hardening, raw_smp_processor_id()) + = arm_a73_apply_bp_hardening; + break; + default: + per_cpu(arm_btbinv.apply_bp_hardening, raw_smp_processor_id()) + = NULL; + break; + } +} +#endif + #ifdef CONFIG_CPU_V7M static int __get_cpu_architecture(void) { @@ -685,6 +719,7 @@ static void __init setup_processor(void) * types. The linker builds this table for us from the * entries in arch/arm/mm/proc-*.S */ + arm_init_bp_hardening(); list = lookup_processor_type(read_cpuid_id()); if (!list) { pr_err("CPU configuration botched (ID %08x), unable to continue.\n", diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index a03a99ae7ac6..373d23eebe10 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -47,6 +47,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -361,6 +362,7 @@ asmlinkage void secondary_start_kernel(void) * The identity mapping is uncached (strongly ordered), so * switch away from it before attempting any exclusive accesses. */ + arm_init_bp_hardening(); cpu_switch_mm(mm->pgd, mm); local_flush_bp_all(); enter_lazy_tlb(mm, current); diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index c1799dd1d0d9..1a5acee44c4f 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -1068,3 +1068,20 @@ config DEBUG_ALIGN_RODATA additional section-aligned split of rodata from kernel text so it can be made explicitly non-executable. This padding may waste memory space to gain the additional protection. + +config HARDEN_BRANCH_PREDICTOR + bool "Harden the branch predictor against aliasing attacks" if EXPERT + default y + help + Speculation attacks against some high-performance processors rely on + being able to manipulate the branch predictor for a victim context by + executing aliasing branches in the attacker context. Such attacks + can be partially mitigated against by clearing internal branch + predictor state and limiting the prediction logic in some situations. + + This config option will take CPU-specific actions to harden the + branch predictor against aliasing attacks and may rely on specific + instruction sequences or control bits being set by the system + firmware. + + If unsure, say Y. diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c index c8c8b9ed02e0..f1874392c875 100644 --- a/arch/arm/mm/context.c +++ b/arch/arm/mm/context.c @@ -276,5 +276,6 @@ void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk) raw_spin_unlock_irqrestore(&cpu_asid_lock, flags); switch_mm_fastpath: + arm_apply_bp_hardening(); cpu_switch_mm(mm->pgd, mm); } -- GitLab From d79e38f71fdc40256bed28aad5841f7ed6020818 Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Mon, 25 Jun 2018 14:17:26 +0530 Subject: [PATCH 308/604] scsi: ufs: avoid deadlock by releasing rw_sem during hibernate Consider the below scenario: Three contexts: 1. Exception event handler [eeh] 2. Clock scaling 3. Error handler [eh] - Exception was raised - eeh runs - acquires dev.cmd.lock [1] - waits for rw_sem [3] - scaling is triggered from userspace - acquires rw_sem [2] - issues hibern8 - error in hibern8 - triggers error-handler (eh) - flushes eh [4] - eh is scheduled - waits on dev.cmd.lock [5] So, [3] waits for [2] which flushes eh and waits on [5] which has been acquired by [1] So, release the rw_sem before issuing hibern8 and flush pending error handler work if any, during clock scaling triggered from user-space. Change-Id: I968dd3d87bdfbf0aa1373a879a75f3c17349564e Signed-off-by: Asutosh Das --- drivers/scsi/ufs/ufshcd.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index c6cfd18c6510..0d72cd07e9b7 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -10239,7 +10239,15 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up) * racing during clock frequency scaling sequence. */ if (ufshcd_is_auto_hibern8_supported(hba)) { + /* + * Scaling prepare acquires the rw_sem: lock + * h8 may sleep in case of errors. + * e.g. link_recovery. Hence, release the rw_sem + * before hibern8. + */ + up_write(&hba->lock); ret = ufshcd_uic_hibern8_enter(hba); + down_write(&hba->lock); if (ret) /* link will be bad state so no need to scale_up_gear */ return ret; @@ -10370,6 +10378,8 @@ static ssize_t ufshcd_clkscale_enable_store(struct device *dev, hba->clk_scaling.is_allowed = value; + flush_work(&hba->eh_work); + if (value) { ufshcd_resume_clkscaling(hba); } else { -- GitLab From 4a1c735a5a1fe94b3a370e0fbcd9d3841c5d0175 Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Thu, 5 Jul 2018 10:55:32 +0530 Subject: [PATCH 309/604] msm: sps: Suppress bind/unbind attributes SPS driver does not support manual bind/unbind operations through sysfs. Suppress the bind/unbind nodes. Do not free SPS struct in sps_device_de_init since it is being done in sps_exit, and also to avoid use-after-free. Change-Id: If6da6c5fb9d1a44d0420c6151f7f9d0a33cb2d04 Signed-off-by: Siva Kumar Akkireddi --- drivers/platform/msm/sps/sps.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c index 6e54fbfae671..05a8c66d57aa 100644 --- a/drivers/platform/msm/sps/sps.c +++ b/drivers/platform/msm/sps/sps.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* 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 @@ -1020,8 +1020,6 @@ static void sps_device_de_init(void) "sps:%s:BAMs are still registered", __func__); sps_map_de_init(); - - kfree(sps); } sps_mem_de_init(); @@ -3006,6 +3004,7 @@ static struct platform_driver msm_sps_driver = { .name = SPS_DRV_NAME, .owner = THIS_MODULE, .of_match_table = msm_sps_match, + .suppress_bind_attrs = true, }, .remove = msm_sps_remove, }; -- GitLab From 32a3877f836097cf111149a15bf83d3fec2d3436 Mon Sep 17 00:00:00 2001 From: Sureshnaidu Laveti Date: Tue, 26 Jun 2018 13:06:15 -0700 Subject: [PATCH 310/604] msm: camera: Fix for actuator manual move lens not working Register Actuator with CRM as real time device. Correct request ID for actuator manual lens move command for the lens to move in sync with request ID with frame delay of 1. Change-Id: I97da811c943fa41fb3291cd5eeaa282b048bcc09 Signed-off-by: Sureshnaidu Laveti --- .../cam_actuator/cam_actuator_core.c | 58 ++++++++++++++----- 1 file changed, 42 insertions(+), 16 deletions(-) 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 da8ff21cd06f..795902730efc 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 @@ -269,7 +269,10 @@ int32_t cam_actuator_apply_settings(struct cam_actuator_ctrl_t *a_ctrl, CAM_ERR(CAM_ACTUATOR, "Failed to apply settings: %d", rc); - return rc; + } else { + CAM_DBG(CAM_ACTUATOR, + "Success:request ID: %d", + i2c_set->request_id); } } @@ -359,6 +362,28 @@ int32_t cam_actuator_establish_link( return 0; } +static void cam_actuator_update_req_mgr( + struct cam_actuator_ctrl_t *a_ctrl, + struct cam_packet *csl_packet) +{ + struct cam_req_mgr_add_request add_req; + + add_req.link_hdl = a_ctrl->bridge_intf.link_hdl; + add_req.req_id = csl_packet->header.request_id; + add_req.dev_hdl = a_ctrl->bridge_intf.device_hdl; + add_req.skip_before_applying = 0; + + if (a_ctrl->bridge_intf.crm_cb && + a_ctrl->bridge_intf.crm_cb->add_req) { + a_ctrl->bridge_intf.crm_cb->add_req(&add_req); + CAM_DBG(CAM_ACTUATOR, "Request Id: %lld added to CRM", + add_req.req_id); + } else { + CAM_ERR(CAM_ACTUATOR, "Can't add Request ID: %lld to CRM", + csl_packet->header.request_id); + } +} + int32_t cam_actuator_publish_dev_info(struct cam_req_mgr_device_info *info) { if (!info) { @@ -368,7 +393,7 @@ int32_t cam_actuator_publish_dev_info(struct cam_req_mgr_device_info *info) info->dev_id = CAM_REQ_MGR_DEVICE_ACTUATOR; strlcpy(info->name, CAM_ACTUATOR_NAME, sizeof(info->name)); - info->p_delay = 0; + info->p_delay = 1; info->trigger = CAM_TRIGGER_POINT_SOF; return 0; @@ -391,7 +416,6 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, struct i2c_data_settings *i2c_data = NULL; struct i2c_settings_array *i2c_reg_settings = NULL; struct cam_cmd_buf_desc *cmd_desc = NULL; - struct cam_req_mgr_add_request add_req; struct cam_actuator_soc_private *soc_private = NULL; struct cam_sensor_power_ctrl_t *power_info = NULL; @@ -555,6 +579,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, "Auto move lens parsing failed: %d", rc); return rc; } + cam_actuator_update_req_mgr(a_ctrl, csl_packet); break; case CAM_ACTUATOR_PACKET_MANUAL_MOVE_LENS: if (a_ctrl->cam_act_state < CAM_ACTUATOR_CONFIG) { @@ -564,11 +589,13 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, a_ctrl->cam_act_state); return rc; } + + a_ctrl->setting_apply_state = ACT_APPLY_SETTINGS_LATER; i2c_data = &(a_ctrl->i2c_data); i2c_reg_settings = &i2c_data->per_frame[ csl_packet->header.request_id % MAX_PER_FRAME_ARRAY]; - i2c_data->init_settings.request_id = + i2c_reg_settings->request_id = csl_packet->header.request_id; i2c_reg_settings->is_settings_valid = 1; offset = (uint32_t *)&csl_packet->payload; @@ -583,20 +610,19 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, "Manual move lens parsing failed: %d", rc); return rc; } + + cam_actuator_update_req_mgr(a_ctrl, csl_packet); break; - } + case CAM_PKT_NOP_OPCODE: + if (a_ctrl->cam_act_state < CAM_ACTUATOR_CONFIG) { + CAM_WARN(CAM_ACTUATOR, + "Received NOP packets in invalid state: %d", + a_ctrl->cam_act_state); + return -EINVAL; + } - if ((csl_packet->header.op_code & 0xFFFFFF) != - CAM_ACTUATOR_PACKET_OPCODE_INIT) { - add_req.link_hdl = a_ctrl->bridge_intf.link_hdl; - add_req.req_id = csl_packet->header.request_id; - add_req.dev_hdl = a_ctrl->bridge_intf.device_hdl; - add_req.skip_before_applying = 0; - if (a_ctrl->bridge_intf.crm_cb && - a_ctrl->bridge_intf.crm_cb->add_req) - a_ctrl->bridge_intf.crm_cb->add_req(&add_req); - CAM_DBG(CAM_ACTUATOR, "Req Id: %lld added to Bridge", - add_req.req_id); + cam_actuator_update_req_mgr(a_ctrl, csl_packet); + break; } return rc; -- GitLab From 8d6666334d027487a9e04c1065b78a55f97dc415 Mon Sep 17 00:00:00 2001 From: Junzhe Zou Date: Fri, 22 Jun 2018 17:40:06 -0700 Subject: [PATCH 311/604] msm: camera: isp: acquire tasklet cmd before processing top half If enqueue_tasklet fails, the payload is leaked because the release happens in bottom_half which will never be called. Acquire tasklet cmd before processing IRQ so that no resource is allocated unless IRQ can be scheduled to tasklet. Change-Id: I7c38189055c50300ca643a8e94f16a0598b435ee Signed-off-by: Junzhe Zou --- .../isp_hw_mgr/hw_utils/cam_tasklet_util.c | 89 ++++++++++--------- .../hw_utils/include/cam_tasklet_util.h | 36 +++++++- .../irq_controller/cam_irq_controller.c | 62 ++++++++++--- .../irq_controller/cam_irq_controller.h | 20 ++++- .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 6 +- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 8 +- 6 files changed, 153 insertions(+), 68 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 3a897328eeb3..b9c51de98dcc 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 @@ -70,25 +70,27 @@ struct cam_tasklet_info { void *ctx_priv; }; -/** - * cam_tasklet_get_cmd() - * - * @brief: Get free cmd from tasklet - * - * @tasklet: Tasklet Info structure to get cmd from - * @tasklet_cmd: Return tasklet_cmd pointer if successful - * - * @return: 0: Success - * Negative: Failure - */ -static int cam_tasklet_get_cmd( - struct cam_tasklet_info *tasklet, - struct cam_tasklet_queue_cmd **tasklet_cmd) +struct cam_irq_bh_api tasklet_bh_api = { + .bottom_half_enqueue_func = cam_tasklet_enqueue_cmd, + .get_bh_payload_func = cam_tasklet_get_cmd, + .put_bh_payload_func = cam_tasklet_put_cmd, +}; + +int cam_tasklet_get_cmd( + void *bottom_half, + void **bh_cmd) { int rc = 0; unsigned long flags; + struct cam_tasklet_info *tasklet = bottom_half; + struct cam_tasklet_queue_cmd *tasklet_cmd = NULL; - *tasklet_cmd = NULL; + *bh_cmd = NULL; + + if (tasklet == NULL) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "tasklet is NULL"); + return -EINVAL; + } if (!atomic_read(&tasklet->tasklet_active)) { CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet is not active!\n"); @@ -102,9 +104,10 @@ static int cam_tasklet_get_cmd( rc = -ENODEV; goto spin_unlock; } else { - *tasklet_cmd = list_first_entry(&tasklet->free_cmd_list, + tasklet_cmd = list_first_entry(&tasklet->free_cmd_list, struct cam_tasklet_queue_cmd, list); - list_del_init(&(*tasklet_cmd)->list); + list_del_init(&(tasklet_cmd)->list); + *bh_cmd = tasklet_cmd; } spin_unlock: @@ -112,25 +115,28 @@ static int cam_tasklet_get_cmd( return rc; } -/** - * cam_tasklet_put_cmd() - * - * @brief: Put back cmd to free list - * - * @tasklet: Tasklet Info structure to put cmd into - * @tasklet_cmd: tasklet_cmd pointer that needs to be put back - * - * @return: Void - */ -static void cam_tasklet_put_cmd( - struct cam_tasklet_info *tasklet, - struct cam_tasklet_queue_cmd **tasklet_cmd) +void cam_tasklet_put_cmd( + void *bottom_half, + void **bh_cmd) { unsigned long flags; + struct cam_tasklet_info *tasklet = bottom_half; + struct cam_tasklet_queue_cmd *tasklet_cmd = *bh_cmd; + + if (tasklet == NULL) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "tasklet is NULL"); + return; + } + + if (tasklet_cmd == NULL) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid tasklet_cmd"); + return; + } spin_lock_irqsave(&tasklet->tasklet_lock, flags); - list_add_tail(&(*tasklet_cmd)->list, - &tasklet->free_cmd_list); + list_del_init(&tasklet_cmd->list); + list_add_tail(&tasklet_cmd->list, &tasklet->free_cmd_list); + *bh_cmd = NULL; spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); } @@ -181,23 +187,26 @@ static int cam_tasklet_dequeue_cmd( return rc; } -int cam_tasklet_enqueue_cmd( +void cam_tasklet_enqueue_cmd( void *bottom_half, + void *bh_cmd, void *handler_priv, void *evt_payload_priv, CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler) { - struct cam_tasklet_info *tasklet = bottom_half; - struct cam_tasklet_queue_cmd *tasklet_cmd = NULL; unsigned long flags; - int rc; + struct cam_tasklet_queue_cmd *tasklet_cmd = bh_cmd; + struct cam_tasklet_info *tasklet = bottom_half; if (!bottom_half) { CAM_ERR(CAM_ISP, "NULL bottom half"); - return -EINVAL; + return; } - rc = cam_tasklet_get_cmd(tasklet, &tasklet_cmd); + if (!bh_cmd) { + CAM_ERR(CAM_ISP, "NULL bh cmd"); + return; + } if (tasklet_cmd) { CAM_DBG(CAM_ISP, "Enqueue tasklet cmd"); @@ -211,8 +220,6 @@ int cam_tasklet_enqueue_cmd( } else { CAM_ERR(CAM_ISP, "tasklet cmd is NULL!"); } - - return rc; } int cam_tasklet_init( @@ -323,7 +330,7 @@ static void cam_tasklet_action(unsigned long data) while (!cam_tasklet_dequeue_cmd(tasklet_info, &tasklet_cmd)) { tasklet_cmd->bottom_half_handler(tasklet_info->ctx_priv, tasklet_cmd->payload); - cam_tasklet_put_cmd(tasklet_info, &tasklet_cmd); + cam_tasklet_put_cmd(tasklet_info, (void **)(&tasklet_cmd)); } } diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h index 0e4bf1261ca1..8bd93d81f620 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.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 @@ -76,6 +76,7 @@ void cam_tasklet_stop(void *tasklet); * @brief: Enqueue the tasklet_cmd to used list * * @bottom_half: Tasklet info to enqueue onto + * @bh_cmd: Tasklet cmd used to enqueue task * @handler_priv: Private Handler data that will be passed to the * handler function * @evt_payload_priv: Event payload that will be passed to the handler @@ -83,13 +84,40 @@ void cam_tasklet_stop(void *tasklet); * @bottom_half_handler: Callback function that will be called by tasklet * for handling event * - * @return: 0: Success - * Negative: Failure + * @return: Void */ -int cam_tasklet_enqueue_cmd( +void cam_tasklet_enqueue_cmd( void *bottom_half, + void *bh_cmd, void *handler_priv, void *evt_payload_priv, CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler); +/** + * cam_tasklet_get_cmd() + * + * @brief: Get free cmd from tasklet + * + * @bottom_half: Tasklet Info structure to get cmd from + * @bh_cmd: Return tasklet_cmd pointer if successful + * + * @return: 0: Success + * Negative: Failure + */ +int cam_tasklet_get_cmd(void *bottom_half, void **bh_cmd); + +/** + * cam_tasklet_put_cmd() + * + * @brief: Put back cmd to free list + * + * @bottom_half: Tasklet Info structure to put cmd into + * @bh_cmd: tasklet_cmd pointer that needs to be put back + * + * @return: Void + */ +void cam_tasklet_put_cmd(void *bottom_half, void **bh_cmd); + +extern struct cam_irq_bh_api tasklet_bh_api; + #endif /* _CAM_TASKLET_UTIL_H_ */ diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c index feb79ccc658d..931574afa1b3 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c @@ -13,6 +13,8 @@ #include #include #include +#include + #include "cam_io_util.h" #include "cam_irq_controller.h" #include "cam_debug_util.h" @@ -42,7 +44,7 @@ struct cam_irq_evt_handler { CAM_IRQ_HANDLER_TOP_HALF top_half_handler; CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler; void *bottom_half; - CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC bottom_half_enqueue_func; + struct cam_irq_bh_api irq_bh_api; struct list_head list_node; struct list_head th_list_node; int index; @@ -232,7 +234,7 @@ int cam_irq_controller_subscribe_irq(void *irq_controller, CAM_IRQ_HANDLER_TOP_HALF top_half_handler, CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler, void *bottom_half, - CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC bottom_half_enqueue_func) + struct cam_irq_bh_api *irq_bh_api) { struct cam_irq_controller *controller = irq_controller; struct cam_irq_evt_handler *evt_handler = NULL; @@ -255,12 +257,24 @@ int cam_irq_controller_subscribe_irq(void *irq_controller, } if (bottom_half_handler && - (!bottom_half || !bottom_half_enqueue_func)) { + (!bottom_half || !irq_bh_api)) { CAM_ERR(CAM_ISP, "Invalid params: bh_handler=%pK bh=%pK bh_enq_f=%pK", bottom_half_handler, bottom_half, - bottom_half_enqueue_func); + irq_bh_api); + return -EINVAL; + } + + if (irq_bh_api && + (!irq_bh_api->bottom_half_enqueue_func || + !irq_bh_api->get_bh_payload_func || + !irq_bh_api->put_bh_payload_func)) { + CAM_ERR(CAM_ISP, + "Invalid: enqueue_func=%pK get_bh=%pK put_bh=%pK", + irq_bh_api->bottom_half_enqueue_func, + irq_bh_api->get_bh_payload_func, + irq_bh_api->put_bh_payload_func); return -EINVAL; } @@ -295,9 +309,11 @@ int cam_irq_controller_subscribe_irq(void *irq_controller, evt_handler->top_half_handler = top_half_handler; evt_handler->bottom_half_handler = bottom_half_handler; evt_handler->bottom_half = bottom_half; - evt_handler->bottom_half_enqueue_func = bottom_half_enqueue_func; evt_handler->index = controller->hdl_idx++; + if (irq_bh_api) + evt_handler->irq_bh_api = *irq_bh_api; + /* Avoid rollover to negative values */ if (controller->hdl_idx > 0x3FFFFFFF) controller->hdl_idx = 1; @@ -564,6 +580,8 @@ static void cam_irq_controller_th_processing( bool is_irq_match; int rc = -EINVAL; int i; + void *bh_cmd = NULL; + struct cam_irq_bh_api *irq_bh_api = NULL; CAM_DBG(CAM_ISP, "Enter"); @@ -588,6 +606,19 @@ static void cam_irq_controller_th_processing( evt_handler->evt_bit_mask_arr[i]; } + irq_bh_api = &evt_handler->irq_bh_api; + bh_cmd = NULL; + + if (evt_handler->bottom_half_handler) { + rc = irq_bh_api->get_bh_payload_func( + evt_handler->bottom_half, &bh_cmd); + if (rc || !bh_cmd) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Can't get bh payload"); + continue; + } + } + /* * irq_status_arr[0] is dummy argument passed. the entire * status array is passed in th_payload. @@ -597,16 +628,21 @@ static void cam_irq_controller_th_processing( controller->irq_status_arr[0], (void *)th_payload); - if (!rc && evt_handler->bottom_half_handler) { + if (rc && bh_cmd) { + irq_bh_api->put_bh_payload_func( + evt_handler->bottom_half, &bh_cmd); + continue; + } + + if (evt_handler->bottom_half_handler) { CAM_DBG(CAM_ISP, "Enqueuing bottom half for %s", controller->name); - if (evt_handler->bottom_half_enqueue_func) { - evt_handler->bottom_half_enqueue_func( - evt_handler->bottom_half, - evt_handler->handler_priv, - th_payload->evt_payload_priv, - evt_handler->bottom_half_handler); - } + irq_bh_api->bottom_half_enqueue_func( + evt_handler->bottom_half, + bh_cmd, + evt_handler->handler_priv, + th_payload->evt_payload_priv, + evt_handler->bottom_half_handler); } } diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h index e3071ac2f230..c3c1e7c936ce 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.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 @@ -111,10 +111,22 @@ typedef int (*CAM_IRQ_HANDLER_TOP_HALF)(uint32_t evt_id, typedef int (*CAM_IRQ_HANDLER_BOTTOM_HALF)(void *handler_priv, void *evt_payload_priv); -typedef int (*CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC)(void *bottom_half, - void *handler_priv, void *evt_payload_priv, +typedef void (*CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC)(void *bottom_half, + void *bh_cmd, void *handler_priv, void *evt_payload_priv, CAM_IRQ_HANDLER_BOTTOM_HALF); +typedef int (*CAM_IRQ_GET_TASKLET_PAYLOAD_FUNC)(void *bottom_half, + void **bh_cmd); + +typedef void (*CAM_IRQ_PUT_TASKLET_PAYLOAD_FUNC)(void *bottom_half, + void **bh_cmd); + +struct cam_irq_bh_api { + CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC bottom_half_enqueue_func; + CAM_IRQ_GET_TASKLET_PAYLOAD_FUNC get_bh_payload_func; + CAM_IRQ_PUT_TASKLET_PAYLOAD_FUNC put_bh_payload_func; +}; + /* * cam_irq_controller_init() * @@ -165,7 +177,7 @@ int cam_irq_controller_subscribe_irq(void *irq_controller, CAM_IRQ_HANDLER_TOP_HALF top_half_handler, CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler, void *bottom_half, - CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC bottom_half_enqueue_func); + struct cam_irq_bh_api *irq_bh_api); /* * cam_irq_controller_unsubscribe_irq() 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 fd38a964faf6..3538e75822e5 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 @@ -560,7 +560,7 @@ int cam_vfe_start(void *hw_priv, void *start_args, uint32_t arg_size) cam_vfe_irq_top_half, cam_ife_mgr_do_tasklet, isp_res->tasklet_info, - cam_tasklet_enqueue_cmd); + &tasklet_bh_api); if (isp_res->irq_handle < 1) rc = -ENOMEM; } else if (isp_res->rdi_only_ctx) { @@ -573,7 +573,7 @@ int cam_vfe_start(void *hw_priv, void *start_args, uint32_t arg_size) cam_vfe_irq_top_half, cam_ife_mgr_do_tasklet, isp_res->tasklet_info, - cam_tasklet_enqueue_cmd); + &tasklet_bh_api); if (isp_res->irq_handle < 1) rc = -ENOMEM; } @@ -606,7 +606,7 @@ int cam_vfe_start(void *hw_priv, void *start_args, uint32_t arg_size) cam_vfe_irq_err_top_half, cam_ife_mgr_do_tasklet, core_info->tasklet_info, - cam_tasklet_enqueue_cmd); + &tasklet_bh_api); if (core_info->irq_err_handle < 1) { CAM_ERR(CAM_ISP, "Error handle subscribe failure"); rc = -ENOMEM; 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 3c37b83a2256..afe496b398b5 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 @@ -1084,7 +1084,7 @@ static int cam_vfe_bus_start_wm(struct cam_isp_resource_node *wm_res) bus_irq_reg_mask, wm_res, wm_res->top_half_handler, cam_ife_mgr_do_tasklet_buf_done, - wm_res->tasklet_info, cam_tasklet_enqueue_cmd); + wm_res->tasklet_info, &tasklet_bh_api); if (wm_res->irq_handle < 0) { CAM_ERR(CAM_ISP, "Subscribe IRQ failed for WM %d", rsrc_data->index); @@ -1565,7 +1565,7 @@ static int cam_vfe_bus_start_comp_grp(struct cam_isp_resource_node *comp_grp) bus_irq_reg_mask, comp_grp, comp_grp->top_half_handler, cam_ife_mgr_do_tasklet_buf_done, - comp_grp->tasklet_info, cam_tasklet_enqueue_cmd); + comp_grp->tasklet_info, &tasklet_bh_api); if (comp_grp->irq_handle < 0) { CAM_ERR(CAM_ISP, "Subscribe IRQ failed for comp_grp %d", rsrc_data->comp_grp_type); @@ -2251,11 +2251,13 @@ static int cam_vfe_bus_ver2_handle_irq(uint32_t evt_id, struct cam_irq_th_payload *th_payload) { struct cam_vfe_bus_ver2_priv *bus_priv; + int rc = 0; bus_priv = th_payload->handler_priv; CAM_DBG(CAM_ISP, "Enter"); - return cam_irq_controller_handle_irq(evt_id, + rc = cam_irq_controller_handle_irq(evt_id, bus_priv->common_data.bus_irq_controller); + return (rc == IRQ_HANDLED) ? 0 : -EINVAL; } static int cam_vfe_bus_error_irq_top_half(uint32_t evt_id, -- GitLab From 3b7805c1f2b225a030ec052acb7f25efa0fa4e03 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Tue, 12 Jun 2018 20:48:47 -0700 Subject: [PATCH 312/604] msm: camera: Fix power related issues across sensor modules Assign the power settings pointer to null after freeing it and reset the power settings size variable to 0. Free power settings if the sensor is in correct state. Add check in acquire device to verify if the device has been probed successfully before acquire. Change-Id: I73f795fd0d8f0c3f17d49d2895c896bc6d349eea Signed-off-by: Jigarkumar Zala Signed-off-by: Vishalsingh Hajeri --- .../cam_actuator/cam_actuator_core.c | 18 +- .../cam_eeprom/cam_eeprom_core.c | 4 + .../cam_sensor_module/cam_ois/cam_ois_core.c | 29 ++- .../cam_sensor/cam_sensor_core.c | 55 +++-- .../cam_sensor_utils/cam_sensor_util.c | 222 ++++++++++++------ 5 files changed, 220 insertions(+), 108 deletions(-) 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 795902730efc..a48cfa239293 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 @@ -54,6 +54,7 @@ int32_t cam_actuator_construct_default_power_setting( free_power_settings: kfree(power_info->power_setting); power_info->power_setting = NULL; + power_info->power_setting_size = 0; return rc; } @@ -659,6 +660,8 @@ void cam_actuator_shutdown(struct cam_actuator_ctrl_t *a_ctrl) kfree(power_info->power_down_setting); power_info->power_setting = NULL; power_info->power_down_setting = NULL; + power_info->power_setting_size = 0; + power_info->power_down_setting_size = 0; a_ctrl->cam_act_state = CAM_ACTUATOR_INIT; } @@ -668,12 +671,19 @@ int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, { int rc = 0; struct cam_control *cmd = (struct cam_control *)arg; + struct cam_actuator_soc_private *soc_private = NULL; + struct cam_sensor_power_ctrl_t *power_info = NULL; if (!a_ctrl || !cmd) { - CAM_ERR(CAM_ACTUATOR, " Invalid Args"); + CAM_ERR(CAM_ACTUATOR, "Invalid Args"); return -EINVAL; } + soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + + power_info = &soc_private->power_info; + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { CAM_ERR(CAM_ACTUATOR, "Invalid handle type: %d", cmd->handle_type); @@ -756,6 +766,12 @@ int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, a_ctrl->bridge_intf.link_hdl = -1; a_ctrl->bridge_intf.session_hdl = -1; a_ctrl->cam_act_state = CAM_ACTUATOR_INIT; + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; } break; case CAM_QUERY_CAP: { diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 7f94f8d8c80d..c8730cab765c 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -785,6 +785,8 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) kfree(power_info->power_down_setting); power_info->power_setting = NULL; power_info->power_down_setting = NULL; + power_info->power_setting_size = 0; + power_info->power_down_setting_size = 0; e_ctrl->cal_data.num_data = 0; e_ctrl->cal_data.num_map = 0; break; @@ -838,6 +840,8 @@ void cam_eeprom_shutdown(struct cam_eeprom_ctrl_t *e_ctrl) kfree(power_info->power_down_setting); power_info->power_setting = NULL; power_info->power_down_setting = NULL; + power_info->power_setting_size = 0; + power_info->power_down_setting_size = 0; } e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c index 6f77e0ecb93e..c2d2e5f42abe 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c @@ -56,6 +56,7 @@ int32_t cam_ois_construct_default_power_setting( free_power_settings: kfree(power_info->power_setting); power_info->power_setting = NULL; + power_info->power_setting_size = 0; return rc; } @@ -638,10 +639,9 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl) { int rc = 0; - struct cam_ois_soc_private *soc_private = + struct cam_ois_soc_private *soc_private = (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; - struct cam_sensor_power_ctrl_t *power_info = - &soc_private->power_info; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; if (o_ctrl->cam_ois_state == CAM_OIS_INIT) return; @@ -666,6 +666,8 @@ void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl) kfree(power_info->power_down_setting); power_info->power_setting = NULL; power_info->power_down_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; o_ctrl->cam_ois_state = CAM_OIS_INIT; } @@ -679,11 +681,13 @@ void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl) */ int cam_ois_driver_cmd(struct cam_ois_ctrl_t *o_ctrl, void *arg) { - int rc = 0; - struct cam_ois_query_cap_t ois_cap = {0}; - struct cam_control *cmd = (struct cam_control *)arg; + int rc = 0; + struct cam_ois_query_cap_t ois_cap = {0}; + struct cam_control *cmd = (struct cam_control *)arg; + struct cam_ois_soc_private *soc_private = NULL; + struct cam_sensor_power_ctrl_t *power_info = NULL; - if (!o_ctrl || !arg) { + if (!o_ctrl || !cmd) { CAM_ERR(CAM_OIS, "Invalid arguments"); return -EINVAL; } @@ -694,6 +698,10 @@ int cam_ois_driver_cmd(struct cam_ois_ctrl_t *o_ctrl, void *arg) return -EINVAL; } + soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + mutex_lock(&(o_ctrl->ois_mutex)); switch (cmd->op_code) { case CAM_QUERY_CAP: @@ -764,6 +772,13 @@ int cam_ois_driver_cmd(struct cam_ois_ctrl_t *o_ctrl, void *arg) o_ctrl->bridge_intf.link_hdl = -1; o_ctrl->bridge_intf.session_hdl = -1; o_ctrl->cam_ois_state = CAM_OIS_INIT; + + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; break; case CAM_STOP_DEV: if (o_ctrl->cam_ois_state != CAM_OIS_START) { diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c index 223aba42372f..0eb8abef28d8 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -499,8 +499,8 @@ void cam_sensor_shutdown(struct cam_sensor_ctrl_t *s_ctrl) &s_ctrl->sensordata->power_info; int rc = 0; - s_ctrl->is_probe_succeed = 0; - if (s_ctrl->sensor_state == CAM_SENSOR_INIT) + if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) && + (s_ctrl->is_probe_succeed == 0)) return; cam_sensor_release_resource(s_ctrl); @@ -514,14 +514,15 @@ void cam_sensor_shutdown(struct cam_sensor_ctrl_t *s_ctrl) s_ctrl->bridge_intf.device_hdl = -1; s_ctrl->bridge_intf.link_hdl = -1; s_ctrl->bridge_intf.session_hdl = -1; - kfree(power_info->power_setting); kfree(power_info->power_down_setting); power_info->power_setting = NULL; power_info->power_down_setting = NULL; - + power_info->power_setting_size = 0; + power_info->power_down_setting_size = 0; s_ctrl->streamon_count = 0; s_ctrl->streamoff_count = 0; + s_ctrl->is_probe_succeed = 0; s_ctrl->sensor_state = CAM_SENSOR_INIT; } @@ -560,8 +561,6 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, { int rc = 0; struct cam_control *cmd = (struct cam_control *)arg; - struct cam_sensor_power_setting *pu = NULL; - struct cam_sensor_power_setting *pd = NULL; struct cam_sensor_power_ctrl_t *power_info = &s_ctrl->sensordata->power_info; if (!s_ctrl || !arg) { @@ -591,8 +590,6 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, rc = cam_handle_mem_ptr(cmd->handle, s_ctrl); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Get Buffer Handle Failed"); - kfree(pu); - kfree(pd); goto release_mutex; } } else { @@ -602,9 +599,6 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, goto release_mutex; } - pu = power_info->power_setting; - pd = power_info->power_down_setting; - /* Parse and fill vreg params for powerup settings */ rc = msm_camera_fill_vreg_params( &s_ctrl->soc_info, @@ -614,9 +608,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, CAM_ERR(CAM_SENSOR, "Fail in filling vreg params for PUP rc %d", rc); - kfree(pu); - kfree(pd); - goto release_mutex; + goto free_power_settings; } /* Parse and fill vreg params for powerdown settings*/ @@ -628,18 +620,14 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, CAM_ERR(CAM_SENSOR, "Fail in filling vreg params for PDOWN rc %d", rc); - kfree(pu); - kfree(pd); - goto release_mutex; + goto free_power_settings; } /* Power up and probe sensor */ rc = cam_sensor_power_up(s_ctrl); if (rc < 0) { CAM_ERR(CAM_SENSOR, "power up failed"); - kfree(pu); - kfree(pd); - goto release_mutex; + goto free_power_settings; } /* Match sensor ID */ @@ -647,9 +635,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, if (rc < 0) { cam_sensor_power_down(s_ctrl); msleep(20); - kfree(pu); - kfree(pd); - goto release_mutex; + goto free_power_settings; } CAM_INFO(CAM_SENSOR, @@ -661,9 +647,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, rc = cam_sensor_power_down(s_ctrl); if (rc < 0) { CAM_ERR(CAM_SENSOR, "fail in Sensor Power Down"); - kfree(pu); - kfree(pd); - goto release_mutex; + goto free_power_settings; } /* * Set probe succeeded flag to 1 so that no other camera shall @@ -677,6 +661,15 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, struct cam_sensor_acquire_dev sensor_acq_dev; struct cam_create_dev_hdl bridge_params; + if ((s_ctrl->is_probe_succeed == 0) || + (s_ctrl->sensor_state != CAM_SENSOR_INIT)) { + CAM_WARN(CAM_SENSOR, + "Not in right state to aquire %d", + s_ctrl->sensor_state); + rc = -EINVAL; + goto release_mutex; + } + if (s_ctrl->bridge_intf.device_hdl != -1) { CAM_ERR(CAM_SENSOR, "Device is already acquired"); rc = -EINVAL; @@ -885,6 +878,16 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, release_mutex: mutex_unlock(&(s_ctrl->cam_sensor_mutex)); return rc; + +free_power_settings: + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return rc; } int cam_sensor_publish_dev_info(struct cam_req_mgr_device_info *info) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index 498112e4236f..46bda0589c52 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -711,8 +711,10 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, kzalloc(sizeof(struct cam_sensor_power_setting) * MAX_POWER_CONFIG, GFP_KERNEL); if (!power_info->power_down_setting) { - rc = -ENOMEM; - goto free_power_settings; + kfree(power_info->power_setting); + power_info->power_setting = NULL; + power_info->power_setting_size = 0; + return -ENOMEM; } while (tot_size < cmd_length) { @@ -722,11 +724,18 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, (struct cam_cmd_power *)ptr; power_info->power_setting_size += pwr_cmd->count; + if (power_info->power_setting_size > MAX_POWER_CONFIG) { + CAM_ERR(CAM_SENSOR, + "Invalid: power up setting size %d", + power_info->power_setting_size); + rc = -EINVAL; + goto free_power_settings; + } scr = ptr + sizeof(struct cam_cmd_power); tot_size = tot_size + sizeof(struct cam_cmd_power); if (pwr_cmd->count == 0) - CAM_WARN(CAM_SENSOR, "Un expected Command"); + CAM_WARN(CAM_SENSOR, "pwr_up_size is zero"); for (i = 0; i < pwr_cmd->count; i++, pwr_up++) { power_info->power_setting[pwr_up].seq_type = @@ -746,7 +755,7 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, CAM_ERR(CAM_SENSOR, "Error: Cmd Buffer is wrong"); rc = -EINVAL; - goto free_power_down_settings; + goto free_power_settings; } CAM_DBG(CAM_SENSOR, "Seq Type[%d]: %d Config_val: %ld", pwr_up, @@ -814,9 +823,17 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, scr = ptr + sizeof(struct cam_cmd_power); tot_size = tot_size + sizeof(struct cam_cmd_power); power_info->power_down_setting_size += pwr_cmd->count; + if (power_info->power_down_setting_size > + MAX_POWER_CONFIG) { + CAM_ERR(CAM_SENSOR, + "Invalid: power down setting size %d", + power_info->power_down_setting_size); + rc = -EINVAL; + goto free_power_settings; + } if (pwr_cmd->count == 0) - CAM_ERR(CAM_SENSOR, "Invalid Command"); + CAM_ERR(CAM_SENSOR, "pwr_down size is zero"); for (i = 0; i < pwr_cmd->count; i++, pwr_down++) { pwr_settings = @@ -840,7 +857,7 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, CAM_ERR(CAM_SENSOR, "Command Buffer is wrong"); rc = -EINVAL; - goto free_power_down_settings; + goto free_power_settings; } CAM_DBG(CAM_SENSOR, "Seq Type[%d]: %d Config_val: %ld", @@ -854,16 +871,19 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, CAM_ERR(CAM_SENSOR, "Error: Un expected Header Type: %d", cmm_hdr->cmd_type); + rc = -EINVAL; + goto free_power_settings; } } return rc; -free_power_down_settings: - kfree(power_info->power_down_setting); - power_info->power_down_setting = NULL; free_power_settings: + kfree(power_info->power_down_setting); kfree(power_info->power_setting); + power_info->power_down_setting = NULL; power_info->power_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; return rc; } @@ -1261,10 +1281,62 @@ int msm_cam_sensor_handle_reg_gpio(int seq_type, return 0; } +static int cam_config_mclk_reg(struct cam_sensor_power_ctrl_t *ctrl, + struct cam_hw_soc_info *soc_info, int32_t index) +{ + int32_t num_vreg = 0, j = 0, rc = 0, idx = 0; + struct cam_sensor_power_setting *ps = NULL; + struct cam_sensor_power_setting *pd = NULL; + + num_vreg = soc_info->num_rgltr; + + pd = &ctrl->power_down_setting[index]; + + for (j = 0; j < num_vreg; j++) { + if (!strcmp(soc_info->rgltr_name[j], "cam_clk")) { + ps = NULL; + for (idx = 0; idx < ctrl->power_setting_size; idx++) { + if (ctrl->power_setting[idx].seq_type == + pd->seq_type) { + ps = &ctrl->power_setting[idx]; + break; + } + } + + if (ps != NULL) { + CAM_DBG(CAM_SENSOR, "Disable MCLK Regulator"); + rc = cam_soc_util_regulator_disable( + soc_info->rgltr[j], + soc_info->rgltr_name[j], + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + soc_info->rgltr_op_mode[j], + soc_info->rgltr_delay[j]); + + if (rc) { + CAM_ERR(CAM_SENSOR, + "MCLK REG DISALBE FAILED: %d", + rc); + return rc; + } + + ps->data[0] = + soc_info->rgltr[j]; + + regulator_put( + soc_info->rgltr[j]); + soc_info->rgltr[j] = NULL; + } + } + } + + return rc; +} + int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, struct cam_hw_soc_info *soc_info) { - int rc = 0, index = 0, no_gpio = 0, ret = 0, num_vreg, j = 0; + int rc = 0, index = 0, no_gpio = 0, ret = 0, num_vreg, j = 0, i = 0; int32_t vreg_idx = -1; struct cam_sensor_power_setting *power_setting = NULL; struct msm_camera_gpio_num_info *gpio_num_info = NULL; @@ -1361,6 +1433,7 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, soc_info->rgltr_name[j], rc); soc_info->rgltr[j] = NULL; + goto power_up_failed; } rc = cam_soc_util_regulator_enable( @@ -1370,7 +1443,11 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, soc_info->rgltr_max_volt[j], soc_info->rgltr_op_mode[j], soc_info->rgltr_delay[j]); - + if (rc) { + CAM_ERR(CAM_SENSOR, + "Reg enable failed"); + goto power_up_failed; + } power_setting->data[0] = soc_info->rgltr[j]; } @@ -1451,6 +1528,7 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, rc); soc_info->rgltr[vreg_idx] = NULL; + goto power_up_failed; } rc = cam_soc_util_regulator_enable( @@ -1460,7 +1538,12 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, soc_info->rgltr_max_volt[vreg_idx], soc_info->rgltr_op_mode[vreg_idx], soc_info->rgltr_delay[vreg_idx]); - + if (rc) { + CAM_ERR(CAM_SENSOR, + "Reg Enable failed for %s", + soc_info->rgltr_name[vreg_idx]); + goto power_up_failed; + } power_setting->data[0] = soc_info->rgltr[vreg_idx]; } @@ -1503,6 +1586,18 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, CAM_DBG(CAM_SENSOR, "type %d", power_setting->seq_type); switch (power_setting->seq_type) { + case SENSOR_MCLK: + for (i = soc_info->num_clk - 1; i >= 0; i--) { + cam_soc_util_clk_disable(soc_info->clk[i], + soc_info->clk_name[i]); + } + ret = cam_config_mclk_reg(ctrl, soc_info, index); + if (ret < 0) { + CAM_ERR(CAM_SENSOR, + "config clk reg failed rc: %d", ret); + continue; + } + break; case SENSOR_RESET: case SENSOR_STANDBY: case SENSOR_CUSTOM_GPIO1: @@ -1535,11 +1630,21 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, soc_info->rgltr_op_mode[vreg_idx], soc_info->rgltr_delay[vreg_idx]); + if (rc) { + CAM_ERR(CAM_SENSOR, + "Fail to disalbe reg: %s", + soc_info->rgltr_name[vreg_idx]); + soc_info->rgltr[vreg_idx] = NULL; + msm_cam_sensor_handle_reg_gpio( + power_setting->seq_type, + gpio_num_info, + GPIOF_OUT_INIT_LOW); + continue; + } power_setting->data[0] = soc_info->rgltr[vreg_idx]; - regulator_put( - soc_info->rgltr[vreg_idx]); + regulator_put(soc_info->rgltr[vreg_idx]); soc_info->rgltr[vreg_idx] = NULL; } else @@ -1565,8 +1670,8 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, if (ctrl->cam_pinctrl_status) { ret = pinctrl_select_state( - ctrl->pinctrl_info.pinctrl, - ctrl->pinctrl_info.gpio_state_suspend); + ctrl->pinctrl_info.pinctrl, + ctrl->pinctrl_info.gpio_state_suspend); if (ret) CAM_ERR(CAM_SENSOR, "cannot set pin to suspend state"); cam_res_mgr_shared_pinctrl_select_state(false); @@ -1605,54 +1710,6 @@ msm_camera_get_power_settings(struct cam_sensor_power_ctrl_t *ctrl, return ps; } -static int cam_config_mclk_reg(struct cam_sensor_power_ctrl_t *ctrl, - struct cam_hw_soc_info *soc_info, int32_t index) -{ - int32_t num_vreg = 0, j = 0, rc = 0, idx = 0; - struct cam_sensor_power_setting *ps = NULL; - struct cam_sensor_power_setting *pd = NULL; - - num_vreg = soc_info->num_rgltr; - - pd = &ctrl->power_down_setting[index]; - - for (j = 0; j < num_vreg; j++) { - if (!strcmp(soc_info->rgltr_name[j], "cam_clk")) { - - ps = NULL; - for (idx = 0; idx < - ctrl->power_setting_size; idx++) { - if (ctrl->power_setting[idx]. - seq_type == pd->seq_type) { - ps = &ctrl->power_setting[idx]; - break; - } - } - - if (ps != NULL) { - CAM_DBG(CAM_SENSOR, "Disable Regulator"); - - rc = cam_soc_util_regulator_disable( - soc_info->rgltr[j], - soc_info->rgltr_name[j], - soc_info->rgltr_min_volt[j], - soc_info->rgltr_max_volt[j], - soc_info->rgltr_op_mode[j], - soc_info->rgltr_delay[j]); - - ps->data[0] = - soc_info->rgltr[j]; - - regulator_put( - soc_info->rgltr[j]); - soc_info->rgltr[j] = NULL; - } - } - } - - return rc; -} - int msm_camera_power_down(struct cam_sensor_power_ctrl_t *ctrl, struct cam_hw_soc_info *soc_info) { @@ -1675,8 +1732,14 @@ int msm_camera_power_down(struct cam_sensor_power_ctrl_t *ctrl, return -EINVAL; } + if (ctrl->power_down_setting_size > MAX_POWER_CONFIG) { + CAM_ERR(CAM_SENSOR, "Invalid: power setting size %d", + ctrl->power_setting_size); + return -EINVAL; + } + for (index = 0; index < ctrl->power_down_setting_size; index++) { - CAM_DBG(CAM_SENSOR, "index %d", index); + CAM_DBG(CAM_SENSOR, "power_down_index %d", index); pd = &ctrl->power_down_setting[index]; if (!pd) { CAM_ERR(CAM_SENSOR, @@ -1686,21 +1749,20 @@ int msm_camera_power_down(struct cam_sensor_power_ctrl_t *ctrl, } ps = NULL; - CAM_DBG(CAM_SENSOR, "type %d", pd->seq_type); + CAM_DBG(CAM_SENSOR, "seq_type %d", pd->seq_type); switch (pd->seq_type) { case SENSOR_MCLK: - ret = cam_config_mclk_reg(ctrl, soc_info, index); - if (ret < 0) { - CAM_ERR(CAM_SENSOR, - "config clk reg failed rc: %d", ret); - return ret; - } - //cam_soc_util_clk_disable_default(soc_info); for (i = soc_info->num_clk - 1; i >= 0; i--) { cam_soc_util_clk_disable(soc_info->clk[i], soc_info->clk_name[i]); } + ret = cam_config_mclk_reg(ctrl, soc_info, index); + if (ret < 0) { + CAM_ERR(CAM_SENSOR, + "config clk reg failed rc: %d", ret); + continue; + } break; case SENSOR_RESET: case SENSOR_STANDBY: @@ -1740,7 +1802,19 @@ int msm_camera_power_down(struct cam_sensor_power_ctrl_t *ctrl, soc_info->rgltr_max_volt[ps->seq_val], soc_info->rgltr_op_mode[ps->seq_val], soc_info->rgltr_delay[ps->seq_val]); - + if (ret) { + CAM_ERR(CAM_SENSOR, + "Reg: %s disable failed", + soc_info->rgltr_name[ + ps->seq_val]); + soc_info->rgltr[ps->seq_val] = + NULL; + msm_cam_sensor_handle_reg_gpio( + pd->seq_type, + gpio_num_info, + GPIOF_OUT_INIT_LOW); + continue; + } ps->data[0] = soc_info->rgltr[ps->seq_val]; -- GitLab From 137adbba30517c46db919c9229f02cc56b134da1 Mon Sep 17 00:00:00 2001 From: Shubhashree Dhar Date: Tue, 26 Jun 2018 18:03:38 +0530 Subject: [PATCH 313/604] drm/msm/sde: Correct sequence for input handler flush work Flush work is done after input handler unregister in encoder virt disable to avoid race condition. Unused variables in encoder enable are removed. Change-Id: Idce3c685deced3ac3d826911ee33e2fc6b6415b4 Signed-off-by: Shubhashree Dhar --- drivers/gpu/drm/msm/sde/sde_encoder.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 73864b617cc4..c05f884373de 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -2689,14 +2689,12 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) struct msm_compression_info *comp_info = NULL; struct drm_display_mode *cur_mode = NULL; struct msm_mode_info mode_info; - struct msm_display_info *disp_info; if (!drm_enc) { SDE_ERROR("invalid encoder\n"); return; } sde_enc = to_sde_encoder_virt(drm_enc); - disp_info = &sde_enc->disp_info; if (!sde_kms_power_resource_is_enabled(drm_enc->dev)) { SDE_ERROR("power resource is not enabled\n"); @@ -2817,14 +2815,14 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc) SDE_EVT32(DRMID(drm_enc)); + if (sde_enc->input_handler) + input_unregister_handler(sde_enc->input_handler); + /* wait for idle */ sde_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE); kthread_flush_work(&sde_enc->input_event_work); - if (sde_enc->input_handler) - input_unregister_handler(sde_enc->input_handler); - /* * For primary command mode encoders, execute the resource control * pre-stop operations before the physical encoders are disabled, to -- GitLab From 8ab49564cd22a5c30d8093bccbb1eb2ec9d40556 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 22 Jun 2018 16:59:47 +0530 Subject: [PATCH 314/604] Kconfig.debug: module: Add debug config to debug modules There can be scenario where, dynamically loadable modules adds a certain nodes in list data structure and forgot to remove reference from the list while unloading themself. And this can result in fault while accessing those dangling pointers. So If we log the module used address ranges, we could be able to tell exact victim module. And, It will be good to keep these debug logs under a config flag. So, let's add DEBUG_MODULE_LOAD_INFO config and use this in printing module used init and core layout address ranges. e.g: Core layout sections: [ 40.599573] .text [ 40.627074] .plt [ 40.603426] .rodata.str1.8 [ 40.608016] __mcount_loc [ 40.622142] .note.gnu.build-id [ 40.612654] .data [ 40.616438] .gnu.linkonce.this_module [ 40.634909] .bss Init layout sections [ 40.630781] .init.plt [ 40.638591] .symtab [ 40.642573] .strtab After this patch: / # insmod sample.ko [ 26.244768] Hi Mukesh [ 26.247314] Loaded sample: module init layout addresses range: 0xffffff9dbff8a000-0xffffff9dbff8bfff [ 26.256896] sample: core layout addresses range: 0xffffff9dbff85000-0xffffff9dbff88fff / # rmmod sample [ 63.812065] Bye Mukesh [ 63.816318] Unloaded sample: module core layout address range: 0xffffff9dbff85000-0xffffff9dbff88fff Change-Id: I4acfc4f53c561f92ca63fa3c4559148929575580 Signed-off-by: Mukesh Ojha --- kernel/module.c | 13 +++++++++++++ lib/Kconfig.debug | 12 ++++++++++++ 2 files changed, 25 insertions(+) diff --git a/kernel/module.c b/kernel/module.c index 13ad2f8c44f9..8a840312efd0 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2156,6 +2156,11 @@ static void free_module(struct module *mod) /* Finally, free the core (containing the module structure) */ disable_ro_nx(&mod->core_layout); +#ifdef CONFIG_DEBUG_MODULE_LOAD_INFO + pr_info("Unloaded %s: module core layout address range: 0x%lx-0x%lx\n", + mod->name, (long)mod->core_layout.base, + (long)(mod->core_layout.base + mod->core_layout.size - 1)); +#endif module_memfree(mod->core_layout.base); #ifdef CONFIG_MPU @@ -3469,6 +3474,14 @@ static noinline int do_init_module(struct module *mod) mod_tree_remove_init(mod); disable_ro_nx(&mod->init_layout); module_arch_freeing_init(mod); +#ifdef CONFIG_DEBUG_MODULE_LOAD_INFO + pr_info("Loaded %s: module init layout addresses range: 0x%lx-0x%lx\n", + mod->name, (long)mod->init_layout.base, + (long)(mod->init_layout.base + mod->init_layout.size - 1)); + pr_info("%s: core layout addresses range: 0x%lx-0x%lx\n", mod->name, + (long)mod->core_layout.base, + (long)(mod->core_layout.base + mod->core_layout.size - 1)); +#endif mod->init_layout.base = NULL; mod->init_layout.size = 0; mod->init_layout.ro_size = 0; diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 640818c67aa3..4fc6d8f6deee 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -113,6 +113,18 @@ config DYNAMIC_DEBUG See Documentation/dynamic-debug-howto.txt for additional information. +config DEBUG_MODULE_LOAD_INFO + bool "Use prints for module info under a debug flag" + help + If you say Y here the resulting kernel image will include + debug prints which was kept under DEBUG_MODULE_LOAD_INFO. + This will be used by developer to debug loadable modules in + the kernel. + Say Y here only if you plan to debug the kernel. + + If unsure, say N. + + endmenu # "printk and dmesg options" menu "Compile-time checks and compiler options" -- GitLab From 5bcb606a4959d1b5b88b4bc467cc11963f7b431e Mon Sep 17 00:00:00 2001 From: Ajit Kumar Date: Mon, 25 Jun 2018 16:01:44 +0530 Subject: [PATCH 315/604] soc: qcom: bgdeamon: call the gpio apis in correct order Call the gpio APIs in correct order to reset BG. Change-Id: Ie3eb6db5a253e8244c53940abb0d600895919783 Signed-off-by: Ajit Kumar --- drivers/soc/qcom/bgcom_interface.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/bgcom_interface.c b/drivers/soc/qcom/bgcom_interface.c index 1cde8c654188..75c99287e851 100644 --- a/drivers/soc/qcom/bgcom_interface.c +++ b/drivers/soc/qcom/bgcom_interface.c @@ -306,10 +306,23 @@ static int bgchar_write_cmd(struct bg_ui_data *fui_obj_msg, int type) int bg_soft_reset(void) { - /*pull down reset gpio */ - gpio_direction_output(bgreset_gpio, 0); + pr_debug("do BG reset using gpio %d\n", bgreset_gpio); + if (!gpio_is_valid(bgreset_gpio)) { + pr_err("gpio %d is not valid\n", bgreset_gpio); + return -ENXIO; + } + if (gpio_direction_output(bgreset_gpio, 1)) + pr_err("gpio %d direction not set\n", bgreset_gpio); + + /* Sleep for 50ms for hardware to detect signal as high */ + msleep(50); + + gpio_set_value(bgreset_gpio, 0); + + /* Sleep for 50ms for hardware to detect signal as high */ msleep(50); gpio_set_value(bgreset_gpio, 1); + return 0; } EXPORT_SYMBOL(bg_soft_reset); -- GitLab From c6bc4127c8cf0a0ba2932630da0a5de29cb1526f Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Fri, 6 Jul 2018 16:08:12 +0530 Subject: [PATCH 316/604] msm: camera: Fix out-of-bounds read in string class name. jpeg driver is calling class_create with stack variable, which can be overwritten by other stack variables. Change-Id: I3c22a5b3375b970ff6b1c6de983dd5833f4e11d0 Signed-off-by: Trishansh Bhardwaj --- drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c index 7d37d7ed14dd..0811efbcb130 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c @@ -32,6 +32,8 @@ #define MSM_JPEG_NAME "jpeg" #define DEV_NAME_LEN 10 +static char devname[DEV_NAME_LEN]; + static int msm_jpeg_open(struct inode *inode, struct file *filp) { int rc = 0; @@ -159,7 +161,6 @@ static int msm_jpeg_init_dev(struct platform_device *pdev) struct msm_jpeg_device *msm_jpeg_device_p; const struct of_device_id *device_id; const struct msm_jpeg_priv_data *priv_data; - char devname[DEV_NAME_LEN]; msm_jpeg_device_p = kzalloc(sizeof(struct msm_jpeg_device), GFP_ATOMIC); if (!msm_jpeg_device_p) { -- GitLab From 26e223c2fb2b07d753cb2cf3973415b87871d2dd Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Thu, 5 Jul 2018 11:50:32 -0700 Subject: [PATCH 317/604] msm: camera: sensor: Allocate buffer to be of DMA memory type QUP I2C requires DMA memory buffer. Change-Id: I4c4425e3f77c674e9d0cce0ca75b130cf4ae0644 Signed-off-by: Vishalsingh Hajeri --- .../cam_sensor_io/cam_sensor_qup_i2c.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c index 1c6ab0b1d94b..9145a1e52f3e 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.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 @@ -245,9 +245,15 @@ static int32_t cam_qup_i2c_write(struct camera_io_master *client, enum camera_sensor_i2c_type data_type) { int32_t rc = 0; - unsigned char buf[I2C_REG_MAX_BUF_SIZE]; + unsigned char *buf = NULL; uint8_t len = 0; + buf = kzalloc(I2C_REG_MAX_BUF_SIZE, GFP_KERNEL | GFP_DMA); + if (!buf) { + CAM_ERR(CAM_SENSOR, "Buffer memory allocation failed"); + return -ENOMEM; + } + CAM_DBG(CAM_SENSOR, "reg addr = 0x%x data type: %d", reg_setting->reg_addr, data_type); if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { @@ -273,7 +279,8 @@ static int32_t cam_qup_i2c_write(struct camera_io_master *client, len = 4; } else { CAM_ERR(CAM_SENSOR, "Invalid I2C addr type"); - return -EINVAL; + rc = -EINVAL; + goto deallocate_buffer; } CAM_DBG(CAM_SENSOR, "Data: 0x%x", reg_setting->reg_data); @@ -307,12 +314,16 @@ static int32_t cam_qup_i2c_write(struct camera_io_master *client, len += 4; } else { CAM_ERR(CAM_SENSOR, "Invalid Data Type"); - return -EINVAL; + rc = -EINVAL; + goto deallocate_buffer; } rc = cam_qup_i2c_txdata(client, buf, len); if (rc < 0) CAM_ERR(CAM_SENSOR, "failed rc: %d", rc); + +deallocate_buffer: + kfree(buf); return rc; } -- GitLab From 0ee965722bc803b99052b06c8cf72ac0c7ce44f8 Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Tue, 3 Jul 2018 12:09:15 -0700 Subject: [PATCH 318/604] msm: camera: cpas: Add protection for concurrent execution This change adds mutex lock in register client to protect client data. It also sets probe done flag to false during dev remove to force all other functions that might be invoked in parallel to return without any action. Change-Id: Iaf4bf65c8a1e0bedf86952817512fcf0f0a71070 Signed-off-by: Venkat Chinta --- .../msm/camera/cam_cpas/cam_cpas_hw.c | 19 +++++++++++++++---- .../msm/camera/cam_cpas/cam_cpas_intf.c | 1 + 2 files changed, 16 insertions(+), 4 deletions(-) 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 90603de7e6d6..8fd144fa08ea 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 @@ -1212,17 +1212,26 @@ static int cam_cpas_hw_register_client(struct cam_hw_info *cpas_hw, rc = cam_common_util_get_string_index(soc_private->client_name, soc_private->num_clients, client_name, &client_indx); + + mutex_lock(&cpas_core->client_mutex[client_indx]); + if (rc || !CAM_CPAS_CLIENT_VALID(client_indx) || CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx)) { - CAM_ERR(CAM_CPAS, "Invalid Client register : %s %d, %d", + CAM_ERR(CAM_CPAS, + "Inval client %s %d : %d %d %pK %d", register_params->identifier, - register_params->cell_index, client_indx); + register_params->cell_index, + CAM_CPAS_CLIENT_VALID(client_indx), + CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx), + cpas_core->cpas_client[client_indx], rc); + mutex_unlock(&cpas_core->client_mutex[client_indx]); mutex_unlock(&cpas_hw->hw_mutex); return -EPERM; } cpas_client = kzalloc(sizeof(struct cam_cpas_client), GFP_KERNEL); if (!cpas_client) { + mutex_unlock(&cpas_core->client_mutex[client_indx]); mutex_unlock(&cpas_hw->hw_mutex); return -ENOMEM; } @@ -1235,6 +1244,7 @@ static int cam_cpas_hw_register_client(struct cam_hw_info *cpas_hw, client_indx, cpas_client->data.identifier, cpas_client->data.cell_index, rc); kfree(cpas_client); + mutex_unlock(&cpas_core->client_mutex[client_indx]); mutex_unlock(&cpas_hw->hw_mutex); return -EINVAL; } @@ -1246,12 +1256,13 @@ static int cam_cpas_hw_register_client(struct cam_hw_info *cpas_hw, cpas_core->cpas_client[client_indx] = cpas_client; cpas_core->registered_clients++; - mutex_unlock(&cpas_hw->hw_mutex); - CAM_DBG(CAM_CPAS, "client=[%d][%s][%d], registered_clients=%d", client_indx, cpas_client->data.identifier, cpas_client->data.cell_index, cpas_core->registered_clients); + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + return 0; } 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 0187a6400275..13d59d6755bb 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 @@ -619,6 +619,7 @@ static int cam_cpas_dev_remove(struct platform_device *dev) } mutex_lock(&g_cpas_intf->intf_lock); + g_cpas_intf->probe_done = false; cam_unregister_subdev(&g_cpas_intf->subdev); cam_cpas_hw_remove(g_cpas_intf->hw_intf); mutex_unlock(&g_cpas_intf->intf_lock); -- GitLab From e227149dd59d50c0282a62d9adc9c31c016af70a Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Fri, 6 Jul 2018 09:49:43 -0700 Subject: [PATCH 319/604] Revert "msm: camera: icp: removes reference input depedency" This change needs to happen in userspace hence reverting the kernel change. Change-Id: I9d126d59a01f91dd6d44d08fb0276d80987d604a Signed-off-by: Karthik Anantha Ram --- .../cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 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 8248adf841ea..c73c25fef428 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 @@ -3340,15 +3340,6 @@ static int cam_icp_mgr_process_cmd_desc(struct cam_icp_hw_mgr *hw_mgr, return rc; } -static bool cam_icp_mgr_is_input_reference_buffer(uint32_t resource_type) -{ - if (resource_type == CAM_ICP_IPE_INPUT_IMAGE_FULL_REF || - resource_type == CAM_ICP_IPE_INPUT_IMAGE_DS4_REF || - resource_type == CAM_ICP_IPE_INPUT_IMAGE_DS16_REF) - return true; - else - return false; -} static int cam_icp_mgr_process_io_cfg(struct cam_icp_hw_mgr *hw_mgr, struct cam_icp_hw_ctx_data *ctx_data, @@ -3368,9 +3359,6 @@ static int cam_icp_mgr_process_io_cfg(struct cam_icp_hw_mgr *hw_mgr, for (i = 0, j = 0, k = 0; i < packet->num_io_configs; i++) { if (io_cfg_ptr[i].direction == CAM_BUF_INPUT) { - if (cam_icp_mgr_is_input_reference_buffer( - io_cfg_ptr[i].resource_type)) - continue; sync_in_obj[j++] = io_cfg_ptr[i].fence; prepare_args->num_in_map_entries++; } else { @@ -3378,9 +3366,8 @@ static int cam_icp_mgr_process_io_cfg(struct cam_icp_hw_mgr *hw_mgr, io_cfg_ptr[i].fence; prepare_args->num_out_map_entries++; } - CAM_DBG(CAM_ICP, "dir[%d]: %u, fence: %u resource_type = %u", - i, io_cfg_ptr[i].direction, io_cfg_ptr[i].fence, - io_cfg_ptr[i].resource_type); + CAM_DBG(CAM_ICP, "dir[%d]: %u, fence: %u", + i, io_cfg_ptr[i].direction, io_cfg_ptr[i].fence); } if (prepare_args->num_in_map_entries > 1) { -- GitLab From 3ef71c3e3b81d66140d880aa25937ab552d69132 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Thu, 21 Jun 2018 16:38:15 -0700 Subject: [PATCH 320/604] msm: camera: Dynamically enable CSID SOF irq Camera request manager on detecting the SOF freeze notifies this event to the IFE driver. IFE driver on receiving this will enable CSID & CAMIF SOF irq which will expediate debugging such scenarios. Change-Id: Id3847cb0a1b163f60c72a7c3c44502d5b3df7e7c Signed-off-by: Karthik Anantha Ram --- .../msm/camera/cam_isp/cam_isp_context.c | 21 +++++++ .../cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 49 +++++++++++++++ .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 2 + .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 60 ++++++++++++++++++- .../isp_hw/include/cam_ife_csid_hw_intf.h | 1 + .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 1 + .../vfe_hw/vfe_top/cam_vfe_camif_ver2.c | 27 ++++++++- .../msm/camera/cam_req_mgr/cam_req_mgr_core.c | 27 +++++++++ .../cam_req_mgr/cam_req_mgr_interface.h | 9 ++- 9 files changed, 193 insertions(+), 4 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 f6fe85071300..203e549d9491 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 @@ -2486,6 +2486,24 @@ static int __cam_isp_ctx_link_resume(struct cam_context *ctx) return rc; } +static int __cam_isp_ctx_handle_sof_freeze_evt( + struct cam_context *ctx) +{ + int rc = 0; + struct cam_isp_hw_cmd_args hw_cmd_args; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_SOF_DEBUG; + hw_cmd_args.u.sof_irq_enable = 1; + + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + + return rc; +} + static int __cam_isp_ctx_process_evt(struct cam_context *ctx, struct cam_req_mgr_link_evt_data *link_evt_data) { @@ -2501,6 +2519,9 @@ static int __cam_isp_ctx_process_evt(struct cam_context *ctx, case CAM_REQ_MGR_LINK_EVT_RESUME: __cam_isp_ctx_link_resume(ctx); break; + case CAM_REQ_MGR_LINK_EVT_SOF_FREEZE: + __cam_isp_ctx_handle_sof_freeze_evt(ctx); + break; default: CAM_WARN(CAM_ISP, "Unknown event from CRM"); break; 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 e5c54d6a85ed..891cbb481644 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 @@ -2699,6 +2699,52 @@ static int cam_ife_mgr_resume_hw(struct cam_ife_hw_mgr_ctx *ctx) return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_INCLUDE); } +static int cam_ife_mgr_sof_irq_debug( + struct cam_ife_hw_mgr_ctx *ctx, + uint32_t sof_irq_enable) +{ + int rc = 0; + uint32_t i = 0; + struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; + struct cam_hw_intf *hw_intf = NULL; + struct cam_isp_resource_node *rsrc_node = NULL; + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.process_cmd) { + rc |= hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_IFE_CSID_SOF_IRQ_DEBUG, + &sof_irq_enable, + sizeof(sof_irq_enable)); + } + } + } + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + rsrc_node = hw_mgr_res->hw_res[i]; + if (rsrc_node->process_cmd && (rsrc_node->res_id == + CAM_ISP_HW_VFE_IN_CAMIF)) { + rc |= hw_mgr_res->hw_res[i]->process_cmd( + hw_mgr_res->hw_res[i], + CAM_ISP_HW_CMD_SOF_IRQ_DEBUG, + &sof_irq_enable, + sizeof(sof_irq_enable)); + } + } + } + + return rc; +} + static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) { int rc = 0; @@ -2730,6 +2776,9 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) case CAM_ISP_HW_MGR_CMD_RESUME_HW: cam_ife_mgr_resume_hw(ctx); break; + case CAM_ISP_HW_MGR_CMD_SOF_DEBUG: + cam_ife_mgr_sof_irq_debug(ctx, hw_cmd_args->u.sof_irq_enable); + break; default: CAM_ERR(CAM_ISP, "Invalid HW mgr command:0x%x", hw_cmd_args->cmd_type); 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 5410858e27a3..8f1911edf2c9 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 @@ -180,6 +180,7 @@ enum cam_isp_hw_mgr_command { CAM_ISP_HW_MGR_CMD_IS_RDI_ONLY_CONTEXT, CAM_ISP_HW_MGR_CMD_PAUSE_HW, CAM_ISP_HW_MGR_CMD_RESUME_HW, + CAM_ISP_HW_MGR_CMD_SOF_DEBUG, CAM_ISP_HW_MGR_CMD_MAX, }; @@ -195,6 +196,7 @@ struct cam_isp_hw_cmd_args { uint32_t cmd_type; union { uint32_t is_rdi_only_context; + uint32_t sof_irq_enable; } u; }; 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 dd1b7b9dcbe6..e5fb03f55086 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 @@ -2476,6 +2476,61 @@ static int cam_ife_csid_write(void *hw_priv, return -EINVAL; } +static int cam_ife_csid_sof_irq_debug( + struct cam_ife_csid_hw *csid_hw, void *cmd_args) +{ + int i = 0; + uint32_t val = 0; + bool sof_irq_enable = false; + struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (*((uint32_t *)cmd_args) == 1) + sof_irq_enable = true; + + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_irq_mask_addr); + + if (val) { + if (sof_irq_enable) + val |= CSID_PATH_INFO_INPUT_SOF; + else + val &= ~CSID_PATH_INFO_INPUT_SOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_irq_mask_addr); + val = 0; + } + + for (i = 0; i < csid_reg->cmn_reg->no_rdis; i++) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_mask_addr); + if (val) { + if (sof_irq_enable) + val |= CSID_PATH_INFO_INPUT_SOF; + else + val &= ~CSID_PATH_INFO_INPUT_SOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_mask_addr); + val = 0; + } + } + + if (sof_irq_enable) + csid_hw->csid_debug |= CSID_DEBUG_ENABLE_SOF_IRQ; + else + csid_hw->csid_debug &= ~CSID_DEBUG_ENABLE_SOF_IRQ; + + CAM_INFO(CAM_ISP, "SOF freeze: CSID SOF irq %s", + (sof_irq_enable == true) ? "enabled" : "disabled"); + + return 0; +} + static int cam_ife_csid_process_cmd(void *hw_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -2498,8 +2553,11 @@ static int cam_ife_csid_process_cmd(void *hw_priv, case CAM_IFE_CSID_SET_CSID_DEBUG: rc = cam_ife_csid_set_csid_debug(csid_hw, cmd_args); break; + case CAM_IFE_CSID_SOF_IRQ_DEBUG: + rc = cam_ife_csid_sof_irq_debug(csid_hw, cmd_args); + break; default: - CAM_ERR(CAM_ISP, "CSID:%d un supported cmd:%d", + CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d", csid_hw->hw_intf->hw_idx, cmd_type); rc = -EINVAL; break; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index 8911f9959fbe..bbd092f2172c 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -153,6 +153,7 @@ struct cam_csid_get_time_stamp_args { enum cam_ife_csid_cmd_type { CAM_IFE_CSID_CMD_GET_TIME_STAMP, CAM_IFE_CSID_SET_CSID_DEBUG, + CAM_IFE_CSID_SOF_IRQ_DEBUG, CAM_IFE_CSID_CMD_MAX, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index c56c49fac5af..70e04677282d 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -95,6 +95,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_BW_CONTROL, CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ, CAM_ISP_HW_CMD_GET_REG_DUMP, + CAM_ISP_HW_CMD_SOF_IRQ_DEBUG, CAM_ISP_HW_CMD_MAX, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index 8bc9bd23a039..b554fe48de3c 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -39,6 +39,7 @@ struct cam_vfe_mux_camif_data { uint32_t first_line; uint32_t last_pixel; uint32_t last_line; + bool enable_sof_irq_debug; }; static int cam_vfe_camif_validate_pix_pattern(uint32_t pattern) @@ -359,6 +360,23 @@ static int cam_vfe_camif_resource_stop( return rc; } +static int cam_vfe_camif_sof_irq_debug( + struct cam_isp_resource_node *rsrc_node, void *cmd_args) +{ + struct cam_vfe_mux_camif_data *camif_priv; + uint32_t *enable_sof_irq = (uint32_t *)cmd_args; + + camif_priv = + (struct cam_vfe_mux_camif_data *)rsrc_node->res_priv; + + if (*enable_sof_irq == 1) + camif_priv->enable_sof_irq_debug = true; + else + camif_priv->enable_sof_irq_debug = false; + + return 0; +} + static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -377,6 +395,9 @@ static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, case CAM_ISP_HW_CMD_GET_REG_DUMP: rc = cam_vfe_camif_reg_dump(rsrc_node); break; + case CAM_ISP_HW_CMD_SOF_IRQ_DEBUG: + rc = cam_vfe_camif_sof_irq_debug(rsrc_node, cmd_args); + break; default: CAM_ERR(CAM_ISP, "unsupported process command:%d", cmd_type); @@ -419,7 +440,11 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, switch (payload->evt_id) { case CAM_ISP_HW_EVENT_SOF: if (irq_status0 & camif_priv->reg_data->sof_irq_mask) { - CAM_DBG(CAM_ISP, "Received SOF"); + if (camif_priv->enable_sof_irq_debug) + CAM_ERR_RATE_LIMIT(CAM_ISP, "Received SOF"); + else + CAM_DBG(CAM_ISP, "Received SOF"); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; } break; 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 cc4c4c59a266..f62f279a21bd 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 @@ -1114,6 +1114,32 @@ static int __cam_req_mgr_reset_in_q(struct cam_req_mgr_req_data *req) return 0; } +/** + * __cam_req_mgr_notify_sof_freeze() + * + * @brief : Notify devices on link on detecting a SOF freeze + * @link : link on which the sof freeze was detected + * + */ +static void __cam_req_mgr_notify_sof_freeze( + struct cam_req_mgr_core_link *link) +{ + int i = 0; + struct cam_req_mgr_link_evt_data evt_data; + struct cam_req_mgr_connected_device *dev = NULL; + + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_SOF_FREEZE; + evt_data.dev_hdl = dev->dev_hdl; + evt_data.link_hdl = link->link_hdl; + evt_data.req_id = 0; + evt_data.u.error = CRM_KMD_ERR_FATAL; + if (dev->ops && dev->ops->process_evt) + dev->ops->process_evt(&evt_data); + } +} + /** * __cam_req_mgr_sof_freeze() * @@ -1138,6 +1164,7 @@ static void __cam_req_mgr_sof_freeze(unsigned long data) CAM_ERR(CAM_CRM, "SOF freeze for session %d link 0x%x", session->session_hdl, link->link_hdl); + __cam_req_mgr_notify_sof_freeze(link); memset(&msg, 0, sizeof(msg)); msg.session_hdl = session->session_hdl; diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h index 1ca6cc598ec8..99292125bc95 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h @@ -177,13 +177,18 @@ enum cam_req_mgr_device_id { /** * enum cam_req_mgr_link_evt_type - * @CAM_REQ_MGR_LINK_EVT_ERR: - * @CAM_REQ_MGR_LINK_EVT_MAX: + * @CAM_REQ_MGR_LINK_EVT_ERR : error on the link from any of the + * connected devices + * @CAM_REQ_MGR_LINK_EVT_PAUSE : to pause the link + * @CAM_REQ_MGR_LINK_EVT_RESUME : resumes the link which was paused + * @CAM_REQ_MGR_LINK_EVT_SOF_FREEZE : request manager has detected an sof freeze + * @CAM_REQ_MGR_LINK_EVT_MAX : invalid event type */ enum cam_req_mgr_link_evt_type { CAM_REQ_MGR_LINK_EVT_ERR, CAM_REQ_MGR_LINK_EVT_PAUSE, CAM_REQ_MGR_LINK_EVT_RESUME, + CAM_REQ_MGR_LINK_EVT_SOF_FREEZE, CAM_REQ_MGR_LINK_EVT_MAX, }; -- GitLab From ea32c78edacd5744f731cd0f47e584ec32bff25f Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Fri, 6 Jul 2018 15:10:00 +0530 Subject: [PATCH 321/604] msm: camera: Return IRQ_NONE from irq handlers IRQ_NONE need to return even if irq handler get the invalid parameters or encounter error condition. If IRQ_NONE handled value not return from irq handler, same irq comes again. Change-Id: I94f4ac9935a2d611734be8f669d5d43388d63ab4 Signed-off-by: Ravikishore Pampana --- .../msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c | 4 ++-- .../camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c | 4 ++-- .../msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c index a18afc6d7acc..87dc6949de0c 100644 --- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c +++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c @@ -532,7 +532,7 @@ irqreturn_t cam_fd_hw_irq(int irq_num, void *data) if (!fd_hw) { CAM_ERR(CAM_FD, "Invalid data in IRQ callback"); - return -EINVAL; + return IRQ_NONE; } fd_core = (struct cam_fd_core *) fd_hw->core_info; @@ -570,7 +570,7 @@ irqreturn_t cam_fd_hw_irq(int irq_num, void *data) CAM_ERR(CAM_FD, "Invalid number of IRQs, value=0x%x, num_irqs=%d", reg_value, num_irqs); - return -EINVAL; + return IRQ_NONE; } trace_cam_irq_activated("FD", irq_type); diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c index 6f98354decbc..595bb8182c8f 100644 --- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c +++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c @@ -1118,7 +1118,7 @@ irqreturn_t cam_lrme_hw_irq(int irq_num, void *data) if (!data) { CAM_ERR(CAM_LRME, "Invalid data in IRQ callback"); - return -EINVAL; + return IRQ_NONE; } lrme_hw = (struct cam_hw_info *)data; @@ -1179,7 +1179,7 @@ irqreturn_t cam_lrme_hw_irq(int irq_num, void *data) task = cam_req_mgr_workq_get_task(lrme_core->work); if (!task) { CAM_ERR(CAM_LRME, "no empty task available"); - return -ENOMEM; + return IRQ_NONE; } work_data = (struct cam_lrme_hw_work_data *)task->payload; work_data->top_irq_status = top_irq_status; 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 2688cd57db89..bc61df42bb94 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 @@ -177,7 +177,7 @@ irqreturn_t cam_csiphy_irq(int irq_num, void *data) if (!csiphy_dev) { CAM_ERR(CAM_CSIPHY, "Invalid Args"); - return -EINVAL; + return IRQ_NONE; } soc_info = &csiphy_dev->soc_info; -- GitLab From f0bb40e99d460d1dfe195e32417fa4934d5e6da9 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Mon, 25 Jun 2018 16:02:04 +0530 Subject: [PATCH 322/604] msm: ADSPRPC: Separate sensors memory from adsp_mem to sdsp_mem Define ION heap 22 for sensors usecases, with sdsp_mem. adsp_mem should be used for Audio usecases. Change-Id: I0e9b05e7d82564a33bfcb66ed3e995a01b25ba9c Acked-by: Bharath Kumar Signed-off-by: Tharun Kumar Merugu --- arch/arm64/boot/dts/qcom/sdm670-ion.dtsi | 7 +++++++ arch/arm64/boot/dts/qcom/sdm670.dtsi | 10 +++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi b/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi index 3fd122901f91..0968a522e488 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi @@ -49,5 +49,12 @@ reg = <9>; qcom,ion-heap-type = "SYSTEM_SECURE"; }; + + qcom,ion-heap@22 { /* ADSP HEAP */ + reg = <22>; + memory-region = <&sdsp_mem>; + qcom,ion-heap-type = "DMA"; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi index c962b42ee023..d942ac362c1d 100644 --- a/arch/arm64/boot/dts/qcom/sdm670.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi @@ -560,7 +560,15 @@ alloc-ranges = <0 0x00000000 0 0xffffffff>; reusable; alignment = <0 0x400000>; - size = <0 0xc00000>; + size = <0 0x800000>; + }; + + sdsp_mem: sdsp_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x400000>; }; qseecom_ta_mem: qseecom_ta_region { -- GitLab From 25f427cf9486d3d1f01a38645b12a99027b31341 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Tue, 3 Jul 2018 15:49:58 -0700 Subject: [PATCH 323/604] ARM: dts: msm: Add field to determine clock control Add new field which decides if one can control the clk rates for that device via debugfs. Change-Id: Ie3274a83fd4a73afbf8a3c4559299cf286eb6967 Signed-off-by: Karthik Anantha Ram --- arch/arm64/boot/dts/qcom/sdm845-camera.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi index e77dcc357dea..0459c07eed68 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi @@ -621,6 +621,7 @@ <0 0 0 0 0 0 538000000 0 0 0 600000000 0 0>; clock-cntl-level = "svs", "turbo"; src-clock-name = "ife_csid_clk_src"; + clock-control-debugfs = "true"; status = "ok"; }; @@ -659,6 +660,7 @@ <0 0 0 0 0 0 600000000 0 0>; clock-cntl-level = "svs", "svs_l1", "turbo"; src-clock-name = "ife_clk_src"; + clock-control-debugfs = "true"; clock-names-option = "ife_dsp_clk"; clocks-option = <&clock_camcc CAM_CC_IFE_0_DSP_CLK>; clock-rates-option = <600000000>; @@ -707,6 +709,7 @@ <0 0 0 0 0 0 538000000 0 0 0 600000000 0 0>; clock-cntl-level = "svs", "turbo"; src-clock-name = "ife_csid_clk_src"; + clock-control-debugfs = "true"; status = "ok"; }; @@ -745,6 +748,7 @@ <0 0 0 0 0 0 600000000 0 0>; clock-cntl-level = "svs", "svs_l1", "turbo"; src-clock-name = "ife_clk_src"; + clock-control-debugfs = "true"; clock-names-option = "ife_dsp_clk"; clocks-option = <&clock_camcc CAM_CC_IFE_1_DSP_CLK>; clock-rates-option = <600000000>; @@ -790,6 +794,7 @@ <0 0 0 0 0 0 538000000 0 0 0 600000000 0>; clock-cntl-level = "svs", "turbo"; src-clock-name = "ife_csid_clk_src"; + clock-control-debugfs = "true"; status = "ok"; }; @@ -825,6 +830,7 @@ <0 0 0 0 0 0 600000000 0>; clock-cntl-level = "svs", "svs_l1", "turbo"; src-clock-name = "ife_clk_src"; + clock-control-debugfs = "true"; status = "ok"; }; @@ -892,6 +898,7 @@ "ipe_0_clk", "ipe_0_clk_src"; src-clock-name = "ipe_0_clk_src"; + clock-control-debugfs = "true"; 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>, @@ -922,6 +929,7 @@ "ipe_1_clk", "ipe_1_clk_src"; src-clock-name = "ipe_1_clk_src"; + clock-control-debugfs = "true"; clocks = <&clock_camcc CAM_CC_IPE_1_AHB_CLK>, <&clock_camcc CAM_CC_IPE_1_AREG_CLK>, <&clock_camcc CAM_CC_IPE_1_AXI_CLK>, @@ -952,6 +960,7 @@ "bps_clk", "bps_clk_src"; src-clock-name = "bps_clk_src"; + clock-control-debugfs = "true"; clocks = <&clock_camcc CAM_CC_BPS_AHB_CLK>, <&clock_camcc CAM_CC_BPS_AREG_CLK>, <&clock_camcc CAM_CC_BPS_AXI_CLK>, @@ -1074,6 +1083,7 @@ <&clock_camcc CAM_CC_FD_CORE_CLK>, <&clock_camcc CAM_CC_FD_CORE_UAR_CLK>; src-clock-name = "fd_core_clk_src"; + clock-control-debugfs = "true"; clock-cntl-level = "svs", "svs_l1", "turbo"; clock-rates = <0 0 0 0 0 400000000 0 0>, -- GitLab From 7a954c223178df6d1a311c833705cdc16f369203 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Thu, 28 Jun 2018 16:39:52 -0700 Subject: [PATCH 324/604] ARM: dts: msm: Add src clk name in csiphy node Currently csiphy driver finds the src clk index by parsing through all the clock names. With this change we can find the src clk index while parsing the DT, the driver no longer needs to find it. Change-Id: I49d6d70d8956c3c96e5e3349d0323c65f1345f6d Signed-off-by: Karthik Anantha Ram --- arch/arm64/boot/dts/qcom/sdm670-camera.dtsi | 3 +++ arch/arm64/boot/dts/qcom/sdm845-camera.dtsi | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi index 3311495c1d6e..209902645554 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi @@ -46,6 +46,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>; @@ -81,6 +82,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>; @@ -117,6 +119,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>; diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi index 0459c07eed68..86b17046ed31 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi @@ -45,6 +45,7 @@ "csiphy0_clk", "csi0phytimer_clk_src", "csi0phytimer_clk"; + src-clock-name = "csi0phytimer_clk_src"; clock-cntl-level = "svs", "turbo"; clock-rates = <0 0 0 0 320000000 0 269333333 0>, @@ -80,6 +81,7 @@ "csiphy1_clk", "csi1phytimer_clk_src", "csi1phytimer_clk"; + src-clock-name = "csi1phytimer_clk_src"; clock-cntl-level = "svs", "turbo"; clock-rates = <0 0 0 0 320000000 0 269333333 0>, @@ -116,6 +118,7 @@ "csiphy2_clk", "csi2phytimer_clk_src", "csi2phytimer_clk"; + src-clock-name = "csi2phytimer_clk_src"; clock-cntl-level = "svs", "turbo"; clock-rates = <0 0 0 0 320000000 0 269333333 0>, -- GitLab From 37d6c5635770283472ce11ab60378386fe33be1d Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 11 Jun 2018 19:28:34 -0700 Subject: [PATCH 325/604] msm: camera: debugfs to update clk rates dynamically This change provides provision to read the supported clk rates for each of the hardwares and one can vote for one of the supported clk levels before streamon. Change-Id: I9626fb87b6a72b70b4479562b6f50b31b85263be Signed-off-by: Karthik Anantha Ram --- .../bindings/media/video/msm-cam-fd.txt | 5 + .../bindings/media/video/msm-cam-icp.txt | 5 + .../bindings/media/video/msm-cam-ife-csid.txt | 5 +- .../bindings/media/video/msm-cam-vfe.txt | 5 + .../msm/camera/cam_cpas/cam_cpas_hw.c | 5 +- .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c | 14 +- .../camera/cam_icp/icp_hw/bps_hw/bps_dev.c | 9 +- .../camera/cam_icp/icp_hw/bps_hw/bps_soc.c | 3 +- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 1 + .../camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c | 11 +- .../camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c | 3 +- .../isp_hw/ife_csid_hw/cam_ife_csid_dev.c | 10 +- .../isp_hw/ife_csid_hw/cam_ife_csid_soc.c | 4 +- .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c | 11 +- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c | 7 +- .../cam_csiphy/cam_csiphy_dev.h | 4 +- .../cam_csiphy/cam_csiphy_soc.c | 18 +- .../msm/camera/cam_utils/cam_soc_util.c | 246 +++++++++++++++++- .../msm/camera/cam_utils/cam_soc_util.h | 21 +- 19 files changed, 336 insertions(+), 51 deletions(-) diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt b/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt index c47cb34a2ae6..b96853054dec 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt @@ -108,6 +108,11 @@ about the device register map, interrupt map, clocks, regulators. Value type: Definition: Source clock name. +- clock-control-debugfs + Usage: optional + Value type: + Definition: Enable/Disable clk rate control. + - clock-cntl-level Usage: required Value type: diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt b/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt index ffc0e96a459d..14958819068c 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt @@ -110,6 +110,11 @@ and name of firmware image. Value type: Definition: Source clock name. +- clock-control-debugfs + Usage: optional + Value type: + Definition: Enable/Disable clk rate control. + - clocks Usage: required Value type: diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-ife-csid.txt b/Documentation/devicetree/bindings/media/video/msm-cam-ife-csid.txt index f9a5e0fc1bf1..29ea987e306d 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-ife-csid.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-ife-csid.txt @@ -73,7 +73,10 @@ First Level Node - CAM IFE CSID device Value type: Definition: Source clock name. - +- clock-control-debugfs + Usage: optional + Value type: + Definition: Enable/Disable clk rate control. Example: diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt b/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt index 99f2c7a0be35..f156cc67b2aa 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt @@ -91,6 +91,11 @@ Optional properties: Value type: Definition: List of clocks rates for optional clocks. +- clock-control-debugfs + Usage: optional + Value type: + Definition: Enable/Disable clk rate control. + Example: qcom,vfe0@acaf000 { cell-index = <0>; 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 8fd144fa08ea..75ca76fc3947 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 @@ -594,10 +594,7 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %d", required_camnoc_bw, clk_rate); - rc = cam_soc_util_set_clk_rate( - soc_info->clk[soc_info->src_clk_idx], - soc_info->clk_name[soc_info->src_clk_idx], - clk_rate); + rc = cam_soc_util_set_src_clk_rate(soc_info, clk_rate); if (!rc) CAM_ERR(CAM_CPAS, "Failed in setting camnoc axi clk %llu %d %d", 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 6d9d330f7838..fd94e7c235c8 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 @@ -24,6 +24,8 @@ #include "cam_fd_hw_v41.h" #include "cam_fd_hw_v501.h" +static char fd_dev_name[8]; + static int cam_fd_hw_dev_probe(struct platform_device *pdev) { struct cam_hw_info *fd_hw; @@ -32,6 +34,7 @@ static int cam_fd_hw_dev_probe(struct platform_device *pdev) const struct of_device_id *match_dev = NULL; struct cam_fd_hw_static_info *hw_static_info = NULL; int rc = 0; + uint32_t hw_idx; struct cam_fd_hw_init_args init_args; struct cam_fd_hw_deinit_args deinit_args; @@ -51,14 +54,21 @@ static int cam_fd_hw_dev_probe(struct platform_device *pdev) kfree(fd_hw_intf); return -ENOMEM; } + of_property_read_u32(pdev->dev.of_node, + "cell-index", &hw_idx); fd_hw_intf->hw_priv = fd_hw; fd_hw->core_info = fd_core; + fd_hw_intf->hw_idx = hw_idx; + + memset(fd_dev_name, 0, sizeof(fd_dev_name)); + snprintf(fd_dev_name, sizeof(fd_dev_name), + "fd%1u", fd_hw_intf->hw_idx); fd_hw->hw_state = CAM_HW_STATE_POWER_DOWN; fd_hw->soc_info.pdev = pdev; fd_hw->soc_info.dev = &pdev->dev; - fd_hw->soc_info.dev_name = pdev->name; + fd_hw->soc_info.dev_name = fd_dev_name; fd_hw->open_count = 0; mutex_init(&fd_hw->hw_mutex); spin_lock_init(&fd_hw->hw_lock); @@ -104,8 +114,6 @@ static int cam_fd_hw_dev_probe(struct platform_device *pdev) goto free_memory; } - fd_hw_intf->hw_idx = fd_hw->soc_info.index; - memset(&init_args, 0x0, sizeof(init_args)); memset(&deinit_args, 0x0, sizeof(deinit_args)); rc = cam_fd_hw_init(fd_hw, &init_args, sizeof(init_args)); 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 feb0bd899d87..6e51b1e91b14 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 @@ -33,6 +33,8 @@ static struct cam_bps_device_hw_info cam_bps_hw_info = { }; EXPORT_SYMBOL(cam_bps_hw_info); +static char bps_dev_name[8]; + static bool cam_bps_cpas_cb(uint32_t client_handle, void *userdata, struct cam_cpas_irq_data *irq_data) { @@ -111,9 +113,14 @@ int cam_bps_probe(struct platform_device *pdev) kfree(bps_dev_intf); return -ENOMEM; } + + memset(bps_dev_name, 0, sizeof(bps_dev_name)); + snprintf(bps_dev_name, sizeof(bps_dev_name), + "bps%1u", bps_dev_intf->hw_idx); + bps_dev->soc_info.pdev = pdev; bps_dev->soc_info.dev = &pdev->dev; - bps_dev->soc_info.dev_name = pdev->name; + bps_dev->soc_info.dev_name = bps_dev_name; bps_dev_intf->hw_priv = bps_dev; bps_dev_intf->hw_ops.init = cam_bps_init_hw; bps_dev_intf->hw_ops.deinit = cam_bps_deinit_hw; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c index d2314c4fd89f..1da99a4d960d 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c @@ -154,8 +154,7 @@ int cam_bps_update_clk_rate(struct cam_hw_soc_info *soc_info, clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; } - return cam_soc_util_set_clk_rate(soc_info->clk[soc_info->src_clk_idx], - soc_info->clk_name[soc_info->src_clk_idx], clk_rate); + return cam_soc_util_set_src_clk_rate(soc_info, clk_rate); } int cam_bps_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable) 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 8248adf841ea..19a42a11c7f8 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 @@ -1373,6 +1373,7 @@ static int cam_icp_hw_mgr_create_debugfs_entry(void) return rc; err: debugfs_remove_recursive(icp_hw_mgr.dentry); + icp_hw_mgr.dentry = NULL; return rc; } 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 cc2b1b1f88a5..456d45e08b74 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 @@ -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 @@ -41,6 +41,8 @@ static struct cam_ipe_device_hw_info cam_ipe_hw_info[] = { }; EXPORT_SYMBOL(cam_ipe_hw_info); +static char ipe_dev_name[8]; + int cam_ipe_register_cpas(struct cam_hw_soc_info *soc_info, struct cam_ipe_device_core_info *core_info, uint32_t hw_idx) @@ -96,9 +98,14 @@ int cam_ipe_probe(struct platform_device *pdev) kfree(ipe_dev_intf); return -ENOMEM; } + + memset(ipe_dev_name, 0, sizeof(ipe_dev_name)); + snprintf(ipe_dev_name, sizeof(ipe_dev_name), + "ipe%1u", ipe_dev_intf->hw_idx); + ipe_dev->soc_info.pdev = pdev; ipe_dev->soc_info.dev = &pdev->dev; - ipe_dev->soc_info.dev_name = pdev->name; + ipe_dev->soc_info.dev_name = ipe_dev_name; ipe_dev_intf->hw_priv = ipe_dev; ipe_dev_intf->hw_ops.init = cam_ipe_init_hw; ipe_dev_intf->hw_ops.deinit = cam_ipe_deinit_hw; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c index d24305ac89fe..91d440fcdcee 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c @@ -157,8 +157,7 @@ int cam_ipe_update_clk_rate(struct cam_hw_soc_info *soc_info, clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; } - return cam_soc_util_set_clk_rate(soc_info->clk[soc_info->src_clk_idx], - soc_info->clk_name[soc_info->src_clk_idx], clk_rate); + return cam_soc_util_set_src_clk_rate(soc_info, clk_rate); } int cam_ipe_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable) diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c index 128c050284d4..2556b65875db 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.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 @@ -21,6 +21,8 @@ static struct cam_hw_intf *cam_ife_csid_hw_list[CAM_IFE_CSID_HW_RES_MAX] = { 0, 0, 0, 0}; +static char csid_dev_name[8]; + int cam_ife_csid_probe(struct platform_device *pdev) { @@ -63,6 +65,10 @@ int cam_ife_csid_probe(struct platform_device *pdev) goto free_dev; } + memset(csid_dev_name, 0, sizeof(csid_dev_name)); + snprintf(csid_dev_name, sizeof(csid_dev_name), + "csid%1u", csid_dev_idx); + csid_hw_intf->hw_idx = csid_dev_idx; csid_hw_intf->hw_type = CAM_ISP_HW_TYPE_IFE_CSID; csid_hw_intf->hw_priv = csid_hw_info; @@ -70,7 +76,7 @@ int cam_ife_csid_probe(struct platform_device *pdev) csid_hw_info->core_info = csid_dev; csid_hw_info->soc_info.pdev = pdev; csid_hw_info->soc_info.dev = &pdev->dev; - csid_hw_info->soc_info.dev_name = pdev->name; + csid_hw_info->soc_info.dev_name = csid_dev_name; csid_hw_info->soc_info.index = csid_dev_idx; csid_hw_data = (struct cam_ife_csid_hw_info *)match_dev->data; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c index e11ff6372ae0..d3261f84e2f4 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.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 @@ -112,8 +112,6 @@ int cam_ife_csid_deinit_soc_resources( CAM_ERR(CAM_ISP, "CPAS unregistration failed rc=%d", rc); rc = cam_soc_util_release_platform_resource(soc_info); - if (rc < 0) - return rc; return rc; } diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c index 74627b8d32ef..66b647d3136b 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.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 @@ -21,6 +21,8 @@ static struct cam_hw_intf *cam_vfe_hw_list[CAM_VFE_HW_NUM_MAX] = {0, 0, 0, 0}; +static char vfe_dev_name[8]; + int cam_vfe_probe(struct platform_device *pdev) { struct cam_hw_info *vfe_hw = NULL; @@ -44,9 +46,14 @@ int cam_vfe_probe(struct platform_device *pdev) rc = -ENOMEM; goto free_vfe_hw_intf; } + + memset(vfe_dev_name, 0, sizeof(vfe_dev_name)); + snprintf(vfe_dev_name, sizeof(vfe_dev_name), + "vfe%1u", vfe_hw_intf->hw_idx); + vfe_hw->soc_info.pdev = pdev; vfe_hw->soc_info.dev = &pdev->dev; - vfe_hw->soc_info.dev_name = pdev->name; + vfe_hw->soc_info.dev_name = vfe_dev_name; vfe_hw_intf->hw_priv = vfe_hw; vfe_hw_intf->hw_ops.get_hw_caps = cam_vfe_get_hw_caps; vfe_hw_intf->hw_ops.init = cam_vfe_init_hw; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index be0ca184113c..47a04388ea8d 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -107,14 +107,11 @@ static int cam_vfe_top_set_hw_clk_rate( if (max_clk_rate == top_priv->hw_clk_rate) return 0; - CAM_DBG(CAM_ISP, "VFE: Clock name=%s idx=%d clk=%lld", + CAM_DBG(CAM_ISP, "VFE: Clock name=%s idx=%d clk=%llu", soc_info->clk_name[soc_info->src_clk_idx], soc_info->src_clk_idx, max_clk_rate); - rc = cam_soc_util_set_clk_rate( - soc_info->clk[soc_info->src_clk_idx], - soc_info->clk_name[soc_info->src_clk_idx], - max_clk_rate); + rc = cam_soc_util_set_src_clk_rate(soc_info, max_clk_rate); if (!rc) top_priv->hw_clk_rate = max_clk_rate; 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 afe4239b2d71..9c85af39bd8c 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 @@ -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 @@ -198,7 +198,6 @@ struct cam_csiphy_param { * @csiphy_reg_ptr: Regulator structure * @csiphy_3p_clk_info: 3Phase clock information * @csiphy_3p_clk: 3Phase clocks structure - * @csiphy_clk_index: Timer Src clk index * @csi_3phase: Is it a 3Phase mode * @ref_count: Reference count * @clk_lane: Clock lane @@ -216,7 +215,6 @@ struct csiphy_device { uint32_t csiphy_max_clk; struct msm_cam_clk_info csiphy_3p_clk_info[2]; struct clk *csiphy_3p_clk[2]; - uint32_t csiphy_clk_index; unsigned char csi_3phase; int32_t ref_count; uint16_t lane_mask[MAX_CSIPHY]; 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 6db5a9796606..28326ecadd2c 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 @@ -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 @@ -97,10 +97,8 @@ int32_t cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev) return rc; } - rc = cam_soc_util_set_clk_rate( - soc_info->clk[csiphy_dev->csiphy_clk_index], - soc_info->clk_name[csiphy_dev->csiphy_clk_index], - soc_info->clk_rate[0][csiphy_dev->csiphy_clk_index]); + rc = cam_soc_util_set_src_clk_rate(soc_info, + soc_info->clk_rate[0][soc_info->src_clk_idx]); if (rc < 0) { CAM_ERR(CAM_CSIPHY, "csiphy_clk_set_rate failed rc: %d", rc); @@ -208,16 +206,14 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, continue; } - if (!strcmp(soc_info->clk_name[i], - "csiphy_timer_src_clk")) { - csiphy_dev->csiphy_max_clk = - soc_info->clk_rate[0][clk_cnt]; - csiphy_dev->csiphy_clk_index = clk_cnt; - } CAM_DBG(CAM_CSIPHY, "clk_rate[%d] = %d", clk_cnt, soc_info->clk_rate[0][clk_cnt]); clk_cnt++; } + + csiphy_dev->csiphy_max_clk = + soc_info->clk_rate[0][soc_info->src_clk_idx]; + rc = cam_soc_util_request_platform_resource(&csiphy_dev->soc_info, cam_csiphy_irq, csiphy_dev); 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 0b1896fc9ed6..91f91ddfd8db 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 @@ -18,6 +18,197 @@ #include "cam_soc_util.h" #include "cam_debug_util.h" +static char supported_clk_info[256]; +static char debugfs_dir_name[64]; + +/** + * cam_soc_util_get_string_from_level() + * + * @brief: Returns the string for a given clk level + * + * @level: Clock level + * + * @return: String corresponding to the clk level + */ +static const char *cam_soc_util_get_string_from_level( + enum cam_vote_level level) +{ + switch (level) { + case CAM_SUSPEND_VOTE: + return ""; + case CAM_MINSVS_VOTE: + return "MINSVS[1]"; + case CAM_LOWSVS_VOTE: + return "LOWSVS[2]"; + case CAM_SVS_VOTE: + return "SVS[3]"; + case CAM_SVSL1_VOTE: + return "SVSL1[4]"; + case CAM_NOMINAL_VOTE: + return "NOM[5]"; + case CAM_TURBO_VOTE: + return "TURBO[6]"; + default: + return ""; + } +} + +/** + * cam_soc_util_get_supported_clk_levels() + * + * @brief: Returns the string of all the supported clk levels for + * the given device + * + * @soc_info: Device soc information + * + * @return: String containing all supported clk levels + */ +static const char *cam_soc_util_get_supported_clk_levels( + struct cam_hw_soc_info *soc_info) +{ + int i = 0; + + memset(supported_clk_info, 0, sizeof(supported_clk_info)); + strlcat(supported_clk_info, "Supported levels: ", + sizeof(supported_clk_info)); + + for (i = 0; i < CAM_MAX_VOTE; i++) { + if (soc_info->clk_level_valid[i] == true) { + strlcat(supported_clk_info, + cam_soc_util_get_string_from_level(i), + sizeof(supported_clk_info)); + strlcat(supported_clk_info, " ", + sizeof(supported_clk_info)); + } + } + + strlcat(supported_clk_info, "\n", sizeof(supported_clk_info)); + return supported_clk_info; +} + +static int cam_soc_util_clk_lvl_options_open(struct inode *inode, + struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t cam_soc_util_clk_lvl_options_read(struct file *file, + char __user *clk_info, size_t size_t, loff_t *loff_t) +{ + struct cam_hw_soc_info *soc_info = + (struct cam_hw_soc_info *)file->private_data; + const char *display_string = + cam_soc_util_get_supported_clk_levels(soc_info); + + return simple_read_from_buffer(clk_info, size_t, loff_t, display_string, + strlen(display_string)); +} + +static const struct file_operations cam_soc_util_clk_lvl_options = { + .open = cam_soc_util_clk_lvl_options_open, + .read = cam_soc_util_clk_lvl_options_read, +}; + +static int cam_soc_util_set_clk_lvl(void *data, u64 val) +{ + struct cam_hw_soc_info *soc_info = (struct cam_hw_soc_info *)data; + + if (val <= CAM_SUSPEND_VOTE || val >= CAM_MAX_VOTE) + return 0; + + if (soc_info->clk_level_valid[val] == true) + soc_info->clk_level_override = val; + else + soc_info->clk_level_override = 0; + + return 0; +} + +static int cam_soc_util_get_clk_lvl(void *data, u64 *val) +{ + struct cam_hw_soc_info *soc_info = (struct cam_hw_soc_info *)data; + + *val = soc_info->clk_level_override; + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_soc_util_clk_lvl_control, + cam_soc_util_get_clk_lvl, cam_soc_util_set_clk_lvl, "%08llu"); + +/** + * cam_soc_util_create_clk_lvl_debugfs() + * + * @brief: Creates debugfs files to view/control device clk rates + * + * @soc_info: Device soc information + * + * @return: Success or failure + */ +static int cam_soc_util_create_clk_lvl_debugfs( + struct cam_hw_soc_info *soc_info) +{ + struct dentry *dentry = NULL; + + if (!soc_info) { + CAM_ERR(CAM_UTIL, "soc info is NULL"); + return -EINVAL; + } + + if (soc_info->dentry) + return 0; + + memset(debugfs_dir_name, 0, sizeof(debugfs_dir_name)); + strlcat(debugfs_dir_name, "clk_dir_", sizeof(debugfs_dir_name)); + strlcat(debugfs_dir_name, soc_info->dev_name, sizeof(debugfs_dir_name)); + + dentry = soc_info->dentry; + dentry = debugfs_create_dir(debugfs_dir_name, NULL); + if (!dentry) { + CAM_ERR(CAM_UTIL, "failed to create debug directory"); + return -ENOMEM; + } + + if (!debugfs_create_file("clk_lvl_options", 0444, + dentry, soc_info, &cam_soc_util_clk_lvl_options)) { + CAM_ERR(CAM_UTIL, "failed to create clk_lvl_options"); + goto err; + } + + if (!debugfs_create_file("clk_lvl_control", 0644, + dentry, soc_info, &cam_soc_util_clk_lvl_control)) { + CAM_ERR(CAM_UTIL, "failed to create clk_lvl_control"); + goto err; + } + + CAM_DBG(CAM_UTIL, "clk lvl debugfs for %s successfully created", + soc_info->dev_name); + + return 0; + +err: + debugfs_remove_recursive(dentry); + dentry = NULL; + return -ENOMEM; +} + +/** + * cam_soc_util_remove_clk_lvl_debugfs() + * + * @brief: Removes the debugfs files used to view/control + * device clk rates + * + * @soc_info: Device soc information + * + */ +static void cam_soc_util_remove_clk_lvl_debugfs( + struct cam_hw_soc_info *soc_info) +{ + debugfs_remove_recursive(soc_info->dentry); + soc_info->dentry = NULL; +} + int cam_soc_util_get_level_from_string(const char *string, enum cam_vote_level *level) { @@ -152,7 +343,18 @@ int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info, return clk_set_flags(soc_info->clk[clk_index], flags); } -int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, +/** + * cam_soc_util_set_clk_rate() + * + * @brief: Sets the given rate for the clk requested for + * + * @clk: Clock structure information for which rate is to be set + * @clk_name: Name of the clock for which rate is being set + * @clk_rate Clock rate to be set + * + * @return: Success or failure + */ +static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, int32_t clk_rate) { int rc = 0; @@ -196,6 +398,26 @@ int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, return rc; } +int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, + int32_t clk_rate) +{ + int32_t src_clk_idx; + struct clk *clk = NULL; + + if (!soc_info || (soc_info->src_clk_idx < 0)) + return -EINVAL; + + if (soc_info->clk_level_override && clk_rate) + clk_rate = soc_info->clk_level_override; + + src_clk_idx = soc_info->src_clk_idx; + clk = soc_info->clk[src_clk_idx]; + + return cam_soc_util_set_clk_rate(clk, + soc_info->clk_name[src_clk_idx], clk_rate); + +} + int cam_soc_util_clk_put(struct clk **clk) { if (!(*clk)) { @@ -402,6 +624,7 @@ static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info) int i, j, rc; int32_t num_clk_level_strings; const char *src_clk_str = NULL; + const char *clk_control_debugfs = NULL; const char *clk_cntl_lvl_string = NULL; enum cam_vote_level level; @@ -515,8 +738,7 @@ static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info) if (rc || !src_clk_str) { CAM_DBG(CAM_UTIL, "No src_clk_str found"); rc = 0; - /* Bottom loop is dependent on src_clk_str. So return here */ - return rc; + goto end; } for (i = 0; i < soc_info->num_clk; i++) { @@ -528,6 +750,18 @@ static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info) } } + rc = of_property_read_string_index(of_node, + "clock-control-debugfs", 0, &clk_control_debugfs); + if (rc || !clk_control_debugfs) { + CAM_DBG(CAM_UTIL, "No clock_control_debugfs property found"); + rc = 0; + goto end; + } + + if (strcmp("true", clk_control_debugfs) == 0) + soc_info->clk_control_enable = true; + +end: return rc; } @@ -1215,6 +1449,9 @@ int cam_soc_util_request_platform_resource( goto put_clk; } + if (soc_info->clk_control_enable) + cam_soc_util_create_clk_lvl_debugfs(soc_info); + return rc; put_clk: @@ -1299,6 +1536,9 @@ int cam_soc_util_release_platform_resource(struct cam_hw_soc_info *soc_info) /* release for gpio */ cam_soc_util_request_gpio_table(soc_info, false); + if (soc_info->clk_control_enable) + cam_soc_util_remove_clk_lvl_debugfs(soc_info); + return 0; } 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 4b57d54466c3..f24bb129edc7 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 @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* 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 @@ -22,6 +22,7 @@ #include #include #include +#include #include "cam_io_util.h" @@ -150,6 +151,9 @@ struct cam_soc_gpio_data { * @clk_level_valid: Indicates whether corresponding level is valid * @gpio_data: Pointer to gpio info * @pinctrl_info: Pointer to pinctrl info + * @dentry: Debugfs entry + * @clk_level_override: Clk level set from debugfs + * @clk_control: Enable/disable clk rate control through debugfs * @soc_private: Soc private data */ struct cam_hw_soc_info { @@ -191,6 +195,10 @@ struct cam_hw_soc_info { struct cam_soc_gpio_data *gpio_data; struct cam_soc_pinctrl_info pinctrl_info; + struct dentry *dentry; + uint32_t clk_level_override; + bool clk_control_enable; + void *soc_private; }; @@ -364,17 +372,16 @@ int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info, uint32_t clk_index, unsigned long flags); /** - * cam_soc_util_set_clk_rate() + * cam_soc_util_set_src_clk_rate() * - * @brief: Set the rate on a given clock. + * @brief: Set the rate on the source clock. * - * @clk: Clock that needs to be set - * @clk_name: Clocks name associated with clk - * @clk_rate: Clocks rate associated with clk + * @soc_info: Device soc information + * @clk_rate: Clock rate associated with the src clk * * @return: success or failure */ -int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, +int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, int32_t clk_rate); /** -- GitLab From 75ff78330c6c0810adb10531e3a46ad97904126a Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Tue, 5 Jun 2018 14:30:02 +0530 Subject: [PATCH 326/604] drm/msm/dsi-staging: update DSI phy T_TA_GO duration This change updates the DSI PHY T_TA_GO duration for DSI phy version v2 and v3 as per HW recommendation. Change-Id: I50d6c51c0e410a826bf7ef02157a5265eaeb10f9 Signed-off-by: Sandeep Panda --- drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v2_0.c | 2 +- drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v3_0.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v2_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v2_0.c index 3da0fc3f0a26..45f757703764 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v2_0.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v2_0.c @@ -113,7 +113,7 @@ void dsi_phy_hw_v2_0_update_timing_params( else timing->lane[i][4] = desc->hs_rqst.reg_value; - timing->lane[i][5] = 0x3; + timing->lane[i][5] = 0x2; timing->lane[i][6] = 0x4; timing->lane[i][7] = 0xA0; pr_debug("[%d][%d %d %d %d %d]\n", i, timing->lane[i][0], diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v3_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v3_0.c index 4392c60eb0f3..c0e9d441542d 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v3_0.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v3_0.c @@ -92,7 +92,7 @@ void dsi_phy_hw_v3_0_update_timing_params( timing->lane_v3[6] = desc->hs_prepare.reg_value; timing->lane_v3[7] = desc->hs_trail.reg_value; timing->lane_v3[8] = desc->hs_rqst.reg_value; - timing->lane_v3[9] = 0x03; + timing->lane_v3[9] = 0x02; timing->lane_v3[10] = 0x04; timing->lane_v3[11] = 0x00; -- GitLab From 88b96ae749d352746c25d26bc347db5370ed1069 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Tue, 10 Jul 2018 11:37:11 +0530 Subject: [PATCH 327/604] ARM: dts: msm: update DSI phy T_TA_GO setting for sdm670 Current value of DSI phy T_TA_GO does not follow MIPI specification properly. Hence update the setting as per HW recommendation for sdm670 platform. Change-Id: I1789fc705858d4979b2439f09adacd183018908a Signed-off-by: Sandeep Panda --- .../boot/dts/qcom/sdm670-sde-display.dtsi | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi index a74337339eb2..578f676f8e13 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi @@ -561,7 +561,7 @@ qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 - 07 05 03 04 00]; + 07 05 02 04 00]; qcom,display-topology = <2 0 2>, <1 0 2>; qcom,default-topology-index = <0>; @@ -583,7 +583,7 @@ qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 - 07 05 03 04 00]; + 07 05 02 04 00]; qcom,display-topology = <2 0 2>, <1 0 2>; qcom,default-topology-index = <0>; @@ -607,7 +607,7 @@ qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 - 05 03 03 04 00]; + 05 03 02 04 00]; qcom,display-topology = <1 1 1>, <2 2 1>, /* dsc merge */ <2 1 1>; /* 3d mux */ @@ -634,7 +634,7 @@ qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 - 04 03 03 04 00]; + 04 03 02 04 00]; qcom,display-topology = <1 1 1>, <2 2 1>, /* dsc merge */ <2 1 1>; /* 3d mux */ @@ -649,7 +649,7 @@ qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 - 07 05 03 04 00]; + 07 05 02 04 00]; qcom,display-topology = <1 0 1>, <2 0 1>; qcom,default-topology-index = <0>; @@ -663,7 +663,7 @@ qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 - 07 05 03 04 00]; + 07 05 02 04 00]; qcom,display-topology = <2 0 2>, <1 0 2>; qcom,default-topology-index = <0>; @@ -682,7 +682,7 @@ qcom,panel-roi-alignment = <720 40 720 40 720 40>; qcom,partial-update-enabled = "single_roi"; qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 - 07 04 03 04 00]; + 07 04 02 04 00]; }; timing@1{ qcom,display-topology = <1 0 1>, @@ -691,7 +691,7 @@ qcom,panel-roi-alignment = <540 40 540 40 540 40>; qcom,partial-update-enabled = "single_roi"; qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 - 07 04 03 04 00]; + 07 04 02 04 00]; }; timing@2{ qcom,display-topology = <1 0 1>, @@ -700,7 +700,7 @@ qcom,panel-roi-alignment = <360 40 360 40 360 40>; qcom,partial-update-enabled = "single_roi"; qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 - 07 04 03 04 00]; + 07 04 02 04 00]; }; }; }; @@ -711,20 +711,20 @@ qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09 - 09 06 03 04 00]; + 09 06 02 04 00]; qcom,display-topology = <2 0 2>; qcom,default-topology-index = <0>; }; timing@1{ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 - 07 05 03 04 00]; + 07 05 02 04 00]; qcom,display-topology = <2 0 2>, <1 0 2>; qcom,default-topology-index = <0>; }; timing@2{ qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 - 06 04 03 04 00]; + 06 04 02 04 00]; qcom,display-topology = <2 0 2>; qcom,default-topology-index = <0>; }; @@ -737,13 +737,13 @@ qcom,mdss-dsi-display-timings { timing@0 { /* 1080p */ qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 - 07 04 03 04 00]; + 07 04 02 04 00]; qcom,display-topology = <1 1 1>; qcom,default-topology-index = <0>; }; timing@1 { /* qhd */ qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 - 05 03 03 04 00]; + 05 03 02 04 00]; qcom,display-topology = <1 1 1>, <2 2 1>, /* dsc merge */ <2 1 1>; /* 3d mux */ @@ -758,13 +758,13 @@ qcom,mdss-dsi-display-timings { timing@0 { /* qhd */ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 - 07 05 03 04 00]; + 07 05 02 04 00]; qcom,display-topology = <2 2 2>; qcom,default-topology-index = <0>; }; timing@1 { /* 4k */ qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 - 06 04 03 04 00]; + 06 04 02 04 00]; qcom,display-topology = <2 2 2>; qcom,default-topology-index = <0>; }; @@ -777,7 +777,7 @@ qcom,mdss-dsi-display-timings { timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 - 07 05 03 04 00]; + 07 05 02 04 00]; qcom,display-topology = <2 0 2>, <1 0 2>; qcom,default-topology-index = <0>; @@ -792,7 +792,7 @@ qcom,mdss-dsi-display-timings { timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 - 07 05 03 04 00]; + 07 05 02 04 00]; qcom,display-topology = <2 0 2>, <1 0 2>; qcom,default-topology-index = <0>; @@ -808,7 +808,7 @@ qcom,mdss-dsi-display-timings { timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1c 05 06 0b 0c - 05 07 05 03 04 00]; + 05 07 05 02 04 00]; qcom,display-topology = <1 0 1>; qcom,default-topology-index = <0>; }; @@ -826,7 +826,7 @@ qcom,mdss-dsi-display-timings { timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1c 05 06 0b 0c - 05 07 05 03 04 00]; + 05 07 05 02 04 00]; qcom,display-topology = <1 0 1>; qcom,default-topology-index = <0>; }; @@ -841,7 +841,7 @@ qcom,mdss-dsi-display-timings { timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 - 07 07 05 03 04 00]; + 07 07 05 02 04 00]; qcom,display-topology = <1 0 1>; qcom,default-topology-index = <0>; }; @@ -862,7 +862,7 @@ qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 23 08 - 08 05 03 04 00]; + 08 05 02 04 00]; qcom,display-topology = <2 0 2>, <1 0 2>; qcom,default-topology-index = <0>; @@ -888,7 +888,7 @@ qcom,mdss-dsi-display-timings { timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 22 08 - 08 05 03 04 00]; + 08 05 02 04 00]; qcom,display-topology = <1 0 1>; qcom,default-topology-index = <0>; }; -- GitLab From caa16bdecaaa676e9a6ec7c18753f3ec7b600532 Mon Sep 17 00:00:00 2001 From: Shankar Ravi Date: Wed, 25 Apr 2018 15:38:37 +0530 Subject: [PATCH 328/604] msm: camera: Check for valid per frame i2c data. Add check for valid i2c data per frame before consuming in the flush request. This issue reported in random stability Change-Id: I43f90f1af714a2a4ae3efd86ec6e306c4fde802c Signed-off-by: Shankar Ravi --- .../camera/cam_sensor_module/cam_sensor/cam_sensor_core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c index 223aba42372f..75f74d30b6af 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -1174,6 +1174,11 @@ int32_t cam_sensor_flush_request(struct cam_req_mgr_flush_request *flush_req) return -EINVAL; } + if (s_ctrl->i2c_data.per_frame == NULL) { + CAM_ERR(CAM_SENSOR, "i2c frame data is NULL"); + return -EINVAL; + } + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { i2c_set = &(s_ctrl->i2c_data.per_frame[i]); -- GitLab From 5438d5741c945251bff3f613e534c36f5b6bde5c Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Fri, 15 Jun 2018 10:48:19 -0700 Subject: [PATCH 329/604] msm: camera: Improve logging capability in kmd drivers Adds new log tags to segregate logs across kernel drivers. The change adds tags to track a request(CAM_REQ), performance logs(CAM_PERF), memory manager(CAM_MEM) & irq controller(CAM_IRQ_CTRL) events. Change-Id: Id6c8dc9403d711e02c171a393ddcdce11c506bba Signed-off-by: Karthik Anantha Ram --- .../msm/camera/cam_core/cam_context_utils.c | 13 +- .../msm/camera/cam_cpas/cam_cpas_hw.c | 4 +- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 63 ++++++-- .../msm/camera/cam_isp/cam_isp_context.c | 38 +++-- .../cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 12 +- .../hw_utils/cam_isp_packet_parser.c | 9 +- .../irq_controller/cam_irq_controller.c | 73 +++++---- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 3 +- .../msm/camera/cam_req_mgr/cam_mem_mgr.c | 149 +++++++++--------- .../msm/camera/cam_req_mgr/cam_req_mgr_core.c | 70 +++++--- .../cam_flash/cam_flash_core.c | 16 +- .../cam_sensor/cam_sensor_core.c | 2 +- .../msm/camera/cam_utils/cam_debug_util.c | 16 +- .../msm/camera/cam_utils/cam_debug_util.h | 12 +- 14 files changed, 307 insertions(+), 173 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 f167ef7ca5ff..fce7fc6cc6b8 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 @@ -91,10 +91,19 @@ int cam_context_buf_done_from_hw(struct cam_context *ctx, */ list_del_init(&req->list); spin_unlock(&ctx->lock); - if (!bubble_state) + if (!bubble_state) { result = CAM_SYNC_STATE_SIGNALED_SUCCESS; - else + } else { + CAM_DBG(CAM_REQ, + "[%s][ctx_id %d] : req[%llu] is done with error", + ctx->dev_name, ctx->ctx_id, req->request_id); + + for (j = 0; j < req->num_out_map_entries; j++) + CAM_DBG(CAM_REQ, "fence %d signaled with error", + req->out_map_entries[j].sync_id); + result = CAM_SYNC_STATE_SIGNALED_ERROR; + } for (j = 0; j < req->num_out_map_entries; j++) { cam_sync_signal(req->out_map_entries[j].sync_id, result); 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 8fd144fa08ea..dc9ada67023c 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 @@ -736,7 +736,7 @@ static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw, goto unlock_client; } - CAM_DBG(CAM_CPAS, + CAM_DBG(CAM_PERF, "Client=[%d][%s][%d] Requested compressed[%llu], uncompressed[%llu]", client_indx, cpas_client->data.identifier, cpas_client->data.cell_index, axi_vote.compressed_bw, @@ -898,7 +898,7 @@ static int cam_cpas_hw_update_ahb_vote(struct cam_hw_info *cpas_hw, goto unlock_client; } - CAM_DBG(CAM_CPAS, + CAM_DBG(CAM_PERF, "client=[%d][%s][%d] : type[%d], level[%d], freq[%ld], applied[%d]", client_indx, cpas_client->data.identifier, cpas_client->data.cell_index, ahb_vote.type, 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 c73c25fef428..8d3854c35d9f 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 @@ -995,6 +995,8 @@ static int cam_icp_update_clk_rate(struct cam_icp_hw_mgr *hw_mgr, id = CAM_ICP_IPE_CMD_UPDATE_CLK; } + CAM_DBG(CAM_PERF, "clk_rate %u for dev_type %d", curr_clk_rate, + ctx_data->icp_dev_acquire_info->dev_type); clk_upd_cmd.curr_clk_rate = curr_clk_rate; clk_upd_cmd.ipe_bps_pc_enable = icp_hw_mgr.ipe_bps_pc_flag; @@ -1058,6 +1060,10 @@ static int cam_icp_update_cpas_vote(struct cam_icp_hw_mgr *hw_mgr, * anyway. */ + CAM_DBG(CAM_ICP, "compress_bw %llu uncompress_bw %llu dev_type %d", + clk_info->compressed_bw, clk_info->uncompressed_bw, + ctx_data->icp_dev_acquire_info->dev_type); + return 0; } @@ -1452,8 +1458,10 @@ static int cam_icp_mgr_handle_frame_process(uint32_t *msg_ptr, int flag) CAM_ERR(CAM_ICP, "Invalid Context"); return -EINVAL; } - CAM_DBG(CAM_ICP, "ctx : %pK, request_id :%lld", - (void *)ctx_data->context_priv, request_id); + CAM_DBG(CAM_REQ, + "ctx_id : %u, request_id :%lld dev_type: %d", + ctx_data->ctx_id, request_id, + ctx_data->icp_dev_acquire_info->dev_type); mutex_lock(&ctx_data->ctx_mutex); cam_icp_ctx_timer_reset(ctx_data); @@ -2324,6 +2332,7 @@ static int cam_icp_mgr_hw_close_u(void *hw_priv, void *hw_close_args) struct cam_icp_hw_mgr *hw_mgr = hw_priv; int rc = 0; + CAM_DBG(CAM_ICP, "UMD calls close"); if (!hw_mgr) { CAM_ERR(CAM_ICP, "Null hw mgr"); return 0; @@ -2340,6 +2349,7 @@ static int cam_icp_mgr_hw_close_k(void *hw_priv, void *hw_close_args) { struct cam_icp_hw_mgr *hw_mgr = hw_priv; + CAM_DBG(CAM_ICP, "KMD calls close"); if (!hw_mgr) { CAM_ERR(CAM_ICP, "Null hw mgr"); return 0; @@ -2369,6 +2379,7 @@ static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr) a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); rc = cam_icp_mgr_hw_close_k(hw_mgr, NULL); } else { + CAM_DBG(CAM_PERF, "Sending PC prep ICP PC enabled"); rc = cam_icp_mgr_send_pc_prep(hw_mgr); cam_hfi_disable_cpu( a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); @@ -3179,8 +3190,10 @@ static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) rc = cam_icp_mgr_enqueue_config(hw_mgr, config_args); if (rc) goto config_err; - CAM_DBG(CAM_ICP, "req_id = %lld %u", - req_id, ctx_data->ctx_id); + CAM_DBG(CAM_REQ, + "req_id = %lld on ctx_id %u for dev %d queued to FW", + req_id, ctx_data->ctx_id, + ctx_data->icp_dev_acquire_info->dev_type); mutex_unlock(&ctx_data->ctx_mutex); mutex_unlock(&hw_mgr->hw_mgr_mutex); @@ -3366,8 +3379,11 @@ static int cam_icp_mgr_process_io_cfg(struct cam_icp_hw_mgr *hw_mgr, io_cfg_ptr[i].fence; prepare_args->num_out_map_entries++; } - CAM_DBG(CAM_ICP, "dir[%d]: %u, fence: %u", - i, io_cfg_ptr[i].direction, io_cfg_ptr[i].fence); + CAM_DBG(CAM_REQ, + "ctx_id: %u req_id: %llu dir[%d]: %u, fence: %u resource_type = %u", + ctx_data->ctx_id, packet->header.request_id, i, + io_cfg_ptr[i].direction, io_cfg_ptr[i].fence, + io_cfg_ptr[i].resource_type); } if (prepare_args->num_in_map_entries > 1) { @@ -3383,7 +3399,9 @@ static int cam_icp_mgr_process_io_cfg(struct cam_icp_hw_mgr *hw_mgr, merged_sync_in_obj; prepare_args->in_map_entries[0].sync_id = merged_sync_in_obj; prepare_args->num_in_map_entries = 1; - CAM_DBG(CAM_ICP, "Merged Sync obj = %d", merged_sync_in_obj); + CAM_DBG(CAM_REQ, "ctx_id: %u req_id: %llu Merged Sync obj: %d", + ctx_data->ctx_id, packet->header.request_id, + merged_sync_in_obj); } else if (prepare_args->num_in_map_entries == 1) { prepare_args->in_map_entries[0].sync_id = sync_in_obj[0]; prepare_args->num_in_map_entries = 1; @@ -3604,7 +3622,8 @@ static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv, return rc; } - CAM_DBG(CAM_ICP, "E: req id = %lld", packet->header.request_id); + CAM_DBG(CAM_REQ, "req id = %lld for ctx = %u", + packet->header.request_id, ctx_data->ctx_id); /* Update Buffer Address from handles and patch information */ rc = cam_packet_util_process_patches(packet, hw_mgr->iommu_hdl, hw_mgr->iommu_sec_hdl); @@ -3820,6 +3839,11 @@ 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); + switch (flush_args->flush_type) { case CAM_FLUSH_TYPE_ALL: mutex_lock(&hw_mgr->hw_mgr_mutex); @@ -3914,7 +3938,8 @@ static int cam_icp_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) if ((!hw_mgr->bps_ctxt_cnt || !hw_mgr->ipe_ctxt_cnt)) cam_icp_device_timer_stop(hw_mgr); - CAM_DBG(CAM_ICP, "Exit"); + CAM_DBG(CAM_ICP, "Release done for ctx_id %d dev %d", ctx_id, + ctx_data->icp_dev_acquire_info->dev_type); return rc; } @@ -4091,6 +4116,21 @@ static int cam_icp_get_acquire_info(struct cam_icp_hw_mgr *hw_mgr, return 0; } +static const char *cam_icp_dev_type_to_name( + uint32_t dev_type) +{ + switch (dev_type) { + case CAM_ICP_RES_TYPE_BPS: + return "BPS"; + case CAM_ICP_RES_TYPE_IPE_RT: + return "IPE_RT"; + case CAM_ICP_RES_TYPE_IPE: + return "IPE"; + default: + return "Invalid dev type"; + } +} + static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) { int rc = 0, bitmap_size = 0; @@ -4222,7 +4262,10 @@ static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) cam_icp_ctx_timer_start(ctx_data); hw_mgr->ctxt_cnt++; mutex_unlock(&hw_mgr->hw_mgr_mutex); - CAM_DBG(CAM_ICP, "Acquire Done"); + CAM_DBG(CAM_ICP, "Acquire Done for ctx_id %u dev name %s dev type %d", + ctx_data->ctx_id, cam_icp_dev_type_to_name( + icp_dev_acquire_info->dev_type), + icp_dev_acquire_info->dev_type); return 0; 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 203e549d9491..29963304c859 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 @@ -435,8 +435,8 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( list_del_init(&req->list); list_add_tail(&req->list, &ctx->free_req_list); ctx_isp->active_req_cnt--; - CAM_DBG(CAM_ISP, - "Move active request %lld to free list(cnt = %d)", + CAM_DBG(CAM_REQ, + "Move active request %lld to free list(cnt = %d) [all fences done]", req->request_id, ctx_isp->active_req_cnt); } @@ -536,7 +536,7 @@ static int __cam_isp_ctx_reg_upd_in_activated_state( if (req_isp->num_fence_map_out != 0) { list_add_tail(&req->list, &ctx->active_req_list); ctx_isp->active_req_cnt++; - CAM_DBG(CAM_ISP, "move request %lld to active list(cnt = %d)", + CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d)", req->request_id, ctx_isp->active_req_cnt); } else { /* no io config, so the request is completed. */ @@ -697,7 +697,7 @@ static int __cam_isp_ctx_reg_upd_in_sof(struct cam_isp_context *ctx_isp, /* need to handle the buf done */ list_add_tail(&req->list, &ctx->active_req_list); ctx_isp->active_req_cnt++; - CAM_DBG(CAM_ISP, + CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d)", req->request_id, ctx_isp->active_req_cnt); @@ -761,7 +761,7 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, list_del_init(&req->list); list_add_tail(&req->list, &ctx->active_req_list); ctx_isp->active_req_cnt++; - CAM_DBG(CAM_ISP, "move request %lld to active list(cnt = %d)", + CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d)", req->request_id, ctx_isp->active_req_cnt); req_isp->bubble_report = 0; } @@ -895,8 +895,9 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( notify.req_id = req->request_id; notify.error = CRM_KMD_ERR_BUBBLE; ctx->ctx_crm_intf->notify_err(¬ify); - CAM_DBG(CAM_ISP, "Notify CRM about Bubble frame %lld", - ctx_isp->frame_id); + CAM_DBG(CAM_REQ, + "Notify CRM about Bubble req_id %llu frame %lld", + req->request_id, ctx_isp->frame_id); } else { /* * If we can not report bubble, then treat it as if no bubble @@ -1192,7 +1193,8 @@ static int __cam_isp_ctx_apply_req_in_activated_state( goto end; } - CAM_DBG(CAM_ISP, "Apply request %lld", req->request_id); + CAM_DBG(CAM_REQ, "Apply request %lld in substate %d", req->request_id, + ctx_isp->substate_activated); req_isp = (struct cam_isp_ctx_req *) req->req_priv; if (ctx_isp->active_req_cnt >= 2) { @@ -1313,6 +1315,8 @@ static int __cam_isp_ctx_flush_req(struct cam_context *ctx, return 0; } + CAM_DBG(CAM_REQ, "Flush [%u] in progress for req_id %llu", + flush_req->type, flush_req->req_id); list_for_each_entry_safe(req, req_temp, req_list, list) { if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { if (req->request_id != flush_req->req_id) { @@ -1942,7 +1946,8 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, ctx->state = CAM_CTX_AVAILABLE; trace_cam_context_state("ISP", ctx); - CAM_DBG(CAM_ISP, "next state %d", ctx->state); + CAM_DBG(CAM_ISP, "Release device success[%u] next state %d", + ctx->ctx_id, ctx->state); return rc; } @@ -2068,8 +2073,9 @@ static int __cam_isp_ctx_config_dev_in_top_state( if (rc) goto free_req; - CAM_DBG(CAM_ISP, "Preprocessing Config %lld successful", - req->request_id); + CAM_DBG(CAM_REQ, + "Preprocessing Config req_id %lld successful on ctx %u", + req->request_id, ctx->ctx_id); return rc; @@ -2200,7 +2206,10 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, ctx->state = CAM_CTX_ACQUIRED; trace_cam_context_state("ISP", ctx); - CAM_DBG(CAM_ISP, "Acquire success."); + CAM_DBG(CAM_ISP, + "Acquire success on session_hdl 0x%x num_rsrces %d RDI only %d ctx %u", + cmd->session_handle, cmd->num_resources, + (hw_cmd_args.u.is_rdi_only_context ? 1 : 0), ctx->ctx_id); kfree(isp_res); return rc; @@ -2342,7 +2351,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, trace_cam_context_state("ISP", ctx); goto end; } - CAM_DBG(CAM_ISP, "start device success"); + CAM_DBG(CAM_ISP, "start device success ctx %u", ctx->ctx_id); if (req_isp->num_fence_map_out) { list_del_init(&req->list); @@ -2425,7 +2434,8 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( ctx_isp->active_req_cnt = 0; ctx_isp->reported_req_id = 0; - CAM_DBG(CAM_ISP, "next state %d", ctx->state); + CAM_DBG(CAM_ISP, "Stop device success next state %d on ctx %u", + ctx->state, ctx->ctx_id); return rc; } 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 891cbb481644..985d0b0e1662 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 @@ -1540,7 +1540,7 @@ static int cam_isp_blob_bw_update( int rc = -EINVAL; uint32_t i; - CAM_DBG(CAM_ISP, + CAM_DBG(CAM_PERF, "usage=%u left cam_bw_bps=%llu ext_bw_bps=%llu\n" "right cam_bw_bps=%llu ext_bw_bps=%llu", bw_config->usage_type, @@ -1953,7 +1953,8 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) cam_ife_hw_mgr_deinit_hw_res(&ctx->res_list_ife_out[i]); - CAM_DBG(CAM_ISP, "Exit...ctx id:%d rc :%d", ctx->ctx_index, rc); + CAM_DBG(CAM_ISP, + "Stop success for ctx id:%d rc :%d", ctx->ctx_index, rc); mutex_lock(&g_ife_hw_mgr.ctx_mutex); if (!atomic_dec_return(&g_ife_hw_mgr.active_ctx_cnt)) { @@ -2231,7 +2232,7 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) } /* Start IFE root node: do nothing */ - CAM_DBG(CAM_ISP, "Exit...(success)"); + CAM_DBG(CAM_ISP, "Start success for ctx id:%d", ctx->ctx_index); return 0; err: stop_hw_method.hw_stop_cmd = CAM_CSID_HALT_IMMEDIATELY; @@ -2418,7 +2419,7 @@ static int cam_isp_blob_clock_update( ctx = prepare->ctxt_to_hw_map; - CAM_DBG(CAM_ISP, + CAM_DBG(CAM_PERF, "usage=%u left_clk= %lu right_clk=%lu", clock_config->usage_type, clock_config->left_pix_hz, @@ -2571,7 +2572,8 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, return -EINVAL; } - CAM_DBG(CAM_ISP, "enter"); + CAM_DBG(CAM_REQ, "Enter for req_id %lld", + prepare->packet->header.request_id); prepare_hw_data = (struct cam_isp_prepare_hw_update_data *) prepare->priv; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index 1444911b7a0d..abc6bb0a6db8 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -469,11 +469,12 @@ int cam_isp_add_io_buffers( for (i = 0; i < prepare->packet->num_io_configs; i++) { CAM_DBG(CAM_ISP, "======= io config idx %d ============", i); - CAM_DBG(CAM_ISP, "i %d resource_type:%d fence:%d", - i, io_cfg[i].resource_type, io_cfg[i].fence); - CAM_DBG(CAM_ISP, "format: %d", io_cfg[i].format); - CAM_DBG(CAM_ISP, "direction %d", + CAM_DBG(CAM_REQ, + "i %d req_id %llu resource_type:%d fence:%d direction %d", + i, prepare->packet->header.request_id, + io_cfg[i].resource_type, io_cfg[i].fence, io_cfg[i].direction); + CAM_DBG(CAM_ISP, "format: %d", io_cfg[i].format); if (io_cfg[i].direction == CAM_BUF_OUTPUT) { res_id_out = io_cfg[i].resource_type & 0xFF; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c index 931574afa1b3..e418fa97081d 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c @@ -141,21 +141,21 @@ int cam_irq_controller_init(const char *name, if (!register_info->num_registers || !register_info->irq_reg_set || !name || !mem_base) { - CAM_ERR(CAM_ISP, "Invalid parameters"); + CAM_ERR(CAM_IRQ_CTRL, "Invalid parameters"); rc = -EINVAL; return rc; } controller = kzalloc(sizeof(struct cam_irq_controller), GFP_KERNEL); if (!controller) { - CAM_DBG(CAM_ISP, "Failed to allocate IRQ Controller"); + CAM_DBG(CAM_IRQ_CTRL, "Failed to allocate IRQ Controller"); return -ENOMEM; } controller->irq_register_arr = kzalloc(register_info->num_registers * sizeof(struct cam_irq_register_obj), GFP_KERNEL); if (!controller->irq_register_arr) { - CAM_DBG(CAM_ISP, "Failed to allocate IRQ register Arr"); + CAM_DBG(CAM_IRQ_CTRL, "Failed to allocate IRQ register Arr"); rc = -ENOMEM; goto reg_alloc_error; } @@ -163,7 +163,7 @@ int cam_irq_controller_init(const char *name, controller->irq_status_arr = kzalloc(register_info->num_registers * sizeof(uint32_t), GFP_KERNEL); if (!controller->irq_status_arr) { - CAM_DBG(CAM_ISP, "Failed to allocate IRQ status Arr"); + CAM_DBG(CAM_IRQ_CTRL, "Failed to allocate IRQ status Arr"); rc = -ENOMEM; goto status_alloc_error; } @@ -172,14 +172,16 @@ int cam_irq_controller_init(const char *name, kzalloc(register_info->num_registers * sizeof(uint32_t), GFP_KERNEL); if (!controller->th_payload.evt_status_arr) { - CAM_DBG(CAM_ISP, "Failed to allocate BH payload bit mask Arr"); + CAM_DBG(CAM_IRQ_CTRL, + "Failed to allocate BH payload bit mask Arr"); rc = -ENOMEM; goto evt_mask_alloc_error; } controller->name = name; - CAM_DBG(CAM_ISP, "num_registers: %d", register_info->num_registers); + CAM_DBG(CAM_IRQ_CTRL, "num_registers: %d", + register_info->num_registers); for (i = 0; i < register_info->num_registers; i++) { controller->irq_register_arr[i].index = i; controller->irq_register_arr[i].mask_reg_offset = @@ -188,11 +190,11 @@ int cam_irq_controller_init(const char *name, register_info->irq_reg_set[i].clear_reg_offset; controller->irq_register_arr[i].status_reg_offset = register_info->irq_reg_set[i].status_reg_offset; - CAM_DBG(CAM_ISP, "i %d mask_reg_offset: 0x%x", i, + CAM_DBG(CAM_IRQ_CTRL, "i %d mask_reg_offset: 0x%x", i, controller->irq_register_arr[i].mask_reg_offset); - CAM_DBG(CAM_ISP, "i %d clear_reg_offset: 0x%x", i, + CAM_DBG(CAM_IRQ_CTRL, "i %d clear_reg_offset: 0x%x", i, controller->irq_register_arr[i].clear_reg_offset); - CAM_DBG(CAM_ISP, "i %d status_reg_offset: 0x%x", i, + CAM_DBG(CAM_IRQ_CTRL, "i %d status_reg_offset: 0x%x", i, controller->irq_register_arr[i].status_reg_offset); } controller->num_registers = register_info->num_registers; @@ -200,11 +202,12 @@ int cam_irq_controller_init(const char *name, controller->global_clear_offset = register_info->global_clear_offset; controller->mem_base = mem_base; - CAM_DBG(CAM_ISP, "global_clear_bitmask: 0x%x", + CAM_DBG(CAM_IRQ_CTRL, "global_clear_bitmask: 0x%x", controller->global_clear_bitmask); - CAM_DBG(CAM_ISP, "global_clear_offset: 0x%x", + CAM_DBG(CAM_IRQ_CTRL, "global_clear_offset: 0x%x", controller->global_clear_offset); - CAM_DBG(CAM_ISP, "mem_base: %pK", (void __iomem *)controller->mem_base); + CAM_DBG(CAM_IRQ_CTRL, "mem_base: %pK", + (void __iomem *)controller->mem_base); INIT_LIST_HEAD(&controller->evt_handler_list_head); for (i = 0; i < CAM_IRQ_PRIORITY_MAX; i++) @@ -245,20 +248,20 @@ int cam_irq_controller_subscribe_irq(void *irq_controller, bool need_lock; if (!controller || !handler_priv || !evt_bit_mask_arr) { - CAM_ERR(CAM_ISP, + CAM_ERR(CAM_IRQ_CTRL, "Inval params: ctlr=%pK hdl_priv=%pK bit_mask_arr=%pK", controller, handler_priv, evt_bit_mask_arr); return -EINVAL; } if (!top_half_handler) { - CAM_ERR(CAM_ISP, "Missing top half handler"); + CAM_ERR(CAM_IRQ_CTRL, "Missing top half handler"); return -EINVAL; } if (bottom_half_handler && (!bottom_half || !irq_bh_api)) { - CAM_ERR(CAM_ISP, + CAM_ERR(CAM_IRQ_CTRL, "Invalid params: bh_handler=%pK bh=%pK bh_enq_f=%pK", bottom_half_handler, bottom_half, @@ -270,7 +273,7 @@ int cam_irq_controller_subscribe_irq(void *irq_controller, (!irq_bh_api->bottom_half_enqueue_func || !irq_bh_api->get_bh_payload_func || !irq_bh_api->put_bh_payload_func)) { - CAM_ERR(CAM_ISP, + CAM_ERR(CAM_IRQ_CTRL, "Invalid: enqueue_func=%pK get_bh=%pK put_bh=%pK", irq_bh_api->bottom_half_enqueue_func, irq_bh_api->get_bh_payload_func, @@ -279,21 +282,21 @@ int cam_irq_controller_subscribe_irq(void *irq_controller, } if (priority >= CAM_IRQ_PRIORITY_MAX) { - CAM_ERR(CAM_ISP, "Invalid priority=%u, max=%u", priority, + CAM_ERR(CAM_IRQ_CTRL, "Invalid priority=%u, max=%u", priority, CAM_IRQ_PRIORITY_MAX); return -EINVAL; } evt_handler = kzalloc(sizeof(struct cam_irq_evt_handler), GFP_KERNEL); if (!evt_handler) { - CAM_DBG(CAM_ISP, "Error allocating hlist_node"); + CAM_DBG(CAM_IRQ_CTRL, "Error allocating hlist_node"); return -ENOMEM; } evt_handler->evt_bit_mask_arr = kzalloc(sizeof(uint32_t) * controller->num_registers, GFP_KERNEL); if (!evt_handler->evt_bit_mask_arr) { - CAM_DBG(CAM_ISP, "Error allocating hlist_node"); + CAM_DBG(CAM_IRQ_CTRL, "Error allocating hlist_node"); rc = -ENOMEM; goto free_evt_handler; } @@ -374,7 +377,7 @@ int cam_irq_controller_enable_irq(void *irq_controller, uint32_t handle) list_for_each_entry_safe(evt_handler, evt_handler_temp, &controller->evt_handler_list_head, list_node) { if (evt_handler->index == handle) { - CAM_DBG(CAM_ISP, "enable item %d", handle); + CAM_DBG(CAM_IRQ_CTRL, "enable item %d", handle); found = 1; rc = 0; break; @@ -430,7 +433,7 @@ int cam_irq_controller_disable_irq(void *irq_controller, uint32_t handle) list_for_each_entry_safe(evt_handler, evt_handler_temp, &controller->evt_handler_list_head, list_node) { if (evt_handler->index == handle) { - CAM_DBG(CAM_ISP, "disable item %d", handle); + CAM_DBG(CAM_IRQ_CTRL, "disable item %d", handle); found = 1; rc = 0; break; @@ -451,13 +454,13 @@ int cam_irq_controller_disable_irq(void *irq_controller, uint32_t handle) irq_mask = cam_io_r_mb(controller->mem_base + irq_register->mask_reg_offset); - CAM_DBG(CAM_ISP, "irq_mask 0x%x before disable 0x%x", + CAM_DBG(CAM_IRQ_CTRL, "irq_mask 0x%x before disable 0x%x", irq_register->mask_reg_offset, irq_mask); irq_mask &= ~(evt_handler->evt_bit_mask_arr[i]); cam_io_w_mb(irq_mask, controller->mem_base + irq_register->mask_reg_offset); - CAM_DBG(CAM_ISP, "irq_mask 0x%x after disable 0x%x", + CAM_DBG(CAM_IRQ_CTRL, "irq_mask 0x%x after disable 0x%x", irq_register->mask_reg_offset, irq_mask); /* Clear the IRQ bits of this handler */ @@ -499,7 +502,7 @@ int cam_irq_controller_unsubscribe_irq(void *irq_controller, list_for_each_entry_safe(evt_handler, evt_handler_temp, &controller->evt_handler_list_head, list_node) { if (evt_handler->index == handle) { - CAM_DBG(CAM_ISP, "unsubscribe item %d", handle); + CAM_DBG(CAM_IRQ_CTRL, "unsubscribe item %d", handle); list_del_init(&evt_handler->list_node); list_del_init(&evt_handler->th_list_node); found = 1; @@ -583,7 +586,7 @@ static void cam_irq_controller_th_processing( void *bh_cmd = NULL; struct cam_irq_bh_api *irq_bh_api = NULL; - CAM_DBG(CAM_ISP, "Enter"); + CAM_DBG(CAM_IRQ_CTRL, "Enter"); if (list_empty(th_list_head)) return; @@ -595,7 +598,7 @@ static void cam_irq_controller_th_processing( if (!is_irq_match) continue; - CAM_DBG(CAM_ISP, "match found"); + CAM_DBG(CAM_IRQ_CTRL, "match found"); cam_irq_th_payload_init(th_payload); th_payload->handler_priv = evt_handler->handler_priv; @@ -635,7 +638,7 @@ static void cam_irq_controller_th_processing( } if (evt_handler->bottom_half_handler) { - CAM_DBG(CAM_ISP, "Enqueuing bottom half for %s", + CAM_DBG(CAM_IRQ_CTRL, "Enqueuing bottom half for %s", controller->name); irq_bh_api->bottom_half_enqueue_func( evt_handler->bottom_half, @@ -646,7 +649,7 @@ static void cam_irq_controller_th_processing( } } - CAM_DBG(CAM_ISP, "Exit"); + CAM_DBG(CAM_IRQ_CTRL, "Exit"); } irqreturn_t cam_irq_controller_clear_and_mask(int irq_num, void *priv) @@ -687,7 +690,7 @@ irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv) if (!controller) return IRQ_NONE; - CAM_DBG(CAM_ISP, "locking controller %pK name %s lock %pK", + CAM_DBG(CAM_IRQ_CTRL, "locking controller %pK name %s lock %pK", controller, controller->name, &controller->lock); spin_lock(&controller->lock); for (i = 0; i < controller->num_registers; i++) { @@ -698,36 +701,36 @@ irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv) cam_io_w_mb(controller->irq_status_arr[i], controller->mem_base + controller->irq_register_arr[i].clear_reg_offset); - CAM_DBG(CAM_ISP, "Read irq status%d (0x%x) = 0x%x", i, + CAM_DBG(CAM_IRQ_CTRL, "Read irq status%d (0x%x) = 0x%x", i, controller->irq_register_arr[i].status_reg_offset, controller->irq_status_arr[i]); for (j = 0; j < CAM_IRQ_PRIORITY_MAX; j++) { if (irq_register->top_half_enable_mask[j] & controller->irq_status_arr[i]) need_th_processing[j] = true; - CAM_DBG(CAM_ISP, + CAM_DBG(CAM_IRQ_CTRL, "i %d j %d need_th_processing = %d", i, j, need_th_processing[j]); } } - CAM_DBG(CAM_ISP, "Status Registers read Successful"); + CAM_DBG(CAM_IRQ_CTRL, "Status Registers read Successful"); if (controller->global_clear_offset) cam_io_w_mb(controller->global_clear_bitmask, controller->mem_base + controller->global_clear_offset); - CAM_DBG(CAM_ISP, "Status Clear done"); + CAM_DBG(CAM_IRQ_CTRL, "Status Clear done"); for (i = 0; i < CAM_IRQ_PRIORITY_MAX; i++) { if (need_th_processing[i]) { - CAM_DBG(CAM_ISP, "Invoke TH processing"); + CAM_DBG(CAM_IRQ_CTRL, "Invoke TH processing"); cam_irq_controller_th_processing(controller, &controller->th_list_head[i]); } } spin_unlock(&controller->lock); - CAM_DBG(CAM_ISP, "unlocked controller %pK name %s lock %pK", + CAM_DBG(CAM_IRQ_CTRL, "unlocked controller %pK name %s lock %pK", controller, controller->name, &controller->lock); return IRQ_HANDLED; 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 afe496b398b5..67b572e039d8 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 @@ -1132,7 +1132,8 @@ static int cam_vfe_bus_stop_wm(struct cam_isp_resource_node *wm_res) /* Disble WM */ /* Disable all register access, reply on global reset */ - CAM_DBG(CAM_ISP, "irq_enabled %d", rsrc_data->irq_enabled); + CAM_DBG(CAM_ISP, "WM res %d irq_enabled %d", + rsrc_data->index, rsrc_data->irq_enabled); /* Unsubscribe IRQ */ if (rsrc_data->irq_enabled) rc = cam_irq_controller_unsubscribe_irq( diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c index 93e4249cc427..d192018bf2f2 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c @@ -30,12 +30,12 @@ static int cam_mem_util_map_cpu_va(struct ion_handle *hdl, { *vaddr = (uintptr_t)ion_map_kernel(tbl.client, hdl); if (IS_ERR_OR_NULL((void *)*vaddr)) { - CAM_ERR(CAM_CRM, "kernel map fail"); + CAM_ERR(CAM_MEM, "kernel map fail"); return -ENOSPC; } if (ion_handle_get_size(tbl.client, hdl, len)) { - CAM_ERR(CAM_CRM, "kernel get len failed"); + CAM_ERR(CAM_MEM, "kernel get len failed"); ion_unmap_kernel(tbl.client, hdl); return -ENOSPC; } @@ -65,7 +65,7 @@ static int cam_mem_util_client_create(void) tbl.client = msm_ion_client_create("camera_global_pool"); if (IS_ERR_OR_NULL(tbl.client)) { - CAM_ERR(CAM_CRM, "fail to create client"); + CAM_ERR(CAM_MEM, "fail to create client"); rc = -EINVAL; } @@ -88,7 +88,7 @@ int cam_mem_mgr_init(void) rc = cam_mem_util_client_create(); if (rc < 0) { - CAM_ERR(CAM_CRM, "fail to create ion client"); + CAM_ERR(CAM_MEM, "fail to create ion client"); goto client_fail; } @@ -175,7 +175,7 @@ int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle, iova_ptr, len_ptr); if (rc < 0) - CAM_ERR(CAM_CRM, "fail to get buf hdl :%d", buf_handle); + CAM_ERR(CAM_MEM, "fail to get buf hdl :%d", buf_handle); handle_mismatch: mutex_unlock(&tbl.bufq[idx].q_lock); @@ -209,7 +209,7 @@ int cam_mem_get_cpu_buf(int32_t buf_handle, uint64_t *vaddr_ptr, size_t *len) ion_hdl = tbl.bufq[idx].i_hdl; if (!ion_hdl) { - CAM_ERR(CAM_CRM, "Invalid ION handle"); + CAM_ERR(CAM_MEM, "Invalid ION handle"); rc = -EINVAL; goto exit_func; } @@ -264,7 +264,7 @@ int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd) rc = ion_handle_get_flags(tbl.client, tbl.bufq[idx].i_hdl, &ion_flag); if (rc) { - CAM_ERR(CAM_CRM, "cache get flags failed %d", rc); + CAM_ERR(CAM_MEM, "cache get flags failed %d", rc); goto fail; } @@ -280,7 +280,7 @@ int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd) ion_cache_ops = ION_IOC_CLEAN_INV_CACHES; break; default: - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "invalid cache ops :%d", cmd->mem_cache_ops); rc = -EINVAL; goto fail; @@ -292,7 +292,7 @@ int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd) tbl.bufq[idx].len, ion_cache_ops); if (rc) - CAM_ERR(CAM_CRM, "cache operation failed %d", rc); + CAM_ERR(CAM_MEM, "cache operation failed %d", rc); } fail: mutex_unlock(&tbl.bufq[idx].q_lock); @@ -310,7 +310,7 @@ static int cam_mem_util_get_dma_buf(size_t len, int rc = 0; if (!hdl || !buf) { - CAM_ERR(CAM_CRM, "Invalid params"); + CAM_ERR(CAM_MEM, "Invalid params"); return -EINVAL; } @@ -320,7 +320,7 @@ static int cam_mem_util_get_dma_buf(size_t len, *buf = ion_share_dma_buf(tbl.client, *hdl); if (IS_ERR_OR_NULL(*buf)) { - CAM_ERR(CAM_CRM, "get dma buf fail"); + CAM_ERR(CAM_MEM, "get dma buf fail"); rc = -EINVAL; goto get_buf_fail; } @@ -343,7 +343,7 @@ static int cam_mem_util_get_dma_buf_fd(size_t len, int rc = 0; if (!hdl || !fd) { - CAM_ERR(CAM_CRM, "Invalid params"); + CAM_ERR(CAM_MEM, "Invalid params"); return -EINVAL; } @@ -353,7 +353,7 @@ static int cam_mem_util_get_dma_buf_fd(size_t len, *fd = ion_share_dma_buf_fd(tbl.client, *hdl); if (*fd < 0) { - CAM_ERR(CAM_CRM, "get fd fail"); + CAM_ERR(CAM_MEM, "get fd fail"); rc = -EINVAL; goto get_fd_fail; } @@ -400,19 +400,19 @@ static int cam_mem_util_ion_alloc(struct cam_mem_mgr_alloc_cmd *cmd, static int cam_mem_util_check_flags(struct cam_mem_mgr_alloc_cmd *cmd) { if (!cmd->flags) { - CAM_ERR(CAM_CRM, "Invalid flags"); + CAM_ERR(CAM_MEM, "Invalid flags"); return -EINVAL; } if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) { - CAM_ERR(CAM_CRM, "Num of mmu hdl exceeded maximum(%d)", + CAM_ERR(CAM_MEM, "Num of mmu hdl exceeded maximum(%d)", CAM_MEM_MMU_MAX_HANDLE); return -EINVAL; } if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE && cmd->flags & CAM_MEM_FLAG_KMD_ACCESS) { - CAM_ERR(CAM_CRM, "Kernel mapping in secure mode not allowed"); + CAM_ERR(CAM_MEM, "Kernel mapping in secure mode not allowed"); return -EINVAL; } @@ -422,24 +422,24 @@ static int cam_mem_util_check_flags(struct cam_mem_mgr_alloc_cmd *cmd) static int cam_mem_util_check_map_flags(struct cam_mem_mgr_map_cmd *cmd) { if (!cmd->flags) { - CAM_ERR(CAM_CRM, "Invalid flags"); + CAM_ERR(CAM_MEM, "Invalid flags"); return -EINVAL; } if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) { - CAM_ERR(CAM_CRM, "Num of mmu hdl exceeded maximum(%d)", + CAM_ERR(CAM_MEM, "Num of mmu hdl exceeded maximum(%d)", CAM_MEM_MMU_MAX_HANDLE); return -EINVAL; } if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE && cmd->flags & CAM_MEM_FLAG_KMD_ACCESS) { - CAM_ERR(CAM_CRM, "Kernel mapping in secure mode not allowed"); + CAM_ERR(CAM_MEM, "Kernel mapping in secure mode not allowed"); return -EINVAL; } if (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Shared memory buffers are not allowed to be mapped"); return -EINVAL; } @@ -460,7 +460,7 @@ static int cam_mem_util_map_hw_va(uint32_t flags, int dir = cam_mem_util_get_dma_dir(flags); if (dir < 0) { - CAM_ERR(CAM_CRM, "fail to map DMA direction"); + CAM_ERR(CAM_MEM, "fail to map DMA direction"); return dir; } @@ -474,7 +474,7 @@ static int cam_mem_util_map_hw_va(uint32_t flags, len); if (rc < 0) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Failed to securely map to smmu"); goto multi_map_fail; } @@ -489,7 +489,7 @@ static int cam_mem_util_map_hw_va(uint32_t flags, region); if (rc < 0) { - CAM_ERR(CAM_CRM, "Failed to map to smmu"); + CAM_ERR(CAM_MEM, "Failed to map to smmu"); goto multi_map_fail; } } @@ -519,14 +519,14 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) size_t len; if (!cmd) { - CAM_ERR(CAM_CRM, " Invalid argument"); + CAM_ERR(CAM_MEM, " Invalid argument"); return -EINVAL; } len = cmd->len; rc = cam_mem_util_check_flags(cmd); if (rc) { - CAM_ERR(CAM_CRM, "Invalid flags: flags = %X", cmd->flags); + CAM_ERR(CAM_MEM, "Invalid flags: flags = %X", cmd->flags); return rc; } @@ -534,12 +534,13 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) &ion_hdl, &ion_fd); if (rc) { - CAM_ERR(CAM_CRM, "Ion allocation failed"); + CAM_ERR(CAM_MEM, "Ion allocation failed"); return rc; } idx = cam_mem_get_slot(); if (idx < 0) { + CAM_ERR(CAM_MEM, "Failed to get slot"); rc = -ENOMEM; goto slot_fail; } @@ -594,7 +595,7 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) cmd->out.fd = tbl.bufq[idx].fd; cmd->out.vaddr = 0; - CAM_DBG(CAM_CRM, "buf handle: %x, fd: %d, len: %zu", + CAM_DBG(CAM_MEM, "buf handle: %x, fd: %d, len: %zu", cmd->out.buf_handle, cmd->out.fd, tbl.bufq[idx].len); @@ -616,7 +617,7 @@ int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) size_t len = 0; if (!cmd || (cmd->fd < 0)) { - CAM_ERR(CAM_CRM, "Invalid argument"); + CAM_ERR(CAM_MEM, "Invalid argument"); return -EINVAL; } @@ -625,13 +626,13 @@ int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) rc = cam_mem_util_check_map_flags(cmd); if (rc) { - CAM_ERR(CAM_CRM, "Invalid flags: flags = %X", cmd->flags); + CAM_ERR(CAM_MEM, "Invalid flags: flags = %X", cmd->flags); return rc; } ion_hdl = ion_import_dma_buf_fd(tbl.client, cmd->fd); if (IS_ERR_OR_NULL((void *)(ion_hdl))) { - CAM_ERR(CAM_CRM, "Failed to import ion fd"); + CAM_ERR(CAM_MEM, "Failed to import ion fd"); return -EINVAL; } @@ -702,7 +703,7 @@ static int cam_mem_util_unmap_hw_va(int32_t idx, int rc = -EINVAL; if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { - CAM_ERR(CAM_CRM, "Incorrect index"); + CAM_ERR(CAM_MEM, "Incorrect index"); return rc; } @@ -726,7 +727,7 @@ static int cam_mem_util_unmap_hw_va(int32_t idx, rc = cam_smmu_unmap_kernel_iova(mmu_hdls[i], tbl.bufq[idx].dma_buf, region); } else { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "invalid caller for unmapping : %d", client); rc = -EINVAL; @@ -739,7 +740,7 @@ static int cam_mem_util_unmap_hw_va(int32_t idx, return rc; unmap_end: - CAM_ERR(CAM_CRM, "unmapping failed"); + CAM_ERR(CAM_MEM, "unmapping failed"); return rc; } @@ -762,11 +763,11 @@ static int cam_mem_mgr_cleanup_table(void) mutex_lock(&tbl.m_lock); for (i = 1; i < CAM_MEM_BUFQ_MAX; i++) { if (!tbl.bufq[i].active) { - CAM_DBG(CAM_CRM, + CAM_DBG(CAM_MEM, "Buffer inactive at idx=%d, continuing", i); continue; } else { - CAM_DBG(CAM_CRM, + CAM_DBG(CAM_MEM, "Active buffer at idx=%d, possible leak needs unmapping", i); cam_mem_mgr_unmap_active_buf(i); @@ -817,16 +818,16 @@ static int cam_mem_util_unmap(int32_t idx, enum cam_smmu_region_id region = CAM_SMMU_REGION_SHARED; if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { - CAM_ERR(CAM_CRM, "Incorrect index"); + CAM_ERR(CAM_MEM, "Incorrect index"); return -EINVAL; } - CAM_DBG(CAM_CRM, "Flags = %X idx %d", tbl.bufq[idx].flags, idx); + CAM_DBG(CAM_MEM, "Flags = %X idx %d", tbl.bufq[idx].flags, idx); mutex_lock(&tbl.m_lock); if ((!tbl.bufq[idx].active) && (tbl.bufq[idx].vaddr) == 0) { - CAM_WARN(CAM_CRM, "Buffer at idx=%d is already unmapped,", + CAM_WARN(CAM_MEM, "Buffer at idx=%d is already unmapped,", idx); mutex_unlock(&tbl.m_lock); return 0; @@ -858,7 +859,7 @@ static int cam_mem_util_unmap(int32_t idx, memset(tbl.bufq[idx].hdls, 0, sizeof(int32_t) * CAM_MEM_MMU_MAX_HANDLE); - CAM_DBG(CAM_CRM, + CAM_DBG(CAM_MEM, "Ion handle at idx = %d freeing = %pK, fd = %d, imported %d dma_buf %pK", idx, tbl.bufq[idx].i_hdl, tbl.bufq[idx].fd, tbl.bufq[idx].is_imported, @@ -889,28 +890,28 @@ int cam_mem_mgr_release(struct cam_mem_mgr_release_cmd *cmd) int rc; if (!cmd) { - CAM_ERR(CAM_CRM, "Invalid argument"); + CAM_ERR(CAM_MEM, "Invalid argument"); return -EINVAL; } idx = CAM_MEM_MGR_GET_HDL_IDX(cmd->buf_handle); if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { - CAM_ERR(CAM_CRM, "Incorrect index extracted from mem handle"); + CAM_ERR(CAM_MEM, "Incorrect index extracted from mem handle"); return -EINVAL; } if (!tbl.bufq[idx].active) { - CAM_ERR(CAM_CRM, "Released buffer state should be active"); + CAM_ERR(CAM_MEM, "Released buffer state should be active"); return -EINVAL; } if (tbl.bufq[idx].buf_handle != cmd->buf_handle) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Released buf handle not matching within table"); return -EINVAL; } - CAM_DBG(CAM_CRM, "Releasing hdl = %u", cmd->buf_handle); + CAM_DBG(CAM_MEM, "Releasing hdl = %u", cmd->buf_handle); rc = cam_mem_util_unmap(idx, CAM_SMMU_MAPPING_USER); return rc; @@ -936,14 +937,14 @@ int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp, enum cam_smmu_region_id region = CAM_SMMU_REGION_SHARED; if (!inp || !out) { - CAM_ERR(CAM_CRM, "Invalid params"); + CAM_ERR(CAM_MEM, "Invalid params"); return -EINVAL; } if (!(inp->flags & CAM_MEM_FLAG_HW_READ_WRITE || inp->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS || inp->flags & CAM_MEM_FLAG_CACHE)) { - CAM_ERR(CAM_CRM, "Invalid flags for request mem"); + CAM_ERR(CAM_MEM, "Invalid flags for request mem"); return -EINVAL; } @@ -963,20 +964,20 @@ int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp, &buf); if (rc) { - CAM_ERR(CAM_CRM, "ION alloc failed for shared buffer"); + CAM_ERR(CAM_MEM, "ION alloc failed for shared buffer"); goto ion_fail; } else { - CAM_DBG(CAM_CRM, "Got dma_buf = %pK, hdl = %pK", buf, hdl); + CAM_DBG(CAM_MEM, "Got dma_buf = %pK, hdl = %pK", buf, hdl); } rc = cam_mem_util_map_cpu_va(hdl, &kvaddr, &request_len); if (rc) { - CAM_ERR(CAM_CRM, "Failed to get kernel vaddr"); + CAM_ERR(CAM_MEM, "Failed to get kernel vaddr"); goto map_fail; } if (!inp->smmu_hdl) { - CAM_ERR(CAM_CRM, "Invalid SMMU handle"); + CAM_ERR(CAM_MEM, "Invalid SMMU handle"); rc = -EINVAL; goto smmu_fail; } @@ -997,7 +998,7 @@ int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp, region); if (rc < 0) { - CAM_ERR(CAM_CRM, "SMMU mapping failed"); + CAM_ERR(CAM_MEM, "SMMU mapping failed"); goto smmu_fail; } @@ -1054,32 +1055,32 @@ int cam_mem_mgr_release_mem(struct cam_mem_mgr_memory_desc *inp) int rc; if (!inp) { - CAM_ERR(CAM_CRM, "Invalid argument"); + CAM_ERR(CAM_MEM, "Invalid argument"); return -EINVAL; } idx = CAM_MEM_MGR_GET_HDL_IDX(inp->mem_handle); if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { - CAM_ERR(CAM_CRM, "Incorrect index extracted from mem handle"); + CAM_ERR(CAM_MEM, "Incorrect index extracted from mem handle"); return -EINVAL; } if (!tbl.bufq[idx].active) { if (tbl.bufq[idx].vaddr == 0) { - CAM_ERR(CAM_CRM, "buffer is released already"); + CAM_ERR(CAM_MEM, "buffer is released already"); return 0; } - CAM_ERR(CAM_CRM, "Released buffer state should be active"); + CAM_ERR(CAM_MEM, "Released buffer state should be active"); return -EINVAL; } if (tbl.bufq[idx].buf_handle != inp->mem_handle) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Released buf handle not matching within table"); return -EINVAL; } - CAM_DBG(CAM_CRM, "Releasing hdl = %X", inp->mem_handle); + CAM_DBG(CAM_MEM, "Releasing hdl = %X", inp->mem_handle); rc = cam_mem_util_unmap(idx, CAM_SMMU_MAPPING_KERNEL); return rc; @@ -1103,17 +1104,17 @@ int cam_mem_mgr_reserve_memory_region(struct cam_mem_mgr_request_desc *inp, int32_t num_hdl = 0; if (!inp || !out) { - CAM_ERR(CAM_CRM, "Invalid param(s)"); + CAM_ERR(CAM_MEM, "Invalid param(s)"); return -EINVAL; } if (!inp->smmu_hdl) { - CAM_ERR(CAM_CRM, "Invalid SMMU handle"); + CAM_ERR(CAM_MEM, "Invalid SMMU handle"); return -EINVAL; } if (region != CAM_SMMU_REGION_SECHEAP) { - CAM_ERR(CAM_CRM, "Only secondary heap supported"); + CAM_ERR(CAM_MEM, "Only secondary heap supported"); return -EINVAL; } @@ -1127,10 +1128,10 @@ int cam_mem_mgr_reserve_memory_region(struct cam_mem_mgr_request_desc *inp, &buf); if (rc) { - CAM_ERR(CAM_CRM, "ION alloc failed for sec heap buffer"); + CAM_ERR(CAM_MEM, "ION alloc failed for sec heap buffer"); goto ion_fail; } else { - CAM_DBG(CAM_CRM, "Got dma_buf = %pK, hdl = %pK", buf, hdl); + CAM_DBG(CAM_MEM, "Got dma_buf = %pK, hdl = %pK", buf, hdl); } rc = cam_smmu_reserve_sec_heap(inp->smmu_hdl, @@ -1139,7 +1140,7 @@ int cam_mem_mgr_reserve_memory_region(struct cam_mem_mgr_request_desc *inp, &request_len); if (rc) { - CAM_ERR(CAM_CRM, "Reserving secondary heap failed"); + CAM_ERR(CAM_MEM, "Reserving secondary heap failed"); goto smmu_fail; } @@ -1195,38 +1196,38 @@ int cam_mem_mgr_free_memory_region(struct cam_mem_mgr_memory_desc *inp) int32_t smmu_hdl; if (!inp) { - CAM_ERR(CAM_CRM, "Invalid argument"); + CAM_ERR(CAM_MEM, "Invalid argument"); return -EINVAL; } if (inp->region != CAM_SMMU_REGION_SECHEAP) { - CAM_ERR(CAM_CRM, "Only secondary heap supported"); + CAM_ERR(CAM_MEM, "Only secondary heap supported"); return -EINVAL; } idx = CAM_MEM_MGR_GET_HDL_IDX(inp->mem_handle); if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { - CAM_ERR(CAM_CRM, "Incorrect index extracted from mem handle"); + CAM_ERR(CAM_MEM, "Incorrect index extracted from mem handle"); return -EINVAL; } if (!tbl.bufq[idx].active) { if (tbl.bufq[idx].vaddr == 0) { - CAM_ERR(CAM_CRM, "buffer is released already"); + CAM_ERR(CAM_MEM, "buffer is released already"); return 0; } - CAM_ERR(CAM_CRM, "Released buffer state should be active"); + CAM_ERR(CAM_MEM, "Released buffer state should be active"); return -EINVAL; } if (tbl.bufq[idx].buf_handle != inp->mem_handle) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Released buf handle not matching within table"); return -EINVAL; } if (tbl.bufq[idx].num_hdl != 1) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Sec heap region should have only one smmu hdl"); return -ENODEV; } @@ -1234,22 +1235,22 @@ int cam_mem_mgr_free_memory_region(struct cam_mem_mgr_memory_desc *inp) memcpy(&smmu_hdl, tbl.bufq[idx].hdls, sizeof(int32_t)); if (inp->smmu_hdl != smmu_hdl) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Passed SMMU handle doesn't match with internal hdl"); return -ENODEV; } rc = cam_smmu_release_sec_heap(inp->smmu_hdl); if (rc) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Sec heap region release failed"); return -ENODEV; } - CAM_DBG(CAM_CRM, "Releasing hdl = %X", inp->mem_handle); + CAM_DBG(CAM_MEM, "Releasing hdl = %X", inp->mem_handle); rc = cam_mem_util_unmap(idx, CAM_SMMU_MAPPING_KERNEL); if (rc) - CAM_ERR(CAM_CRM, "unmapping secondary heap failed"); + CAM_ERR(CAM_MEM, "unmapping secondary heap failed"); return rc; } 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 f62f279a21bd..346cd5678379 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 @@ -482,7 +482,8 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, trace_cam_req_mgr_apply_request(link, &apply_req, dev); apply_req.trigger_point = trigger; - CAM_DBG(CAM_CRM, "SEND: link_hdl: %x pd %d req_id %lld", + CAM_DBG(CAM_REQ, + "SEND: link_hdl: %x pd %d req_id %lld", link->link_hdl, pd, apply_req.request_id); if (dev->ops && dev->ops->apply_req) { rc = dev->ops->apply_req(&apply_req); @@ -566,7 +567,7 @@ static int __cam_req_mgr_check_link_is_ready(struct cam_req_mgr_core_link *link, if (!rc && traverse_data.result == link->pd_mask) { CAM_DBG(CAM_CRM, - "APPLY: link_hdl= %x idx= %d, req_id= %lld :%lld :%lld", + "READY: link_hdl= %x idx= %d, req_id= %lld :%lld :%lld", link->link_hdl, idx, apply_data[2].req_id, apply_data[1].req_id, @@ -742,13 +743,13 @@ static int __cam_req_mgr_process_sync_req( sync_link = link->sync_link; req_id = slot->req_id; - CAM_DBG(CAM_CRM, + CAM_DBG(CAM_REQ, "link_hdl %x req %lld sync_self_ref %lld sof_counter %lld frame_skip_flag %d sync_link_self_ref %lld", link->link_hdl, req_id, link->sync_self_ref, link->sof_counter, link->frame_skip_flag, link->sync_link->sync_self_ref); if (sync_link->sync_link_sof_skip) { - CAM_DBG(CAM_CRM, + CAM_DBG(CAM_REQ, "No req applied on corresponding SOF on sync link: %x", sync_link->link_hdl); sync_link->sync_link_sof_skip = false; @@ -761,7 +762,7 @@ static int __cam_req_mgr_process_sync_req( __cam_req_mgr_sof_cnt_initialize(link); } else if ((link->frame_skip_flag) && (sync_link->sync_self_ref != -1)) { - CAM_DBG(CAM_CRM, "Link[%x] Req[%lld] Resetting values ", + CAM_DBG(CAM_REQ, "Link[%x] Req[%lld] Resetting values ", link->link_hdl, req_id); __cam_req_mgr_reset_sof_cnt(link); __cam_req_mgr_sof_cnt_initialize(link); @@ -771,8 +772,8 @@ static int __cam_req_mgr_process_sync_req( rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true, true); if (rc) { - CAM_DBG(CAM_CRM, - "Req: %lld [My link]not available link: %x, rc=%d", + CAM_DBG(CAM_REQ, + "Req: %lld [My link] not ready on link: %x, rc=%d", req_id, link->link_hdl, rc); link->sync_link_sof_skip = true; goto failure; @@ -794,8 +795,8 @@ static int __cam_req_mgr_process_sync_req( } if ((sync_slot_idx != -1) && - ((sync_link->req.in_q->slot[sync_slot_idx].status == - CRM_SLOT_STATUS_REQ_APPLIED) || (rc == 0))) { + ((sync_link->req.in_q->slot[sync_slot_idx].status == + CRM_SLOT_STATUS_REQ_APPLIED) || (rc == 0))) { rc = __cam_req_mgr_validate_sof_cnt(link, sync_link); if (rc) { CAM_DBG(CAM_CRM, @@ -804,7 +805,7 @@ static int __cam_req_mgr_process_sync_req( goto failure; } - CAM_DBG(CAM_CRM, + CAM_DBG(CAM_REQ, "Req: %lld ready to apply on link: %x [validation successful]", req_id, link->link_hdl); /* @@ -819,7 +820,7 @@ static int __cam_req_mgr_process_sync_req( CAM_WARN(CAM_CRM, "Unexpected return value rc: %d", rc); } } else { - CAM_DBG(CAM_CRM, + CAM_DBG(CAM_REQ, "Req: %lld [Other link] not ready to apply on link: %x", req_id, sync_link->link_hdl); rc = -EPERM; @@ -862,7 +863,7 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, * - if in applied_state, somthign wrong. * - if in no_req state, no new req */ - CAM_DBG(CAM_CRM, "SOF Req[%lld] idx %d req_status %d link_hdl %x", + CAM_DBG(CAM_REQ, "SOF Req[%lld] idx %d req_status %d link_hdl %x", in_q->slot[in_q->rd_idx].req_id, in_q->rd_idx, in_q->slot[in_q->rd_idx].status, link->link_hdl); @@ -1480,7 +1481,7 @@ int cam_req_mgr_process_flush_req(void *priv, void *data) link = (struct cam_req_mgr_core_link *)priv; task_data = (struct crm_task_payload *)data; flush_info = (struct cam_req_mgr_flush_info *)&task_data->u; - CAM_DBG(CAM_CRM, "link_hdl %x req_id %lld type %d", + CAM_DBG(CAM_REQ, "link_hdl %x req_id %lld type %d", flush_info->link_hdl, flush_info->req_id, flush_info->flush_type); @@ -1679,7 +1680,7 @@ int cam_req_mgr_process_add_req(void *priv, void *data) trace_cam_req_mgr_add_req(link, idx, add_req, tbl, device); if (slot->req_ready_map == tbl->dev_mask) { - CAM_DBG(CAM_CRM, "idx %d req_id %lld pd %d SLOT READY", + CAM_DBG(CAM_REQ, "idx %d req_id %lld pd %d SLOT READY", idx, add_req->req_id, tbl->pd); slot->state = CRM_REQ_STATE_READY; } @@ -1807,7 +1808,7 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) task_data = (struct crm_task_payload *)data; trigger_data = (struct cam_req_mgr_trigger_notify *)&task_data->u; - CAM_DBG(CAM_CRM, "link_hdl %x frame_id %lld, trigger %x\n", + CAM_DBG(CAM_REQ, "link_hdl %x frame_id %lld, trigger %x\n", trigger_data->link_hdl, trigger_data->frame_id, trigger_data->trigger); @@ -1850,6 +1851,30 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) return rc; } +/** + * __cam_req_mgr_dev_handle_to_name() + * + * @brief : Finds device name based on the device handle + * @dev_hdl : Device handle whose name is to be found + * @link : Link on which the device is connected + * @return : String containing the device name + * + */ +static const char *__cam_req_mgr_dev_handle_to_name( + int32_t dev_hdl, struct cam_req_mgr_core_link *link) +{ + struct cam_req_mgr_connected_device *dev = NULL; + int i = 0; + + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + + if (dev_hdl == dev->dev_hdl) + return dev->dev_info.name; + } + + return "Invalid dev_hdl"; +} /* Linked devices' Callback section */ @@ -1875,8 +1900,6 @@ static int cam_req_mgr_cb_add_req(struct cam_req_mgr_add_request *add_req) return -EINVAL; } - CAM_DBG(CAM_CRM, "E: dev %x dev req %lld", - add_req->dev_hdl, add_req->req_id); link = (struct cam_req_mgr_core_link *) cam_get_device_priv(add_req->link_hdl); @@ -1885,6 +1908,10 @@ static int cam_req_mgr_cb_add_req(struct cam_req_mgr_add_request *add_req) return -EINVAL; } + CAM_DBG(CAM_REQ, "dev name %s dev_hdl %d dev req %lld", + __cam_req_mgr_dev_handle_to_name(add_req->dev_hdl, link), + add_req->dev_hdl, add_req->req_id); + mutex_lock(&link->lock); spin_lock_bh(&link->link_state_spin_lock); if (link->state < CAM_CRM_LINK_STATE_READY) { @@ -2526,7 +2553,7 @@ int cam_req_mgr_schedule_request( goto end; } - CAM_DBG(CAM_CRM, "link %x req %lld, sync_mode %d", + CAM_DBG(CAM_CRM, "link 0x%x req %lld, sync_mode %d", sched_req->link_hdl, sched_req->req_id, sched_req->sync_mode); task_data.type = CRM_WORKQ_TASK_SCHED_REQ; @@ -2543,8 +2570,8 @@ int cam_req_mgr_schedule_request( rc = cam_req_mgr_process_sched_req(link, &task_data); - CAM_DBG(CAM_CRM, "DONE dev %x req %lld sync_mode %d", - sched_req->link_hdl, sched_req->req_id, sched_req->sync_mode); + CAM_DBG(CAM_REQ, "Open req %lld on link 0x%x with sync_mode %d", + sched_req->req_id, sched_req->link_hdl, sched_req->sync_mode); end: mutex_unlock(&g_crm_core_dev->crm_lock); return rc; @@ -2618,6 +2645,9 @@ int cam_req_mgr_sync_config( link2->sync_link = link1; cam_session->sync_mode = sync_info->sync_mode; + CAM_DBG(CAM_REQ, + "Sync config on link1 0x%x & link2 0x%x with sync_mode %d", + link1->link_hdl, link2->link_hdl, cam_session->sync_mode); done: mutex_unlock(&cam_session->lock); 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 f0efd4cd41cf..855ad29a6b07 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 @@ -151,7 +151,7 @@ static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl, else curr = soc_private->torch_op_current[i]; - CAM_DBG(CAM_FLASH, + CAM_DBG(CAM_PERF, "Led_Current[%d] = %d", i, curr); cam_res_mgr_led_trigger_event( flash_ctrl->torch_trigger[i], @@ -169,7 +169,7 @@ static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl, else curr = soc_private->flash_op_current[i]; - CAM_DBG(CAM_FLASH, "LED flash_current[%d]: %d", + CAM_DBG(CAM_PERF, "LED flash_current[%d]: %d", i, curr); cam_res_mgr_led_trigger_event( flash_ctrl->flash_trigger[i], @@ -338,6 +338,10 @@ int cam_flash_apply_setting(struct cam_flash_ctrl *fctrl, if (fctrl->nrt_info.cmn_attr.cmd_type == CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE) { flash_data = &fctrl->nrt_info; + CAM_DBG(CAM_REQ, + "FLASH_INIT_FIRE req_id: %u flash_opcode: %d", + req_id, flash_data->opcode); + if (flash_data->opcode == CAMERA_SENSOR_FLASH_OP_FIREHIGH) { if (fctrl->flash_state != @@ -381,6 +385,10 @@ int cam_flash_apply_setting(struct cam_flash_ctrl *fctrl, } else if (fctrl->nrt_info.cmn_attr.cmd_type == CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET) { flash_data = &fctrl->nrt_info; + CAM_DBG(CAM_REQ, + "FLASH_WIDGET req_id: %u flash_opcode: %d", + req_id, flash_data->opcode); + if (flash_data->opcode == CAMERA_SENSOR_FLASH_OP_FIRELOW) { rc = cam_flash_low(fctrl, flash_data); @@ -411,6 +419,8 @@ int cam_flash_apply_setting(struct cam_flash_ctrl *fctrl, goto nrt_del_req; } } + CAM_DBG(CAM_REQ, "FLASH_RER req_id: %u", req_id); + num_iterations = flash_data->num_iterations; for (i = 0; i < num_iterations; i++) { /* Turn On Torch */ @@ -445,6 +455,8 @@ int cam_flash_apply_setting(struct cam_flash_ctrl *fctrl, } else { frame_offset = req_id % MAX_PER_FRAME_ARRAY; flash_data = &fctrl->per_frame[frame_offset]; + CAM_DBG(CAM_REQ, "FLASH_RT req_id: %u flash_opcode: %d", + req_id, flash_data->opcode); if ((flash_data->opcode == CAMERA_SENSOR_FLASH_OP_FIREHIGH) && (flash_data->cmn_attr.is_settings_valid) && diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c index 0eb8abef28d8..1a28d52fc4fb 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -1153,7 +1153,7 @@ int32_t cam_sensor_apply_request(struct cam_req_mgr_apply_request *apply) CAM_ERR(CAM_SENSOR, "Device data is NULL"); return -EINVAL; } - CAM_DBG(CAM_SENSOR, " Req Id: %lld", apply->request_id); + CAM_DBG(CAM_REQ, " Sensor update req id: %lld", apply->request_id); trace_cam_apply_req("Sensor", apply->request_id); rc = cam_sensor_apply_settings(s_ctrl, apply->request_id, CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE); diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c index 26f2ba12be9f..4f326342e3a7 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c +++ b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundataion. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundataion. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -30,7 +30,7 @@ const char *cam_get_module_name(unsigned int module_id) name = "CAM-CORE"; break; case CAM_CRM: - name = "CAM_CRM"; + name = "CAM-CRM"; break; case CAM_CPAS: name = "CAM-CPAS"; @@ -86,6 +86,18 @@ const char *cam_get_module_name(unsigned int module_id) case CAM_OIS: name = "CAM-OIS"; break; + case CAM_IRQ_CTRL: + name = "CAM-IRQ-CTRL"; + break; + case CAM_MEM: + name = "CAM-MEM"; + break; + case CAM_PERF: + name = "CAM-PERF"; + break; + case CAM_REQ: + name = "CAM-REQ"; + break; default: name = "CAM"; break; diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h index 4e97100bfb6a..1ed7056cd09f 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h +++ b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.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,6 +35,16 @@ #define CAM_CTXT (1 << 19) #define CAM_OIS (1 << 20) #define CAM_RES (1 << 21) +#define CAM_MEM (1 << 22) + +/* CAM_IRQ_CTRL: For events in irq controller */ +#define CAM_IRQ_CTRL (1 << 23) + +/* CAM_REQ: Tracks a request submitted to KMD */ +#define CAM_REQ (1 << 24) + +/* CAM_PERF: Used for performance (clock, BW etc) logs */ +#define CAM_PERF (1 << 25) #define STR_BUFFER_MAX_LENGTH 1024 -- GitLab From 95468291f659bd28b157bb52300e3ad6f95b4e27 Mon Sep 17 00:00:00 2001 From: Vishwanath Raju K Date: Wed, 11 Jul 2018 14:32:52 +0530 Subject: [PATCH 330/604] ARM: dts: msm: update to memory map v2 for sdx24 on 512MB variant Increase modem size from 131MB to 135MB and TZ APP added with 12MB for SDX24 on 512MB variant. Change-Id: Ib5383946339af0f39bf241e2cbf4f3ab597d5ad5 Signed-off-by: Vishwanath Raju K --- .../boot/dts/qcom/sdxpoorwills-cdp-256.dtsi | 1 + .../dts/qcom/sdxpoorwills-memory-256.dtsi | 19 +++++++++++++++++++ .../boot/dts/qcom/sdxpoorwills-mtp-256.dtsi | 1 + arch/arm/boot/dts/qcom/sdxpoorwills.dtsi | 4 ++-- 4 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 arch/arm/boot/dts/qcom/sdxpoorwills-memory-256.dtsi diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi index 0f9c8bc422f6..cfc1df00ab1d 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi @@ -11,6 +11,7 @@ */ #include "sdxpoorwills-cdp.dtsi" +#include "sdxpoorwills-memory-256.dtsi" &soc { vreg_sd_mmc: vreg_sd_mmc { diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-memory-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-memory-256.dtsi new file mode 100644 index 000000000000..0c2181431c5a --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-memory-256.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. + */ + +&peripheral2_mem { + reg = <0x8fe00000 0x200000>; +}; + +&mss_mem { + reg = <0x87000000 0x8300000>; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi index 741203123468..12e78f30b45d 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi @@ -11,6 +11,7 @@ */ #include "sdxpoorwills-mtp.dtsi" +#include "sdxpoorwills-memory-256.dtsi" &soc { vreg_sd_mmc: vreg_sd_mmc { diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi index 3e318265b51d..833e897d867d 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi @@ -36,7 +36,7 @@ peripheral2_mem: peripheral2_region@8fe00000 { compatible = "removed-dma-pool"; no-map; - reg = <0x8fe00000 0x200000>; + reg = <0x8fe00000 0xe00000>; label = "peripheral2_mem"; }; @@ -65,7 +65,7 @@ mss_mem: mss_region@87400000 { compatible = "removed-dma-pool"; no-map; - reg = <0x87400000 0x8300000>; + reg = <0x87000000 0x8700000>; label = "mss_mem"; }; -- GitLab From e8aa3b401dd803e6ea444803e2e5a29efb6c06cc Mon Sep 17 00:00:00 2001 From: Houston Yaroschoff Date: Mon, 11 Jun 2018 12:39:09 +0200 Subject: [PATCH 331/604] usb: cdc_acm: Add quirk for Uniden UBC125 scanner commit 4a762569a2722b8a48066c7bacf0e1dc67d17fa1 upstream. Uniden UBC125 radio scanner has USB interface which fails to work with cdc_acm driver: usb 1-1.5: new full-speed USB device number 4 using xhci_hcd cdc_acm 1-1.5:1.0: Zero length descriptor references cdc_acm: probe of 1-1.5:1.0 failed with error -22 Adding the NO_UNION_NORMAL quirk for the device fixes the issue: usb 1-4: new full-speed USB device number 15 using xhci_hcd usb 1-4: New USB device found, idVendor=1965, idProduct=0018 usb 1-4: New USB device strings: Mfr=1, Product=2, SerialNumber=3 usb 1-4: Product: UBC125XLT usb 1-4: Manufacturer: Uniden Corp. usb 1-4: SerialNumber: 0001 cdc_acm 1-4:1.0: ttyACM0: USB ACM device `lsusb -v` of the device: Bus 001 Device 015: ID 1965:0018 Uniden Corporation Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 2 Communications bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x1965 Uniden Corporation idProduct 0x0018 bcdDevice 0.01 iManufacturer 1 Uniden Corp. iProduct 2 UBC125XLT iSerial 3 0001 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 48 bNumInterfaces 2 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 500mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 0 None iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x87 EP 7 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0008 1x 8 bytes bInterval 10 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 Unused bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Device Status: 0x0000 (Bus Powered) Signed-off-by: Houston Yaroschoff Cc: stable Acked-by: Oliver Neukum 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 fe22ac7c760a..08bef18372ea 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1712,6 +1712,9 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x11ca, 0x0201), /* VeriFone Mx870 Gadget Serial */ .driver_info = SINGLE_RX_URB, }, + { USB_DEVICE(0x1965, 0x0018), /* Uniden UBC125XLT */ + .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ + }, { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, -- GitLab From b9a0ce3b8422a1043192bf6b9ba6106a06fc0d43 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 18 Jun 2018 10:24:03 +0200 Subject: [PATCH 332/604] USB: serial: cp210x: add CESINEL device ids commit 24160628a34af962ac99f2f58e547ac3c4cbd26f upstream. Add device ids for CESINEL products. Reported-by: Carlos Barcala Lara Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 46b4dea7a0ec..b6e4d3414045 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -92,6 +92,9 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */ { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ { USB_DEVICE(0x10C4, 0x815F) }, /* Timewave HamLinkUSB */ + { USB_DEVICE(0x10C4, 0x817C) }, /* CESINEL MEDCAL N Power Quality Monitor */ + { USB_DEVICE(0x10C4, 0x817D) }, /* CESINEL MEDCAL NT Power Quality Monitor */ + { USB_DEVICE(0x10C4, 0x817E) }, /* CESINEL MEDCAL S Power Quality Monitor */ { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */ { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */ { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */ @@ -109,6 +112,9 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */ { USB_DEVICE(0x10C4, 0x8281) }, /* Nanotec Plug & Drive */ { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */ + { USB_DEVICE(0x10C4, 0x82EF) }, /* CESINEL FALCO 6105 AC Power Supply */ + { USB_DEVICE(0x10C4, 0x82F1) }, /* CESINEL MEDCAL EFD Earth Fault Detector */ + { USB_DEVICE(0x10C4, 0x82F2) }, /* CESINEL MEDCAL ST Network Analyzer */ { USB_DEVICE(0x10C4, 0x82F4) }, /* Starizona MicroTouch */ { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */ { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ @@ -121,7 +127,9 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8470) }, /* Juniper Networks BX Series System Console */ { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */ { USB_DEVICE(0x10C4, 0x84B6) }, /* Starizona Hyperion */ + { USB_DEVICE(0x10C4, 0x851E) }, /* CESINEL MEDCAL PT Network Analyzer */ { USB_DEVICE(0x10C4, 0x85A7) }, /* LifeScan OneTouch Verio IQ */ + { USB_DEVICE(0x10C4, 0x85B8) }, /* CESINEL ReCon T Energy Logger */ { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */ { USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */ { USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */ @@ -131,10 +139,13 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8857) }, /* CEL EM357 ZigBee USB Stick */ { USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */ { USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */ + { USB_DEVICE(0x10C4, 0x88FB) }, /* CESINEL MEDCAL STII Network Analyzer */ + { USB_DEVICE(0x10C4, 0x8938) }, /* CESINEL MEDCAL S II Network Analyzer */ { USB_DEVICE(0x10C4, 0x8946) }, /* Ketra N1 Wireless Interface */ { USB_DEVICE(0x10C4, 0x8962) }, /* Brim Brothers charging dock */ { USB_DEVICE(0x10C4, 0x8977) }, /* CEL MeshWorks DevKit Device */ { USB_DEVICE(0x10C4, 0x8998) }, /* KCF Technologies PRN */ + { USB_DEVICE(0x10C4, 0x89A4) }, /* CESINEL FTBC Flexible Thyristor Bridge Controller */ { USB_DEVICE(0x10C4, 0x8A2A) }, /* HubZ dual ZigBee and Z-Wave dongle */ { USB_DEVICE(0x10C4, 0x8A5E) }, /* CEL EM3588 ZigBee USB Stick Long Range */ { USB_DEVICE(0x10C4, 0x8B34) }, /* Qivicon ZigBee USB Radio Stick */ -- GitLab From 1b9f7d27057bb310e97aa5602da53cc6fff86b99 Mon Sep 17 00:00:00 2001 From: Karoly Pados Date: Sat, 9 Jun 2018 13:26:08 +0200 Subject: [PATCH 333/604] USB: serial: cp210x: add Silicon Labs IDs for Windows Update commit 2f839823382748664b643daa73f41ee0cc01ced6 upstream. Silicon Labs defines alternative VID/PID pairs for some chips that when used will automatically install drivers for Windows users without manual intervention. Unfortunately, these IDs are not recognized by the Linux module, so using these IDs improves user experience on one platform but degrades it on Linux. This patch addresses this problem. Signed-off-by: Karoly Pados Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index b6e4d3414045..6f2c77a7c08e 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -151,8 +151,11 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8B34) }, /* Qivicon ZigBee USB Radio Stick */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA63) }, /* Silicon Labs Windows Update (CP2101-4/CP2102N) */ { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */ + { USB_DEVICE(0x10C4, 0xEA7A) }, /* Silicon Labs Windows Update (CP2105) */ + { USB_DEVICE(0x10C4, 0xEA7B) }, /* Silicon Labs Windows Update (CP2108) */ { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */ { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */ { USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */ -- GitLab From 42525f7a25067b78dfa8ed4f899ebcec6636b476 Mon Sep 17 00:00:00 2001 From: William Wu Date: Mon, 21 May 2018 18:12:00 +0800 Subject: [PATCH 334/604] usb: dwc2: fix the incorrect bitmaps for the ports of multi_tt hub commit 8760675932ddb614e83702117d36ea644050c609 upstream. The dwc2_get_ls_map() use ttport to reference into the bitmap if we're on a multi_tt hub. But the bitmaps index from 0 to (hub->maxchild - 1), while the ttport index from 1 to hub->maxchild. This will cause invalid memory access when the number of ttport is hub->maxchild. Without this patch, I can easily meet a Kernel panic issue if connect a low-speed USB mouse with the max port of FE2.1 multi-tt hub (1a40:0201) on rk3288 platform. Fixes: 9f9f09b048f5 ("usb: dwc2: host: Totally redo the microframe scheduler") Cc: Reviewed-by: Douglas Anderson Acked-by: Minas Harutyunyan hminas@synopsys.com> Signed-off-by: William Wu Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/hcd_queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 13754353251f..9669184fb1fe 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -479,7 +479,7 @@ static unsigned long *dwc2_get_ls_map(struct dwc2_hsotg *hsotg, /* Get the map and adjust if this is a multi_tt hub */ map = qh->dwc_tt->periodic_bitmaps; if (qh->dwc_tt->usb_tt->multi) - map += DWC2_ELEMENTS_PER_LS_BITMAP * qh->ttport; + map += DWC2_ELEMENTS_PER_LS_BITMAP * (qh->ttport - 1); return map; } -- GitLab From 947dead99ef1f1ee0aa41b3ccde99bbd9900cd9d Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sat, 26 May 2018 09:53:13 +0900 Subject: [PATCH 335/604] n_tty: Fix stall at n_tty_receive_char_special(). commit 3d63b7e4ae0dc5e02d28ddd2fa1f945defc68d81 upstream. syzbot is reporting stalls at n_tty_receive_char_special() [1]. This is because comparison is not working as expected since ldata->read_head can change at any moment. Mitigate this by explicitly masking with buffer size when checking condition for "while" loops. [1] https://syzkaller.appspot.com/bug?id=3d7481a346958d9469bebbeb0537d5f056bdd6e8 Signed-off-by: Tetsuo Handa Reported-by: syzbot Fixes: bc5a5e3f45d04784 ("n_tty: Don't wrap input buffer indices at buffer size") Cc: stable Cc: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 1c70541a1467..a8a7a13c8683 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -126,6 +126,8 @@ struct n_tty_data { struct mutex output_lock; }; +#define MASK(x) ((x) & (N_TTY_BUF_SIZE - 1)) + static inline size_t read_cnt(struct n_tty_data *ldata) { return ldata->read_head - ldata->read_tail; @@ -980,14 +982,15 @@ static void eraser(unsigned char c, struct tty_struct *tty) } seen_alnums = 0; - while (ldata->read_head != ldata->canon_head) { + while (MASK(ldata->read_head) != MASK(ldata->canon_head)) { head = ldata->read_head; /* erase a single possibly multibyte character */ do { head--; c = read_buf(ldata, head); - } while (is_continuation(c, tty) && head != ldata->canon_head); + } while (is_continuation(c, tty) && + MASK(head) != MASK(ldata->canon_head)); /* do not partially erase */ if (is_continuation(c, tty)) @@ -1029,7 +1032,7 @@ static void eraser(unsigned char c, struct tty_struct *tty) * This info is used to go back the correct * number of columns. */ - while (tail != ldata->canon_head) { + while (MASK(tail) != MASK(ldata->canon_head)) { tail--; c = read_buf(ldata, tail); if (c == '\t') { @@ -1304,7 +1307,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c) finish_erasing(ldata); echo_char(c, tty); echo_char_raw('\n', ldata); - while (tail != ldata->read_head) { + while (MASK(tail) != MASK(ldata->read_head)) { echo_char(read_buf(ldata, tail), tty); tail++; } @@ -2413,7 +2416,7 @@ static unsigned long inq_canon(struct n_tty_data *ldata) tail = ldata->read_tail; nr = head - tail; /* Skip EOF-chars.. */ - while (head != tail) { + while (MASK(head) != MASK(tail)) { if (test_bit(tail & (N_TTY_BUF_SIZE - 1), ldata->read_flags) && read_buf(ldata, tail) == __DISABLED_CHAR) nr--; -- GitLab From 9264e9864a6175259cf94177facbbe1a67b6ce49 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sat, 26 May 2018 09:53:14 +0900 Subject: [PATCH 336/604] n_tty: Access echo_* variables carefully. commit ebec3f8f5271139df618ebdf8427e24ba102ba94 upstream. syzbot is reporting stalls at __process_echoes() [1]. This is because since ldata->echo_commit < ldata->echo_tail becomes true for some reason, the discard loop is serving as almost infinite loop. This patch tries to avoid falling into ldata->echo_commit < ldata->echo_tail situation by making access to echo_* variables more carefully. Since reset_buffer_flags() is called without output_lock held, it should not touch echo_* variables. And omit a call to reset_buffer_flags() from n_tty_open() by using vzalloc(). Since add_echo_byte() is called without output_lock held, it needs memory barrier between storing into echo_buf[] and incrementing echo_head counter. echo_buf() needs corresponding memory barrier before reading echo_buf[]. Lack of handling the possibility of not-yet-stored multi-byte operation might be the reason of falling into ldata->echo_commit < ldata->echo_tail situation, for if I do WARN_ON(ldata->echo_commit == tail + 1) prior to echo_buf(ldata, tail + 1), the WARN_ON() fires. Also, explicitly masking with buffer for the former "while" loop, and use ldata->echo_commit > tail for the latter "while" loop. [1] https://syzkaller.appspot.com/bug?id=17f23b094cd80df750e5b0f8982c521ee6bcbf40 Signed-off-by: Tetsuo Handa Reported-by: syzbot Cc: Peter Hurley Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index a8a7a13c8683..0475f9685a41 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -145,6 +145,7 @@ static inline unsigned char *read_buf_addr(struct n_tty_data *ldata, size_t i) static inline unsigned char echo_buf(struct n_tty_data *ldata, size_t i) { + smp_rmb(); /* Matches smp_wmb() in add_echo_byte(). */ return ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)]; } @@ -320,9 +321,7 @@ static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata) static void reset_buffer_flags(struct n_tty_data *ldata) { ldata->read_head = ldata->canon_head = ldata->read_tail = 0; - ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0; ldata->commit_head = 0; - ldata->echo_mark = 0; ldata->line_start = 0; ldata->erasing = 0; @@ -621,12 +620,19 @@ static size_t __process_echoes(struct tty_struct *tty) old_space = space = tty_write_room(tty); tail = ldata->echo_tail; - while (ldata->echo_commit != tail) { + while (MASK(ldata->echo_commit) != MASK(tail)) { c = echo_buf(ldata, tail); if (c == ECHO_OP_START) { unsigned char op; int no_space_left = 0; + /* + * Since add_echo_byte() is called without holding + * output_lock, we might see only portion of multi-byte + * operation. + */ + if (MASK(ldata->echo_commit) == MASK(tail + 1)) + goto not_yet_stored; /* * If the buffer byte is the start of a multi-byte * operation, get the next byte, which is either the @@ -638,6 +644,8 @@ static size_t __process_echoes(struct tty_struct *tty) unsigned int num_chars, num_bs; case ECHO_OP_ERASE_TAB: + if (MASK(ldata->echo_commit) == MASK(tail + 2)) + goto not_yet_stored; num_chars = echo_buf(ldata, tail + 2); /* @@ -732,7 +740,8 @@ static size_t __process_echoes(struct tty_struct *tty) /* If the echo buffer is nearly full (so that the possibility exists * of echo overrun before the next commit), then discard enough * data at the tail to prevent a subsequent overrun */ - while (ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) { + while (ldata->echo_commit > tail && + ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) { if (echo_buf(ldata, tail) == ECHO_OP_START) { if (echo_buf(ldata, tail + 1) == ECHO_OP_ERASE_TAB) tail += 3; @@ -742,6 +751,7 @@ static size_t __process_echoes(struct tty_struct *tty) tail++; } + not_yet_stored: ldata->echo_tail = tail; return old_space - space; } @@ -752,6 +762,7 @@ static void commit_echoes(struct tty_struct *tty) size_t nr, old, echoed; size_t head; + mutex_lock(&ldata->output_lock); head = ldata->echo_head; ldata->echo_mark = head; old = ldata->echo_commit - ldata->echo_tail; @@ -760,10 +771,12 @@ static void commit_echoes(struct tty_struct *tty) * is over the threshold (and try again each time another * block is accumulated) */ nr = head - ldata->echo_tail; - if (nr < ECHO_COMMIT_WATERMARK || (nr % ECHO_BLOCK > old % ECHO_BLOCK)) + if (nr < ECHO_COMMIT_WATERMARK || + (nr % ECHO_BLOCK > old % ECHO_BLOCK)) { + mutex_unlock(&ldata->output_lock); return; + } - mutex_lock(&ldata->output_lock); ldata->echo_commit = head; echoed = __process_echoes(tty); mutex_unlock(&ldata->output_lock); @@ -814,7 +827,9 @@ static void flush_echoes(struct tty_struct *tty) static inline void add_echo_byte(unsigned char c, struct n_tty_data *ldata) { - *echo_buf_addr(ldata, ldata->echo_head++) = c; + *echo_buf_addr(ldata, ldata->echo_head) = c; + smp_wmb(); /* Matches smp_rmb() in echo_buf(). */ + ldata->echo_head++; } /** @@ -1883,30 +1898,21 @@ static int n_tty_open(struct tty_struct *tty) struct n_tty_data *ldata; /* Currently a malloc failure here can panic */ - ldata = vmalloc(sizeof(*ldata)); + ldata = vzalloc(sizeof(*ldata)); if (!ldata) - goto err; + return -ENOMEM; ldata->overrun_time = jiffies; mutex_init(&ldata->atomic_read_lock); mutex_init(&ldata->output_lock); tty->disc_data = ldata; - reset_buffer_flags(tty->disc_data); - ldata->column = 0; - ldata->canon_column = 0; - ldata->num_overrun = 0; - ldata->no_room = 0; - ldata->lnext = 0; tty->closing = 0; /* indicate buffer work may resume */ clear_bit(TTY_LDISC_HALTED, &tty->flags); n_tty_set_termios(tty, NULL); tty_unthrottle(tty); - return 0; -err: - return -ENOMEM; } static inline int input_available_p(struct tty_struct *tty, int poll) -- GitLab From 06bef9eebec3aa9543ac6196d983632d5fafe6f0 Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Mon, 11 Jun 2018 11:06:53 -0700 Subject: [PATCH 337/604] staging: android: ion: Return an ERR_PTR in ion_map_kernel commit 0a2bc00341dcfcc793c0dbf4f8d43adf60458b05 upstream. The expected return value from ion_map_kernel is an ERR_PTR. The error path for a vmalloc failure currently just returns NULL, triggering a warning in ion_buffer_kmap_get. Encode the vmalloc failure as an ERR_PTR. Reported-by: syzbot+55b1d9f811650de944c6@syzkaller.appspotmail.com Signed-off-by: Laura Abbott Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion_heap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c index 4e5c0f17f579..c2a7cb95725b 100644 --- a/drivers/staging/android/ion/ion_heap.c +++ b/drivers/staging/android/ion/ion_heap.c @@ -38,7 +38,7 @@ void *ion_heap_map_kernel(struct ion_heap *heap, struct page **tmp = pages; if (!pages) - return NULL; + return ERR_PTR(-ENOMEM); if (buffer->flags & ION_FLAG_CACHED) pgprot = PAGE_KERNEL; -- GitLab From 3bf351b89186181f9869612bd502ff115209abf0 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Thu, 14 Jun 2018 12:23:09 +0200 Subject: [PATCH 338/604] vt: prevent leaking uninitialized data to userspace via /dev/vcs* commit 21eff69aaaa0e766ca0ce445b477698dc6a9f55a upstream. KMSAN reported an infoleak when reading from /dev/vcs*: BUG: KMSAN: kernel-infoleak in vcs_read+0x18ba/0x1cc0 Call Trace: ... kmsan_copy_to_user+0x7a/0x160 mm/kmsan/kmsan.c:1253 copy_to_user ./include/linux/uaccess.h:184 vcs_read+0x18ba/0x1cc0 drivers/tty/vt/vc_screen.c:352 __vfs_read+0x1b2/0x9d0 fs/read_write.c:416 vfs_read+0x36c/0x6b0 fs/read_write.c:452 ... Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:279 kmsan_internal_poison_shadow+0xb8/0x1b0 mm/kmsan/kmsan.c:189 kmsan_kmalloc+0x94/0x100 mm/kmsan/kmsan.c:315 __kmalloc+0x13a/0x350 mm/slub.c:3818 kmalloc ./include/linux/slab.h:517 vc_allocate+0x438/0x800 drivers/tty/vt/vt.c:787 con_install+0x8c/0x640 drivers/tty/vt/vt.c:2880 tty_driver_install_tty drivers/tty/tty_io.c:1224 tty_init_dev+0x1b5/0x1020 drivers/tty/tty_io.c:1324 tty_open_by_driver drivers/tty/tty_io.c:1959 tty_open+0x17b4/0x2ed0 drivers/tty/tty_io.c:2007 chrdev_open+0xc25/0xd90 fs/char_dev.c:417 do_dentry_open+0xccc/0x1440 fs/open.c:794 vfs_open+0x1b6/0x2f0 fs/open.c:908 ... Bytes 0-79 of 240 are uninitialized Consistently allocating |vc_screenbuf| with kzalloc() fixes the problem Reported-by: syzbot+17a8efdf800000@syzkaller.appspotmail.com Signed-off-by: Alexander Potapenko Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 9e1ac58e269e..9d3e413f48c6 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -785,7 +785,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ if (!*vc->vc_uni_pagedir_loc) con_set_default_unimap(vc); - vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL); + vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_KERNEL); if (!vc->vc_screenbuf) goto err_free; @@ -872,7 +872,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, if (new_screen_size > (4 << 20)) return -EINVAL; - newscreen = kmalloc(new_screen_size, GFP_USER); + newscreen = kzalloc(new_screen_size, GFP_USER); if (!newscreen) return -ENOMEM; -- GitLab From e581746bc737ce8d72982359bf479f19d84bee09 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 18 Apr 2017 20:38:35 +0200 Subject: [PATCH 339/604] i2c: rcar: fix resume by always initializing registers before transfer commit ae481cc139658e89eb3ea671dd00b67bd87f01a3 upstream. Resume failed because of uninitialized registers. Instead of adding a resume callback, we simply initialize registers before every transfer. This lightweight change is more robust and will keep us safe if we ever need support for power domains or dynamic frequency changes. Signed-off-by: Wolfram Sang Acked-by: Kuninori Morimoto Signed-off-by: Wolfram Sang Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-rcar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 726615e54f2a..c7592fe30e6e 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -700,6 +700,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, pm_runtime_get_sync(dev); + rcar_i2c_init(priv); + ret = rcar_i2c_bus_barrier(priv); if (ret < 0) goto out; @@ -857,8 +859,6 @@ static int rcar_i2c_probe(struct platform_device *pdev) if (ret < 0) goto out_pm_put; - rcar_i2c_init(priv); - /* Don't suspend when multi-master to keep arbitration working */ if (of_property_read_bool(dev->of_node, "multi-master")) priv->flags |= ID_P_PM_BLOCKED; -- GitLab From 58d7ac7d3078e64c787350985c76bdd14f2d3557 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 19 Jun 2018 18:47:52 +0100 Subject: [PATCH 340/604] ipv4: Fix error return value in fib_convert_metrics() The validation code modified by commit 5b5e7a0de2bb ("net: metrics: add proper netlink validation") is organised differently in older kernel versions. The fib_convert_metrics() function that is modified in the backports to 4.4 and 4.9 needs to returns an error code, not a success flag. Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- net/ipv4/fib_semantics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index d476b7950adf..a88dab33cdf6 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -980,7 +980,7 @@ fib_convert_metrics(struct fib_info *fi, const struct fib_config *cfg) return -EINVAL; } else { if (nla_len(nla) != sizeof(u32)) - return false; + return -EINVAL; val = nla_get_u32(nla); } if (type == RTAX_ADVMSS && val > 65535 - 40) -- GitLab From 8391d38ca80ed3a6c0c769196351cb496b353aa8 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 29 Mar 2017 14:00:25 +0900 Subject: [PATCH 341/604] kprobes/x86: Do not modify singlestep buffer while resuming commit 804dec5bda9b4fcdab5f67fe61db4a0498af5221 upstream. Do not modify singlestep execution buffer (kprobe.ainsn.insn) while resuming from single-stepping, instead, modifies the buffer to add a jump back instruction at preparing buffer. Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Andrey Ryabinin Cc: Anil S Keshavamurthy Cc: Borislav Petkov Cc: Brian Gerst Cc: David S . Miller Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Ye Xiaolong Link: http://lkml.kernel.org/r/149076361560.22469.1610155860343077495.stgit@devbox Signed-off-by: Ingo Molnar Reviewed-by: "Steven Rostedt (VMware)" Signed-off-by: Alexey Makhalov Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/kprobes/core.c | 42 ++++++++++++++++------------------ 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 91c48cdfe81f..516be613bd41 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -414,25 +414,38 @@ void free_insn_page(void *page) module_memfree(page); } +/* Prepare reljump right after instruction to boost */ +static void prepare_boost(struct kprobe *p, int length) +{ + if (can_boost(p->ainsn.insn, p->addr) && + MAX_INSN_SIZE - length >= RELATIVEJUMP_SIZE) { + /* + * These instructions can be executed directly if it + * jumps back to correct address. + */ + synthesize_reljump(p->ainsn.insn + length, p->addr + length); + p->ainsn.boostable = 1; + } else { + p->ainsn.boostable = -1; + } +} + static int arch_copy_kprobe(struct kprobe *p) { - int ret; + int len; set_memory_rw((unsigned long)p->ainsn.insn & PAGE_MASK, 1); /* Copy an instruction with recovering if other optprobe modifies it.*/ - ret = __copy_instruction(p->ainsn.insn, p->addr); - if (!ret) + len = __copy_instruction(p->ainsn.insn, p->addr); + if (!len) return -EINVAL; /* * __copy_instruction can modify the displacement of the instruction, * but it doesn't affect boostable check. */ - if (can_boost(p->ainsn.insn, p->addr)) - p->ainsn.boostable = 0; - else - p->ainsn.boostable = -1; + prepare_boost(p, len); set_memory_ro((unsigned long)p->ainsn.insn & PAGE_MASK, 1); @@ -897,21 +910,6 @@ static void resume_execution(struct kprobe *p, struct pt_regs *regs, break; } - if (p->ainsn.boostable == 0) { - if ((regs->ip > copy_ip) && - (regs->ip - copy_ip) + 5 < MAX_INSN_SIZE) { - /* - * These instructions can be executed directly if it - * jumps back to correct address. - */ - synthesize_reljump((void *)regs->ip, - (void *)orig_ip + (regs->ip - copy_ip)); - p->ainsn.boostable = 1; - } else { - p->ainsn.boostable = -1; - } - } - regs->ip += orig_ip - copy_ip; no_change: -- GitLab From 440bf5ac49c578a0c56070573a28a522a87e75df Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Mon, 11 Jun 2018 22:16:33 +0900 Subject: [PATCH 342/604] netfilter: nf_tables: use WARN_ON_ONCE instead of BUG_ON in nft_do_chain() commit adc972c5b88829d38ede08b1069718661c7330ae upstream. When depth of chain is bigger than NFT_JUMP_STACK_SIZE, the nft_do_chain crashes. But there is no need to crash hard here. Suggested-by: Florian Westphal Signed-off-by: Taehee Yoo Acked-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/netfilter/nf_tables_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c index 0dd5c695482f..9d593ecd8e87 100644 --- a/net/netfilter/nf_tables_core.c +++ b/net/netfilter/nf_tables_core.c @@ -185,7 +185,8 @@ nft_do_chain(struct nft_pktinfo *pkt, void *priv) switch (regs.verdict.code) { case NFT_JUMP: - BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE); + if (WARN_ON_ONCE(stackptr >= NFT_JUMP_STACK_SIZE)) + return NF_DROP; jumpstack[stackptr].chain = chain; jumpstack[stackptr].rule = rule; jumpstack[stackptr].rulenum = rulenum; -- GitLab From 5b8fcc075714b86fb8fe194bb463fed2998a8e85 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 6 Jun 2017 11:34:06 -0400 Subject: [PATCH 343/604] Revert "sit: reload iphdr in ipip6_rcv" commit f4eb17e1efe538d4da7d574bedb00a8dafcc26b7 upstream. This reverts commit b699d0035836f6712917a41e7ae58d84359b8ff9. As per Eric Dumazet, the pskb_may_pull() is a NOP in this particular case, so the 'iph' reload is unnecessary. Signed-off-by: David S. Miller Cc: Luca Boccassi Signed-off-by: Greg Kroah-Hartman --- net/ipv6/sit.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index ae0485d776f4..fc7ca1e46908 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -659,7 +659,6 @@ static int ipip6_rcv(struct sk_buff *skb) if (iptunnel_pull_header(skb, 0, htons(ETH_P_IPV6), !net_eq(tunnel->net, dev_net(tunnel->dev)))) goto out; - iph = ip_hdr(skb); err = IP_ECN_decapsulate(iph, skb); if (unlikely(err)) { -- GitLab From 7dafda5bf29f06c1d62f1a25bd4c1f13d0242b3f Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Thu, 13 Apr 2017 14:11:27 -0500 Subject: [PATCH 344/604] net: phy: micrel: fix crash when statistic requested for KSZ9031 phy commit bfe72442578bb112626e476ffe1f276504d85b95 upstream. Now the command: ethtool --phy-statistics eth0 will cause system crash with meassage "Unable to handle kernel NULL pointer dereference at virtual address 00000010" from: (kszphy_get_stats) from [] (ethtool_get_phy_stats+0xd8/0x210) (ethtool_get_phy_stats) from [] (dev_ethtool+0x5b8/0x228c) (dev_ethtool) from [] (dev_ioctl+0x3fc/0x964) (dev_ioctl) from [] (sock_ioctl+0x170/0x2c0) (sock_ioctl) from [] (do_vfs_ioctl+0xa8/0x95c) (do_vfs_ioctl) from [] (SyS_ioctl+0x3c/0x64) (SyS_ioctl) from [] (ret_fast_syscall+0x0/0x44) The reason: phy_driver structure for KSZ9031 phy has no .probe() callback defined. As result, struct phy_device *phydev->priv pointer will not be initializes (null). This issue will affect also following phys: KSZ8795, KSZ886X, KSZ8873MLL, KSZ9031, KSZ9021, KSZ8061, KS8737 Fix it by: - adding .probe() = kszphy_probe() callback to KSZ9031, KSZ9021 phys. The kszphy_probe() can be re-used as it doesn't do any phy specific settings. - removing statistic callbacks from other phys (KSZ8795, KSZ886X, KSZ8873MLL, KSZ8061, KS8737) as they doesn't have corresponding statistic counters. Fixes: 2b2427d06426 ("phy: micrel: Add ethtool statistics counters") Signed-off-by: Grygorii Strashko Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller Cc: Dan Rue Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/micrel.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 2032a6de026b..707190d3ada0 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -801,9 +801,6 @@ static struct phy_driver ksphy_driver[] = { .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, - .get_sset_count = kszphy_get_sset_count, - .get_strings = kszphy_get_strings, - .get_stats = kszphy_get_stats, .suspend = genphy_suspend, .resume = genphy_resume, }, { @@ -948,9 +945,6 @@ static struct phy_driver ksphy_driver[] = { .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, - .get_sset_count = kszphy_get_sset_count, - .get_strings = kszphy_get_strings, - .get_stats = kszphy_get_stats, .suspend = genphy_suspend, .resume = genphy_resume, }, { @@ -960,6 +954,7 @@ static struct phy_driver ksphy_driver[] = { .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause), .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .driver_data = &ksz9021_type, + .probe = kszphy_probe, .config_init = ksz9021_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -979,6 +974,7 @@ static struct phy_driver ksphy_driver[] = { .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause), .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .driver_data = &ksz9021_type, + .probe = kszphy_probe, .config_init = ksz9031_config_init, .config_aneg = genphy_config_aneg, .read_status = ksz9031_read_status, @@ -998,9 +994,6 @@ static struct phy_driver ksphy_driver[] = { .config_init = kszphy_config_init, .config_aneg = ksz8873mll_config_aneg, .read_status = ksz8873mll_read_status, - .get_sset_count = kszphy_get_sset_count, - .get_strings = kszphy_get_strings, - .get_stats = kszphy_get_stats, .suspend = genphy_suspend, .resume = genphy_resume, }, { @@ -1012,9 +1005,6 @@ static struct phy_driver ksphy_driver[] = { .config_init = kszphy_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, - .get_sset_count = kszphy_get_sset_count, - .get_strings = kszphy_get_strings, - .get_stats = kszphy_get_stats, .suspend = genphy_suspend, .resume = genphy_resume, }, { @@ -1026,9 +1016,6 @@ static struct phy_driver ksphy_driver[] = { .config_init = kszphy_config_init, .config_aneg = ksz8873mll_config_aneg, .read_status = ksz8873mll_read_status, - .get_sset_count = kszphy_get_sset_count, - .get_strings = kszphy_get_strings, - .get_stats = kszphy_get_stats, .suspend = genphy_suspend, .resume = genphy_resume, } }; -- GitLab From 0e76f4db40893ca36a184d8921777194704cf81a Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Tue, 22 May 2018 19:45:09 +0200 Subject: [PATCH 345/604] ARM: dts: imx6q: Use correct SDMA script for SPI5 core commit df07101e1c4a29e820df02f9989a066988b160e6 upstream. According to the reference manual the shp_2_mcu / mcu_2_shp scripts must be used for devices connected through the SPBA. This fixes an issue we saw with DMA transfers. Sometimes the SPI controller RX FIFO was not empty after a DMA transfer and the driver got stuck in the next PIO transfer when it read one word more than expected. commit dd4b487b32a35 ("ARM: dts: imx6: Use correct SDMA script for SPI cores") is fixing the same issue but only for SPI1 - 4. Fixes: 677940258dd8e ("ARM: dts: imx6q: enable dma for ecspi5") Signed-off-by: Sean Nyekjaer Reviewed-by: Fabio Estevam Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/imx6q.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index e9a5d0b8c7b0..908b269a016b 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -96,7 +96,7 @@ clocks = <&clks IMX6Q_CLK_ECSPI5>, <&clks IMX6Q_CLK_ECSPI5>; clock-names = "ipg", "per"; - dmas = <&sdma 11 7 1>, <&sdma 12 7 2>; + dmas = <&sdma 11 8 1>, <&sdma 12 8 2>; dma-names = "rx", "tx"; status = "disabled"; }; -- GitLab From 389a3fcb3472c58ed13a7a5421cdf870f2b7b013 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Thu, 31 May 2018 11:30:09 -0700 Subject: [PATCH 346/604] IB/hfi1: Fix user context tail allocation for DMA_RTAIL commit 1bc0299d976e000ececc6acd76e33b4582646cb7 upstream. The following code fails to allocate a buffer for the tail address that the hardware DMAs into when the user context DMA_RTAIL is set. if (HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL)) { rcd->rcvhdrtail_kvaddr = dma_zalloc_coherent( &dd->pcidev->dev, PAGE_SIZE, &dma_hdrqtail, gfp_flags); if (!rcd->rcvhdrtail_kvaddr) goto bail_free; rcd->rcvhdrqtailaddr_dma = dma_hdrqtail; } So the rcvhdrtail_kvaddr would then be NULL. The mmap logic fails to check for a NULL rcvhdrtail_kvaddr. The fix is to test for both user and kernel DMA_TAIL options during the allocation as well as testing for a NULL rcvhdrtail_kvaddr during the mmap processing. Additionally, all downstream testing of the capmask for DMA_RTAIL have been eliminated in favor of testing rcvhdrtail_kvaddr. Cc: # 4.9.x Reviewed-by: Michael J. Ruhl Signed-off-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/hfi1/chip.c | 8 ++++---- drivers/infiniband/hw/hfi1/file_ops.c | 2 +- drivers/infiniband/hw/hfi1/init.c | 9 ++++----- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 148b313c6471..d30b3b908621 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -6717,7 +6717,7 @@ static void rxe_kernel_unfreeze(struct hfi1_devdata *dd) for (i = 0; i < dd->n_krcv_queues; i++) { rcvmask = HFI1_RCVCTRL_CTXT_ENB; /* HFI1_RCVCTRL_TAILUPD_[ENB|DIS] needs to be set explicitly */ - rcvmask |= HFI1_CAP_KGET_MASK(dd->rcd[i]->flags, DMA_RTAIL) ? + rcvmask |= dd->rcd[i]->rcvhdrtail_kvaddr ? HFI1_RCVCTRL_TAILUPD_ENB : HFI1_RCVCTRL_TAILUPD_DIS; hfi1_rcvctrl(dd, rcvmask, i); } @@ -8211,7 +8211,7 @@ static inline int check_packet_present(struct hfi1_ctxtdata *rcd) u32 tail; int present; - if (!HFI1_CAP_IS_KSET(DMA_RTAIL)) + if (!rcd->rcvhdrtail_kvaddr) present = (rcd->seq_cnt == rhf_rcv_seq(rhf_to_cpu(get_rhf_addr(rcd)))); else /* is RDMA rtail */ @@ -11550,7 +11550,7 @@ void hfi1_rcvctrl(struct hfi1_devdata *dd, unsigned int op, int ctxt) /* reset the tail and hdr addresses, and sequence count */ write_kctxt_csr(dd, ctxt, RCV_HDR_ADDR, rcd->rcvhdrq_dma); - if (HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL)) + if (rcd->rcvhdrtail_kvaddr) write_kctxt_csr(dd, ctxt, RCV_HDR_TAIL_ADDR, rcd->rcvhdrqtailaddr_dma); rcd->seq_cnt = 1; @@ -11630,7 +11630,7 @@ void hfi1_rcvctrl(struct hfi1_devdata *dd, unsigned int op, int ctxt) rcvctrl |= RCV_CTXT_CTRL_INTR_AVAIL_SMASK; if (op & HFI1_RCVCTRL_INTRAVAIL_DIS) rcvctrl &= ~RCV_CTXT_CTRL_INTR_AVAIL_SMASK; - if (op & HFI1_RCVCTRL_TAILUPD_ENB && rcd->rcvhdrqtailaddr_dma) + if ((op & HFI1_RCVCTRL_TAILUPD_ENB) && rcd->rcvhdrtail_kvaddr) rcvctrl |= RCV_CTXT_CTRL_TAIL_UPD_SMASK; if (op & HFI1_RCVCTRL_TAILUPD_DIS) { /* See comment on RcvCtxtCtrl.TailUpd above */ diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c index bb729764a799..d612f9d94083 100644 --- a/drivers/infiniband/hw/hfi1/file_ops.c +++ b/drivers/infiniband/hw/hfi1/file_ops.c @@ -609,7 +609,7 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma) ret = -EINVAL; goto done; } - if (flags & VM_WRITE) { + if ((flags & VM_WRITE) || !uctxt->rcvhdrtail_kvaddr) { ret = -EPERM; goto done; } diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c index c81c44525dd5..9dc8cf096e2e 100644 --- a/drivers/infiniband/hw/hfi1/init.c +++ b/drivers/infiniband/hw/hfi1/init.c @@ -1618,7 +1618,6 @@ int hfi1_create_rcvhdrq(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd) u64 reg; if (!rcd->rcvhdrq) { - dma_addr_t dma_hdrqtail; gfp_t gfp_flags; /* @@ -1641,13 +1640,13 @@ int hfi1_create_rcvhdrq(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd) goto bail; } - if (HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL)) { + if (HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL) || + HFI1_CAP_UGET_MASK(rcd->flags, DMA_RTAIL)) { rcd->rcvhdrtail_kvaddr = dma_zalloc_coherent( - &dd->pcidev->dev, PAGE_SIZE, &dma_hdrqtail, - gfp_flags); + &dd->pcidev->dev, PAGE_SIZE, + &rcd->rcvhdrqtailaddr_dma, gfp_flags); if (!rcd->rcvhdrtail_kvaddr) goto bail_free; - rcd->rcvhdrqtailaddr_dma = dma_hdrqtail; } rcd->rcvhdrq_size = amt; -- GitLab From 05a5d4baac9eb67de53df12d7c287492d80d674a Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Thu, 21 Jun 2018 10:43:31 +0200 Subject: [PATCH 347/604] x86/xen: Add call of speculative_store_bypass_ht_init() to PV paths commit 74899d92e66663dc7671a8017b3146dcd4735f3b upstream. Commit: 1f50ddb4f418 ("x86/speculation: Handle HT correctly on AMD") ... added speculative_store_bypass_ht_init() to the per-CPU initialization sequence. speculative_store_bypass_ht_init() needs to be called on each CPU for PV guests, too. Reported-by: Brian Woods Tested-by: Brian Woods Signed-off-by: Juergen Gross Cc: Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: boris.ostrovsky@oracle.com Cc: xen-devel@lists.xenproject.org Fixes: 1f50ddb4f4189243c05926b842dc1a0332195f31 ("x86/speculation: Handle HT correctly on AMD") Link: https://lore.kernel.org/lkml/20180621084331.21228-1-jgross@suse.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/smp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index a11540e51f62..8eca26ef6471 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -87,6 +88,8 @@ static void cpu_bringup(void) cpu_data(cpu).x86_max_cores = 1; set_cpu_sibling_map(cpu); + speculative_store_bypass_ht_init(); + xen_setup_cpu_clockevents(); notify_cpu_starting(cpu); @@ -375,6 +378,8 @@ static void __init xen_smp_prepare_cpus(unsigned int max_cpus) } set_cpu_sibling_map(0); + speculative_store_bypass_ht_init(); + xen_pmu_init(0); if (xen_smp_intr_init(0)) -- GitLab From 1adc34adc3447c34926994b87db5d929f5ab45b5 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Wed, 18 Jan 2017 11:15:39 -0800 Subject: [PATCH 348/604] x86/cpu: Re-apply forced caps every time CPU caps are re-read commit 60d3450167433f2d099ce2869dc52dd9e7dc9b29 upstream. Calling get_cpu_cap() will reset a bunch of CPU features. This will cause the system to lose track of force-set and force-cleared features in the words that are reset until the end of CPU initialization. This can cause X86_FEATURE_FPU, for example, to change back and forth during boot and potentially confuse CPU setup. To minimize the chance of confusion, re-apply forced caps every time get_cpu_cap() is called. Signed-off-by: Andy Lutomirski Reviewed-by: Borislav Petkov Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Matthew Whitehead Cc: Oleg Nesterov Cc: One Thousand Gnomes Cc: Peter Zijlstra Cc: Rik van Riel Cc: Thomas Gleixner Cc: Yu-cheng Yu Link: http://lkml.kernel.org/r/c817eb373d2c67c2c81413a70fc9b845fa34a37e.1484705016.git.luto@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/common.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index b0fd028b2eee..7a4279d8a902 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -848,6 +848,13 @@ void get_cpu_cap(struct cpuinfo_x86 *c) init_scattered_cpuid_features(c); init_speculation_control(c); + + /* + * Clear/Set all flags overridden by options, after probe. + * This needs to happen each time we re-probe, which may happen + * several times during CPU initialization. + */ + apply_forced_caps(c); } static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c) -- GitLab From 433c183fa2478055e7c6171184e1c72e23836700 Mon Sep 17 00:00:00 2001 From: Cannon Matthews Date: Tue, 3 Jul 2018 17:02:43 -0700 Subject: [PATCH 349/604] mm: hugetlb: yield when prepping struct pages commit 520495fe96d74e05db585fc748351e0504d8f40d upstream. When booting with very large numbers of gigantic (i.e. 1G) pages, the operations in the loop of gather_bootmem_prealloc, and specifically prep_compound_gigantic_page, takes a very long time, and can cause a softlockup if enough pages are requested at boot. For example booting with 3844 1G pages requires prepping (set_compound_head, init the count) over 1 billion 4K tail pages, which takes considerable time. Add a cond_resched() to the outer loop in gather_bootmem_prealloc() to prevent this lockup. Tested: Booted with softlockup_panic=1 hugepagesz=1G hugepages=3844 and no softlockup is reported, and the hugepages are reported as successfully setup. Link: http://lkml.kernel.org/r/20180627214447.260804-1-cannonmatthews@google.com Signed-off-by: Cannon Matthews Reviewed-by: Andrew Morton Reviewed-by: Mike Kravetz Acked-by: Michal Hocko Cc: Andres Lagar-Cavilla Cc: Peter Feiner Cc: Greg Thelen Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/hugetlb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 6ff65c405243..f9e735537c37 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -2171,6 +2171,7 @@ static void __init gather_bootmem_prealloc(void) */ if (hstate_is_gigantic(h)) adjust_managed_page_count(page, 1 << h->order); + cond_resched(); } } -- GitLab From 07cd8167aa703efc15fe01da8211d585ac6d3be0 Mon Sep 17 00:00:00 2001 From: Changbin Du Date: Wed, 31 Jan 2018 23:48:49 +0800 Subject: [PATCH 350/604] tracing: Fix missing return symbol in function_graph output commit 1fe4293f4b8de75824935f8d8e9a99c7fc6873da upstream. The function_graph tracer does not show the interrupt return marker for the leaf entry. On leaf entries, we see an unbalanced interrupt marker (the interrupt was entered, but nevern left). Before: 1) | SyS_write() { 1) | __fdget_pos() { 1) 0.061 us | __fget_light(); 1) 0.289 us | } 1) | vfs_write() { 1) 0.049 us | rw_verify_area(); 1) + 15.424 us | __vfs_write(); 1) ==========> | 1) 6.003 us | smp_apic_timer_interrupt(); 1) 0.055 us | __fsnotify_parent(); 1) 0.073 us | fsnotify(); 1) + 23.665 us | } 1) + 24.501 us | } After: 0) | SyS_write() { 0) | __fdget_pos() { 0) 0.052 us | __fget_light(); 0) 0.328 us | } 0) | vfs_write() { 0) 0.057 us | rw_verify_area(); 0) | __vfs_write() { 0) ==========> | 0) 8.548 us | smp_apic_timer_interrupt(); 0) <========== | 0) + 36.507 us | } /* __vfs_write */ 0) 0.049 us | __fsnotify_parent(); 0) 0.066 us | fsnotify(); 0) + 50.064 us | } 0) + 50.952 us | } Link: http://lkml.kernel.org/r/1517413729-20411-1-git-send-email-changbin.du@intel.com Cc: stable@vger.kernel.org Fixes: f8b755ac8e0cc ("tracing/function-graph-tracer: Output arrows signal on hardirq call/return") Signed-off-by: Changbin Du Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_functions_graph.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index a17cb1d8415c..01e71812e174 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -830,6 +830,7 @@ print_graph_entry_leaf(struct trace_iterator *iter, struct ftrace_graph_ret *graph_ret; struct ftrace_graph_ent *call; unsigned long long duration; + int cpu = iter->cpu; int i; graph_ret = &ret_entry->ret; @@ -838,7 +839,6 @@ print_graph_entry_leaf(struct trace_iterator *iter, if (data) { struct fgraph_cpu_data *cpu_data; - int cpu = iter->cpu; cpu_data = per_cpu_ptr(data->cpu_data, cpu); @@ -868,6 +868,9 @@ print_graph_entry_leaf(struct trace_iterator *iter, trace_seq_printf(s, "%ps();\n", (void *)call->func); + print_graph_irq(iter, graph_ret->func, TRACE_GRAPH_RET, + cpu, iter->ent->pid, flags); + return trace_handle_return(s); } -- GitLab From b6db8af7e34edfa1bf1d7b0797da15c3811a2a98 Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Mon, 25 Jun 2018 16:25:44 +0200 Subject: [PATCH 351/604] scsi: sg: mitigate read/write abuse commit 26b5b874aff5659a7e26e5b1997e3df2c41fa7fd upstream. As Al Viro noted in commit 128394eff343 ("sg_write()/bsg_write() is not fit to be called under KERNEL_DS"), sg improperly accesses userspace memory outside the provided buffer, permitting kernel memory corruption via splice(). But it doesn't just do it on ->write(), also on ->read(). As a band-aid, make sure that the ->read() and ->write() handlers can not be called in weird contexts (kernel context or credentials different from file opener), like for ib_safe_file_access(). If someone needs to use these interfaces from different security contexts, a new interface should be written that goes through the ->ioctl() handler. I've mostly copypasted ib_safe_file_access() over as sg_safe_file_access() because I couldn't find a good common header - please tell me if you know a better way. [mkp: s/_safe_/_check_/] Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: Signed-off-by: Jann Horn Acked-by: Douglas Gilbert Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sg.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 0f81d739f9e9..2065a0f9dca6 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -51,6 +51,7 @@ static int sg_version_num = 30536; /* 2 digits for each component */ #include #include #include +#include /* for sg_check_file_access() */ #include "scsi.h" #include @@ -210,6 +211,33 @@ static void sg_device_destroy(struct kref *kref); sdev_prefix_printk(prefix, (sdp)->device, \ (sdp)->disk->disk_name, fmt, ##a) +/* + * The SCSI interfaces that use read() and write() as an asynchronous variant of + * ioctl(..., SG_IO, ...) are fundamentally unsafe, since there are lots of ways + * to trigger read() and write() calls from various contexts with elevated + * privileges. This can lead to kernel memory corruption (e.g. if these + * interfaces are called through splice()) and privilege escalation inside + * userspace (e.g. if a process with access to such a device passes a file + * descriptor to a SUID binary as stdin/stdout/stderr). + * + * This function provides protection for the legacy API by restricting the + * calling context. + */ +static int sg_check_file_access(struct file *filp, const char *caller) +{ + if (filp->f_cred != current_real_cred()) { + pr_err_once("%s: process %d (%s) changed security contexts after opening file descriptor, this is not allowed.\n", + caller, task_tgid_vnr(current), current->comm); + return -EPERM; + } + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) { + pr_err_once("%s: process %d (%s) called from kernel context, this is not allowed.\n", + caller, task_tgid_vnr(current), current->comm); + return -EACCES; + } + return 0; +} + static int sg_allow_access(struct file *filp, unsigned char *cmd) { struct sg_fd *sfp = filp->private_data; @@ -394,6 +422,14 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) struct sg_header *old_hdr = NULL; int retval = 0; + /* + * This could cause a response to be stranded. Close the associated + * file descriptor to free up any resources being held. + */ + retval = sg_check_file_access(filp, __func__); + if (retval) + return retval; + if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) return -ENXIO; SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, @@ -581,9 +617,11 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) struct sg_header old_hdr; sg_io_hdr_t *hp; unsigned char cmnd[SG_MAX_CDB_SIZE]; + int retval; - if (unlikely(segment_eq(get_fs(), KERNEL_DS))) - return -EINVAL; + retval = sg_check_file_access(filp, __func__); + if (retval) + return retval; if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) return -ENXIO; -- GitLab From 0cab67a1ed6bbae481dae0ea7047f880a43fd017 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 21 Jun 2018 14:49:38 +0200 Subject: [PATCH 352/604] s390: Correct register corruption in critical section cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 891f6a726cacbb87e5b06076693ffab53bd378d7 upstream. In the critical section cleanup we must not mess with r1. For march=z9 or older, larl + ex (instead of exrl) are used with r1 as a temporary register. This can clobber r1 in several interrupt handlers. Fix this by using r11 as a temp register. r11 is being saved by all callers of cleanup_critical. Fixes: 6dd85fbb87 ("s390: move expoline assembler macros to a header") Cc: stable@vger.kernel.org #v4.16 Reported-by: Oliver Kurz Reported-by: Petr Tesařík Signed-off-by: Christian Borntraeger Reviewed-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/entry.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index a4fd00064c80..771cfd2e1e6d 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -1187,7 +1187,7 @@ cleanup_critical: jl 0f clg %r9,BASED(.Lcleanup_table+104) # .Lload_fpu_regs_end jl .Lcleanup_load_fpu_regs -0: BR_EX %r14 +0: BR_EX %r14,%r11 .align 8 .Lcleanup_table: @@ -1217,7 +1217,7 @@ cleanup_critical: ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE lctlg %c1,%c1,__LC_USER_ASCE # load primary asce larl %r9,sie_exit # skip forward to sie_exit - BR_EX %r14 + BR_EX %r14,%r11 #endif .Lcleanup_system_call: -- GitLab From f9b1cd6e7490e3aed85b915cd4a5e3a10ac2bd58 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Mon, 25 Jun 2018 11:39:52 +0200 Subject: [PATCH 353/604] drbd: fix access after free commit 64dafbc9530c10300acffc57fae3269d95fa8f93 upstream. We have struct drbd_requests { ... struct bio *private_bio; ... } to hold a bio clone for local submission. On local IO completion, we put that bio, and in case we want to use the result later, we overload that member to hold the ERR_PTR() of the completion result, Which, before v4.3, used to be the passed in "int error", so we could first bio_put(), then assign. v4.3-rc1~100^2~21 4246a0b63bd8 block: add a bi_error field to struct bio changed that: bio_put(req->private_bio); - req->private_bio = ERR_PTR(error); + req->private_bio = ERR_PTR(bio->bi_error); Which introduces an access after free, because it was non obvious that req->private_bio == bio. Impact of that was mostly unnoticable, because we only use that value in a multiple-failure case, and even then map any "unexpected" error code to EIO, so worst case we could potentially mask a more specific error with EIO in a multiple failure case. Unless the pointed to memory region was unmapped, as is the case with CONFIG_DEBUG_PAGEALLOC, in which case this results in BUG: unable to handle kernel paging request v4.13-rc1~70^2~75 4e4cbee93d56 block: switch bios to blk_status_t changes it further to bio_put(req->private_bio); req->private_bio = ERR_PTR(blk_status_to_errno(bio->bi_status)); And blk_status_to_errno() now contains a WARN_ON_ONCE() for unexpected values, which catches this "sometimes", if the memory has been reused quickly enough for other things. Should also go into stable since 4.3, with the trivial change around 4.13. Cc: stable@vger.kernel.org Fixes: 4246a0b63bd8 block: add a bi_error field to struct bio Reported-by: Sarah Newman Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/drbd/drbd_worker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index c6755c9a0aea..51c233c4e058 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -269,8 +269,8 @@ void drbd_request_endio(struct bio *bio) what = COMPLETED_OK; } - bio_put(req->private_bio); req->private_bio = ERR_PTR(bio->bi_error); + bio_put(bio); /* not req_mod(), we need irqsave here! */ spin_lock_irqsave(&device->resource->req_lock, flags); -- GitLab From 2c4f6b710bcc109d9d7063ee8114bbd1ac7dc45b Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Thu, 5 Jul 2018 13:46:34 -0300 Subject: [PATCH 354/604] cifs: Fix infinite loop when using hard mount option commit 7ffbe65578b44fafdef577a360eb0583929f7c6e upstream. For every request we send, whether it is SMB1 or SMB2+, we attempt to reconnect tcon (cifs_reconnect_tcon or smb2_reconnect) before carrying out the request. So, while server->tcpStatus != CifsNeedReconnect, we wait for the reconnection to succeed on wait_event_interruptible_timeout(). If it returns, that means that either the condition was evaluated to true, or timeout elapsed, or it was interrupted by a signal. Since we're not handling the case where the process woke up due to a received signal (-ERESTARTSYS), the next call to wait_event_interruptible_timeout() will _always_ fail and we end up looping forever inside either cifs_reconnect_tcon() or smb2_reconnect(). Here's an example of how to trigger that: $ mount.cifs //foo/share /mnt/test -o username=foo,password=foo,vers=1.0,hard (break connection to server before executing bellow cmd) $ stat -f /mnt/test & sleep 140 [1] 2511 $ ps -aux -q 2511 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 2511 0.0 0.0 12892 1008 pts/0 S 12:24 0:00 stat -f /mnt/test $ kill -9 2511 (wait for a while; process is stuck in the kernel) $ ps -aux -q 2511 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 2511 83.2 0.0 12892 1008 pts/0 R 12:24 30:01 stat -f /mnt/test By using 'hard' mount point means that cifs.ko will keep retrying indefinitely, however we must allow the process to be killed otherwise it would hang the system. Signed-off-by: Paulo Alcantara Cc: stable@vger.kernel.org Reviewed-by: Aurelien Aptel Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/cifssmb.c | 10 ++++++++-- fs/cifs/smb2pdu.c | 18 ++++++++++++------ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index d57222894892..8407b07428a6 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -150,8 +150,14 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) * greater than cifs socket timeout which is 7 seconds */ while (server->tcpStatus == CifsNeedReconnect) { - wait_event_interruptible_timeout(server->response_q, - (server->tcpStatus != CifsNeedReconnect), 10 * HZ); + rc = wait_event_interruptible_timeout(server->response_q, + (server->tcpStatus != CifsNeedReconnect), + 10 * HZ); + if (rc < 0) { + cifs_dbg(FYI, "%s: aborting reconnect due to a received" + " signal by the process\n", __func__); + return -ERESTARTSYS; + } /* are we still trying to reconnect? */ if (server->tcpStatus != CifsNeedReconnect) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index e0214334769b..4ded64b8b43b 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -155,7 +155,7 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ , static int smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) { - int rc = 0; + int rc; struct nls_table *nls_codepage; struct cifs_ses *ses; struct TCP_Server_Info *server; @@ -166,10 +166,10 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) * for those three - in the calling routine. */ if (tcon == NULL) - return rc; + return 0; if (smb2_command == SMB2_TREE_CONNECT) - return rc; + return 0; if (tcon->tidStatus == CifsExiting) { /* @@ -212,8 +212,14 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) return -EAGAIN; } - wait_event_interruptible_timeout(server->response_q, - (server->tcpStatus != CifsNeedReconnect), 10 * HZ); + rc = wait_event_interruptible_timeout(server->response_q, + (server->tcpStatus != CifsNeedReconnect), + 10 * HZ); + if (rc < 0) { + cifs_dbg(FYI, "%s: aborting reconnect due to a received" + " signal by the process\n", __func__); + return -ERESTARTSYS; + } /* are we still trying to reconnect? */ if (server->tcpStatus != CifsNeedReconnect) @@ -231,7 +237,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) } if (!tcon->ses->need_reconnect && !tcon->need_reconnect) - return rc; + return 0; nls_codepage = load_nls_default(); -- GitLab From 0f80447d031d91748878e002b9506e323d932467 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 3 Jun 2018 16:40:54 +0200 Subject: [PATCH 355/604] drm/udl: fix display corruption of the last line commit 99ec9e77511dea55d81729fc80b6c63a61bfa8e0 upstream. The displaylink hardware has such a peculiarity that it doesn't render a command until next command is received. This produces occasional corruption, such as when setting 22x11 font on the console, only the first line of the cursor will be blinking if the cursor is located at some specific columns. When we end up with a repeating pixel, the driver has a bug that it leaves one uninitialized byte after the command (and this byte is enough to flush the command and render it - thus it fixes the screen corruption), however whe we end up with a non-repeating pixel, there is no byte appended and this results in temporary screen corruption. This patch fixes the screen corruption by always appending a byte 0xAF at the end of URB. It also removes the uninitialized byte. Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/udl/udl_fb.c | 5 ++++- drivers/gpu/drm/udl/udl_transfer.c | 11 +++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index 67ea2ce03a23..39d0fdcb17d2 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -136,7 +136,10 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, if (cmd > (char *) urb->transfer_buffer) { /* Send partial buffer remaining before exiting */ - int len = cmd - (char *) urb->transfer_buffer; + int len; + if (cmd < (char *) urb->transfer_buffer + urb->transfer_buffer_length) + *cmd++ = 0xAF; + len = cmd - (char *) urb->transfer_buffer; ret = udl_submit_urb(dev, urb, len); bytes_sent += len; } else diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c index 917dcb978c2c..9259a2f8bf3a 100644 --- a/drivers/gpu/drm/udl/udl_transfer.c +++ b/drivers/gpu/drm/udl/udl_transfer.c @@ -152,11 +152,11 @@ static void udl_compress_hline16( raw_pixels_count_byte = cmd++; /* we'll know this later */ raw_pixel_start = pixel; - cmd_pixel_end = pixel + (min(MAX_CMD_PIXELS + 1, - min((int)(pixel_end - pixel) / bpp, - (int)(cmd_buffer_end - cmd) / 2))) * bpp; + cmd_pixel_end = pixel + min3(MAX_CMD_PIXELS + 1UL, + (unsigned long)(pixel_end - pixel) / bpp, + (unsigned long)(cmd_buffer_end - 1 - cmd) / 2) * bpp; - prefetch_range((void *) pixel, (cmd_pixel_end - pixel) * bpp); + prefetch_range((void *) pixel, cmd_pixel_end - pixel); pixel_val16 = get_pixel_val16(pixel, bpp); while (pixel < cmd_pixel_end) { @@ -192,6 +192,9 @@ static void udl_compress_hline16( if (pixel > raw_pixel_start) { /* finalize last RAW span */ *raw_pixels_count_byte = ((pixel-raw_pixel_start) / bpp) & 0xFF; + } else { + /* undo unused byte */ + cmd--; } *cmd_pixels_count_byte = ((pixel - cmd_pixel_start) / bpp) & 0xFF; -- GitLab From 8ef97ef67ce0f8fc3d32c7218e6b412e479ee2ab Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 16 Jun 2018 20:21:45 -0400 Subject: [PATCH 356/604] jbd2: don't mark block as modified if the handle is out of credits commit e09463f220ca9a1a1ecfda84fcda658f99a1f12a upstream. Do not set the b_modified flag in block's journal head should not until after we're sure that jbd2_journal_dirty_metadat() will not abort with an error due to there not being enough space reserved in the jbd2 handle. Otherwise, future attempts to modify the buffer may lead a large number of spurious errors and warnings. This addresses CVE-2018-10883. https://bugzilla.kernel.org/show_bug.cgi?id=200071 Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/jbd2/transaction.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 9e9e0936138b..b320c1ba7fdc 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1353,6 +1353,13 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) if (jh->b_transaction == transaction && jh->b_jlist != BJ_Metadata) { jbd_lock_bh_state(bh); + if (jh->b_transaction == transaction && + jh->b_jlist != BJ_Metadata) + pr_err("JBD2: assertion failure: h_type=%u " + "h_line_no=%u block_no=%llu jlist=%u\n", + handle->h_type, handle->h_line_no, + (unsigned long long) bh->b_blocknr, + jh->b_jlist); J_ASSERT_JH(jh, jh->b_transaction != transaction || jh->b_jlist == BJ_Metadata); jbd_unlock_bh_state(bh); @@ -1372,11 +1379,11 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) * of the transaction. This needs to be done * once a transaction -bzzz */ - jh->b_modified = 1; if (handle->h_buffer_credits <= 0) { ret = -ENOSPC; goto out_unlock_bh; } + jh->b_modified = 1; handle->h_buffer_credits--; } -- GitLab From 9e4842f2aa6c4b4340669730c90cb6fbf630ee42 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 13 Jun 2018 23:08:26 -0400 Subject: [PATCH 357/604] ext4: make sure bitmaps and the inode table don't overlap with bg descriptors commit 77260807d1170a8cf35dbb06e07461a655f67eee upstream. It's really bad when the allocation bitmaps and the inode table overlap with the block group descriptors, since it causes random corruption of the bg descriptors. So we really want to head those off at the pass. https://bugzilla.kernel.org/show_bug.cgi?id=199865 Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index bfb83d76d128..6525127133e8 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2231,6 +2231,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 block_bitmap; ext4_fsblk_t inode_bitmap; ext4_fsblk_t inode_table; @@ -2263,6 +2264,14 @@ static int ext4_check_descriptors(struct super_block *sb, if (!(sb->s_flags & MS_RDONLY)) return 0; } + if (block_bitmap >= sb_block + 1 && + block_bitmap <= last_bg_block) { + ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " + "Block bitmap for group %u overlaps " + "block group descriptors", i); + if (!(sb->s_flags & MS_RDONLY)) + return 0; + } if (block_bitmap < first_block || block_bitmap > last_block) { ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " "Block bitmap for group %u not in group " @@ -2277,6 +2286,14 @@ static int ext4_check_descriptors(struct super_block *sb, if (!(sb->s_flags & MS_RDONLY)) return 0; } + if (inode_bitmap >= sb_block + 1 && + inode_bitmap <= last_bg_block) { + ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " + "Inode bitmap for group %u overlaps " + "block group descriptors", i); + if (!(sb->s_flags & MS_RDONLY)) + return 0; + } if (inode_bitmap < first_block || inode_bitmap > last_block) { ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " "Inode bitmap for group %u not in group " @@ -2291,6 +2308,14 @@ static int ext4_check_descriptors(struct super_block *sb, if (!(sb->s_flags & MS_RDONLY)) return 0; } + if (inode_table >= sb_block + 1 && + inode_table <= last_bg_block) { + ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " + "Inode table for group %u overlaps " + "block group descriptors", i); + if (!(sb->s_flags & MS_RDONLY)) + return 0; + } if (inode_table < first_block || inode_table + sbi->s_itb_per_group - 1 > last_block) { ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " -- GitLab From cdde876fce2501828af33d5e4faa36c8919fc96a Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 13 Jun 2018 23:00:48 -0400 Subject: [PATCH 358/604] ext4: always check block group bounds in ext4_init_block_bitmap() commit 819b23f1c501b17b9694325471789e6b5cc2d0d2 upstream. Regardless of whether the flex_bg feature is set, we should always check to make sure the bits we are setting in the block bitmap are within the block group bounds. https://bugzilla.kernel.org/show_bug.cgi?id=199865 Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/balloc.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 6776f4aa3d12..badb4e075225 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -183,7 +183,6 @@ static int ext4_init_block_bitmap(struct super_block *sb, unsigned int bit, bit_max; struct ext4_sb_info *sbi = EXT4_SB(sb); ext4_fsblk_t start, tmp; - int flex_bg = 0; struct ext4_group_info *grp; J_ASSERT_BH(bh, buffer_locked(bh)); @@ -216,22 +215,19 @@ static int ext4_init_block_bitmap(struct super_block *sb, start = ext4_group_first_block_no(sb, block_group); - if (ext4_has_feature_flex_bg(sb)) - flex_bg = 1; - /* Set bits for block and inode bitmaps, and inode table */ tmp = ext4_block_bitmap(sb, gdp); - if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) + if (ext4_block_in_group(sb, tmp, block_group)) ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data); tmp = ext4_inode_bitmap(sb, gdp); - if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) + if (ext4_block_in_group(sb, tmp, block_group)) ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data); tmp = ext4_inode_table(sb, gdp); for (; tmp < ext4_inode_table(sb, gdp) + sbi->s_itb_per_group; tmp++) { - if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) + if (ext4_block_in_group(sb, tmp, block_group)) ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data); } -- GitLab From 5ae57329580d6ceca97559ff030a5f0e91fa66fe Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 14 Jun 2018 00:58:00 -0400 Subject: [PATCH 359/604] ext4: only look at the bg_flags field if it is valid commit 8844618d8aa7a9973e7b527d038a2a589665002c upstream. The bg_flags field in the block group descripts is only valid if the uninit_bg or metadata_csum feature is enabled. We were not consistently looking at this field; fix this. Also block group #0 must never have uninitialized allocation bitmaps, or need to be zeroed, since that's where the root inode, and other special inodes are set up. Check for these conditions and mark the file system as corrupted if they are detected. This addresses CVE-2018-10876. https://bugzilla.kernel.org/show_bug.cgi?id=199403 Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/balloc.c | 11 ++++++++++- fs/ext4/ialloc.c | 14 ++++++++++++-- fs/ext4/mballoc.c | 6 ++++-- fs/ext4/super.c | 11 ++++++++++- 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index badb4e075225..ad13f07cf0d3 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -450,7 +450,16 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) goto verify; } ext4_lock_group(sb, block_group); - if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { + if (ext4_has_group_desc_csum(sb) && + (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) { + if (block_group == 0) { + ext4_unlock_group(sb, block_group); + unlock_buffer(bh); + ext4_error(sb, "Block bitmap for bg 0 marked " + "uninitialized"); + err = -EFSCORRUPTED; + goto out; + } err = ext4_init_block_bitmap(sb, bh, block_group, desc); set_bitmap_uptodate(bh); set_buffer_uptodate(bh); diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index dcf63daefee0..460866b2166d 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -152,7 +152,16 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) } ext4_lock_group(sb, block_group); - if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { + if (ext4_has_group_desc_csum(sb) && + (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT))) { + if (block_group == 0) { + ext4_unlock_group(sb, block_group); + unlock_buffer(bh); + ext4_error(sb, "Inode bitmap for bg 0 marked " + "uninitialized"); + err = -EFSCORRUPTED; + goto out; + } memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8); ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8, bh->b_data); @@ -926,7 +935,8 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, /* recheck and clear flag under lock if we still need to */ ext4_lock_group(sb, group); - if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { + if (ext4_has_group_desc_csum(sb) && + (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) { gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); ext4_free_group_clusters_set(sb, gdp, ext4_free_clusters_after_init(sb, group, gdp)); diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 14bd37041e1a..53e1890660a2 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -2444,7 +2444,8 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group, * initialize bb_free to be able to skip * empty groups without initialization */ - if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { + if (ext4_has_group_desc_csum(sb) && + (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) { meta_group_info[i]->bb_free = ext4_free_clusters_after_init(sb, group, desc); } else { @@ -2969,7 +2970,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, #endif ext4_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start, ac->ac_b_ex.fe_len); - if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { + if (ext4_has_group_desc_csum(sb) && + (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) { gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); ext4_free_group_clusters_set(sb, gdp, ext4_free_clusters_after_init(sb, diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 6525127133e8..4c5d9df1790a 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3023,13 +3023,22 @@ static ext4_group_t ext4_has_uninit_itable(struct super_block *sb) ext4_group_t group, ngroups = EXT4_SB(sb)->s_groups_count; struct ext4_group_desc *gdp = NULL; + if (!ext4_has_group_desc_csum(sb)) + return ngroups; + for (group = 0; group < ngroups; group++) { gdp = ext4_get_group_desc(sb, group, NULL); if (!gdp) continue; - if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))) + if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED)) + continue; + if (group != 0) break; + ext4_error(sb, "Inode table for bg 0 marked as " + "needing zeroing"); + if (sb->s_flags & MS_RDONLY) + return ngroups; } return group; -- GitLab From 87dad44faabd45683fba94443471298f8809e8a8 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 14 Jun 2018 12:55:10 -0400 Subject: [PATCH 360/604] ext4: verify the depth of extent tree in ext4_find_extent() commit bc890a60247171294acc0bd67d211fa4b88d40ba upstream. If there is a corupted file system where the claimed depth of the extent tree is -1, this can cause a massive buffer overrun leading to sadness. This addresses CVE-2018-10877. https://bugzilla.kernel.org/show_bug.cgi?id=199417 Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ext4_extents.h | 1 + fs/ext4/extents.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h index 8ecf84b8f5a1..a284fb28944b 100644 --- a/fs/ext4/ext4_extents.h +++ b/fs/ext4/ext4_extents.h @@ -103,6 +103,7 @@ struct ext4_extent_header { }; #define EXT4_EXT_MAGIC cpu_to_le16(0xf30a) +#define EXT4_MAX_EXTENT_DEPTH 5 #define EXT4_EXTENT_TAIL_OFFSET(hdr) \ (sizeof(struct ext4_extent_header) + \ diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 63c702b4b24c..106a5bb3ae68 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -881,6 +881,12 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block, eh = ext_inode_hdr(inode); depth = ext_depth(inode); + if (depth < 0 || depth > EXT4_MAX_EXTENT_DEPTH) { + EXT4_ERROR_INODE(inode, "inode has invalid extent depth: %d", + depth); + ret = -EFSCORRUPTED; + goto err; + } if (path) { ext4_ext_drop_refs(path); -- GitLab From 2f135cc8c094152d361b3172d3f757369de28a08 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 15 Jun 2018 12:27:16 -0400 Subject: [PATCH 361/604] ext4: include the illegal physical block in the bad map ext4_error msg commit bdbd6ce01a70f02e9373a584d0ae9538dcf0a121 upstream. Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 7c025ee1276f..81b16c3eccd4 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -377,9 +377,9 @@ static int __check_block_validity(struct inode *inode, const char *func, if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), map->m_pblk, map->m_len)) { ext4_error_inode(inode, func, line, map->m_pblk, - "lblock %lu mapped to illegal pblock " + "lblock %lu mapped to illegal pblock %llu " "(length %d)", (unsigned long) map->m_lblk, - map->m_len); + map->m_pblk, map->m_len); return -EFSCORRUPTED; } return 0; -- GitLab From a5e063d348bd2ef14fff96b129749409a8991ea5 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 15 Jun 2018 12:28:16 -0400 Subject: [PATCH 362/604] ext4: clear i_data in ext4_inode_info when removing inline data commit 6e8ab72a812396996035a37e5ca4b3b99b5d214b upstream. When converting from an inode from storing the data in-line to a data block, ext4_destroy_inline_data_nolock() was only clearing the on-disk copy of the i_blocks[] array. It was not clearing copy of the i_blocks[] in ext4_inode_info, in i_data[], which is the copy actually used by ext4_map_blocks(). This didn't matter much if we are using extents, since the extents header would be invalid and thus the extents could would re-initialize the extents tree. But if we are using indirect blocks, the previous contents of the i_blocks array will be treated as block numbers, with potentially catastrophic results to the file system integrity and/or user data. This gets worse if the file system is using a 1k block size and s_first_data is zero, but even without this, the file system can get quite badly corrupted. This addresses CVE-2018-10881. https://bugzilla.kernel.org/show_bug.cgi?id=200015 Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inline.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 73cbc01ef5ad..e6ac24de119d 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -434,6 +434,7 @@ static int ext4_destroy_inline_data_nolock(handle_t *handle, memset((void *)ext4_raw_inode(&is.iloc)->i_block, 0, EXT4_MIN_INLINE_DATA_SIZE); + memset(ei->i_data, 0, EXT4_MIN_INLINE_DATA_SIZE); if (ext4_has_feature_extents(inode->i_sb)) { if (S_ISDIR(inode->i_mode) || -- GitLab From 425dc465de3725210162da9b1e9062e86cc2de27 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 17 Jun 2018 00:41:14 -0400 Subject: [PATCH 363/604] ext4: add more inode number paranoia checks commit c37e9e013469521d9adb932d17a1795c139b36db upstream. If there is a directory entry pointing to a system inode (such as a journal inode), complain and declare the file system to be corrupted. Also, if the superblock's first inode number field is too small, refuse to mount the file system. This addresses CVE-2018-10882. https://bugzilla.kernel.org/show_bug.cgi?id=200069 Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ext4.h | 5 ----- fs/ext4/inode.c | 3 ++- fs/ext4/super.c | 5 +++++ 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index a8a750f59621..43e27d8ec770 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1542,11 +1542,6 @@ static inline struct timespec ext4_current_time(struct inode *inode) static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino) { return ino == EXT4_ROOT_INO || - ino == EXT4_USR_QUOTA_INO || - ino == EXT4_GRP_QUOTA_INO || - ino == EXT4_BOOT_LOADER_INO || - ino == EXT4_JOURNAL_INO || - ino == EXT4_RESIZE_INO || (ino >= EXT4_FIRST_INO(sb) && ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count)); } diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 81b16c3eccd4..5c4c9af4aaf4 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4242,7 +4242,8 @@ static int __ext4_get_inode_loc(struct inode *inode, int inodes_per_block, inode_offset; iloc->bh = NULL; - if (!ext4_valid_inum(sb, inode->i_ino)) + if (inode->i_ino < EXT4_ROOT_INO || + inode->i_ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count)) return -EFSCORRUPTED; iloc->block_group = (inode->i_ino - 1) / EXT4_INODES_PER_GROUP(sb); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 4c5d9df1790a..25e078e839fb 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3713,6 +3713,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) } else { sbi->s_inode_size = le16_to_cpu(es->s_inode_size); sbi->s_first_ino = le32_to_cpu(es->s_first_ino); + if (sbi->s_first_ino < EXT4_GOOD_OLD_FIRST_INO) { + ext4_msg(sb, KERN_ERR, "invalid first ino: %u", + sbi->s_first_ino); + goto failed_mount; + } if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) || (!is_power_of_2(sbi->s_inode_size)) || (sbi->s_inode_size > blocksize)) { -- GitLab From eb13a42605ab8560b02fdeb117f119f327e4776d Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 17 Jun 2018 18:11:20 -0400 Subject: [PATCH 364/604] ext4: add more mount time checks of the superblock commit bfe0a5f47ada40d7984de67e59a7d3390b9b9ecc upstream. The kernel's ext4 mount-time checks were more permissive than e2fsprogs's libext2fs checks when opening a file system. The superblock is considered too insane for debugfs or e2fsck to operate on it, the kernel has no business trying to mount it. This will make file system fuzzing tools work harder, but the failure cases that they find will be more useful and be easier to evaluate. Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 25e078e839fb..fff215a1f1a9 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3656,6 +3656,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) le32_to_cpu(es->s_log_block_size)); goto failed_mount; } + if (le32_to_cpu(es->s_log_cluster_size) > + (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) { + ext4_msg(sb, KERN_ERR, + "Invalid log cluster size: %u", + le32_to_cpu(es->s_log_cluster_size)); + goto failed_mount; + } if (le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) > (blocksize / 4)) { ext4_msg(sb, KERN_ERR, @@ -3794,13 +3801,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) "block size (%d)", clustersize, blocksize); goto failed_mount; } - if (le32_to_cpu(es->s_log_cluster_size) > - (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) { - ext4_msg(sb, KERN_ERR, - "Invalid log cluster size: %u", - le32_to_cpu(es->s_log_cluster_size)); - goto failed_mount; - } sbi->s_cluster_bits = le32_to_cpu(es->s_log_cluster_size) - le32_to_cpu(es->s_log_block_size); sbi->s_clusters_per_group = @@ -3821,10 +3821,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) } } else { if (clustersize != blocksize) { - ext4_warning(sb, "fragment/cluster size (%d) != " - "block size (%d)", clustersize, - blocksize); - clustersize = blocksize; + ext4_msg(sb, KERN_ERR, + "fragment/cluster size (%d) != " + "block size (%d)", clustersize, blocksize); + goto failed_mount; } if (sbi->s_blocks_per_group > blocksize * 8) { ext4_msg(sb, KERN_ERR, @@ -3878,6 +3878,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ext4_blocks_count(es)); goto failed_mount; } + if ((es->s_first_data_block == 0) && (es->s_log_block_size == 0) && + (sbi->s_cluster_ratio == 1)) { + ext4_msg(sb, KERN_WARNING, "bad geometry: first data " + "block is 0 with a 1k block and cluster size"); + goto failed_mount; + } + blocks_count = (ext4_blocks_count(es) - le32_to_cpu(es->s_first_data_block) + EXT4_BLOCKS_PER_GROUP(sb) - 1); @@ -3913,6 +3920,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ret = -ENOMEM; goto failed_mount; } + if (((u64)sbi->s_groups_count * sbi->s_inodes_per_group) != + le32_to_cpu(es->s_inodes_count)) { + ext4_msg(sb, KERN_ERR, "inodes count not valid: %u vs %llu", + le32_to_cpu(es->s_inodes_count), + ((u64)sbi->s_groups_count * sbi->s_inodes_per_group)); + ret = -EINVAL; + goto failed_mount; + } bgl_lock_init(sbi->s_blockgroup_lock); -- GitLab From 917692c9cdf5ea62e783d08dfef40bfb982a9dca Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Mon, 2 Jul 2018 18:45:18 -0400 Subject: [PATCH 365/604] ext4: check superblock mapped prior to committing commit a17712c8e4be4fa5404d20e9cd3b2b21eae7bc56 upstream. This patch attempts to close a hole leading to a BUG seen with hot removals during writes [1]. A block device (NVME namespace in this test case) is formatted to EXT4 without partitions. It's mounted and write I/O is run to a file, then the device is hot removed from the slot. The superblock attempts to be written to the drive which is no longer present. The typical chain of events leading to the BUG: ext4_commit_super() __sync_dirty_buffer() submit_bh() submit_bh_wbc() BUG_ON(!buffer_mapped(bh)); This fix checks for the superblock's buffer head being mapped prior to syncing. [1] https://www.spinics.net/lists/linux-ext4/msg56527.html Signed-off-by: Jon Derrick Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index fff215a1f1a9..41ef83471ea5 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -4629,6 +4629,14 @@ static int ext4_commit_super(struct super_block *sb, int sync) if (!sbh || block_device_ejected(sb)) return error; + + /* + * The superblock bh should be mapped, but it might not be if the + * device was hot-removed. Not much we can do but fail the I/O. + */ + if (!buffer_mapped(sbh)) + return error; + /* * If the file system is mounted read-only, don't update the * superblock write time. This avoids updating the superblock -- GitLab From 2f1a56ef237d91bb649526292434fd60220d6b41 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 8 Jul 2018 14:23:19 +0300 Subject: [PATCH 366/604] mlxsw: spectrum: Forbid linking of VLAN devices to devices that have uppers Jiri Slaby noticed that the backport of upstream commit 25cc72a33835 ("mlxsw: spectrum: Forbid linking to devices that have uppers") to kernel 4.9.y introduced the same check twice in the same function instead of in two different places. Fix this by relocating one of the checks to its intended place, thus preventing unsupported configurations as described in the original commit. Fixes: 73ee5a73e75f ("mlxsw: spectrum: Forbid linking to devices that have uppers") Signed-off-by: Ido Schimmel Reported-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index d50350c7adc4..22a5916e477e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4187,10 +4187,6 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev, if (netif_is_lag_port(dev) && is_vlan_dev(upper_dev) && !netif_is_lag_master(vlan_dev_real_dev(upper_dev))) return -EINVAL; - if (!info->linking) - break; - if (netdev_has_any_upper_dev(upper_dev)) - return -EINVAL; break; case NETDEV_CHANGEUPPER: upper_dev = info->upper_dev; @@ -4566,6 +4562,8 @@ static int mlxsw_sp_netdevice_vport_event(struct net_device *dev, return -EINVAL; if (!info->linking) break; + if (netdev_has_any_upper_dev(upper_dev)) + return -EINVAL; /* We can't have multiple VLAN interfaces configured on * the same port and being members in the same bridge. */ -- GitLab From 814b4302fda0c4fc09b023e18ca813d88c3350b6 Mon Sep 17 00:00:00 2001 From: Jason Andryuk Date: Fri, 22 Jun 2018 12:25:49 -0400 Subject: [PATCH 367/604] HID: i2c-hid: Fix "incomplete report" noise commit ef6eaf27274c0351f7059163918f3795da13199c upstream. Commit ac75a041048b ("HID: i2c-hid: fix size check and type usage") started writing messages when the ret_size is <= 2 from i2c_master_recv. However, my device i2c-DLL07D1 returns 2 for a short period of time (~0.5s) after I stop moving the pointing stick or touchpad. It varies, but you get ~50 messages each time which spams the log hard. [ 95.925055] i2c_hid i2c-DLL07D1:01: i2c_hid_get_input: incomplete report (83/2) This has also been observed with a i2c-ALP0017. [ 1781.266353] i2c_hid i2c-ALP0017:00: i2c_hid_get_input: incomplete report (30/2) Only print the message when ret_size is totally invalid and less than 2 to cut down on the log spam. Fixes: ac75a041048b ("HID: i2c-hid: fix size check and type usage") Reported-by: John Smith Cc: stable@vger.kernel.org Signed-off-by: Jason Andryuk Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/i2c-hid/i2c-hid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 2548c5dbdc75..00bce002b357 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -477,7 +477,7 @@ static void i2c_hid_get_input(struct i2c_hid *ihid) return; } - if ((ret_size > size) || (ret_size <= 2)) { + if ((ret_size > size) || (ret_size < 2)) { dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n", __func__, size, ret_size); return; -- GitLab From 82e360cd6fb2055cb178f92934eb71d511b1aa47 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 29 Jun 2018 17:08:44 -0500 Subject: [PATCH 368/604] HID: hiddev: fix potential Spectre v1 commit 4f65245f2d178b9cba48350620d76faa4a098841 upstream. uref->field_index, uref->usage_index, finfo.field_index and cinfo.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/hid/usbhid/hiddev.c:473 hiddev_ioctl_usage() warn: potential spectre issue 'report->field' (local cap) drivers/hid/usbhid/hiddev.c:477 hiddev_ioctl_usage() warn: potential spectre issue 'field->usage' (local cap) drivers/hid/usbhid/hiddev.c:757 hiddev_ioctl() warn: potential spectre issue 'report->field' (local cap) drivers/hid/usbhid/hiddev.c:801 hiddev_ioctl() warn: potential spectre issue 'hid->collection' (local cap) Fix this by sanitizing such structure fields before using them to index report->field, field->usage and hid->collection 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: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/usbhid/hiddev.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 700145b15088..b59b15d4caa9 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "usbhid.h" #ifdef CONFIG_USB_DYNAMIC_MINORS @@ -478,10 +479,14 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, if (uref->field_index >= report->maxfield) goto inval; + uref->field_index = array_index_nospec(uref->field_index, + report->maxfield); field = report->field[uref->field_index]; if (uref->usage_index >= field->maxusage) goto inval; + uref->usage_index = array_index_nospec(uref->usage_index, + field->maxusage); uref->usage_code = field->usage[uref->usage_index].hid; @@ -508,6 +513,8 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, if (uref->field_index >= report->maxfield) goto inval; + uref->field_index = array_index_nospec(uref->field_index, + report->maxfield); field = report->field[uref->field_index]; @@ -761,6 +768,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (finfo.field_index >= report->maxfield) break; + finfo.field_index = array_index_nospec(finfo.field_index, + report->maxfield); field = report->field[finfo.field_index]; memset(&finfo, 0, sizeof(finfo)); @@ -801,6 +810,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (cinfo.index >= hid->maxcollection) break; + cinfo.index = array_index_nospec(cinfo.index, + hid->maxcollection); cinfo.type = hid->collection[cinfo.index].type; cinfo.usage = hid->collection[cinfo.index].usage; -- GitLab From 4a30c12542290f1def08b9ef0d677c024c500589 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 2 Jul 2018 16:59:37 -0700 Subject: [PATCH 369/604] HID: debug: check length before copy_to_user() commit 717adfdaf14704fd3ec7fa2c04520c0723247eac upstream. If our length is greater than the size of the buffer, we overflow the buffer Cc: stable@vger.kernel.org Signed-off-by: Daniel Rosenberg Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-debug.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index acfb522a432a..29423691c105 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -1152,6 +1152,8 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer, goto out; if (list->tail > list->head) { len = list->tail - list->head; + if (len > count) + len = count; if (copy_to_user(buffer + ret, &list->hid_debug_buf[list->head], len)) { ret = -EFAULT; @@ -1161,6 +1163,8 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer, list->head += len; } else { len = HID_DEBUG_BUFSIZE - list->head; + if (len > count) + len = count; if (copy_to_user(buffer, &list->hid_debug_buf[list->head], len)) { ret = -EFAULT; @@ -1168,7 +1172,9 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer, } list->head = 0; ret += len; - goto copy_rest; + count -= len; + if (count > 0) + goto copy_rest; } } -- GitLab From 6989d4079d60c20753413d1fc01547e098417cc7 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Thu, 14 Jun 2018 15:56:08 +0200 Subject: [PATCH 370/604] PM / OPP: Update voltage in case freq == old_freq commit c5c2a97b3ac7d1ec19e7cff9e38caca6afefc3de upstream. This commit fixes a rare but possible case when the clk rate is updated without update of the regulator voltage. At boot up, CPUfreq checks if the system is running at the right freq. This is a sanity check in case a bootloader set clk rate that is outside of freq table present with cpufreq core. In such cases system can be unstable so better to change it to a freq that is preset in freq-table. The CPUfreq takes next freq that is >= policy->cur and this is our target_freq that needs to be set now. dev_pm_opp_set_rate(dev, target_freq) checks the target_freq and the old_freq (a current rate). If these are equal it returns early. If not, it searches for OPP (old_opp) that fits best to old_freq (not listed in the table) and updates old_freq (!). Here, we can end up with old_freq = old_opp.rate = target_freq, which is not handled in _generic_set_opp_regulator(). It's supposed to update voltage only when freq > old_freq || freq > old_freq. if (freq > old_freq) { ret = _set_opp_voltage(dev, reg, new_supply); [...] if (freq < old_freq) { ret = _set_opp_voltage(dev, reg, new_supply); if (ret) It results in, no voltage update while clk rate is updated. Example: freq-table = { 1000MHz 1.15V 666MHZ 1.10V 333MHz 1.05V } boot-up-freq = 800MHz # not listed in freq-table freq = target_freq = 1GHz old_freq = 800Mhz old_opp = _find_freq_ceil(opp_table, &old_freq); #(old_freq is modified!) old_freq = 1GHz Fixes: 6a0712f6f199 ("PM / OPP: Add dev_pm_opp_set_rate()") Cc: 4.6+ # v4.6+ Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Viresh Kumar Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/opp/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index a7c5b79371a7..23ee46a0c78c 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c @@ -651,7 +651,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) rcu_read_unlock(); /* Scaling up? Scale voltage before frequency */ - if (freq > old_freq) { + if (freq >= old_freq) { ret = _set_opp_voltage(dev, reg, u_volt, u_volt_min, u_volt_max); if (ret) -- GitLab From b5d7d7d919f1708f2645739d37dc19747ac0ab5b Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Sun, 8 Apr 2018 23:35:28 +0200 Subject: [PATCH 371/604] Kbuild: fix # escaping in .cmd files for future Make MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 9564a8cf422d7b58f6e857e3546d346fa970191e upstream. I tried building using a freshly built Make (4.2.1-69-g8a731d1), but already the objtool build broke with orc_dump.c: In function ‘orc_dump’: orc_dump.c:106:2: error: ‘elf_getshnum’ is deprecated [-Werror=deprecated-declarations] if (elf_getshdrnum(elf, &nr_sections)) { Turns out that with that new Make, the backslash was not removed, so cpp didn't see a #include directive, grep found nothing, and -DLIBELF_USE_DEPRECATED was wrongly put in CFLAGS. Now, that new Make behaviour is documented in their NEWS file: * WARNING: Backward-incompatibility! Number signs (#) appearing inside a macro reference or function invocation no longer introduce comments and should not be escaped with backslashes: thus a call such as: foo := $(shell echo '#') is legal. Previously the number sign needed to be escaped, for example: foo := $(shell echo '\#') Now this latter will resolve to "\#". If you want to write makefiles portable to both versions, assign the number sign to a variable: C := \# foo := $(shell echo '$C') This was claimed to be fixed in 3.81, but wasn't, for some reason. To detect this change search for 'nocomment' in the .FEATURES variable. This also fixes up the two make-cmd instances to replace # with $(pound) rather than with \#. There might very well be other places that need similar fixup in preparation for whatever future Make release contains the above change, but at least this builds an x86_64 defconfig with the new make. Link: https://bugzilla.kernel.org/show_bug.cgi?id=197847 Cc: Randy Dunlap Signed-off-by: Rasmus Villemoes Signed-off-by: Masahiro Yamada Signed-off-by: Greg Kroah-Hartman --- scripts/Kbuild.include | 5 +++-- tools/build/Build.include | 5 +++-- tools/objtool/Makefile | 2 +- tools/scripts/Makefile.include | 2 ++ 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 179219845dfc..63774307a751 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -8,6 +8,7 @@ squote := ' empty := space := $(empty) $(empty) space_escape := _-_SPACE_-_ +pound := \# ### # Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o @@ -241,11 +242,11 @@ endif # Replace >$< with >$$< to preserve $ when reloading the .cmd file # (needed for make) -# Replace >#< with >\#< to avoid starting a comment in the .cmd file +# Replace >#< with >$(pound)< to avoid starting a comment in the .cmd file # (needed for make) # Replace >'< with >'\''< to be able to enclose the whole string in '...' # (needed for the shell) -make-cmd = $(call escsq,$(subst \#,\\\#,$(subst $$,$$$$,$(cmd_$(1))))) +make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1))))) # Find any prerequisites that is newer than target or that does not exist. # PHONY targets skipped in both cases. diff --git a/tools/build/Build.include b/tools/build/Build.include index 1dcb95e76f70..b8165545ddf6 100644 --- a/tools/build/Build.include +++ b/tools/build/Build.include @@ -12,6 +12,7 @@ # Convenient variables comma := , squote := ' +pound := \# ### # Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o @@ -43,11 +44,11 @@ echo-cmd = $(if $($(quiet)cmd_$(1)),\ ### # Replace >$< with >$$< to preserve $ when reloading the .cmd file # (needed for make) -# Replace >#< with >\#< to avoid starting a comment in the .cmd file +# Replace >#< with >$(pound)< to avoid starting a comment in the .cmd file # (needed for make) # Replace >'< with >'\''< to be able to enclose the whole string in '...' # (needed for the shell) -make-cmd = $(call escsq,$(subst \#,\\\#,$(subst $$,$$$$,$(cmd_$(1))))) +make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1))))) ### # Find any prerequisites that is newer than target or that does not exist. diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index e6acc281dd37..8ae824dbfca3 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -35,7 +35,7 @@ CFLAGS += -Wall -Werror $(WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) LDFLAGS += -lelf $(LIBSUBCMD) # Allow old libelf to be used: -elfshdr := $(shell echo '\#include ' | $(CC) $(CFLAGS) -x c -E - | grep elf_getshdr) +elfshdr := $(shell echo '$(pound)include ' | $(CC) $(CFLAGS) -x c -E - | grep elf_getshdr) CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED) AWK = awk diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include index 19edc1a7a232..7ea4438b801d 100644 --- a/tools/scripts/Makefile.include +++ b/tools/scripts/Makefile.include @@ -92,3 +92,5 @@ ifneq ($(silent),1) QUIET_INSTALL = @printf ' INSTALL %s\n' $1; endif endif + +pound := \# -- GitLab From d96a0d3cd5395aa0e4deb20e06e1ec2d723c426c Mon Sep 17 00:00:00 2001 From: Brad Love Date: Tue, 6 Mar 2018 14:15:34 -0500 Subject: [PATCH 372/604] media: cx25840: Use subdev host data for PLL override commit 3ee9bc12342cf546313d300808ff47d7dbb8e7db upstream. The cx25840 driver currently configures 885, 887, and 888 using default divisors for each chip. This check to see if the cx23885 driver has passed the cx25840 a non-default clock rate for a specific chip. If a cx23885 board has left clk_freq at 0, the clock default values will be used to configure the PLLs. This patch only has effect on 888 boards who set clk_freq to 25M. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/media/i2c/cx25840/cx25840-core.c | 28 +++++++++++++++++++----- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index d558ed3e59c6..cc5666050282 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -467,8 +467,13 @@ static void cx23885_initialize(struct i2c_client *client) { DEFINE_WAIT(wait); struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + u32 clk_freq = 0; struct workqueue_struct *q; + /* cx23885 sets hostdata to clk_freq pointer */ + if (v4l2_get_subdev_hostdata(&state->sd)) + clk_freq = *((u32 *)v4l2_get_subdev_hostdata(&state->sd)); + /* * Come out of digital power down * The CX23888, at least, needs this, otherwise registers aside from @@ -504,8 +509,13 @@ static void cx23885_initialize(struct i2c_client *client) * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz * 572.73 MHz before post divide */ - /* HVR1850 or 50MHz xtal */ - cx25840_write(client, 0x2, 0x71); + if (clk_freq == 25000000) { + /* 888/ImpactVCBe or 25Mhz xtal */ + ; /* nothing to do */ + } else { + /* HVR1850 or 50MHz xtal */ + cx25840_write(client, 0x2, 0x71); + } cx25840_write4(client, 0x11c, 0x01d1744c); cx25840_write4(client, 0x118, 0x00000416); cx25840_write4(client, 0x404, 0x0010253e); @@ -548,9 +558,15 @@ static void cx23885_initialize(struct i2c_client *client) /* HVR1850 */ switch (state->id) { case CX23888_AV: - /* 888/HVR1250 specific */ - cx25840_write4(client, 0x10c, 0x13333333); - cx25840_write4(client, 0x108, 0x00000515); + if (clk_freq == 25000000) { + /* 888/ImpactVCBe or 25MHz xtal */ + cx25840_write4(client, 0x10c, 0x01b6db7b); + cx25840_write4(client, 0x108, 0x00000512); + } else { + /* 888/HVR1250 or 50MHz xtal */ + cx25840_write4(client, 0x10c, 0x13333333); + cx25840_write4(client, 0x108, 0x00000515); + } break; default: cx25840_write4(client, 0x10c, 0x002be2c9); @@ -580,7 +596,7 @@ static void cx23885_initialize(struct i2c_client *client) * 368.64 MHz before post divide * 122.88 MHz / 0xa = 12.288 MHz */ - /* HVR1850 or 50MHz xtal */ + /* HVR1850 or 50MHz xtal or 25MHz xtal */ cx25840_write4(client, 0x114, 0x017dbf48); cx25840_write4(client, 0x110, 0x000a030e); break; -- GitLab From 6cfbbdd2bcc950e21c293019a1f9c40458405891 Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Thu, 7 Jun 2018 17:09:29 -0700 Subject: [PATCH 373/604] mm, page_alloc: do not break __GFP_THISNODE by zonelist reset commit 7810e6781e0fcbca78b91cf65053f895bf59e85f upstream. In __alloc_pages_slowpath() we reset zonelist and preferred_zoneref for allocations that can ignore memory policies. The zonelist is obtained from current CPU's node. This is a problem for __GFP_THISNODE allocations that want to allocate on a different node, e.g. because the allocating thread has been migrated to a different CPU. This has been observed to break SLAB in our 4.4-based kernel, because there it relies on __GFP_THISNODE working as intended. If a slab page is put on wrong node's list, then further list manipulations may corrupt the list because page_to_nid() is used to determine which node's list_lock should be locked and thus we may take a wrong lock and race. Current SLAB implementation seems to be immune by luck thanks to commit 511e3a058812 ("mm/slab: make cache_grow() handle the page allocated on arbitrary node") but there may be others assuming that __GFP_THISNODE works as promised. We can fix it by simply removing the zonelist reset completely. There is actually no reason to reset it, because memory policies and cpusets don't affect the zonelist choice in the first place. This was different when commit 183f6371aac2 ("mm: ignore mempolicies when using ALLOC_NO_WATERMARK") introduced the code, as mempolicies provided their own restricted zonelists. We might consider this for 4.17 although I don't know if there's anything currently broken. SLAB is currently not affected, but in kernels older than 4.7 that don't yet have 511e3a058812 ("mm/slab: make cache_grow() handle the page allocated on arbitrary node") it is. That's at least 4.4 LTS. Older ones I'll have to check. So stable backports should be more important, but will have to be reviewed carefully, as the code went through many changes. BTW I think that also the ac->preferred_zoneref reset is currently useless if we don't also reset ac->nodemask from a mempolicy to NULL first (which we probably should for the OOM victims etc?), but I would leave that for a separate patch. Link: http://lkml.kernel.org/r/20180525130853.13915-1-vbabka@suse.cz Signed-off-by: Vlastimil Babka Fixes: 183f6371aac2 ("mm: ignore mempolicies when using ALLOC_NO_WATERMARK") Acked-by: Mel Gorman Cc: Michal Hocko Cc: David Rientjes Cc: Joonsoo Kim Cc: Vlastimil Babka Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/page_alloc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 94018ea5f935..28240ce475d6 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -3642,7 +3642,6 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, * orientated. */ if (!(alloc_flags & ALLOC_CPUSET) || (alloc_flags & ALLOC_NO_WATERMARKS)) { - ac->zonelist = node_zonelist(numa_node_id(), gfp_mask); ac->preferred_zoneref = first_zones_zonelist(ac->zonelist, ac->high_zoneidx, ac->nodemask); } -- GitLab From 0758c35b535fc166e743b05287bf395e2241fa60 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Thu, 17 Nov 2016 11:24:20 -0800 Subject: [PATCH 374/604] dm bufio: avoid sleeping while holding the dm_bufio lock commit 9ea61cac0b1ad0c09022f39fd97e9b99a2cfc2dc upstream. We've seen in-field reports showing _lots_ (18 in one case, 41 in another) of tasks all sitting there blocked on: mutex_lock+0x4c/0x68 dm_bufio_shrink_count+0x38/0x78 shrink_slab.part.54.constprop.65+0x100/0x464 shrink_zone+0xa8/0x198 In the two cases analyzed, we see one task that looks like this: Workqueue: kverityd verity_prefetch_io __switch_to+0x9c/0xa8 __schedule+0x440/0x6d8 schedule+0x94/0xb4 schedule_timeout+0x204/0x27c schedule_timeout_uninterruptible+0x44/0x50 wait_iff_congested+0x9c/0x1f0 shrink_inactive_list+0x3a0/0x4cc shrink_lruvec+0x418/0x5cc shrink_zone+0x88/0x198 try_to_free_pages+0x51c/0x588 __alloc_pages_nodemask+0x648/0xa88 __get_free_pages+0x34/0x7c alloc_buffer+0xa4/0x144 __bufio_new+0x84/0x278 dm_bufio_prefetch+0x9c/0x154 verity_prefetch_io+0xe8/0x10c process_one_work+0x240/0x424 worker_thread+0x2fc/0x424 kthread+0x10c/0x114 ...and that looks to be the one holding the mutex. The problem has been reproduced on fairly easily: 0. Be running Chrome OS w/ verity enabled on the root filesystem 1. Pick test patch: http://crosreview.com/412360 2. Install launchBalloons.sh and balloon.arm from http://crbug.com/468342 ...that's just a memory stress test app. 3. On a 4GB rk3399 machine, run nice ./launchBalloons.sh 4 900 100000 ...that tries to eat 4 * 900 MB of memory and keep accessing. 4. Login to the Chrome web browser and restore many tabs With that, I've seen printouts like: DOUG: long bufio 90758 ms ...and stack trace always show's we're in dm_bufio_prefetch(). The problem is that we try to allocate memory with GFP_NOIO while we're holding the dm_bufio lock. Instead we should be using GFP_NOWAIT. Using GFP_NOIO can cause us to sleep while holding the lock and that causes the above problems. The current behavior explained by David Rientjes: It will still try reclaim initially because __GFP_WAIT (or __GFP_KSWAPD_RECLAIM) is set by GFP_NOIO. This is the cause of contention on dm_bufio_lock() that the thread holds. You want to pass GFP_NOWAIT instead of GFP_NOIO to alloc_buffer() when holding a mutex that can be contended by a concurrent slab shrinker (if count_objects didn't use a trylock, this pattern would trivially deadlock). This change significantly increases responsiveness of the system while in this state. It makes a real difference because it unblocks kswapd. In the bug report analyzed, kswapd was hung: kswapd0 D ffffffc000204fd8 0 72 2 0x00000000 Call trace: [] __switch_to+0x9c/0xa8 [] __schedule+0x440/0x6d8 [] schedule+0x94/0xb4 [] schedule_preempt_disabled+0x28/0x44 [] __mutex_lock_slowpath+0x120/0x1ac [] mutex_lock+0x4c/0x68 [] dm_bufio_shrink_count+0x38/0x78 [] shrink_slab.part.54.constprop.65+0x100/0x464 [] shrink_zone+0xa8/0x198 [] balance_pgdat+0x328/0x508 [] kswapd+0x424/0x51c [] kthread+0x10c/0x114 [] ret_from_fork+0x10/0x40 By unblocking kswapd memory pressure should be reduced. Suggested-by: David Rientjes Reviewed-by: Guenter Roeck Signed-off-by: Douglas Anderson Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-bufio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 35fd57fdeba9..6deb1feff5c7 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -824,7 +824,8 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client * dm-bufio is resistant to allocation failures (it just keeps * one buffer reserved in cases all the allocations fail). * So set flags to not try too hard: - * GFP_NOIO: don't recurse into the I/O layer + * GFP_NOWAIT: don't wait; if we need to sleep we'll release our + * mutex and wait ourselves. * __GFP_NORETRY: don't retry and rather return failure * __GFP_NOMEMALLOC: don't use emergency reserves * __GFP_NOWARN: don't print a warning in case of failure @@ -834,7 +835,7 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client */ while (1) { if (dm_bufio_cache_size_latch != 1) { - b = alloc_buffer(c, GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN); + b = alloc_buffer(c, GFP_NOWAIT | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN); if (b) return b; } -- GitLab From 34d2fe724aeed1d61dd524d1062cf428f5bca2f1 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 23 Nov 2016 17:04:00 -0500 Subject: [PATCH 375/604] dm bufio: drop the lock when doing GFP_NOIO allocation commit 41c73a49df31151f4ff868f28fe4f129f113fa2c upstream. If the first allocation attempt using GFP_NOWAIT fails, drop the lock and retry using GFP_NOIO allocation (lock is dropped because the allocation can take some time). Note that we won't do GFP_NOIO allocation when we loop for the second time, because the lock shouldn't be dropped between __wait_for_free_buffer and __get_unclaimed_buffer. Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-bufio.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 6deb1feff5c7..57b01bc3c70b 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -819,6 +819,7 @@ enum new_flag { static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client *c, enum new_flag nf) { struct dm_buffer *b; + bool tried_noio_alloc = false; /* * dm-bufio is resistant to allocation failures (it just keeps @@ -843,6 +844,15 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client if (nf == NF_PREFETCH) return NULL; + if (dm_bufio_cache_size_latch != 1 && !tried_noio_alloc) { + dm_bufio_unlock(c); + b = alloc_buffer(c, GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN); + dm_bufio_lock(c); + if (b) + return b; + tried_noio_alloc = true; + } + if (!list_empty(&c->reserved_buffers)) { b = list_entry(c->reserved_buffers.next, struct dm_buffer, lru_list); -- GitLab From 9d1304f5816db4cc96cab6e5cceb75054cb841c5 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Mon, 18 Jun 2018 22:41:03 +0200 Subject: [PATCH 376/604] mtd: rawnand: mxc: set spare area size register explicitly commit 3f77f244d8ec28e3a0a81240ffac7d626390060c upstream. The v21 version of the NAND flash controller contains a Spare Area Size Register (SPAS) at offset 0x10. Its setting defaults to the maximum spare area size of 218 bytes. The size that is set in this register is used by the controller when it calculates the ECC bytes internally in hardware. Usually, this register is updated from settings in the IIM fuses when the system is booting from NAND flash. For other boot media, however, the SPAS register remains at the default setting, which may not work for the particular flash chip on the board. The same goes for flash chips whose configuration cannot be set in the IIM fuses (e.g. chips with 2k sector size and 128 bytes spare area size can't be configured in the IIM fuses on imx25 systems). Set the SPAS register explicitly during the preset operation. Derive the register value from mtd->oobsize that was detected during probe by decoding the flash chip's ID bytes. While at it, rename the define for the spare area register's offset to NFC_V21_RSLTSPARE_AREA. The register at offset 0x10 on v1 controllers is different from the register on v21 controllers. Fixes: d484018 ("mtd: mxc_nand: set NFC registers after reset") Cc: stable@vger.kernel.org Signed-off-by: Martin Kaiser Reviewed-by: Sascha Hauer Reviewed-by: Miquel Raynal Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/mxc_nand.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 0c84ee80e5b6..5c44eb57885b 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -48,7 +48,7 @@ #define NFC_V1_V2_CONFIG (host->regs + 0x0a) #define NFC_V1_V2_ECC_STATUS_RESULT (host->regs + 0x0c) #define NFC_V1_V2_RSLTMAIN_AREA (host->regs + 0x0e) -#define NFC_V1_V2_RSLTSPARE_AREA (host->regs + 0x10) +#define NFC_V21_RSLTSPARE_AREA (host->regs + 0x10) #define NFC_V1_V2_WRPROT (host->regs + 0x12) #define NFC_V1_UNLOCKSTART_BLKADDR (host->regs + 0x14) #define NFC_V1_UNLOCKEND_BLKADDR (host->regs + 0x16) @@ -1121,6 +1121,9 @@ static void preset_v2(struct mtd_info *mtd) writew(config1, NFC_V1_V2_CONFIG1); /* preset operation */ + /* spare area size in 16-bit half-words */ + writew(mtd->oobsize / 2, NFC_V21_RSLTSPARE_AREA); + /* Unlock the internal RAM Buffer */ writew(0x2, NFC_V1_V2_CONFIG); -- GitLab From 4779184af75437c83c7ac5f257fa0db1fe1ed9b7 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 23 Nov 2016 16:52:01 -0500 Subject: [PATCH 377/604] dm bufio: don't take the lock in dm_bufio_shrink_count commit d12067f428c037b4575aaeb2be00847fc214c24a upstream. dm_bufio_shrink_count() is called from do_shrink_slab to find out how many freeable objects are there. The reported value doesn't have to be precise, so we don't need to take the dm-bufio lock. Suggested-by: David Rientjes Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-bufio.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 57b01bc3c70b..c837defb5e4d 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -1598,19 +1598,11 @@ dm_bufio_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) static unsigned long dm_bufio_shrink_count(struct shrinker *shrink, struct shrink_control *sc) { - struct dm_bufio_client *c; - unsigned long count; - unsigned long retain_target; - - c = container_of(shrink, struct dm_bufio_client, shrinker); - if (sc->gfp_mask & __GFP_FS) - dm_bufio_lock(c); - else if (!dm_bufio_trylock(c)) - return 0; + struct dm_bufio_client *c = container_of(shrink, struct dm_bufio_client, shrinker); + unsigned long count = READ_ONCE(c->n_buffers[LIST_CLEAN]) + + READ_ONCE(c->n_buffers[LIST_DIRTY]); + unsigned long retain_target = get_retain_buffers(c); - count = c->n_buffers[LIST_CLEAN] + c->n_buffers[LIST_DIRTY]; - retain_target = get_retain_buffers(c); - dm_bufio_unlock(c); return (count < retain_target) ? 0 : (count - retain_target); } -- GitLab From c2f163e35f2eab7d38c5e3fb14d5a7e902fb6d8a Mon Sep 17 00:00:00 2001 From: Tokunori Ikegami Date: Wed, 30 May 2018 18:32:27 +0900 Subject: [PATCH 378/604] mtd: cfi_cmdset_0002: Change definition naming to retry write operation commit 85a82e28b023de9b259a86824afbd6ba07bd6475 upstream. The definition can be used for other program and erase operations also. So change the naming to MAX_RETRIES from MAX_WORD_RETRIES. Signed-off-by: Tokunori Ikegami Reviewed-by: Joakim Tjernlund Cc: Chris Packham Cc: Brian Norris Cc: David Woodhouse Cc: Boris Brezillon Cc: Marek Vasut Cc: Richard Weinberger Cc: Cyrille Pitchen Cc: linux-mtd@lists.infradead.org Cc: stable@vger.kernel.org Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/chips/cfi_cmdset_0002.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 33d025e42793..1065388e6287 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -42,7 +42,7 @@ #define AMD_BOOTLOC_BUG #define FORCE_WORD_WRITE 0 -#define MAX_WORD_RETRIES 3 +#define MAX_RETRIES 3 #define SST49LF004B 0x0060 #define SST49LF040B 0x0050 @@ -1643,7 +1643,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, map_write( map, CMD(0xF0), chip->start ); /* FIXME - should have reset delay before continuing */ - if (++retry_cnt <= MAX_WORD_RETRIES) + if (++retry_cnt <= MAX_RETRIES) goto retry; ret = -EIO; @@ -2102,7 +2102,7 @@ static int do_panic_write_oneword(struct map_info *map, struct flchip *chip, map_write(map, CMD(0xF0), chip->start); /* FIXME - should have reset delay before continuing */ - if (++retry_cnt <= MAX_WORD_RETRIES) + if (++retry_cnt <= MAX_RETRIES) goto retry; ret = -EIO; -- GitLab From ed1746148b3eabb8d9019dfdbbfc8f59f2917980 Mon Sep 17 00:00:00 2001 From: Tokunori Ikegami Date: Wed, 30 May 2018 18:32:28 +0900 Subject: [PATCH 379/604] mtd: cfi_cmdset_0002: Change erase functions to retry for error commit 45f75b8a919a4255f52df454f1ffdee0e42443b2 upstream. For the word write functions it is retried for error. But it is not implemented to retry for the erase functions. To make sure for the erase functions change to retry as same. This is needed to prevent the flash erase error caused only once. It was caused by the error case of chip_good() in the do_erase_oneblock(). Also it was confirmed on the MACRONIX flash device MX29GL512FHT2I-11G. But the error issue behavior is not able to reproduce at this moment. The flash controller is parallel Flash interface integrated on BCM53003. Signed-off-by: Tokunori Ikegami Reviewed-by: Joakim Tjernlund Cc: Chris Packham Cc: Brian Norris Cc: David Woodhouse Cc: Boris Brezillon Cc: Marek Vasut Cc: Richard Weinberger Cc: Cyrille Pitchen Cc: linux-mtd@lists.infradead.org Cc: stable@vger.kernel.org Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/chips/cfi_cmdset_0002.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 1065388e6287..ccfbb41ed322 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -2237,6 +2237,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) unsigned long int adr; DECLARE_WAITQUEUE(wait, current); int ret = 0; + int retry_cnt = 0; adr = cfi->addr_unlock1; @@ -2254,6 +2255,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) ENABLE_VPP(map); xip_disable(map, chip, adr); + retry: cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -2308,6 +2310,9 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) map_write( map, CMD(0xF0), chip->start ); /* FIXME - should have reset delay before continuing */ + if (++retry_cnt <= MAX_RETRIES) + goto retry; + ret = -EIO; } @@ -2327,6 +2332,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long timeo = jiffies + HZ; DECLARE_WAITQUEUE(wait, current); int ret = 0; + int retry_cnt = 0; adr += chip->start; @@ -2344,6 +2350,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, ENABLE_VPP(map); xip_disable(map, chip, adr); + retry: cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -2401,6 +2408,9 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, map_write( map, CMD(0xF0), chip->start ); /* FIXME - should have reset delay before continuing */ + if (++retry_cnt <= MAX_RETRIES) + goto retry; + ret = -EIO; } -- GitLab From a0239d83e1cb60de5e78452d4708c083b9e3dcbe Mon Sep 17 00:00:00 2001 From: Tokunori Ikegami Date: Wed, 30 May 2018 18:32:29 +0900 Subject: [PATCH 380/604] mtd: cfi_cmdset_0002: Change erase functions to check chip good only commit 79ca484b613041ca223f74b34608bb6f5221724b upstream. Currently the functions use to check both chip ready and good. But the chip ready is not enough to check the operation status. So change this to check the chip good instead of this. About the retry functions to make sure the error handling remain it. Signed-off-by: Tokunori Ikegami Reviewed-by: Joakim Tjernlund Cc: Chris Packham Cc: Brian Norris Cc: David Woodhouse Cc: Boris Brezillon Cc: Marek Vasut Cc: Richard Weinberger Cc: Cyrille Pitchen Cc: linux-mtd@lists.infradead.org Cc: stable@vger.kernel.org Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/chips/cfi_cmdset_0002.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index ccfbb41ed322..de35a2a362f9 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -2292,12 +2292,13 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) chip->erase_suspended = 0; } - if (chip_ready(map, adr)) + if (chip_good(map, adr, map_word_ff(map))) break; if (time_after(jiffies, timeo)) { printk(KERN_WARNING "MTD %s(): software timeout\n", __func__ ); + ret = -EIO; break; } @@ -2305,15 +2306,15 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) UDELAY(map, chip, adr, 1000000/HZ); } /* Did we succeed? */ - if (!chip_good(map, adr, map_word_ff(map))) { + if (ret) { /* reset on all failures. */ map_write( map, CMD(0xF0), chip->start ); /* FIXME - should have reset delay before continuing */ - if (++retry_cnt <= MAX_RETRIES) + if (++retry_cnt <= MAX_RETRIES) { + ret = 0; goto retry; - - ret = -EIO; + } } chip->state = FL_READY; @@ -2387,7 +2388,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, chip->erase_suspended = 0; } - if (chip_ready(map, adr)) { + if (chip_good(map, adr, map_word_ff(map))) { xip_enable(map, chip, adr); break; } @@ -2396,6 +2397,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, xip_enable(map, chip, adr); printk(KERN_WARNING "MTD %s(): software timeout\n", __func__ ); + ret = -EIO; break; } @@ -2403,15 +2405,15 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, UDELAY(map, chip, adr, 1000000/HZ); } /* Did we succeed? */ - if (!chip_good(map, adr, map_word_ff(map))) { + if (ret) { /* reset on all failures. */ map_write( map, CMD(0xF0), chip->start ); /* FIXME - should have reset delay before continuing */ - if (++retry_cnt <= MAX_RETRIES) + if (++retry_cnt <= MAX_RETRIES) { + ret = 0; goto retry; - - ret = -EIO; + } } chip->state = FL_READY; -- GitLab From 1712fae9489eaf16de9592e654d2d92a863fc06e Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Mon, 25 Jun 2018 17:22:00 +0200 Subject: [PATCH 381/604] netfilter: nf_log: don't hold nf_log_mutex during user access commit ce00bf07cc95a57cd20b208e02b3c2604e532ae8 upstream. The old code would indefinitely block other users of nf_log_mutex if a userspace access in proc_dostring() blocked e.g. due to a userfaultfd region. Fix it by moving proc_dostring() out of the locked region. This is a followup to commit 266d07cb1c9a ("netfilter: nf_log: fix sleeping function called from invalid context"), which changed this code from using rcu_read_lock() to taking nf_log_mutex. Fixes: 266d07cb1c9a ("netfilter: nf_log: fix sleeping function calle[...]") Signed-off-by: Jann Horn Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/netfilter/nf_log.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index ffb9e8ada899..e02fed784cd0 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -444,14 +444,17 @@ static int nf_log_proc_dostring(struct ctl_table *table, int write, rcu_assign_pointer(net->nf.nf_loggers[tindex], logger); mutex_unlock(&nf_log_mutex); } else { + struct ctl_table tmp = *table; + + tmp.data = buf; mutex_lock(&nf_log_mutex); logger = nft_log_dereference(net->nf.nf_loggers[tindex]); if (!logger) - table->data = "NONE"; + strlcpy(buf, "NONE", sizeof(buf)); else - table->data = logger->name; - r = proc_dostring(table, write, buffer, lenp, ppos); + strlcpy(buf, logger->name, sizeof(buf)); mutex_unlock(&nf_log_mutex); + r = proc_dostring(&tmp, write, buffer, lenp, ppos); } return r; -- GitLab From e31cd420e1be4e701292078e0840df0fe4c0cd8b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 5 Jun 2018 12:36:30 +0300 Subject: [PATCH 382/604] staging: comedi: quatech_daqp_cs: fix no-op loop daqp_ao_insn_write() commit 1376b0a2160319125c3a2822e8c09bd283cd8141 upstream. There is a '>' vs '<' typo so this loop is a no-op. Fixes: d35dcc89fc93 ("staging: comedi: quatech_daqp_cs: fix daqp_ao_insn_write()") Signed-off-by: Dan Carpenter Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/quatech_daqp_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index 802f51e46405..171960568356 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -642,7 +642,7 @@ static int daqp_ao_insn_write(struct comedi_device *dev, /* Make sure D/A update mode is direct update */ outb(0, dev->iobase + DAQP_AUX_REG); - for (i = 0; i > insn->n; i++) { + for (i = 0; i < insn->n; i++) { unsigned int val = data[i]; int ret; -- GitLab From 060744011e93679f03932f050619744be895b772 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 11 Jul 2018 16:26:46 +0200 Subject: [PATCH 383/604] Linux 4.9.112 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b10646531fcd..c4544293db10 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 111 +SUBLEVEL = 112 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From 9a13c888f54676bbe8aa62be399a996d20059204 Mon Sep 17 00:00:00 2001 From: Amine Najahi Date: Tue, 10 Jul 2018 16:52:14 -0400 Subject: [PATCH 384/604] msm/sde/rotator: reduce log level of sde_rotator_footswitch_ctrl Reduce the log level when handling a consecutive call to sde_rotator_footswitch_ctrl as it is not really an error. Change-Id: Id7730987791775d1c576ce38c8dc6e5b2b020aa3 Signed-off-by: Amine Najahi --- drivers/media/platform/msm/sde/rotator/sde_rotator_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c index ce50dcda961d..ca3b010c95c6 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c @@ -303,7 +303,7 @@ static int sde_rotator_footswitch_ctrl(struct sde_rot_mgr *mgr, bool on) int ret = 0; if (mgr->regulator_enable == on) { - SDEROT_ERR("Regulators already in selected mode on=%d\n", on); + SDEROT_DBG("Regulators already in selected mode on=%d\n", on); return 0; } -- GitLab From 0739502f2542fd67f13c706bde4d6456b4697350 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 11 Jul 2018 14:59:10 -0700 Subject: [PATCH 385/604] msm: camera: icp: Add release call Currently a buffer allocated by ICP driver, is not being released at the end of the use case. This change releases that memory. Change-Id: Iab820711a06ba71a09990dc5cff0857e73f57181 Signed-off-by: Karthik Anantha Ram --- .../msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 1 + 1 file changed, 1 insertion(+) 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 c73c25fef428..46e95c2d80aa 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 @@ -2025,6 +2025,7 @@ static void cam_icp_free_hfi_mem(void) cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.cmd_q); cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.msg_q); cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.dbg_q); + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.sfr_buf); } static int cam_icp_alloc_secheap_mem(struct cam_mem_mgr_memory_desc *secheap) -- GitLab From 0cf55399c83f6b5e911f41d57012f374c9b0a47d Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 11 Jul 2018 23:51:28 -0700 Subject: [PATCH 386/604] msm: camera: cci: Fix error check The change fixes the error check during cci read. Change-Id: Ia6be7ff5ff828f98d57fb7d39b9a06991aca2241 Signed-off-by: Karthik Anantha Ram --- .../msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b47f4f35b108..058e3528e248 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 @@ -1410,7 +1410,7 @@ static int32_t cam_cci_read_bytes(struct v4l2_subdev *sd, else rc = cam_cci_read(sd, c_ctrl); - if (!rc) { + if (rc) { CAM_ERR(CAM_CCI, "failed to read rc:%d", rc); goto ERROR; } -- GitLab From 5a10dd15301ce885a584ad947483ab1ac72bbc25 Mon Sep 17 00:00:00 2001 From: Raviteja Tamatam Date: Fri, 29 Jun 2018 16:19:06 +0530 Subject: [PATCH 387/604] drm/msm/sde: fix flush bit setting in pp-split case For single flush cases (dual-ctl or pp-split), skip setting the flush bit for the slave interface, since both interfaces use same ctl and HW will only flush the master. Change-Id: Ic48a1e0acbc1c8c215cbc41db5a3dc8daccbfa7d Signed-off-by: Raviteja Tamatam --- .../gpu/drm/msm/sde/sde_encoder_phys_vid.c | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c index d363d62746f0..74bf5187bd89 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c @@ -40,6 +40,20 @@ #define POLL_TIME_USEC_FOR_LN_CNT 500 #define MAX_POLL_CNT 10 +static bool _sde_encoder_phys_is_ppsplit(struct sde_encoder_phys *phys_enc) +{ + enum sde_rm_topology_name topology; + + if (!phys_enc) + return false; + + topology = sde_connector_get_topology_name(phys_enc->connector); + if (topology == SDE_RM_TOPOLOGY_PPSPLIT) + return true; + + return false; +} + static bool sde_encoder_phys_vid_is_master( struct sde_encoder_phys *phys_enc) { @@ -313,12 +327,14 @@ static void programmable_rot_fetch_config(struct sde_encoder_phys *phys_enc, if (!phys_enc->sde_kms->splash_data.cont_splash_en) { SDE_EVT32(DRMID(phys_enc->parent), f.enable, f.fetch_start); - phys_enc->hw_ctl->ops.get_bitmask_intf( - phys_enc->hw_ctl, &flush_mask, - vid_enc->hw_intf->idx); - phys_enc->hw_ctl->ops.update_pending_flush( - phys_enc->hw_ctl, flush_mask); - + if (!_sde_encoder_phys_is_ppsplit(phys_enc) || + sde_encoder_phys_vid_is_master(phys_enc)) { + phys_enc->hw_ctl->ops.get_bitmask_intf( + phys_enc->hw_ctl, &flush_mask, + vid_enc->hw_intf->idx); + phys_enc->hw_ctl->ops.update_pending_flush( + phys_enc->hw_ctl, flush_mask); + } spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); vid_enc->hw_intf->ops.setup_rot_start(vid_enc->hw_intf, &f); spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); @@ -496,20 +512,6 @@ static void sde_encoder_phys_vid_underrun_irq(void *arg, int irq_idx) phys_enc); } -static bool _sde_encoder_phys_is_ppsplit(struct sde_encoder_phys *phys_enc) -{ - enum sde_rm_topology_name topology; - - if (!phys_enc) - return false; - - topology = sde_connector_get_topology_name(phys_enc->connector); - if (topology == SDE_RM_TOPOLOGY_PPSPLIT) - return true; - - return false; -} - static bool _sde_encoder_phys_is_dual_ctl(struct sde_encoder_phys *phys_enc) { enum sde_rm_topology_name topology; -- GitLab From f9e14f293cdaa22987ac71541561e597df193151 Mon Sep 17 00:00:00 2001 From: Harsh Shah Date: Thu, 12 Jul 2018 16:42:14 -0700 Subject: [PATCH 388/604] msm: camera: cdm: Add log utility for CDM cmd buffers This change adds capability to parse and dump CDM command buffers, which can be used in case of any errors. Change-Id: I71eee7ae9f587bd64e8b63790be602e4af31e643 Signed-off-by: Venkat Chinta Signed-off-by: Vishalsingh Hajeri Signed-off-by: Harsh Shah --- .../msm/camera/cam_cdm/cam_cdm_util.c | 178 +++++++++++++++++- .../msm/camera/cam_cdm/cam_cdm_util.h | 23 ++- 2 files changed, 191 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.c index c8b830ff82ea..a97a51965ae3 100644 --- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.c +++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.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 @@ -22,6 +22,14 @@ #define CAM_CDM_DWORD 4 +#define CAM_CDM_SW_CMD_COUNT 2 +#define CAM_CMD_LENGTH_MASK 0xFFFF +#define CAM_CDM_COMMAND_OFFSET 24 +#define CAM_CDM_REG_OFFSET_MASK 0x00FFFFFF + +#define CAM_CDM_DMI_DATA_HI_OFFSET 8 +#define CAM_CDM_DMI_DATA_LO_OFFSET 12 + static unsigned int CDMCmdHeaderSizes[ CAM_CDM_CMD_PRIVATE_BASE + CAM_CDM_SW_CMD_COUNT] = { 0, /* UNUSED*/ @@ -33,7 +41,7 @@ static unsigned int CDMCmdHeaderSizes[ 2, /* GenerateIRQ*/ 3, /* WaitForEvent*/ 1, /* ChangeBase*/ - 1, /* PERF_CONTINUOUSROL*/ + 1, /* PERF_CONTROL*/ 3, /* DMI32*/ 3, /* DMI64*/ }; @@ -540,3 +548,169 @@ int cam_cdm_util_cmd_buf_write(void __iomem **current_device_base, return ret; } + +static long cam_cdm_util_dump_dmi_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_DMI]; + CAM_INFO(CAM_CDM, "DMI"); + return ret; +} + +static long cam_cdm_util_dump_buff_indirect(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_BUFF_INDIRECT]; + CAM_INFO(CAM_CDM, "Buff Indirect"); + return ret; +} + +static long cam_cdm_util_dump_reg_cont_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + struct cdm_regcontinuous_cmd *p_regcont_cmd; + uint32_t *temp_ptr = cmd_buf_addr; + int i = 0; + + p_regcont_cmd = (struct cdm_regcontinuous_cmd *)temp_ptr; + temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_CONT]; + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_CONT]; + + CAM_INFO(CAM_CDM, "REG_CONT: COUNT: %u OFFSET: 0x%X", + p_regcont_cmd->count, p_regcont_cmd->offset); + + for (i = 0; i < p_regcont_cmd->count; i++) { + CAM_INFO(CAM_CDM, "DATA_%d: 0x%X", i, + *temp_ptr); + temp_ptr++; + ret++; + } + + return ret; +} + +static long cam_cdm_util_dump_reg_random_cmd(uint32_t *cmd_buf_addr) +{ + struct cdm_regrandom_cmd *p_regrand_cmd; + uint32_t *temp_ptr = cmd_buf_addr; + long ret = 0; + int i = 0; + + p_regrand_cmd = (struct cdm_regrandom_cmd *)temp_ptr; + temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_RANDOM]; + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_RANDOM]; + + CAM_INFO(CAM_CDM, "REG_RAND: COUNT: %u", + p_regrand_cmd->count); + + for (i = 0; i < p_regrand_cmd->count; i++) { + CAM_INFO(CAM_CDM, "OFFSET_%d: 0x%X DATA_%d: 0x%X", + i, *temp_ptr & CAM_CDM_REG_OFFSET_MASK, i, + *(temp_ptr + 1)); + temp_ptr += 2; + ret += 2; + } + + return ret; +} + +static long cam_cdm_util_dump_gen_irq_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_GEN_IRQ]; + + CAM_INFO(CAM_CDM, "GEN_IRQ"); + + return ret; +} + +static long cam_cdm_util_dump_wait_event_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_WAIT_EVENT]; + + CAM_INFO(CAM_CDM, "WAIT_EVENT"); + + return ret; +} + +static long cam_cdm_util_dump_change_base_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + struct cdm_changebase_cmd *p_cbase_cmd; + uint32_t *temp_ptr = cmd_buf_addr; + + p_cbase_cmd = (struct cdm_changebase_cmd *)temp_ptr; + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_CHANGE_BASE]; + + CAM_INFO(CAM_CDM, "CHANGE_BASE: 0x%X", + p_cbase_cmd->base); + + return ret; +} + +static long cam_cdm_util_dump_perf_ctrl_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_PERF_CTRL]; + + CAM_INFO(CAM_CDM, "PERF_CTRL"); + + return ret; +} + +void cam_cdm_util_dump_cmd_buf( + uint32_t *cmd_buf_start, uint32_t *cmd_buf_end) +{ + uint32_t *buf_now = cmd_buf_start; + uint32_t cmd = 0; + + if (!cmd_buf_start || !cmd_buf_end) { + CAM_INFO(CAM_CDM, "Invalid args"); + return; + } + + do { + cmd = *buf_now; + cmd = cmd >> CAM_CDM_COMMAND_OFFSET; + + switch (cmd) { + case CAM_CDM_CMD_DMI: + case CAM_CDM_CMD_DMI_32: + case CAM_CDM_CMD_DMI_64: + buf_now += cam_cdm_util_dump_dmi_cmd(buf_now); + break; + case CAM_CDM_CMD_REG_CONT: + buf_now += cam_cdm_util_dump_reg_cont_cmd(buf_now); + break; + case CAM_CDM_CMD_REG_RANDOM: + buf_now += cam_cdm_util_dump_reg_random_cmd(buf_now); + break; + case CAM_CDM_CMD_BUFF_INDIRECT: + buf_now += cam_cdm_util_dump_buff_indirect(buf_now); + break; + case CAM_CDM_CMD_GEN_IRQ: + buf_now += cam_cdm_util_dump_gen_irq_cmd(buf_now); + break; + case CAM_CDM_CMD_WAIT_EVENT: + buf_now += cam_cdm_util_dump_wait_event_cmd(buf_now); + break; + case CAM_CDM_CMD_CHANGE_BASE: + buf_now += cam_cdm_util_dump_change_base_cmd(buf_now); + break; + case CAM_CDM_CMD_PERF_CTRL: + buf_now += cam_cdm_util_dump_perf_ctrl_cmd(buf_now); + break; + default: + CAM_INFO(CAM_CDM, "Invalid CMD: 0x%x buf 0x%x", + cmd, *buf_now); + buf_now++; + break; + } + } while (buf_now <= cmd_buf_end); +} diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.h b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.h index 09d0d638c987..8f2b48853ca8 100644 --- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.h +++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.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 @@ -13,13 +13,6 @@ #ifndef _CAM_CDM_UTIL_H_ #define _CAM_CDM_UTIL_H_ -#define CAM_CDM_SW_CMD_COUNT 2 -#define CAM_CMD_LENGTH_MASK 0xFFFF -#define CAM_CDM_COMMAND_OFFSET 24 - -#define CAM_CDM_DMI_DATA_HI_OFFSET 8 -#define CAM_CDM_DMI_DATA_LO_OFFSET 12 - enum cam_cdm_command { CAM_CDM_CMD_UNUSED = 0x0, CAM_CDM_CMD_DMI = 0x1, @@ -158,4 +151,18 @@ void (*cdm_write_genirq)( uint32_t userdata); }; +/** + * cam_cdm_util_log_cmd_bufs() + * + * @brief: Util function to log cdm command buffers + * + * @cmd_buffer_start: Pointer to start of cmd buffer + * @cmd_buffer_end: Pointer to end of cmd buffer + * + */ +void cam_cdm_util_dump_cmd_buf( + uint32_t *cmd_buffer_start, uint32_t *cmd_buffer_end); + + + #endif /* _CAM_CDM_UTIL_H_ */ -- GitLab From 111567509bc4739017f0dac85c1be21f97e200ff Mon Sep 17 00:00:00 2001 From: Harsh Shah Date: Mon, 9 Jul 2018 18:05:48 -0700 Subject: [PATCH 389/604] msm: camera: isp: Fix the return value for CDM timeout error In case CDM submit times out, the return value needs to be error code. Without this change, the error is not propagated and the session continues then causing a wait on requests, adding to the delay of when the error is caught. Change-Id: I670c9916e419876d19e0559645569e0837f9d0ce Signed-off-by: Harsh Shah --- .../platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 2 -- 1 file changed, 2 deletions(-) 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 985d0b0e1662..8d764b043a18 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 @@ -1696,8 +1696,6 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, "config done Success for req_id=%llu", cfg->request_id); } - - rc = 0; } } else { CAM_ERR(CAM_ISP, "No commands to config"); -- GitLab From 42ac38d909369facca56adaa57bcf782ddef7246 Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Fri, 6 Jul 2018 12:42:04 -0700 Subject: [PATCH 390/604] drm: msm: sde: control idle-pc through crtc property Add a crtc idle power-collapse property, so user-mode can control the enable/disable of idle power-collapse. Always reset the idle-pc to original state during crtc disable, user-mode will change the state on crtc enable commit based on the use-case/requirement. Change-Id: Icc55b878a4af340ebc9a8e04f89219195b557bbe Signed-off-by: Veera Sundaram Sankaran --- drivers/gpu/drm/msm/msm_drv.h | 1 + drivers/gpu/drm/msm/sde/sde_crtc.c | 26 +++++++++++++++++++ drivers/gpu/drm/msm/sde/sde_crtc.h | 12 +++++++++ drivers/gpu/drm/msm/sde/sde_encoder.c | 36 +++++++++++++++++++++------ drivers/gpu/drm/msm/sde/sde_encoder.h | 7 ++++++ 5 files changed, 74 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index fcdddb34f925..978aba28a9b1 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -158,6 +158,7 @@ enum msm_mdp_crtc_property { CRTC_PROP_CAPTURE_OUTPUT, CRTC_PROP_ENABLE_SUI_ENHANCEMENT, + CRTC_PROP_IDLE_PC_STATE, /* total # of properties */ CRTC_PROP_COUNT diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index b9c4b52fea07..924ffdfb2225 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -3689,6 +3689,7 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, struct sde_kms *sde_kms; struct sde_crtc_state *cstate; bool is_error, reset_req; + enum sde_crtc_idle_pc_state idle_pc_state; if (!crtc) { SDE_ERROR("invalid argument\n"); @@ -3719,6 +3720,8 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, is_error = _sde_crtc_prepare_for_kickoff_rot(dev, crtc); + idle_pc_state = sde_crtc_get_property(cstate, CRTC_PROP_IDLE_PC_STATE); + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { struct sde_encoder_kickoff_params params = { 0 }; @@ -3734,6 +3737,10 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, crtc->state); if (sde_encoder_prepare_for_kickoff(encoder, ¶ms)) reset_req = true; + + if (idle_pc_state != IDLE_PC_NONE) + sde_encoder_control_idle_pc(encoder, + (idle_pc_state == IDLE_PC_ENABLE) ? true : false); } /* @@ -4233,6 +4240,13 @@ static void sde_crtc_disable(struct drm_crtc *crtc) sde_encoder_register_frame_event_callback(encoder, NULL, NULL); cstate->rsc_client = NULL; cstate->rsc_update = false; + + /* + * reset idle power-collapse to original state during suspend; + * user-mode will change the state on resume, if required + */ + if (sde_kms->catalog->has_idle_pc) + sde_encoder_control_idle_pc(encoder, true); } if (sde_crtc->power_event) @@ -4974,6 +4988,12 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, {CAPTURE_DSPP_OUT, "capture_pp_out"}, }; + static const struct drm_prop_enum_list e_idle_pc_state[] = { + {IDLE_PC_NONE, "idle_pc_none"}, + {IDLE_PC_ENABLE, "idle_pc_enable"}, + {IDLE_PC_DISABLE, "idle_pc_disable"}, + }; + SDE_DEBUG("\n"); if (!crtc || !catalog) { @@ -5053,6 +5073,12 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, "enable_sui_enhancement", 0, 0, U64_MAX, 0, CRTC_PROP_ENABLE_SUI_ENHANCEMENT); + if (catalog->has_idle_pc) + msm_property_install_enum(&sde_crtc->property_info, + "idle_pc_state", 0x0, 0, e_idle_pc_state, + ARRAY_SIZE(e_idle_pc_state), + CRTC_PROP_IDLE_PC_STATE); + if (catalog->has_cwb_support) msm_property_install_enum(&sde_crtc->property_info, "capture_mode", 0, 0, e_cwb_data_points, diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h index 99177b111745..709a51f15618 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.h +++ b/drivers/gpu/drm/msm/sde/sde_crtc.h @@ -58,6 +58,18 @@ enum sde_crtc_output_capture_point { CAPTURE_DSPP_OUT }; +/** + * enum sde_crtc_idle_pc_state: states of idle power collapse + * @IDLE_PC_NONE: no-op + * @IDLE_PC_ENABLE: enable idle power-collapse + * @IDLE_PC_DISABLE: disable idle power-collapse + */ +enum sde_crtc_idle_pc_state { + IDLE_PC_NONE, + IDLE_PC_ENABLE, + IDLE_PC_DISABLE, +}; + /** * @connectors : Currently associated drm connectors for retire event * @num_connectors: Number of associated drm connectors for retire event diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 73864b617cc4..a6643bbe31ae 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -200,7 +200,8 @@ enum sde_enc_rc_states { * @disp_info: local copy of msm_display_info struct * @misr_enable: misr enable/disable status * @misr_frame_count: misr frame count before start capturing the data - * @idle_pc_supported: indicate if idle power collaps is supported + * @idle_pc_enabled: indicate if idle power collapse is enabled + * currently. This can be controlled by user-mode * @rc_lock: resource control mutex lock to protect * virt encoder over various state changes * @rc_state: resource controller state @@ -250,7 +251,7 @@ struct sde_encoder_virt { bool misr_enable; u32 misr_frame_count; - bool idle_pc_supported; + bool idle_pc_enabled; struct mutex rc_lock; enum sde_enc_rc_states rc_state; struct kthread_delayed_work delayed_off_work; @@ -1922,6 +1923,25 @@ static void sde_encoder_input_event_handler(struct input_handle *handle, &sde_enc->input_event_work); } +void sde_encoder_control_idle_pc(struct drm_encoder *drm_enc, bool enable) +{ + struct sde_encoder_virt *sde_enc; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + sde_enc = to_sde_encoder_virt(drm_enc); + + /* return early if there is no state change */ + if (sde_enc->idle_pc_enabled == enable) + return; + + sde_enc->idle_pc_enabled = enable; + + SDE_DEBUG("idle-pc state:%d\n", sde_enc->idle_pc_enabled); + SDE_EVT32(sde_enc->idle_pc_enabled); +} static int sde_encoder_resource_control(struct drm_encoder *drm_enc, u32 sw_event) @@ -1948,7 +1968,7 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, * when idle_pc is not supported, process only KICKOFF, STOP and MODESET * events and return early for other events (ie wb display). */ - if (!sde_enc->idle_pc_supported && + if (!sde_enc->idle_pc_enabled && (sw_event != SDE_ENC_RC_EVENT_KICKOFF && sw_event != SDE_ENC_RC_EVENT_PRE_MODESET && sw_event != SDE_ENC_RC_EVENT_POST_MODESET && @@ -1956,9 +1976,9 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, sw_event != SDE_ENC_RC_EVENT_PRE_STOP)) return 0; - SDE_DEBUG_ENC(sde_enc, "sw_event:%d, idle_pc_supported:%d\n", sw_event, - sde_enc->idle_pc_supported); - SDE_EVT32_VERBOSE(DRMID(drm_enc), sw_event, sde_enc->idle_pc_supported, + SDE_DEBUG_ENC(sde_enc, "sw_event:%d, idle_pc:%d\n", + sw_event, sde_enc->idle_pc_enabled); + SDE_EVT32_VERBOSE(DRMID(drm_enc), sw_event, sde_enc->idle_pc_enabled, sde_enc->rc_state, SDE_EVTLOG_FUNC_ENTRY); switch (sw_event) { @@ -2348,7 +2368,7 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, break; } - SDE_EVT32_VERBOSE(DRMID(drm_enc), sw_event, sde_enc->idle_pc_supported, + SDE_EVT32_VERBOSE(DRMID(drm_enc), sw_event, sde_enc->idle_pc_enabled, sde_enc->rc_state, SDE_EVTLOG_FUNC_EXIT); return 0; } @@ -4483,7 +4503,7 @@ static int sde_encoder_setup_display(struct sde_encoder_virt *sde_enc, if ((disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) || (disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE)) - sde_enc->idle_pc_supported = sde_kms->catalog->has_idle_pc; + sde_enc->idle_pc_enabled = sde_kms->catalog->has_idle_pc; mutex_lock(&sde_enc->enc_lock); for (i = 0; i < disp_info->num_of_h_tiles && !ret; i++) { diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h index 42b9e5880e05..c40db41adecf 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder.h @@ -257,4 +257,11 @@ int sde_encoder_display_failure_notification(struct drm_encoder *enc); */ int sde_encoder_in_clone_mode(struct drm_encoder *enc); +/** + * sde_encoder_control_idle_pc - control enable/disable of idle power collapse + * @drm_enc: Pointer to drm encoder structure + * @enable: enable/disable flag + */ +void sde_encoder_control_idle_pc(struct drm_encoder *enc, bool enable); + #endif /* __SDE_ENCODER_H__ */ -- GitLab From 8ee1cfa1f8ae1fa28ee555fe69e9600919b769a1 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Tue, 15 May 2018 22:18:23 +0530 Subject: [PATCH 391/604] drm/msm/sde: fix arguments of usleep_range function usleep_range is getting called with wrong arguments which in turn is causing the thread to go to infinite sleep. This patch fixes all such instances in DRM display driver. Change-Id: Icf327267fdc6104d4325be00ff9f925782fcc4bd Signed-off-by: Sandeep Panda --- drivers/gpu/drm/msm/dsi-staging/dsi_panel.c | 2 +- drivers/gpu/drm/msm/sde_io_util.c | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index dab85f4fa6ee..fedbddae212b 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -377,7 +377,7 @@ static int dsi_panel_reset(struct dsi_panel *panel) if (r_config->sequence[i].sleep_ms) usleep_range(r_config->sequence[i].sleep_ms * 1000, - r_config->sequence[i].sleep_ms * 1000); + (r_config->sequence[i].sleep_ms * 1000) + 100); } if (gpio_is_valid(panel->bl_config.en_gpio)) { diff --git a/drivers/gpu/drm/msm/sde_io_util.c b/drivers/gpu/drm/msm/sde_io_util.c index d5a438e5f26c..f8300109b6fd 100644 --- a/drivers/gpu/drm/msm/sde_io_util.c +++ b/drivers/gpu/drm/msm/sde_io_util.c @@ -1,4 +1,5 @@ -/* 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 @@ -230,7 +231,7 @@ int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable) need_sleep = !regulator_is_enabled(in_vreg[i].vreg); if (in_vreg[i].pre_on_sleep && need_sleep) usleep_range(in_vreg[i].pre_on_sleep * 1000, - in_vreg[i].pre_on_sleep * 1000); + (in_vreg[i].pre_on_sleep * 1000) + 10); rc = regulator_set_load(in_vreg[i].vreg, in_vreg[i].enable_load); if (rc < 0) { @@ -242,7 +243,7 @@ int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable) rc = regulator_enable(in_vreg[i].vreg); if (in_vreg[i].post_on_sleep && need_sleep) usleep_range(in_vreg[i].post_on_sleep * 1000, - in_vreg[i].post_on_sleep * 1000); + (in_vreg[i].post_on_sleep * 1000) + 10); if (rc < 0) { DEV_ERR("%pS->%s: %s enable failed\n", __builtin_return_address(0), __func__, @@ -254,13 +255,13 @@ int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable) for (i = num_vreg-1; i >= 0; i--) { if (in_vreg[i].pre_off_sleep) usleep_range(in_vreg[i].pre_off_sleep * 1000, - in_vreg[i].pre_off_sleep * 1000); + (in_vreg[i].pre_off_sleep * 1000) + 10); regulator_set_load(in_vreg[i].vreg, in_vreg[i].disable_load); regulator_disable(in_vreg[i].vreg); if (in_vreg[i].post_off_sleep) usleep_range(in_vreg[i].post_off_sleep * 1000, - in_vreg[i].post_off_sleep * 1000); + (in_vreg[i].post_off_sleep * 1000) + 10); } } return rc; @@ -272,13 +273,13 @@ int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable) for (i--; i >= 0; i--) { if (in_vreg[i].pre_off_sleep) usleep_range(in_vreg[i].pre_off_sleep * 1000, - in_vreg[i].pre_off_sleep * 1000); + (in_vreg[i].pre_off_sleep * 1000) + 10); regulator_set_load(in_vreg[i].vreg, in_vreg[i].disable_load); regulator_disable(in_vreg[i].vreg); if (in_vreg[i].post_off_sleep) usleep_range(in_vreg[i].post_off_sleep * 1000, - in_vreg[i].post_off_sleep * 1000); + (in_vreg[i].post_off_sleep * 1000) + 10); } return rc; -- GitLab From e1d64b86fbfe4e69b8e74cde3c9949a9dd8bd0b0 Mon Sep 17 00:00:00 2001 From: Yu Wang Date: Tue, 26 Dec 2017 14:43:21 +0800 Subject: [PATCH 392/604] cnss: notify wlan driver when failed to power up During SSR, if power-up fails, wlan driver will enter ssr_in_progress state, which will block driver unloading, it's not reasonable. To improve this, notify wlan driver about the failure, then driver unloading can be handled properly according to this flag. CRs-Fixed: 2246361 Change-Id: I669cc0137811a991c00ff9e73ebbb2bcf2d621a1 Signed-off-by: Yu Wang --- drivers/net/wireless/cnss/cnss_pci.c | 12 ++++++++---- include/net/cnss.h | 7 +++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index 8797e688241c..211db7f3f963 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -2717,10 +2717,14 @@ static int cnss_powerup(const struct subsys_desc *subsys) cnss_configure_wlan_en_gpio(WLAN_EN_LOW); cnss_wlan_vreg_set(vreg_info, VREG_OFF); if (penv->pdev) { - pr_err("%d: Unregistering pci device\n", __LINE__); - pci_unregister_driver(&cnss_wlan_pci_driver); - penv->pdev = NULL; - penv->pci_register_again = true; + if (wdrv && wdrv->update_status) + wdrv->update_status(penv->pdev, CNSS_SSR_FAIL); + if (!penv->recovery_in_progress) { + pr_err("%d: Unregistering pci device\n", __LINE__); + pci_unregister_driver(&cnss_wlan_pci_driver); + penv->pdev = NULL; + penv->pci_register_again = true; + } } err_wlan_vreg_on: diff --git a/include/net/cnss.h b/include/net/cnss.h index 368d01ecc879..c7f41e343c22 100644 --- a/include/net/cnss.h +++ b/include/net/cnss.h @@ -102,11 +102,14 @@ struct cnss_platform_cap { u32 cap_flag; }; -/* WLAN driver status */ +/* WLAN driver status, keep it aligned with cnss2 */ enum cnss_driver_status { CNSS_UNINITIALIZED, CNSS_INITIALIZED, - CNSS_LOAD_UNLOAD + CNSS_LOAD_UNLOAD, + CNSS_RECOVERY, + CNSS_FW_DOWN, + CNSS_SSR_FAIL, }; enum cnss_runtime_request { -- GitLab From e5088acc17410ac7669fb6ad5b6e6d7cce5614ad Mon Sep 17 00:00:00 2001 From: Tirupathi Reddy Date: Wed, 4 Jul 2018 11:37:24 +0530 Subject: [PATCH 393/604] ARM: dts: msm: update APC CPR configuration for sdm439 Update APC CPR closed-loop voltage adjustments as per voltage plan. Also update max floor-to-ceiling constant for NOMP voltage corner as per voltage plan. Change-Id: Ic941f26151f524ecda410bb73758543a01082356 Signed-off-by: Tirupathi Reddy --- arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi index 414e8feaa3c7..42c3e83c0118 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi @@ -477,17 +477,22 @@ qcom,cpr-quotient-adjustment = <66 77 66>, /* SVSP/NOM/TUR:30/35/30 mV */ - <(-74) (-57) (-30)>, /* SVSP/NOM/TUR:-34/-26/-14 mV */ + <(-74) 0 (-30)>, /* SVSP/NOM/TUR:-34/0/-14 mV */ <0 0 0>; qcom,cpr-floor-to-ceiling-max-range = - <50000 50000 50000 65000 65000>, - <50000 50000 50000 65000 65000>, - <50000 50000 50000 65000 65000>; + <50000 50000 65000 65000 65000>, + <50000 50000 65000 65000 65000>, + <50000 50000 65000 65000 65000>; qcom,cpr-voltage-ceiling-override = <(-1) (-1) 810000 845000 885000 960000 960000>; + qcom,cpr-virtual-corner-quotient-adjustment = + <0 0 0 0 0>, + <0 0 (-22) 0 0>, /* NOMP: -10 mV */ + <0 0 0 0 0>; + qcom,cpr-enable; }; -- GitLab From e32ee878340ac62b7b7d750534d84635931e39fb Mon Sep 17 00:00:00 2001 From: zijuhu Date: Mon, 16 Jul 2018 14:04:42 +0800 Subject: [PATCH 394/604] ARM: dts: msm: Enable bluetooth for stacked sdxpoorwills Enable bluetooth UART blsp1_uart2b and configure bluetooth RFKILL. CRs-Fixed: 2278327 Change-Id: I088f444472d68ba90082f7d1ec3b2d92b57bd587 Signed-off-by: zijuhu --- arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts | 4 ++++ arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi | 8 ++++++++ arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts | 4 ++++ arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi | 8 ++++++++ 4 files changed, 24 insertions(+) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts index 04f11ce9ec7b..fa858c371a7a 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts @@ -20,3 +20,7 @@ "qcom,sdxpoorwills", "qcom,cdp"; qcom,board-id = <1 0x0>; }; + +&blsp1_uart2b_hs { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi index 0f9c8bc422f6..5091d0b548af 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi @@ -21,3 +21,11 @@ &sdhc_1 { cd-gpios = <&tlmm 21 0x1>; }; + +&soc { + bluetooth: bt_qca6174 { + compatible = "qca,qca6174"; + qca,bt-reset-gpio = <&pmxpoorwills_gpios 4 0>; /* BT_EN */ + qca,bt-vdd-pa-supply = <&vreg_wlan>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts index 2377d79cd5b8..a774c8bcea34 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts @@ -20,3 +20,7 @@ "qcom,sdxpoorwills", "qcom,mtp"; qcom,board-id = <8 0x0>; }; + +&blsp1_uart2b_hs { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi index 741203123468..c18d914fd220 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi @@ -21,3 +21,11 @@ &sdhc_1 { cd-gpios = <&tlmm 21 0x1>; }; + +&soc { + bluetooth: bt_qca6174 { + compatible = "qca,qca6174"; + qca,bt-reset-gpio = <&pmxpoorwills_gpios 4 0>; /* BT_EN */ + qca,bt-vdd-pa-supply = <&vreg_wlan>; + }; +}; -- GitLab From cd3caa69c785d36c02a1c38e98eb79cea7563add Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 27 Apr 2017 11:19:00 -0700 Subject: [PATCH 395/604] mm: Silence vmap() allocation failures based on caller gfp_flags If the caller has set __GFP_NOWARN don't print the following message: vmap allocation for size 15736832 failed: use vmalloc= to increase size. This can happen with the ARM/Linux or ARM64/Linux module loader built with CONFIG_ARM{,64}_MODULE_PLTS=y which does a first attempt at loading a large module from module space, then falls back to vmalloc space. Change-Id: Ib907156055959e22a419b79fb424772baea556d0 Acked-by: Michal Hocko Signed-off-by: Florian Fainelli Signed-off-by: Catalin Marinas Git-Commit: 03497d761c55438144fd63534d4223418fdfd345 Git-Repo: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git Signed-off-by: Vinayak Menon --- mm/vmalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 7b3865c18a9b..6b5f0bce0bd2 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -543,7 +543,7 @@ static struct vmap_area *alloc_vmap_area(unsigned long size, } } - if (printk_ratelimit()) + if (!(gfp_mask & __GFP_NOWARN) && printk_ratelimit()) pr_warn("vmap allocation for size %lu failed: use vmalloc= to increase size\n", size); kfree(va); -- GitLab From 0d92314d85c8edc4f587e93843791f1697587954 Mon Sep 17 00:00:00 2001 From: Yuan Zhao Date: Thu, 21 Jun 2018 17:04:07 +0800 Subject: [PATCH 396/604] ARM: dts: msm: Add a new display panel support for SDM710 QRD There is a new display panel, driver IC is HX83112A. SDM710 QRD device can support this panel. So add the initial parameters for the panel. Change-Id: I4b3ac02bb71327c37f578314eaae6f95baf36527 Signed-off-by: Yuan Zhao --- ...l-hx83112a-truly-singlemipi-fhd-video.dtsi | 157 ++++++++++++++++++ .../boot/dts/qcom/sdm670-sde-display.dtsi | 51 +++++- 2 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi 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 new file mode 100644 index 000000000000..e065f002395f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi @@ -0,0 +1,157 @@ +/* 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_hx83112a_truly_video: qcom,mdss_dsi_hx83112a_truly_video { + qcom,mdss-dsi-panel-name = + "hx83112a 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 = <42>; + qcom,mdss-dsi-h-back-porch = <42>; + qcom,mdss-dsi-h-pulse-width = <10>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <15>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <3>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 04 B9 83 11 2A + 39 01 00 00 00 00 09 B1 08 29 29 00 00 4F 54 + 33 + 39 01 00 00 00 00 11 B2 00 02 00 80 70 00 08 + 26 FC 01 00 03 15 A3 87 09 + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 03 D2 2C 2C + 39 01 00 00 00 00 1C B4 01 CE 01 CE 01 CE 0A + CE 0A CE 0A CE 00 FF 00 FF 00 00 22 23 00 + 28 0A 13 14 00 8A + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 0A B4 00 92 12 22 88 12 12 + 00 53 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 04 B6 82 82 E3 + 39 01 00 00 00 00 02 CC 08 + 39 01 00 00 00 00 2B D3 40 00 00 00 00 01 01 + 0A 0A 07 07 00 08 09 09 09 09 32 10 09 00 + 09 32 21 0A 00 0A 32 10 08 00 00 00 00 00 + 00 00 00 00 0B 08 82 + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 09 D3 00 00 19 00 00 0A 00 + 81 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 31 D5 18 18 18 18 18 18 18 + 18 31 31 30 30 2F 2F 31 31 30 30 2F 2F C0 + 18 40 40 01 00 07 06 05 04 03 02 21 20 18 + 18 19 19 18 18 03 03 18 18 18 18 18 18 + 39 01 00 00 00 00 31 D6 18 18 18 18 18 18 18 + 18 31 31 30 30 2F 2F 31 31 30 30 2F 2F C0 + 18 40 40 02 03 04 05 06 07 00 01 20 21 18 + 18 18 18 19 19 20 20 18 18 18 18 18 18 + 39 01 00 00 00 00 19 D8 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 19 D8 AA AA AA AA AA AA AA + AA AA AA AA AA AA AA AA AA AA AA AA AA AA + AA AA AA + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 0D D8 AF FF FA AA BA AA AA + FF FA AA BA AA + 39 01 00 00 00 00 02 BD 03 + 39 01 00 00 00 00 19 D8 AA AA AA AA AA AA AA + AA AA AA AA AA AA AA AA AA AA AA AA AA AA + AA AA AA + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 18 E7 0E 0E 1E 6A 1D 6A 00 + 32 02 02 00 00 02 02 02 05 14 14 32 B9 23 + B9 08 + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 0A E7 02 00 98 01 9A 0D A8 + 0E 01 + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 1E E7 00 00 08 00 01 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 04 00 00 00 00 02 00 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 02 C1 01 + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 3A C1 FF F7 F0 E9 E2 DB D4 + C6 BF B8 B1 AB A5 9F 99 94 8E 8A 85 7C 74 + 6C 65 5F 58 52 4B 47 42 3C 37 31 2C 27 22 + 1C 18 12 0D 08 05 04 02 01 00 27 B9 BE 54 + C6 B8 9C 37 43 3D E5 00 + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 3A C1 FF F7 F0 E9 E2 DB D4 + C6 BF B8 B1 AB A5 9F 99 94 8E 8A 85 7C 74 + 6C 65 5F 58 52 4B 47 42 3C 37 31 2C 27 22 + 1C 18 12 0D 08 05 04 02 01 00 27 B9 BE 54 + C6 B8 9C 37 43 3D E5 00 + 39 01 00 00 00 00 02 BD 03 + 39 01 00 00 00 00 3A C1 FF F7 F0 E9 E2 DB D4 + C6 BF B8 B1 AB A5 9F 99 94 8E 8A 85 7C 74 + 6C 65 5F 58 52 4B 47 42 3C 37 31 2C 27 22 + 1C 18 12 0D 08 05 04 02 01 00 27 B9 BE 54 + C6 B8 9C 37 43 3D E5 00 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 02 E9 C3 + 39 01 00 00 00 00 03 CB 92 01 + 39 01 00 00 00 00 02 E9 3F + 39 01 00 00 00 00 07 C7 70 00 04 E0 33 00 + 39 01 00 00 00 00 03 51 0F FF + 39 01 00 00 00 00 02 53 24 + 39 01 00 00 00 00 02 55 00 + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 96 00 02 11 00 + 05 01 00 00 32 00 02 29 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 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/sdm670-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi index a74337339eb2..ac81ba443fa5 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi @@ -27,6 +27,7 @@ #include "dsi-panel-rm67195-amoled-fhd-cmd.dtsi" #include "dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi" #include "dsi-panel-hx8399-truly-singlemipi-fhd-video.dtsi" +#include "dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi" #include &soc { @@ -489,7 +490,30 @@ ibb-supply = <&lcdb_ncp_vreg>; }; - ext_dsi_bridge_display: qcom,dsi-display@17 { + dsi_hx83112a_truly_video_display: qcom,dsi-display@17 { + compatible = "qcom,dsi-display"; + label = "dsi_hx83112a_truly_video_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + 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 10 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + + qcom,dsi-panel = <&dsi_hx83112a_truly_video>; + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + ext_dsi_bridge_display: qcom,dsi-display@18 { compatible = "qcom,dsi-display"; label = "ext_dsi_bridge_display"; qcom,display-type = "primary"; @@ -894,3 +918,28 @@ }; }; }; + +&dsi_hx83112a_truly_video { + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x30>; + + qcom,mdss-dsi-min-refresh-rate = <55>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + 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 = [00 1f 08 08 24 22 08 + 08 05 02 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; -- GitLab From ee01e5b34d7f4e7c116a9b1fca76709ef49229d4 Mon Sep 17 00:00:00 2001 From: Shadab Naseem Date: Mon, 16 Jul 2018 10:54:26 +0530 Subject: [PATCH 397/604] defconfig: msm: Enable remaining configs for sdm670 32 bit Enable HIGHMEM for memory support that are more than 768MB for sdm670 32 bit. Enable power reset configs for reboot into fastboot and download mode for sdm670 32 bit. Enable audio configs for sound card to be detected for sdm670 32 bit. Enable CONFIG_ARM_MODULE_PLTS for sdm670 32 bit. Change-Id: I017f9e480a4f0a438f222636f3681957bf249bbd Signed-off-by: Shadab Naseem --- arch/arm/configs/sdm670_defconfig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/configs/sdm670_defconfig b/arch/arm/configs/sdm670_defconfig index 2fda0e2d1967..082a53a7c4ec 100644 --- a/arch/arm/configs/sdm670_defconfig +++ b/arch/arm/configs/sdm670_defconfig @@ -63,6 +63,8 @@ CONFIG_NR_CPUS=8 CONFIG_ARM_PSCI=y CONFIG_PREEMPT=y CONFIG_AEABI=y +CONFIG_HIGHMEM=y +CONFIG_ARM_MODULE_PLTS=y CONFIG_CLEANCACHE=y CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y @@ -236,6 +238,7 @@ CONFIG_RFKILL=y CONFIG_IPC_ROUTER=y CONFIG_IPC_ROUTER_SECURITY=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_AQT_REGMAP=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y CONFIG_ZRAM=y @@ -312,6 +315,9 @@ CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y CONFIG_PINCTRL_SDM670=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y CONFIG_POWER_SUPPLY=y CONFIG_QPNP_FG_GEN3=y CONFIG_SMB1355_SLAVE_CHARGER=y @@ -363,6 +369,7 @@ CONFIG_LOGO=y # CONFIG_LOGO_LINUX_VGA16 is not set CONFIG_SOUND=y CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y CONFIG_SND_USB_AUDIO=y CONFIG_SND_USB_AUDIO_QMI=y CONFIG_SND_SOC=y -- GitLab From 29130252d2cffa38b5a889db71feeb75daa222ae Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Mon, 16 Jul 2018 11:09:43 +0530 Subject: [PATCH 398/604] msm: camera: icp: icp log modification ICP log message is accessing the freed memory in the release function. Modified the log message. Change-Id: Ibf5b17d329b4a4bb9190cf4358386f8cc6974a89 Signed-off-by: Ravikishore Pampana --- .../msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 3 +-- 1 file changed, 1 insertion(+), 2 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 747c487bc93b..d32d4b69938f 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 @@ -3940,8 +3940,7 @@ static int cam_icp_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) if ((!hw_mgr->bps_ctxt_cnt || !hw_mgr->ipe_ctxt_cnt)) cam_icp_device_timer_stop(hw_mgr); - CAM_DBG(CAM_ICP, "Release done for ctx_id %d dev %d", ctx_id, - ctx_data->icp_dev_acquire_info->dev_type); + CAM_DBG(CAM_ICP, "Release done for ctx_id %d", ctx_id); return rc; } -- GitLab From 9276c20f6035f0aedaa64ca8b5dbc5309e1d6778 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Tue, 3 Jul 2018 13:27:10 -0700 Subject: [PATCH 399/604] msm: camera: cpas: Update logic for reading hw version at runtime This change will read the hw version and assign the cpas hw version at runtime. This change help to remove DT entry for every hw iteration. Change-Id: I3c3ad3b2bab1735b308e21e6e0ffb9780cdc3270 Signed-off-by: Jigarkumar Zala --- .../msm/camera/cam_cpas/cam_cpas_hw.c | 25 ------------ .../msm/camera/cam_cpas/cam_cpas_soc.c | 12 ------ .../msm/camera/cam_cpas/cam_cpas_soc.h | 2 - .../camera/cam_cpas/cpas_top/cam_cpastop_hw.c | 39 +++++++++++++++++-- 4 files changed, 35 insertions(+), 43 deletions(-) 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 51b11b7fb267..407462d42605 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 @@ -1506,27 +1506,6 @@ static int cam_cpas_util_get_internal_ops(struct platform_device *pdev, return rc; } -static int cam_cpas_util_get_hw_version(struct platform_device *pdev, - struct cam_hw_soc_info *soc_info) -{ - struct device_node *of_node = pdev->dev.of_node; - int rc; - - soc_info->hw_version = 0; - - rc = of_property_read_u32(of_node, - "qcom,cpas-hw-ver", &soc_info->hw_version); - - CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_info->hw_version); - - if (rc) { - CAM_ERR(CAM_CPAS, "failed to get CPAS HW Version rc=%d", rc); - return -EINVAL; - } - - return rc; -} - int cam_cpas_hw_probe(struct platform_device *pdev, struct cam_hw_intf **hw_intf) { @@ -1669,10 +1648,6 @@ int cam_cpas_hw_probe(struct platform_device *pdev, if (rc) goto axi_cleanup; - rc = cam_cpas_util_get_hw_version(pdev, &cpas_hw->soc_info); - if (rc) - goto axi_cleanup; - *hw_intf = cpas_hw_intf; return 0; diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c index 3fee45f49ff4..11a2afcf3a64 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c +++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c @@ -44,18 +44,6 @@ int cam_cpas_get_custom_dt_info(struct platform_device *pdev, return rc; } - - soc_private->hw_version = 0; - rc = of_property_read_u32(of_node, - "qcom,cpas-hw-ver", &soc_private->hw_version); - if (rc) { - CAM_ERR(CAM_CPAS, "device %s failed to read cpas-hw-ver", - pdev->name); - return rc; - } - - CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_private->hw_version); - soc_private->camnoc_axi_min_ib_bw = 0; rc = of_property_read_u64(of_node, "camnoc-axi-min-ib-bw", diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h index 9d8c25d2b624..d92e1add0557 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h +++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h @@ -34,7 +34,6 @@ struct cam_cpas_vdd_ahb_mapping { * struct cam_cpas_private_soc : CPAS private DT info * * @arch_compat: ARCH compatible string - * @hw_version: Camera HW version * @client_id_based: Whether clients are id based * @num_clients: Number of clients supported * @client_name: Client names @@ -52,7 +51,6 @@ struct cam_cpas_vdd_ahb_mapping { */ struct cam_cpas_private_soc { const char *arch_compat; - uint32_t hw_version; bool client_id_based; uint32_t num_clients; const char *client_name[CAM_CPAS_MAX_CLIENTS]; 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 93e4b3678db3..22c4021eeca5 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 @@ -76,6 +76,38 @@ static int cam_cpastop_get_hw_info(struct cam_hw_info *cpas_hw, hw_caps->cpas_version.major, hw_caps->cpas_version.minor, hw_caps->cpas_version.incr, hw_caps->camera_capability); + soc_info->hw_version = CAM_CPAS_TITAN_NONE; + + if ((hw_caps->camera_version.major == 1) && + (hw_caps->camera_version.minor == 7) && + (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_170_V100; + else if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 1) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_170_V110; + else if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 2) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_170_V120; + } else if ((hw_caps->camera_version.major == 1) && + (hw_caps->camera_version.minor == 7) && + (hw_caps->camera_version.incr == 5)) { + 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_175_V100; + else if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 0) && + (hw_caps->cpas_version.incr == 1)) + soc_info->hw_version = CAM_CPAS_TITAN_175_V101; + } + + CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_info->hw_version); + return 0; } @@ -522,12 +554,11 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw, struct cam_cpas_hw_caps *hw_caps) { int rc = 0; - struct cam_cpas_private_soc *soc_private = - (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; CAM_DBG(CAM_CPAS, "hw_version=0x%x Camera Version %d.%d.%d, cpas version %d.%d.%d", - soc_private->hw_version, + soc_info->hw_version, hw_caps->camera_version.major, hw_caps->camera_version.minor, hw_caps->camera_version.incr, @@ -535,7 +566,7 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw, hw_caps->cpas_version.minor, hw_caps->cpas_version.incr); - switch (soc_private->hw_version) { + switch (soc_info->hw_version) { case CAM_CPAS_TITAN_170_V100: camnoc_info = &cam170_cpas100_camnoc_info; break; -- GitLab From 7bdb2abbdad799c23d8be8398cb449c7c4c3aeda Mon Sep 17 00:00:00 2001 From: shaoxing Date: Mon, 16 Jul 2018 17:25:19 +0800 Subject: [PATCH 400/604] ARM: dts: msm: add dt document for qcs605 ipcamera audio Add dt bindings document for qcs605 ipcamera Audio config. Change-Id: I45661182198c64d575894f076856bde998092b77 Signed-off-by: Shaoxing --- .../bindings/sound/qcom-audio-dev.txt | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index 20cb25b1db9b..6c9d82538c4f 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -3290,3 +3290,97 @@ Example: qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", "SpkrLeft", "SpkrRight"; } + +* QCS605 IPcamera ASoC Machine driver + +Required properties: +- compatible : "qcom,qcs605-asoc-snd-tavil" +- qcom,model : The user-visible name of this sound card. +- qcom,audio-routing : A list of the connections between audio components. +- qcom,msm-gpios : Lists down all the gpio sets that are supported. +- qcom,pinctrl-names : Lists all the possible combinations of the gpio sets +mentioned in qcom,msm-gpios. +- pinctrl-names : The combinations of gpio sets from above that are supported in +the flavor. +- pinctrl-# : Pinctrl states as mentioned in pinctrl-names. + +Optional properties: +- qcom,wsa-disable : Boolean. Disables WSA speaker dailinks from sound node. +- qcom,msm-spk-ext-pa : GPIO which enables external speaker pa. +- qcom,msm-mclk-freq : This property is used to inform machine driver about +mclk frequency needs to be configured for internal and external PA. +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order given. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". +- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target +- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target +- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device +- qcom,cdc-dmic-gpios : phandle for Digital mic clk and data gpios. +- qcom,cdc-sdw-gpios : phandle for soundwire clk and data gpios. +- qcom,pri-mi2s-gpios : phandle for primary MI2S clk, word select and data gpios. +- qcom,sec-mi2s-gpios : phandle for secondary MI2S clk, word select and data gpios. +- qcom,tert-mi2s-gpios : phandle for tertiary MI2S clk, word select and data gpios. +- qcom,quat-mi2s-gpios : phandle for quaternary MI2S clk, word select and data gpios. +- qcom,quin-mi2s-gpios : phandle for quinary MI2S clk, word select and data gpios. + +Example: + sound { + compatible = "qcom,qcs605-asoc-snd-tavil"; + qcom,model = "qcs605-tavil-snd-card"; + qcom,audio-routing = + "RX_BIAS", "INT_MCLK0", + "SPK_RX_BIAS", "INT_MCLK0", + "DMIC1", "DIGITAL_REGULATOR", + "DIGITAL_REGULATOR", "Digital Mic1", + "DMIC2", "DIGITAL_REGULATOR", + "DIGITAL_REGULATOR", "Digital Mic2", + "DMIC3", "DIGITAL_REGULATOR", + "DIGITAL_REGULATOR", "Digital Mic3", + "DMIC4", "DIGITAL_REGULATOR", + "DIGITAL_REGULATOR", "Digital Mic4", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + qcom,msm-mclk-freq = <9600000>; + qcom,msm-gpios = + "slim", + "us_eu_gpio"; + qcom,pinctrl-names = + "all_off", + "slim_act", + "us_eu_gpio_act", + "slim_us_eu_gpio_act"; + pinctrl-names = + "all_off", + "slim_act", + "us_eu_gpio_act", + "slim_us_eu_gpio_act"; + pinctrl-0 = <&cdc_slim_lines_sus &cross_conn_det_sus>; + pinctrl-1 = <&cdc_slim_lines_act &cross_conn_det_sus>; + pinctrl-2 = <&cdc_slim_lines_sus &cross_conn_det_act>; + pinctrl-3 = <&cdc_slim_lines_act &cross_conn_det_act>; + qcom,cdc-dmic-gpios = <&cdc_dmic_gpios>; + + asoc-codec = <&stub_codec>, <&msm_digital_codec>, + <&msm_sdw_codec>; + asoc-codec-names = "msm-stub-codec.1", "msm-dig-codec", + "msm_sdw_codec"; + + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_211_en>, <&wsa881x_212_en>, + <&wsa881x_213_en>, <&wsa881x_214_en>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + } -- GitLab From 833b62a6b25ac36f2d2a68a755db632f26d004d8 Mon Sep 17 00:00:00 2001 From: shaoxing Date: Mon, 9 Jul 2018 14:53:39 +0800 Subject: [PATCH 401/604] ARM: dts: msm: add device tree support for qcs605 LC IP camera Add device tree for qcs605 IP camera. Change-Id: Ic9b92bf1e71d13566a7990576d4fb7c3d0f70cd5 Signed-off-by: Shaoxing --- arch/arm64/boot/dts/qcom/Makefile | 3 + .../dts/qcom/qcs605-lc-ipcamera-audio.dtsi | 360 ++++++++++++++++++ .../dts/qcom/qcs605-lc-ipcamera-overlay.dts | 30 ++ .../boot/dts/qcom/qcs605-lc-ipcamera.dts | 24 ++ .../boot/dts/qcom/qcs605-lc-ipcamera.dtsi | 196 ++++++++++ arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi | 28 ++ 6 files changed, 641 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera-audio.dtsi create mode 100644 arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera.dts create mode 100644 arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera.dtsi diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index e4d62009dd2e..8b0cb9f639d2 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -150,6 +150,7 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) qcs605-mtp-overlay.dtbo \ qcs605-360camera-overlay.dtbo \ qcs605-external-codec-mtp-overlay.dtbo \ + qcs605-lc-ipcamera-overlay.dtbo \ qcs605-lc-mtp-overlay.dtbo \ qcs605-lc-cdp-overlay.dtbo \ sdm710-cdp-overlay.dtbo \ @@ -211,6 +212,7 @@ qcs605-cdp-overlay.dtbo-base := qcs605.dtb qcs605-mtp-overlay.dtbo-base := qcs605.dtb qcs605-external-codec-mtp-overlay.dtbo-base := qcs605.dtb qcs605-lc-mtp-overlay.dtbo-base := qcs605-lc.dtb +qcs605-lc-ipcamera-overlay.dtbo-base := qcs605-lc.dtb qcs605-360camera-overlay.dtbo-base := qcs605.dtb qcs605-lc-cdp-overlay.dtbo-base := qcs605-lc-cdp-base.dtb sdm710-cdp-overlay.dtbo-base := sdm710.dtb @@ -271,6 +273,7 @@ dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \ qcs605-mtp.dtb \ qcs605-cdp.dtb \ qcs605-external-codec-mtp.dtb \ + qcs605-lc-ipcamera.dtb \ qcs605-lc-mtp.dtb \ qcs605-lc-cdp.dtb \ sdm710-mtp.dtb \ diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera-audio.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera-audio.dtsi new file mode 100644 index 000000000000..ab82fe6e3071 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera-audio.dtsi @@ -0,0 +1,360 @@ +/* + * 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 + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT 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 "sdm670-wcd.dtsi" +#include "sdm670-wsa881x.dtsi" +#include "sdm670-lpi.dtsi" +#include + +&tavil_snd { + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "hifi amp", "LINEOUT1", + "hifi amp", "LINEOUT2", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC3", "MIC BIAS2", + "MIC BIAS2", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS2", + "MIC BIAS2", "ANCLeft Headset Mic", + "AMIC5", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,hph-en0-gpio = <&tavil_hph_en0>; + qcom,hph-en1-gpio = <&tavil_hph_en1>; + qcom,msm-mclk-freq = <9600000>; + asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", "msm-ext-disp-audio-codec-rx"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; +}; + +&tasha_snd { + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "hifi amp", "LINEOUT1", + "hifi amp", "LINEOUT2", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC3", "MIC BIAS2", + "MIC BIAS2", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS2", + "MIC BIAS2", "ANCLeft Headset Mic", + "AMIC5", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; + qcom,msm-mclk-freq = <9600000>; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>, + <&wsa881x_213>, <&wsa881x_214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; +}; + +&soc { + wcd_usbc_analog_en1_gpio: msm_cdc_pinctrl_usbc_audio_en1 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd_usbc_analog_en1_active>; + pinctrl-1 = <&wcd_usbc_analog_en1_idle>; + }; + + cdc_pdm_gpios: cdc_pdm_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_pdm_clk_active &cdc_pdm_sync_active + &cdc_pdm_rx0_active &cdc_pdm_rx1_2_active + &cdc_pdm_2_gpios_active>; + pinctrl-1 = <&cdc_pdm_clk_sleep &cdc_pdm_sync_sleep + &cdc_pdm_rx0_sleep &cdc_pdm_rx1_2_sleep + &cdc_pdm_2_gpios_sleep>; + qcom,lpi-gpios; + }; + + cdc_comp_gpios: cdc_comp_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_rx0_comp_active &cdc_rx1_comp_active>; + pinctrl-1 = <&cdc_rx0_comp_sleep &cdc_rx1_comp_sleep>; + qcom,lpi-gpios; + }; + + cdc_dmic_gpios: cdc_dmic_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_dmic12_gpios_active + &cdc_dmic34_gpios_active>; + pinctrl-1 = <&cdc_dmic12_gpios_sleep + &cdc_dmic34_gpios_sleep>; + qcom,lpi-gpios; + }; + + cdc_sdw_gpios: sdw_clk_data_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&sdw_clk_active &sdw_data_active>; + pinctrl-1 = <&sdw_clk_sleep &sdw_data_sleep>; + }; + + wsa_spkr_en1: wsa_spkr_en1_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_1_sd_n_active>; + pinctrl-1 = <&spkr_1_sd_n_sleep>; + }; + + wsa_spkr_en2: wsa_spkr_en2_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_2_sd_n_active>; + pinctrl-1 = <&spkr_2_sd_n_sleep>; + }; + + msm_sdw_codec: msm-sdw-codec@62ec1000 { + status = "okay"; + compatible = "qcom,msm-sdw-codec"; + reg = <0x62ec1000 0x0>; + interrupts = <0 88 0>; + interrupt-names = "swr_master_irq"; + qcom,cdc-sdw-gpios = <&cdc_sdw_gpios>; + + swr_master { + compatible = "qcom,swr-wcd"; + #address-cells = <2>; + #size-cells = <0>; + + wsa881x_211_en: wsa881x_en@20170211 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170211>; + qcom,spkr-sd-n-node = <&wsa_spkr_en1>; + }; + + wsa881x_212_en: wsa881x_en@20170212 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170212>; + qcom,spkr-sd-n-node = <&wsa_spkr_en2>; + }; + + wsa881x_213_en: wsa881x_en@21170213 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170213>; + qcom,spkr-sd-n-node = <&wsa_spkr_en1>; + }; + + wsa881x_214_en: wsa881x_en@21170214 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170214>; + qcom,spkr-sd-n-node = <&wsa_spkr_en2>; + }; + }; + }; + + wcd9xxx_intc: wcd9xxx-irq { + status = "disabled"; + compatible = "qcom,wcd9xxx-irq"; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&tlmm>; + qcom,gpio-connect = <&tlmm 80 0>; + pinctrl-names = "default"; + pinctrl-0 = <&wcd_intr_default>; + }; + + clock_audio_native: audio_ext_clk_native { + status = "disabled"; + compatible = "qcom,audio-ref-clk"; + #clock-cells = <1>; + qcom,lpass-mclk-id = <0x116>; + qcom,codec-mclk-clk-freq = <11289600>; + qcom,audio-ref-clk-gpio = <&lpi_tlmm 19 0>; + pinctrl-names = "sleep", "active"; + pinctrl-0 = <&lpi_mclk0_sleep>; + pinctrl-1 = <&lpi_mclk0_active>; + }; + + clock_audio: audio_ext_clk { + status = "disabled"; + compatible = "qcom,audio-ref-clk"; + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&tasha_mclk_default>; + pinctrl-1 = <&tasha_mclk_default>; + qcom,audio-ref-clk-gpio = <&pm660_gpios 3 0>; + clock-names = "osr_clk"; + clocks = <&pm660_div_clk>; + qcom,node_has_rpm_clock; + #clock-cells = <1>; + }; + + clock_audio_lnbb: audio_ext_clk_lnbb { + status = "disabled"; + compatible = "qcom,audio-ref-clk"; + clock-names = "osr_clk"; + clocks = <&clock_rpmh RPMH_LN_BB_CLK2>; + qcom,node_has_rpm_clock; + #clock-cells = <1>; + }; + + wcd_rst_gpio: msm_cdc_pinctrl@64 { + status = "disabled"; + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&lpi_cdc_reset_active>; + pinctrl-1 = <&lpi_cdc_reset_sleep>; + qcom,lpi-gpios; + }; + + wdsp_mgr: qcom,wcd-dsp-mgr { + compatible = "qcom,wcd-dsp-mgr"; + qcom,wdsp-components = <&wcd934x_cdc 0>, + <&wcd_spi_0 1>, + <&glink_spi_xprt_wdsp 2>; + qcom,img-filename = "cpe_9340"; + }; + + wdsp_glink: qcom,wcd-dsp-glink { + compatible = "qcom,wcd-dsp-glink"; + }; + + tert_mi2s_gpios: tert_mi2s_pinctrl { + status = "disabled"; + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&ter_i2s_data0_active &ter_i2s_data1_active + &ter_i2s_sck_active>; + pinctrl-1 = <&ter_i2s_data0_sleep &ter_i2s_data1_sleep + &ter_i2s_sck_sleep>; + }; +}; + +&slim_aud { + wcd9335: tasha_codec { + status = "disabled"; + compatible = "qcom,tasha-slim-pgd"; + elemental-addr = [00 01 a0 01 17 02]; + + interrupt-parent = <&wcd9xxx_intc>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 + 30>; + + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + + clock-names = "wcd_clk", "wcd_native_clk"; + clocks = <&clock_audio AUDIO_PMI_CLK>, + <&clock_audio_native AUDIO_LPASS_MCLK>; + + cdc-vdd-mic-bias-supply = <&pm660l_bob>; + qcom,cdc-vdd-mic-bias-voltage = <3312000 3312000>; + qcom,cdc-vdd-mic-bias-current = <30400>; + + qcom,cdc-static-supplies = "cdc-vdd-mic-bias"; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-mclk-clk-rate = <9600000>; + qcom,cdc-slim-ifd = "tasha-slim-ifd"; + qcom,cdc-slim-ifd-elemental-addr = [00 00 a0 01 17 02]; + qcom,cdc-dmic-sample-rate = <4800000>; + qcom,cdc-mad-dmic-rate = <600000>; + }; + + wcd934x_cdc: tavil_codec { + status = "disabled"; + compatible = "qcom,tavil-slim-pgd"; + elemental-addr = [00 01 50 02 17 02]; + + interrupt-parent = <&wcd9xxx_intc>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 + 30 31>; + + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + + clock-names = "wcd_clk"; + clocks = <&clock_audio_lnbb AUDIO_PMIC_LNBB_CLK>; + + cdc-vdd-mic-bias-supply = <&pm660l_bob>; + qcom,cdc-vdd-mic-bias-voltage = <3312000 3312000>; + qcom,cdc-vdd-mic-bias-current = <30400>; + + qcom,cdc-static-supplies = "cdc-vdd-mic-bias"; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-mclk-clk-rate = <9600000>; + qcom,cdc-slim-ifd = "tavil-slim-ifd"; + qcom,cdc-slim-ifd-elemental-addr = [00 00 50 02 17 02]; + qcom,cdc-dmic-sample-rate = <4800000>; + qcom,cdc-mad-dmic-rate = <600000>; + + qcom,wdsp-cmpnt-dev-name = "tavil_codec"; + + wcd_spi_0: wcd_spi { + compatible = "qcom,wcd-spi-v2"; + qcom,master-bus-num = <0>; + qcom,chip-select = <0>; + qcom,max-frequency = <24000000>; + qcom,mem-base-addr = <0x100000>; + }; + }; +}; + + diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera-overlay.dts new file mode 100644 index 000000000000..c7912d6aa1be --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera-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 +#include +#include +#include + +#include "qcs605-lc-ipcamera.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 IPC"; + compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp"; + qcom,msm-id = <347 0x0>; + qcom,board-id = <8 6>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera.dts b/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera.dts new file mode 100644 index 000000000000..90dcd7b98b25 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera.dts @@ -0,0 +1,24 @@ +/* + * 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 "qcs605-lc.dtsi" +#include "qcs605-lc-ipcamera.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 IPC"; + compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp"; + qcom,board-id = <8 6>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera.dtsi new file mode 100644 index 000000000000..d6d9a1797f98 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera.dtsi @@ -0,0 +1,196 @@ +/* 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 + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT 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 "qcs605-lc-pmic-overlay.dtsi" +#include "qcs605-lc-camera-sensor-mtp.dtsi" +#include "qcs605-lc-ipcamera-audio.dtsi" + +&qupv3_se9_2uart { + status = "disabled"; +}; + +&qupv3_se12_2uart { + status = "ok"; +}; + +&sdhc_1 { + vdd-supply = <&pm660_l19>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&pm660_l8>; + 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"; +}; + +&tlmm { + sdc2_cd_on: cd_on { + mux { + pins = "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio116"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + sdc2_cd_off: cd_off { + mux { + pins = "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio116"; + drive-strength = <2>; + bias-disable; + }; + }; +}; + +&sdhc_2 { + /* VDD external regulator is enabled/disabled by pm660_l18 regulator */ + vdd-io-supply = <&pm660_l18>; + qcom,vdd-io-voltage-level = <1800000 2960000>; + 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 116 0x1>; + + status = "ok"; +}; + +&usb0 { + dwc3@a600000 { + dr_mode = "host"; + }; +}; + +&icnss { + status = "disabled"; +}; + +&msm_sdw_codec { + status = "disabled"; +}; + +&cdc_pdm_gpios { + status = "disabled"; +}; + +&cdc_comp_gpios { + status = "disabled"; +}; + +&cdc_dmic_gpios { + status = "disabled"; +}; + +&cdc_sdw_gpios { + status = "disabled"; +}; + +&wsa_spkr_en1 { + status = "disabled"; +}; + +&wsa_spkr_en2 { + status = "disabled"; +}; + +&qupv3_se8_spi { + status = "okay"; +}; + +&wcd9xxx_intc { + status = "okay"; +}; + +&wdsp_mgr { + status = "okay"; +}; + +&wdsp_glink { + status = "okay"; +}; + +&slim_aud { + status = "okay"; +}; + +&dai_slim { + status = "okay"; +}; + +&wcd934x_cdc { + status = "okay"; +}; + +&clock_audio_lnbb { + status = "okay"; +}; + +&tavil_snd { + status = "okay"; + compatible = "qcom,qcs605-asoc-snd-tavil"; + qcom,model = "qcs605-tavil-snd-card"; + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "SpkrLeft IN", "SPK1 OUT"; + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft"; +}; + +&soc { + wcd_rst_gpio1: msm_cdc_pinctrl@11 { + compatible = "qcom,msm-cdc-pinctrl"; + qcom,cdc-rst-n-gpio = <&tlmm 11 0>; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_reset_active>; + pinctrl-1 = <&cdc_reset_sleep>; + }; +}; + +&wcd934x_cdc { + /delete-property/ cdc-vdd-mic-bias-supply; + /delete-property/ qcom,cdc-static-supplies; + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio1>; +}; + +&wcd9335 { + /delete-property/ cdc-vdd-mic-bias-supply; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi index 04614292bad8..0453cee11191 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi @@ -1490,6 +1490,34 @@ }; }; + cdc_reset_ctrl { + cdc_reset_sleep: cdc_reset_sleep { + mux { + pins = "gpio11"; + function = "gpio"; + }; + config { + pins = "gpio11"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_reset_active:cdc_reset_active { + mux { + pins = "gpio11"; + function = "gpio"; + }; + config { + pins = "gpio11"; + drive-strength = <8>; + bias-pull-down; + output-high; + }; + }; + }; + /* WSA speaker reset pins */ spkr_1_sd_n { spkr_1_sd_n_sleep: spkr_1_sd_n_sleep { -- GitLab From 5b2c99599d1dcf79ef7dec93c7935d6fc48869db Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Mon, 2 Jul 2018 12:11:59 +0530 Subject: [PATCH 402/604] sched: energy: rebuild sched_domains with actual capacities While sched initialization, sched_domains might have built with default capacity values, and max_{min_}_cap_org_cpu's have updated based on them. After energy probe called, these capacities would change, but max_{min_}cap_org_cpu's still have old values. And using these staled cpus could give wrong start_cpu in finding energy efficient cpu. So rebuild sched_domains, which updates all cpu's group capacities with actual capacities and then build domains again, and update max_{min_}cap_org_cpus as well. Change-Id: I07d58bc849de363c5ed8fb743ab98d3fba727130 Signed-off-by: Lingutla Chandrasekhar --- kernel/sched/energy.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/kernel/sched/energy.c b/kernel/sched/energy.c index 77d8361a7c21..01daf82926ce 100644 --- a/kernel/sched/energy.c +++ b/kernel/sched/energy.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -49,6 +50,17 @@ static void free_resources(void) } } +static int update_topology; + +/* + * Ideally this should be arch specific implementation, + * let's define here to help rebuild sched_domain with new capacities. + */ +int arch_update_cpu_topology(void) +{ + return update_topology; +} + void init_sched_energy_costs(void) { struct device_node *cn, *cp; @@ -273,8 +285,22 @@ static int sched_energy_probe(struct platform_device *pdev) kfree(max_frequencies); - if (is_sge_valid) + if (is_sge_valid) { + /* + * Sched_domains might have built with default cpu capacity + * values on bootup. + * + * Let's rebuild them again with actual cpu capacities. + * And partition_sched_domain() expects update in cpu topology + * to rebuild the domains, so make it satisfied.. + */ + update_topology = 1; + rebuild_sched_domains(); + update_topology = 0; + walt_sched_energy_populated_callback(); + } + dev_info(&pdev->dev, "Sched-energy-costs capacity updated\n"); return 0; -- GitLab From 44c37b7712271ca2dc976f6cf587f53f86fa90ac Mon Sep 17 00:00:00 2001 From: Vijay Viswanath Date: Wed, 4 Jul 2018 14:02:52 +0530 Subject: [PATCH 403/604] mmc: sdhci-msm: Fix the order of removing sdhci-msm functionalities In sdhci_msm_remove API, we are disabling/removing the functionalities in the wrong order. Fix this order. Also a functionality to be removed was missed. Fix this as well, so that unbinding and then binding the platform device will work cleanly. Also remove pm qos requests and debugfs nodes, if they were added during card insertion. Otherwise, unbinding sdhci-msm will later cause crashes in other subsystems, when they unfortunately use pm_qos. Change-Id: I74cd862426c3aad495a89f16881c75d0fe4e0a76 Signed-off-by: Vijay Viswanath --- drivers/mmc/host/sdhci-msm.c | 38 ++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 7d242133528d..111929240975 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -5239,19 +5239,50 @@ static int sdhci_msm_remove(struct platform_device *pdev) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; struct sdhci_msm_pltfm_data *pdata = msm_host->pdata; + int nr_groups = msm_host->pdata->pm_qos_data.cpu_group_map.nr_groups; + int i; int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); - pr_debug("%s: %s\n", dev_name(&pdev->dev), __func__); + pr_debug("%s: %s Enter\n", dev_name(&pdev->dev), __func__); if (!gpio_is_valid(msm_host->pdata->status_gpio)) device_remove_file(&pdev->dev, &msm_host->polling); + + device_remove_file(&pdev->dev, &msm_host->auto_cmd21_attr); device_remove_file(&pdev->dev, &msm_host->msm_bus_vote.max_bus_bw); pm_runtime_disable(&pdev->dev); + if (msm_host->pm_qos_group_enable) { + struct sdhci_msm_pm_qos_group *group; + + for (i = 0; i < nr_groups; i++) + cancel_delayed_work_sync( + &msm_host->pm_qos[i].unvote_work); + + device_remove_file(&msm_host->pdev->dev, + &msm_host->pm_qos_group_enable_attr); + device_remove_file(&msm_host->pdev->dev, + &msm_host->pm_qos_group_status_attr); + + for (i = 0; i < nr_groups; i++) { + group = &msm_host->pm_qos[i]; + pm_qos_remove_request(&group->req); + } + } + + if (msm_host->pm_qos_irq.enabled) { + cancel_delayed_work_sync(&msm_host->pm_qos_irq.unvote_work); + device_remove_file(&pdev->dev, + &msm_host->pm_qos_irq.enable_attr); + device_remove_file(&pdev->dev, + &msm_host->pm_qos_irq.status_attr); + pm_qos_remove_request(&msm_host->pm_qos_irq.req); + } + if (msm_host->pm_qos_wq) destroy_workqueue(msm_host->pm_qos_wq); + sdhci_remove_host(host, dead); - sdhci_pltfm_free(pdev); sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false); @@ -5262,6 +5293,9 @@ static int sdhci_msm_remove(struct platform_device *pdev) sdhci_msm_bus_cancel_work_and_set_vote(host, 0); sdhci_msm_bus_unregister(msm_host); } + + sdhci_pltfm_free(pdev); + return 0; } -- GitLab From 2dba40ba9492d70849b49573c7b03fcf70a8a457 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Tue, 19 Jun 2018 14:19:29 -0700 Subject: [PATCH 404/604] sched: improve trace prints Add the target and backup cpu in find_best_target trace print. During placement print more information about the cpu before skipping it. This helps in understanding why the cpu was not considered for placement. Change-Id: Ifc4de6b1d7495d2d701a92f465f4c81e86f468ea Signed-off-by: Abhijeet Dharmapurikar [clingutla@codeaurora.org: Resolved merge conflicts] Signed-off-by: Lingutla Chandrasekhar --- include/trace/events/sched.h | 24 ++++++++++++++++++------ kernel/sched/fair.c | 8 ++++---- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index b355ebfd7697..b3ec962785f8 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -657,6 +657,10 @@ TRACE_EVENT(sched_cpu_util, __field(unsigned int, capacity_orig ) __field(int, idle_state ) __field(u64, irqload ) + __field(int, online ) + __field(int, isolated ) + __field(int, reserved ) + __field(int, high_irq_load ) ), TP_fast_assign( @@ -669,10 +673,14 @@ TRACE_EVENT(sched_cpu_util, __entry->capacity_orig = capacity_orig_of(cpu); __entry->idle_state = idle_get_state_idx(cpu_rq(cpu)); __entry->irqload = sched_irqload(cpu); + __entry->online = cpu_online(cpu); + __entry->isolated = cpu_isolated(cpu); + __entry->reserved = is_reserved(cpu); + __entry->high_irq_load = sched_cpu_high_irqload(cpu); ), - TP_printk("cpu=%d nr_running=%d cpu_util=%ld cpu_util_cum=%ld capacity_curr=%u capacity=%u capacity_orig=%u idle_state=%d irqload=%llu", - __entry->cpu, __entry->nr_running, __entry->cpu_util, __entry->cpu_util_cum, __entry->capacity_curr, __entry->capacity, __entry->capacity_orig, __entry->idle_state, __entry->irqload) + TP_printk("cpu=%d nr_running=%d cpu_util=%ld cpu_util_cum=%ld capacity_curr=%u capacity=%u capacity_orig=%u idle_state=%d irqload=%llu online=%u isolated=%u reserved=%u high_irq_load=%u", + __entry->cpu, __entry->nr_running, __entry->cpu_util, __entry->cpu_util_cum, __entry->capacity_curr, __entry->capacity, __entry->capacity_orig, __entry->idle_state, __entry->irqload, __entry->online, __entry->isolated, __entry->reserved, __entry->high_irq_load) ); TRACE_EVENT(sched_energy_diff, @@ -1637,10 +1645,11 @@ TRACE_EVENT(sched_find_best_target, TP_PROTO(struct task_struct *tsk, bool prefer_idle, unsigned long min_util, int start_cpu, - int best_idle, int best_active, int target), + int best_idle, int best_active, int target, + int backup_cpu), TP_ARGS(tsk, prefer_idle, min_util, start_cpu, - best_idle, best_active, target), + best_idle, best_active, target, backup_cpu), TP_STRUCT__entry( __array( char, comm, TASK_COMM_LEN ) @@ -1651,6 +1660,7 @@ TRACE_EVENT(sched_find_best_target, __field( int, best_idle ) __field( int, best_active ) __field( int, target ) + __field( int, backup_cpu ) ), TP_fast_assign( @@ -1662,14 +1672,16 @@ TRACE_EVENT(sched_find_best_target, __entry->best_idle = best_idle; __entry->best_active = best_active; __entry->target = target; + __entry->backup_cpu = backup_cpu; ), TP_printk("pid=%d comm=%s prefer_idle=%d start_cpu=%d " - "best_idle=%d best_active=%d target=%d", + "best_idle=%d best_active=%d target=%d backup=%d", __entry->pid, __entry->comm, __entry->prefer_idle, __entry->start_cpu, __entry->best_idle, __entry->best_active, - __entry->target) + __entry->target, + __entry->backup_cpu) ); TRACE_EVENT(sched_group_energy, diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 38fed13db70f..5fedeaa38ce7 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6976,6 +6976,7 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, cpumask_clear_cpu(i, &search_cpus); + trace_sched_cpu_util(i); if (!cpu_online(i) || cpu_isolated(i)) continue; @@ -6987,8 +6988,6 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, if (walt_cpu_high_irqload(i) || is_reserved(i)) continue; - trace_sched_cpu_util(i); - /* * p's blocked utilization is still accounted for on prev_cpu * so prev_cpu will receive a negative bias due to the double @@ -7057,7 +7056,8 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, trace_sched_find_best_target(p, prefer_idle, min_util, cpu, best_idle_cpu, - best_active_cpu, i); + best_active_cpu, + i, -1); return i; } @@ -7278,7 +7278,7 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, trace_sched_find_best_target(p, prefer_idle, min_util, cpu, best_idle_cpu, best_active_cpu, - target_cpu); + target_cpu, *backup_cpu); schedstat_inc(p->se.statistics.nr_wakeups_fbt_count); schedstat_inc(this_rq()->eas_stats.fbt_count); -- GitLab From 1a734c2be99162466a8947ef3923cd1cb201af88 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Tue, 26 Jun 2018 14:24:37 -0700 Subject: [PATCH 405/604] sched/fair: dont run energy calculation unless necessary The placement code calls find_best_target() to find the next cpu, and if possible a backup cpu. After that it does an energy evaluation between next, backup and prev cpu. When find_best_target() finds the next or backup the same as prev, we unnecessarily account for the same cpu twice in energy evaluation. So, drop the backup if its same as prev. If the next cpu is same as the prev, make backup the next candidate. Also replace task_cpu() with stack prev_cpu variable. Change-Id: Ia2dc0c1b059ad515d99e7d66556795b24d30629c Signed-off-by: Abhijeet Dharmapurikar [clingutla@codeaurora.org: Resolved merge conflicts, and include backup cpu check with target cpu.] Signed-off-by: Lingutla Chandrasekhar --- kernel/sched/fair.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 5fedeaa38ce7..536f55581e9c 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6930,6 +6930,7 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, int cpu, i; unsigned int active_cpus_count = 0; int isolated_candidate = -1; + int prev_cpu = task_cpu(p); *backup_cpu = -1; @@ -6982,7 +6983,7 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, isolated_candidate = i; - if (avoid_prev_cpu && i == task_cpu(p)) + if (avoid_prev_cpu && i == prev_cpu) continue; if (walt_cpu_high_irqload(i) || is_reserved(i)) @@ -7234,7 +7235,7 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, if (best_idle_cpu != -1 && !is_packing_eligible(p, target_cpu, fbt_env, active_cpus_count, best_idle_cstate)) { - if (target_cpu == task_cpu(p)) + if (target_cpu == prev_cpu) fbt_env->avoid_prev_cpu = true; target_cpu = best_idle_cpu; @@ -7270,12 +7271,28 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, ? best_active_cpu : best_idle_cpu; - if (target_cpu == -1 && cpu_isolated(task_cpu(p)) && + if (target_cpu == -1 && cpu_isolated(prev_cpu) && isolated_candidate != -1) { target_cpu = isolated_candidate; fbt_env->avoid_prev_cpu = true; } + /* + * - It is possible for target and backup + * to select same CPU - if so, drop backup + * + * - The next step of energy evaluation includes + * prev_cpu. Drop target or backup if it is + * same as prev_cpu. + */ + if (*backup_cpu == target_cpu || *backup_cpu == prev_cpu) + *backup_cpu = -1; + + if (target_cpu == prev_cpu) { + target_cpu = *backup_cpu; + *backup_cpu = -1; + } + trace_sched_find_best_target(p, prefer_idle, min_util, cpu, best_idle_cpu, best_active_cpu, target_cpu, *backup_cpu); -- GitLab From e2d5c2545ad32d12d90726d63d0f08445472d160 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 27 Apr 2017 11:19:01 -0700 Subject: [PATCH 406/604] ARM: Silence first allocation with CONFIG_ARM_MODULE_PLTS=y When CONFIG_ARM_MODULE_PLTS is enabled, the first allocation using the module space fails, because the module is too big, and then the module allocation is attempted from vmalloc space. Silence the first allocation failure in that case by setting __GFP_NOWARN. Change-Id: I94ed69d0cb42b16f68b08354f6f62dc22851d84a Acked-by: Russell King Signed-off-by: Florian Fainelli Signed-off-by: Catalin Marinas Git-commit: 75d24d968af8913f641c612930c96acc5399e427 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git Signed-off-by: Vinayak Menon --- arch/arm/kernel/module.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index 4f14b5ce6535..c2b440b05692 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c @@ -40,8 +40,15 @@ #ifdef CONFIG_MMU void *module_alloc(unsigned long size) { - void *p = __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, - GFP_KERNEL, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE, + gfp_t gfp_mask = GFP_KERNEL; + void *p; + + /* Silence the initial allocation */ + if (IS_ENABLED(CONFIG_ARM_MODULE_PLTS)) + gfp_mask |= __GFP_NOWARN; + + p = __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, + gfp_mask, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE, __builtin_return_address(0)); if (!IS_ENABLED(CONFIG_ARM_MODULE_PLTS) || p) return p; -- GitLab From ad4beb82a470f4fbcbd5ec4dc2466502d15452cd Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Thu, 10 May 2018 19:51:48 +0530 Subject: [PATCH 407/604] msm: adsprpc: handle audio daemon connection to aDSP Mark audio pd services up, if the current state is up during audio pdr registration. Change-Id: Ic3c148e5b7a547decfc5ca823940db6e0208530c Signed-off-by: Tharun Kumar Merugu --- drivers/char/adsprpc.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index d84dea6c2df2..6aa60b1eb5af 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -3512,8 +3512,16 @@ static int fastrpc_get_service_location_notify(struct notifier_block *nb, pdr->domain_list[i].name, pdr->domain_list[i].instance_id, &spd->pdrnb, &curr_state); - if (IS_ERR(spd->pdrhandle)) + if (IS_ERR(spd->pdrhandle)) { pr_err("ADSPRPC: Unable to register notifier\n"); + } else if (curr_state == + SERVREG_NOTIF_SERVICE_STATE_UP_V01) { + pr_info("ADSPRPC: STATE_UP_V01 received\n"); + spd->ispdup = 1; + } else if (curr_state == + SERVREG_NOTIF_SERVICE_STATE_UNINIT_V01) { + pr_info("ADSPRPC: STATE_UNINIT_V01 received\n"); + } break; } } -- GitLab From 5e5dc65a2f11bbe4e30f82e69d2ca46e3fdcb4b3 Mon Sep 17 00:00:00 2001 From: Bhasker Reddy Komatireddy Date: Mon, 16 Jul 2018 17:25:01 +0530 Subject: [PATCH 408/604] ARM: dts: msm: QCS605 overlay camera changes Add support to probe aux sensor in QCS605. Change-Id: I6a957834df089562f39e064fe28e8aa02986829a Signed-off-by: Bhasker Reddy Komatireddy --- .../qcs605-external-codec-mtp-overlay.dts | 46 ++++++++++++++++++- .../dts/qcom/qcs605-external-codec-mtp.dts | 46 ++++++++++++++++++- 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts index 44fae6ab54d8..76088af93732 100644 --- a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts @@ -1,5 +1,5 @@ /* - * 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 @@ -32,3 +32,47 @@ <0x0001001b 0x0102001a 0x0 0x0>, <0x0001001b 0x0201011a 0x0 0x0>; }; + +&cam_cci { + /delete-node/ qcom,cam-sensor@1; + 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>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts index abc3f2da8a25..47ea8f390a78 100644 --- a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts +++ b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts @@ -1,5 +1,5 @@ /* - * 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 @@ -26,3 +26,47 @@ <0x0001001b 0x0102001a 0x0 0x0>, <0x0001001b 0x0201011a 0x0 0x0>; }; + +&cam_cci { + /delete-node/ qcom,cam-sensor@1; + 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>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; -- GitLab From 20b29ea75f4433ae9800f2eb2fd69a27ca2bc03b Mon Sep 17 00:00:00 2001 From: Om Parkash Date: Fri, 6 Jul 2018 20:31:12 +0530 Subject: [PATCH 409/604] ARM64: dts: msm: Correct SDM670 camera sensor EEPROM properties Number of "rgltr-load-current" values don't match No. of regulators, Which causes failure in parsing regulator current parameters from DTSi. CRs-Fixed: 2283389 Change-Id: I43fe2b3666d91d94428360be3d8cac24ccad1ac7 Signed-off-by: Om Parkash --- .../arm64/boot/dts/qcom/sdm670-camera-sensor-360camera.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-360camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-360camera.dtsi index c40fff684e60..1cfa3aeccdaa 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-360camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-360camera.dtsi @@ -1,5 +1,5 @@ /* - * 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 @@ -189,7 +189,7 @@ rgltr-cntrl-support; rgltr-min-voltage = <1352000 1800000 2850000 0 2800000>; rgltr-max-voltage = <1352000 1800000 2850000 0 2800000>; - rgltr-load-current = <105000 0 80000 0>; + rgltr-load-current = <105000 0 80000 0 0>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk1_active @@ -226,7 +226,7 @@ rgltr-cntrl-support; rgltr-min-voltage = <1800000 2850000 1352000 0 2800000>; rgltr-max-voltage = <1800000 2850000 1352000 0 2800000>; - rgltr-load-current = <0 80000 105000 0>; + rgltr-load-current = <0 80000 105000 0 0>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk2_active -- GitLab From fb8ba94778e2515d3818e91cfe2a5e0d8546b718 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Fri, 13 Jul 2018 15:47:51 +0530 Subject: [PATCH 410/604] msm: ipa3: Update holb config on USB DPL ep Once USB DPL consumer ep is configured, there is a chance of IPA hardware getting stalled, if DPL client is not pulling the data over other end. so, set holb discard over USB DPL cons ep to avoid this stall. Change-Id: I520b8c1ec84e03b783677c43670cbb9f904a4b4f Signed-off-by: Mohammed Javid --- drivers/platform/msm/ipa/ipa_v3/ipa_client.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index 5bcd49ec24bf..cfac126312b7 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -63,7 +63,15 @@ int ipa3_enable_data_path(u32 clnt_hdl) IPADBG("Enabling data path\n"); if (IPA_CLIENT_IS_CONS(ep->client)) { memset(&holb_cfg, 0, sizeof(holb_cfg)); - holb_cfg.en = IPA_HOLB_TMR_DIS; + /* + * Set HOLB on USB DPL CONS to avoid IPA stall + * if DPL client is not pulling the data + * on other end from IPA hw. + */ + if (ep->client == IPA_CLIENT_USB_DPL_CONS) + holb_cfg.en = IPA_HOLB_TMR_EN; + else + holb_cfg.en = IPA_HOLB_TMR_DIS; holb_cfg.tmr_val = 0; res = ipa3_cfg_ep_holb(clnt_hdl, &holb_cfg); } -- GitLab From 545e03e8420164506457367959ccf01bd055e1aa Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Tue, 17 Jul 2018 21:38:54 +0530 Subject: [PATCH 411/604] msm: ipa4: Fix dangling pointer dereferencing after NAT del cmd Once after the dma free, assign the pointer with NULL and reset mem allocated flag, to avoid dangling pointer dereferencing. Change-Id: I74a2c2b0589a576de7946e4e2244c7ef5cca975f Signed-off-by: Mohammed Javid --- drivers/platform/msm/ipa/ipa_v3/ipa_nat.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c index 7065e2c270e3..2716d4aa396a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c @@ -1516,6 +1516,8 @@ int ipa3_del_nat_table(struct ipa_ioc_nat_ipv6ct_table_del *del) ipa3_ctx->nat_mem.pdn_mem.size, ipa3_ctx->nat_mem.pdn_mem.base, ipa3_ctx->nat_mem.pdn_mem.phys_base); + ipa3_ctx->nat_mem.pdn_mem.base = NULL; + ipa3_ctx->nat_mem.dev.is_mem_allocated = false; } ipa3_nat_ipv6ct_free_mem(&ipa3_ctx->nat_mem.dev); -- GitLab From 25cb9ebac7c21adf534ff9fc44ba1dfea07e36e2 Mon Sep 17 00:00:00 2001 From: Zhaohong Chen Date: Thu, 12 Jul 2018 15:22:21 +0800 Subject: [PATCH 412/604] msm: camera: fix i2c eeprom probe failed There is a null pointer issue in msm_eeprom_i2c_probe. Fix the null pointer issue referring to msm_eeprom_platform_probe. Change-Id: I8a6f16ba5d143606026a220e5f6981cb18162778 Signed-off-by: Zhaohong Chen --- .../msm/camera_v2/sensor/eeprom/msm_eeprom.c | 305 ++++++++++++------ .../msm/camera_v2/sensor/msm_sensor_driver.c | 6 +- 2 files changed, 204 insertions(+), 107 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c index cd162362e418..f4305ea53c30 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c +++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c @@ -788,11 +788,101 @@ static struct v4l2_subdev_ops msm_eeprom_subdev_ops = { .core = &msm_eeprom_subdev_core_ops, }; +static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl) +{ + int rc = 0, i = 0; + struct msm_eeprom_board_info *eb_info; + struct msm_camera_power_ctrl_t *power_info = + &e_ctrl->eboard_info->power_info; + struct device_node *of_node = NULL; + struct msm_camera_gpio_conf *gconf = NULL; + int8_t gpio_array_size = 0; + uint16_t *gpio_array = NULL; + + eb_info = e_ctrl->eboard_info; + if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE) + of_node = e_ctrl->i2c_client. + spi_client->spi_master->dev.of_node; + else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE) + of_node = e_ctrl->pdev->dev.of_node; + else if (e_ctrl->eeprom_device_type == MSM_CAMERA_I2C_DEVICE) + of_node = e_ctrl->i2c_client.client->dev.of_node; + + if (!of_node) { + pr_err("%s: %d of_node is NULL\n", __func__, __LINE__); + return -ENOMEM; + } + rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg, + &power_info->num_vreg); + if (rc < 0) + return rc; + + if (e_ctrl->userspace_probe == 0) { + rc = msm_camera_get_dt_power_setting_data(of_node, + power_info->cam_vreg, power_info->num_vreg, + power_info); + if (rc < 0) + goto ERROR1; + } + + power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf), + GFP_KERNEL); + if (!power_info->gpio_conf) { + rc = -ENOMEM; + goto ERROR2; + } + gconf = power_info->gpio_conf; + gpio_array_size = of_gpio_count(of_node); + CDBG("%s gpio count %d\n", __func__, gpio_array_size); + + if (gpio_array_size > 0) { + gpio_array = kcalloc(gpio_array_size, sizeof(uint16_t), + GFP_KERNEL); + if (!gpio_array) + goto ERROR3; + for (i = 0; i < gpio_array_size; i++) { + gpio_array[i] = of_get_gpio(of_node, i); + CDBG("%s gpio_array[%d] = %d\n", __func__, i, + gpio_array[i]); + } + + rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR4; + } + + rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR4; + } + kfree(gpio_array); + } + + return rc; +ERROR4: + kfree(gpio_array); +ERROR3: + kfree(power_info->gpio_conf); +ERROR2: + kfree(power_info->cam_vreg); +ERROR1: + kfree(power_info->power_setting); + return rc; +} + static int msm_eeprom_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int rc = 0; + uint32_t temp = 0; struct msm_eeprom_ctrl_t *e_ctrl = NULL; + struct msm_eeprom_board_info *eb_info = NULL; + struct device_node *of_node = client->dev.of_node; + struct msm_camera_power_ctrl_t *power_info = NULL; CDBG("%s E\n", __func__); @@ -804,41 +894,122 @@ static int msm_eeprom_i2c_probe(struct i2c_client *client, e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); if (!e_ctrl) return -ENOMEM; + e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops; e_ctrl->eeprom_mutex = &msm_eeprom_mutex; - CDBG("%s client = 0x%pK\n", __func__, client); - e_ctrl->eboard_info = (struct msm_eeprom_board_info *)(id->driver_data); - if (!e_ctrl->eboard_info) { - pr_err("%s:%d board info NULL\n", __func__, __LINE__); - rc = -EINVAL; - goto ectrl_free; - } - e_ctrl->i2c_client.client = client; + e_ctrl->cal_data.mapdata = NULL; e_ctrl->cal_data.map = NULL; e_ctrl->userspace_probe = 0; - e_ctrl->is_supported = 1; - + e_ctrl->is_supported = 0; + if (!of_node) { + pr_err("%s dev.of_node NULL\n", __func__); + rc = -EINVAL; + goto ectrl_free; + } /* Set device type as I2C */ e_ctrl->eeprom_device_type = MSM_CAMERA_I2C_DEVICE; e_ctrl->i2c_client.i2c_func_tbl = &msm_eeprom_qup_func_tbl; - if (e_ctrl->eboard_info->i2c_slaveaddr != 0) - e_ctrl->i2c_client.client->addr = - e_ctrl->eboard_info->i2c_slaveaddr; + e_ctrl->eboard_info = kzalloc(sizeof( + struct msm_eeprom_board_info), GFP_KERNEL); + if (!e_ctrl->eboard_info) { + rc = -ENOMEM; + goto ectrl_free; + } + eb_info = e_ctrl->eboard_info; + power_info = &eb_info->power_info; + e_ctrl->i2c_client.client = client; + power_info->dev = &client->dev; /*Get clocks information*/ rc = msm_camera_i2c_dev_get_clk_info( &e_ctrl->i2c_client.client->dev, - &e_ctrl->eboard_info->power_info.clk_info, - &e_ctrl->eboard_info->power_info.clk_ptr, - &e_ctrl->eboard_info->power_info.clk_info_size); + &power_info->clk_info, + &power_info->clk_ptr, + &power_info->clk_info_size); if (rc < 0) { pr_err("failed: msm_camera_get_clk_info rc %d", rc); - goto ectrl_free; + goto board_free; + } + + rc = of_property_read_u32(of_node, "cell-index", + &e_ctrl->subdev_id); + CDBG("cell-index %d, rc %d\n", e_ctrl->subdev_id, rc); + if (rc < 0) { + pr_err("failed rc %d\n", rc); + goto board_free; } - /*IMPLEMENT READING PART*/ + rc = of_property_read_string(of_node, "qcom,eeprom-name", + &eb_info->eeprom_name); + CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__, + eb_info->eeprom_name, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + e_ctrl->userspace_probe = 1; + } + + rc = msm_eeprom_get_dt_data(e_ctrl); + if (rc < 0) + goto board_free; + + if (e_ctrl->userspace_probe == 0) { + rc = of_property_read_u32(of_node, "qcom,slave-addr", + &temp); + if (rc < 0) { + pr_err("%s failed rc %d\n", __func__, rc); + goto board_free; + } + + rc = of_property_read_u32(of_node, "qcom,i2c-freq-mode", + &e_ctrl->i2c_freq_mode); + CDBG("qcom,i2c_freq_mode %d, rc %d\n", + e_ctrl->i2c_freq_mode, rc); + if (rc < 0) { + pr_err("%s qcom,i2c-freq-mode read fail. Setting to 0 %d\n", + __func__, rc); + e_ctrl->i2c_freq_mode = 0; + } + if (e_ctrl->i2c_freq_mode >= I2C_MAX_MODES) { + pr_err("%s:%d invalid i2c_freq_mode = %d\n", + __func__, __LINE__, e_ctrl->i2c_freq_mode); + e_ctrl->i2c_freq_mode = 0; + } + eb_info->i2c_slaveaddr = temp; + CDBG("qcom,slave-addr = 0x%X\n", eb_info->i2c_slaveaddr); + eb_info->i2c_freq_mode = e_ctrl->i2c_freq_mode; + + rc = msm_eeprom_parse_memory_map(of_node, &e_ctrl->cal_data); + if (rc < 0) + goto board_free; + + rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc) { + pr_err("failed rc %d\n", rc); + goto memdata_free; + } + + rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data); + if (rc < 0) { + pr_err("%s read_eeprom_memory failed\n", __func__); + goto power_down; + } + CDBG("%s cal_data: %*ph\n", __func__, + e_ctrl->cal_data.num_data, e_ctrl->cal_data.mapdata); + + e_ctrl->is_supported |= msm_eeprom_match_crc(&e_ctrl->cal_data); + + rc = msm_camera_power_down(power_info, + e_ctrl->eeprom_device_type, &e_ctrl->i2c_client); + if (rc) { + pr_err("failed rc %d\n", rc); + goto memdata_free; + } + } else + e_ctrl->is_supported = 1; + /* Initialize sub device */ v4l2_i2c_subdev_init(&e_ctrl->msm_sd.sd, e_ctrl->i2c_client.client, @@ -846,12 +1017,23 @@ static int msm_eeprom_i2c_probe(struct i2c_client *client, v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl); e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops; e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(e_ctrl->msm_sd.sd.name, + ARRAY_SIZE(e_ctrl->msm_sd.sd.name), "msm_eeprom"); media_entity_pads_init(&e_ctrl->msm_sd.sd.entity, 0, NULL); e_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_EEPROM; msm_sd_register(&e_ctrl->msm_sd); - CDBG("%s success result=%d X\n", __func__, rc); + e_ctrl->is_supported = (e_ctrl->is_supported << 1) | 1; + pr_err("%s success result=%d X\n", __func__, rc); return rc; +power_down: + msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); +memdata_free: + kfree(e_ctrl->cal_data.mapdata); + kfree(e_ctrl->cal_data.map); +board_free: + kfree(e_ctrl->eboard_info); ectrl_free: kfree(e_ctrl); probe_failure: @@ -961,91 +1143,6 @@ static int msm_eeprom_match_id(struct msm_eeprom_ctrl_t *e_ctrl) return 0; } -static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl) -{ - int rc = 0, i = 0; - struct msm_eeprom_board_info *eb_info; - struct msm_camera_power_ctrl_t *power_info = - &e_ctrl->eboard_info->power_info; - struct device_node *of_node = NULL; - struct msm_camera_gpio_conf *gconf = NULL; - int8_t gpio_array_size = 0; - uint16_t *gpio_array = NULL; - - eb_info = e_ctrl->eboard_info; - if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE) - of_node = e_ctrl->i2c_client. - spi_client->spi_master->dev.of_node; - else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE) - of_node = e_ctrl->pdev->dev.of_node; - - if (!of_node) { - pr_err("%s: %d of_node is NULL\n", __func__, __LINE__); - return -ENOMEM; - } - rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg, - &power_info->num_vreg); - if (rc < 0) - return rc; - - if (e_ctrl->userspace_probe == 0) { - rc = msm_camera_get_dt_power_setting_data(of_node, - power_info->cam_vreg, power_info->num_vreg, - power_info); - if (rc < 0) - goto ERROR1; - } - - power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf), - GFP_KERNEL); - if (!power_info->gpio_conf) { - rc = -ENOMEM; - goto ERROR2; - } - gconf = power_info->gpio_conf; - gpio_array_size = of_gpio_count(of_node); - CDBG("%s gpio count %d\n", __func__, gpio_array_size); - - if (gpio_array_size > 0) { - gpio_array = kcalloc(gpio_array_size, sizeof(uint16_t), - GFP_KERNEL); - if (!gpio_array) - goto ERROR3; - for (i = 0; i < gpio_array_size; i++) { - gpio_array[i] = of_get_gpio(of_node, i); - CDBG("%s gpio_array[%d] = %d\n", __func__, i, - gpio_array[i]); - } - - rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, - gpio_array, gpio_array_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR4; - } - - rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, - gpio_array, gpio_array_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR4; - } - kfree(gpio_array); - } - - return rc; -ERROR4: - kfree(gpio_array); -ERROR3: - kfree(power_info->gpio_conf); -ERROR2: - kfree(power_info->cam_vreg); -ERROR1: - kfree(power_info->power_setting); - return rc; -} - - static int msm_eeprom_cmm_dts(struct msm_eeprom_board_info *eb_info, struct device_node *of_node) { diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c index 78321812dd99..4bc13d03d36d 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c @@ -513,7 +513,7 @@ static int32_t msm_sensor_create_pd_settings(void *setting, int c, end; struct msm_sensor_power_setting pd_tmp; - pr_err("Generating power_down_setting"); + pr_err("Generating power_down_setting\n"); #ifdef CONFIG_COMPAT if (is_compat_task()) { @@ -603,7 +603,7 @@ static int32_t msm_sensor_get_power_down_settings(void *setting, /* Print power setting */ for (i = 0; i < size_down; i++) { - CDBG("DOWN seq_type %d seq_val %d config_val %ld delay %d", + CDBG("DOWN seq_type %d seq_val %d config_val %ld delay %d\n", pd[i].seq_type, pd[i].seq_val, pd[i].config_val, pd[i].delay); } @@ -657,7 +657,7 @@ static int32_t msm_sensor_get_power_up_settings(void *setting, /* Print power setting */ for (i = 0; i < size; i++) { - CDBG("UP seq_type %d seq_val %d config_val %ld delay %d", + CDBG("UP seq_type %d seq_val %d config_val %ld delay %d\n", pu[i].seq_type, pu[i].seq_val, pu[i].config_val, pu[i].delay); } -- GitLab From 176ee1673e971d3c74cac74ee08989ca15181f3b Mon Sep 17 00:00:00 2001 From: Zhenhua Huang Date: Wed, 18 Jul 2018 13:04:34 +0800 Subject: [PATCH 413/604] arm: show extra regs only for kernel mode Align with 64-bit implementation, It is meaningless to show extra regs for user mode. Also remove show around regs r0->r10. It will cause some NOC errors if showed address is protected by TZ. Change-Id: Ic1d2a985c690de21d46926e310f2b341d8264255 Signed-off-by: Zhenhua Huang --- arch/arm/kernel/process.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 38ad8b956c6b..b876193c9b26 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -150,17 +150,6 @@ static void show_extra_register_data(struct pt_regs *regs, int nbytes) show_data(regs->ARM_sp - nbytes, nbytes * 2, "SP"); show_data(regs->ARM_ip - nbytes, nbytes * 2, "IP"); show_data(regs->ARM_fp - nbytes, nbytes * 2, "FP"); - show_data(regs->ARM_r0 - nbytes, nbytes * 2, "R0"); - show_data(regs->ARM_r1 - nbytes, nbytes * 2, "R1"); - show_data(regs->ARM_r2 - nbytes, nbytes * 2, "R2"); - show_data(regs->ARM_r3 - nbytes, nbytes * 2, "R3"); - show_data(regs->ARM_r4 - nbytes, nbytes * 2, "R4"); - show_data(regs->ARM_r5 - nbytes, nbytes * 2, "R5"); - show_data(regs->ARM_r6 - nbytes, nbytes * 2, "R6"); - show_data(regs->ARM_r7 - nbytes, nbytes * 2, "R7"); - show_data(regs->ARM_r8 - nbytes, nbytes * 2, "R8"); - show_data(regs->ARM_r9 - nbytes, nbytes * 2, "R9"); - show_data(regs->ARM_r10 - nbytes, nbytes * 2, "R10"); set_fs(fs); } @@ -256,7 +245,8 @@ void __show_regs(struct pt_regs *regs) } #endif - show_extra_register_data(regs, 128); + if (!user_mode(regs)) + show_extra_register_data(regs, 128); } void show_regs(struct pt_regs * regs) -- GitLab From 3b7a59d74eb82278ba6848c1ec50f812d9132a4b Mon Sep 17 00:00:00 2001 From: Hardik Arya Date: Mon, 16 Jul 2018 17:15:52 +0530 Subject: [PATCH 414/604] soc: qcom: glink_pkt: Use vfree_atomic in atomic context Calling sleeping function vfree from atomic context may end up in reset. Use vfree_atomic when calling from atomic context. Change-Id: I84cd710604498412bd84e0312ecc7cd1e0905c8a Signed-off-by: Hardik Arya --- drivers/soc/qcom/msm_glink_pkt.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/soc/qcom/msm_glink_pkt.c b/drivers/soc/qcom/msm_glink_pkt.c index a2928791444c..4559f11b7d52 100644 --- a/drivers/soc/qcom/msm_glink_pkt.c +++ b/drivers/soc/qcom/msm_glink_pkt.c @@ -398,7 +398,10 @@ void glink_pkt_notify_tx_done(void *handle, const void *priv, GLINK_PKT_INFO("%s(): priv[%p] pkt_priv[%p] ptr[%p]\n", __func__, priv, pkt_priv, ptr); /* Free Tx buffer allocated in glink_pkt_write */ - kvfree(ptr); + if (is_vmalloc_addr(ptr)) + vfree_atomic(ptr); + else + kfree(ptr); } /** @@ -787,14 +790,20 @@ ssize_t glink_pkt_write(struct file *file, GLINK_PKT_ERR( "%s copy_from_user failed ret[%d] on dev id:%d size %zu\n", __func__, ret, devp->i, count); - kvfree(data); + if (is_vmalloc_addr(data)) + vfree_atomic(data); + else + kfree(data); return -EFAULT; } ret = glink_tx(devp->handle, data, data, count, GLINK_TX_REQ_INTENT); if (ret) { GLINK_PKT_ERR("%s glink_tx failed ret[%d]\n", __func__, ret); - kvfree(data); + if (is_vmalloc_addr(data)) + vfree_atomic(data); + else + kfree(data); return ret; } -- GitLab From fa2e93ea6f5eeecdd354d3518f151ae348e5694f Mon Sep 17 00:00:00 2001 From: Wang Yafei Date: Tue, 3 Jul 2018 17:30:32 +0530 Subject: [PATCH 415/604] input: touchscreen: Add Goodix touchscreen support Add Goodix gt9xx v2.8 driver support for 10" display panel. Squash the following commits: commit 9e50a79cf8aa780343b4e7b4e6ed5c6320215e01 (refs/remotes/goodix/master) Author: Charles Wang Date: Mon Jul 2 14:53:38 2018 +0800 Fix errors and warnings when build on msm-kernel-4.9 - Fix errors and warnings when build on msm-kernel-4.9. - Optimization touch effect. Signed-off-by: Charles Wang commit bd29bac9657816c6f297b3df506d35c18898fdda Author: Charles Wang Date: Fri Mar 2 01:59:08 2018 +0800 Remove debug info form makefile Signed-off-by: Charles Wang commit 1a28cac74d1bfd175796f229cdb695676dd55c1c Author: Charles Wang Date: Fri Mar 2 01:20:07 2018 +0800 Fix some coding style problem Signed-off-by: Wang Yafei commit 09baa4effb7b8379809ee8d9b30575f973f7233f Author: Wang Yafei Date: Fri Feb 2 19:27:42 2018 +0800 Modify dts config properties Signed-off-by: Wang Yafei commit 44446a88e9ccbd6c62cdec43bf3c7682c556cada Author: Wang Yafei Date: Mon Jan 29 20:30:46 2018 +0800 Add reset-pin pinstrl support - Use pinctrl control reset-pin state - Fix user space memory direct access Signed-off-by: Wang Yafei commit 6a5b40a189651121ed3ccdd6474b43116f759bcb Author: Wang Yafei Date: Sat Nov 11 02:03:44 2017 +0800 Modify pinctrl Signed-off-by: Wang Yafei commit 1ef4fbf61982222d0599b21d9d6ab6e017c54759 Author: Wang Yafei Date: Thu Nov 9 02:09:09 2017 +0800 Fix little problem when firmware update failed Signed-off-by: Wang Yafei commit 529f4c536fbd0047bfcb5a31d277aae5706d8e4f Author: Wang Yafei Date: Wed Nov 8 05:03:42 2017 +0800 Fix Kconfig problems Signed-off-by: Wang Yafei commit 877e4b186d597f1a53ed35a2ba2fb7a2debde063 Author: Wang Yafei Date: Tue Nov 7 05:29:48 2017 +0800 Add Goodix gt9xx v2.8 driver Signed-off-by: Wang Yafei commit ca7a8083ab72ab110919223c3a32e6f814dbbe9c Author: Wang Yafei Date: Tue Nov 7 05:12:11 2017 +0800 Add apq8053-dragon dts file Signed-off-by: Wang Yafei commit 6bd539a42db3a518ca10841d829be93f9d524d56 Author: Wang Yafei Date: Tue Nov 7 03:38:36 2017 +0800 first commit Signed-off-by: Wang Yafei Change-Id: I559e3ecc28e86b9de98721d02f46bc782e96aae6 Git-commit: 9e50a79cf8aa780343b4e7b4e6ed5c6320215e01 Git-repo: https://github.com/goodix/msm-3.18 Signed-off-by: Venkataraman Nerellapalli --- .../input/touchscreen/git9xx/gt9xx.txt | 99 + drivers/input/touchscreen/Kconfig | 12 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/gt9xx_v2.8/Kconfig | 36 + drivers/input/touchscreen/gt9xx_v2.8/Makefile | 7 + .../touchscreen/gt9xx_v2.8/goodix_tool.c | 529 ++++ drivers/input/touchscreen/gt9xx_v2.8/gt9xx.c | 2678 +++++++++++++++++ drivers/input/touchscreen/gt9xx_v2.8/gt9xx.h | 375 +++ .../touchscreen/gt9xx_v2.8/gt9xx_update.c | 2090 +++++++++++++ 9 files changed, 5827 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/git9xx/gt9xx.txt create mode 100644 drivers/input/touchscreen/gt9xx_v2.8/Kconfig create mode 100644 drivers/input/touchscreen/gt9xx_v2.8/Makefile create mode 100644 drivers/input/touchscreen/gt9xx_v2.8/goodix_tool.c create mode 100644 drivers/input/touchscreen/gt9xx_v2.8/gt9xx.c create mode 100644 drivers/input/touchscreen/gt9xx_v2.8/gt9xx.h create mode 100644 drivers/input/touchscreen/gt9xx_v2.8/gt9xx_update.c diff --git a/Documentation/devicetree/bindings/input/touchscreen/git9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/git9xx/gt9xx.txt new file mode 100644 index 000000000000..ba61a2fcfa23 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/git9xx/gt9xx.txt @@ -0,0 +1,99 @@ +Goodix GT9xx series touch controller + +Required properties: + + - compatible : Should be "goodix,gt9xx" + - reg : I2C slave address of the device. + - interrupt-parent : Parent of interrupt. + - interrupts : Configuration of touch panel controller interrupt + GPIO. + - goodix,product-id : Product identification of the controller. + - interrupt-gpios : Interrupt gpio which is to provide interrupts to + host, same as "interrupts" node. + - reset-gpios : Reset gpio to control the reset of chip. + - goodix,display-coords : Display coordinates in pixels. It is a four + tuple consisting of min x, min y, max x and + max y values. + +Optional properties: + + - avdd-supply : Power supply needed to power up the device, this is + for fixed voltage external regulator. + - vdd-supply : Power supply needed to power up the device, when use + external regulator, do not add this property. + - vcc-i2c-supply : Power source required to power up i2c bus. + GT9xx series can provide 1.8V from internal + LDO, add this properties base on hardware + design. + - goodix,panel-coords : Panel coordinates for the chip in pixels. + It is a four tuple consisting of min x, + min y, max x and max y values. + - goodix,i2c-pull-up : To specify pull up is required. + - goodix,force-update : To specify force update is allowed. + - goodix,enable-power-off : Power off touchscreen during suspend. + - goodix,button-map : Button map of key codes. The number of key codes + depend on panel. + - goodix,cfg-data0 : Touch screen controller config data group 0. Ask vendor + to provide that. + Driver supports maximum six config groups. If more than one + groups are defined, driver will select config group depending + on hardware configuration. If only config group 0 is defined, + it will be used for all hardware configurations. + Touch screen controller will use its onchip default config data + if this property is not present. + - goodix,cfg-data1 : Touch screen controller config data group 1. Ask vendor + to provide that. + - goodix,cfg-data2 : Touch screen controller config data group 2. Ask vendor + to provide that. + - goodix,cfg-data3 : Touch screen controller config data group 3. Ask vendor + to provide that. + - goodix,cfg-data4 : Touch screen controller config data group 4. Ask vendor + to provide that. + - goodix,cfg-data5 : Touch screen controller config data group 5. Ask vendor + to provide that. + - goodix,fw-name : Touch screen controller firmware file name. + - goodix,slide-wakeup : To specify slide-wakeup property is enabled or not. + - goodix,dbl-clk-wakeup : To specify dbl-clk-wakeup property is enabled or not. + - goodix,change-x2y : To specify change-x2y property is enabled or not. + - goodix,driver-send-cfg : To specify driver-send-cfg property is enabled or not. + - goodix,have-touch-key : To specify have-touch-key property is enabled or not. + - goodix,with-pen : To specify with-pen property is enabled or not. +Example: +i2c@f9927000 { + goodix@5d { + compatible = "goodix,gt9xx"; + reg = <0x5d>; + interrupt-parent = <&msmgpio>; + interrupts = <17 0x2008>; + reset-gpios = <&msmgpio 16 0x00>; + interrupt-gpios = <&msmgpio 17 0x00>; + avdd-supply = <&tp_power>; + goodix,panel-coords = <0 0 720 1200>; + goodix,display-coords = <0 0 720 1080>; + goodix,button-map= <158 102 139>; + goodix,product-id = "915"; + goodix,cfg-data0 = [ + 41 D0 02 00 05 0A 05 01 01 08 + 12 58 50 41 03 05 00 00 00 00 + 00 00 00 00 00 00 00 8C 2E 0E + 28 24 73 13 00 00 00 83 03 1D + 40 02 00 00 00 03 64 32 00 00 + 00 1A 38 94 C0 02 00 00 00 04 + 9E 1C 00 8D 20 00 7A 26 00 6D + 2C 00 60 34 00 60 10 38 68 00 + F0 50 35 FF FF 27 00 00 00 00 + 00 01 1B 14 0C 14 00 00 01 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 02 04 06 08 0A 0C 0E 10 + 12 14 16 18 1A 1C FF FF FF FF + FF FF FF FF FF FF FF FF FF FF + FF FF 00 02 04 06 08 0A 0C 0F + 10 12 13 14 16 18 1C 1D 1E 1F + 20 21 22 24 26 28 29 2A FF FF + FF FF FF FF FF FF FF 22 22 22 + 22 22 22 FF 07 01]; + goodix,fw_name = "gtp_fw.bin"; + goodix,have-touch-key; + goodix,driver-send-cfg; + }; +}; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 6c4156a5fe67..e9c1d696f8f4 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1279,6 +1279,18 @@ config FT_SECURE_TOUCH If unsure, say N. +config TOUCHSCREEN_GT9XX_v28 + bool "Goodix touchpanel GT9xx_v28 series" + depends on I2C + help + Say Y here if you have a Goodix GT9xx_v28 touchscreen. + Gt9xx controllers are multi touch controllers which can + report 5 touches at a time. + + If unsure, say N. + +source "drivers/input/touchscreen/gt9xx_v2.8/Kconfig" + config TOUCHSCREEN_HIMAX_CHIPSET bool "Himax touchpanel CHIPSET" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index a5952cab1e75..c8e01040bf19 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -105,3 +105,4 @@ obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_touch/ obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET) += hxchipset/ +obj-$(CONFIG_TOUCHSCREEN_GT9XX_v28) += gt9xx_v2.8/ \ No newline at end of file diff --git a/drivers/input/touchscreen/gt9xx_v2.8/Kconfig b/drivers/input/touchscreen/gt9xx_v2.8/Kconfig new file mode 100644 index 000000000000..7046cc9011a5 --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_v2.8/Kconfig @@ -0,0 +1,36 @@ +# +# Goodix GT9xx Touchscreen driver +# +config TOUCHSCREEN_GT9XX_v28 + bool "Goodix touchpanel GT9xx series" + depends on I2C + help + Enable this for support Goodix GT9xx_v28 driver. + + Say Y here if you have a Goodix GT9xx touchscreen + controller. + + If unsure, say N. + +config TOUCHSCREEN_GT9XX_UPDATE + tristate "Goodix GT9xx touch controller auto update support" + depends on TOUCHSCREEN_GT9XX_v28 + help + Enable this for support firmware update. + + Say Y here if you want update touch controller + firmware. + + If unsure, say N. + +config TOUCHSCREEN_GT9XX_TOOL + tristate "Goodix GT9xx Tools for debuging" + depends on TOUCHSCREEN_GT9XX_v28 + help + This implement interface support for Goodix GT9xx + touchscreen debug. + + Say Y here if you want to have a Android app debug interface + to your system. + + If unsure, say N. diff --git a/drivers/input/touchscreen/gt9xx_v2.8/Makefile b/drivers/input/touchscreen/gt9xx_v2.8/Makefile new file mode 100644 index 000000000000..6c1c4042ecfa --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_v2.8/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the Goodix gt9xx touchscreen driver. +# +#subdir-ccflags-y += -DDEBUG +obj-$(CONFIG_TOUCHSCREEN_GT9XX_v28) += gt9xx.o +obj-$(CONFIG_TOUCHSCREEN_GT9XX_UPDATE) += gt9xx_update.o +obj-$(CONFIG_TOUCHSCREEN_GT9XX_TOOL) += goodix_tool.o diff --git a/drivers/input/touchscreen/gt9xx_v2.8/goodix_tool.c b/drivers/input/touchscreen/gt9xx_v2.8/goodix_tool.c new file mode 100644 index 000000000000..7db5ae25488b --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_v2.8/goodix_tool.c @@ -0,0 +1,529 @@ +/* + * Goodix GT9xx touchscreen driver + * + * Copyright (C) 2016 - 2017 Goodix. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * but WITHOUT 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 "gt9xx.h" + +#define DATA_LENGTH_UINT 512 +#define CMD_HEAD_LENGTH (sizeof(struct st_cmd_head) - sizeof(u8 *)) +static char procname[20] = {0}; + +#pragma pack(1) +struct st_cmd_head { + u8 wr; /*write read flag 0:R 1:W 2:PID 3:*/ + u8 flag; /*0:no need flag/int 1: need flag 2:need int*/ + u8 flag_addr[2]; /*flag address*/ + u8 flag_val; /*flag val*/ + u8 flag_relation; /*flag_val:flag 0:not equal 1:equal 2:> 3:<*/ + u16 circle; /*polling cycle*/ + u8 times; /*plling times*/ + u8 retry; /*I2C retry times*/ + u16 delay; /*delay before read or after write*/ + u16 data_len; /*data length*/ + u8 addr_len; /*address length*/ + u8 addr[2]; /*address*/ + u8 res[3]; /*reserved*/ + u8 *data; }; /*data pointer*/ +#pragma pack() +struct st_cmd_head cmd_head; + +static struct i2c_client *gt_client; +static struct proc_dir_entry *goodix_proc_entry; + +static ssize_t goodix_tool_read(struct file *, char __user *, size_t, loff_t *); +static ssize_t goodix_tool_write(struct file *, const char __user *, + size_t, loff_t *); +static const struct file_operations gtp_proc_ops = { + .owner = THIS_MODULE, + .read = goodix_tool_read, + .write = goodix_tool_write, +}; + +/* static s32 goodix_tool_write(struct file *filp, + * const char __user *buff, unsigned long len, void *data); + */ +/*static s32 goodix_tool_read( char *page, char + **start, off_t off, int count, int *eof, void *data ); + */ +static s32 (*tool_i2c_read)(u8 *, u16); +static s32 (*tool_i2c_write)(u8 *, u16); + +static s32 DATA_LENGTH = (s32)0; +static s8 IC_TYPE[16] = "GT9XX"; + +static void tool_set_proc_name(char *procname) +{ + snprintf(procname, 20, "gmnode"); /* modify for moto */ +} + +static s32 tool_i2c_read_no_extra(u8 *buf, u16 len) +{ + s32 ret = -1; + s32 i = 0; + struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client); + + for (i = 0; i < cmd_head.retry; i++) { + ret = gtp_i2c_read(ts->client, buf, len + GTP_ADDR_LENGTH); + if (ret > 0) + break; + } + return ret; +} + +static s32 tool_i2c_write_no_extra(u8 *buf, u16 len) +{ + s32 ret = -1; + s32 i = 0; + struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client); + + for (i = 0; i < cmd_head.retry; i++) { + ret = gtp_i2c_write(ts->client, buf, len); + if (ret > 0) + break; + } + + return ret; +} + +static s32 tool_i2c_read_with_extra(u8 *buf, u16 len) +{ + s32 ret = -1; + u8 pre[2] = {0x0f, 0xff}; + u8 end[2] = {0x80, 0x00}; + + tool_i2c_write_no_extra(pre, 2); + ret = tool_i2c_read_no_extra(buf, len); + tool_i2c_write_no_extra(end, 2); + + return ret; +} + +static s32 tool_i2c_write_with_extra(u8 *buf, u16 len) +{ + s32 ret = -1; + u8 pre[2] = {0x0f, 0xff}; + u8 end[2] = {0x80, 0x00}; + + tool_i2c_write_no_extra(pre, 2); + ret = tool_i2c_write_no_extra(buf, len); + tool_i2c_write_no_extra(end, 2); + + return ret; +} + +static void register_i2c_func(void) +{ + /* if (!strcmp(IC_TYPE, "GT818", 5) + * || !strcmp(IC_TYPE, "GT816", 5) + * || !strcmp(IC_TYPE, "GT811", 5) + * || !strcmp(IC_TYPE, "GT818F", 6) + * || !strcmp(IC_TYPE, "GT827", 5) + * || !strcmp(IC_TYPE,"GT828", 5) + * || !strcmp(IC_TYPE, "GT813", 5)) + */ + if (strcmp(IC_TYPE, "GT8110") && + strcmp(IC_TYPE, "GT8105") && + strcmp(IC_TYPE, "GT801") && + strcmp(IC_TYPE, "GT800") && + strcmp(IC_TYPE, "GT801PLUS") && + strcmp(IC_TYPE, "GT811") && + strcmp(IC_TYPE, "GTxxx") && + strcmp(IC_TYPE, "GT9XX")) { + tool_i2c_read = tool_i2c_read_with_extra; + tool_i2c_write = tool_i2c_write_with_extra; + dev_dbg(>_client->dev, "I2C function: with pre and end cmd!"); + } else { + tool_i2c_read = tool_i2c_read_no_extra; + tool_i2c_write = tool_i2c_write_no_extra; + dev_info(>_client->dev, "I2C function: without pre and end cmd!"); + } +} + +static void unregister_i2c_func(void) +{ + tool_i2c_read = NULL; + tool_i2c_write = NULL; + dev_info(>_client->dev, "I2C function: unregister i2c transfer function!"); +} + +s32 init_wr_node(struct i2c_client *client) +{ + s32 i; + + gt_client = client; + memset(&cmd_head, 0, sizeof(cmd_head)); + cmd_head.data = NULL; + + i = 6; + while ((!cmd_head.data) && i) { + cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL); + if (cmd_head.data) + break; + i--; + } + if (i) { + DATA_LENGTH = i * DATA_LENGTH_UINT - GTP_ADDR_LENGTH; + dev_info(>_client->dev, + "Alloc memory size:%d.", DATA_LENGTH); + } else { + dev_err(>_client->dev, "Apply for memory failed."); + return FAIL; + } + + cmd_head.addr_len = 2; + cmd_head.retry = 5; + + register_i2c_func(); + + tool_set_proc_name(procname); + goodix_proc_entry = proc_create(procname, 0664, NULL, >p_proc_ops); + if (!goodix_proc_entry) { + dev_err(>_client->dev, "Couldn't create proc entry!"); + return FAIL; + } + + dev_info(>_client->dev, "Create proc entry success!"); + return SUCCESS; +} + +void uninit_wr_node(void) +{ + kfree(cmd_head.data); + cmd_head.data = NULL; + unregister_i2c_func(); + remove_proc_entry(procname, NULL); +} + +static u8 relation(u8 src, u8 dst, u8 rlt) +{ + u8 ret = 0; + + switch (rlt) { + case 0: + ret = (src != dst) ? true : false; + break; + + case 1: + ret = (src == dst) ? true : false; + dev_dbg(>_client->dev, + "equal:src:0x%02x dst:0x%02x ret:%d.", + src, dst, (s32)ret); + break; + + case 2: + ret = (src > dst) ? true : false; + break; + + case 3: + ret = (src < dst) ? true : false; + break; + + case 4: + ret = (src & dst) ? true : false; + break; + + case 5: + ret = (!(src | dst)) ? true : false; + break; + + default: + ret = false; + break; + } + + return ret; +} + +/******************************************************* + * Function: + * Comfirm function. + * Input: + * None. + * Output: + * Return write length. + ********************************************************/ +static u8 comfirm(void) +{ + s32 i = 0; + u8 buf[32]; + + memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len); + + for (i = 0; i < cmd_head.times; i++) { + if (tool_i2c_read(buf, 1) <= 0) { + dev_err(>_client->dev, "Read flag data failed!"); + return FAIL; + } + if (true == relation(buf[GTP_ADDR_LENGTH], + cmd_head.flag_val, cmd_head.flag_relation)) { + dev_dbg(>_client->dev, "value at flag addr:0x%02x.", + buf[GTP_ADDR_LENGTH]); + dev_dbg(>_client->dev, "flag value:0x%02x.", + cmd_head.flag_val); + break; + } + + msleep(cmd_head.circle); + } + + if (i >= cmd_head.times) { + dev_err(>_client->dev, "Can't get the continue flag!"); + return FAIL; + } + + return SUCCESS; +} + +ssize_t goodix_tool_write(struct file *filp, const char __user *buff, + size_t len, loff_t *off) +{ + s32 ret = 0; + struct goodix_ts_data *ts = i2c_get_clientdata(gt_client); + + ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH); + if (ret) { + dev_err(>_client->dev, "copy_from_user failed."); + return -EPERM; + } + + dev_dbg(>_client->dev, "[Operation]wr: %02X", cmd_head.wr); + dev_dbg(>_client->dev, + "[Flag]flag: %02X,addr: %02X%02X,value: %02X,relation: %02X", + cmd_head.flag, cmd_head.flag_addr[0], + cmd_head.flag_addr[1], cmd_head.flag_val, + cmd_head.flag_relation); + dev_dbg(>_client->dev, + "[Retry]circle: %d,times: %d,retry: %d, delay: %d", + (s32)cmd_head.circle, + (s32)cmd_head.times, (s32)cmd_head.retry, + (s32)cmd_head.delay); + + if (cmd_head.wr == 1) { + if (cmd_head.data_len > DATA_LENGTH) { + dev_err(>_client->dev, + "Tool write failed data too long"); + return -EPERM; + } + ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], + &buff[CMD_HEAD_LENGTH], + cmd_head.data_len); + if (ret) { + dev_err(>_client->dev, "copy_from_user failed."); + return -EPERM; + } + memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len], + cmd_head.addr, cmd_head.addr_len); + + GTP_DEBUG_ARRAY(cmd_head.data, cmd_head.data_len + + cmd_head.addr_len); + + if (cmd_head.flag == 1) { + if (comfirm() == FAIL) { + dev_err(>_client->dev, + "[WRITE]Comfirm fail!"); + return -EPERM; + } + } else if (cmd_head.flag == 2) { + /*Need interrupt!*/ + } + if (tool_i2c_write(&cmd_head.data[GTP_ADDR_LENGTH - + cmd_head.addr_len], cmd_head.data_len + + cmd_head.addr_len) <= 0) { + dev_err(>_client->dev, "[WRITE]Write data failed!"); + return -EPERM; + } + + GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH - + cmd_head.addr_len], + cmd_head.data_len + cmd_head.addr_len); + if (cmd_head.delay) + msleep(cmd_head.delay); + } else if (cmd_head.wr == 3) { + if (cmd_head.data_len > DATA_LENGTH) { + dev_err(>_client->dev, + "Tool write failed data too long"); + return -EPERM; + } + ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], + cmd_head.data_len); + if (ret) { + dev_err(>_client->dev, "copy_from_user failed."); + return -EPERM; + } + memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); + + register_i2c_func(); + } else if (cmd_head.wr == 5) { + /*memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);*/ + } else if (cmd_head.wr == 7) {/*disable irq!*/ + gtp_work_control_enable(i2c_get_clientdata(gt_client), false); + + if (ts->pdata->esd_protect) + gtp_esd_off(ts); + } else if (cmd_head.wr == 9) {/*enable irq!*/ + gtp_work_control_enable(i2c_get_clientdata(gt_client), true); + + if (ts->pdata->esd_protect) + gtp_esd_on(ts); + } else if (cmd_head.wr == 17) { + if (cmd_head.data_len > DATA_LENGTH) { + dev_err(>_client->dev, + "Tool write failed data too long"); + return -EPERM; + } + ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], + &buff[CMD_HEAD_LENGTH], + cmd_head.data_len); + if (ret) { + dev_dbg(>_client->dev, "copy_from_user failed."); + return -EPERM; + } + if (cmd_head.data[GTP_ADDR_LENGTH]) { + dev_info(>_client->dev, "gtp enter rawdiff."); + set_bit(RAW_DATA_MODE, &ts->flags); + } else { + clear_bit(RAW_DATA_MODE, &ts->flags); + dev_info(>_client->dev, "gtp leave rawdiff."); + } + } else if (cmd_head.wr == 19) { + /* add new command: reset guitar */ + gtp_reset_guitar(gt_client, 20); + } +#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE + else if (cmd_head.wr == 11) {/*Enter update mode!*/ + if (gup_enter_update_mode(gt_client) == FAIL) + return -EPERM; + } else if (cmd_head.wr == 13) {/*Leave update mode!*/ + gup_leave_update_mode(gt_client); + } else if (cmd_head.wr == 15) {/*Update firmware!*/ + show_len = 0; + total_len = 0; + if (cmd_head.data_len > DATA_LENGTH) { + dev_err(>_client->dev, + "Tool write failed data too long"); + return -EPERM; + } + memset(cmd_head.data, 0, DATA_LENGTH); + ret = copy_from_user(cmd_head.data, + &buff[CMD_HEAD_LENGTH], + cmd_head.data_len); + if (ret) { + dev_dbg(>_client->dev, "copy_from_user failed."); + return -EPERM; + } + + if (gup_update_proc((void *)cmd_head.data) == FAIL) + return -EPERM; + } +#endif + + return len; +} + +/******************************************************* + * Function: + * Goodix tool read function. + * Input: + * standard proc read function param. + * Output: + * Return read length. + ********************************************************/ +ssize_t goodix_tool_read(struct file *file, char __user *page, + size_t size, loff_t *ppos) +{ + s32 ret = 0; + + if (*ppos) { + /* ADB call again + * dev_dbg(>_client->dev, "[HEAD]wr: %d", cmd_head.wr); + * dev_dbg(>_client->dev, + * "[PARAM]size: %d, *ppos: %d", size, (int)*ppos); + * dev_dbg(>_client->dev, + * "[TOOL_READ]ADB call again, return it."); + */ + *ppos = 0; + return 0; + } + + if (cmd_head.wr % 2) { + return -EPERM; + } else if (!cmd_head.wr) { + u16 len, data_len, loc, addr; + + if (cmd_head.flag == 1) { + if (comfirm() == FAIL) { + dev_err(>_client->dev, "[READ]Comfirm fail!"); + return -EPERM; + } + } else if (cmd_head.flag == 2) { + /*Need interrupt!*/ + } + + if (cmd_head.delay) + msleep(cmd_head.delay); + + data_len = cmd_head.data_len; + addr = (cmd_head.addr[0] << 8) + cmd_head.addr[1]; + loc = 0; + + while (data_len > 0) { + len = data_len > DATA_LENGTH ? DATA_LENGTH : data_len; + cmd_head.data[0] = (addr >> 8) & 0xFF; + cmd_head.data[1] = (addr & 0xFF); + if (tool_i2c_read(cmd_head.data, len) <= 0) { + dev_err(>_client->dev, "[READ]Read data failed!"); + return -EPERM; + } + ret = simple_read_from_buffer(&page[loc], size, ppos, + &cmd_head.data[GTP_ADDR_LENGTH], len); + if (ret < 0) + return ret; + loc += len; + addr += len; + data_len -= len; + } + return cmd_head.data_len; + } else if (cmd_head.wr == 2) { + ret = simple_read_from_buffer(page, size, ppos, + IC_TYPE, sizeof(IC_TYPE)); + return ret; + } +#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE + else if (cmd_head.wr == 4) { + u8 progress_buf[4]; + + progress_buf[0] = show_len >> 8; + progress_buf[1] = show_len & 0xff; + progress_buf[2] = total_len >> 8; + progress_buf[3] = total_len & 0xff; + + ret = simple_read_from_buffer(page, size, ppos, + progress_buf, 4); + return ret; + } +#endif + else if (cmd_head.wr == 6) { + /*Read error code!*/ + } else if (cmd_head.wr == 8) { /*Read driver version*/ + ret = simple_read_from_buffer(page, size, ppos, + GTP_DRIVER_VERSION, + strlen(GTP_DRIVER_VERSION)); + return ret; + } + + return -EPERM; +} diff --git a/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.c b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.c new file mode 100644 index 000000000000..03328d040539 --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.c @@ -0,0 +1,2678 @@ +/* + * Goodix GT9xx touchscreen driver + * + * Copyright (C) 2016 - 2017 Goodix. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * but WITHOUT 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 "gt9xx.h" + +#define GOODIX_VTG_MIN_UV 2600000 +#define GOODIX_VTG_MAX_UV 3300000 +#define GOODIX_I2C_VTG_MIN_UV 1800000 +#define GOODIX_I2C_VTG_MAX_UV 1800000 + +#define DELAY_FOR_DISCHARGING 35 +#define GOODIX_COORDS_ARR_SIZE 4 +#define PROP_NAME_SIZE 24 +#define I2C_MAX_TRANSFER_SIZE 255 +#define GTP_PEN_BUTTON1 BTN_STYLUS +#define GTP_PEN_BUTTON2 BTN_STYLUS2 + +static const char *goodix_ts_name = "goodix-ts"; +static const char *goodix_input_phys = "input/ts"; +struct i2c_client *i2c_connect_client; +static struct proc_dir_entry *gtp_config_proc; + +enum doze { + DOZE_DISABLED = 0, + DOZE_ENABLED = 1, + DOZE_WAKEUP = 2, +}; + +static enum doze doze_status = DOZE_DISABLED; + +static int gtp_i2c_test(struct i2c_client *client); +static int gtp_enter_doze(struct goodix_ts_data *ts); + +static int gtp_unregister_powermanager(struct goodix_ts_data *ts); +static int gtp_register_powermanager(struct goodix_ts_data *ts); + +static int gtp_esd_init(struct goodix_ts_data *ts); +static void gtp_esd_check_func(struct work_struct *); +static int gtp_init_ext_watchdog(struct i2c_client *client); + +/* + * return: 2 - ok, < 0 - i2c transfer error + */ +int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len) +{ + unsigned int transfer_length = 0; + unsigned int pos = 0, address = (buf[0] << 8) + buf[1]; + unsigned char get_buf[64], addr_buf[2]; + int retry, r = 2; + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = !I2C_M_RD, + .buf = &addr_buf[0], + .len = GTP_ADDR_LENGTH, + }, { + .addr = client->addr, + .flags = I2C_M_RD, + } + }; + + len -= GTP_ADDR_LENGTH; + if (likely(len < sizeof(get_buf))) { + /* code optimize, use stack memory */ + msgs[1].buf = &get_buf[0]; + } else { + msgs[1].buf = kzalloc(len > I2C_MAX_TRANSFER_SIZE + ? I2C_MAX_TRANSFER_SIZE : len, GFP_KERNEL); + if (!msgs[1].buf) + return -ENOMEM; + } + + while (pos != len) { + if (unlikely(len - pos > I2C_MAX_TRANSFER_SIZE)) + transfer_length = I2C_MAX_TRANSFER_SIZE; + else + transfer_length = len - pos; + msgs[0].buf[0] = (address >> 8) & 0xFF; + msgs[0].buf[1] = address & 0xFF; + msgs[1].len = transfer_length; + for (retry = 0; retry < RETRY_MAX_TIMES; retry++) { + if (likely(i2c_transfer(client->adapter, + msgs, 2) == 2)) { + memcpy(&buf[2 + pos], msgs[1].buf, + transfer_length); + pos += transfer_length; + address += transfer_length; + break; + } + dev_dbg(&client->dev, "I2c read retry[%d]:0x%x\n", + retry + 1, address); + usleep_range(2000, 2100); + } + if (unlikely(retry == RETRY_MAX_TIMES)) { + dev_err(&client->dev, + "I2c read failed,dev:%02x,reg:%04x,size:%u\n", + client->addr, address, len); + r = -EAGAIN; + goto read_exit; + } + } +read_exit: + if (len >= sizeof(get_buf)) + kfree(msgs[1].buf); + return r; +} + +/******************************************************* + * Function: + * Write data to the i2c slave device. + * Input: + * client: i2c device. + * buf[0~1]: write start address. + * buf[2~len-1]: data buffer + * len: GTP_ADDR_LENGTH + write bytes count + * Output: + * numbers of i2c_msgs to transfer: + * 1: succeed, otherwise: failed + *********************************************************/ +int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len) + +{ + unsigned int pos = 0, transfer_length = 0; + unsigned int address = (buf[0] << 8) + buf[1]; + unsigned char put_buf[64]; + int retry, r = 1; + struct i2c_msg msg = { + .addr = client->addr, + .flags = !I2C_M_RD, + }; + + if (likely(len < sizeof(put_buf))) { + /* code optimize,use stack memory*/ + msg.buf = &put_buf[0]; + } else { + msg.buf = kmalloc(len > I2C_MAX_TRANSFER_SIZE + ? I2C_MAX_TRANSFER_SIZE : len, GFP_KERNEL); + if (!msg.buf) + return -ENOMEM; + } + + len -= GTP_ADDR_LENGTH; + while (pos != len) { + if (unlikely(len - pos > I2C_MAX_TRANSFER_SIZE + - GTP_ADDR_LENGTH)) + transfer_length = I2C_MAX_TRANSFER_SIZE + - GTP_ADDR_LENGTH; + else + transfer_length = len - pos; + msg.buf[0] = (unsigned char)((address >> 8) & 0xFF); + msg.buf[1] = (unsigned char)(address & 0xFF); + msg.len = transfer_length + 2; + memcpy(&msg.buf[2], &buf[2 + pos], transfer_length); + for (retry = 0; retry < RETRY_MAX_TIMES; retry++) { + if (likely(i2c_transfer(client->adapter, + &msg, 1) == 1)) { + pos += transfer_length; + address += transfer_length; + break; + } + dev_dbg(&client->dev, "I2C write retry[%d]\n", + retry + 1); + usleep_range(2000, 2100); + } + if (unlikely(retry == RETRY_MAX_TIMES)) { + dev_err(&client->dev, + "I2c write failed,dev:%02x,reg:%04x,size:%u\n", + client->addr, address, len); + r = -EAGAIN; + goto write_exit; + } + } +write_exit: + if (len + GTP_ADDR_LENGTH >= sizeof(put_buf)) + kfree(msg.buf); + return r; +} + +/******************************************************* + * Function: + * i2c read twice, compare the results + * Input: + * client: i2c device + * addr: operate address + * rxbuf: read data to store, if compare successful + * len: bytes to read + * Output: + * FAIL: read failed + * SUCCESS: read successful + *********************************************************/ +s32 gtp_i2c_read_dbl_check(struct i2c_client *client, + u16 addr, u8 *rxbuf, int len) +{ + u8 buf[16] = {0}; + u8 confirm_buf[16] = {0}; + u8 retry = 0; + + if (len + 2 > sizeof(buf)) { + dev_warn(&client->dev, + "%s, only support length less then %zu\n", + __func__, sizeof(buf) - 2); + return FAIL; + } + while (retry++ < 3) { + memset(buf, 0xAA, 16); + buf[0] = (u8)(addr >> 8); + buf[1] = (u8)(addr & 0xFF); + gtp_i2c_read(client, buf, len + 2); + + memset(confirm_buf, 0xAB, 16); + confirm_buf[0] = (u8)(addr >> 8); + confirm_buf[1] = (u8)(addr & 0xFF); + gtp_i2c_read(client, confirm_buf, len + 2); + + if (!memcmp(buf, confirm_buf, len + 2)) { + memcpy(rxbuf, confirm_buf + 2, len); + return SUCCESS; + } + } + dev_err(&client->dev, + "I2C read 0x%04X, %d bytes, double check failed!\n", + addr, len); + + return FAIL; +} + +/******************************************************* + * Function: + * Send config. + * Input: + * client: i2c device. + * Output: + * result of i2c write operation. + * 1: succeed, otherwise + * 0: Not executed + * < 0: failed + *********************************************************/ +s32 gtp_send_cfg(struct i2c_client *client) +{ + s32 ret, i; + u8 check_sum; + s32 retry = 0; + struct goodix_ts_data *ts = i2c_get_clientdata(client); + struct goodix_config_data *cfg = &ts->pdata->config; + + if (!cfg->length || !ts->pdata->driver_send_cfg) { + dev_info(&ts->client->dev, + "No config data or error occurred in panel_init\n"); + return 0; + } + + check_sum = 0; + for (i = GTP_ADDR_LENGTH; i < cfg->length; i++) + check_sum += cfg->data[i]; + cfg->data[cfg->length] = (~check_sum) + 1; + + dev_info(&ts->client->dev, "Driver send config\n"); + for (retry = 0; retry < RETRY_MAX_TIMES; retry++) { + ret = gtp_i2c_write(client, cfg->data, + GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH); + if (ret > 0) + break; + } + + return ret; +} + +/******************************************************* + * Function: + * Control enable or disable of work thread. + * Input: + * ts: goodix i2c_client private data + * enable: enable var. + *********************************************************/ +void gtp_work_control_enable(struct goodix_ts_data *ts, bool enable) +{ + if (enable) { + set_bit(REPORT_THREAD_ENABLED, &ts->flags); + dev_dbg(&ts->client->dev, "Input report thread enabled!\n"); + } else { + clear_bit(REPORT_THREAD_ENABLED, &ts->flags); + dev_dbg(&ts->client->dev, "Input report thread disabled!\n"); + } +} + +static int gtp_gesture_handler(struct goodix_ts_data *ts) +{ + u8 doze_buf[3] = {GTP_REG_DOZE_BUF >> 8, GTP_REG_DOZE_BUF & 0xFF}; + int ret; + + ret = gtp_i2c_read(ts->client, doze_buf, 3); + if (ret < 0) { + dev_err(&ts->client->dev, "Failed read doze buf"); + return -EINVAL; + } + + dev_dbg(&ts->client->dev, "0x814B = 0x%02X", doze_buf[2]); + if ((doze_buf[2] == 'a') || (doze_buf[2] == 'b') || + (doze_buf[2] == 'c') || (doze_buf[2] == 'd') || + (doze_buf[2] == 'e') || (doze_buf[2] == 'g') || + (doze_buf[2] == 'h') || (doze_buf[2] == 'm') || + (doze_buf[2] == 'o') || (doze_buf[2] == 'q') || + (doze_buf[2] == 's') || (doze_buf[2] == 'v') || + (doze_buf[2] == 'w') || (doze_buf[2] == 'y') || + (doze_buf[2] == 'z') || (doze_buf[2] == 0x5E) || + (doze_buf[2] == 0xAA) || (doze_buf[2] == 0xAB) || + (doze_buf[2] == 0xBA) || (doze_buf[2] == 0xBB) || + (doze_buf[2] == 0xCC)) { + doze_status = DOZE_WAKEUP; + input_report_key(ts->input_dev, KEY_POWER, 1); + input_sync(ts->input_dev); + input_report_key(ts->input_dev, KEY_POWER, 0); + input_sync(ts->input_dev); + /* clear 0x814B */ + doze_buf[2] = 0x00; + gtp_i2c_write(ts->client, doze_buf, 3); + } else { + /* clear 0x814B */ + doze_buf[2] = 0x00; + gtp_i2c_write(ts->client, doze_buf, 3); + gtp_enter_doze(ts); + } + return 0; +} + +/* + * return touch state register value + * pen event id fixed with 9 and set tool type TOOL_PEN + * + */ +static u8 gtp_get_points(struct goodix_ts_data *ts, + struct goodix_point_t *points, + u8 *key_value) +{ + int ret; + int i; + u8 *coor_data = NULL; + u8 finger_state = 0; + u8 touch_num = 0; + u8 end_cmd[3] = { GTP_READ_COOR_ADDR >> 8, + GTP_READ_COOR_ADDR & 0xFF, 0 }; + u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH_ID + 1] = { + GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF }; + + ret = gtp_i2c_read(ts->client, point_data, 12); + if (ret < 0) { + dev_err(&ts->client->dev, + "I2C transfer error. errno:%d\n ", ret); + return 0; + } + finger_state = point_data[GTP_ADDR_LENGTH]; + if (finger_state == 0x00) + return 0; + + touch_num = finger_state & 0x0f; + if ((finger_state & MASK_BIT_8) == 0 || + touch_num > ts->pdata->max_touch_id) { + dev_err(&ts->client->dev, + "Invalid touch state: 0x%x", finger_state); + finger_state = 0; + goto exit_get_point; + } + + if (touch_num > 1) { + u8 buf[8 * GTP_MAX_TOUCH_ID] = { + (GTP_READ_COOR_ADDR + 10) >> 8, + (GTP_READ_COOR_ADDR + 10) & 0xff }; + + ret = gtp_i2c_read(ts->client, buf, 2 + 8 * (touch_num - 1)); + if (ret < 0) { + dev_err(&ts->client->dev, "I2C error. %d\n", ret); + finger_state = 0; + goto exit_get_point; + } + memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1)); + } + + /* panel have touch key */ + /* 0x20_UPKEY 0X10_DOWNKEY 0X40_ALLKEYDOWN */ + *key_value = point_data[3 + 8 * touch_num]; + + memset(points, 0, sizeof(*points) * GTP_MAX_TOUCH_ID); + for (i = 0; i < touch_num; i++) { + coor_data = &point_data[i * 8 + 3]; + points[i].id = coor_data[0]; + points[i].x = coor_data[1] | (coor_data[2] << 8); + points[i].y = coor_data[3] | (coor_data[4] << 8); + points[i].w = coor_data[5] | (coor_data[6] << 8); + /* if pen hover points[].p must set to zero */ + points[i].p = coor_data[5] | (coor_data[6] << 8); + + if (ts->pdata->swap_x2y) + GTP_SWAP(points[i].x, points[i].y); + + dev_dbg(&ts->client->dev, "[%d][%d %d %d]\n", + points[i].id, points[i].x, points[i].y, points[i].p); + + /* pen device coordinate */ + if (points[i].id & 0x80) { + points[i].tool_type = GTP_TOOL_PEN; + points[i].id = 10; + if (ts->pdata->pen_suppress_finger) { + points[0] = points[i]; + memset(++points, 0, sizeof(*points) * + (GTP_MAX_TOUCH_ID - 1)); + finger_state &= 0xf0; + finger_state |= 0x01; + break; + } + } else { + points[i].tool_type = GTP_TOOL_FINGER; + } + } + +exit_get_point: + if (!test_bit(RAW_DATA_MODE, &ts->flags)) { + ret = gtp_i2c_write(ts->client, end_cmd, 3); + if (ret < 0) + dev_info(&ts->client->dev, "I2C write end_cmd error!"); + } + return finger_state; +} + +static void gtp_type_a_report(struct goodix_ts_data *ts, u8 touch_num, + struct goodix_point_t *points) +{ + int i; + u16 cur_touch = 0; + static u16 pre_touch; + static u8 pre_pen_id; + + if (touch_num) + input_report_key(ts->input_dev, BTN_TOUCH, 1); + + for (i = 0; i < ts->pdata->max_touch_id; i++) { + if (touch_num && i == points->id) { + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, points->id); + + if (points->tool_type == GTP_TOOL_PEN) { + input_report_key(ts->input_dev, + BTN_TOOL_PEN, true); + pre_pen_id = points->id; + } else { + input_report_key(ts->input_dev, + BTN_TOOL_FINGER, true); + } + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + points->x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + points->y); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + points->w); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + points->p); + input_mt_sync(ts->input_dev); + + cur_touch |= 0x01 << points->id; + points++; + } else if (pre_touch & 0x01 << i) { + if (pre_pen_id == i) { + input_report_key(ts->input_dev, + BTN_TOOL_PEN, false); +/* valid id will < 10, so id to 0xff to indicate a invalid state */ + pre_pen_id = 0xff; + } else { + input_report_key(ts->input_dev, + BTN_TOOL_FINGER, false); + } + } + } + + pre_touch = cur_touch; + if (!pre_touch) { + input_mt_sync(ts->input_dev); + input_report_key(ts->input_dev, BTN_TOUCH, 0); + } + input_sync(ts->input_dev); +} + +static void gtp_mt_slot_report(struct goodix_ts_data *ts, u8 touch_num, + struct goodix_point_t *points) +{ + int i; + u16 cur_touch = 0; + static u16 pre_touch; + static u8 pre_pen_id; + + for (i = 0; i < ts->pdata->max_touch_id; i++) { + if (touch_num && i == points->id) { + input_mt_slot(ts->input_dev, points->id); + + if (points->tool_type == GTP_TOOL_PEN) { + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_PEN, true); + pre_pen_id = points->id; + } else { + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_FINGER, true); + } + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + points->x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + points->y); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + points->w); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + points->p); + + cur_touch |= 0x01 << points->id; + points++; + } else if (pre_touch & 0x01 << i) { + input_mt_slot(ts->input_dev, i); + if (pre_pen_id == i) { + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_PEN, false); + /* valid id will < 10, so set id to 0xff to + * indicate a invalid state + */ + pre_pen_id = 0xff; + } else { + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_FINGER, false); + } + } + } + + pre_touch = cur_touch; + /* report BTN_TOUCH event */ + input_mt_sync_frame(ts->input_dev); + input_sync(ts->input_dev); +} + +/******************************************************* + * Function: + * Goodix touchscreen sensor report function + * Input: + * ts: goodix tp private data + * Output: + * None. + *********************************************************/ +static void gtp_work_func(struct goodix_ts_data *ts) +{ + u8 point_state = 0; + u8 key_value = 0; + s32 i = 0; + s32 ret = -1; + static u8 pre_key; + struct goodix_point_t points[GTP_MAX_TOUCH_ID]; + + if (test_bit(PANEL_RESETTING, &ts->flags)) + return; + if (!test_bit(REPORT_THREAD_ENABLED, &ts->flags)) + return; + + /* gesture event */ + if (ts->pdata->slide_wakeup && test_bit(DOZE_MODE, &ts->flags)) { + ret = gtp_gesture_handler(ts); + if (ret) + dev_err(&ts->client->dev, + "Failed handler gesture event %d\n", ret); + return; + } + + point_state = gtp_get_points(ts, points, &key_value); + if (!point_state) { + dev_dbg(&ts->client->dev, "Invalid finger points\n"); + return; + } + + /* touch key event */ + if (key_value & 0xf0 || pre_key & 0xf0) { + /* pen button */ + switch (key_value) { + case 0x40: + input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 1); + input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 1); + break; + case 0x10: + input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 1); + input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 0); + dev_dbg(&ts->client->dev, "pen button1 down\n"); + break; + case 0x20: + input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 0); + input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 1); + break; + default: + input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 0); + input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 0); + dev_dbg(&ts->client->dev, "button1 up\n"); + break; + } + input_sync(ts->input_dev); + pre_key = key_value; + } else if (key_value & 0x0f || pre_key & 0x0f) { + /* panel key */ + for (i = 0; i < ts->pdata->key_nums; i++) { + if ((pre_key | key_value) & (0x01 << i)) + input_report_key(ts->input_dev, + ts->pdata->key_map[i], + key_value & (0x01 << i)); + } + input_sync(ts->input_dev); + pre_key = key_value; + } + + if (!ts->pdata->type_a_report) + gtp_mt_slot_report(ts, point_state & 0x0f, points); + else + gtp_type_a_report(ts, point_state & 0x0f, points); +} + +/******************************************************* + * Function: + * Timer interrupt service routine for polling mode. + * Input: + * timer: timer struct pointer + * Output: + * Timer work mode. + * HRTIMER_NORESTART: + * no restart mode + *********************************************************/ +static enum hrtimer_restart gtp_timer_handler(struct hrtimer *timer) +{ + struct goodix_ts_data *ts = + container_of(timer, struct goodix_ts_data, timer); + + gtp_work_func(ts); + hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME + 6) * 1000000), + HRTIMER_MODE_REL); + + return HRTIMER_NORESTART; +} + +static irqreturn_t gtp_irq_handler(int irq, void *dev_id) +{ + struct goodix_ts_data *ts = dev_id; + + gtp_work_func(ts); + return IRQ_HANDLED; +} + +void gtp_int_output(struct goodix_ts_data *ts, int level) +{ + if (!ts->pdata->int_sync) + return; + + if (level == 0) { + if (ts->pinctrl.pinctrl) + pinctrl_select_state(ts->pinctrl.pinctrl, + ts->pinctrl.int_out_low); + else if (gpio_is_valid(ts->pdata->irq_gpio)) + gpio_direction_output(ts->pdata->irq_gpio, 0); + else + dev_err(&ts->client->dev, + "Failed set int pin output low\n"); + } else { + if (ts->pinctrl.pinctrl) + pinctrl_select_state(ts->pinctrl.pinctrl, + ts->pinctrl.int_out_high); + else if (gpio_is_valid(ts->pdata->irq_gpio)) + gpio_direction_output(ts->pdata->irq_gpio, 1); + else + dev_err(&ts->client->dev, + "Failed set int pin output high\n"); + } +} + +void gtp_int_sync(struct goodix_ts_data *ts, s32 ms) +{ + if (!ts->pdata->int_sync) + return; + + if (ts->pinctrl.pinctrl) { + gtp_int_output(ts, 0); + msleep(ms); + pinctrl_select_state(ts->pinctrl.pinctrl, + ts->pinctrl.int_input); + } else if (gpio_is_valid(ts->pdata->irq_gpio)) { + gpio_direction_output(ts->pdata->irq_gpio, 0); + msleep(ms); + gpio_direction_input(ts->pdata->irq_gpio); + } else { + dev_err(&ts->client->dev, "Failed sync int pin\n"); + } +} + +void gtp_rst_output(struct goodix_ts_data *ts, int level) +{ + if (level == 0) { + if (ts->pinctrl.pinctrl) + pinctrl_select_state(ts->pinctrl.pinctrl, + ts->pinctrl.rst_out_low); + else if (gpio_is_valid(ts->pdata->rst_gpio)) + gpio_direction_output(ts->pdata->rst_gpio, 0); + else + dev_err(&ts->client->dev, + "Failed set rst pin output low\n"); + } else { + if (ts->pinctrl.pinctrl) + pinctrl_select_state(ts->pinctrl.pinctrl, + ts->pinctrl.rst_out_high); + else if (gpio_is_valid(ts->pdata->rst_gpio)) + gpio_direction_output(ts->pdata->rst_gpio, 1); + else + dev_err(&ts->client->dev, + "Failed set rst pin output high\n"); + } +} + +void gtp_rst_input(struct goodix_ts_data *ts) +{ + if (ts->pinctrl.pinctrl) + pinctrl_select_state(ts->pinctrl.pinctrl, + ts->pinctrl.rst_input); + else if (gpio_is_valid(ts->pdata->rst_gpio)) + gpio_direction_input(ts->pdata->rst_gpio); + else + dev_err(&ts->client->dev, + "Failed set rst pin input\n"); +} + +/******************************************************* + * Function: + * Reset chip. Control the reset pin and int-pin(if + * defined), + * Input: + * client: i2c device. + * ms: reset time in millisecond + * Output: + * None. + *******************************************************/ +void gtp_reset_guitar(struct i2c_client *client, s32 ms) +{ + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + dev_info(&client->dev, "Guitar reset"); + set_bit(PANEL_RESETTING, &ts->flags); + if (!gpio_is_valid(ts->pdata->rst_gpio)) { + dev_warn(&client->dev, "reset failed no valid reset gpio"); + return; + } + + gtp_rst_output(ts, 0); + usleep_range(ms * 1000, ms * 1000 + 100); /* T2: > 10ms */ + + gtp_int_output(ts, client->addr == 0x14); + + usleep_range(2000, 3000); /* T3: > 100us (2ms)*/ + gtp_rst_output(ts, 1); + + usleep_range(6000, 7000); /* T4: > 5ms */ + gtp_rst_input(ts); + + gtp_int_sync(ts, 50); + if (ts->pdata->esd_protect) + gtp_init_ext_watchdog(client); + + clear_bit(PANEL_RESETTING, &ts->flags); +} + +/******************************************************* + * Function: + * Enter doze mode for sliding wakeup. + * Input: + * ts: goodix tp private data + * Output: + * 1: succeed, otherwise failed + *******************************************************/ +static int gtp_enter_doze(struct goodix_ts_data *ts) +{ + int ret = -1; + int retry = 0; + u8 i2c_control_buf[3] = { (u8)(GTP_REG_COMMAND >> 8), + (u8)GTP_REG_COMMAND, 8 }; + + /* resend doze command + * if (test_and_set_bit(DOZE_MODE, &ts->flags)) { + * dev_info(&ts->client->dev, "Already in doze mode\n"); + * return SUCCESS; + * } + */ + set_bit(DOZE_MODE, &ts->flags); + dev_dbg(&ts->client->dev, "Entering gesture mode."); + while (retry++ < 5) { + i2c_control_buf[0] = (u8)(GTP_REG_COMMAND_CHECK >> 8); + i2c_control_buf[1] = (u8)GTP_REG_COMMAND_CHECK; + ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); + if (ret < 0) { + dev_dbg(&ts->client->dev, + "failed to set doze flag into 0x8046, %d\n", + retry); + continue; + } + i2c_control_buf[0] = (u8)(GTP_REG_COMMAND >> 8); + i2c_control_buf[1] = (u8)GTP_REG_COMMAND; + ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); + if (ret > 0) { + dev_dbg(&ts->client->dev, "Gesture mode enabled\n"); + return ret; + } + usleep_range(10000, 11000); + } + + dev_err(&ts->client->dev, "Failed enter doze mode\n"); + clear_bit(DOZE_MODE, &ts->flags); + return ret; +} + +static s8 gtp_enter_sleep(struct goodix_ts_data *ts) +{ + s8 ret = -1; + s8 retry = 0; + u8 i2c_control_buf[3] = { (u8)(GTP_REG_COMMAND >> 8), + (u8)GTP_REG_COMMAND, 5 }; + + gtp_int_output(ts, 0); + usleep_range(5000, 6000); + + while (retry++ < 5) { + ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); + if (ret > 0) { + dev_info(&ts->client->dev, "Enter sleep mode\n"); + + return ret; + } + usleep_range(10000, 11000); + } + dev_err(&ts->client->dev, "Failed send sleep cmd\n"); + + return ret; +} + +static int gtp_wakeup_sleep(struct goodix_ts_data *ts) +{ + u8 retry = 0; + int ret = -1; + + while (retry++ < 10) { + gtp_int_output(ts, 1); + usleep_range(5000, 6000); + + ret = gtp_i2c_test(ts->client); + if (!ret) { + dev_dbg(&ts->client->dev, "Success wakeup sleep\n"); + + gtp_int_sync(ts, 25); + if (ts->pdata->esd_protect) + gtp_init_ext_watchdog(ts->client); + + return ret; + } + gtp_reset_guitar(ts->client, 20); + } + + dev_err(&ts->client->dev, "Failed wakeup from sleep mode\n"); + return -EINVAL; +} + +static int gtp_find_valid_cfg_data(struct goodix_ts_data *ts) +{ + int ret = -1; + u8 sensor_id = 0; + struct goodix_config_data *cfg = &ts->pdata->config; + + /* if defined CONFIG_OF, parse config data from dtsi + * else parse config data form header file. + */ + cfg->length = 0; + +#ifndef CONFIG_OF + u8 cfg_info_group0[] = CTP_CFG_GROUP0; + u8 cfg_info_group1[] = CTP_CFG_GROUP1; + u8 cfg_info_group2[] = CTP_CFG_GROUP2; + u8 cfg_info_group3[] = CTP_CFG_GROUP3; + u8 cfg_info_group4[] = CTP_CFG_GROUP4; + u8 cfg_info_group5[] = CTP_CFG_GROUP5; + + u8 *send_cfg_buf[] = { cfg_info_group0, cfg_info_group1, + cfg_info_group2, cfg_info_group3, + cfg_info_group4, cfg_info_group5 }; + u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group0), + CFG_GROUP_LEN(cfg_info_group1), + CFG_GROUP_LEN(cfg_info_group2), + CFG_GROUP_LEN(cfg_info_group3), + CFG_GROUP_LEN(cfg_info_group4), + CFG_GROUP_LEN(cfg_info_group5)}; + + dev_dbg(&ts->client->dev, + "Config Groups\' Lengths: %d, %d, %d, %d, %d, %d", + cfg_info_len[0], cfg_info_len[1], cfg_info_len[2], + cfg_info_len[3], cfg_info_len[4], cfg_info_len[5]); +#endif + + /* read sensor id */ + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, + &sensor_id, 1); + if (ret != SUCCESS || sensor_id >= 0x06) { + dev_err(&ts->client->dev, + "Failed get valid sensor_id(0x%02X), No Config Sent\n", + sensor_id); + return -EINVAL; + } + + dev_dbg(&ts->client->dev, "Sensor_ID: %d", sensor_id); + /* parse config data */ +#ifdef CONFIG_OF + dev_dbg(&ts->client->dev, "Get config data from device tree\n"); + ret = gtp_parse_dt_cfg(&ts->client->dev, + &cfg->data[GTP_ADDR_LENGTH], + &cfg->length, sensor_id); + if (ret < 0) { + dev_err(&ts->client->dev, + "Failed to parse config data form device tree\n"); + cfg->length = 0; + return -EPERM; + } +#else + dev_dbg(&ts->client->dev, "Get config data from header file\n"); + if ((!cfg_info_len[1]) && (!cfg_info_len[2]) && + (!cfg_info_len[3]) && (!cfg_info_len[4]) && + (!cfg_info_len[5])) { + sensor_id = 0; + } + cfg->length = cfg_info_len[sensor_id]; + memset(&cfg->data[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH); + memcpy(&cfg->data[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id], + cfg->length); +#endif + + if (cfg->length < GTP_CONFIG_MIN_LENGTH) { + dev_err(&ts->client->dev, + "Failed get valid config data with sensor id %d\n", + sensor_id); + cfg->length = 0; + return -EPERM; + } + + dev_info(&ts->client->dev, "Config group%d used,length: %d\n", + sensor_id, cfg->length); + + return 0; +} + +/******************************************************* + * Function: + * Get valid config data from dts or .h file. + * Read firmware version info and judge firmware + * working state + * Input: + * ts: goodix private data + * Output: + * Executive outcomes. + * 0: succeed, otherwise: failed + *******************************************************/ +static s32 gtp_init_panel(struct goodix_ts_data *ts) +{ + s32 ret = -1; + u8 opr_buf[16] = {0}; + u8 drv_cfg_version = 0; + u8 flash_cfg_version = 0; + struct goodix_config_data *cfg = &ts->pdata->config; + + if (!ts->pdata->driver_send_cfg) { + dev_info(&ts->client->dev, "Driver set not send config\n"); + cfg->length = GTP_CONFIG_MAX_LENGTH; + ret = gtp_i2c_read(ts->client, + cfg->data, cfg->length + + GTP_ADDR_LENGTH); + if (ret < 0) + dev_err(&ts->client->dev, "Read origin Config Failed\n"); + + return 0; + } + + gtp_find_valid_cfg_data(ts); + + /* check firmware */ + ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1); + if (ret == SUCCESS) { + if (opr_buf[0] != 0xBE) { + set_bit(FW_ERROR, &ts->flags); + dev_err(&ts->client->dev, + "Firmware error, no config sent!\n"); + return -EINVAL; + } + } + + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, + &opr_buf[0], 1); + if (ret == SUCCESS) { + dev_dbg(&ts->client->dev, + "Config Version: %d; IC Config Version: %d\n", + cfg->data[GTP_ADDR_LENGTH], opr_buf[0]); + flash_cfg_version = opr_buf[0]; + drv_cfg_version = cfg->data[GTP_ADDR_LENGTH]; + + if (flash_cfg_version < 120 && + flash_cfg_version > drv_cfg_version) + cfg->data[GTP_ADDR_LENGTH] = 0x00; + } else { + dev_err(&ts->client->dev, + "Failed to get ic config version!No config sent\n"); + return -EPERM; + } + + ret = gtp_send_cfg(ts->client); + if (ret < 0) + dev_err(&ts->client->dev, "Send config error\n"); + else + usleep_range(10000, 11000); /* 10 ms */ + + /* restore config version */ + cfg->data[GTP_ADDR_LENGTH] = drv_cfg_version; + + return 0; +} + +static ssize_t gtp_config_read_proc(struct file *file, char __user *page, + size_t size, loff_t *ppos) +{ + int i, ret; + char *ptr; + size_t data_len = 0; + char temp_data[GTP_CONFIG_MAX_LENGTH + 2] = { + (u8)(GTP_REG_CONFIG_DATA >> 8), + (u8)GTP_REG_CONFIG_DATA }; + struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client); + struct goodix_config_data *cfg = &ts->pdata->config; + + ptr = kzalloc(4096, GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + data_len += snprintf(ptr + data_len, 4096 - data_len, + "====init value====\n"); + for (i = 0 ; i < GTP_CONFIG_MAX_LENGTH ; i++) { + data_len += snprintf(ptr + data_len, 4096 - data_len, + "0x%02X ", cfg->data[i + 2]); + + if (i % 8 == 7) + data_len += snprintf(ptr + data_len, + 4096 - data_len, "\n"); + } + data_len += snprintf(ptr + data_len, 4096 - data_len, "\n"); + + data_len += snprintf(ptr + data_len, 4096 - data_len, + "====real value====\n"); + ret = gtp_i2c_read(i2c_connect_client, temp_data, + GTP_CONFIG_MAX_LENGTH + 2); + if (ret < 0) { + data_len += snprintf(ptr + data_len, 4096 - data_len, + "Failed read real config data\n"); + } else { + for (i = 0; i < GTP_CONFIG_MAX_LENGTH; i++) { + data_len += snprintf(ptr + data_len, 4096 - data_len, + "0x%02X ", temp_data[i + 2]); + + if (i % 8 == 7) + data_len += snprintf(ptr + data_len, + 4096 - data_len, "\n"); + } + } + + data_len = simple_read_from_buffer(page, size, ppos, ptr, data_len); + kfree(ptr); + ptr = NULL; + return data_len; +} + +int gtp_ascii_to_array(const u8 *src_buf, int src_len, u8 *dst_buf) +{ + int i, ret; + int cfg_len = 0; + long val; + char temp_buf[5]; + + for (i = 0; i < src_len;) { + if (src_buf[i] == ' ' || src_buf[i] == '\r' || + src_buf[i] == '\n') { + i++; + continue; + } + + temp_buf[0] = src_buf[i]; + temp_buf[1] = src_buf[i + 1]; + temp_buf[2] = src_buf[i + 2]; + temp_buf[3] = src_buf[i + 3]; + temp_buf[4] = '\0'; + if (!kstrtol(temp_buf, 16, &val)) { + if (cfg_len < GTP_CONFIG_MAX_LENGTH) { + dst_buf[cfg_len++] = val & 0xFF; + i += 5; + } else { + ret = -2; + goto convert_failed; + } + } else { + ret = -3; + goto convert_failed; + } + } + return cfg_len; + +convert_failed: + return ret; +} + +static ssize_t gtp_config_write_proc(struct file *filp, + const char __user *buffer, + size_t count, loff_t *off) +{ + u8 *temp_buf; + u8 *file_config; + int file_cfg_len; + s32 ret = 0, i; + struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client); + + dev_dbg(&ts->client->dev, "write count %zu\n", count); + + if (count > PAGE_SIZE) { + dev_err(&ts->client->dev, "config to long %zu\n", count); + return -EFAULT; + } + + temp_buf = kzalloc(count, GFP_KERNEL); + if (!temp_buf) + return -ENOMEM; + + file_config = kzalloc(GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH, + GFP_KERNEL); + if (!file_config) { + kfree(temp_buf); + return -ENOMEM; + } + file_config[0] = GTP_REG_CONFIG_DATA >> 8; + file_config[1] = GTP_REG_CONFIG_DATA & 0xff; + + if (copy_from_user(temp_buf, buffer, count)) { + dev_err(&ts->client->dev, "Failed copy from user\n"); + ret = -EFAULT; + goto send_cfg_err; + } + + file_cfg_len = gtp_ascii_to_array(temp_buf, (int)count, + &file_config[GTP_ADDR_LENGTH]); + if (file_cfg_len < 0) { + dev_err(&ts->client->dev, "failed covert ascii to hex"); + ret = -EFAULT; + goto send_cfg_err; + } + + GTP_DEBUG_ARRAY(file_config + GTP_ADDR_LENGTH, file_cfg_len); + + i = 0; + while (i++ < 5) { + ret = gtp_i2c_write(ts->client, file_config, file_cfg_len + 2); + if (ret > 0) { + dev_info(&ts->client->dev, "Send config SUCCESS."); + break; + } + dev_err(&ts->client->dev, "Send config i2c error."); + ret = -EFAULT; + goto send_cfg_err; + } + + ret = count; +send_cfg_err: + kfree(temp_buf); + kfree(file_config); + return ret; +} + +static const struct file_operations config_proc_ops = { + .owner = THIS_MODULE, + .read = gtp_config_read_proc, + .write = gtp_config_write_proc, +}; + +static ssize_t gtp_workmode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + size_t data_len = 0; + struct goodix_ts_data *data = dev_get_drvdata(dev); + + if (test_bit(DOZE_MODE, &data->flags)) + data_len = scnprintf(buf, PAGE_SIZE, "%s\n", + "doze_mode"); + else if (test_bit(SLEEP_MODE, &data->flags)) + data_len = scnprintf(buf, PAGE_SIZE, "%s\n", + "sleep_mode"); + else + data_len = scnprintf(buf, PAGE_SIZE, "%s\n", + "normal_mode"); + + return data_len; +} +static DEVICE_ATTR(workmode, 0444, gtp_workmode_show, NULL); + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE +#define FW_NAME_MAX_LEN 80 +static ssize_t gtp_dofwupdate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct goodix_ts_data *ts = dev_get_drvdata(dev); + char update_file_name[FW_NAME_MAX_LEN]; + int retval; + + if (count > FW_NAME_MAX_LEN) { + dev_info(&ts->client->dev, "FW filename is too long\n"); + retval = -EINVAL; + goto exit; + } + + strlcpy(update_file_name, buf, count); + + ts->force_update = true; + retval = gup_update_proc(update_file_name); + if (retval == FAIL) + dev_err(&ts->client->dev, "Fail to update GTP firmware.\n"); + else + dev_info(&ts->client->dev, "Update success\n"); + + return count; + +exit: + return retval; +} +static DEVICE_ATTR(dofwupdate, 0664, NULL, gtp_dofwupdate_store); +#endif + +static ssize_t gtp_productinfo_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct goodix_ts_data *data = dev_get_drvdata(dev); + struct goodix_fw_info *fw_info = &data->fw_info; + + return scnprintf(buf, PAGE_SIZE, "GT%s_%x_%d\n", + fw_info->pid, fw_info->version, fw_info->sensor_id); +} +static DEVICE_ATTR(productinfo, 0444, gtp_productinfo_show, NULL); + +static ssize_t gtp_drv_irq_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long value = 0; + int err = 0; + struct goodix_ts_data *data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 10, &value); + if (err < 0) { + dev_err(dev, "Failed to convert value\n"); + return -EINVAL; + } + + switch (value) { + case 0: + /* Disable irq */ + gtp_work_control_enable(data, false); + break; + case 1: + /* Enable irq */ + gtp_work_control_enable(data, true); + break; + default: + dev_err(dev, "Invalid value\n"); + return -EINVAL; + } + + return count; +} + +static ssize_t gtp_drv_irq_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct goodix_ts_data *data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%s\n", + test_bit(REPORT_THREAD_ENABLED, &data->flags) + ? "enabled" : "disabled"); +} +static DEVICE_ATTR(drv_irq, 0664, gtp_drv_irq_show, gtp_drv_irq_store); + +static ssize_t gtp_reset_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct goodix_ts_data *data = dev_get_drvdata(dev); + + if ('1' != buf[0]) { + dev_err(dev, "Invalid argument for reset\n"); + return -EINVAL; + } + + gtp_reset_guitar(data->client, 20); + + return count; +} +static DEVICE_ATTR(reset, 0220, NULL, gtp_reset_store); + +static struct attribute *gtp_attrs[] = { + &dev_attr_workmode.attr, + &dev_attr_productinfo.attr, + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE + &dev_attr_dofwupdate.attr, +#endif + + &dev_attr_drv_irq.attr, + &dev_attr_reset.attr, + NULL +}; + +static const struct attribute_group gtp_attr_group = { + .attrs = gtp_attrs, +}; + +static int gtp_create_file(struct goodix_ts_data *ts) +{ + int ret; + struct i2c_client *client = ts->client; + + /* Create proc file system */ + gtp_config_proc = NULL; + gtp_config_proc = proc_create(GT91XX_CONFIG_PROC_FILE, 0664, + NULL, &config_proc_ops); + if (!gtp_config_proc) + dev_err(&client->dev, "create_proc_entry %s failed\n", + GT91XX_CONFIG_PROC_FILE); + else + dev_info(&client->dev, "create proc entry %s success\n", + GT91XX_CONFIG_PROC_FILE); + + ret = sysfs_create_group(&client->dev.kobj, >p_attr_group); + if (ret) { + dev_err(&client->dev, "Failure create sysfs group %d\n", ret); + /*TODO: debug change */ + goto exit_free_config_proc; + } + return 0; + +exit_free_config_proc: + remove_proc_entry(GT91XX_CONFIG_PROC_FILE, gtp_config_proc); + return -ENODEV; +} + +s32 gtp_get_fw_info(struct i2c_client *client, struct goodix_fw_info *fw_info) +{ + s32 ret = -1; + u8 buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff}; + + ret = gtp_i2c_read(client, buf, sizeof(buf)); + if (ret < 0) { + dev_err(&client->dev, "Failed read fw_info\n"); + return ret; + } + + /* product id */ + memset(fw_info, 0, sizeof(*fw_info)); + + if (buf[5] == 0x00) { + memcpy(fw_info->pid, buf + GTP_ADDR_LENGTH, 3); + dev_info(&client->dev, "IC Version: %c%c%c_%02X%02X\n", + buf[2], buf[3], buf[4], buf[7], buf[6]); + } else { + memcpy(fw_info->pid, buf + GTP_ADDR_LENGTH, 4); + dev_info(&client->dev, "IC Version: %c%c%c%c_%02X%02X\n", + buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]); + } + + /* current firmware version */ + fw_info->version = (buf[7] << 8) | buf[6]; + + /* read sensor id */ + fw_info->sensor_id = 0xff; + ret = gtp_i2c_read_dbl_check(client, GTP_REG_SENSOR_ID, + &fw_info->sensor_id, 1); + if (ret != SUCCESS || fw_info->sensor_id >= 0x06) { + dev_err(&client->dev, + "Failed get valid sensor_id(0x%02X), No Config Sent\n", + fw_info->sensor_id); + + fw_info->sensor_id = 0xff; + } + + return ret; +} + +static int gtp_i2c_test(struct i2c_client *client) +{ + u8 test[3] = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff}; + u8 retry = 0; + int ret = -1; + + while (retry++ < 3) { + ret = gtp_i2c_read(client, test, 3); + if (ret == 2) + return 0; + + dev_err(&client->dev, "GTP i2c test failed time %d\n", retry); + usleep_range(10000, 11000); /* 10 ms */ + } + + return -EAGAIN; +} + +static int gtp_pinctrl_init(struct goodix_ts_data *ts) +{ + struct goodix_pinctrl *pinctrl = &ts->pinctrl; + + pinctrl->pinctrl = devm_pinctrl_get(&ts->client->dev); + if (IS_ERR_OR_NULL(pinctrl->pinctrl)) { + dev_info(&ts->client->dev, "No pinctrl found\n"); + pinctrl->pinctrl = NULL; + return 0; + } + + /* INT pinctrl */ + pinctrl->int_default = pinctrl_lookup_state(pinctrl->pinctrl, + "gdix_ts_int_default"); + if (IS_ERR_OR_NULL(pinctrl->int_default)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:INT default state\n"); + goto exit_pinctrl_init; + } + + pinctrl->int_out_high = pinctrl_lookup_state(pinctrl->pinctrl, + "gdix_ts_int_output_high"); + if (IS_ERR_OR_NULL(pinctrl->int_out_high)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:INT output_high\n"); + goto exit_pinctrl_init; + } + + pinctrl->int_out_low = pinctrl_lookup_state(pinctrl->pinctrl, + "gdix_ts_int_output_low"); + if (IS_ERR_OR_NULL(pinctrl->int_out_low)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:INT output_low\n"); + goto exit_pinctrl_init; + } + + pinctrl->int_input = pinctrl_lookup_state(pinctrl->pinctrl, + "gdix_ts_int_input"); + if (IS_ERR_OR_NULL(pinctrl->int_input)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:int-input\n"); + goto exit_pinctrl_init; + } + dev_info(&ts->client->dev, "Success init INT pinctrl\n"); + + /* RST pinctrl */ + pinctrl->rst_default = pinctrl_lookup_state(pinctrl->pinctrl, + "gdix_ts_rst_default"); + if (IS_ERR_OR_NULL(pinctrl->rst_default)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:RST default state\n"); + goto exit_pinctrl_init; + } + + pinctrl->rst_out_high = pinctrl_lookup_state(pinctrl->pinctrl, + "gdix_ts_rst_output_high"); + if (IS_ERR_OR_NULL(pinctrl->rst_out_high)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:RST output_high\n"); + goto exit_pinctrl_init; + } + + pinctrl->rst_out_low = pinctrl_lookup_state(pinctrl->pinctrl, + "gdix_ts_rst_output_low"); + if (IS_ERR_OR_NULL(pinctrl->rst_out_low)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:RST output_low\n"); + goto exit_pinctrl_init; + } + + pinctrl->rst_input = pinctrl_lookup_state(pinctrl->pinctrl, + "gdix_ts_rst_input"); + if (IS_ERR_OR_NULL(pinctrl->rst_input)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:rst-input\n"); + goto exit_pinctrl_init; + } + dev_info(&ts->client->dev, "Success init RST pinctrl\n"); + + return 0; +exit_pinctrl_init: + devm_pinctrl_put(pinctrl->pinctrl); + pinctrl->pinctrl = NULL; + pinctrl->int_default = NULL; + pinctrl->int_out_high = NULL; + pinctrl->int_out_low = NULL; + pinctrl->int_input = NULL; + pinctrl->rst_default = NULL; + pinctrl->rst_out_high = NULL; + pinctrl->rst_out_low = NULL; + pinctrl->rst_input = NULL; + return -EINVAL; +} + +static void gtp_pinctrl_deinit(struct goodix_ts_data *ts) +{ + if (ts->pinctrl.pinctrl) + devm_pinctrl_put(ts->pinctrl.pinctrl); +} + +static int gtp_request_io_port(struct goodix_ts_data *ts) +{ + int ret = 0; + + if (gpio_is_valid(ts->pdata->irq_gpio)) { + ret = gpio_request(ts->pdata->irq_gpio, "goodix_ts_int"); + if (ret < 0) { + dev_err(&ts->client->dev, + "Failed to request GPIO:%d, ERRNO:%d\n", + (s32)ts->pdata->irq_gpio, ret); + return -ENODEV; + } + + gpio_direction_input(ts->pdata->irq_gpio); + dev_info(&ts->client->dev, "Success request irq-gpio\n"); + } + + if (gpio_is_valid(ts->pdata->rst_gpio)) { + ret = gpio_request(ts->pdata->rst_gpio, "goodix_ts_rst"); + if (ret < 0) { + dev_err(&ts->client->dev, + "Failed to request GPIO:%d, ERRNO:%d\n", + (s32)ts->pdata->rst_gpio, ret); + + if (gpio_is_valid(ts->pdata->irq_gpio)) + gpio_free(ts->pdata->irq_gpio); + + return -ENODEV; + } + + gpio_direction_input(ts->pdata->rst_gpio); + dev_info(&ts->client->dev, "Success request rst-gpio\n"); + } + + return 0; +} + +/******************************************************* + * Function: + * Request interrupt if define irq pin, else use hrtimer + * as interrupt source + * Input: + * ts: private data. + * Output: + * Executive outcomes. + * 0: succeed, -1: failed. + *******************************************************/ +static int gtp_request_irq(struct goodix_ts_data *ts) +{ + int ret = -1; + + /* use irq */ + if (gpio_is_valid(ts->pdata->irq_gpio) || ts->client->irq > 0) { + if (gpio_is_valid(ts->pdata->irq_gpio)) + ts->client->irq = gpio_to_irq(ts->pdata->irq_gpio); + + dev_info(&ts->client->dev, "INT num %d, trigger type:%d\n", + ts->client->irq, ts->pdata->irq_flags); + ret = request_threaded_irq(ts->client->irq, NULL, + gtp_irq_handler, + ts->pdata->irq_flags | IRQF_ONESHOT, + ts->client->name, + ts); + if (ret < 0) { + dev_err(&ts->client->dev, + "Failed to request irq %d\n", ts->client->irq); + return ret; + } + } else { /* use hrtimer */ + dev_info(&ts->client->dev, "No hardware irq, use hrtimer\n"); + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ts->timer.function = gtp_timer_handler; + hrtimer_start(&ts->timer, + ktime_set(0, (GTP_POLL_TIME + 6) * 1000000), + HRTIMER_MODE_REL); + set_bit(HRTIMER_USED, &ts->flags); + ret = 0; + } + return ret; +} + +static s8 gtp_request_input_dev(struct goodix_ts_data *ts) +{ + s8 ret = -1; + u8 index = 0; + + ts->input_dev = input_allocate_device(); + if (!ts->input_dev) { + dev_err(&ts->client->dev, "Failed to allocate input device\n"); + return -ENOMEM; + } + + ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) + | BIT_MASK(EV_ABS); + if (!ts->pdata->type_a_report) { + input_mt_init_slots(ts->input_dev, 16, INPUT_MT_DIRECT); + dev_info(&ts->client->dev, "Use slot report protocol\n"); + } else { + __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + __set_bit(BTN_TOUCH, ts->input_dev->keybit); + dev_info(&ts->client->dev, "Use type A report protocol\n"); + } + + input_set_capability(ts->input_dev, EV_KEY, GTP_PEN_BUTTON1); + input_set_capability(ts->input_dev, EV_KEY, GTP_PEN_BUTTON2); + + /* touch key register */ + for (index = 0; index < ts->pdata->key_nums; index++) + input_set_capability(ts->input_dev, EV_KEY, + ts->pdata->key_map[index]); + + if (ts->pdata->slide_wakeup) + input_set_capability(ts->input_dev, EV_KEY, KEY_POWER); + + if (ts->pdata->swap_x2y) + GTP_SWAP(ts->pdata->abs_size_x, ts->pdata->abs_size_y); + + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, + ts->pdata->abs_size_x, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, + ts->pdata->abs_size_y, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, + ts->pdata->max_touch_width, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, + ts->pdata->max_touch_pressure, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, + ts->pdata->max_touch_id, 0, 0); + if (!ts->pdata->type_a_report) { + input_set_abs_params(ts->input_dev, ABS_MT_TOOL_TYPE, + 0, MT_TOOL_MAX, 0, 0); + } else { + __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit); + __set_bit(BTN_TOOL_FINGER, ts->input_dev->keybit); + } + + ts->input_dev->name = goodix_ts_name; + ts->input_dev->phys = goodix_input_phys; + ts->input_dev->id.bustype = BUS_I2C; + ts->input_dev->id.vendor = 0xDEAD; + ts->input_dev->id.product = 0xBEEF; + ts->input_dev->id.version = 10427; + + ret = input_register_device(ts->input_dev); + if (ret) { + dev_err(&ts->client->dev, "Register %s input device failed\n", + ts->input_dev->name); + input_free_device(ts->input_dev); + return -ENODEV; + } + + return 0; +} + +/* + * Devices Tree support + */ +#ifdef CONFIG_OF +static void gtp_parse_dt_coords(struct device *dev, + struct goodix_ts_platform_data *pdata) +{ + struct device_node *np = dev->of_node; + int ret; + + ret = of_property_read_u32(np, "touchscreen-max-id", + &pdata->max_touch_id); + if (ret || pdata->max_touch_id > GTP_MAX_TOUCH_ID) { + dev_info(dev, "Unset touchscreen-max-id, use default\n"); + pdata->max_touch_id = GTP_MAX_TOUCH_ID; + } + + ret = of_property_read_u32(np, "touchscreen-size-x", + &pdata->abs_size_x); + if (ret) { + dev_info(dev, "Unset touchscreen-size-x, use default\n"); + pdata->abs_size_x = GTP_DEFAULT_MAX_X; + } + + ret = of_property_read_u32(np, "touchscreen-size-y", + &pdata->abs_size_y); + if (ret) { + dev_info(dev, "Unset touchscreen-size-y, use default\n"); + pdata->abs_size_y = GTP_DEFAULT_MAX_Y; + } + + ret = of_property_read_u32(np, "touchscreen-max-w", + &pdata->max_touch_width); + if (ret) { + dev_info(dev, "Unset touchscreen-max-w, use default\n"); + pdata->max_touch_width = GTP_DEFAULT_MAX_WIDTH; + } + + ret = of_property_read_u32(np, "touchscreen-max-p", + &pdata->max_touch_pressure); + if (ret) { + dev_info(dev, "Unset touchscreen-max-p, use default\n"); + pdata->max_touch_pressure = GTP_DEFAULT_MAX_PRESSURE; + } + dev_info(dev, "touch input parameters is [id x y w p]<%d %d %d %d %d>\n", + pdata->max_touch_id, pdata->abs_size_x, pdata->abs_size_y, + pdata->max_touch_width, pdata->max_touch_pressure); +} + +static int gtp_parse_dt(struct device *dev, + struct goodix_ts_platform_data *pdata) +{ + int ret; + u32 key_nums; + struct property *prop; + u32 key_map[MAX_KEY_NUMS]; + struct device_node *np = dev->of_node; + + gtp_parse_dt_coords(dev, pdata); + + ret = of_property_read_u32(np, "irq-flags", + &pdata->irq_flags); + if (ret) { + dev_info(dev, + "Failed get int-trigger-type from dts,set default\n"); + pdata->irq_flags = GTP_DEFAULT_INT_TRIGGER; + } + of_property_read_u32(np, "goodix,int-sync", &pdata->int_sync); + if (pdata->int_sync) + dev_info(dev, "int-sync enabled\n"); + + of_property_read_u32(np, "goodix,driver-send-cfg", + &pdata->driver_send_cfg); + if (pdata->driver_send_cfg) + dev_info(dev, "driver-send-cfg enabled\n"); + + of_property_read_u32(np, "goodix,swap-x2y", &pdata->swap_x2y); + if (pdata->swap_x2y) + dev_info(dev, "swap-x2y enabled\n"); + + of_property_read_u32(np, "goodix,slide-wakeup", &pdata->slide_wakeup); + if (pdata->slide_wakeup) + dev_info(dev, "slide-wakeup enabled\n"); + + of_property_read_u32(np, "goodix,auto-update", &pdata->auto_update); + if (pdata->auto_update) + dev_info(dev, "auto-update enabled\n"); + + of_property_read_u32(np, "goodix,auto-update-cfg", + &pdata->auto_update_cfg); + if (pdata->auto_update_cfg) + dev_info(dev, "auto-update-cfg enabled\n"); + + of_property_read_u32(np, "goodix,esd-protect", &pdata->esd_protect); + if (pdata->esd_protect) + dev_info(dev, "esd-protect enabled\n"); + + of_property_read_u32(np, "goodix,type-a-report", + &pdata->type_a_report); + if (pdata->type_a_report) + dev_info(dev, "type-a-report enabled\n"); + + of_property_read_u32(np, "goodix,resume-in-workqueue", + &pdata->resume_in_workqueue); + if (pdata->resume_in_workqueue) + dev_info(dev, "resume-in-workqueue enabled\n"); + + of_property_read_u32(np, "goodix,power-off-sleep", + &pdata->power_off_sleep); + if (pdata->power_off_sleep) + dev_info(dev, "power-off-sleep enabled\n"); + + of_property_read_u32(np, "goodix,pen-suppress-finger", + &pdata->pen_suppress_finger); + if (pdata->pen_suppress_finger) + dev_info(dev, "pen-suppress-finger enabled\n"); + + prop = of_find_property(np, "touchscreen-key-map", NULL); + if (prop) { + key_nums = prop->length / sizeof(key_map[0]); + key_nums = key_nums > MAX_KEY_NUMS ? MAX_KEY_NUMS : key_nums; + + dev_dbg(dev, "key nums %d\n", key_nums); + ret = of_property_read_u32_array(np, + "touchscreen-key-map", key_map, + key_nums); + if (ret) { + dev_err(dev, "Unable to read key codes\n"); + pdata->key_nums = 0; + memset(pdata->key_map, 0, + MAX_KEY_NUMS * sizeof(pdata->key_map[0])); + } + pdata->key_nums = key_nums; + memcpy(pdata->key_map, key_map, + key_nums * sizeof(pdata->key_map[0])); + dev_info(dev, "key-map is [%x %x %x %x]\n", + pdata->key_map[0], pdata->key_map[1], + pdata->key_map[2], pdata->key_map[3]); + } + + pdata->irq_gpio = of_get_named_gpio(np, "irq-gpios", 0); + if (!gpio_is_valid(pdata->irq_gpio)) + dev_err(dev, "No valid irq gpio"); + + pdata->rst_gpio = of_get_named_gpio(np, "reset-gpios", 0); + if (!gpio_is_valid(pdata->rst_gpio)) + dev_err(dev, "No valid rst gpio"); + + return 0; +} + +/******************************************************* + * Function: + * parse config data from devices tree. + * Input: + * dev: device that this driver attached. + * cfg: pointer of the config array. + * cfg_len: pointer of the config length. + * sid: sensor id. + * Output: + * Executive outcomes. + * 0-succeed, -1-faileds. + *******************************************************/ +int gtp_parse_dt_cfg(struct device *dev, u8 *cfg, int *cfg_len, u8 sid) +{ + struct device_node *np = dev->of_node; + struct property *prop; + char cfg_name[18]; + int ret; + + snprintf(cfg_name, sizeof(cfg_name), "goodix,cfg-group%d", sid); + prop = of_find_property(np, cfg_name, cfg_len); + if (!prop || !prop->value || *cfg_len == 0 || + *cfg_len > GTP_CONFIG_MAX_LENGTH) { + *cfg_len = 0; + ret = -EPERM;/* failed */ + } else { + memcpy(cfg, prop->value, *cfg_len); + ret = 0; + } + + return ret; +} + +#endif + +static int gtp_power_on(struct goodix_ts_data *ts) +{ + int ret = 0; + + if (ts->vdd_ana) { + ret = regulator_set_voltage(ts->vdd_ana, GOODIX_VTG_MIN_UV, + GOODIX_VTG_MAX_UV); + if (ret) { + dev_err(&ts->client->dev, + "Regulator set_vtg failed vdd ret=%d\n", + ret); + goto err_set_vtg_vdd_ana; + } + ret = regulator_enable(ts->vdd_ana); + if (ret) { + dev_err(&ts->client->dev, + "Regulator vdd enable failed ret=%d\n", + ret); + goto err_enable_vdd_ana; + } + } + + if (ts->vcc_i2c) { + ret = regulator_set_voltage(ts->vcc_i2c, GOODIX_I2C_VTG_MIN_UV, + GOODIX_I2C_VTG_MAX_UV); + if (ret) { + dev_err(&ts->client->dev, + "Regulator set_vtg failed vcc_i2c ret=%d\n", + ret); + goto err_set_vtg_vcc_i2c; + } + ret = regulator_enable(ts->vcc_i2c); + if (ret) { + dev_err(&ts->client->dev, + "Regulator vcc_i2c enable failed ret=%d\n", + ret); + goto err_enable_vcc_i2c; + } + } + clear_bit(POWER_OFF_MODE, &ts->flags); + return 0; + +err_enable_vcc_i2c: + if (ts->vcc_i2c) + regulator_set_voltage(ts->vcc_i2c, 0, GOODIX_I2C_VTG_MAX_UV); +err_set_vtg_vcc_i2c: + if (ts->vdd_ana) + regulator_disable(ts->vdd_ana); +err_enable_vdd_ana: + if (ts->vdd_ana) + regulator_set_voltage(ts->vdd_ana, 0, GOODIX_VTG_MAX_UV); +err_set_vtg_vdd_ana: + set_bit(POWER_OFF_MODE, &ts->flags); + return ret; +} + +static int gtp_power_off(struct goodix_ts_data *ts) +{ + int ret = 0; + + if (ts->vcc_i2c) { + set_bit(POWER_OFF_MODE, &ts->flags); + ret = regulator_set_voltage(ts->vcc_i2c, 0, + GOODIX_I2C_VTG_MAX_UV); + if (ret < 0) { + dev_err(&ts->client->dev, + "Regulator vcc_i2c set_vtg failed ret=%d\n", + ret); + goto err_set_vtg_vcc_i2c; + } + ret = regulator_disable(ts->vcc_i2c); + if (ret) { + dev_err(&ts->client->dev, + "Regulator vcc_i2c disable failed ret=%d\n", + ret); + goto err_disable_vcc_i2c; + } + dev_info(&ts->client->dev, + "Regulator vcc_i2c disabled\n"); + } + + if (ts->vdd_ana) { + set_bit(POWER_OFF_MODE, &ts->flags); + ret = regulator_set_voltage(ts->vdd_ana, 0, GOODIX_VTG_MAX_UV); + if (ret < 0) { + dev_err(&ts->client->dev, + "Regulator vdd set_vtg failed ret=%d\n", + ret); + goto err_set_vtg_vdd_ana; + } + ret = regulator_disable(ts->vdd_ana); + if (ret) { + dev_err(&ts->client->dev, + "Regulator vdd disable failed ret=%d\n", + ret); + goto err_disable_vdd_ana; + } + dev_info(&ts->client->dev, + "Regulator vdd_ana disabled\n"); + } + return ret; + +err_disable_vdd_ana: + if (ts->vdd_ana) + regulator_set_voltage(ts->vdd_ana, GOODIX_VTG_MIN_UV, + GOODIX_VTG_MAX_UV); +err_set_vtg_vdd_ana: + if (ts->vcc_i2c) + ret = regulator_enable(ts->vcc_i2c); +err_disable_vcc_i2c: + if (ts->vcc_i2c) + regulator_set_voltage(ts->vcc_i2c, GOODIX_I2C_VTG_MIN_UV, + GOODIX_I2C_VTG_MAX_UV); +err_set_vtg_vcc_i2c: + clear_bit(POWER_OFF_MODE, &ts->flags); + return ret; +} + +static int gtp_power_init(struct goodix_ts_data *ts) +{ + int ret; + + ts->vdd_ana = regulator_get(&ts->client->dev, "vdd_ana"); + if (IS_ERR(ts->vdd_ana)) { + ts->vdd_ana = NULL; + ret = PTR_ERR(ts->vdd_ana); + dev_info(&ts->client->dev, + "Regulator get failed vdd ret=%d\n", ret); + } + + ts->vcc_i2c = regulator_get(&ts->client->dev, "vcc_i2c"); + if (IS_ERR(ts->vcc_i2c)) { + ts->vcc_i2c = NULL; + ret = PTR_ERR(ts->vcc_i2c); + dev_info(&ts->client->dev, + "Regulator get failed vcc_i2c ret=%d\n", ret); + } + return 0; +} + +static int gtp_power_deinit(struct goodix_ts_data *ts) +{ + if (ts->vdd_ana) + regulator_put(ts->vdd_ana); + if (ts->vcc_i2c) + regulator_put(ts->vcc_i2c); + + return 0; +} + +static void gtp_shutdown(struct i2c_client *client) +{ + struct goodix_ts_data *data = i2c_get_clientdata(client); + + if (!data->init_done) + return; + + gtp_work_control_enable(data, false); + gtp_power_off(data); +} + +static int gtp_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret = -1; + struct goodix_ts_data *ts; + struct goodix_ts_platform_data *pdata; + + /* do NOT remove these logs */ + dev_info(&client->dev, "GTP Driver Version: %s\n", GTP_DRIVER_VERSION); + dev_info(&client->dev, "GTP I2C Address: 0x%02x\n", client->addr); + + i2c_connect_client = client; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "Failed check I2C functionality"); + return -ENODEV; + } + + ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + devm_kfree(&client->dev, ts); + return -EINVAL; + } + + ts->init_done = false; + +#ifdef CONFIG_OF + if (client->dev.of_node) { + ret = gtp_parse_dt(&client->dev, pdata); + if (ret) { + dev_err(&client->dev, "Failed parse dts\n"); + goto exit_free_client_data; + } + } +#else + /* set parameters at here if you platform doesn't DTS */ + pdata->rst_gpio = GTP_RST_PORT; + pdata->irq_gpio = GTP_INT_PORT; + pdata->slide_wakeup = false; + pdata->auto_update = true; + pdata->auto_update_cfg = false; + pdata->type_a_report = false; + pdata->esd_protect = false; + pdata->max_touch_id = GTP_MAX_TOUCH_ID; + pdata->abs_size_x = GTP_DEFAULT_MAX_X; + pdata->abs_size_y = GTP_DEFAULT_MAX_Y; + pdata->max_touch_width = GTP_DEFAULT_MAX_WIDTH; + pdata->max_touch_pressure = GTP_DEFAULT_MAX_PRESSURE; +#endif + + ts->client = client; + ts->pdata = pdata; + + i2c_set_clientdata(client, ts); + + ret = gtp_power_init(ts); + if (ret) { + dev_err(&client->dev, "Failed get regulator\n"); + ret = -EINVAL; + goto exit_free_client_data; + } + + ret = gtp_pinctrl_init(ts); + if (ret < 0) { + /* if define pinctrl must define the following state + * to let int-pin work normally: default, int_output_high, + * int_output_low, int_input + */ + dev_err(&client->dev, "Failed get wanted pinctrl state\n"); + goto exit_deinit_power; + } + + ret = gtp_request_io_port(ts); + if (ret < 0) { + dev_err(&client->dev, "Failed request IO port\n"); + goto exit_pinctrl; + } + + /*wait for discharging power, which from i2c pull-up flow backward*/ + gtp_rst_output(ts, 0); + msleep(DELAY_FOR_DISCHARGING); + + ret = gtp_power_on(ts); + if (ret) { + dev_err(&client->dev, "Failed power on device\n"); + ret = -EINVAL; + goto exit_free_io_port; + } + + gtp_reset_guitar(ts->client, 20); + + ret = gtp_i2c_test(client); + if (ret) { + dev_err(&client->dev, "Failed communicate with IC use I2C\n"); + goto exit_power_off; + } + + dev_info(&client->dev, "I2C Addr is %x\n", client->addr); + + ret = gtp_get_fw_info(client, &ts->fw_info); + if (ret < 0) { + dev_err(&client->dev, "Failed read FW version\n"); + goto exit_power_off; + } + + pdata->config.data[0] = GTP_REG_CONFIG_DATA >> 8; + pdata->config.data[1] = GTP_REG_CONFIG_DATA & 0xff; + ret = gtp_init_panel(ts); + if (ret < 0) + dev_info(&client->dev, "Panel un-initialize\n"); + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE + if (ts->pdata->auto_update) { + ret = gup_init_update_proc(ts); + if (ret < 0) + dev_err(&client->dev, "Failed create update thread\n"); + } +#endif + + ret = gtp_request_input_dev(ts); + if (ret < 0) { + dev_err(&client->dev, "Failed request input device\n"); + goto exit_power_off; + } + + mutex_init(&ts->lock); + + ret = gtp_request_irq(ts); + if (ret < 0) { + dev_err(&client->dev, "Failed create work thread"); + goto exit_unreg_input_dev; + } + gtp_work_control_enable(ts, false); + if (ts->pdata->slide_wakeup) { + dev_info(&client->dev, "slide wakeup enabled\n"); + ret = enable_irq_wake(client->irq); + if (ret < 0) + dev_err(&client->dev, "Failed set irq wake\n"); + } + + gtp_register_powermanager(ts); + + ret = gtp_create_file(ts); + if (ret) { + dev_info(&client->dev, "Failed create attributes file"); + goto exit_powermanager; + } + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL + init_wr_node(client);/*TODO judge return value */ +#endif + + gtp_esd_init(ts); + gtp_esd_on(ts); + /* probe init finished */ + ts->init_done = true; + gtp_work_control_enable(ts, true); + + return 0; + +exit_powermanager: + gtp_unregister_powermanager(ts); +exit_unreg_input_dev: + input_unregister_device(ts->input_dev); +exit_power_off: + gtp_power_off(ts); +exit_free_io_port: + if (gpio_is_valid(ts->pdata->rst_gpio)) + gpio_free(ts->pdata->rst_gpio); + if (gpio_is_valid(ts->pdata->irq_gpio)) + gpio_free(ts->pdata->irq_gpio); +exit_pinctrl: + gtp_pinctrl_deinit(ts); +exit_deinit_power: + gtp_power_deinit(ts); +exit_free_client_data: + devm_kfree(&client->dev, pdata); + devm_kfree(&client->dev, ts); + i2c_set_clientdata(client, NULL); + + return ret; +} + +static int gtp_drv_remove(struct i2c_client *client) +{ + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + gtp_work_control_enable(ts, false); + gtp_unregister_powermanager(ts); + + remove_proc_entry(GT91XX_CONFIG_PROC_FILE, gtp_config_proc); + + sysfs_remove_group(&client->dev.kobj, >p_attr_group); + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL + uninit_wr_node(); +#endif + + if (ts->pdata->esd_protect) + gtp_esd_off(ts); + + /* TODO: how to judge a irq numbers validity */ + if (ts->client->irq) + free_irq(client->irq, ts); + else + hrtimer_cancel(&ts->timer); + + if (gpio_is_valid(ts->pdata->rst_gpio)) + gpio_free(ts->pdata->rst_gpio); + + if (gpio_is_valid(ts->pdata->irq_gpio)) + gpio_free(ts->pdata->irq_gpio); + + gtp_power_off(ts); + gtp_power_deinit(ts); + gtp_pinctrl_deinit(ts); + dev_info(&client->dev, "goodix ts driver removed"); + i2c_set_clientdata(client, NULL); + input_unregister_device(ts->input_dev); + mutex_destroy(&ts->lock); + + devm_kfree(&client->dev, ts->pdata); + devm_kfree(&client->dev, ts); + + return 0; +} + +static void gtp_suspend(struct goodix_ts_data *ts) +{ + int ret = -1; + + if (test_bit(FW_UPDATE_RUNNING, &ts->flags)) { + dev_warn(&ts->client->dev, + "Fw upgrade in progress, can't go to suspend\n"); + return; + } + + if (test_and_set_bit(SLEEP_MODE, &ts->flags)) { + dev_info(&ts->client->dev, "Already in suspend state\n"); + return; + } + + dev_dbg(&ts->client->dev, "Try enter suspend mode\n"); + + gtp_esd_off(ts); + gtp_work_control_enable(ts, false); + if (ts->pdata->slide_wakeup) { + ret = gtp_enter_doze(ts); + gtp_work_control_enable(ts, true); + } else if (ts->pdata->power_off_sleep) { + /*TODO: power off routine */ + gtp_power_off(ts); + ret = SUCCESS; + } else { + ret = gtp_enter_sleep(ts); + } + + if (ret < 0) + dev_err(&ts->client->dev, "Failed enter suspend\n"); + + /* to avoid waking up while not sleeping */ + /* delay 48 + 10ms to ensure reliability */ + msleep(GTP_58_DLY_MS); +} + +static int gtp_gesture_wakeup(struct goodix_ts_data *ts) +{ + int ret; + int retry = 10; + + do { + gtp_reset_guitar(ts->client, 10); + ret = gtp_i2c_test(ts->client); + if (!ret) + break; + } while (--retry); + + if (!retry) + ret = -EIO; + + clear_bit(DOZE_MODE, &ts->flags); + return ret; +} + +static void gtp_resume(struct goodix_ts_data *ts) +{ + int ret = 0; + + if (test_bit(FW_UPDATE_RUNNING, &ts->flags)) { + dev_info(&ts->client->dev, + "Fw upgrade in progress, can't do resume\n"); + return; + } + + if (!test_bit(SLEEP_MODE, &ts->flags)) { + dev_dbg(&ts->client->dev, "Already in awake state\n"); + return; + } + + dev_info(&ts->client->dev, "Try resume from sleep mode\n"); + + gtp_work_control_enable(ts, false); + + if (ts->pdata->slide_wakeup && test_bit(DOZE_MODE, &ts->flags)) { + ret = gtp_gesture_wakeup(ts); + if (ret) + dev_warn(&ts->client->dev, "Failed wake up from gesture mode\n"); + } else if (ts->pdata->power_off_sleep) { + ret = gtp_power_on(ts); + if (ret) { + dev_warn(&ts->client->dev, "Failed wake up from gesture mode\n"); + } else { + gtp_reset_guitar(ts->client, 20); + ret = gtp_i2c_test(ts->client); + if (ret) + dev_warn(&ts->client->dev, + "I2C communicate failed after power on\n"); + } + } else { + ret = gtp_wakeup_sleep(ts); + if (ret) + dev_warn(&ts->client->dev, + "Failed wakeup from sleep mode\n"); + } + + if (ret) + dev_warn(&ts->client->dev, "Later resume failed\n"); + else + gtp_esd_on(ts); + + clear_bit(SLEEP_MODE, &ts->flags); + gtp_work_control_enable(ts, true); +} + +#if defined(CONFIG_FB) +static void fb_notify_resume_work(struct work_struct *work) +{ + struct goodix_ts_data *ts = + container_of(work, struct goodix_ts_data, fb_notify_work); + dev_info(&ts->client->dev, "try resume in workqueue\n"); + gtp_resume(ts); +} + +/* frame buffer notifier block control the suspend/resume procedure */ +static int gtp_fb_notifier_callback(struct notifier_block *noti, + unsigned long event, void *data) +{ + struct fb_event *ev_data = data; + struct goodix_ts_data *ts = container_of(noti, + struct goodix_ts_data, notifier); + int *blank; + + if (ev_data && ev_data->data && event == FB_EVENT_BLANK && ts) { + blank = ev_data->data; + if (*blank == FB_BLANK_UNBLANK || + *blank == FB_BLANK_NORMAL) { + dev_dbg(&ts->client->dev, "ts_resume"); + if (ts->pdata->resume_in_workqueue) + schedule_work(&ts->fb_notify_work); + else + gtp_resume(ts); + } else if (*blank == FB_BLANK_POWERDOWN) { + dev_dbg(&ts->client->dev, "ts_suspend"); + if (ts->pdata->resume_in_workqueue) + flush_work(&ts->fb_notify_work); + gtp_suspend(ts); + } + } + + return 0; +} + +#elif defined(CONFIG_PM) +static int gtp_pm_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + if (ts) { + dev_dbg(&ts->client->dev, "Suspend by i2c pm."); + gtp_suspend(ts); + } + + return 0; +} + +static int gtp_pm_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + if (ts) { + dev_dbg(&ts->client->dev, "Resume by i2c pm."); + gtp_resume(ts); + } + + return 0; +} + +static const struct dev_pm_ops gtp_pm_ops = { + .suspend = gtp_pm_suspend, + .resume = gtp_pm_resume, +}; + +#elif defined(CONFIG_HAS_EARLYSUSPEND) +static void gtp_early_suspend(struct early_suspend *h) +{ + struct goodix_ts_data *ts = container_of(h, + struct goodix_ts_data, early_suspend); + + if (ts) { + dev_dbg(&ts->client->dev, "Suspend by earlysuspend module."); + gtp_suspend(ts); + } +} + +static void gtp_late_resume(struct early_suspend *h) +{ + struct goodix_ts_data *ts = container_of(h, + struct goodix_ts_data, early_suspend); + + if (ts) { + dev_dbg(&ts->client->dev, "Resume by earlysuspend module."); + gtp_resume(ts); + } +} +#endif + +static int gtp_register_powermanager(struct goodix_ts_data *ts) +{ + int ret; +#if defined(CONFIG_FB) + INIT_WORK(&ts->fb_notify_work, fb_notify_resume_work); + ts->notifier.notifier_call = gtp_fb_notifier_callback; + ret = fb_register_client(&ts->notifier); + if (ret) + dev_err(&ts->client->dev, + "Unable to register fb_notifier: %d\n", ret); +#elif defined(CONFIG_HAS_EARLYSUSPEND) + ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ts->early_suspend.suspend = goodix_ts_early_suspend; + ts->early_suspend.resume = goodix_ts_late_resume; + register_early_suspend(&ts->early_suspend); +#endif + + return ret; +} + +static int gtp_unregister_powermanager(struct goodix_ts_data *ts) +{ +#if defined(CONFIG_FB) + fb_unregister_client(&ts->notifier); +#elif defined(CONFIG_HAS_EARLYSUSPEND) + unregister_early_suspend(&ts->early_suspend); +#endif + + return 0; +} + +/******************************************************* + * Function: + * Initialize external watchdog for esd protect + * Input: + * client: i2c device. + * Output: + * result of i2c write operation. + * 0: succeed, otherwise: failed + ********************************************************/ +static int gtp_init_ext_watchdog(struct i2c_client *client) +{ + int ret; + u8 opr_buffer[3] = { (u8)(GTP_REG_ESD_CHECK >> 8), + (u8)GTP_REG_ESD_CHECK, + (u8)GTP_ESD_CHECK_VALUE }; + + dev_dbg(&client->dev, "[Esd]Init external watchdog\n"); + ret = gtp_i2c_write(client, opr_buffer, 3); + if (ret == 1) + return 0; + + dev_err(&client->dev, "Failed init ext watchdog\n"); + return -EINVAL; +} + +static void gtp_esd_check_func(struct work_struct *work) +{ + s32 i; + s32 ret = -1; + u8 esd_buf[5] = { (u8)(GTP_REG_COMMAND >> 8), (u8)GTP_REG_COMMAND }; + struct delayed_work *dwork = to_delayed_work(work); + struct goodix_ts_esd *ts_esd = container_of(dwork, struct goodix_ts_esd, + delayed_work); + struct goodix_ts_data *ts = container_of(ts_esd, struct goodix_ts_data, + ts_esd); + + if (test_bit(SLEEP_MODE, &ts->flags) || + test_bit(FW_UPDATE_RUNNING, &ts->flags)) { + dev_dbg(&ts->client->dev, + "Esd cancled by power_suspend or fw_update!"); + return; + } + + if (ts_esd->esd_on == false) + return; + + for (i = 0; i < 3; i++) { + ret = gtp_i2c_read(ts->client, esd_buf, 4); + if (ret < 0) + continue; + + dev_dbg(&ts->client->dev, + "[Esd]0x8040 = 0x%02X, 0x8041 = 0x%02X", + esd_buf[2], esd_buf[3]); + if (esd_buf[2] == (u8)GTP_ESD_CHECK_VALUE || + esd_buf[3] != (u8)GTP_ESD_CHECK_VALUE) { + gtp_i2c_read(ts->client, esd_buf, 4); + if (ret < 0) + continue; + + if (esd_buf[2] == (u8)GTP_ESD_CHECK_VALUE || + esd_buf[3] != (u8)GTP_ESD_CHECK_VALUE) { + i = 3; + break; + } + } else { + /* IC works normally, Write 0x8040 0xAA, feed the dog */ + esd_buf[2] = (u8)GTP_ESD_CHECK_VALUE; + gtp_i2c_write(ts->client, esd_buf, 3); + break; + } + } + if (i >= 3) { + dev_err(&ts->client->dev, "IC working abnormally! Reset IC\n"); + esd_buf[0] = 0x42; + esd_buf[1] = 0x26; + esd_buf[2] = 0x01; + esd_buf[3] = 0x01; + esd_buf[4] = 0x01; + gtp_i2c_write(ts->client, esd_buf, 5); + /* TODO: Is power off really need? */ + msleep(GTP_50_DLY_MS); + gtp_power_off(ts); + msleep(GTP_20_DLY_MS); + gtp_power_on(ts); + msleep(GTP_20_DLY_MS); + + gtp_reset_guitar(ts->client, 50); + msleep(GTP_50_DLY_MS); + gtp_send_cfg(ts->client); + } + + if (ts_esd->esd_on == true && !test_bit(SLEEP_MODE, &ts->flags)) { + schedule_delayed_work(&ts_esd->delayed_work, 2 * HZ); + dev_dbg(&ts->client->dev, "ESD work rescheduled\n"); + } +} + +static int gtp_esd_init(struct goodix_ts_data *ts) +{ + struct goodix_ts_esd *ts_esd = &ts->ts_esd; + + INIT_DELAYED_WORK(&ts_esd->delayed_work, gtp_esd_check_func); + mutex_init(&ts_esd->mutex); + ts_esd->esd_on = false; + + return 0; +} + +void gtp_esd_on(struct goodix_ts_data *ts) +{ + struct goodix_ts_esd *ts_esd = &ts->ts_esd; + + if (!ts->pdata->esd_protect) + return; + mutex_lock(&ts_esd->mutex); + if (ts_esd->esd_on == false) { + ts_esd->esd_on = true; + schedule_delayed_work(&ts_esd->delayed_work, 2 * HZ); + dev_info(&ts->client->dev, "ESD on"); + } + mutex_unlock(&ts_esd->mutex); +} + +void gtp_esd_off(struct goodix_ts_data *ts) +{ + struct goodix_ts_esd *ts_esd = &ts->ts_esd; + + if (!ts->pdata->esd_protect) + return; + mutex_lock(&ts_esd->mutex); + if (ts_esd->esd_on == true) { + ts_esd->esd_on = false; + cancel_delayed_work_sync(&ts_esd->delayed_work); + dev_info(&ts->client->dev, "ESD off"); + } + mutex_unlock(&ts_esd->mutex); +} + +#ifdef CONFIG_OF +static const struct of_device_id gtp_match_table[] = { + {.compatible = "goodix,gt9xx",}, + { }, +}; +#endif + +static const struct i2c_device_id gtp_device_id[] = { + { GTP_I2C_NAME, 0 }, + { } +}; + +static struct i2c_driver goodix_ts_driver = { + .probe = gtp_probe, + .remove = gtp_drv_remove, + .id_table = gtp_device_id, + .shutdown = gtp_shutdown, + .driver = { + .name = GTP_I2C_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = gtp_match_table, +#endif +#if !defined(CONFIG_FB) && defined(CONFIG_PM) + .pm = >p_pm_ops, +#endif + }, +}; + +static int __init gtp_init(void) +{ + s32 ret; + + pr_info("Gt9xx driver installing..\n"); + ret = i2c_add_driver(&goodix_ts_driver); + + return ret; +} + +static void __exit gtp_exit(void) +{ + pr_info("Gt9xx driver exited\n"); + i2c_del_driver(&goodix_ts_driver); +} + +module_init(gtp_init); +module_exit(gtp_exit); + +MODULE_DESCRIPTION("GT9 serials touch controller Driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.h b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.h new file mode 100644 index 000000000000..78fa3382487d --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.h @@ -0,0 +1,375 @@ +/* + * Goodix GT9xx touchscreen driver + * + * Copyright (C) 2016 - 2017 Goodix. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * Version: 2.8.0.2 + * Release Date: 2017/12/14 + */ + +#ifndef _GOODIX_GT9XX_H_ +#define _GOODIX_GT9XX_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_OF +#include +#endif +#ifdef CONFIG_FB +#include +#include +#endif +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include + +#define GTP_TOOL_PEN 1 +#define GTP_TOOL_FINGER 2 + +#define MAX_KEY_NUMS 4 +#define GTP_CONFIG_MAX_LENGTH 240 +#define GTP_ADDR_LENGTH 2 + +/***************************PART1:ON/OFF define*******************************/ +#define GTP_DEBUG_ON 1 +#define GTP_DEBUG_ARRAY_ON 0 +#define GTP_DEBUG_FUNC_ON 0 + +struct goodix_point_t { + int id; + int x; + int y; + int w; + int p; + int tool_type; +}; + +struct goodix_config_data { + int length; + u8 data[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH]; +}; + +struct goodix_ts_platform_data { + int irq_gpio; + int rst_gpio; + u32 irq_flags; + u32 abs_size_x; + u32 abs_size_y; + u32 max_touch_id; + u32 max_touch_width; + u32 max_touch_pressure; + u32 key_map[MAX_KEY_NUMS]; + u32 key_nums; + u32 int_sync; + u32 driver_send_cfg; + u32 swap_x2y; + u32 slide_wakeup; + u32 auto_update; + u32 auto_update_cfg; + u32 esd_protect; + u32 type_a_report; + u32 power_off_sleep; + u32 resume_in_workqueue; + u32 pen_suppress_finger; + struct goodix_config_data config; +}; + +struct goodix_ts_esd { + struct delayed_work delayed_work; + struct mutex mutex; + bool esd_on; +}; + +enum { + REPORT_THREAD_ENABLED = 0, + HRTIMER_USED, + FW_ERROR, + + DOZE_MODE, + SLEEP_MODE, + POWER_OFF_MODE, + RAW_DATA_MODE, + + FW_UPDATE_RUNNING, + PANEL_RESETTING +}; + +struct goodix_pinctrl { + struct pinctrl *pinctrl; + struct pinctrl_state *int_default; + struct pinctrl_state *int_out_high; + struct pinctrl_state *int_out_low; + struct pinctrl_state *int_input; + struct pinctrl_state *rst_default; + struct pinctrl_state *rst_out_high; + struct pinctrl_state *rst_out_low; + struct pinctrl_state *rst_input; +}; + +struct goodix_fw_info { + u8 pid[6]; + u16 version; + u8 sensor_id; +}; + +struct goodix_ts_data { + unsigned long flags; /* This member record the device status */ + + struct goodix_ts_esd ts_esd; + struct i2c_client *client; + struct input_dev *input_dev; + struct input_dev *pen_dev; + struct goodix_ts_platform_data *pdata; + /* use pinctrl control int-pin output low or high */ + struct goodix_pinctrl pinctrl; + struct hrtimer timer; + struct mutex lock; + struct notifier_block ps_notif; + struct regulator *vdd_ana; + struct regulator *vcc_i2c; +#if defined(CONFIG_FB) + struct notifier_block notifier; + struct work_struct fb_notify_work; +#elif defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif + struct goodix_fw_info fw_info; + bool force_update; + bool init_done; +}; + +/************************* PART2:TODO define *******************************/ +/* STEP_1(REQUIRED): Define Configuration Information Group(s) + * Sensor_ID Map: + * sensor_opt1 sensor_opt2 Sensor_ID + * GND GND 0 + * VDDIO GND 1 + * NC GND 2 + * GND NC/300K 3 + * VDDIO NC/300K 4 + * NC NC/300K 5 + */ +/* TODO: define your own default or for Sensor_ID == 0 config here. + * The predefined one is just a sample config, + * which is not suitable for your tp in most cases. + */ +#define CTP_CFG_GROUP0 {\ + 0x41, 0xD0, 0x02, 0x00, 0x05, 0x0A, 0x34, \ + 0x00, 0x01, 0x08, 0x28, 0x05, 0x50, 0x32, \ + 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x17, 0x19, 0x1E, 0x14, 0x8C, \ + 0x2D, 0x0E, 0x3C, 0x3E, 0x82, 0x0A, 0x82, \ + 0x0A, 0x00, 0x99, 0x33, 0x1D, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x2B, 0x19, 0x64, 0x94, 0xC0, 0x02, \ + 0x08, 0x00, 0x00, 0x04, 0xF2, 0x1C, 0x00, \ + 0xB9, 0x26, 0x00, 0x93, 0x32, 0x00, 0x77, \ + 0x42, 0x00, 0x62, 0x57, 0x00, 0x62, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0xFF, 0x65, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x19, 0x46, 0x00, 0x00, 0x00, 0x00, 0x32, \ + 0x1C, 0x1A, 0x18, 0x16, 0x14, 0x12, 0x10, \ + 0x0E, 0x0C, 0x0A, 0x08, 0x06, 0x04, 0x02, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x02, 0x04, 0x06, 0x08, \ + 0x0A, 0x0C, 0x0F, 0x10, 0x12, 0x13, 0x14, \ + 0x18, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, \ + 0x22, 0x24, 0x26, 0x28, 0x29, 0x2A, 0xFF, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0xB8, 0x01\ +} + +/* TODO: define your config for Sensor_ID == 1 here, if needed */ +#define CTP_CFG_GROUP1 {\ +} + +/* TODO: define your config for Sensor_ID == 2 here, if needed */ +#define CTP_CFG_GROUP2 {\ +} + +/* TODO: define your config for Sensor_ID == 3 here, if needed */ +#define CTP_CFG_GROUP3 {\ +} +/* TODO: define your config for Sensor_ID == 4 here, if needed */ +#define CTP_CFG_GROUP4 {\ +} + +/* TODO: define your config for Sensor_ID == 5 here, if needed */ +#define CTP_CFG_GROUP5 {\ +} + +/* STEP_2(REQUIRED): Customize your I/O ports & I/O operations */ +#define GTP_RST_PORT 64 /* EXYNOS4_GPX2(0) */ +#define GTP_INT_PORT 65 /* EXYNOS4_GPX2(1) */ + +#define GTP_GPIO_AS_INPUT(pin) (gpio_direction_input(pin)) +#define GTP_GPIO_AS_INT(pin) (GTP_GPIO_AS_INPUT(pin)) +#define GTP_GPIO_GET_VALUE(pin) gpio_get_value(pin) +#define GTP_GPIO_OUTPUT(pin, level) gpio_direction_output(pin, level) +#define GTP_GPIO_REQUEST(pin, label) gpio_request(pin, label) +#define GTP_GPIO_FREE(pin) gpio_free(pin) + +/* STEP_3(optional): Specify your special config info if needed */ +#define GTP_DEFAULT_MAX_X 720 /* default coordinate max values */ +#define GTP_DEFAULT_MAX_Y 1080 +#define GTP_DEFAULT_MAX_WIDTH 1024 +#define GTP_DEFAULT_MAX_PRESSURE 1024 +#define GTP_DEFAULT_INT_TRIGGER 1 /* 1 rising, 2 falling */ +#define GTP_MAX_TOUCH_ID 16 + +/* STEP_4(optional): If keys are available and reported as keys, + * config your key info here + */ +#define GTP_KEY_TAB {KEY_MENU, KEY_HOME, KEY_BACK, KEY_HOMEPAGE, \ + KEY_F1, KEY_F2, KEY_F3} + +/**************************PART3:OTHER define*******************************/ +#define GTP_DRIVER_VERSION "V2.8.0.2<2017/12/14>" +#define GTP_I2C_NAME "goodix-ts" +#define GT91XX_CONFIG_PROC_FILE "gt9xx_config" +#define GTP_POLL_TIME 10 +#define GTP_CONFIG_MIN_LENGTH 186 +#define GTP_ESD_CHECK_VALUE 0xAA +#define RETRY_MAX_TIMES 5 +#define PEN_TRACK_ID 9 +#define MASK_BIT_8 0x80 +#define FAIL 0 +#define SUCCESS 1 + +/* Registers define */ +#define GTP_REG_COMMAND 0x8040 +#define GTP_REG_ESD_CHECK 0x8041 +#define GTP_REG_COMMAND_CHECK 0x8046 +#define GTP_REG_CONFIG_DATA 0x8047 +#define GTP_REG_VERSION 0x8140 +#define GTP_REG_SENSOR_ID 0x814A +#define GTP_REG_DOZE_BUF 0x814B +#define GTP_READ_COOR_ADDR 0x814E + +/* Sleep time define */ +#define GTP_1_DLY_MS 1 +#define GTP_2_DLY_MS 2 +#define GTP_10_DLY_MS 10 +#define GTP_20_DLY_MS 20 +#define GTP_50_DLY_MS 50 +#define GTP_58_DLY_MS 58 +#define GTP_100_DLY_MS 100 +#define GTP_500_DLY_MS 500 +#define GTP_1000_DLY_MS 1000 +#define GTP_3000_DLY_MS 3000 + +#define RESOLUTION_LOC 3 +#define TRIGGER_LOC 8 + +#define CFG_GROUP_LEN(p_cfg_grp) ARRAY_SIZE(p_cfg_grp) +/* Log define */ +#define GTP_DEBUG(fmt, arg...) \ +do { \ + if (GTP_DEBUG_ON) {\ + pr_info("<<-GTP-DEBUG->> [%d]"fmt"\n", __LINE__, ##arg);\ + } \ +} while (0) +#define GTP_DEBUG_ARRAY(array, num) \ +do { \ + s32 i;\ + u8 *a = array;\ + if (GTP_DEBUG_ARRAY_ON) {\ + pr_warn("<<-GTP-DEBUG-ARRAY->>\n");\ + for (i = 0; i < (num); i++) {\ + pr_warn("%02x ", (a)[i]);\ + if ((i + 1) % 10 == 0) {\ + pr_warn("\n");\ + } \ + } \ + pr_warn("\n");\ + } \ +} while (0) +#define GTP_DEBUG_FUNC() \ +do {\ + if (GTP_DEBUG_FUNC_ON) {\ + pr_warn("<<-GTP-FUNC->> Func:%s@Line:%d\n", \ + __func__, __LINE__);\ + } \ +} while (0) +#define GTP_SWAP(x, y) \ +do {\ + typeof(x) z = x;\ + x = y;\ + y = z;\ +} while (0) + +/******************************End of Part III********************************/ +#ifdef CONFIG_OF +extern int gtp_parse_dt_cfg(struct device *dev, u8 *cfg, int *cfg_len, u8 sid); +#endif + +extern void gtp_reset_guitar(struct i2c_client *client, s32 ms); +extern void gtp_int_sync(struct goodix_ts_data *ts, s32 ms); +extern void gtp_esd_on(struct goodix_ts_data *ts); +extern void gtp_esd_off(struct goodix_ts_data *ts); +extern void gtp_work_control_enable(struct goodix_ts_data *ts, bool enable); + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE +extern u16 show_len; +extern u16 total_len; +extern u8 gup_init_update_proc(struct goodix_ts_data *ts); +extern s32 gup_update_proc(void *dir); +extern s32 gup_enter_update_mode(struct i2c_client *client); +extern void gup_leave_update_mode(struct i2c_client *client); +#endif + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL +extern s32 init_wr_node(struct i2c_client *client); +extern void uninit_wr_node(void); +#endif + +/*********** For gt9xx_update Start *********/ +extern struct i2c_client *i2c_connect_client; +extern void gtp_reset_guitar(struct i2c_client *client, s32 ms); +extern void gtp_int_output(struct goodix_ts_data *ts, int level); +extern void gtp_rst_output(struct goodix_ts_data *ts, int level); +extern void gtp_rst_input(struct goodix_ts_data *ts); +extern s32 gtp_send_cfg(struct i2c_client *client); +extern s32 gtp_get_fw_info(struct i2c_client *client, + struct goodix_fw_info *fw_info); +extern s32 gtp_i2c_read_dbl_check(struct i2c_client *client, + u16 addr, u8 *rxbuf, int len); +extern int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len); +extern int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len); +extern s32 gtp_fw_startup(struct i2c_client *client); +extern int gtp_ascii_to_array(const u8 *src_buf, int src_len, u8 *dst_buf); +/*********** For gt9xx_update End *********/ + +#endif /* _GOODIX_GT9XX_H_ */ diff --git a/drivers/input/touchscreen/gt9xx_v2.8/gt9xx_update.c b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx_update.c new file mode 100644 index 000000000000..7a428a3f6c6f --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx_update.c @@ -0,0 +1,2090 @@ +/* + * Goodix GT9xx touchscreen driver + * + * Copyright (C) 2016 - 2017 Goodix. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * but WITHOUT 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 "gt9xx.h" + +#include +#include +#include +#include + +#define GUP_REG_HW_INFO 0x4220 +#define GUP_REG_FW_MSG 0x41E4 +#define GUP_REG_PID_VID 0x8140 + +#define FIRMWARE_NAME_LEN_MAX 256 +#define GOODIX_FIRMWARE_FILE_NAME "goodix_firmware.bin" +#define GOODIX_CONFIG_FILE_NAME "goodix_config.cfg" + +#define FW_HEAD_LENGTH 14 +#define FW_SECTION_LENGTH 0x2000 /* 8K */ +#define FW_DSP_ISP_LENGTH 0x1000 /* 4K */ +#define FW_DSP_LENGTH 0x1000 /* 4K */ +#define FW_BOOT_LENGTH 0x800 /* 2K */ +#define FW_SS51_LENGTH (4 * FW_SECTION_LENGTH) /* 32K */ +#define FW_BOOT_ISP_LENGTH 0x800 /* 2k */ +#define FW_GLINK_LENGTH 0x3000 /* 12k */ +#define FW_GWAKE_LENGTH (4 * FW_SECTION_LENGTH) /* 32k */ + +#define DELAY_FOR_SENDCFG 500 +#define PACK_SIZE 256 +#define MAX_FRAME_CHECK_TIME 5 + +#define _bRW_MISCTL__SRAM_BANK 0x4048 +#define _bRW_MISCTL__MEM_CD_EN 0x4049 +#define _bRW_MISCTL__CACHE_EN 0x404B +#define _bRW_MISCTL__TMR0_EN 0x40B0 +#define _rRW_MISCTL__SWRST_B0_ 0x4180 +#define _bWO_MISCTL__CPU_SWRST_PULSE 0x4184 +#define _rRW_MISCTL__BOOTCTL_B0_ 0x4190 +#define _rRW_MISCTL__BOOT_OPT_B0_ 0x4218 +#define _rRW_MISCTL__BOOT_CTL_ 0x5094 + +#pragma pack(1) +struct st_fw_head { + u8 hw_info[4]; /* hardware info */ + u8 pid[8]; /* product id */ + u16 vid; /* version id */ +}; +#pragma pack() + +struct st_update_msg { + u8 fw_damaged; + u8 fw_flag; + const u8 *fw_data; + struct file *cfg_file; + struct st_fw_head ic_fw_msg; + u32 fw_total_len; + u32 fw_burned_len; + const struct firmware *fw; +} update_msg; + +struct st_update_msg update_msg; + +u16 show_len; +u16 total_len; + +static u8 gup_burn_fw_gwake_section(struct i2c_client *client, + u8 *fw_section, u16 start_addr, + u32 len, u8 bank_cmd); + +static s32 gup_init_panel(struct goodix_ts_data *ts) +{ + s32 ret = 0; + u8 opr_buf[16]; + u8 sensor_id = 0; + u8 drv_cfg_version; + u8 flash_cfg_version; + struct goodix_config_data *cfg = &ts->pdata->config; + + if (cfg->length < GTP_CONFIG_MIN_LENGTH) { + dev_err(&ts->client->dev, + "No valid config with sensor_ID(%d) ", + sensor_id); + + return -EPERM; + } + + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, + &opr_buf[0], 1); + if (ret == SUCCESS) { + dev_dbg(&ts->client->dev, + "CFG_GROUP%d Config Version: %d, IC Config Version: %d", + sensor_id, cfg->data[GTP_ADDR_LENGTH], opr_buf[0]); + + flash_cfg_version = opr_buf[0]; + drv_cfg_version = cfg->data[GTP_ADDR_LENGTH]; + + if (flash_cfg_version < 90 && + flash_cfg_version > drv_cfg_version) + cfg->data[GTP_ADDR_LENGTH] = 0x00; + } else { + dev_err(&ts->client->dev, + "Failed to get ic config version!No config sent!"); + return -EPERM; + } + + ret = gtp_send_cfg(ts->client); + if (ret < 0) + dev_err(&ts->client->dev, "Send config error."); + else + usleep_range(10000, 11000); + + /* restore config vrsion */ + cfg->data[GTP_ADDR_LENGTH] = drv_cfg_version; + + return 0; +} + + +static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8 *msg, s32 len) +{ + s32 i = 0; + + msg[0] = (addr >> 8) & 0xff; + msg[1] = addr & 0xff; + + for (i = 0; i < 5; i++) { + if (gtp_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0) + break; + } + + if (i >= 5) { + dev_err(&client->dev, + "Read data from 0x%02x%02x failed!", + msg[0], msg[1]); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_set_ic_msg(struct i2c_client *client, u16 addr, u8 val) +{ + s32 i = 0; + u8 msg[3]; + + msg[0] = (addr >> 8) & 0xff; + msg[1] = addr & 0xff; + msg[2] = val; + + for (i = 0; i < 5; i++) { + if (gtp_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0) + break; + } + + if (i >= 5) { + dev_err(&client->dev, + "Set data to 0x%02x%02x failed!", msg[0], msg[1]); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_get_ic_fw_msg(struct i2c_client *client) +{ + s32 ret = -1; + u8 retry = 0; + u8 buf[16]; + u8 i; + + /* step1:get hardware info */ + ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO, + &buf[GTP_ADDR_LENGTH], 4); + if (ret == FAIL) { + dev_err(&client->dev, "[get_ic_fw_msg]get hw_info failed,exit"); + return FAIL; + } + + /* buf[2~5]: 00 06 90 00 + * hw_info: 00 90 06 00 + */ + for (i = 0; i < 4; i++) + update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i]; + dev_dbg(&client->dev, + "IC Hardware info:%02x%02x%02x%02x", + update_msg.ic_fw_msg.hw_info[0], + update_msg.ic_fw_msg.hw_info[1], + update_msg.ic_fw_msg.hw_info[2], + update_msg.ic_fw_msg.hw_info[3]); + /* step2:get firmware message */ + for (retry = 0; retry < 2; retry++) { + ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1); + if (ret == FAIL) { + dev_err(&client->dev, "Read firmware message fail."); + return ret; + } + + update_msg.fw_damaged = buf[GTP_ADDR_LENGTH]; + if ((update_msg.fw_damaged != 0xBE) && (!retry)) { + dev_info(&client->dev, "The check sum in ic is error."); + dev_info(&client->dev, "The IC will be updated by force."); + continue; + } + break; + } + dev_dbg(&client->dev, + "IC force update flag:0x%x", update_msg.fw_damaged); + + /* step3:get pid & vid */ + ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID, + &buf[GTP_ADDR_LENGTH], 6); + if (ret == FAIL) { + dev_err(&client->dev, "[get_ic_fw_msg]get pid & vid failed,exit"); + return FAIL; + } + + memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid)); + memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4); + dev_dbg(&client->dev, "IC Product id:%s", update_msg.ic_fw_msg.pid); + + /* GT9XX PID MAPPING */ + /*|-----FLASH-----RAM-----| + *|------918------918-----| + *|------968------968-----| + *|------913------913-----| + *|------913P-----913P----| + *|------927------927-----| + *|------927P-----927P----| + *|------9110-----9110----| + *|------9110P----9111----| + */ + if (update_msg.ic_fw_msg.pid[0] != 0) { + if (!memcmp(update_msg.ic_fw_msg.pid, "9111", 4)) { + dev_dbg(&client->dev, "IC Mapping Product id:%s", + update_msg.ic_fw_msg.pid); + memcpy(update_msg.ic_fw_msg.pid, "9110P", 5); + } + } + + update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH + 4] + + (buf[GTP_ADDR_LENGTH + 5] << 8); + dev_dbg(&client->dev, "IC version id:%04x", update_msg.ic_fw_msg.vid); + + return SUCCESS; +} + +s32 gup_enter_update_mode(struct i2c_client *client) +{ + s32 ret = -1; + s32 retry = 0; + u8 rd_buf[3]; + + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + /* step1:RST output low last at least 2ms */ + if (!gpio_is_valid(ts->pdata->rst_gpio)) { + dev_err(&ts->client->dev, "update failed, no rst pin\n"); + return FAIL; + } + gtp_rst_output(ts, 0); + usleep_range(2000, 3000); + + /* step2:select I2C slave addr,INT:0--0xBA;1--0x28. */ + gtp_int_output(ts, client->addr == 0x14); + usleep_range(2000, 3000); + + /* step3:RST output high reset guitar */ + gtp_rst_output(ts, 1); + + /* 20121211 modify start */ + usleep_range(5000, 6000); + while (retry++ < 200) { + /* step4:Hold ss51 & dsp */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_dbg(&client->dev, + "Hold ss51 & dsp I2C error,retry:%d", + retry); + continue; + } + + /* step5:Confirm hold */ + ret = gup_get_ic_msg(client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1); + if (ret <= 0) { + dev_dbg(&client->dev, + "Hold ss51 & dsp I2C error,retry:%d", + retry); + continue; + } + if (rd_buf[GTP_ADDR_LENGTH] == 0x0C) { + dev_dbg(&client->dev, "Hold ss51 & dsp confirm SUCCESS"); + break; + } + dev_dbg(&client->dev, + "Hold ss51 & dsp confirm 0x4180 failed,value:%d", + rd_buf[GTP_ADDR_LENGTH]); + } + if (retry >= 200) { + dev_err(&client->dev, "Enter update Hold ss51 failed."); + return FAIL; + } + + /* step6:DSP_CK and DSP_ALU_CK PowerOn */ + ret = gup_set_ic_msg(client, 0x4010, 0x00); + + /* 20121211 modify end */ + return ret; +} + +void gup_leave_update_mode(struct i2c_client *client) +{ + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + if (ts->pdata->int_sync && ts->pinctrl.pinctrl) + pinctrl_select_state(ts->pinctrl.pinctrl, + ts->pinctrl.int_input); + else if (ts->pdata->int_sync && gpio_is_valid(ts->pdata->irq_gpio)) + gpio_direction_input(ts->pdata->irq_gpio); + dev_dbg(&client->dev, "[leave_update_mode]reset chip."); + gtp_reset_guitar(i2c_connect_client, 20); +} + +static u8 gup_enter_update_judge(struct i2c_client *client, + struct st_fw_head *fw_head) +{ + u16 u16_tmp; + s32 i = 0; + u32 fw_len = 0; + s32 pid_cmp_len = 0; + + u16_tmp = fw_head->vid; + fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8); + + dev_info(&client->dev, "FILE HARDWARE INFO:%*ph\n", 4, + &fw_head->hw_info[0]); + dev_info(&client->dev, "FILE PID:%s\n", fw_head->pid); + dev_info(&client->dev, "FILE VID:%04x\n", fw_head->vid); + + dev_info(&client->dev, "IC HARDWARE INFO:%*ph\n", 4, + &update_msg.ic_fw_msg.hw_info[0]); + dev_info(&client->dev, "IC PID:%s\n", update_msg.ic_fw_msg.pid); + dev_info(&client->dev, "IC VID:%04x\n", update_msg.ic_fw_msg.vid); + + if (!memcmp(fw_head->pid, "9158", 4) && + !memcmp(update_msg.ic_fw_msg.pid, "915S", 4)) { + dev_info(&client->dev, "Update GT915S to GT9158 directly!"); + return SUCCESS; + } + /* First two conditions */ + if (!memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info, + sizeof(update_msg.ic_fw_msg.hw_info))) { + fw_len = 42 * 1024; + } else { + fw_len = fw_head->hw_info[3]; + fw_len += (((u32)fw_head->hw_info[2]) << 8); + fw_len += (((u32)fw_head->hw_info[1]) << 16); + fw_len += (((u32)fw_head->hw_info[0]) << 24); + } + if (update_msg.fw_total_len != fw_len) { + dev_err(&client->dev, + "Inconsistent firmware size, Update aborted!"); + dev_err(&client->dev, + " Default size: %d(%dK), actual size: %d(%dK)", + fw_len, fw_len/1024, update_msg.fw_total_len, + update_msg.fw_total_len/1024); + return FAIL; + } + dev_info(&client->dev, "Firmware length:%d(%dK)", + update_msg.fw_total_len, + update_msg.fw_total_len/1024); + + if (update_msg.fw_damaged != 0xBE) { + dev_info(&client->dev, "FW chksum error,need enter update."); + return SUCCESS; + } + + /* 20130523 start */ + if (strlen(update_msg.ic_fw_msg.pid) < 3) { + dev_info(&client->dev, "Illegal IC pid, need enter update"); + return SUCCESS; + } + + /* check pid legality */ + for (i = 0; i < 3; i++) { + if (!isdigit(update_msg.ic_fw_msg.pid[i])) { + dev_info(&client->dev, + "Illegal IC pid, need enter update"); + return SUCCESS; + } + } + /* 20130523 end */ + + pid_cmp_len = strlen(fw_head->pid); + if (pid_cmp_len < strlen(update_msg.ic_fw_msg.pid)) + pid_cmp_len = strlen(update_msg.ic_fw_msg.pid); + + if ((!memcmp(fw_head->pid, update_msg.ic_fw_msg.pid, pid_cmp_len)) || + (!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4)) || + (!memcmp(fw_head->pid, "91XX", 4))) { + if (!memcmp(fw_head->pid, "91XX", 4)) + dev_dbg(&client->dev, + "Force none same pid update mode."); + else + dev_dbg(&client->dev, "Get the same pid."); + + /* The third condition */ + if (fw_head->vid != update_msg.ic_fw_msg.vid) { + dev_info(&client->dev, "Need enter update."); + return SUCCESS; + } + dev_err(&client->dev, "File VID == Ic VID, update aborted!"); + } else { + dev_err(&client->dev, "File PID != Ic PID, update aborted!"); + } + + return FAIL; +} + +static int gup_update_config(struct i2c_client *client) +{ + s32 ret = 0; + s32 i = 0; + s32 file_cfg_len = 0; + u8 *file_config; + const struct firmware *fw_cfg; + + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + ret = request_firmware(&fw_cfg, GOODIX_CONFIG_FILE_NAME, + &client->dev); + if (ret < 0) { + dev_err(&client->dev, + "Cannot get config file - %s (%d)\n", + GOODIX_CONFIG_FILE_NAME, ret); + return -EFAULT; + } + if (!fw_cfg || !fw_cfg->data || fw_cfg->size > PAGE_SIZE) { + dev_err(&client->dev, "config file illegal"); + ret = -EFAULT; + goto cfg_fw_err; + } + + dev_dbg(&client->dev, "config firmware file len:%zu", fw_cfg->size); + + file_config = kzalloc(GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH, + GFP_KERNEL); + if (!file_config) { + ret = -ENOMEM; + goto cfg_fw_err; + } + file_config[0] = GTP_REG_CONFIG_DATA >> 8; + file_config[1] = GTP_REG_CONFIG_DATA & 0xff; + file_cfg_len = gtp_ascii_to_array(fw_cfg->data, fw_cfg->size, + &file_config[GTP_ADDR_LENGTH]); + if (file_cfg_len < 0) { + dev_err(&client->dev, "failed covert ascii to hex"); + ret = -EFAULT; + goto update_cfg_file_failed; + } + + GTP_DEBUG_ARRAY(file_config + GTP_ADDR_LENGTH, file_cfg_len); + + i = 0; + while (i++ < 5) { + ret = gtp_i2c_write(client, file_config, file_cfg_len + 2); + if (ret > 0) { + dev_info(&client->dev, "Send config SUCCESS."); + msleep(DELAY_FOR_SENDCFG); + break; + } + dev_err(&ts->client->dev, "Send config i2c error."); + } + +update_cfg_file_failed: + kfree(file_config); +cfg_fw_err: + release_firmware(fw_cfg); + return ret; +} + +static u8 gup_check_firmware_name(struct i2c_client *client, + u8 **path_p) +{ + u8 len; + u8 *fname; + + if (!(*path_p)) { + *path_p = GOODIX_FIRMWARE_FILE_NAME; + return 0; + } + + len = strnlen(*path_p, FIRMWARE_NAME_LEN_MAX); + if (len >= FIRMWARE_NAME_LEN_MAX) { + dev_err(&client->dev, "firmware name too long!"); + return -EINVAL; + } + + fname = strrchr(*path_p, '/'); + if (fname) { + fname = fname + 1; + *path_p = fname; + } + + return 0; +} + +static u8 gup_get_update_file(struct i2c_client *client, + struct st_fw_head *fw_head, u8 *path) +{ + s32 ret = 0; + s32 i = 0; + s32 fw_checksum = 0; + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + if (ts->pdata->auto_update_cfg) { + ret = gup_update_config(client); + if (ret <= 0) + dev_err(&client->dev, "Update config failed."); + } + + ret = gup_check_firmware_name(client, &path); + if (ret < 0) + return FAIL; + + ret = request_firmware(&update_msg.fw, path, &client->dev); + if (ret < 0) { + dev_err(&client->dev, "Failed get firmware:%d\n", ret); + return FAIL; + } + + dev_info(&client->dev, "FW File: %s size=%zu", + path, update_msg.fw->size); + update_msg.fw_data = update_msg.fw->data; + update_msg.fw_total_len = update_msg.fw->size; + + if (update_msg.fw_total_len < + FW_HEAD_LENGTH + FW_SECTION_LENGTH * 4 + FW_DSP_ISP_LENGTH + + FW_DSP_LENGTH + FW_BOOT_LENGTH) { + dev_err(&client->dev, + "INVALID bin file(size: %d), update aborted.", + update_msg.fw_total_len); + goto invalied_fw; + } + + update_msg.fw_total_len -= FW_HEAD_LENGTH; + + dev_dbg(&client->dev, "Bin firmware actual size: %d(%dK)", + update_msg.fw_total_len, update_msg.fw_total_len/1024); + + memcpy(fw_head, update_msg.fw_data, FW_HEAD_LENGTH); + + /* check firmware legality */ + fw_checksum = 0; + for (i = 0; i < update_msg.fw_total_len; i += 2) { + u16 temp; + + temp = (update_msg.fw_data[FW_HEAD_LENGTH + i] << 8) + + update_msg.fw_data[FW_HEAD_LENGTH + i + 1]; + fw_checksum += temp; + } + + dev_dbg(&client->dev, "firmware checksum:%x", fw_checksum&0xFFFF); + if (fw_checksum & 0xFFFF) { + dev_err(&client->dev, "Illegal firmware file."); + goto invalied_fw; + } + + return SUCCESS; + +invalied_fw: + update_msg.fw_data = NULL; + update_msg.fw_total_len = 0; + release_firmware(update_msg.fw); + return FAIL; +} + +static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf, + u16 start_addr, u16 total_length) +{ + s32 ret = 0; + u16 burn_addr = start_addr; + u16 frame_length = 0; + u16 burn_length = 0; + u8 wr_buf[PACK_SIZE + GTP_ADDR_LENGTH]; + u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH]; + u8 retry = 0; + + dev_dbg(&client->dev, "Begin burn %dk data to addr 0x%x", + total_length / 1024, start_addr); + while (burn_length < total_length) { + dev_dbg(&client->dev, + "B/T:%04d/%04d", burn_length, total_length); + frame_length = ((total_length - burn_length) + > PACK_SIZE) ? PACK_SIZE : (total_length - burn_length); + wr_buf[0] = (u8)(burn_addr>>8); + rd_buf[0] = wr_buf[0]; + wr_buf[1] = (u8)burn_addr; + rd_buf[1] = wr_buf[1]; + memcpy(&wr_buf[GTP_ADDR_LENGTH], + &burn_buf[burn_length], frame_length); + + for (retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++) { + ret = gtp_i2c_write(client, + wr_buf, GTP_ADDR_LENGTH + frame_length); + if (ret <= 0) { + dev_err(&client->dev, + "Write frame data i2c error."); + continue; + } + ret = gtp_i2c_read(client, rd_buf, + GTP_ADDR_LENGTH + frame_length); + if (ret <= 0) { + dev_err(&client->dev, + "Read back frame data i2c error."); + continue; + } + if (memcmp(&wr_buf[GTP_ADDR_LENGTH], + &rd_buf[GTP_ADDR_LENGTH], frame_length)) { + dev_err(&client->dev, + "Check frame data fail,not equal."); + dev_dbg(&client->dev, "write array:"); + GTP_DEBUG_ARRAY(&wr_buf[GTP_ADDR_LENGTH], + frame_length); + dev_dbg(&client->dev, "read array:"); + GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], + frame_length); + continue; + } else { + /* dev_dbg(&client->dev, + * "Check frame data success."); + */ + break; + } + } + if (retry >= MAX_FRAME_CHECK_TIME) { + dev_err(&client->dev, + "Burn frame data time out,exit."); + return FAIL; + } + burn_length += frame_length; + burn_addr += frame_length; + } + + return SUCCESS; +} + +static u8 gup_load_section_file(u8 *buf, u32 offset, u16 length, u8 set_or_end) +{ + if (!update_msg.fw_data || + update_msg.fw_total_len < FW_HEAD_LENGTH + offset + length) { + pr_err("<<-GTP->> cannot load section data. fw_len=%d read end=%d\n", + update_msg.fw_total_len, + FW_HEAD_LENGTH + offset + length); + return FAIL; + } + + if (set_or_end == SEEK_SET) { + memcpy(buf, &update_msg.fw_data[FW_HEAD_LENGTH + offset], + length); + } else { + /* seek end */ + memcpy(buf, &update_msg.fw_data[update_msg.fw_total_len + + FW_HEAD_LENGTH - offset], length); + } + + return SUCCESS; +} + +static u8 gup_recall_check(struct i2c_client *client, u8 *chk_src, + u16 start_rd_addr, u16 chk_length) +{ + u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH]; + s32 ret = 0; + u16 recall_addr = start_rd_addr; + u16 recall_length = 0; + u16 frame_length = 0; + + while (recall_length < chk_length) { + frame_length = ((chk_length - recall_length) + > PACK_SIZE) ? PACK_SIZE : + (chk_length - recall_length); + ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length); + if (ret <= 0) { + dev_err(&client->dev, "recall i2c error,exit"); + return FAIL; + } + + if (memcmp(&rd_buf[GTP_ADDR_LENGTH], + &chk_src[recall_length], frame_length)) { + dev_err(&client->dev, "Recall frame data fail,not equal."); + dev_dbg(&client->dev, "chk_src array:"); + GTP_DEBUG_ARRAY(&chk_src[recall_length], frame_length); + dev_dbg(&client->dev, "recall array:"); + GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length); + return FAIL; + } + + recall_length += frame_length; + recall_addr += frame_length; + } + dev_dbg(&client->dev, + "Recall check %dk firmware success.", + (chk_length/1024)); + + return SUCCESS; +} + +static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section, + u16 start_addr, u8 bank_cmd) +{ + s32 ret = 0; + u8 rd_buf[5]; + + /* step1:hold ss51 & dsp */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_section]hold ss51 & dsp fail."); + return FAIL; + } + + /* step2:set scramble */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_section]set scramble fail."); + return FAIL; + } + + /* step3:select bank */ + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, + (bank_cmd >> 4)&0x0F); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]select bank %d fail.", + (bank_cmd >> 4)&0x0F); + return FAIL; + } + + /* step4:enable accessing code */ + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]enable accessing code fail."); + return FAIL; + } + + /* step5:burn 8k fw section */ + ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_section]burn fw_section fail."); + return FAIL; + } + + /* step6:hold ss51 & release dsp */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]hold ss51 & release dsp fail."); + return FAIL; + } + /* must delay */ + usleep_range(1000, 2000); + + /* step7:send burn cmd to move data to flash from sram */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_section]send burn cmd fail."); + return FAIL; + } + dev_dbg(&client->dev, + "[burn_fw_section]Wait for the burn is complete......"); + do { + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]Get burn state fail"); + return FAIL; + } + usleep_range(10000, 11000); + /* dev_dbg(&client->dev, "[burn_fw_section]Get burn state:%d.", + * rd_buf[GTP_ADDR_LENGTH]); + */ + } while (rd_buf[GTP_ADDR_LENGTH]); + + /* step8:select bank */ + ret = gup_set_ic_msg(client, + _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4) & 0x0F); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]select bank %d fail.", + (bank_cmd >> 4)&0x0F); + return FAIL; + } + + /* step9:enable accessing code */ + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]enable accessing code fail."); + return FAIL; + } + + /* step10:recall 8k fw section */ + ret = gup_recall_check(client, + fw_section, start_addr, FW_SECTION_LENGTH); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_section]recall check %dk firmware fail.", + FW_SECTION_LENGTH / 1024); + return FAIL; + } + + /* step11:disable accessing code */ + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]disable accessing code fail."); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_burn_dsp_isp(struct i2c_client *client) +{ + s32 ret = 0; + u8 *fw_dsp_isp = NULL; + u8 retry = 0; + + dev_info(&client->dev, "[burn_dsp_isp]Begin burn dsp isp---->>"); + + /* step1:alloc memory */ + dev_dbg(&client->dev, "[burn_dsp_isp]step1:alloc memory"); + while (retry++ < 5) { + fw_dsp_isp = kzalloc(FW_DSP_ISP_LENGTH, GFP_KERNEL); + if (fw_dsp_isp == NULL) { + continue; + } else { + dev_info(&client->dev, + "[burn_dsp_isp]Alloc %dk byte memory success.", + FW_DSP_ISP_LENGTH / 1024); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, "[burn_dsp_isp]Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load dsp isp file data */ + dev_dbg(&client->dev, "[burn_dsp_isp]step2:load dsp isp file data"); + ret = gup_load_section_file(fw_dsp_isp, + FW_DSP_ISP_LENGTH, FW_DSP_ISP_LENGTH, SEEK_END); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_dsp_isp]load firmware dsp_isp fail."); + goto exit_burn_dsp_isp; + } + + /* step3:disable wdt,clear cache enable */ + dev_dbg(&client->dev, + "[burn_dsp_isp]step3:disable wdt,clear cache enable"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_dsp_isp]disable wdt fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_dsp_isp]clear cache enable fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + /* step4:hold ss51 & dsp */ + dev_dbg(&client->dev, "[burn_dsp_isp]step4:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_err(&client->dev, "[burn_dsp_isp]hold ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + /* step5:set boot from sram */ + dev_dbg(&client->dev, "[burn_dsp_isp]step5:set boot from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02); + if (ret <= 0) { + dev_err(&client->dev, "[burn_dsp_isp]set boot from sram fail"); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + /* step6:software reboot */ + dev_dbg(&client->dev, "[burn_dsp_isp]step6:software reboot"); + ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01); + if (ret <= 0) { + dev_err(&client->dev, "[burn_dsp_isp]software reboot fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + /* step7:select bank2 */ + dev_dbg(&client->dev, "[burn_dsp_isp]step7:select bank2"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02); + if (ret <= 0) { + dev_err(&client->dev, "[burn_dsp_isp]select bank2 fail"); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + /* step8:enable accessing code */ + dev_dbg(&client->dev, "[burn_dsp_isp]step8:enable accessing code"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_dsp_isp]enable accessing code fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + /* step9:burn 4k dsp_isp */ + dev_dbg(&client->dev, "[burn_dsp_isp]step9:burn 4k dsp_isp"); + ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH); + if (ret == FAIL) { + dev_err(&client->dev, "[burn_dsp_isp]burn dsp_isp fail."); + goto exit_burn_dsp_isp; + } + + /* step10:set scramble */ + dev_dbg(&client->dev, "[burn_dsp_isp]step10:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_dsp_isp]set scramble fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + update_msg.fw_burned_len += FW_DSP_ISP_LENGTH; + dev_dbg(&client->dev, "[burn_dsp_isp]Burned length:%d", + update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_dsp_isp: + kfree(fw_dsp_isp); + + return ret; +} + +static u8 gup_burn_fw_ss51(struct i2c_client *client) +{ + u8 *fw_ss51 = NULL; + u8 retry = 0; + s32 ret = 0; + + dev_info(&client->dev, "[burn_fw_ss51]Begin burn ss51 firmware---->>"); + + /* step1:alloc memory */ + dev_dbg(&client->dev, "[burn_fw_ss51]step1:alloc memory"); + while (retry++ < 5) { + fw_ss51 = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL); + if (fw_ss51 == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_ss51]Alloc %dk byte memory success.", + (FW_SECTION_LENGTH / 1024)); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, "[burn_fw_ss51]Alloc memory fail,exit."); + return FAIL; + } + + dev_info(&client->dev, "[burn_fw_ss51]Reset first 8K of ss51 to 0xFF."); + dev_dbg(&client->dev, "[burn_fw_ss51]step2: reset bank0 0xC000~0xD000"); + memset(fw_ss51, 0xFF, FW_SECTION_LENGTH); + + /* step3:clear control flag */ + dev_dbg(&client->dev, "[burn_fw_ss51]step3:clear control flag"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_ss51]clear control flag fail."); + ret = FAIL; + goto exit_burn_fw_ss51; + } + + /* step4:burn ss51 firmware section 1 */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step4:burn ss51 firmware section 1"); + ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_ss51]burn ss51 firmware section 1 fail."); + goto exit_burn_fw_ss51; + } + + /* step5:load ss51 firmware section 2 file data */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step5:load ss51 firmware section 2 file data"); + ret = gup_load_section_file(fw_ss51, + FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_ss51]load ss51 firmware section 2 fail."); + goto exit_burn_fw_ss51; + } + + /* step6:burn ss51 firmware section 2 */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step6:burn ss51 firmware section 2"); + ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_ss51]burn ss51 firmware section 2 fail."); + goto exit_burn_fw_ss51; + } + + /* step7:load ss51 firmware section 3 file data */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step7:load ss51 firmware section 3 file data"); + ret = gup_load_section_file(fw_ss51, + 2 * FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_ss51]load ss51 firmware section 3 fail."); + goto exit_burn_fw_ss51; + } + + /* step8:burn ss51 firmware section 3 */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step8:burn ss51 firmware section 3"); + ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_ss51]burn ss51 firmware section 3 fail."); + goto exit_burn_fw_ss51; + } + + /* step9:load ss51 firmware section 4 file data */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step9:load ss51 firmware section 4 file data"); + ret = gup_load_section_file(fw_ss51, + 3 * FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_ss51]load ss51 firmware section 4 fail."); + goto exit_burn_fw_ss51; + } + + /* step10:burn ss51 firmware section 4 */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step10:burn ss51 firmware section 4"); + ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_ss51]burn ss51 firmware section 4 fail."); + goto exit_burn_fw_ss51; + } + + update_msg.fw_burned_len += (FW_SECTION_LENGTH*4); + dev_dbg(&client->dev, "[burn_fw_ss51]Burned length:%d", + update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_fw_ss51: + kfree(fw_ss51); + return ret; +} + +static u8 gup_burn_fw_dsp(struct i2c_client *client) +{ + s32 ret = 0; + u8 *fw_dsp = NULL; + u8 retry = 0; + u8 rd_buf[5]; + + dev_info(&client->dev, "[burn_fw_dsp]Begin burn dsp firmware---->>"); + /* step1:alloc memory */ + dev_dbg(&client->dev, "[burn_fw_dsp]step1:alloc memory"); + while (retry++ < 5) { + fw_dsp = kzalloc(FW_DSP_LENGTH, GFP_KERNEL); + if (fw_dsp == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_dsp]Alloc %dk byte memory success.", + FW_SECTION_LENGTH / 1024); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, "[burn_fw_dsp]Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load firmware dsp */ + dev_dbg(&client->dev, "[burn_fw_dsp]step2:load firmware dsp"); + ret = gup_load_section_file(fw_dsp, + 4 * FW_SECTION_LENGTH, FW_DSP_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, "[burn_fw_dsp]load firmware dsp fail."); + goto exit_burn_fw_dsp; + } + + /* step3:select bank3 */ + dev_dbg(&client->dev, "[burn_fw_dsp]step3:select bank3"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_dsp]select bank3 fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + + /* step4:hold ss51 & dsp */ + dev_dbg(&client->dev, "[burn_fw_dsp]step4:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_dsp]hold ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + + /* step5:set scramble */ + dev_dbg(&client->dev, "[burn_fw_dsp]step5:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_dsp]set scramble fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + + /* step6:release ss51 & dsp */ + dev_dbg(&client->dev, "[burn_fw_dsp]step6:release ss51 & dsp"); + ret = gup_set_ic_msg( + client, _rRW_MISCTL__SWRST_B0_, 0x04);/* 20121211 */ + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_dsp]release ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + /* must delay */ + usleep_range(1000, 1100); + + /* step7:burn 4k dsp firmware */ + dev_dbg(&client->dev, "[burn_fw_dsp]step7:burn 4k dsp firmware"); + ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH); + if (ret == FAIL) { + dev_err(&client->dev, "[burn_fw_dsp]burn fw_section fail."); + goto exit_burn_fw_dsp; + } + + /* step8:send burn cmd to move data to flash from sram */ + dev_dbg(&client->dev, + "[burn_fw_dsp]step8:send burn cmd to move data to flash from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_dsp]send burn cmd fail."); + goto exit_burn_fw_dsp; + } + dev_dbg(&client->dev, "[burn_fw_dsp]Wait for the burn is complete......"); + do { + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_dsp]Get burn state fail"); + goto exit_burn_fw_dsp; + } + usleep_range(10000, 11000); + /* dev_dbg(&client->dev, "[burn_fw_dsp]Get burn state:%d.", + * rd_buf[GTP_ADDR_LENGTH]); + */ + } while (rd_buf[GTP_ADDR_LENGTH]); + + /* step9:recall check 4k dsp firmware */ + dev_dbg(&client->dev, + "[burn_fw_dsp]step9:recall check 4k dsp firmware"); + ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_dsp]recall check 4k dsp firmware fail."); + goto exit_burn_fw_dsp; + } + + update_msg.fw_burned_len += FW_DSP_LENGTH; + dev_dbg(&client->dev, "[burn_fw_dsp]Burned length:%d", + update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_fw_dsp: + kfree(fw_dsp); + + return ret; +} + +static u8 gup_burn_fw_boot(struct i2c_client *client) +{ + s32 ret = 0; + u8 *fw_boot = NULL; + u8 retry = 0; + u8 rd_buf[5]; + + dev_info(&client->dev, + "[burn_fw_boot]Begin burn bootloader firmware---->>"); + + /* step1:Alloc memory */ + dev_dbg(&client->dev, "[burn_fw_boot]step1:Alloc memory"); + while (retry++ < 5) { + fw_boot = kzalloc(FW_BOOT_LENGTH, GFP_KERNEL); + if (fw_boot == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_boot]Alloc %dk byte memory success.", + FW_BOOT_LENGTH / 1024); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, "[burn_fw_boot]Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load firmware bootloader */ + dev_dbg(&client->dev, "[burn_fw_boot]step2:load firmware bootloader"); + ret = gup_load_section_file(fw_boot, + (4 * FW_SECTION_LENGTH + FW_DSP_LENGTH), FW_BOOT_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_boot]load firmware bootcode fail."); + goto exit_burn_fw_boot; + } + + /* step3:hold ss51 & dsp */ + dev_dbg(&client->dev, "[burn_fw_boot]step3:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot]hold ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + /* step4:set scramble */ + dev_dbg(&client->dev, "[burn_fw_boot]step4:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot]set scramble fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + /* step5:hold ss51 & release dsp */ + dev_dbg(&client->dev, "[burn_fw_boot]step5:hold ss51 & release dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); + /* 20121211 */ + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot]release ss51 & dsp fail"); + ret = FAIL; + goto exit_burn_fw_boot; + } + /* must delay */ + usleep_range(1000, 1100); + + /* step6:select bank3 */ + dev_dbg(&client->dev, "[burn_fw_boot]step6:select bank3"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot]select bank3 fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + /* step6:burn 2k bootloader firmware */ + dev_dbg(&client->dev, + "[burn_fw_boot]step6:burn 2k bootloader firmware"); + ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH); + if (ret == FAIL) { + dev_err(&client->dev, "[burn_fw_boot]burn fw_boot fail."); + goto exit_burn_fw_boot; + } + + /* step7:send burn cmd to move data to flash from sram */ + dev_dbg(&client->dev, + "[burn_fw_boot]step7:send burn cmd to move data to flash from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot]send burn cmd fail."); + goto exit_burn_fw_boot; + } + dev_dbg(&client->dev, + "[burn_fw_boot]Wait for the burn is complete......"); + do { + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_boot]Get burn state fail"); + goto exit_burn_fw_boot; + } + usleep_range(10000, 11000); + /* dev_dbg(&client->dev, "[burn_fw_boot]Get burn state:%d.", + * rd_buf[GTP_ADDR_LENGTH]); + */ + } while (rd_buf[GTP_ADDR_LENGTH]); + + /* step8:recall check 2k bootloader firmware */ + dev_dbg(&client->dev, + "[burn_fw_boot]step8:recall check 2k bootloader firmware"); + ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_boot]recall check 2k bootcode firmware fail"); + goto exit_burn_fw_boot; + } + + update_msg.fw_burned_len += FW_BOOT_LENGTH; + dev_dbg(&client->dev, "[burn_fw_boot]Burned length:%d", + update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_fw_boot: + kfree(fw_boot); + + return ret; +} +static u8 gup_burn_fw_boot_isp(struct i2c_client *client) +{ + s32 ret = 0; + u8 *fw_boot_isp = NULL; + u8 retry = 0; + u8 rd_buf[5]; + + if (update_msg.fw_burned_len >= update_msg.fw_total_len) { + dev_dbg(&client->dev, "No need to upgrade the boot_isp code!"); + return SUCCESS; + } + dev_info(&client->dev, + "[burn_fw_boot_isp]Begin burn boot_isp firmware---->>"); + + /* step1:Alloc memory */ + dev_dbg(&client->dev, "[burn_fw_boot_isp]step1:Alloc memory"); + while (retry++ < 5) { + fw_boot_isp = kzalloc(FW_BOOT_ISP_LENGTH, GFP_KERNEL); + if (fw_boot_isp == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_boot_isp]Alloc %dk byte memory success.", + (FW_BOOT_ISP_LENGTH/1024)); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, + "[burn_fw_boot_isp]Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load firmware bootloader */ + dev_dbg(&client->dev, + "[burn_fw_boot_isp]step2:load firmware bootloader isp"); + /* ret = gup_load_section_file(fw_boot_isp, + * (4*FW_SECTION_LENGTH+FW_DSP_LENGTH + + * FW_BOOT_LENGTH+FW_DSP_ISP_LENGTH), FW_BOOT_ISP_LENGTH, SEEK_SET); + */ + ret = gup_load_section_file(fw_boot_isp, + (update_msg.fw_burned_len - FW_DSP_ISP_LENGTH), + FW_BOOT_ISP_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_boot_isp]load firmware boot_isp fail."); + goto exit_burn_fw_boot_isp; + } + + /* step3:hold ss51 & dsp */ + dev_dbg(&client->dev, "[burn_fw_boot_isp]step3:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot_isp]hold ss51 & dsp fail"); + ret = FAIL; + goto exit_burn_fw_boot_isp; + } + + /* step4:set scramble */ + dev_dbg(&client->dev, "[burn_fw_boot_isp]step4:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot_isp]set scramble fail."); + ret = FAIL; + goto exit_burn_fw_boot_isp; + } + + + /* step5:hold ss51 & release dsp */ + dev_dbg(&client->dev, + "[burn_fw_boot_isp]step5:hold ss51 & release dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); + /* 20121211 */ + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_boot_isp]release ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_boot_isp; + } + /* must delay */ + usleep_range(1000, 2000); + + /* step6:select bank3 */ + dev_dbg(&client->dev, "[burn_fw_boot_isp]step6:select bank3"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot_isp]select bank3 fail."); + ret = FAIL; + goto exit_burn_fw_boot_isp; + } + + /* step7:burn 2k bootload_isp firmware */ + dev_dbg(&client->dev, + "[burn_fw_boot_isp]step7:burn 2k bootloader firmware"); + ret = gup_burn_proc(client, fw_boot_isp, 0x9000, FW_BOOT_ISP_LENGTH); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_boot_isp]burn fw_section fail."); + goto exit_burn_fw_boot_isp; + } + + /* step7:send burn cmd to move data to flash from sram */ + dev_dbg(&client->dev, + "[burn_fw_boot_isp]step8:send burn cmd to move data to flash from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x07); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot_isp]send burn cmd fail."); + goto exit_burn_fw_boot_isp; + } + dev_dbg(&client->dev, + "[burn_fw_boot_isp]Wait for the burn is complete......"); + do { + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_boot_isp]Get burn state fail"); + goto exit_burn_fw_boot_isp; + } + usleep_range(10000, 11000); + /* dev_dbg(&client->dev, "[burn_fw_boot_isp]Get + * burn state:%d.", rd_buf[GTP_ADDR_LENGTH]); + */ + } while (rd_buf[GTP_ADDR_LENGTH]); + + /* step8:recall check 2k bootload_isp firmware */ + dev_dbg(&client->dev, + "[burn_fw_boot_isp]step9:recall check 2k bootloader firmware"); + ret = gup_recall_check(client, fw_boot_isp, 0x9000, FW_BOOT_ISP_LENGTH); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_boot_isp]recall check 2k bootcode_isp firmware fail."); + goto exit_burn_fw_boot_isp; + } + + update_msg.fw_burned_len += FW_BOOT_ISP_LENGTH; + dev_dbg(&client->dev, + "[burn_fw_boot_isp]Burned length:%d", update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_fw_boot_isp: + kfree(fw_boot_isp); + + return ret; +} + +static u8 gup_burn_fw_link(struct i2c_client *client) +{ + u8 *fw_link = NULL; + u8 retry = 0; + s32 ret = 0; + u32 offset; + + if (update_msg.fw_burned_len >= update_msg.fw_total_len) { + dev_dbg(&client->dev, "No need to upgrade the link code!"); + return SUCCESS; + } + dev_info(&client->dev, "[burn_fw_link]Begin burn link firmware---->>"); + + /* step1:Alloc memory */ + dev_dbg(&client->dev, "[burn_fw_link]step1:Alloc memory"); + while (retry++ < 5) { + fw_link = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL); + if (fw_link == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_link]Alloc %dk byte memory success.", + (FW_SECTION_LENGTH/1024)); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, "[burn_fw_link]Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load firmware link section 1 */ + dev_dbg(&client->dev, + "[burn_fw_link]step2:load firmware link section 1"); + offset = update_msg.fw_burned_len - FW_DSP_ISP_LENGTH; + ret = gup_load_section_file( + fw_link, offset, FW_SECTION_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_link]load firmware link section 1 fail."); + goto exit_burn_fw_link; + } + + /* step3:burn link firmware section 1 */ + dev_dbg(&client->dev, + "[burn_fw_link]step3:burn link firmware section 1"); + ret = gup_burn_fw_gwake_section( + client, fw_link, 0x9000, FW_SECTION_LENGTH, 0x38); + + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_link]burn link firmware section 1 fail."); + goto exit_burn_fw_link; + } + + /* step4:load link firmware section 2 file data */ + dev_dbg(&client->dev, + "[burn_fw_link]step4:load link firmware section 2 file data"); + offset += FW_SECTION_LENGTH; + ret = gup_load_section_file( + fw_link, offset, FW_GLINK_LENGTH - FW_SECTION_LENGTH, SEEK_SET); + + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_link]load link firmware section 2 fail."); + goto exit_burn_fw_link; + } + + /* step5:burn link firmware section 2 */ + dev_dbg(&client->dev, + "[burn_fw_link]step4:burn link firmware section 2"); + ret = gup_burn_fw_gwake_section(client, + fw_link, 0x9000, FW_GLINK_LENGTH - FW_SECTION_LENGTH, 0x39); + + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_link]burn link firmware section 2 fail."); + goto exit_burn_fw_link; + } + + update_msg.fw_burned_len += FW_GLINK_LENGTH; + dev_dbg(&client->dev, + "[burn_fw_link]Burned length:%d", update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_fw_link: + kfree(fw_link); + + return ret; +} + +static u8 gup_burn_fw_gwake_section(struct i2c_client *client, + u8 *fw_section, u16 start_addr, u32 len, u8 bank_cmd) +{ + s32 ret = 0; + u8 rd_buf[5]; + + /* step1:hold ss51 & dsp */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_app_section]hold ss51 & dsp fail."); + return FAIL; + } + + /* step2:set scramble */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_app_section]set scramble fail."); + return FAIL; + } + + /* step3:hold ss51 & release dsp */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_app_section]hold ss51 & release dsp fail."); + return FAIL; + } + /* must delay */ + usleep_range(1000, 2000); + + /* step4:select bank */ + ret = gup_set_ic_msg( + client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]select bank %d fail.", + (bank_cmd >> 4)&0x0F); + return FAIL; + } + + /* step5:burn fw section */ + ret = gup_burn_proc(client, fw_section, start_addr, len); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_app_section]burn fw_section fail."); + return FAIL; + } + + /* step6:send burn cmd to move data to flash from sram */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0F); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_app_section]send burn cmd fail."); + return FAIL; + } + dev_dbg(&client->dev, + "[burn_fw_section]Wait for the burn is complete......"); + do { + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_app_section]Get burn state fail"); + return FAIL; + } + usleep_range(10000, 11000); + /* dev_dbg(&client->dev, "[burn_fw_app_section]Get burn state:%d." + * rd_buf[GTP_ADDR_LENGTH]); + */ + } while (rd_buf[GTP_ADDR_LENGTH]); + + /* step7:recall fw section */ + ret = gup_recall_check(client, fw_section, start_addr, len); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_app_section]recall check %dk firmware fail.", + len/1024); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_burn_fw_gwake(struct i2c_client *client) +{ + u8 *fw_gwake = NULL; + u8 retry = 0; + s32 ret = 0; + u16 start_index = 4*FW_SECTION_LENGTH + + FW_DSP_LENGTH + FW_BOOT_LENGTH + + FW_BOOT_ISP_LENGTH + FW_GLINK_LENGTH;/* 32 + 4 + 2 + 4 = 42K */ + /* u16 start_index; */ + + if (start_index >= update_msg.fw_total_len) { + dev_dbg(&client->dev, "No need to upgrade the gwake code!"); + return SUCCESS; + } + /* start_index = update_msg.fw_burned_len - FW_DSP_ISP_LENGTH; */ + dev_info(&client->dev, + "[burn_fw_gwake]Begin burn gwake firmware---->>"); + + /* step1:alloc memory */ + dev_dbg(&client->dev, "[burn_fw_gwake]step1:alloc memory"); + while (retry++ < 5) { + fw_gwake = + kzalloc(FW_SECTION_LENGTH, GFP_KERNEL); + if (fw_gwake == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_gwake]Alloc %dk byte memory success.", + (FW_SECTION_LENGTH/1024)); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, "[burn_fw_gwake]Alloc memory fail,exit."); + return FAIL; + } + + /* clear control flag */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_finish]clear control flag fail."); + goto exit_burn_fw_gwake; + } + + /* step2:load app_code firmware section 1 file data */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step2:load app_code firmware section 1 file data"); + ret = gup_load_section_file(fw_gwake, + start_index, FW_SECTION_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_gwake]load app_code firmware section 1 fail."); + goto exit_burn_fw_gwake; + } + + /* step3:burn app_code firmware section 1 */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step3:burn app_code firmware section 1"); + ret = gup_burn_fw_gwake_section(client, + fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3A); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_gwake]burn app_code firmware section 1 fail."); + goto exit_burn_fw_gwake; + } + + /* step5:load app_code firmware section 2 file data */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step5:load app_code firmware section 2 file data"); + ret = gup_load_section_file( + fw_gwake, start_index+FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_gwake]load app_code firmware section 2 fail."); + goto exit_burn_fw_gwake; + } + + /* step6:burn app_code firmware section 2 */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step6:burn app_code firmware section 2"); + ret = gup_burn_fw_gwake_section(client, + fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3B); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_gwake]burn app_code firmware section 2 fail."); + goto exit_burn_fw_gwake; + } + + /* step7:load app_code firmware section 3 file data */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step7:load app_code firmware section 3 file data"); + ret = gup_load_section_file( + fw_gwake, start_index + 2*FW_SECTION_LENGTH, + FW_SECTION_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_gwake]load app_code firmware section 3 fail."); + goto exit_burn_fw_gwake; + } + + /* step8:burn app_code firmware section 3 */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step8:burn app_code firmware section 3"); + ret = gup_burn_fw_gwake_section( + client, fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3C); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_gwake]burn app_code firmware section 3 fail."); + goto exit_burn_fw_gwake; + } + + /* step9:load app_code firmware section 4 file data */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step9:load app_code firmware section 4 file data"); + ret = gup_load_section_file(fw_gwake, + start_index + 3*FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_gwake]load app_code firmware section 4 fail."); + goto exit_burn_fw_gwake; + } + + /* step10:burn app_code firmware section 4 */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step10:burn app_code firmware section 4"); + ret = gup_burn_fw_gwake_section( + client, fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3D); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_gwake]burn app_code firmware section 4 fail."); + goto exit_burn_fw_gwake; + } + + /* update_msg.fw_burned_len += FW_GWAKE_LENGTH; */ + dev_dbg(&client->dev, + "[burn_fw_gwake]Burned length:%d", update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_fw_gwake: + kfree(fw_gwake); + + return ret; +} + +static u8 gup_burn_fw_finish(struct i2c_client *client) +{ + u8 *fw_ss51 = NULL; + u8 retry = 0; + s32 ret = 0; + + dev_info(&client->dev, + "[burn_fw_finish]burn first 8K of ss51 and finish update."); + /* step1:alloc memory */ + dev_dbg(&client->dev, "[burn_fw_finish]step1:alloc memory"); + while (retry++ < 5) { + fw_ss51 = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL); + if (fw_ss51 == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_finish]Alloc %dk byte memory success.", + (FW_SECTION_LENGTH/1024)); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, + "[burn_fw_finish]Alloc memory fail,exit."); + return FAIL; + } + + dev_dbg(&client->dev, "[burn_fw_finish]step2: burn ss51 first 8K."); + ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_finish]load ss51 firmware section 1 fail."); + goto exit_burn_fw_finish; + } + + dev_dbg(&client->dev, "[burn_fw_finish]step3:clear control flag"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_finish]clear control flag fail."); + goto exit_burn_fw_finish; + } + + dev_dbg(&client->dev, + "[burn_fw_finish]step4:burn ss51 firmware section 1"); + ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_finish]burn ss51 firmware section 1 fail."); + goto exit_burn_fw_finish; + } + + /* step11:enable download DSP code */ + dev_dbg(&client->dev, + "[burn_fw_finish]step5:enable download DSP code "); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_finish]enable download DSP code fail."); + goto exit_burn_fw_finish; + } + + /* step12:release ss51 & hold dsp */ + dev_dbg(&client->dev, "[burn_fw_finish]step6:release ss51 & hold dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_finish]release ss51 & hold dsp fail."); + goto exit_burn_fw_finish; + } + + if (fw_ss51 != NULL) + kfree(fw_ss51); + return SUCCESS; + +exit_burn_fw_finish: + if (fw_ss51 != NULL) + kfree(fw_ss51); + + return FAIL; +} + +/* return 0 can update, else no update condition */ +static int gup_update_condition_check(struct goodix_ts_data *ts) +{ + if (test_bit(SLEEP_MODE, &ts->flags)) { + dev_info(&ts->client->dev, "Update abort, tp in sleep mode\n"); + return -EINVAL; + } + + return 0; +} +s32 gup_update_proc(void *dir) +{ + s32 ret = 0; + s32 update_ret = FAIL; + u8 retry = 0; + struct st_fw_head fw_head; + struct goodix_ts_data *ts = NULL; + + ts = i2c_get_clientdata(i2c_connect_client); + + dev_dbg(&ts->client->dev, "[update_proc]Begin update ......\n"); + + show_len = 1; + total_len = 100; + + ret = gup_update_condition_check(ts); + if (ret) { + dev_warn(&ts->client->dev, "Update start failed\n"); + return FAIL; + } + + if (test_and_set_bit(FW_UPDATE_RUNNING, &ts->flags)) { + dev_warn(&ts->client->dev, "FW update may already running\n"); + return FAIL; + } + + ret = gup_get_update_file(i2c_connect_client, &fw_head, (u8 *)dir); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "Failed get valied firmware data\n"); + clear_bit(FW_UPDATE_RUNNING, &ts->flags); + return FAIL; + } + + gtp_work_control_enable(ts, false); + gtp_esd_off(ts); + + ret = gup_get_ic_fw_msg(i2c_connect_client); + if (ret == FAIL) { + dev_err(&ts->client->dev, "[update_proc]get ic message fail."); + goto file_fail; + } + + if (ts->force_update || dir) { + dev_dbg(&ts->client->dev, "Enter force update."); + } else { + ret = gup_enter_update_judge(i2c_connect_client, &fw_head); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]Doesn't meet update condition\n"); + goto file_fail; + } + } + + ret = gup_enter_update_mode(ts->client); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]enter update mode fail."); + goto update_fail; + } + + while (retry++ < 5) { + show_len = 10; + total_len = 100; + update_msg.fw_burned_len = 0; + ret = gup_burn_dsp_isp(i2c_connect_client); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]burn dsp isp fail."); + continue; + } + + show_len = 20; + ret = gup_burn_fw_gwake(i2c_connect_client); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]burn app_code firmware fail."); + continue; + } + + show_len = 30; + ret = gup_burn_fw_ss51(i2c_connect_client); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]burn ss51 firmware fail."); + continue; + } + + show_len = 40; + ret = gup_burn_fw_dsp(i2c_connect_client); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]burn dsp firmware fail."); + continue; + } + + show_len = 50; + ret = gup_burn_fw_boot(i2c_connect_client); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]burn bootloader firmware fail."); + continue; + } + show_len = 60; + + ret = gup_burn_fw_boot_isp(i2c_connect_client); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]burn boot_isp firmware fail."); + continue; + } + + show_len = 70; + ret = gup_burn_fw_link(i2c_connect_client); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]burn link firmware fail."); + continue; + } + + show_len = 80; + ret = gup_burn_fw_finish(i2c_connect_client); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]burn finish fail."); + continue; + } + show_len = 90; + dev_info(&ts->client->dev, "[update_proc]UPDATE SUCCESS."); + retry = 0; + break; + } + + if (retry >= 5) { + dev_err(&ts->client->dev, + "[update_proc]retry timeout,UPDATE FAIL."); + update_ret = FAIL; + } else { + update_ret = SUCCESS; + } + +update_fail: + dev_dbg(&ts->client->dev, "[update_proc]leave update mode."); + gup_leave_update_mode(i2c_connect_client); + + msleep(GTP_100_DLY_MS); + + if (update_ret == SUCCESS) { + dev_info(&ts->client->dev, + "firmware error auto update, resent config!\n"); + gup_init_panel(ts); + } + gtp_get_fw_info(ts->client, &ts->fw_info); + +file_fail: + + update_msg.fw_data = NULL; + update_msg.fw_total_len = 0; + release_firmware(update_msg.fw); + + clear_bit(FW_UPDATE_RUNNING, &ts->flags); + gtp_work_control_enable(ts, true); + gtp_esd_on(ts); + total_len = 100; + ts->force_update = false; + if (update_ret == SUCCESS) { + show_len = 100; + clear_bit(FW_ERROR, &ts->flags); + return SUCCESS; + } + + show_len = 200; + return FAIL; +} + +u8 gup_init_update_proc(struct goodix_ts_data *ts) +{ + struct task_struct *thread = NULL; + + dev_info(&ts->client->dev, "Ready to run update thread."); + + thread = kthread_run(gup_update_proc, + (void *)NULL, "guitar_update"); + + if (IS_ERR(thread)) { + dev_err(&ts->client->dev, + "Failed to create update thread.\n"); + return -EPERM; + } + + return 0; +} -- GitLab From 63cc55b445f2520d9bb9291f794935668806ab58 Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Wed, 18 Jul 2018 13:14:42 +0530 Subject: [PATCH 416/604] defconfig: msm: Enable Minidump for SDM845 Enable Minidump support for perf builds on SDM845. Change-Id: I669a289101806410cff0bfc9f22875ed36807a25 Signed-off-by: Lingutla Chandrasekhar --- arch/arm64/configs/sdm845-perf_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig index e35e571cb7a8..0c541826b47d 100644 --- a/arch/arm64/configs/sdm845-perf_defconfig +++ b/arch/arm64/configs/sdm845-perf_defconfig @@ -520,6 +520,7 @@ CONFIG_MSM_BOOT_STATS=y CONFIG_QCOM_EUD=y CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_MINIDUMP=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_BUS_CONFIG_RPMH=y CONFIG_QCOM_SECURE_BUFFER=y -- GitLab From 0af3c660bc565c84e159e5ac045bb2f1fa476ab6 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Fri, 29 Jun 2018 15:06:00 +0530 Subject: [PATCH 417/604] msm: ipa: Error prints are misleading fix it IPC logging is for debugging purpose and it may disabled in kernel anytime. From IPA driver printing the error log on IPC create context is misleading. Instead of error, make it as debug. Change-Id: Icee2b1ad9fcef446f79dfc71f554a24a90ea3d2d Signed-off-by: Mohammed Javid --- drivers/platform/msm/ipa/ipa_v2/ipa.c | 8 ++------ drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c | 2 +- drivers/platform/msm/ipa/ipa_v3/ipa.c | 2 +- drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c | 2 +- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c index 10468f34c85b..6f9afa678dfb 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c @@ -3938,11 +3938,8 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, } ipa_ctx->logbuf = ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa", 0); - if (ipa_ctx->logbuf == NULL) { - IPAERR("failed to get logbuf\n"); - result = -ENOMEM; - goto fail_logbuf; - } + if (ipa_ctx->logbuf == NULL) + IPADBG("failed to create IPC log, continue...\n"); ipa_ctx->pdev = ipa_dev; ipa_ctx->uc_pdev = ipa_dev; @@ -4488,7 +4485,6 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, kfree(ipa_ctx->ctrl); fail_mem_ctrl: ipc_log_context_destroy(ipa_ctx->logbuf); -fail_logbuf: kfree(ipa_ctx); ipa_ctx = NULL; fail_mem_ctx: diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c index c2f7aae63a12..7d315a4b0c0c 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c @@ -1903,7 +1903,7 @@ static ssize_t ipa_enable_ipc_low(struct file *file, ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa_low", 0); if (ipa_ipc_low_buff == NULL) - IPAERR("failed to get logbuf_low\n"); + IPADBG("failed to get logbuf_low\n"); } ipa_ctx->logbuf_low = ipa_ipc_low_buff; } else { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index c7422c79533f..8a773e4d84c6 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -5018,7 +5018,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, ipa3_ctx->logbuf = ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa", 0); if (ipa3_ctx->logbuf == NULL) - IPAERR("failed to create IPC log, continue...\n"); + IPADBG("failed to create IPC log, continue...\n"); /* ipa3_ctx->pdev and ipa3_ctx->uc_pdev will be set in the smmu probes*/ ipa3_ctx->master_pdev = ipa_pdev; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index 10abdcf45499..3728a4376087 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -2089,7 +2089,7 @@ static ssize_t ipa3_enable_ipc_low(struct file *file, "ipa_low", 0); } if (ipa_ipc_low_buff == NULL) - IPAERR("failed to get logbuf_low\n"); + IPADBG("failed to get logbuf_low\n"); ipa3_ctx->logbuf_low = ipa_ipc_low_buff; } else { ipa3_ctx->logbuf_low = NULL; -- GitLab From fd4231b22522dda1e2f529a8bd6c45b30fc37ce1 Mon Sep 17 00:00:00 2001 From: Pratap Nirujogi Date: Tue, 17 Jul 2018 15:57:24 +0530 Subject: [PATCH 418/604] msm: camera: cpp: Check for valid tx level check for valid tx level before reading the tx fifo Change-Id: I5600debb0eeaea84b37fe357c598fd13a3238e70 Signed-off-by: Pratap Nirujogi --- .../media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index 1ad2f2578445..85ca27540c3e 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -949,9 +949,14 @@ static irqreturn_t msm_cpp_irq(int irq_num, void *data) if (irq_status & 0x8) { tx_level = msm_camera_io_r(cpp_dev->base + MSM_CPP_MICRO_FIFO_TX_STAT) >> 2; - for (i = 0; i < tx_level; i++) { - tx_fifo[i] = msm_camera_io_r(cpp_dev->base + - MSM_CPP_MICRO_FIFO_TX_DATA); + if (tx_level < MSM_CPP_TX_FIFO_LEVEL) { + for (i = 0; i < tx_level; i++) { + tx_fifo[i] = msm_camera_io_r(cpp_dev->base + + MSM_CPP_MICRO_FIFO_TX_DATA); + } + } else { + pr_err("Fatal invalid tx level %d", tx_level); + goto err; } spin_lock_irqsave(&cpp_dev->tasklet_lock, flags); queue_cmd = &cpp_dev->tasklet_queue_cmd[cpp_dev->taskletq_idx]; @@ -1006,6 +1011,7 @@ static irqreturn_t msm_cpp_irq(int irq_num, void *data) pr_debug("DEBUG_R1: 0x%x\n", msm_camera_io_r(cpp_dev->base + 0x8C)); } +err: msm_camera_io_w(irq_status, cpp_dev->base + MSM_CPP_MICRO_IRQGEN_CLR); return IRQ_HANDLED; } -- GitLab From 0ae5cc3799074b0761bd2476710e542ce3a2fc12 Mon Sep 17 00:00:00 2001 From: Liangliang Lu Date: Tue, 17 Jul 2018 13:26:46 +0800 Subject: [PATCH 419/604] sound: usb: use er_mapped flag to indicate event ring mapped or not In the case that have two USB controller, xHCI address is different. If we plug in one USB headset to one USB port, and play audio, when another USB head plug into the 2rd USB port, there will be IOMMU mapping error like below. Fix this by use er_mapped flag instead of xHCI address to indicate event ring mapped or not. [] arm_lpae_init_pte.isra.11+0x4c/0xf0 [] __arm_lpae_map+0x38c/0x3a4 [] __arm_lpae_map+0x118/0x3a4 [] __arm_lpae_map+0x118/0x3a4 [] arm_lpae_map+0x8c/0xa8 [] arm_smmu_map+0x9c/0x134 [] iommu_map+0xe8/0x2f0 [] uaudio_iommu_map+0x27c/0x338 [] handle_uaudio_stream_req+0x608/0x1030 [] uaudio_qmi_svc_req_cb+0x7c/0xa4 [] qmi_recv_msg+0x23c/0x97c [] uaudio_qmi_svc_recv_msg+0x70/0xa8 [] process_one_work+0x1a8/0x4ac [] worker_thread+0x140/0x460 [] kthread+0xf4/0x108 [] ret_from_fork+0x10/0x50 Change-Id: Ibbb670d226fdfd6c2589996b8e4b406ab26e0e9a Signed-off-by: Liangliang Lu --- sound/usb/usb_audio_qmi_svc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c index ce1f0ad8e5c0..fe29aed37660 100644 --- a/sound/usb/usb_audio_qmi_svc.c +++ b/sound/usb/usb_audio_qmi_svc.c @@ -110,8 +110,8 @@ struct uaudio_qmi_dev { unsigned long curr_xfer_buf_iova; /* bit fields representing pcm card enabled */ unsigned long card_slot; - /* cache event ring phys addr */ - u64 er_phys_addr; + /* indicate event ring mapped or not */ + bool er_mapped; }; static struct uaudio_qmi_dev *uaudio_qdev; @@ -295,7 +295,7 @@ static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa, case MEM_EVENT_RING: va = IOVA_BASE; /* er already mapped */ - if (uaudio_qdev->er_phys_addr == pa) + if (uaudio_qdev->er_mapped) map = false; break; case MEM_XFER_RING: @@ -407,8 +407,8 @@ static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va, switch (mtype) { case MEM_EVENT_RING: - if (uaudio_qdev->er_phys_addr) - uaudio_qdev->er_phys_addr = 0; + if (uaudio_qdev->er_mapped) + uaudio_qdev->er_mapped = false; else unmap = false; break; @@ -637,7 +637,7 @@ static int prepare_qmi_response(struct snd_usb_substream *subs, uaudio_qdev->sid); resp->xhci_mem_info.evt_ring.pa = dma; resp->xhci_mem_info.evt_ring.size = PAGE_SIZE; - uaudio_qdev->er_phys_addr = xhci_pa; + uaudio_qdev->er_mapped = true; resp->speed_info = get_speed_info(subs->dev->speed); if (resp->speed_info == USB_AUDIO_DEVICE_SPEED_INVALID_V01) -- GitLab From 146ed987bf3b2a36acc667c5cde49928aa4c1cf8 Mon Sep 17 00:00:00 2001 From: raghavendra ambadas Date: Tue, 17 Jul 2018 16:36:36 +0530 Subject: [PATCH 420/604] fbdev: msm: Avoid reserve of mixers for single layer mixer Avoid reserving mixer for target having only one layer mixer. Check for nunber of active layer mixer's present and avoid allocating mixers to external or pluggable display if active layer mixers are more than one. Change-Id: I1ff7cff03808b65bb2e5ae6bdc897f48c6b1d5cd Signed-off-by: Raghavendra Ambadas --- drivers/video/fbdev/msm/mdss_mdp_ctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 4cfb48d6a99b..0b6195d536af 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -2559,7 +2559,7 @@ struct mdss_mdp_mixer *mdss_mdp_mixer_alloc( mixer_pool += ctl->mdata->ndspp; nmixers -= ctl->mdata->ndspp; } else if ((ctl->panel_data->panel_info.is_pluggable) && - nmixers_active) { + nmixers_active > 1) { mixer_pool += ctl->mdata->ndspp; nmixers -= ctl->mdata->ndspp; } -- GitLab From df93b2b1a2fa01a6f35fe92672ab38f2260e7151 Mon Sep 17 00:00:00 2001 From: "Katepallewar, Mrugesh" Date: Wed, 11 Jul 2018 17:56:42 +0530 Subject: [PATCH 421/604] ARM: dts: msm: Add support for 8" hx8394d dsi panel Add support for dsi-panel-hx8394d-wxga video mode panel for enabling display on OpenQ 624 - hw variants. Change-Id: I69f95cd6667b336b631d78db8e2fc1c38ca8a2a5 Signed-off-by: Katepallewar, Mrugesh Git-commit: c21f31e903c3af1bb370aeda8f22cbb15ed163c2 Git-Repo: https://github.com/mrugeshmk/h_pjt Signed-off-by: Vijay Navnath Kamble --- .../qcom/dsi-panel-hx8394d-wxga-video.dtsi | 86 +++++++++++++++++++ .../boot/dts/qcom/msm8953-mdss-panels.dtsi | 9 ++ 2 files changed, 95 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-hx8394d-wxga-video.dtsi diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx8394d-wxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx8394d-wxga-video.dtsi new file mode 100644 index 000000000000..69f168b8e054 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx8394d-wxga-video.dtsi @@ -0,0 +1,86 @@ +/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&mdss_mdp { + dsi_hx8394d_kingdisplay_vid: qcom,mdss_dsi_hx8394d_kingdisplay_vid { + qcom,mdss-dsi-panel-name = "hx8394d wxga video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <800>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-h-front-porch = <24>; + qcom,mdss-dsi-h-back-porch = <132>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <16>; + qcom,mdss-dsi-v-front-porch = <9>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 04 B9 FF 83 94 + 39 01 00 00 32 00 05 D9 00 8B 02 07 + 39 01 00 00 00 00 03 BA 73 83 + 39 01 00 00 00 00 10 B1 6C 10 10 24 E4 11 F1 80 E4 D7 23 80 C0 D2 58 + 39 01 00 00 00 00 0C B2 00 64 10 07 70 1C 08 08 1C 4D 00 + 39 01 00 00 00 00 0D B4 00 FF 03 5A 03 5A 03 5A 01 6A 01 6A + 39 01 00 00 00 00 1F D3 00 06 00 40 1A 08 00 32 10 07 00 07 54 15 0F 05 04 02 12 10 05 07 33 33 0B 0B 37 10 07 07 + 39 01 00 00 00 00 2D D5 19 19 18 18 1A 1A 1B 1B 04 05 06 07 00 01 02 03 20 21 18 18 18 18 18 18 18 18 18 18 18 18 22 23 18 18 18 18 18 18 18 18 18 18 18 18 + 39 01 00 00 00 00 2D D6 18 18 19 19 1A 1A 1B 1B 03 02 01 00 07 06 05 04 23 22 18 18 18 18 18 18 18 18 18 18 18 18 21 20 18 18 18 18 18 18 18 18 19 18 18 18 + 39 01 00 00 00 00 2B E0 00 00 02 3C 3E 3F 12 3D 06 09 0A 19 0F 11 14 12 13 07 12 15 16 00 00 01 3C 3E 3F 12 3D 07 09 0B 12 0D 11 13 11 13 08 13 14 19 + 15 01 00 00 00 00 02 CC 09 + 15 01 00 00 00 00 02 D2 55 + 39 01 00 00 00 00 03 C0 30 14 + 39 01 00 00 00 00 04 BF 41 0E 01 + 39 01 00 00 00 00 05 C7 00 C0 40 C0 + 15 01 00 00 00 00 02 DF 8E + 05 01 00 00 C8 00 01 11 + 05 01 00 00 C8 00 01 29 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = + [8B 1f 14 00 45 4A 19 23 23 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x04>; + qcom,mdss-dsi-t-clk-pre = <0x1D>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>; + qcom,mdss-dsi-init-delay-us = <50000>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-pan-physical-width-dimension = <107>; + qcom,mdss-pan-physical-height-dimension = <172>; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi index 7bc181c3a265..be6ab790373e 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi @@ -26,6 +26,7 @@ #include "dsi-panel-hx8399c-fhd-plus-video.dtsi" #include "dsi-panel-hx83100a-800p-video.dtsi" #include "dsi-panel-boent51021-1200p-video.dtsi" +#include "dsi-panel-hx8394d-wxga-video.dtsi" &soc { dsi_panel_pwr_supply: dsi_panel_pwr_supply { @@ -184,3 +185,11 @@ 25 20 08 0a 06 03 04 a0 25 1d 08 0a 06 03 04 a0]; }; + +&dsi_hx8394d_kingdisplay_vid { + qcom,mdss-dsi-panel-timings-phy-v2 = [1c 19 02 03 01 03 04 a0 + 1c 19 02 03 01 03 04 a0 + 1c 19 02 03 01 03 04 a0 + 1c 19 02 03 01 03 04 a0 + 1c 07 02 03 01 03 04 a0]; +}; -- GitLab From f9e6109ddaa4eb41dcc208154dd1bc8acf3a9b72 Mon Sep 17 00:00:00 2001 From: Monika Singh Date: Wed, 13 Jun 2018 12:27:47 +0530 Subject: [PATCH 422/604] ARM: dts: Mount system as root for msm8917go System needs to be mounted as root with the System-As-Root feature for non-A/B builds. Change-Id: Ifb5dd5877f30fdb2aec0e1ce53ffb3bfd10677ca Signed-off-by: Monika Singh --- arch/arm64/boot/dts/qcom/msm8917.dtsi | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8917.dtsi b/arch/arm64/boot/dts/qcom/msm8917.dtsi index cc51694a7d37..d5f524325a14 100644 --- a/arch/arm64/boot/dts/qcom/msm8917.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917.dtsi @@ -68,14 +68,6 @@ fsmgr_flags = "wait,avb"; status = "ok"; }; - system { - compatible = "android,system"; - dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system"; - type = "ext4"; - mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait,avb"; - status = "ok"; - }; }; }; }; -- GitLab From da6a68d0784b00954f22be343853551da43c1ae4 Mon Sep 17 00:00:00 2001 From: Ramandeep Trehan Date: Wed, 18 Jul 2018 17:22:01 +0530 Subject: [PATCH 423/604] msm8937: Enable config flag for File based Encryption File system flags for ext4 are required for Inline Crypto Engine based file encryption to work smoothly. Change-Id: Iaede05ffca2b5f821153cd695e46825057268800 Signed-off-by: Ramandeep Trehan --- arch/arm/configs/msm8937-perf_defconfig | 3 +++ arch/arm/configs/msm8937_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index 34c9daafbafc..3747ca39cc1f 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -592,6 +592,9 @@ CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index e4c9eb2d90dc..a33bdbdd8f8c 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -613,6 +613,9 @@ CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_ENCRYPTION=y -- GitLab From f5edaf756e8c09326d06c87247072ed621783acc Mon Sep 17 00:00:00 2001 From: Vijay Navnath Kamble Date: Wed, 11 Jul 2018 18:35:06 +0530 Subject: [PATCH 424/604] ARM: dts: msm: Enable display panel support for OpenQ 624 hw variant Add display node to support hx8394d wxga video mode dsi panel. Add corresponding mdss node information for OpenQ 624 hw variant. Change-Id: I5128f9eac543209253ff6adca399df0951329f37 Signed-off-by: Vijay Navnath Kamble --- .../dts/qcom/apq8053-lite-dragon-v2.3.dtsi | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.3.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.3.dtsi index 5cf8ac06ff43..c682f58f0e1d 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.3.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.3.dtsi @@ -42,6 +42,7 @@ &i2c_3 { status = "okay"; + /delete-node/ focaltech@38; /delete-node/ himax_ts@48; focaltech_ts@38 { compatible = "focaltech,fts"; @@ -64,6 +65,7 @@ }; &wled { + qcom,cons-sync-write-delay-us = <1000>; qcom,led-strings-list = [00 01 02]; }; @@ -78,3 +80,19 @@ &camera2{ qcom,mount-angle = <90>; }; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_hx8394d_kingdisplay_vid>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + + vdd-supply = <&pm8953_l17>; + vddio-supply = <&pm8953_l6>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + + qcom,platform-te-gpio = <&tlmm 24 0>; + qcom,platform-reset-gpio = <&tlmm 61 0>; + qcom,platform-bklight-en-gpio = <&tlmm 100 0>; +}; -- GitLab From d996b26efee64c7e499daf4f8b4ac217823327a5 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Wed, 18 Jul 2018 22:28:53 +0530 Subject: [PATCH 425/604] msm: adsprpc: DSP device node to provide restricted access to ADSP/SLPI Support 2 separate device nodes with this change, one for ADSP/SLPI and another for CDSP. Change-Id: I2a09ebfdeccd9a092b1a3602c249b2727ec91c92 Acked-by: Amol Mahesh Signed-off-by: Tharun Kumar Merugu --- .../devicetree/bindings/qdsp/msm-fastrpc.txt | 1 + drivers/char/adsprpc.c | 125 +++++++++++++++++- drivers/char/adsprpc_shared.h | 1 + 3 files changed, 120 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt index a034acc98aa6..e546dc22a368 100644 --- a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt +++ b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt @@ -16,6 +16,7 @@ Optional properties: - qcom,adsp-remoteheap-vmid: FastRPC remote heap VMID list - qcom,fastrpc-adsp-audio-pdr: Flag to enable ADSP Audio PDR - qcom,fastrpc-adsp-sensors-pdr: Flag to enable Sensors PDR +- qcom,secure-domains: FastRPC secure domain configuration Optional subnodes: - qcom,msm_fastrpc_compute_cb : Child nodes representing the compute context diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index d84dea6c2df2..e636dda7e886 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -79,6 +79,16 @@ #define FASTRPC_CTX_MAGIC (0xbeeddeed) #define FASTRPC_CTX_MAX (256) #define FASTRPC_CTXID_MASK (0xFF0) +#define NUM_DEVICES 2 /* adsprpc-smd, adsprpc-smd-secure */ +#define MINOR_NUM_DEV 0 +#define MINOR_NUM_SECURE_DEV 1 +#define NON_SECURE_CHANNEL 0 +#define SECURE_CHANNEL 1 + +#define ADSP_DOMAIN_ID (0) +#define MDSP_DOMAIN_ID (1) +#define SDSP_DOMAIN_ID (2) +#define CDSP_DOMAIN_ID (3) #define IS_CACHE_ALIGNED(x) (((x) & ((L1_CACHE_BYTES)-1)) == 0) @@ -282,6 +292,8 @@ struct fastrpc_channel_ctx { int ramdumpenabled; void *remoteheap_ramdump_dev; struct fastrpc_glink_info link; + /* Indicates, if channel is restricted to secure node only */ + int secure; }; struct fastrpc_apps { @@ -380,6 +392,8 @@ struct fastrpc_file { struct mutex map_mutex; struct mutex fl_map_mutex; int refcount; + /* Identifies the device (MINOR_NUM_DEV / MINOR_NUM_SECURE_DEV) */ + int dev_minor; }; static struct fastrpc_apps gfa; @@ -1854,7 +1868,11 @@ static void fastrpc_init(struct fastrpc_apps *me) init_completion(&me->channel[i].work); init_completion(&me->channel[i].workport); me->channel[i].sesscount = 0; + /* All channels are secure by default except CDSP */ + me->channel[i].secure = SECURE_CHANNEL; } + /* Set CDSP channel to non secure */ + me->channel[CDSP_DOMAIN_ID].secure = NON_SECURE_CHANNEL; } static int fastrpc_release_current_dsp_process(struct fastrpc_file *fl); @@ -2943,6 +2961,9 @@ static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer, len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, "%s\n\n", chan->name); + len += scnprintf(fileinfo + len, + DEBUGFS_SIZE - len, "%s %d\n", + "secure:", chan->secure); len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, "%s %d\n", "sesscount:", chan->sesscount); @@ -2971,6 +2992,9 @@ static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer, len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, "%s %d\n\n", "SSRCOUNT:", fl->ssrcount); + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s %d\n\n", + "DEV_MINOR:", fl->dev_minor); len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, "%s\n", "LIST OF BUFS:"); @@ -3107,6 +3131,19 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) struct fastrpc_file *fl = NULL; struct fastrpc_apps *me = &gfa; + /* + * Indicates the device node opened + * MINOR_NUM_DEV or MINOR_NUM_SECURE_DEV + */ + int dev_minor = MINOR(inode->i_rdev); + + VERIFY(err, ((dev_minor == MINOR_NUM_DEV) || + (dev_minor == MINOR_NUM_SECURE_DEV))); + if (err) { + pr_err("adsprpc: Invalid dev minor num %d\n", dev_minor); + return err; + } + VERIFY(err, NULL != (fl = kzalloc(sizeof(*fl), GFP_KERNEL))); if (err) return err; @@ -3123,6 +3160,8 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) fl->apps = me; fl->mode = FASTRPC_MODE_SERIAL; fl->cid = -1; + fl->dev_minor = dev_minor; + if (debugfs_file != NULL) fl->debugfs_file = debugfs_file; fl->qos_request = 0; @@ -3150,6 +3189,23 @@ static int fastrpc_get_info(struct fastrpc_file *fl, uint32_t *info) VERIFY(err, cid < NUM_CHANNELS); if (err) goto bail; + /* Check to see if the device node is non-secure */ + if (fl->dev_minor == MINOR_NUM_DEV) { + /* + * For non secure device node check and make sure that + * the channel allows non-secure access + * If not, bail. Session will not start. + * cid will remain -1 and client will not be able to + * invoke any other methods without failure + */ + if (fl->apps->channel[cid].secure == SECURE_CHANNEL) { + err = -EPERM; + pr_err("adsprpc: GetInfo failed dev %d, cid %d, secure %d\n", + fl->dev_minor, cid, + fl->apps->channel[cid].secure); + goto bail; + } + } fl->cid = cid; fl->ssrcount = fl->apps->channel[cid].ssrcount; VERIFY(err, !fastrpc_session_alloc_locked( @@ -3721,6 +3777,25 @@ static void init_secure_vmid_list(struct device *dev, char *prop_name, } } +static void configure_secure_channels(uint32_t secure_domains) +{ + struct fastrpc_apps *me = &gfa; + int ii = 0; + /* + * secure_domains contains the bitmask of the secure channels + * Bit 0 - ADSP + * Bit 1 - MDSP + * Bit 2 - SLPI + * Bit 3 - CDSP + */ + for (ii = ADSP_DOMAIN_ID; ii <= CDSP_DOMAIN_ID; ++ii) { + int secure = (secure_domains >> ii) & 0x01; + + me->channel[ii].secure = secure; + } +} + + static int fastrpc_probe(struct platform_device *pdev) { int err = 0; @@ -3731,7 +3806,7 @@ static int fastrpc_probe(struct platform_device *pdev) struct cma *cma; uint32_t val; int ret = 0; - + uint32_t secure_domains; if (of_device_is_compatible(dev->of_node, "qcom,msm-fastrpc-compute")) { @@ -3741,6 +3816,16 @@ static int fastrpc_probe(struct platform_device *pdev) of_property_read_u32(dev->of_node, "qcom,rpc-latency-us", &me->latency); + if (of_get_property(dev->of_node, + "qcom,secure-domains", NULL) != NULL) { + VERIFY(err, !of_property_read_u32(dev->of_node, + "qcom,secure-domains", + &secure_domains)); + if (!err) + configure_secure_channels(secure_domains); + else + pr_info("adsprpc: unable to read the domain configuration from dts\n"); + } } if (of_device_is_compatible(dev->of_node, "qcom,msm-fastrpc-compute-cb")) @@ -3886,6 +3971,7 @@ static int __init fastrpc_device_init(void) { struct fastrpc_apps *me = &gfa; struct device *dev = NULL; + struct device *secure_dev = NULL; int err = 0, i; memset(me, 0, sizeof(*me)); @@ -3903,7 +3989,7 @@ static int __init fastrpc_device_init(void) cdev_init(&me->cdev, &fops); me->cdev.owner = THIS_MODULE; VERIFY(err, 0 == cdev_add(&me->cdev, MKDEV(MAJOR(me->dev_no), 0), - 1)); + NUM_DEVICES)); if (err) goto cdev_init_bail; me->class = class_create(THIS_MODULE, "fastrpc"); @@ -3911,14 +3997,30 @@ static int __init fastrpc_device_init(void) if (err) goto class_create_bail; me->compat = (fops.compat_ioctl == NULL) ? 0 : 1; + + /* + * Create devices and register with sysfs + * Create first device with minor number 0 + */ dev = device_create(me->class, NULL, - MKDEV(MAJOR(me->dev_no), 0), - NULL, gcinfo[0].name); + MKDEV(MAJOR(me->dev_no), MINOR_NUM_DEV), + NULL, DEVICE_NAME); VERIFY(err, !IS_ERR_OR_NULL(dev)); if (err) goto device_create_bail; + + /* Create secure device with minor number for secure device */ + secure_dev = device_create(me->class, NULL, + MKDEV(MAJOR(me->dev_no), MINOR_NUM_SECURE_DEV), + NULL, DEVICE_NAME_SECURE); + VERIFY(err, !IS_ERR_OR_NULL(secure_dev)); + if (err) + goto device_create_bail; + for (i = 0; i < NUM_CHANNELS; i++) { - me->channel[i].dev = dev; + me->channel[i].dev = secure_dev; + if (i == CDSP_DOMAIN_ID) + me->channel[i].dev = dev; me->channel[i].ssrcount = 0; me->channel[i].prevssrcount = 0; me->channel[i].issubsystemup = 1; @@ -3943,7 +4045,11 @@ static int __init fastrpc_device_init(void) &me->channel[i].nb); } if (!IS_ERR_OR_NULL(dev)) - device_destroy(me->class, MKDEV(MAJOR(me->dev_no), 0)); + device_destroy(me->class, MKDEV(MAJOR(me->dev_no), + MINOR_NUM_DEV)); + if (!IS_ERR_OR_NULL(secure_dev)) + device_destroy(me->class, MKDEV(MAJOR(me->dev_no), + MINOR_NUM_SECURE_DEV)); class_destroy(me->class); class_create_bail: cdev_del(&me->cdev); @@ -3965,10 +4071,15 @@ static void __exit fastrpc_device_exit(void) for (i = 0; i < NUM_CHANNELS; i++) { if (!gcinfo[i].name) continue; - device_destroy(me->class, MKDEV(MAJOR(me->dev_no), i)); subsys_notif_unregister_notifier(me->channel[i].handle, &me->channel[i].nb); } + + /* Destroy the secure and non secure devices */ + device_destroy(me->class, MKDEV(MAJOR(me->dev_no), MINOR_NUM_DEV)); + device_destroy(me->class, MKDEV(MAJOR(me->dev_no), + MINOR_NUM_SECURE_DEV)); + class_destroy(me->class); cdev_del(&me->cdev); unregister_chrdev_region(me->dev_no, NUM_CHANNELS); diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h index 952b87ca319b..25a2ad85374f 100644 --- a/drivers/char/adsprpc_shared.h +++ b/drivers/char/adsprpc_shared.h @@ -36,6 +36,7 @@ #define FASTRPC_GLINK_GUID "fastrpcglink-apps-dsp" #define FASTRPC_SMD_GUID "fastrpcsmd-apps-dsp" #define DEVICE_NAME "adsprpc-smd" +#define DEVICE_NAME_SECURE "adsprpc-smd-secure" /* Set for buffers that have no virtual mapping in userspace */ #define FASTRPC_ATTR_NOVA 0x1 -- GitLab From b511d8079585838f0a48b570e09e63aa0f3135f1 Mon Sep 17 00:00:00 2001 From: Ramandeep Trehan Date: Thu, 19 Jul 2018 09:25:25 +0530 Subject: [PATCH 426/604] msm8937: Enable config flag for File based Encryption File system flags for ext4 are required for Inline Crypto Engine based file encryption to work smoothly. Change-Id: I4f4852efcb08f75012390e30ca391df2da8e980a Signed-off-by: Ramandeep Trehan --- arch/arm64/configs/msm8937-perf_defconfig | 5 ++++- arch/arm64/configs/msm8937_defconfig | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig index be3fae71b031..bf35544ee133 100644 --- a/arch/arm64/configs/msm8937-perf_defconfig +++ b/arch/arm64/configs/msm8937-perf_defconfig @@ -591,6 +591,9 @@ CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_QUOTA=y @@ -622,12 +625,12 @@ CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_CTI=y CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_HWEVENT=y +CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y -CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig index ebcc83e0fa2b..ba390c4d34e6 100644 --- a/arch/arm64/configs/msm8937_defconfig +++ b/arch/arm64/configs/msm8937_defconfig @@ -610,6 +610,9 @@ CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_QUOTA=y @@ -688,12 +691,12 @@ CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_CTI=y CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_HWEVENT=y +CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y -CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y -- GitLab From 2d5ce98a8e5abd3dbb5e28344279551550f2622b Mon Sep 17 00:00:00 2001 From: Venkataraman Nerellapalli Date: Wed, 4 Jul 2018 20:21:45 +0530 Subject: [PATCH 427/604] ARM: dts: msm: add Goodix support for apq8053-lite-dragon-v2.2 Add Goodix touch screen support for apq8053-lite-dragon-v2.2. Change-Id: I191bc4de03217ebbf8810a729912ce72a09c1127 Signed-off-by: Venkataraman Nerellapalli --- .../dts/qcom/apq8053-lite-dragon-v2.2.dts | 9 ++ .../boot/dts/qcom/apq8053-lite-dragon.dtsi | 73 ++++++++++++++ arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi | 97 +++++++++++++++++++ 3 files changed, 179 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dts index ecc4fea1cb28..599f3ef97af3 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dts +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dts @@ -25,3 +25,12 @@ &blsp2_uart0 { status = "okay"; }; + +&i2c_3 { + status = "okay"; + /delete-node/ himax_ts@48; + gt9xx-i2c@14 { + status = "okay"; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi index 90b1d4fad300..f7a2026f7588 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi @@ -223,6 +223,79 @@ himax,irq-gpio = <&tlmm 65 0x2008>; report_type = <1>; }; + + gt9xx-i2c@14 { + compatible = "goodix,gt9xx"; + reg = <0x14>; + vdd_ana-supply = <&pm8953_l10>; + vcc_i2c-supply = <&pm8953_l6>; + interrupt-parent = <&tlmm>; + interrupts = <65 0x2008>; + pinctrl-names = "gdix_ts_int_default", "gdix_ts_int_output_low", + "gdix_ts_int_output_high", "gdix_ts_int_input", + "gdix_ts_rst_default", "gdix_ts_rst_output_low", + "gdix_ts_rst_output_high", "gdix_ts_rst_input"; + pinctrl-0 = <&ts_int_default>; + pinctrl-1 = <&ts_int_output_low>; + pinctrl-2 = <&ts_int_output_high>; + pinctrl-3 = <&ts_int_input>; + pinctrl-4 = <&ts_rst_default>; + pinctrl-5 = <&ts_rst_output_low>; + pinctrl-6 = <&ts_rst_output_high>; + pinctrl-7 = <&ts_rst_input>; + + reset-gpios = <&tlmm 64 0x00>; + irq-gpios = <&tlmm 65 0x2008>; + irq-flags = <2>; + + touchscreen-max-id = <11>; + touchscreen-size-x = <1200>; + touchscreen-size-y = <1920>; + touchscreen-max-w = <1024>; + touchscreen-max-p = <1024>; + + goodix,type-a-report = <0>; + goodix,driver-send-cfg = <1>; + goodix,wakeup-with-reset = <0>; + goodix,resume-in-workqueue = <0>; + goodix,int-sync = <1>; + goodix,swap-x2y = <0>; + goodix,esd-protect = <1>; + goodix,pen-suppress-finger = <0>; + goodix,auto-update = <1>; + goodix,auto-update-cfg = <0>; + goodix,power-off-sleep = <0>; + + goodix,cfg-group0 = [ + 5A B0 04 80 07 0A 35 10 22 08 32 0D 50 3C 0A 04 + 01 01 00 B4 11 11 44 15 19 1B 14 95 35 FF 3A 3C + 39 13 00 00 00 98 03 1C 00 00 00 00 03 00 00 00 + 00 80 0A 37 46 40 E5 52 23 28 00 04 81 38 00 7F + 3B 00 7D 3E 00 7C 41 00 7A 44 0C 7A 00 50 33 50 + 0B 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 55 00 01 00 00 02 00 00 00 + 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 0F 0E + 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00 2A 29 + 28 27 26 25 24 23 22 21 20 1F 1E 1D 1C 1B 19 18 + 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 + 07 06 05 04 03 02 01 00 08 01 + ]; + + goodix,cfg-group2 = [ + 5B B0 04 80 07 0A 35 10 22 08 32 0D 50 32 0A 04 + 01 01 00 B4 11 11 44 2B 31 36 28 95 35 FF 3E 40 + 39 13 00 00 00 DA 03 1C 00 00 00 00 03 00 00 00 + 00 80 0A 32 42 40 E5 52 23 28 00 04 7D 33 00 7D + 36 00 7E 39 00 7F 3C 00 80 40 0C 80 00 50 33 50 + 0B 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 55 00 01 00 00 02 00 00 00 + 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 0F 0E + 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00 2A 29 + 28 27 26 25 24 23 22 21 20 1F 1E 1D 1C 1B 19 18 + 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 + 07 06 05 04 03 02 01 00 81 01 + ]; + }; }; &soc { diff --git a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi index 3552055f01c9..046e9308e797 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi @@ -1400,6 +1400,103 @@ }; }; + /* add pingrp for touchscreen */ + ts_int_default: ts_int_default { + mux { + pins = "gpio65"; + function = "gpio"; + }; + config { + pins = "gpio65"; + drive-strength = <16>; + /*bias-pull-up;*/ + input-enable; + bias-disable; + }; + }; + + ts_int_output_high: ts_int_output_high { + mux { + pins = "gpio65"; + function = "gpio"; + }; + config { + pins = "gpio65"; + output-high; + }; + }; + + ts_int_output_low: ts_int_output_low { + mux { + pins = "gpio65"; + function = "gpio"; + }; + config { + pins = "gpio65"; + output-low; + }; + }; + + ts_int_input: ts_int_input { + mux { + pins = "gpio65"; + function = "gpio"; + }; + config { + pins = "gpio65"; + input-enable; + bias-disable; + }; + }; + + ts_rst_default: ts_rst_default { + mux { + pins = "gpio64"; + function = "gpio"; + }; + config { + pins = "gpio64"; + drive-strength = <16>; + /*bias-pull-up;*/ + input-enable; + bias-disable; + }; + }; + + ts_rst_output_high: ts_rst_output_high { + mux { + pins = "gpio64"; + function = "gpio"; + }; + config { + pins = "gpio64"; + output-high; + }; + }; + + ts_rst_output_low: ts_rst_output_low { + mux { + pins = "gpio64"; + function = "gpio"; + }; + config { + pins = "gpio64"; + output-low; + }; + }; + + ts_rst_input: ts_rst_input { + mux { + pins = "gpio64"; + function = "gpio"; + }; + config { + pins = "gpio64"; + input-enable; + bias-disable; + }; + }; + /* add pingrp for touchscreen */ pmx_ts_int_active { ts_int_active: ts_int_active { -- GitLab From 23c45823967076939b8e124c4d4da8577a88b573 Mon Sep 17 00:00:00 2001 From: Chaojun Wang Date: Wed, 18 Jul 2018 11:32:50 +0800 Subject: [PATCH 428/604] input: vl53l0x: return ENODEV if vl53l0x not enable if vl53l0x sensor not enable, it will output a wrong data. so we return "ENODEV" when sensor not enable. Change-Id: I4b6a074d9999e5fd947738e9b611be45708b9a1c Signed-off-by: Chaojun Wang --- drivers/input/misc/vl53l0x/stmvl53l0x_module.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x_module.c b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c index 26cee2ee7508..34508b2069c8 100644 --- a/drivers/input/misc/vl53l0x/stmvl53l0x_module.c +++ b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c @@ -963,6 +963,8 @@ static ssize_t stmvl53l0x_show_meter(struct device *dev, struct vl_data *data = dev_get_drvdata(dev); struct VL_RangingMeasurementData_t Measure; + if (data->enable_ps_sensor == 0) + return -ENODEV; papi_func_tbl->PerformSingleRangingMeasurement(data, &Measure); return snprintf(buf, 7, "%d\n", Measure.RangeMilliMeter); } -- GitLab From b6912518b2732609546754a6d9e387c00ffbb347 Mon Sep 17 00:00:00 2001 From: Arun Kumar Neelakantam Date: Thu, 19 Jul 2018 13:51:39 +0530 Subject: [PATCH 429/604] net: ipc_router: Remove header length check V1 header length check for read_avail cause read failures if packet comes with V2 header and payload less than 16bytes. Remove the V1 header length check to read small packets once it receives. CRs-Fixed: 2279076 Change-Id: I7daf5c150e501d209057d6f2af998f685f5cd25d Signed-off-by: Arun Kumar Neelakantam --- net/ipc_router/ipc_router_fifo_xprt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipc_router/ipc_router_fifo_xprt.c b/net/ipc_router/ipc_router_fifo_xprt.c index ae85fd1277ae..c90534dac923 100644 --- a/net/ipc_router/ipc_router_fifo_xprt.c +++ b/net/ipc_router/ipc_router_fifo_xprt.c @@ -255,7 +255,7 @@ static void xprt_read_data(struct work_struct *work) hdr_len = sizeof(struct rr_header_v1); while (1) { rx_avail = fifo_rx_avail(&xprtp->rx_pipe); - if (!rx_avail || (rx_avail < hdr_len)) + if (!rx_avail) break; fifo_rx_peak(&xprtp->rx_pipe, &hdr, 0, hdr_len); -- GitLab From a9ce2339eeffcc043bbbb5b4479b936e42d5a46d Mon Sep 17 00:00:00 2001 From: Venkataraman Nerellapalli Date: Tue, 3 Jul 2018 14:17:42 +0530 Subject: [PATCH 430/604] ARM: dts: msm: Configure SPI6 node for MSM8953 Configure SPI6 node for MSM8953 with default status set to disabled. Client needs to enable this instance as per usecase. SPI6 is exposed on the sensor connector (J53) of the Open-Q board. Change-Id: I00875b933f90d8f4e9ceed26ae8d8cff16983a05 Signed-off-by: c_vnerel --- arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi | 60 +++++++++++++++++++ arch/arm64/boot/dts/qcom/msm8953.dtsi | 28 +++++++++ 2 files changed, 88 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi index 3552055f01c9..65b2397a54b8 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi @@ -1400,6 +1400,66 @@ }; }; + spi6 { + spi6_default: spi6_default { + /* active state */ + mux { + /* MOSI, MISO, CLK */ + pins = "gpio20", "gpio21", "gpio23"; + function = "blsp_spi6"; + }; + + config { + pins = "gpio20", "gpio21", "gpio23"; + drive-strength = <12>; /* 12 MA */ + bias-disable = <0>; /* No PULL */ + }; + }; + + spi6_sleep: spi6_sleep { + /* suspended state */ + mux { + /* MOSI, MISO, CLK */ + pins = "gpio20", "gpio21", "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio20", "gpio21", "gpio23"; + drive-strength = <2>; /* 2 MA */ + bias-pull-down; /* PULL Down */ + }; + }; + + spi6_cs0_active: cs0_active { + /* CS */ + mux { + pins = "gpio22"; + function = "blsp_spi6"; + }; + + config { + pins = "gpio22"; + drive-strength = <2>; + bias-disable = <0>; + }; + }; + + spi6_cs0_sleep: cs0_sleep { + /* CS */ + mux { + pins = "gpio22"; + function = "gpio"; + }; + + config { + pins = "gpio22"; + drive-strength = <2>; + bias-disable = <0>; + }; + }; + }; + /* add pingrp for touchscreen */ pmx_ts_int_active { ts_int_active: ts_int_active { diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index d12e04acc893..3ab3b2b8007e 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -179,6 +179,7 @@ i2c3 = &i2c_3; i2c5 = &i2c_5; spi3 = &spi_3; + spi6 = &spi_6; }; soc: soc { @@ -700,6 +701,33 @@ qcom,master-id = <86>; status = "disabled"; }; + + spi_6: spi@7af6000 { /* BLSP2 QUP2 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0x7af6000 0x600>, + <0x7ac4000 0x1f000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 300 0>, <0 239 0>; + spi-max-frequency = <19200000>; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi6_default &spi6_cs0_active>; + pinctrl-1 = <&spi6_sleep &spi6_cs0_sleep>; + clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>, + <&clock_gcc clk_gcc_blsp2_qup2_spi_apps_clk>; + clock-names = "iface_clk", "core_clk"; + qcom,infinite-mode = <0>; + qcom,use-bam; + qcom,use-pinctrl; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <6>; + qcom,bam-producer-pipe-index = <7>; + qcom,master-id = <84>; + status = "disabled"; + }; + i2c_1: i2c@78b5000 { /* BLSP1 QUP1 */ compatible = "qcom,i2c-msm-v2"; #address-cells = <1>; -- GitLab From b3a1b646b3cbb84cc4853ee23d0affd9d207f80f Mon Sep 17 00:00:00 2001 From: Chintan Pandya Date: Fri, 20 Apr 2018 18:57:32 +0530 Subject: [PATCH 431/604] soc: qcom: add llcc support for qcs605 Add Last level cache controller driver support for qcs605 Change-Id: I1d92df8b61b1a66edfc9ba5f791577dd43aba91f Signed-off-by: Chintan Pandya [mojha@codeaurora.org: Added entry for CPUSS in SCT table] Signed-off-by: Mukesh Ojha --- .../devicetree/bindings/arm/msm/qcom,llcc.txt | 3 +- drivers/soc/qcom/Kconfig | 8 ++ drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/llcc-qcs605.c | 106 ++++++++++++++++++ 4 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 drivers/soc/qcom/llcc-qcs605.c diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt index 90bc36823a83..c4ada7cfd154 100644 --- a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt +++ b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt @@ -86,7 +86,8 @@ Optional Properties: compatible devices: qcom,sdm845-llcc, - qcom,sdm670-llcc + qcom,sdm670-llcc, + qcom,qcs605-llcc Example: diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 3ecca591bb7c..52d9f65c711e 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -52,6 +52,14 @@ config QCOM_SDM670_LLCC can start using the LLCC slices. Say yes here to enable llcc driver for SDM670. +config QCOM_QCS605_LLCC + tristate "Qualcomm Technologies, Inc. QCS605 LLCC driver" + depends on QCOM_LLCC + help + This provides Last level cache controller driver for QCS605. + This driver provides data required to configure LLCC, so that clients + can start using the LLCC slices. + Say yes here to enable llcc driver for QCS605. config QCOM_LLCC_AMON tristate "Qualcomm Technologies, Inc. LLCC Activity Monitor(AMON) driver" diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 0b711214389d..1da834679417 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o obj-$(CONFIG_QCOM_LLCC) += llcc-core.o llcc-slice.o obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o obj-$(CONFIG_QCOM_SDM670_LLCC) += llcc-sdm670.o +obj-$(CONFIG_QCOM_QCS605_LLCC) += llcc-qcs605.o obj-$(CONFIG_QCOM_LLCC_PERFMON) += llcc_perfmon.o obj-$(CONFIG_QCOM_LLCC_AMON) += llcc-amon.o obj-$(CONFIG_QPNP_PBS) += qpnp-pbs.o diff --git a/drivers/soc/qcom/llcc-qcs605.c b/drivers/soc/qcom/llcc-qcs605.c new file mode 100644 index 000000000000..d3d339007c51 --- /dev/null +++ b/drivers/soc/qcom/llcc-qcs605.c @@ -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. + */ + +#include +#include +#include +#include +#include + +/* + * SCT entry contains of the following parameters + * name: Name of the client's use case for which the llcc slice is used + * uid: Unique id for the client's use case + * slice_id: llcc slice id for each client + * max_cap: The maximum capacity of the cache slice provided in KB + * priority: Priority of the client used to select victim line for replacement + * fixed_size: Determine of the slice has a fixed capacity + * bonus_ways: Bonus ways to be used by any slice, bonus way is used only if + * it't not a reserved way. + * res_ways: Reserved ways for the cache slice, the reserved ways cannot be used + * by any other client than the one its assigned to. + * cache_mode: Each slice operates as a cache, this controls the mode of the + * slice normal or TCM + * probe_target_ways: Determines what ways to probe for access hit. When + * configured to 1 only bonus and reseved ways are probed. + * when configured to 0 all ways in llcc are probed. + * dis_cap_alloc: Disable capacity based allocation for a client + * retain_on_pc: If this bit is set and client has maitained active vote + * then the ways assigned to this client are not flushed on power + * collapse. + * activate_on_init: Activate the slice immidiately after the SCT is programmed + */ +#define SCT_ENTRY(n, uid, sid, mc, p, fs, bway, rway, cmod, ptw, dca, rp, a) \ + { \ + .name = n, \ + .usecase_id = uid, \ + .slice_id = sid, \ + .max_cap = mc, \ + .priority = p, \ + .fixed_size = fs, \ + .bonus_ways = bway, \ + .res_ways = rway, \ + .cache_mode = cmod, \ + .probe_target_ways = ptw, \ + .dis_cap_alloc = dca, \ + .retain_on_pc = rp, \ + .activate_on_init = a, \ + } + +static struct llcc_slice_config qcs605_data[] = { + SCT_ENTRY("cpuss", 1, 1, 512, 1, 0, 0xF, 0x0, 0, 0, 1, 1, 1), + SCT_ENTRY("vidsc0", 2, 2, 256, 2, 1, 0x3, 0x0, 0, 0, 1, 1, 0), + SCT_ENTRY("vidsc1", 3, 3, 256, 2, 1, 0x3, 0x0, 0, 0, 1, 1, 0), + SCT_ENTRY("voice", 5, 5, 512, 1, 0, 0xF, 0x0, 0, 0, 1, 1, 0), + SCT_ENTRY("audio", 6, 6, 512, 1, 0, 0xF, 0x0, 0, 0, 1, 1, 0), + SCT_ENTRY("modem", 8, 8, 512, 1, 0, 0xF, 0x0, 0, 0, 1, 1, 0), + SCT_ENTRY("compute", 10, 10, 512, 1, 0, 0xF, 0x0, 0, 0, 1, 1, 0), + SCT_ENTRY("gpu", 12, 12, 512, 1, 0, 0xF, 0x0, 0, 0, 1, 1, 0), + SCT_ENTRY("mmuhwt", 13, 13, 512, 1, 0, 0xF, 0x0, 0, 0, 1, 0, 1), + SCT_ENTRY("audiohw", 22, 22, 512, 1, 1, 0xF, 0x0, 0, 0, 1, 1, 0), +}; + +static int qcs605_qcom_llcc_probe(struct platform_device *pdev) +{ + return qcom_llcc_probe(pdev, qcs605_data, + ARRAY_SIZE(qcs605_data)); +} + +static const struct of_device_id qcs605_qcom_llcc_of_match[] = { + { .compatible = "qcom,qcs605-llcc", }, + { }, +}; + +static struct platform_driver qcs605_qcom_llcc_driver = { + .driver = { + .name = "qcs605-llcc", + .owner = THIS_MODULE, + .of_match_table = qcs605_qcom_llcc_of_match, + }, + .probe = qcs605_qcom_llcc_probe, + .remove = qcom_llcc_remove, +}; + +static int __init qcs605_init_qcom_llcc_init(void) +{ + return platform_driver_register(&qcs605_qcom_llcc_driver); +} +module_init(qcs605_init_qcom_llcc_init); + +static void __exit qcs605_exit_qcom_llcc_exit(void) +{ + platform_driver_unregister(&qcs605_qcom_llcc_driver); +} +module_exit(qcs605_exit_qcom_llcc_exit); + +MODULE_DESCRIPTION("QTI qcs605 LLCC driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From 506e54c8942dbcfc262a7f33db6487b926efaf0f Mon Sep 17 00:00:00 2001 From: Chintan Pandya Date: Thu, 3 May 2018 17:21:21 +0530 Subject: [PATCH 432/604] ARM: dts: msm: Add support for qcs605-llcc qcs605-llcc configuration is re-using sdm670-llcc config. Add proper compatibility to support LLCC on qcs605. Change-Id: I8e4384519af646ca36f28ef54bd19a283bf384ae Signed-off-by: Chintan Pandya --- arch/arm64/boot/dts/qcom/qcs605.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs605.dtsi b/arch/arm64/boot/dts/qcom/qcs605.dtsi index 61a812c9aaa4..61ea299dde2c 100644 --- a/arch/arm64/boot/dts/qcom/qcs605.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs605.dtsi @@ -76,6 +76,10 @@ }; }; +&llcc { + compatible = "qcom,qcs605-llcc"; +}; + &ipa_hw { status = "disabled"; }; -- GitLab From a0b999524ebe43bcccef752b259316c8fa95c0f4 Mon Sep 17 00:00:00 2001 From: Chintan Pandya Date: Thu, 3 May 2018 17:48:22 +0530 Subject: [PATCH 433/604] defconfig: msm: Enable llcc for QCS605 Enable LLCC for QCS605 to get benefits of last-level cache. Change-Id: I9f9dfbd678ad901da88d36045485fe00fecb9ec7 Signed-off-by: Chintan Pandya --- arch/arm64/configs/sdm670-perf_defconfig | 1 + arch/arm64/configs/sdm670_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig index 6740bd7bf8bb..ac21b6388323 100644 --- a/arch/arm64/configs/sdm670-perf_defconfig +++ b/arch/arm64/configs/sdm670-perf_defconfig @@ -513,6 +513,7 @@ CONFIG_IOMMU_TESTS=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_LLCC=y CONFIG_QCOM_SDM670_LLCC=y +CONFIG_QCOM_QCS605_LLCC=y CONFIG_QCOM_LLCC_PERFMON=m CONFIG_MSM_SERVICE_LOCATOR=y CONFIG_MSM_SERVICE_NOTIFIER=y diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig index 53fb1cd53d00..9a6da1f8fb2c 100644 --- a/arch/arm64/configs/sdm670_defconfig +++ b/arch/arm64/configs/sdm670_defconfig @@ -527,6 +527,7 @@ CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_LLCC=y CONFIG_QCOM_SDM670_LLCC=y +CONFIG_QCOM_QCS605_LLCC=y CONFIG_QCOM_LLCC_PERFMON=m CONFIG_MSM_SERVICE_LOCATOR=y CONFIG_MSM_SERVICE_NOTIFIER=y -- GitLab From 90b3842e365054bc9716b8da8b3206cd71a8bd6d Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Thu, 19 Jul 2018 17:00:35 +0530 Subject: [PATCH 434/604] power: qpnp-qg: Update GOOD_OCV after clearing the old data The current implementation, during resume clears the stored FIFO data after updating it with the GOOD_OCV value. Fix this by clearing the data before storing GOOD_OCV. Change-Id: I2dd744bf7bbdf13539eb6dedcebab18d381d6216 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 d1b6beaa8507..d47628faed26 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -3474,10 +3474,10 @@ static int process_resume(struct qpnp_qg *chip) return rc; } - chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv; - chip->kdata.param[QG_GOOD_OCV_UV].valid = true; /* Clear suspend data as there has been a GOOD OCV */ memset(&chip->kdata, 0, sizeof(chip->kdata)); + chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv; + chip->kdata.param[QG_GOOD_OCV_UV].valid = true; chip->suspend_data = false; qg_dbg(chip, QG_DEBUG_PM, "GOOD OCV @ resume good_ocv=%d uV\n", -- GitLab From df6fd5cd6dc1505c7f312319655af28070482f36 Mon Sep 17 00:00:00 2001 From: Madhukar Sandi Date: Thu, 19 Jul 2018 14:57:57 +0530 Subject: [PATCH 435/604] defconfig: msm: enable crypto configs in 8909 perf build Enable CONFIG_DM_VERITY_FEC in perf config file. This flag is required when FEC is passed from kernel command line and adding some more Crypto dependency flags Change-Id: I50865c2b441df750dfe21e7b5d8e1af7583adb7b Signed-off-by: Madhukar Sandi --- arch/arm/configs/msm8909-perf_defconfig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index d907a0dc0c25..5f655b47e4ed 100644 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -63,6 +63,7 @@ CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y CONFIG_CPU_IDLE=y CONFIG_VFP=y CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_PM_AUTOSLEEP=y CONFIG_PM_WAKELOCKS=y @@ -230,6 +231,7 @@ CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_TUN=y @@ -470,4 +472,9 @@ CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_CRYPTO_DEV_OTA_CRYPTO=y CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_ARM_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM_NEON=y +CONFIG_CRYPTO_SHA2_ARM_CE=y +CONFIG_CRYPTO_AES_ARM_BS=y +CONFIG_CRYPTO_AES_ARM_CE=y CONFIG_QMI_ENCDEC=y -- GitLab From ec39fc88862e6970b107ae5a6f98434b1066eb5e Mon Sep 17 00:00:00 2001 From: Suraj Dongre Date: Wed, 18 Jul 2018 14:34:03 -0700 Subject: [PATCH 436/604] 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 d240b53b7164..103ff5a2d642 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 408bc5c61af0869e8e0ae2ffaa99d6fb6cf94355 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Wed, 13 Jun 2018 11:57:49 -0700 Subject: [PATCH 437/604] usb: pd: Update some sysfs entries to return hex values Update several of the PD 3.0 related sysfs entries to return a hexadecimal string of the byte data returned instead of decimal. For the messages that correspond to non-extended messages, these data objects should be printed as '0x1234ABCD' to ease human translation to binary. For extended messages the payloads contain fields of single or multi-byte values, so it's easiest to return a string of hex bytes. Change-Id: I436e90d9b5b472362ae39050dd775363db46207c Signed-off-by: Jack Pham --- drivers/usb/pd/policy_engine.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 6685f05bab57..475c73674904 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -3690,8 +3690,12 @@ static ssize_t get_src_cap_ext_show(struct device *dev, return ret; for (i = 0; i < PD_SRC_CAP_EXT_DB_LEN; i++) - len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", - pd->src_cap_ext_db[i]); + len += snprintf(buf + len, PAGE_SIZE - len, "%s0x%02x", + i ? " " : "", pd->src_cap_ext_db[i]); + + buf[len++] = '\n'; + buf[len] = '\0'; + return len; } static DEVICE_ATTR_RO(get_src_cap_ext); @@ -3709,7 +3713,7 @@ static ssize_t get_pps_status_show(struct device *dev, if (ret) return ret; - return snprintf(buf, PAGE_SIZE, "%d\n", pd->pps_status_db); + return snprintf(buf, PAGE_SIZE, "0x%08x\n", pd->pps_status_db); } static DEVICE_ATTR_RO(get_pps_status); @@ -3751,8 +3755,12 @@ static ssize_t get_battery_cap_show(struct device *dev, return -EINVAL; for (i = 0; i < PD_BATTERY_CAP_DB_LEN; i++) - len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", - pd->battery_cap_db[i]); + len += snprintf(buf + len, PAGE_SIZE - len, "%s0x%02x", + i ? " " : "", pd->battery_cap_db[i]); + + buf[len++] = '\n'; + buf[len] = '\0'; + return len; } static DEVICE_ATTR_RW(get_battery_cap); @@ -3783,7 +3791,7 @@ static ssize_t get_battery_status_show(struct device *dev, if (pd->get_battery_status_db == -EINVAL) return -EINVAL; - return snprintf(buf, PAGE_SIZE, "%d\n", pd->battery_sts_dobj); + return snprintf(buf, PAGE_SIZE, "0x%08x\n", pd->battery_sts_dobj); } static DEVICE_ATTR_RW(get_battery_status); -- GitLab From b904b66361d3e9f1c82ba20692b724be992c6c2c Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Fri, 8 Jun 2018 10:10:12 -0700 Subject: [PATCH 438/604] usb: pd: qpnp-pdphy: Switch to hrtimer-based wait Currently wait_event_interruptible_timeout() is used when sending a message or hard reset signal to wait for a completion interrupt. However, the jiffies-based timer is not accurate for the short timeout durations used (15ms TX, 5ms hard reset) and can result in timing out too early. Switch to hrtimer-based wait_event_interruptible_hrtimeout() for better accuracy. Change-Id: I1c9866114b548ce849ec6002c0eb1362ac9a7786 Signed-off-by: Jack Pham --- drivers/usb/pd/qpnp-pdphy.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c index 2997976d1aa0..5d4543f3fb8a 100644 --- a/drivers/usb/pd/qpnp-pdphy.c +++ b/drivers/usb/pd/qpnp-pdphy.c @@ -437,12 +437,12 @@ int pd_phy_signal(enum pd_sig_type sig) if (ret) return ret; - ret = wait_event_interruptible_timeout(pdphy->tx_waitq, + ret = wait_event_interruptible_hrtimeout(pdphy->tx_waitq, pdphy->tx_status != -EINPROGRESS, - msecs_to_jiffies(HARD_RESET_COMPLETE_TIME)); - if (ret <= 0) { + ms_to_ktime(HARD_RESET_COMPLETE_TIME)); + if (ret) { dev_err(pdphy->dev, "%s: failed ret %d", __func__, ret); - return ret ? ret : -ETIMEDOUT; + return ret; } ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, 0); @@ -526,12 +526,12 @@ int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, enum pd_sop_type sop) if (ret) return ret; - ret = wait_event_interruptible_timeout(pdphy->tx_waitq, + ret = wait_event_interruptible_hrtimeout(pdphy->tx_waitq, pdphy->tx_status != -EINPROGRESS, - msecs_to_jiffies(RECEIVER_RESPONSE_TIME)); - if (ret <= 0) { + ms_to_ktime(RECEIVER_RESPONSE_TIME)); + if (ret) { dev_err(pdphy->dev, "%s: failed ret %d", __func__, ret); - return ret ? ret : -ETIMEDOUT; + return ret; } if (hdr && !pdphy->tx_status) -- GitLab From c67125245f16a153b98f781d34b77daba1d66625 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Thu, 7 Jun 2018 10:29:15 -0700 Subject: [PATCH 439/604] usb: pd: qpnp-pdphy: Set nRetryCount based on PD spec rev PD 3.0 changed nRetryCount to 2 whereas it was 3 on PD 2.0. This affects how many times a failed TX message will be attempted in pd_phy_write(). Add a check for the spec rev field of the message header to determine what value to set for TX_CONTROL_RETRY_COUNT. Change-Id: I342262e6555734184222e5a97aac03a148bc900b Signed-off-by: Jack Pham --- drivers/usb/pd/qpnp-pdphy.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c index 5d4543f3fb8a..a1b8a3258bba 100644 --- a/drivers/usb/pd/qpnp-pdphy.c +++ b/drivers/usb/pd/qpnp-pdphy.c @@ -50,7 +50,7 @@ #define TX_SIZE_MASK 0xF #define USB_PDPHY_TX_CONTROL 0x44 -#define TX_CONTROL_RETRY_COUNT (BIT(6) | BIT(5)) +#define TX_CONTROL_RETRY_COUNT(n) (((n) & 0x3) << 5) #define TX_CONTROL_FRAME_TYPE (BIT(4) | BIT(3) | BIT(2)) #define TX_CONTROL_FRAME_TYPE_CABLE_RESET (0x1 << 2) #define TX_CONTROL_SEND_SIGNAL BIT(1) @@ -80,6 +80,9 @@ #define VDD_PDPHY_VOL_MAX 3088000 /* uV */ #define VDD_PDPHY_HPM_LOAD 3000 /* uA */ +/* Message Spec Rev field */ +#define PD_MSG_HDR_REV(hdr) (((hdr) >> 6) & 3) + /* timers */ #define RECEIVER_RESPONSE_TIME 15 /* tReceiverResponse */ #define HARD_RESET_COMPLETE_TIME 5 /* tHardResetComplete */ @@ -520,7 +523,13 @@ int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, enum pd_sop_type sop) usleep_range(2, 3); - val = TX_CONTROL_RETRY_COUNT | (sop << 2) | TX_CONTROL_SEND_MSG; + val = (sop << 2) | TX_CONTROL_SEND_MSG; + + /* nRetryCount == 2 for PD 3.0, 3 for PD 2.0 */ + if (PD_MSG_HDR_REV(hdr) == USBPD_REV_30) + val |= TX_CONTROL_RETRY_COUNT(2); + else + val |= TX_CONTROL_RETRY_COUNT(3); ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, val); if (ret) -- GitLab From da401d78b0b0aa651ccfade17003fecaa0dde04a Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Thu, 7 Jun 2018 19:29:52 -0700 Subject: [PATCH 440/604] usb: pd: Fix Alert/Get_Status handling When an ALERT message is received, GET_STATUS should not be sent right away as that is not part of its atomic message sequence. Further, as a sink, this also violates collision avoidance rules since the ALERT is sent during SinkTxNG. Instead, queue up the GET_STATUS to be sent when Rp is back to SinkTxOk. In addition, replace the ado sysfs entry with get_status since the former is not very useful to userspace. Reading from this entry will trigger a GET_STATUS to be sent and block until the STATUS is received. Change-Id: I6943e1e8fab300c13ec94c516e89fc466dac8209 Signed-off-by: Jack Pham --- drivers/usb/pd/policy_engine.c | 71 ++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 475c73674904..6bb0d5682ce3 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -374,7 +374,6 @@ struct usbpd { struct rx_msg *rx_ext_msg; u32 received_pdos[PD_MAX_DATA_OBJ]; - u32 received_ado; u16 src_cap_id; u8 selected_pdo; u8 requested_pdo; @@ -443,6 +442,7 @@ struct usbpd { u8 src_cap_ext_db[PD_SRC_CAP_EXT_DB_LEN]; bool send_get_pps_status; u32 pps_status_db; + bool send_get_status; u8 status_db[PD_STATUS_DB_LEN]; bool send_get_battery_cap; u8 get_battery_cap_db; @@ -2588,23 +2588,32 @@ static void usbpd_sm(struct work_struct *w) sizeof(pd->pps_status_db)); complete(&pd->is_ready); } else if (IS_DATA(rx_msg, MSG_ALERT)) { - if (rx_msg->data_len != sizeof(pd->received_ado)) { + u32 ado; + + if (rx_msg->data_len != sizeof(ado)) { usbpd_err(&pd->dev, "Invalid ado\n"); break; } - memcpy(&pd->received_ado, rx_msg->payload, - sizeof(pd->received_ado)); - ret = pd_send_msg(pd, MSG_GET_STATUS, NULL, - 0, SOP_MSG); + memcpy(&ado, rx_msg->payload, sizeof(ado)); + usbpd_dbg(&pd->dev, "Received Alert 0x%08x\n", ado); + + /* + * Don't send Get_Status right away so we can coalesce + * multiple Alerts. 150ms should be enough to not get + * in the way of any other AMS that might happen. + */ + pd->send_get_status = true; + kick_sm(pd, 150); + } else if (pd->send_get_status && is_sink_tx_ok(pd)) { + pd->send_get_status = false; + ret = pd_send_msg(pd, MSG_GET_STATUS, NULL, 0, SOP_MSG); if (ret) { - dev_err(&pd->dev, - "Error sending get_status\n"); + usbpd_err(&pd->dev, "Error sending get_status\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } kick_sm(pd, SENDER_RESPONSE_TIME); - } else if (rx_msg && - IS_EXT(rx_msg, MSG_STATUS)) { + } else if (rx_msg && IS_EXT(rx_msg, MSG_STATUS)) { if (rx_msg->data_len != PD_STATUS_DB_LEN) { usbpd_err(&pd->dev, "Invalid status db\n"); break; @@ -3297,9 +3306,9 @@ static int usbpd_uevent(struct device *dev, struct kobj_uevent_env *env) "explicit" : "implicit"); add_uevent_var(env, "ALT_MODE=%d", pd->vdm_state == MODE_ENTERED); - add_uevent_var(env, "ADO=%08x", pd->received_ado); - for (i = 0; i < PD_STATUS_DB_LEN; i++) - add_uevent_var(env, "SDB%d=%08x", i, pd->status_db[i]); + add_uevent_var(env, "SDB=%02x %02x %02x %02x %02x", pd->status_db[0], + pd->status_db[1], pd->status_db[2], pd->status_db[3], + pd->status_db[4]); return 0; } @@ -3700,32 +3709,46 @@ static ssize_t get_src_cap_ext_show(struct device *dev, } static DEVICE_ATTR_RO(get_src_cap_ext); -static ssize_t get_pps_status_show(struct device *dev, +static ssize_t get_status_show(struct device *dev, struct device_attribute *attr, char *buf) { - int ret; + int i, ret, len = 0; struct usbpd *pd = dev_get_drvdata(dev); if (pd->spec_rev == USBPD_REV_20) return -EINVAL; - ret = trigger_tx_msg(pd, &pd->send_get_pps_status); + ret = trigger_tx_msg(pd, &pd->send_get_status); if (ret) return ret; - return snprintf(buf, PAGE_SIZE, "0x%08x\n", pd->pps_status_db); + for (i = 0; i < PD_STATUS_DB_LEN; i++) + len += snprintf(buf + len, PAGE_SIZE - len, "%s0x%02x", + i ? " " : "", pd->status_db[i]); + + buf[len++] = '\n'; + buf[len] = '\0'; + + return len; } -static DEVICE_ATTR_RO(get_pps_status); +static DEVICE_ATTR_RO(get_status); -static ssize_t rx_ado_show(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t get_pps_status_show(struct device *dev, + struct device_attribute *attr, char *buf) { + int ret; struct usbpd *pd = dev_get_drvdata(dev); - /* dump the ADO as a hex string */ - return snprintf(buf, PAGE_SIZE, "%08x\n", pd->received_ado); + if (pd->spec_rev == USBPD_REV_20) + return -EINVAL; + + ret = trigger_tx_msg(pd, &pd->send_get_pps_status); + if (ret) + return ret; + + return snprintf(buf, PAGE_SIZE, "0x%08x\n", pd->pps_status_db); } -static DEVICE_ATTR_RO(rx_ado); +static DEVICE_ATTR_RO(get_pps_status); static ssize_t get_battery_cap_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) @@ -3815,8 +3838,8 @@ static struct attribute *usbpd_attrs[] = { &dev_attr_rdo_h.attr, &dev_attr_hard_reset.attr, &dev_attr_get_src_cap_ext.attr, + &dev_attr_get_status.attr, &dev_attr_get_pps_status.attr, - &dev_attr_rx_ado.attr, &dev_attr_get_battery_cap.attr, &dev_attr_get_battery_status.attr, NULL, -- GitLab From 3a3def6d506d57dc56188d31f683037b5cc5a45f Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Thu, 7 Jun 2018 19:33:58 -0700 Subject: [PATCH 441/604] usb: pd: Replace dev_err with usbpd_err Replace a number of instances of dev_err with usbpd_err so that they can also be logged using the IPC log mechanism. Change-Id: I84207c4fc31570fc347f84aa321a9e5e81480f81 Signed-off-by: Jack Pham --- drivers/usb/pd/policy_engine.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 6bb0d5682ce3..2c0c0ed80c54 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -2252,7 +2252,7 @@ static void usbpd_sm(struct work_struct *w) pd->send_pr_swap = false; ret = pd_send_msg(pd, MSG_PR_SWAP, NULL, 0, SOP_MSG); if (ret) { - dev_err(&pd->dev, "Error sending PR Swap\n"); + usbpd_err(&pd->dev, "Error sending PR Swap\n"); usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET); break; } @@ -2263,7 +2263,7 @@ static void usbpd_sm(struct work_struct *w) pd->send_dr_swap = false; ret = pd_send_msg(pd, MSG_DR_SWAP, NULL, 0, SOP_MSG); if (ret) { - dev_err(&pd->dev, "Error sending DR Swap\n"); + usbpd_err(&pd->dev, "Error sending DR Swap\n"); usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET); break; } @@ -2552,8 +2552,7 @@ static void usbpd_sm(struct work_struct *w) ret = pd_send_msg(pd, MSG_GET_SOURCE_CAP_EXTENDED, NULL, 0, SOP_MSG); if (ret) { - dev_err(&pd->dev, - "Error sending get_src_cap_ext\n"); + usbpd_err(&pd->dev, "Error sending get_src_cap_ext\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } @@ -2572,8 +2571,7 @@ static void usbpd_sm(struct work_struct *w) ret = pd_send_msg(pd, MSG_GET_PPS_STATUS, NULL, 0, SOP_MSG); if (ret) { - dev_err(&pd->dev, - "Error sending get_pps_status\n"); + usbpd_err(&pd->dev, "Error sending get_pps_status\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } @@ -2626,8 +2624,7 @@ static void usbpd_sm(struct work_struct *w) ret = pd_send_ext_msg(pd, MSG_GET_BATTERY_CAP, &pd->get_battery_cap_db, 1, SOP_MSG); if (ret) { - dev_err(&pd->dev, - "Error sending get_battery_cap\n"); + usbpd_err(&pd->dev, "Error sending get_battery_cap\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } @@ -2646,8 +2643,7 @@ static void usbpd_sm(struct work_struct *w) ret = pd_send_ext_msg(pd, MSG_GET_BATTERY_STATUS, &pd->get_battery_status_db, 1, SOP_MSG); if (ret) { - dev_err(&pd->dev, - "Error sending get_battery_status\n"); + usbpd_err(&pd->dev, "Error sending get_battery_status\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } @@ -2677,7 +2673,7 @@ static void usbpd_sm(struct work_struct *w) pd->send_pr_swap = false; ret = pd_send_msg(pd, MSG_PR_SWAP, NULL, 0, SOP_MSG); if (ret) { - dev_err(&pd->dev, "Error sending PR Swap\n"); + usbpd_err(&pd->dev, "Error sending PR Swap\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } @@ -2688,7 +2684,7 @@ static void usbpd_sm(struct work_struct *w) pd->send_dr_swap = false; ret = pd_send_msg(pd, MSG_DR_SWAP, NULL, 0, SOP_MSG); if (ret) { - dev_err(&pd->dev, "Error sending DR Swap\n"); + usbpd_err(&pd->dev, "Error sending DR Swap\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } -- GitLab From 3dc939306eff6f2acad430c60022bde944362ef9 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Fri, 20 Jul 2018 12:54:20 +0800 Subject: [PATCH 442/604] power: qpnp-qnovo: Enable auto FG ESR extraction in CV charging After entering into CV mode charging, Qnovo is still enabled but no PT is rearmed, ESR extraction is expected to be handled by FG itself in this case. QNI would detect the CV mode charging and write value 0 to PE_CTRL2 register, so detecting this register write and notify FG driver to enable auto ESR extraction. Change-Id: Iffbcbdb27a2d1a45e2f7a8aef7d933c653823c46 Signed-off-by: Fenglin Wu --- drivers/power/supply/qcom/qpnp-qnovo.c | 50 +++++++++++++++++++++----- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c index 53af3415ec6a..6adc19a2012a 100644 --- a/drivers/power/supply/qcom/qpnp-qnovo.c +++ b/drivers/power/supply/qcom/qpnp-qnovo.c @@ -127,6 +127,7 @@ #define DC_READY_VOTER "DC_READY_VOTER" #define PT_RESTART_VOTER "PT_RESTART_VOTER" +#define REG_WRITE_VOTER "REG_WRITE_VOTER" struct qnovo_dt_props { bool external_rsense; @@ -145,6 +146,7 @@ struct qnovo { struct votable *not_ok_to_qnovo_votable; struct votable *chg_ready_votable; struct votable *awake_votable; + struct votable *auto_esr_votable; struct class qnovo_class; struct pmic_revid_data *pmic_rev_id; u32 wa_flags; @@ -340,15 +342,7 @@ static int qnovo_disable_cb(struct votable *votable, void *data, int disable, return -EINVAL; } - /* - * fg must be available for enable FG_AVAILABLE_VOTER - * won't enable it otherwise - */ - - if (is_fg_available(chip)) - power_supply_set_property(chip->bms_psy, - POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE, - &pval); + vote(chip->auto_esr_votable, QNOVO_OVERALL_VOTER, disable, 0); vote(chip->pt_dis_votable, QNOVO_OVERALL_VOTER, disable, 0); rc = qnovo_batt_psy_update(chip, disable); @@ -420,6 +414,27 @@ static int awake_cb(struct votable *votable, void *data, int awake, return 0; } +static int auto_esr_cb(struct votable *votable, void *data, int auto_esr, + const char *client) +{ + struct qnovo *chip = data; + union power_supply_propval pval = {0}; + + pval.intval = !auto_esr; + if (is_fg_available(chip)) + power_supply_set_property(chip->bms_psy, + POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE, + &pval); + + return 0; +} + +static void pe_ctrl2_write_cb(struct qnovo *chip, u8 *val) +{ + if (get_effective_result(chip->disable_votable) == 0) + vote(chip->auto_esr_votable, REG_WRITE_VOTER, (*val == 0), 0); +} + static int qnovo_parse_dt(struct qnovo *chip) { struct device_node *node = chip->dev->of_node; @@ -497,6 +512,7 @@ struct param_info { int reg_to_unit_offset; int min_val; int max_val; + void (*callback)(struct qnovo *chip, u8 *val); char *units_str; }; @@ -523,6 +539,7 @@ static struct param_info params[] = { .name = "PE_CTRL2_REG", .start_addr = QNOVO_PE_CTRL2, .num_regs = 1, + .callback = pe_ctrl2_write_cb, .units_str = "", }, [PTRAIN_STS_REG] = { @@ -892,6 +909,10 @@ static ssize_t reg_store(struct class *c, struct class_attribute *attr, pr_err("Couldn't write %s rc = %d\n", params[i].name, rc); return -EINVAL; } + + if (params[i].callback) + params[i].callback(chip, buf); + return count; } @@ -1464,6 +1485,8 @@ static int qnovo_hw_init(struct qnovo *chip) vote(chip->pt_dis_votable, QNOVO_OVERALL_VOTER, true, 0); vote(chip->pt_dis_votable, ESR_VOTER, false, 0); + vote(chip->auto_esr_votable, QNOVO_OVERALL_VOTER, true, 0); + val = 0; rc = qnovo_write(chip, QNOVO_STRM_CTRL, &val, 1); if (rc < 0) { @@ -1656,6 +1679,13 @@ static int qnovo_probe(struct platform_device *pdev) goto destroy_chg_ready_votable; } + chip->auto_esr_votable = create_votable("AUTO_ESR", VOTE_SET_ANY, + auto_esr_cb, chip); + if (IS_ERR(chip->auto_esr_votable)) { + rc = PTR_ERR(chip->auto_esr_votable); + goto destroy_auto_esr_votable; + } + INIT_WORK(&chip->status_change_work, status_change_work); INIT_DELAYED_WORK(&chip->dc_debounce_work, dc_debounce_work); INIT_DELAYED_WORK(&chip->usb_debounce_work, usb_debounce_work); @@ -1700,6 +1730,8 @@ static int qnovo_probe(struct platform_device *pdev) unreg_notifier: power_supply_unreg_notifier(&chip->nb); +destroy_auto_esr_votable: + destroy_votable(chip->auto_esr_votable); destroy_awake_votable: destroy_votable(chip->awake_votable); destroy_chg_ready_votable: -- GitLab From a8bc5748e1c576c00642f9b6846fec97182b5c39 Mon Sep 17 00:00:00 2001 From: Ramandeep Trehan Date: Thu, 19 Jul 2018 09:36:23 +0530 Subject: [PATCH 443/604] msm8953: Enable config flag for File based Encryption File system flags for ext4 are required for Inline Crypto Engine based file encryption to work smoothly. Change-Id: I58ba97134f2c606e1fdb8fbf24fac7c893479229 Signed-off-by: Ramandeep Trehan --- arch/arm64/configs/msm8953-perf_defconfig | 5 ++++- arch/arm64/configs/msm8953_defconfig | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig index fca320eda749..eeb1d74c3398 100644 --- a/arch/arm64/configs/msm8953-perf_defconfig +++ b/arch/arm64/configs/msm8953-perf_defconfig @@ -604,6 +604,9 @@ CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_QUOTA=y @@ -635,12 +638,12 @@ CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_CTI=y CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_HWEVENT=y +CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y -CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig index a3547be86d45..d0783cd63972 100644 --- a/arch/arm64/configs/msm8953_defconfig +++ b/arch/arm64/configs/msm8953_defconfig @@ -623,6 +623,9 @@ CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_QUOTA=y @@ -702,12 +705,12 @@ CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_CTI=y CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_HWEVENT=y +CONFIG_PFK=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y -CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y -- GitLab From 306dcc1d810a54535a832a4889ac02db04b1a45b Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Mon, 16 Jul 2018 17:03:05 +0530 Subject: [PATCH 444/604] power: qpnp-qg: Update VBAT_LOW fifo_length handling There can be a race between VBAT_LOW and FIFO_DONE irq handler (as VBAT_LOW is triggered based on the FIFO average). This may cause the FIFO_DONE handler to incorrectly process the fifo-length (if the VBAT_LOW irq handler executes just before the FIFO_DONE handler). Fix this by updating the fifo-length only in the next FIFO-DONE handler, after the VBAT_LOW has triggered. Change-Id: I2829f12274692871ead9af00fc843c3bb29af4a9 Signed-off-by: Anirudh Ghayal --- drivers/power/supply/qcom/qpnp-qg.c | 122 ++++++++++++---------------- 1 file changed, 54 insertions(+), 68 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index d1b6beaa8507..6f4805969371 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -452,13 +452,11 @@ static int qg_process_rt_fifo(struct qpnp_qg *chip) } #define MIN_FIFO_FULL_TIME_MS 12000 -static int process_rt_fifo_data(struct qpnp_qg *chip, - bool update_vbat_low, bool update_smb) +static int process_rt_fifo_data(struct qpnp_qg *chip, bool update_smb) { int rc = 0; ktime_t now = ktime_get(); s64 time_delta; - u8 fifo_length; /* * Reject the FIFO read event if there are back-to-back requests @@ -467,11 +465,10 @@ static int process_rt_fifo_data(struct qpnp_qg *chip, */ time_delta = ktime_ms_delta(now, chip->last_user_update_time); - qg_dbg(chip, QG_DEBUG_FIFO, "time_delta=%lld ms update_vbat_low=%d update_smb=%d\n", - time_delta, update_vbat_low, update_smb); + qg_dbg(chip, QG_DEBUG_FIFO, "time_delta=%lld ms update_smb=%d\n", + time_delta, update_smb); - if (time_delta > MIN_FIFO_FULL_TIME_MS || update_vbat_low - || update_smb) { + if (time_delta > MIN_FIFO_FULL_TIME_MS || update_smb) { rc = qg_master_hold(chip, true); if (rc < 0) { pr_err("Failed to hold master, rc=%d\n", rc); @@ -484,20 +481,6 @@ static int process_rt_fifo_data(struct qpnp_qg *chip, goto done; } - if (update_vbat_low) { - /* change FIFO length */ - fifo_length = chip->vbat_low ? - chip->dt.s2_vbat_low_fifo_length : - chip->dt.s2_fifo_length; - rc = qg_update_fifo_length(chip, fifo_length); - if (rc < 0) - goto done; - - qg_dbg(chip, QG_DEBUG_STATUS, - "FIFO length updated to %d vbat_low=%d\n", - fifo_length, chip->vbat_low); - } - if (update_smb) { rc = qg_masked_write(chip, chip->qg_base + QG_MODE_CTL1_REG, PARALLEL_IBAT_SENSE_EN_BIT, @@ -539,60 +522,67 @@ static int process_rt_fifo_data(struct qpnp_qg *chip, static int qg_vbat_low_wa(struct qpnp_qg *chip) { int rc, i, temp = 0; - u32 vbat_low_uv = 0; + u32 vbat_low_uv = 0, fifo_length = 0; - rc = qg_get_battery_temp(chip, &temp); - if (rc < 0) { - pr_err("Failed to read batt_temp rc=%d\n", rc); - temp = 250; + if ((chip->wa_flags & QG_VBAT_LOW_WA) && chip->vbat_low) { + rc = qg_get_battery_temp(chip, &temp); + if (rc < 0) { + pr_err("Failed to read batt_temp rc=%d\n", rc); + temp = 250; + } + + vbat_low_uv = 1000 * ((temp < chip->dt.cold_temp_threshold) ? + chip->dt.vbatt_low_cold_mv : + chip->dt.vbatt_low_mv); + vbat_low_uv += VBAT_LOW_HYST_UV; + /* + * PMI632 1.0 does not generate a falling VBAT_LOW IRQ. + * To exit from VBAT_LOW config, check if any of the FIFO + * averages is > vbat_low threshold and reconfigure the + * FIFO length to normal. + */ + for (i = 0; i < chip->kdata.fifo_length; i++) { + if (chip->kdata.fifo[i].v > vbat_low_uv) { + chip->vbat_low = false; + pr_info("Exit VBAT_LOW vbat_avg=%duV vbat_low=%duV updated fifo_length=%d\n", + chip->kdata.fifo[i].v, vbat_low_uv, + chip->dt.s2_fifo_length); + break; + } + } } - vbat_low_uv = 1000 * ((temp < chip->dt.cold_temp_threshold) ? - chip->dt.vbatt_low_cold_mv : - chip->dt.vbatt_low_mv); - vbat_low_uv += VBAT_LOW_HYST_UV; + rc = get_fifo_length(chip, &fifo_length, false); + if (rc < 0) { + pr_err("Failed to get FIFO length, rc=%d\n", rc); + return rc; + } - if (!(chip->wa_flags & QG_VBAT_LOW_WA) || !chip->vbat_low) + if (chip->vbat_low && fifo_length == chip->dt.s2_vbat_low_fifo_length) return 0; - /* - * PMI632 1.0 does not generate a falling VBAT_LOW IRQ. - * To exit from VBAT_LOW config, check if any of the FIFO - * averages is > vbat_low threshold and reconfigure the - * FIFO length to normal. - */ - for (i = 0; i < chip->kdata.fifo_length; i++) { - if (chip->kdata.fifo[i].v > vbat_low_uv) { - rc = qg_master_hold(chip, true); - if (rc < 0) { - pr_err("Failed to hold master, rc=%d\n", rc); - goto done; - } - rc = qg_update_fifo_length(chip, - chip->dt.s2_fifo_length); - if (rc < 0) - goto done; - - rc = qg_master_hold(chip, false); - if (rc < 0) { - pr_err("Failed to release master, rc=%d\n", rc); - goto done; - } - /* FIFOs restarted */ - chip->last_fifo_update_time = ktime_get(); + if (!chip->vbat_low && fifo_length == chip->dt.s2_fifo_length) + return 0; - chip->vbat_low = false; - pr_info("Exit VBAT_LOW vbat_avg=%duV vbat_low=%duV updated fifo_length=%d\n", - chip->kdata.fifo[i].v, vbat_low_uv, - chip->dt.s2_fifo_length); - break; - } + rc = qg_master_hold(chip, true); + if (rc < 0) { + pr_err("Failed to hold master, rc=%d\n", rc); + goto done; } - return 0; + fifo_length = chip->vbat_low ? chip->dt.s2_vbat_low_fifo_length : + chip->dt.s2_fifo_length; + + rc = qg_update_fifo_length(chip, fifo_length); + if (rc < 0) + goto done; + qg_dbg(chip, QG_DEBUG_STATUS, "FIFO length updated to %d vbat_low=%d\n", + fifo_length, chip->vbat_low); done: qg_master_hold(chip, false); + /* FIFOs restarted */ + chip->last_fifo_update_time = ktime_get(); return rc; } @@ -1174,10 +1164,6 @@ static irqreturn_t qg_vbat_low_handler(int irq, void *data) chip->vbat_low = !!(status & VBAT_LOW_INT_RT_STS_BIT); - rc = process_rt_fifo_data(chip, true, false); - if (rc < 0) - pr_err("Failed to process RT FIFO data, rc=%d\n", rc); - qg_dbg(chip, QG_DEBUG_IRQ, "VBAT_LOW = %d\n", chip->vbat_low); done: mutex_unlock(&chip->data_lock); @@ -1950,7 +1936,7 @@ static int qg_parallel_status_update(struct qpnp_qg *chip) if (!chip->dt.qg_ext_sense) update_smb = true; - rc = process_rt_fifo_data(chip, false, update_smb); + rc = process_rt_fifo_data(chip, update_smb); if (rc < 0) pr_err("Failed to process RT FIFO data, rc=%d\n", rc); -- GitLab From 6f3f1fab1dd8ddf3f04dea97ef1f404ccfecf7b8 Mon Sep 17 00:00:00 2001 From: Arun Kumar Neelakantam Date: Thu, 19 Jul 2018 14:25:22 +0530 Subject: [PATCH 445/604] net: ipc_router: Initialize the sockaddr in recvmsg() handler sockaddr structure is filled with required information only which results in few memory locations of structure with uninitialized data. Memset complete structure before using it to remove uninitialized data. CRs-Fixed: 2274853 Change-Id: I181710bde100fb1553b925d9fdf227af35ff38b5 Signed-off-by: Arun Kumar Neelakantam --- net/ipc_router/ipc_router_socket.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipc_router/ipc_router_socket.c b/net/ipc_router/ipc_router_socket.c index a758a0902c17..4e53861c4acc 100644 --- a/net/ipc_router/ipc_router_socket.c +++ b/net/ipc_router/ipc_router_socket.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* 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 @@ -146,6 +146,7 @@ static int msm_ipc_router_extract_msg(struct msghdr *m, return -EINVAL; } ctl_msg = (union rr_control_msg *)(temp->data); + memset(addr, 0x0, sizeof(*addr)); addr->family = AF_MSM_IPC; addr->address.addrtype = MSM_IPC_ADDR_ID; addr->address.addr.port_addr.node_id = ctl_msg->cli.node_id; @@ -154,6 +155,7 @@ static int msm_ipc_router_extract_msg(struct msghdr *m, return offset; } if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_DATA)) { + memset(addr, 0x0, sizeof(*addr)); addr->family = AF_MSM_IPC; addr->address.addrtype = MSM_IPC_ADDR_ID; addr->address.addr.port_addr.node_id = hdr->src_node_id; -- GitLab From 3c52b9b3273e3453d6d87829f37f53c936091bf6 Mon Sep 17 00:00:00 2001 From: Nirmal Abraham Date: Fri, 20 Jul 2018 14:30:08 +0530 Subject: [PATCH 446/604] fbmem: Remove mutex use from do_fb_ioctl() Remove use of this mutex to allow multiple msm_fb ioctl calls. Mutexes within the individual fb_ioctl calls already provide the necessary locking. This is based on android-msm-2.6.35 commit: a809819d (msm_fb: display: Add delay kickoff to MDDI) which includes this change among others. Change-Id: Iee68bf3556ab913f916868988f4adbad1ed6b2a0 Signed-off-by: Kuogee Hsieh Signed-off-by: Veera Sundaram Sankaran Signed-off-by: Nirmal Abraham --- drivers/video/fbdev/core/fbmem.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 2ef33d45b0b6..52bbbc47e937 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1219,8 +1219,6 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, console_unlock(); break; default: - if (!lock_fb_info(info)) - return -ENODEV; fb = info->fbops; if (fb->fb_ioctl_v2) ret = fb->fb_ioctl_v2(info, cmd, arg, file); @@ -1228,7 +1226,6 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, ret = fb->fb_ioctl(info, cmd, arg); else ret = -ENOTTY; - unlock_fb_info(info); } return ret; } -- GitLab From f14ef34236428f718ec0b3bf3817fb29dfe5b614 Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Fri, 20 Jul 2018 17:17:55 +0530 Subject: [PATCH 447/604] dmaengine: gpi: Set dma mask to 64 GPI driver need not consider the IOVA range and size when setting the dma mask, which otherwise could result in a too low value for the mask on 32-bit builds. Set it to 64 unconditionally. Change-Id: I4ec1fb60dd6b62570b2c4a2b1f30c4349871d544 Signed-off-by: Siva Kumar Akkireddi --- drivers/dma/qcom/gpi.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c index 065b765c02b4..fff2ae91470a 100644 --- a/drivers/dma/qcom/gpi.c +++ b/drivers/dma/qcom/gpi.c @@ -2564,22 +2564,6 @@ static struct dma_iommu_mapping *gpi_create_mapping(struct gpi_dev *gpi_dev) return arm_iommu_create_mapping(&platform_bus_type, base, size); } -static int gpi_dma_mask(struct gpi_dev *gpi_dev) -{ - int mask = 64; - - if (gpi_dev->smmu_cfg && !(gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS)) { - unsigned long addr; - - addr = gpi_dev->iova_base + gpi_dev->iova_size + 1; - mask = find_last_bit(&addr, 64); - } - - GPI_LOG(gpi_dev, "Setting dma mask to %d\n", mask); - - return dma_set_mask(gpi_dev->dev, DMA_BIT_MASK(mask)); -} - static int gpi_smmu_init(struct gpi_dev *gpi_dev) { struct dma_iommu_mapping *mapping = NULL; @@ -2643,9 +2627,10 @@ static int gpi_smmu_init(struct gpi_dev *gpi_dev) } } - ret = gpi_dma_mask(gpi_dev); + GPI_LOG(gpi_dev, "Setting dma mask to 64\n"); + ret = dma_set_mask(gpi_dev->dev, DMA_BIT_MASK(64)); if (ret) { - GPI_ERR(gpi_dev, "Error setting dma_mask, ret:%d\n", ret); + GPI_ERR(gpi_dev, "Error setting dma_mask to 64, ret:%d\n", ret); goto error_set_mask; } -- GitLab From d4b10f953e833f9116602bdb9ed95a49adb50815 Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Thu, 28 Jun 2018 16:53:34 +0530 Subject: [PATCH 448/604] ARM: dts: msm: Add camera support for MSM8917 MTP device Add camera dtsi changes for MSM8917 MTP. Port msm-3.18 camera kernel on msm-4.9 kernel This snapshot is taken from msm-3.18 branch as of: 'commit 3e917a308af6 ("ARM: dts: msm: Add camera device tree files for MSMgold")' Change-Id: I6669cd4219e3dc791015f866cd67d582fbd0ef81 Signed-off-by: Abhishek Jain --- .../dts/qcom/msm8917-camera-sensor-mtp.dtsi | 282 ++++++++++++++++++ arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi | 1 + arch/arm64/boot/dts/qcom/msm8917-pmi8937.dtsi | 11 + arch/arm64/boot/dts/qcom/msm8917-pmi8940.dtsi | 11 + 4 files changed, 305 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/msm8917-camera-sensor-mtp.dtsi diff --git a/arch/arm64/boot/dts/qcom/msm8917-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-camera-sensor-mtp.dtsi new file mode 100644 index 000000000000..23c0987e34f2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-camera-sensor-mtp.dtsi @@ -0,0 +1,282 @@ +/* + * 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. + */ + +&cci { + actuator0: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + qcom,cci-master = <0>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <2850000>; + qcom,cam-vreg-max-voltage = <2850000>; + qcom,cam-vreg-op-mode = <80000>; + }; + + actuator1: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + qcom,cci-master = <0>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <2850000>; + qcom,cam-vreg-max-voltage = <2850000>; + qcom,cam-vreg-op-mode = <80000>; + }; + + eeprom0: qcom,eeprom@0 { + cell-index = <0>; + compatible = "qcom,eeprom"; + qcom,cci-master = <0>; + reg = <0x0>; + cam_vdig-supply = <&pm8937_l23>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio", + "cam_vaf"; + qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-op-mode = <200000 0 80000 100000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_default + &cam_sensor_rear_default>; + pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; + gpios = <&tlmm 26 0>, + <&tlmm 36 0>, + <&tlmm 35 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_STANDBY0"; + status = "ok"; + clocks = <&clock_gcc clk_mclk0_clk_src>, + <&clock_gcc clk_gcc_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <19200000 0>; + }; + + eeprom1: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + qcom,eeprom-name = "sunny_8865"; + compatible = "qcom,eeprom"; + qcom,slave-addr = <0x6c>; + qcom,cci-master = <0>; + qcom,num-blocks = <8>; + + qcom,page0 = <1 0x0100 2 0x01 1 1>; + qcom,poll0 = <0 0x0 2 0x0 1 0>; + qcom,mem0 = <0 0x0 2 0x0 1 0>; + + qcom,page1 = <1 0x5002 2 0x00 1 0>; + qcom,poll1 = <0 0x0 2 0x0 1 0>; + qcom,mem1 = <0 0x0 2 0x0 1 0>; + + qcom,page2 = <1 0x3d84 2 0xc0 1 0>; + qcom,poll2 = <0 0x0 2 0x0 1 0>; + qcom,mem2 = <0 0x0 2 0x0 1 0>; + + qcom,page3 = <1 0x3d88 2 0x70 1 0>; + qcom,poll3 = <0 0x0 2 0x0 1 0>; + qcom,mem3 = <0 0x0 2 0x0 1 0>; + + qcom,page4 = <1 0x3d89 2 0x10 1 0>; + qcom,poll4 = <0 0x0 2 0x0 1 0>; + qcom,mem4 = <0 0x0 2 0x0 1 0>; + + qcom,page5 = <1 0x3d8a 2 0x70 1 0>; + qcom,poll5 = <0 0x0 2 0x0 1 0>; + qcom,mem5 = <0 0x0 2 0x0 1 0>; + + qcom,page6 = <1 0x3d8b 2 0xf4 1 0>; + qcom,poll6 = <0 0x0 2 0x0 1 0>; + qcom,mem6 = <0 0x0 2 0x0 1 0>; + + qcom,page7 = <1 0x3d81 2 0x01 1 10>; + qcom,poll7 = <0 0x0 2 0x0 1 1>; + qcom,mem7 = <1536 0x7010 2 0 1 0>; + + cam_vdig-supply = <&pm8937_l23>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", + "cam_vaf"; + qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-op-mode = <105000 0 80000 100000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_default + &cam_sensor_front1_default>; + pinctrl-1 = <&cam_sensor_mclk2_sleep &cam_sensor_front1_sleep>; + gpios = <&tlmm 28 0>, + <&tlmm 40 0>, + <&tlmm 39 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_STANDBY2"; + qcom,cam-power-seq-type = "sensor_vreg", "sensor_vreg", + "sensor_vreg", + "sensor_gpio", "sensor_gpio" , "sensor_clk"; + qcom,cam-power-seq-val = "cam_vdig", "cam_vana", "cam_vio", + "sensor_gpio_reset", "sensor_gpio_standby", + "sensor_cam_mclk"; + qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>; + qcom,cam-power-seq-delay = <1 1 1 30 30 5>; + status = "ok"; + clocks = <&clock_gcc clk_mclk2_clk_src>, + <&clock_gcc clk_gcc_camss_mclk2_clk>; + clock-names = "cam_src_clk", "cam_clk"; + }; + + qcom,camera@0 { + cell-index = <0>; + compatible = "qcom,camera"; + reg = <0x0>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <270>; + qcom,led-flash-src = <&led_flash0>; + qcom,eeprom-src = <&eeprom0>; + qcom,actuator-src = <&actuator0>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vaf"; + qcom,cam-vreg-min-voltage = <0 2800000 2850000>; + qcom,cam-vreg-max-voltage = <0 2800000 2850000>; + qcom,cam-vreg-op-mode = <0 80000 100000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_default + &cam_sensor_rear_default + &cam_sensor_rear_vdig>; + pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep + &cam_sensor_rear_vdig_sleep>; + gpios = <&tlmm 26 0>, + <&tlmm 36 0>, + <&tlmm 35 0>, + <&tlmm 62 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-vdig = <3>; + qcom,gpio-req-tbl-num = <0 1 2 3>; + qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_STANDBY0", + "CAM_VDIG"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_gcc clk_mclk0_clk_src>, + <&clock_gcc clk_gcc_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@1 { + cell-index = <1>; + compatible = "qcom,camera"; + reg = <0x1>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <1>; + qcom,mount-angle = <90>; + cam_vdig-supply = <&pm8937_l23>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", + "cam_vaf"; + qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-op-mode = <200000 0 80000 100000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_default + &cam_sensor_front_default>; + pinctrl-1 = <&cam_sensor_mclk1_sleep + &cam_sensor_front_sleep>; + gpios = <&tlmm 27 0>, + <&tlmm 38 0>, + <&tlmm 50 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_STANDBY1"; + qcom,sensor-position = <0x100>; + qcom,sensor-mode = <1>; + qcom,cci-master = <1>; + clocks = <&clock_gcc clk_mclk1_clk_src>, + <&clock_gcc clk_gcc_camss_mclk1_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@2 { + cell-index = <2>; + compatible = "qcom,camera"; + reg = <0x02>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <1>; + qcom,mount-angle = <90>; + qcom,eeprom-src = <&eeprom1>; + qcom,actuator-src = <&actuator1>; + cam_vdig-supply = <&pm8937_l23>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", + "cam_vaf"; + qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-op-mode = <105000 0 80000 100000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_default + &cam_sensor_front1_default>; + pinctrl-1 = <&cam_sensor_mclk2_sleep + &cam_sensor_front1_sleep>; + gpios = <&tlmm 28 0>, + <&tlmm 40 0>, + <&tlmm 39 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_STANDBY2"; + qcom,sensor-position = <1>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_gcc clk_mclk2_clk_src>, + <&clock_gcc clk_gcc_camss_mclk2_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi index d2e100e97017..7f35e1ebcf41 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi @@ -11,6 +11,7 @@ * GNU General Public License for more details. */ +#include "msm8917-camera-sensor-mtp.dtsi" &blsp1_uart2 { status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8937.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pmi8937.dtsi index 91a290f98003..55e8e211060a 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-pmi8937.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8937.dtsi @@ -22,3 +22,14 @@ &usb_otg { extcon = <&qpnp_smbcharger>; }; + +&soc { + led_flash0: qcom,camera-flash { + cell-index = <0>; + compatible = "qcom,camera-flash"; + qcom,flash-type = <1>; + qcom,flash-source = <&pmi8937_flash0 &pmi8937_flash1>; + qcom,torch-source = <&pmi8937_torch0 &pmi8937_torch1>; + qcom,switch-source = <&pmi8937_switch>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8940.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pmi8940.dtsi index 90226da7eb41..9b9cd474395d 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-pmi8940.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8940.dtsi @@ -22,3 +22,14 @@ &usb_otg { extcon = <&qpnp_smbcharger>; }; + +&soc { + led_flash0: qcom,camera-flash { + cell-index = <0>; + compatible = "qcom,camera-flash"; + qcom,flash-type = <1>; + qcom,flash-source = <&pmi8940_flash0 &pmi8940_flash1>; + qcom,torch-source = <&pmi8940_torch0 &pmi8940_torch1>; + qcom,switch-source = <&pmi8940_switch>; + }; +}; -- GitLab From 0eed3f6cc0d9061ffc139b9e78c2fff89f5b4076 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Fri, 20 Jul 2018 03:15:13 -0700 Subject: [PATCH 449/604] 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 | 8 ++++---- 1 file changed, 4 insertions(+), 4 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 5a6a4010231d..afab016756f6 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 @@ -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 @@ -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 26e6274f352d615d407fcd217b8021984d730264 Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Fri, 4 May 2018 17:19:06 -0700 Subject: [PATCH 450/604] qseecom: abort all listener threads before listener unregistration Wake up and abort all busy listener processing threads before listener unregistration, then to avoid deadlock between listener unregistration and listener processing threads, as mutex may be hold by another busy listener thread when qseecom gets a listener unregistration request or qseecom daemon is dead. Change-Id: I6b6ddb34eb6bcff763e3d13f026c4b2f4bcb32a9 Signed-off-by: Zhen Kong --- drivers/misc/qseecom.c | 155 +++++++++++++++++++++-------------------- 1 file changed, 80 insertions(+), 75 deletions(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 07ae56f4efb5..39244560a788 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -189,6 +189,7 @@ struct qseecom_registered_listener_list { wait_queue_head_t listener_block_app_wq; struct sglist_info sglistinfo_ptr[MAX_ION_FD]; uint32_t sglist_cnt; + int abort; }; struct qseecom_registered_app_list { @@ -1223,6 +1224,23 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data, return ret; } +static void __qseecom_listener_abort_all(int abort) +{ + struct qseecom_registered_listener_list *entry = NULL; + unsigned long flags; + + spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags); + list_for_each_entry(entry, + &qseecom.registered_listener_list_head, list) { + pr_debug("set abort %d for listener %d\n", + abort, entry->svc.listener_id); + entry->abort = abort; + } + if (abort) + wake_up_interruptible_all(&qseecom.send_resp_wq); + spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags); +} + static int qseecom_unregister_listener(struct qseecom_dev_handle *data) { int ret = 0; @@ -1256,6 +1274,7 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data) list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head, list) { if (ptr_svc->svc.listener_id == data->listener.id) { + ptr_svc->abort = 1; wake_up_all(&ptr_svc->rcv_req_wq); break; } @@ -1602,12 +1621,13 @@ static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data, return 0; } -static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data) +static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data, + struct qseecom_registered_listener_list *ptr_svc) { int ret; ret = (qseecom.send_resp_flag != 0); - return ret || data->abort; + return ret || data->abort || ptr_svc->abort; } static int __qseecom_reentrancy_listener_has_sent_rsp( @@ -1617,56 +1637,7 @@ static int __qseecom_reentrancy_listener_has_sent_rsp( int ret; ret = (ptr_svc->send_resp_flag != 0); - return ret || data->abort; -} - -static int __qseecom_qseos_fail_return_resp_tz(struct qseecom_dev_handle *data, - struct qseecom_command_scm_resp *resp, - struct qseecom_client_listener_data_irsp *send_data_rsp, - struct qseecom_registered_listener_list *ptr_svc, - uint32_t lstnr) { - int ret = 0; - - send_data_rsp->status = QSEOS_RESULT_FAILURE; - qseecom.send_resp_flag = 0; - send_data_rsp->qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND; - send_data_rsp->listener_id = lstnr; - if (ptr_svc) - pr_warn("listener_id:%x, lstnr: %x\n", - ptr_svc->svc.listener_id, lstnr); - if (ptr_svc && ptr_svc->ihandle) { - ret = msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle, - ptr_svc->sb_virt, ptr_svc->sb_length, - ION_IOC_CLEAN_INV_CACHES); - if (ret) { - pr_err("cache operation failed %d\n", ret); - return ret; - } - } - - if (lstnr == RPMB_SERVICE) { - ret = __qseecom_enable_clk(CLK_QSEE); - if (ret) - return ret; - } - ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, send_data_rsp, - sizeof(send_data_rsp), resp, sizeof(*resp)); - if (ret) { - pr_err("scm_call() failed with err: %d (app_id = %d)\n", - ret, data->client.app_id); - if (lstnr == RPMB_SERVICE) - __qseecom_disable_clk(CLK_QSEE); - return ret; - } - if ((resp->result != QSEOS_RESULT_SUCCESS) && - (resp->result != QSEOS_RESULT_INCOMPLETE)) { - pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n", - resp->result, data->client.app_id, lstnr); - ret = -EINVAL; - } - if (lstnr == RPMB_SERVICE) - __qseecom_disable_clk(CLK_QSEE); - return ret; + return ret || data->abort || ptr_svc->abort; } static void __qseecom_clean_listener_sglistinfo( @@ -1717,23 +1688,33 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, if (ptr_svc == NULL) { pr_err("Listener Svc %d does not exist\n", lstnr); - __qseecom_qseos_fail_return_resp_tz(data, resp, - &send_data_rsp, ptr_svc, lstnr); - return -EINVAL; + rc = -EINVAL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } if (!ptr_svc->ihandle) { pr_err("Client handle is not initialized\n"); - __qseecom_qseos_fail_return_resp_tz(data, resp, - &send_data_rsp, ptr_svc, lstnr); - return -EINVAL; + rc = -EINVAL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } if (ptr_svc->svc.listener_id != lstnr) { - pr_warn("Service requested does not exist\n"); - __qseecom_qseos_fail_return_resp_tz(data, resp, - &send_data_rsp, NULL, lstnr); - return -ERESTARTSYS; + pr_err("Service %d does not exist\n", + lstnr); + rc = -ERESTARTSYS; + ptr_svc = NULL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; + } + + if (ptr_svc->abort == 1) { + pr_err("Service %d abort %d\n", + lstnr, ptr_svc->abort); + rc = -ENODEV; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n"); @@ -1750,7 +1731,8 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, */ if (!qseecom.qsee_reentrancy_support && !wait_event_freezable(qseecom.send_resp_wq, - __qseecom_listener_has_sent_rsp(data))) { + __qseecom_listener_has_sent_rsp( + data, ptr_svc))) { break; } @@ -1764,7 +1746,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, /* restore signal mask */ sigprocmask(SIG_SETMASK, &old_sigset, NULL); - if (data->abort) { + if (data->abort || ptr_svc->abort) { pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d", data->client.app_id, lstnr, ret); rc = -ENODEV; @@ -1772,7 +1754,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, } else { status = QSEOS_RESULT_SUCCESS; } - +err_resp: qseecom.send_resp_flag = 0; ptr_svc->send_resp_flag = 0; table = ptr_svc->sglistinfo_ptr; @@ -1832,6 +1814,8 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, __qseecom_disable_clk(CLK_QSEE); 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) && (resp->result != QSEOS_RESULT_INCOMPLETE)) { pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n", @@ -1985,7 +1969,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd( size_t cmd_len; struct sglist_info *table = NULL; - while (ret == 0 && rc == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) { + while (ret == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) { lstnr = resp->data; /* * Wake up blocking lsitener service with the lstnr id @@ -2006,17 +1990,33 @@ static int __qseecom_reentrancy_process_incomplete_cmd( if (ptr_svc == NULL) { pr_err("Listener Svc %d does not exist\n", lstnr); - return -EINVAL; + rc = -EINVAL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } if (!ptr_svc->ihandle) { pr_err("Client handle is not initialized\n"); - return -EINVAL; + rc = -EINVAL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } if (ptr_svc->svc.listener_id != lstnr) { - pr_warn("Service requested does not exist\n"); - return -ERESTARTSYS; + pr_err("Service %d does not exist\n", + lstnr); + rc = -ERESTARTSYS; + ptr_svc = NULL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; + } + + if (ptr_svc->abort == 1) { + pr_err("Service %d abort %d\n", + lstnr, ptr_svc->abort); + rc = -ENODEV; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n"); @@ -2042,7 +2042,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd( /* restore signal mask */ sigprocmask(SIG_SETMASK, &old_sigset, NULL); - if (data->abort) { + if (data->abort || ptr_svc->abort) { pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d", data->client.app_id, lstnr, ret); rc = -ENODEV; @@ -2050,6 +2050,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd( } else { status = QSEOS_RESULT_SUCCESS; } +err_resp: table = ptr_svc->sglistinfo_ptr; if (qseecom.qsee_version < QSEE_VERSION_40) { send_data_rsp.listener_id = lstnr; @@ -3813,7 +3814,7 @@ static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data, int ret; ret = (svc->rcv_req_flag != 0); - return ret || data->abort; + return ret || data->abort || svc->abort; } static int qseecom_receive_req(struct qseecom_dev_handle *data) @@ -3837,9 +3838,9 @@ static int qseecom_receive_req(struct qseecom_dev_handle *data) return -ERESTARTSYS; } - if (data->abort) { + if (data->abort || this_lstnr->abort) { pr_err("Aborting Listener Service = %d\n", - (uint32_t)data->listener.id); + (uint32_t)data->listener.id); return -ENODEV; } this_lstnr->rcv_req_flag = 0; @@ -6154,7 +6155,7 @@ static int qseecom_update_key_user_info(struct qseecom_dev_handle *data, } static int qseecom_is_es_activated(void __user *argp) { - struct qseecom_is_es_activated_req req; + struct qseecom_is_es_activated_req req = {0}; struct qseecom_command_scm_resp resp; int ret; @@ -6999,12 +7000,14 @@ static inline long qseecom_ioctl(struct file *file, break; } pr_debug("ioctl unregister_listener_req()\n"); + __qseecom_listener_abort_all(1); mutex_lock(&app_access_lock); atomic_inc(&data->ioctl_count); ret = qseecom_unregister_listener(data); atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); mutex_unlock(&app_access_lock); + __qseecom_listener_abort_all(0); if (ret) pr_err("failed qseecom_unregister_listener: %d\n", ret); break; @@ -7671,9 +7674,11 @@ static int qseecom_release(struct inode *inode, struct file *file) data->type, data->mode, data); switch (data->type) { case QSEECOM_LISTENER_SERVICE: + __qseecom_listener_abort_all(1); mutex_lock(&app_access_lock); ret = qseecom_unregister_listener(data); mutex_unlock(&app_access_lock); + __qseecom_listener_abort_all(0); break; case QSEECOM_CLIENT_APP: mutex_lock(&app_access_lock); -- GitLab From 7314e274576f6f7d25e4dc8419442e9280fca237 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 16 Jul 2018 13:33:35 -0700 Subject: [PATCH 451/604] 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 Signed-off-by: Vishalsingh Hajeri --- .../cam_flash/cam_flash_core.c | 33 +++++++++++-------- .../cam_flash/cam_flash_dev.h | 10 +++--- 2 files changed, 24 insertions(+), 19 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 855ad29a6b07..4a9cfb0457b2 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 @@ -494,8 +494,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; } } @@ -766,17 +772,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; @@ -926,19 +935,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 92726a9a125c..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 @@ -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 @@ -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 94f25703294f12049b18a6060bd0b005787469fa Mon Sep 17 00:00:00 2001 From: Bojun Pan Date: Tue, 17 Jul 2018 15:00:34 -0700 Subject: [PATCH 452/604] Revert "msm: gsi: gsi channel mode switch spinlock fix" This reverts commit 1c6246891b4f2db802dda4a25747fe088aa81b66. We don't need the unnecessary spinlock to be added and the previous logic works fine Change-Id: Ie644541171ab22d9f1c633efd2648bbd9ecb6cbb Signed-off-by: Bojun Pan --- drivers/platform/msm/gsi/gsi.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 2c29538c35c6..5d8b12bb52a0 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -2788,27 +2788,21 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode) return -GSI_STATUS_UNSUPPORTED_OP; } + spin_lock_irqsave(&gsi_ctx->slock, flags); if (curr == GSI_CHAN_MODE_CALLBACK && mode == GSI_CHAN_MODE_POLL) { - spin_lock_irqsave(&gsi_ctx->slock, flags); __gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, 0); - spin_unlock_irqrestore(&gsi_ctx->slock, flags); - spin_lock_irqsave(&ctx->ring.slock, flags); atomic_set(&ctx->poll_mode, mode); - spin_unlock_irqrestore(&ctx->ring.slock, flags); ctx->stats.callback_to_poll++; } if (curr == GSI_CHAN_MODE_POLL && mode == GSI_CHAN_MODE_CALLBACK) { - spin_lock_irqsave(&ctx->ring.slock, flags); atomic_set(&ctx->poll_mode, mode); - spin_unlock_irqrestore(&ctx->ring.slock, flags); - spin_lock_irqsave(&gsi_ctx->slock, flags); __gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, ~0); - spin_unlock_irqrestore(&gsi_ctx->slock, flags); ctx->stats.poll_to_callback++; } + spin_unlock_irqrestore(&gsi_ctx->slock, flags); return GSI_STATUS_SUCCESS; } -- GitLab From 177532b07c446940e3804b471b33e33f6a4a13ca Mon Sep 17 00:00:00 2001 From: Vijay Navnath Kamble Date: Wed, 18 Jul 2018 19:22:09 +0530 Subject: [PATCH 453/604] input: touchscreen: Remove himax touchscreen support Himax updated touch driver by fixing all the errors. Need to remove existing touch driver code and update with latest comits. Change-Id: Ia56efc11d3192ddd3449f38b9c62afbe585ef83a Signed-off-by: Vijay Navnath Kamble --- .../bindings/input/touchscreen/himax.txt | 22 - .../devicetree/bindings/vendor-prefixes.txt | 1 - arch/arm/configs/msm8953-perf_defconfig | 4 - arch/arm/configs/msm8953_defconfig | 4 - drivers/input/touchscreen/Kconfig | 12 - drivers/input/touchscreen/Makefile | 3 +- .../hxchipset/HX83100_Amber_0901_030B.i | 0 .../input/touchscreen/hxchipset/HX_CRC_124.i | 0 .../input/touchscreen/hxchipset/HX_CRC_128.i | 0 .../input/touchscreen/hxchipset/HX_CRC_60.i | 0 .../input/touchscreen/hxchipset/HX_CRC_64.i | 0 drivers/input/touchscreen/hxchipset/Kconfig | 21 - drivers/input/touchscreen/hxchipset/Makefile | 3 - .../touchscreen/hxchipset/himax_common.c | 1936 -------------- .../touchscreen/hxchipset/himax_common.h | 395 --- .../input/touchscreen/hxchipset/himax_debug.c | 2329 ----------------- .../input/touchscreen/hxchipset/himax_debug.h | 181 -- .../input/touchscreen/hxchipset/himax_ic.c | 2118 --------------- .../input/touchscreen/hxchipset/himax_ic.h | 82 - .../touchscreen/hxchipset/himax_platform.c | 796 ------ .../touchscreen/hxchipset/himax_platform.h | 135 - 21 files changed, 1 insertion(+), 8041 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/himax.txt delete mode 100644 drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i delete mode 100644 drivers/input/touchscreen/hxchipset/HX_CRC_124.i delete mode 100644 drivers/input/touchscreen/hxchipset/HX_CRC_128.i delete mode 100644 drivers/input/touchscreen/hxchipset/HX_CRC_60.i delete mode 100644 drivers/input/touchscreen/hxchipset/HX_CRC_64.i delete mode 100644 drivers/input/touchscreen/hxchipset/Kconfig delete mode 100644 drivers/input/touchscreen/hxchipset/Makefile delete mode 100644 drivers/input/touchscreen/hxchipset/himax_common.c delete mode 100644 drivers/input/touchscreen/hxchipset/himax_common.h delete mode 100644 drivers/input/touchscreen/hxchipset/himax_debug.c delete mode 100644 drivers/input/touchscreen/hxchipset/himax_debug.h delete mode 100644 drivers/input/touchscreen/hxchipset/himax_ic.c delete mode 100644 drivers/input/touchscreen/hxchipset/himax_ic.h delete mode 100644 drivers/input/touchscreen/hxchipset/himax_platform.c delete mode 100644 drivers/input/touchscreen/hxchipset/himax_platform.h diff --git a/Documentation/devicetree/bindings/input/touchscreen/himax.txt b/Documentation/devicetree/bindings/input/touchscreen/himax.txt deleted file mode 100644 index b54c85971927..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/himax.txt +++ /dev/null @@ -1,22 +0,0 @@ -Himax touch controller - -Required properties: - - - compatible : Should be "himax,hxcommon" - - reg : i2c slave address of the device. - - interrupt-parent : parent of interrupt. - - himax,irq-gpio : irq gpio. - - himax,reset-gpio : reset gpio. - - vdd-supply : Power supply needed to power up the device. - - avdd-supply : Power source required to power up i2c bus. - - himax,panel-coords : panel coordinates for the chip in pixels. - It is a four tuple consisting of min x, - min y, max x and max y values. - - himax,display-coords : display coordinates in pixels. It is a four - tuple consisting of min x, min y, max x and - max y values - -Optional properties: - - himax,3v3-gpio : gpio acting as 3.3 v supply. - - report_type : Multi-touch protocol type. Default 0. - 0 for protocol A, 1 for protocol B. diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index a22edb520505..559d0909076e 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -123,7 +123,6 @@ halo Halo Microelectronics Co., Ltd. hannstar HannStar Display Corporation haoyu Haoyu Microelectronic Co. Ltd. hardkernel Hardkernel Co., Ltd -himax Himax Technologies, Inc. hisilicon Hisilicon Limited. hit Hitachi Ltd. hitex Hitex Development Tools diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig index fca07a10e3ba..dab1a183c731 100644 --- a/arch/arm/configs/msm8953-perf_defconfig +++ b/arch/arm/configs/msm8953-perf_defconfig @@ -310,10 +310,6 @@ CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_FT5X06=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y -CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y -CONFIG_TOUCHSCREEN_HIMAX_I2C=y -CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y -CONFIG_HMX_DB=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig index 690faf2296f0..abe1d7786664 100644 --- a/arch/arm/configs/msm8953_defconfig +++ b/arch/arm/configs/msm8953_defconfig @@ -315,10 +315,6 @@ CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_FT5X06=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y -CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y -CONFIG_TOUCHSCREEN_HIMAX_I2C=y -CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y -CONFIG_HMX_DB=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index e9c1d696f8f4..d9b612dc727f 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1291,16 +1291,4 @@ config TOUCHSCREEN_GT9XX_v28 source "drivers/input/touchscreen/gt9xx_v2.8/Kconfig" -config TOUCHSCREEN_HIMAX_CHIPSET - bool "Himax touchpanel CHIPSET" - depends on I2C - help - Say Y here if you have a Himax CHIPSET touchscreen. - HIMAX controllers are multi touch controllers which can - report 10 touches at a time. - - If unsure, say N. - -source "drivers/input/touchscreen/hxchipset/Kconfig" - endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index c8e01040bf19..1f2faf98eb9b 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -104,5 +104,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_FTS) += focaltech_touch/ -obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET) += hxchipset/ -obj-$(CONFIG_TOUCHSCREEN_GT9XX_v28) += gt9xx_v2.8/ \ No newline at end of file +obj-$(CONFIG_TOUCHSCREEN_GT9XX_v28) += gt9xx_v2.8/ diff --git a/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i b/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_124.i b/drivers/input/touchscreen/hxchipset/HX_CRC_124.i deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_128.i b/drivers/input/touchscreen/hxchipset/HX_CRC_128.i deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_60.i b/drivers/input/touchscreen/hxchipset/HX_CRC_60.i deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_64.i b/drivers/input/touchscreen/hxchipset/HX_CRC_64.i deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/drivers/input/touchscreen/hxchipset/Kconfig b/drivers/input/touchscreen/hxchipset/Kconfig deleted file mode 100644 index ebf3aa478af5..000000000000 --- a/drivers/input/touchscreen/hxchipset/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -# -# Himax Touchscreen driver configuration -# - -config TOUCHSCREEN_HIMAX_I2C - tristate "HIMAX chipset i2c touchscreen" - depends on TOUCHSCREEN_HIMAX_CHIPSET - help - This enables support for HIMAX CHIPSET over I2C based touchscreens. - -config TOUCHSCREEN_HIMAX_DEBUG - tristate "HIMAX debug function" - depends on TOUCHSCREEN_HIMAX_I2C - help - This enables support for HIMAX debug function. - -config HMX_DB - tristate "HIMAX driver test over Dragon Board" - depends on TOUCHSCREEN_HIMAX_I2C - help - This enables support for HIMAX driver test over Dragon Board. diff --git a/drivers/input/touchscreen/hxchipset/Makefile b/drivers/input/touchscreen/hxchipset/Makefile deleted file mode 100644 index 509d4913bc39..000000000000 --- a/drivers/input/touchscreen/hxchipset/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# Makefile for the Himax touchscreen drivers. - -obj-$(CONFIG_TOUCHSCREEN_HIMAX_I2C) += himax_platform.o himax_ic.o himax_common.o himax_debug.o diff --git a/drivers/input/touchscreen/hxchipset/himax_common.c b/drivers/input/touchscreen/hxchipset/himax_common.c deleted file mode 100644 index 417b0c08e361..000000000000 --- a/drivers/input/touchscreen/hxchipset/himax_common.c +++ /dev/null @@ -1,1936 +0,0 @@ -/* Himax Android Driver Sample Code for Himax chipset -* -* Copyright (C) 2015 Himax Corporation. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#include "himax_common.h" -#include "himax_ic.h" - -#define SUPPORT_FINGER_DATA_CHECKSUM 0x0F -#define TS_WAKE_LOCK_TIMEOUT (2 * HZ) -#define FRAME_COUNT 5 - -#if defined(HX_AUTO_UPDATE_FW) - static unsigned char i_CTPM_FW[]= - { - #include "HX83100_Amber_0901_030B.i" - }; -#endif - -#ifdef HX_ESD_WORKAROUND - extern void HX_report_ESD_event(void); - unsigned char ESD_00_counter = 0; - unsigned char ESD_00_Flag = 0; -#endif - -//static int tpd_keys_local[HX_KEY_MAX_COUNT] = HX_KEY_ARRAY; // for Virtual key array - -struct himax_ts_data *private_ts; -struct himax_ic_data* ic_data; - -static int HX_TOUCH_INFO_POINT_CNT; - -#ifdef HX_AUTO_UPDATE_FW -extern unsigned long FW_VER_MAJ_FLASH_ADDR; -extern unsigned long FW_VER_MIN_FLASH_ADDR; -extern unsigned long CFG_VER_MAJ_FLASH_ADDR; -extern unsigned long CFG_VER_MIN_FLASH_ADDR; -#endif -extern unsigned long FW_VER_MAJ_FLASH_LENG; -extern unsigned long FW_VER_MIN_FLASH_LENG; -extern unsigned long CFG_VER_MAJ_FLASH_LENG; -extern unsigned long CFG_VER_MIN_FLASH_LENG; -extern unsigned char IC_TYPE; -extern unsigned char IC_CHECKSUM; - -#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) -extern int himax_touch_proc_init(void); -extern void himax_touch_proc_deinit(void); -//PROC-START -#ifdef HX_TP_PROC_FLASH_DUMP -extern void himax_ts_flash_func(void); -extern void setFlashBuffer(void); -extern bool getFlashDumpGoing(void); -extern uint8_t getSysOperation(void); -extern void setSysOperation(uint8_t operation); -#endif - -#ifdef HX_TP_PROC_HITOUCH -extern bool hitouch_is_connect; -#endif - -#ifdef HX_TP_PROC_DIAG - extern int touch_monitor_stop_flag; - extern int touch_monitor_stop_limit; - extern void himax_ts_diag_func(void); - extern int16_t *getMutualBuffer(void); - extern int16_t *getMutualNewBuffer(void); - extern int16_t *getMutualOldBuffer(void); - extern int16_t *getSelfBuffer(void); - extern uint8_t getXChannel(void); - extern uint8_t getYChannel(void); - extern uint8_t getDiagCommand(void); - extern void setXChannel(uint8_t x); - extern void setYChannel(uint8_t y); - extern void setMutualBuffer(void); - extern void setMutualNewBuffer(void); - extern void setMutualOldBuffer(void); - extern uint8_t coordinate_dump_enable; - extern struct file *coordinate_fn; - extern uint8_t diag_coor[128]; -#ifdef HX_TP_PROC_2T2R - extern int16_t *getMutualBuffer_2(void); - extern uint8_t getXChannel_2(void); - extern uint8_t getYChannel_2(void); - extern void setXChannel_2(uint8_t x); - extern void setYChannel_2(uint8_t y); - extern void setMutualBuffer_2(void); -#endif -#endif -//PROC-END -#endif - -extern int himax_parse_dt(struct himax_ts_data *ts, - struct himax_i2c_platform_data *pdata); -extern int himax_ts_pinctrl_init(struct himax_ts_data *ts); - -static uint8_t vk_press; -static uint8_t AA_press; -static uint8_t EN_NoiseFilter; -static uint8_t Last_EN_NoiseFilter; -static int hx_point_num; // for himax_ts_work_func use -static int p_point_num = 0xFFFF; -static int tpd_key; -static int tpd_key_old; -static int probe_fail_flag; -static bool config_load; -static struct himax_config *config_selected; - -//static int iref_number = 11; -//static bool iref_found = false; - -#ifdef HX_USB_DETECT2 -extern bool USB_Flag; -#endif - -#if defined(CONFIG_FB) -int fb_notifier_callback(struct notifier_block *self, - unsigned long event, void *data); -#elif defined(CONFIG_HAS_EARLYSUSPEND) -static void himax_ts_early_suspend(struct early_suspend *h); -static void himax_ts_late_resume(struct early_suspend *h); -#endif - -int himax_input_register(struct himax_ts_data *ts) -{ - int ret; - ts->input_dev = input_allocate_device(); - if (ts->input_dev == NULL) { - ret = -ENOMEM; - E("%s: Failed to allocate input device\n", __func__); - return ret; - } - ts->input_dev->name = "himax-touchscreen"; - - set_bit(EV_SYN, ts->input_dev->evbit); - set_bit(EV_ABS, ts->input_dev->evbit); - set_bit(EV_KEY, ts->input_dev->evbit); - - set_bit(KEY_BACK, ts->input_dev->keybit); - set_bit(KEY_HOME, ts->input_dev->keybit); - set_bit(KEY_MENU, ts->input_dev->keybit); - set_bit(KEY_SEARCH, ts->input_dev->keybit); -#if defined(HX_SMART_WAKEUP) - set_bit(KEY_POWER, ts->input_dev->keybit); - set_bit(KEY_CUST_01, ts->input_dev->keybit); - set_bit(KEY_CUST_02, ts->input_dev->keybit); - set_bit(KEY_CUST_03, ts->input_dev->keybit); - set_bit(KEY_CUST_04, ts->input_dev->keybit); - set_bit(KEY_CUST_05, ts->input_dev->keybit); - set_bit(KEY_CUST_06, ts->input_dev->keybit); - set_bit(KEY_CUST_07, ts->input_dev->keybit); - set_bit(KEY_CUST_08, ts->input_dev->keybit); - set_bit(KEY_CUST_09, ts->input_dev->keybit); - set_bit(KEY_CUST_10, ts->input_dev->keybit); - set_bit(KEY_CUST_11, ts->input_dev->keybit); - set_bit(KEY_CUST_12, ts->input_dev->keybit); - set_bit(KEY_CUST_13, ts->input_dev->keybit); - set_bit(KEY_CUST_14, ts->input_dev->keybit); - set_bit(KEY_CUST_15, ts->input_dev->keybit); -#endif - set_bit(BTN_TOUCH, ts->input_dev->keybit); - - set_bit(KEY_F10, ts->input_dev->keybit); - - set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); - - if (ts->protocol_type == PROTOCOL_TYPE_A) { - //ts->input_dev->mtsize = ts->nFinger_support; - input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, - 0, 3, 0, 0); - } else {/* PROTOCOL_TYPE_B */ - set_bit(MT_TOOL_FINGER, ts->input_dev->keybit); - input_mt_init_slots(ts->input_dev, ts->nFinger_support,0); - } - - I("input_set_abs_params: mix_x %d, max_x %d, min_y %d, max_y %d\n", - ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); - - input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_x_fuzz, 0); - input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,ts->pdata->abs_y_min, ts->pdata->abs_y_max, ts->pdata->abs_y_fuzz, 0); - input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0); - input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE,ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0); - input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR,ts->pdata->abs_width_min, ts->pdata->abs_width_max, ts->pdata->abs_pressure_fuzz, 0); - -// input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE, 0, ((ts->pdata->abs_pressure_max << 16) | ts->pdata->abs_width_max), 0, 0); -// input_set_abs_params(ts->input_dev, ABS_MT_POSITION, 0, (BIT(31) | (ts->pdata->abs_x_max << 16) | ts->pdata->abs_y_max), 0, 0); - - return input_register_device(ts->input_dev); -} - -static void calcDataSize(uint8_t finger_num) -{ - struct himax_ts_data *ts_data = private_ts; - ts_data->coord_data_size = 4 * finger_num; - ts_data->area_data_size = ((finger_num / 4) + (finger_num % 4 ? 1 : 0)) * 4; - ts_data->raw_data_frame_size = 128 - ts_data->coord_data_size - ts_data->area_data_size - 4 - 4 - 1; - ts_data->raw_data_nframes = ((uint32_t)ts_data->x_channel * ts_data->y_channel + - ts_data->x_channel + ts_data->y_channel) / ts_data->raw_data_frame_size + - (((uint32_t)ts_data->x_channel * ts_data->y_channel + - ts_data->x_channel + ts_data->y_channel) % ts_data->raw_data_frame_size)? 1 : 0; - I("%s: coord_data_size: %d, area_data_size:%d, raw_data_frame_size:%d, raw_data_nframes:%d", __func__, ts_data->coord_data_size, ts_data->area_data_size, ts_data->raw_data_frame_size, ts_data->raw_data_nframes); -} - -static void calculate_point_number(void) -{ - HX_TOUCH_INFO_POINT_CNT = ic_data->HX_MAX_PT * 4 ; - - if ( (ic_data->HX_MAX_PT % 4) == 0) - HX_TOUCH_INFO_POINT_CNT += (ic_data->HX_MAX_PT / 4) * 4 ; - else - HX_TOUCH_INFO_POINT_CNT += ((ic_data->HX_MAX_PT / 4) +1) * 4 ; -} - -#if 0 -static int himax_read_Sensor_ID(struct i2c_client *client) -{ - uint8_t val_high[1], val_low[1], ID0=0, ID1=0; - char data[3]; - const int normalRetry = 10; - int sensor_id; - - data[0] = 0x56; data[1] = 0x02; data[2] = 0x02;/*ID pin PULL High*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); - - //read id pin high - i2c_himax_read(client, 0x57, val_high, 1, normalRetry); - - data[0] = 0x56; data[1] = 0x01; data[2] = 0x01;/*ID pin PULL Low*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); - - //read id pin low - i2c_himax_read(client, 0x57, val_low, 1, normalRetry); - - if((val_high[0] & 0x01) ==0) - ID0=0x02;/*GND*/ - else if((val_low[0] & 0x01) ==0) - ID0=0x01;/*Floating*/ - else - ID0=0x04;/*VCC*/ - - if((val_high[0] & 0x02) ==0) - ID1=0x02;/*GND*/ - else if((val_low[0] & 0x02) ==0) - ID1=0x01;/*Floating*/ - else - ID1=0x04;/*VCC*/ - if((ID0==0x04)&&(ID1!=0x04)) - { - data[0] = 0x56; data[1] = 0x02; data[2] = 0x01;/*ID pin PULL High,Low*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); - - } - else if((ID0!=0x04)&&(ID1==0x04)) - { - data[0] = 0x56; data[1] = 0x01; data[2] = 0x02;/*ID pin PULL Low,High*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); - - } - else if((ID0==0x04)&&(ID1==0x04)) - { - data[0] = 0x56; data[1] = 0x02; data[2] = 0x02;/*ID pin PULL High,High*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); - - } - sensor_id=(ID1<<4)|ID0; - - data[0] = 0xE4; data[1] = sensor_id; - i2c_himax_master_write(client, &data[0],2,normalRetry);/*Write to MCU*/ - usleep_range(1000, 2000); - - return sensor_id; - -} -#endif -static void himax_power_on_initCMD(struct i2c_client *client) -{ - I("%s:\n", __func__); - - himax_touch_information(client); - - //himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM -} - -#ifdef HX_AUTO_UPDATE_FW -static int i_update_FW(void) -{ - int upgrade_times = 0; - unsigned char* ImageBuffer = i_CTPM_FW; - int fullFileLength = sizeof(i_CTPM_FW); - int i_FW_VER = 0, i_CFG_VER = 0; - uint8_t ret = -1, result = 0; -// uint8_t tmp_addr[4]; -// uint8_t tmp_data[4]; - int CRC_from_FW = 0; - int CRC_Check_result = 0; - - i_FW_VER = i_CTPM_FW[FW_VER_MAJ_FLASH_ADDR]<<8 |i_CTPM_FW[FW_VER_MIN_FLASH_ADDR]; - i_CFG_VER = i_CTPM_FW[CFG_VER_MAJ_FLASH_ADDR]<<8 |i_CTPM_FW[CFG_VER_MIN_FLASH_ADDR]; - - I("%s: i_fullFileLength = %d\n", __func__,fullFileLength); - - himax_sense_off(private_ts->client); - msleep(500); - - CRC_from_FW = himax_check_CRC(private_ts->client,fw_image_64k); - CRC_Check_result = Calculate_CRC_with_AP(ImageBuffer, CRC_from_FW,fw_image_64k); - I("%s: Check sum result = %d\n", __func__,CRC_Check_result); - //I("%s: ic_data->vendor_fw_ver = %X, i_FW_VER = %X,\n", __func__,ic_data->vendor_fw_ver, i_FW_VER); - //I("%s: ic_data->vendor_config_ver = %X, i_CFG_VER = %X,\n", __func__,ic_data->vendor_config_ver, i_CFG_VER); - - if ((CRC_Check_result == 0)|| ( ic_data->vendor_fw_ver < i_FW_VER ) || ( ic_data->vendor_config_ver < i_CFG_VER )) - { - himax_int_enable(private_ts->client->irq,0); -update_retry: - if(fullFileLength == FW_SIZE_60k){ - ret = fts_ctpm_fw_upgrade_with_sys_fs_60k(private_ts->client,ImageBuffer,fullFileLength,false); - }else if (fullFileLength == FW_SIZE_64k){ - ret = fts_ctpm_fw_upgrade_with_sys_fs_64k(private_ts->client,ImageBuffer,fullFileLength,false); - }else if (fullFileLength == FW_SIZE_124k){ - ret = fts_ctpm_fw_upgrade_with_sys_fs_124k(private_ts->client,ImageBuffer,fullFileLength,false); - }else if (fullFileLength == FW_SIZE_128k){ - ret = fts_ctpm_fw_upgrade_with_sys_fs_128k(private_ts->client,ImageBuffer,fullFileLength,false); - } - if(ret == 0){ - upgrade_times++; - E("%s: TP upgrade error, upgrade_times = %d\n", __func__, upgrade_times); - if(upgrade_times < 3) - goto update_retry; - else - { - himax_sense_on(private_ts->client, 0x01); - msleep(120); -#ifdef HX_ESD_WORKAROUND - HX_ESD_RESET_ACTIVATE = 1; -#endif - result = -1;//upgrade fail - } - } - else if(ret == 1){ -/* - // 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver) - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; - himax_register_write(private_ts->client, tmp_addr, 1, tmp_data); - - // 2. Write driver initial code condition - // write value from AHB I2C : 0x8001_C603 = 0x000000FF - tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xC6; tmp_addr[0] = 0x03; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xFF; - himax_register_write(private_ts->client, tmp_addr, 1, tmp_data); - - // 1. Set DDREG_Req = 0 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver) - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_register_write(private_ts->client, tmp_addr, 1, tmp_data); -*/ - himax_sense_on(private_ts->client, 0x01); - msleep(120); -#ifdef HX_ESD_WORKAROUND - HX_ESD_RESET_ACTIVATE = 1; -#endif - - ic_data->vendor_fw_ver = i_FW_VER; - ic_data->vendor_config_ver = i_CFG_VER; - result = 1;//upgrade success - I("%s: TP upgrade OK\n", __func__); - } - - himax_int_enable(private_ts->client->irq,1); - return result; - } - else - { - himax_sense_on(private_ts->client, 0x01); - return 0;//NO upgrade - } -} -#endif - -#ifdef HX_RST_PIN_FUNC -void himax_HW_reset(uint8_t loadconfig,uint8_t int_off) -{ - struct himax_ts_data *ts = private_ts; - int ret = 0; - - return; - if (ts->rst_gpio) { - if(int_off) - { - if (ts->use_irq) - himax_int_enable(private_ts->client->irq,0); - else { - hrtimer_cancel(&ts->timer); - ret = cancel_work_sync(&ts->work); - } - } - - I("%s: Now reset the Touch chip.\n", __func__); - - himax_rst_gpio_set(ts->rst_gpio, 0); - msleep(20); - himax_rst_gpio_set(ts->rst_gpio, 1); - msleep(20); - - if(loadconfig) - himax_loadSensorConfig(private_ts->client,private_ts->pdata); - - if(int_off) - { - if (ts->use_irq) - himax_int_enable(private_ts->client->irq,1); - else - hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); - } - } -} -#endif - -int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_data *pdata) -{ - - if (!client) { - E("%s: Necessary parameters client are null!\n", __func__); - return -EINVAL; - } - - if(config_load == false) - { - config_selected = kzalloc(sizeof(*config_selected), GFP_KERNEL); - if (config_selected == NULL) { - E("%s: alloc config_selected fail!\n", __func__); - return -ENOMEM; - } - } - - himax_power_on_initCMD(client); - - himax_int_enable(client->irq,0); - himax_read_FW_ver(client); -#ifdef HX_RST_PIN_FUNC - himax_HW_reset(true,false); -#endif - himax_int_enable(client->irq,1); - I("FW_VER : %X \n",ic_data->vendor_fw_ver); - - ic_data->vendor_sensor_id=0x2602; - I("sensor_id=%x.\n",ic_data->vendor_sensor_id); - - himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM - msleep(120); -#ifdef HX_ESD_WORKAROUND - HX_ESD_RESET_ACTIVATE = 1; -#endif - I("%s: initialization complete\n", __func__); - - return 1; -} - -#ifdef HX_ESD_WORKAROUND -void ESD_HW_REST(void) -{ - I("START_Himax TP: ESD - Reset\n"); - - HX_report_ESD_event(); - ESD_00_counter = 0; - ESD_00_Flag = 0; - /*************************************/ - if (private_ts->protocol_type == PROTOCOL_TYPE_A) - input_mt_sync(private_ts->input_dev); - input_report_key(private_ts->input_dev, BTN_TOUCH, 0); - input_sync(private_ts->input_dev); - /*************************************/ - - I("END_Himax TP: ESD - Reset\n"); -} -#endif -#ifdef HX_HIGH_SENSE -void himax_set_HSEN_func(struct i2c_client *client,uint8_t HSEN_enable) -{ - uint8_t tmp_data[4]; - - if(HSEN_enable) - { - I(" %s in", __func__); - HSEN_bit_retry: - himax_set_HSEN_enable(client,HSEN_enable); - msleep(20); - himax_get_HSEN_enable(client,tmp_data); - I("%s: Read HSEN bit data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); - if(tmp_data[0]!= 0x01) - { - I("%s: retry HSEN bit write data[0]=%x \n",__func__,tmp_data[0]); - goto HSEN_bit_retry; - } - } -} - -static void himax_HSEN_func(struct work_struct *work) -{ - struct himax_ts_data *ts = container_of(work, struct himax_ts_data, - hsen_work.work); - - himax_set_HSEN_func(ts->client, ts->HSEN_enable); -} - -#endif - -#ifdef HX_SMART_WAKEUP -#ifdef HX_GESTURE_TRACK -static void gest_pt_log_coordinate(int rx, int tx) -{ - //driver report x y with range 0 - 255 , we scale it up to x/y pixel - gest_pt_x[gest_pt_cnt] = rx*(ic_data->HX_X_RES)/255; - gest_pt_y[gest_pt_cnt] = tx*(ic_data->HX_Y_RES)/255; -} -#endif -static int himax_parse_wake_event(struct himax_ts_data *ts) -{ - uint8_t buf[64]; - unsigned char check_sum_cal = 0; -#ifdef HX_GESTURE_TRACK - int tmp_max_x=0x00,tmp_min_x=0xFFFF,tmp_max_y=0x00,tmp_min_y=0xFFFF; - int gest_len; -#endif - int i=0, check_FC = 0, gesture_flag = 0; - - himax_burst_enable(ts->client, 0); - himax_read_event_stack(ts->client,buf,56); - - for(i=0;igest_pt_x[i]) - tmp_min_x=gest_pt_x[i]; - if(tmp_max_ygest_pt_y[i]) - tmp_min_y=gest_pt_y[i]; - } - I("gest_point x_min= %d, x_max= %d, y_min= %d, y_max= %d\n",tmp_min_x,tmp_max_x,tmp_min_y,tmp_max_y); - gest_start_x=gest_pt_x[0]; - gn_gesture_coor[0] = gest_start_x; - gest_start_y=gest_pt_y[0]; - gn_gesture_coor[1] = gest_start_y; - gest_end_x=gest_pt_x[gest_pt_cnt-1]; - gn_gesture_coor[2] = gest_end_x; - gest_end_y=gest_pt_y[gest_pt_cnt-1]; - gn_gesture_coor[3] = gest_end_y; - gest_width = tmp_max_x - tmp_min_x; - gn_gesture_coor[4] = gest_width; - gest_height = tmp_max_y - tmp_min_y; - gn_gesture_coor[5] = gest_height; - gest_mid_x = (tmp_max_x + tmp_min_x)/2; - gn_gesture_coor[6] = gest_mid_x; - gest_mid_y = (tmp_max_y + tmp_min_y)/2; - gn_gesture_coor[7] = gest_mid_y; - gn_gesture_coor[8] = gest_mid_x;//gest_up_x - gn_gesture_coor[9] = gest_mid_y-gest_height/2;//gest_up_y - gn_gesture_coor[10] = gest_mid_x;//gest_down_x - gn_gesture_coor[11] = gest_mid_y+gest_height/2; //gest_down_y - gn_gesture_coor[12] = gest_mid_x-gest_width/2; //gest_left_x - gn_gesture_coor[13] = gest_mid_y; //gest_left_y - gn_gesture_coor[14] = gest_mid_x+gest_width/2; //gest_right_x - gn_gesture_coor[15] = gest_mid_y; //gest_right_y - - } - - } -#endif - if(gesture_flag != 0x80) - { - if(!ts->gesture_cust_en[gesture_flag]) - { - I("%s NOT report customer key \n ",__func__); - return 0;//NOT report customer key - } - } - else - { - if(!ts->gesture_cust_en[0]) - { - I("%s NOT report report double click \n",__func__); - return 0;//NOT report power key - } - } - - if(gesture_flag == 0x80) - return EV_GESTURE_PWR; - else - return gesture_flag; -} - -void himax_wake_check_func(void) -{ - int ret_event = 0, KEY_EVENT = 0; - - ret_event = himax_parse_wake_event(private_ts); - switch (ret_event) { - case EV_GESTURE_PWR: - KEY_EVENT = KEY_POWER; - break; - case EV_GESTURE_01: - KEY_EVENT = KEY_CUST_01; - break; - case EV_GESTURE_02: - KEY_EVENT = KEY_CUST_02; - break; - case EV_GESTURE_03: - KEY_EVENT = KEY_CUST_03; - break; - case EV_GESTURE_04: - KEY_EVENT = KEY_CUST_04; - break; - case EV_GESTURE_05: - KEY_EVENT = KEY_CUST_05; - break; - case EV_GESTURE_06: - KEY_EVENT = KEY_CUST_06; - break; - case EV_GESTURE_07: - KEY_EVENT = KEY_CUST_07; - break; - case EV_GESTURE_08: - KEY_EVENT = KEY_CUST_08; - break; - case EV_GESTURE_09: - KEY_EVENT = KEY_CUST_09; - break; - case EV_GESTURE_10: - KEY_EVENT = KEY_CUST_10; - break; - case EV_GESTURE_11: - KEY_EVENT = KEY_CUST_11; - break; - case EV_GESTURE_12: - KEY_EVENT = KEY_CUST_12; - break; - case EV_GESTURE_13: - KEY_EVENT = KEY_CUST_13; - break; - case EV_GESTURE_14: - KEY_EVENT = KEY_CUST_14; - break; - case EV_GESTURE_15: - KEY_EVENT = KEY_CUST_15; - break; - } - if(ret_event) - { - I(" %s SMART WAKEUP KEY event %x press\n",__func__,KEY_EVENT); - input_report_key(private_ts->input_dev, KEY_EVENT, 1); - input_sync(private_ts->input_dev); - //msleep(100); - I(" %s SMART WAKEUP KEY event %x release\n",__func__,KEY_EVENT); - input_report_key(private_ts->input_dev, KEY_EVENT, 0); - input_sync(private_ts->input_dev); - FAKE_POWER_KEY_SEND=true; -#ifdef HX_GESTURE_TRACK - I("gest_start_x= %d, gest_start_y= %d, gest_end_x= %d, gest_end_y= %d\n",gest_start_x,gest_start_y, - gest_end_x,gest_end_y); - I("gest_width= %d, gest_height= %d, gest_mid_x= %d, gest_mid_y= %d\n",gest_width,gest_height, - gest_mid_x,gest_mid_y); - I("gest_up_x= %d, gest_up_y= %d, gest_down_x= %d, gest_down_y= %d\n",gn_gesture_coor[8],gn_gesture_coor[9], - gn_gesture_coor[10],gn_gesture_coor[11]); - I("gest_left_x= %d, gest_left_y= %d, gest_right_x= %d, gest_right_y= %d\n",gn_gesture_coor[12],gn_gesture_coor[13], - gn_gesture_coor[14],gn_gesture_coor[15]); -#endif - } -} - -#endif -static void himax_ts_button_func(int tp_key_index,struct himax_ts_data *ts) -{ - uint16_t x_position = 0, y_position = 0; -if ( tp_key_index != 0x00) - { - I("virtual key index =%x\n",tp_key_index); - if ( tp_key_index == 0x01) { - vk_press = 1; - I("back key pressed\n"); - if (ts->pdata->virtual_key) - { - if (ts->button[0].index) { - x_position = (ts->button[0].x_range_min + ts->button[0].x_range_max) / 2; - y_position = (ts->button[0].y_range_min + ts->button[0].y_range_max) / 2; - } - if (ts->protocol_type == PROTOCOL_TYPE_A) { - input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - input_mt_sync(ts->input_dev); - } else if (ts->protocol_type == PROTOCOL_TYPE_B) { - input_mt_slot(ts->input_dev, 0); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, - 1); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - } - } - else - input_report_key(ts->input_dev, KEY_BACK, 1); - } - else if ( tp_key_index == 0x02) { - vk_press = 1; - I("home key pressed\n"); - if (ts->pdata->virtual_key) - { - if (ts->button[1].index) { - x_position = (ts->button[1].x_range_min + ts->button[1].x_range_max) / 2; - y_position = (ts->button[1].y_range_min + ts->button[1].y_range_max) / 2; - } - if (ts->protocol_type == PROTOCOL_TYPE_A) { - input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - input_mt_sync(ts->input_dev); - } else if (ts->protocol_type == PROTOCOL_TYPE_B) { - input_mt_slot(ts->input_dev, 0); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, - 1); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - } - } - else - input_report_key(ts->input_dev, KEY_HOME, 1); - } - else if ( tp_key_index == 0x04) { - vk_press = 1; - I("APP_switch key pressed\n"); - if (ts->pdata->virtual_key) - { - if (ts->button[2].index) { - x_position = (ts->button[2].x_range_min + ts->button[2].x_range_max) / 2; - y_position = (ts->button[2].y_range_min + ts->button[2].y_range_max) / 2; - } - if (ts->protocol_type == PROTOCOL_TYPE_A) { - input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - input_mt_sync(ts->input_dev); - } else if (ts->protocol_type == PROTOCOL_TYPE_B) { - input_mt_slot(ts->input_dev, 0); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, - 1); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - } - } - else - input_report_key(ts->input_dev, KEY_F10, 1); - } - input_sync(ts->input_dev); - } -else/*tp_key_index =0x00*/ - { - I("virtual key released\n"); - vk_press = 0; - if (ts->protocol_type == PROTOCOL_TYPE_A) { - input_mt_sync(ts->input_dev); - } - else if (ts->protocol_type == PROTOCOL_TYPE_B) { - input_mt_slot(ts->input_dev, 0); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); - } - input_report_key(ts->input_dev, KEY_BACK, 0); - input_report_key(ts->input_dev, KEY_HOME, 0); - input_report_key(ts->input_dev, KEY_F10, 0); - input_sync(ts->input_dev); - } -} - -void himax_ts_work(struct himax_ts_data *ts) -{ - int ret = 0; - uint8_t finger_num, hw_reset_check[2]; - uint8_t buf[128]; - uint8_t finger_on = 0; - int32_t loop_i; - uint16_t check_sum_cal = 0; - int raw_cnt_max ; - int raw_cnt_rmd ; - int hx_touch_info_size; - uint8_t coordInfoSize = ts->coord_data_size + ts->area_data_size + 4; - -#ifdef HX_TP_PROC_DIAG - int16_t *mutual_data; - int16_t *self_data; - uint8_t diag_cmd; - int i; - int mul_num; - int self_num; - int RawDataLen = 0; - //coordinate dump start - char coordinate_char[15+(ic_data->HX_MAX_PT+5)*2*5+2]; - //coordinate dump end -#endif - - memset(buf, 0x00, sizeof(buf)); - memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); - - raw_cnt_max = ic_data->HX_MAX_PT/4; - raw_cnt_rmd = ic_data->HX_MAX_PT%4; - -#if defined(HX_USB_DETECT2) - himax_cable_detect_func(); -#endif - - if (raw_cnt_rmd != 0x00) //more than 4 fingers - { - RawDataLen = cal_data_len(raw_cnt_rmd, ic_data->HX_MAX_PT, raw_cnt_max); - hx_touch_info_size = (ic_data->HX_MAX_PT+raw_cnt_max+2)*4; - } - else //less than 4 fingers - { - RawDataLen = cal_data_len(raw_cnt_rmd, ic_data->HX_MAX_PT, raw_cnt_max); - hx_touch_info_size = (ic_data->HX_MAX_PT+raw_cnt_max+1)*4; - } - -#ifdef HX_TP_PROC_DIAG - diag_cmd = getDiagCommand(); - if( diag_cmd ){ - ret = read_event_stack(ts->client, buf, 128); - } - else{ - if(touch_monitor_stop_flag != 0){ - ret = read_event_stack(ts->client, buf, 128); - touch_monitor_stop_flag-- ; - } - else{ - ret = read_event_stack(ts->client, buf, hx_touch_info_size); - } - } - - if (!ret) -#else - if(!read_event_stack(ts->client, buf, hx_touch_info_size)) -#endif - { - E("%s: can't read data from chip!\n", __func__); - goto err_workqueue_out; - } - post_read_event_stack(ts->client); -#ifdef HX_ESD_WORKAROUND - for(i = 0; i < hx_touch_info_size; i++) - { - if(buf[i] == 0xED)/*case 1 ESD recovery flow*/ - { - check_sum_cal = 1; - - }else if(buf[i] == 0x00) - { - ESD_00_Flag = 1; - } - else - { - check_sum_cal = 0; - ESD_00_counter = 0; - ESD_00_Flag = 0; - i = hx_touch_info_size; - break; - } - } - if (ESD_00_Flag == 1){ - ESD_00_counter ++; - } - if (ESD_00_counter > 1){ - check_sum_cal = 2; - } - - if (check_sum_cal == 2 && HX_ESD_RESET_ACTIVATE == 0) - { - I("[HIMAX TP MSG]: ESD event checked - ALL Zero.\n"); - ESD_HW_REST(); - return; - } - - if (check_sum_cal == 1 && HX_ESD_RESET_ACTIVATE == 0) - { - I("[HIMAX TP MSG]: ESD event checked - ALL 0xED.\n"); - ESD_HW_REST(); - return; - } - else if (HX_ESD_RESET_ACTIVATE) - { -#ifdef HX_SMART_WAKEUP - queue_delayed_work(ts->himax_smwp_wq, &ts->smwp_work, msecs_to_jiffies(50)); -#endif -#ifdef HX_HIGH_SENSE - queue_delayed_work(ts->himax_hsen_wq, &ts->hsen_work, msecs_to_jiffies(50)); -#endif - HX_ESD_RESET_ACTIVATE = 0;/*drop 1st interrupts after chip reset*/ - I("[HIMAX TP MSG]:%s: Back from reset, ready to serve.\n", __func__); - } -#endif - for (loop_i = 0, check_sum_cal = 0; loop_i < hx_touch_info_size; loop_i++) - check_sum_cal += buf[loop_i]; - - if ((check_sum_cal % 0x100 != 0) ) - { - I("[HIMAX TP MSG] checksum fail : check_sum_cal: 0x%02X\n", check_sum_cal); - return; - } - - if (ts->debug_log_level & BIT(0)) { - I("%s: raw data:\n", __func__); - for (loop_i = 0; loop_i < hx_touch_info_size; loop_i++) { - I("P %d = 0x%2.2X ", loop_i, buf[loop_i]); - if (loop_i % 8 == 7) - I("\n"); - } - } - - //touch monitor raw data fetch -#ifdef HX_TP_PROC_DIAG - diag_cmd = getDiagCommand(); - if (diag_cmd >= 1 && diag_cmd <= 6) - { - //Check 124th byte CRC - if(!diag_check_sum(hx_touch_info_size, buf)) - { - goto bypass_checksum_failed_packet; - } -#ifdef HX_TP_PROC_2T2R - if(Is_2T2R && diag_cmd == 4) - { - mutual_data = getMutualBuffer_2(); - self_data = getSelfBuffer(); - - // initiallize the block number of mutual and self - mul_num = getXChannel_2() * getYChannel_2(); - -#ifdef HX_EN_SEL_BUTTON - self_num = getXChannel_2() + getYChannel_2() + ic_data->HX_BT_NUM; -#else - self_num = getXChannel_2() + getYChannel_2(); -#endif - } - else -#endif - { - mutual_data = getMutualBuffer(); - self_data = getSelfBuffer(); - - // initiallize the block number of mutual and self - mul_num = getXChannel() * getYChannel(); - -#ifdef HX_EN_SEL_BUTTON - self_num = getXChannel() + getYChannel() + ic_data->HX_BT_NUM; -#else - self_num = getXChannel() + getYChannel(); -#endif - } - - diag_parse_raw_data(hx_touch_info_size, RawDataLen, mul_num, self_num, buf, diag_cmd, mutual_data, self_data); - - } - else if (diag_cmd == 7) - { - memcpy(&(diag_coor[0]), &buf[0], 128); - } - //coordinate dump start - if (coordinate_dump_enable == 1) - { - for(i=0; i<(15 + (ic_data->HX_MAX_PT+5)*2*5); i++) - { - coordinate_char[i] = 0x20; - } - coordinate_char[15 + (ic_data->HX_MAX_PT+5)*2*5] = 0xD; - coordinate_char[15 + (ic_data->HX_MAX_PT+5)*2*5 + 1] = 0xA; - } - //coordinate dump end -bypass_checksum_failed_packet: -#endif - EN_NoiseFilter = (buf[HX_TOUCH_INFO_POINT_CNT+2]>>3); - //I("EN_NoiseFilter=%d\n",EN_NoiseFilter); - EN_NoiseFilter = EN_NoiseFilter & 0x01; - //I("EN_NoiseFilter2=%d\n",EN_NoiseFilter); - -#if defined(HX_EN_SEL_BUTTON) || defined(HX_EN_MUT_BUTTON) - tpd_key = (buf[HX_TOUCH_INFO_POINT_CNT+2]>>4); - if (tpd_key == 0x0F)/*All (VK+AA)leave*/ - { - tpd_key = 0x00; - } - //I("[DEBUG] tpd_key: %x\r\n", tpd_key); -#else - tpd_key = 0x00; -#endif - - p_point_num = hx_point_num; - - if (buf[HX_TOUCH_INFO_POINT_CNT] == 0xff) - hx_point_num = 0; - else - hx_point_num= buf[HX_TOUCH_INFO_POINT_CNT] & 0x0f; - - // Touch Point information - if (hx_point_num != 0 ) { - if(vk_press == 0x00) - { - uint16_t old_finger = ts->pre_finger_mask; - ts->pre_finger_mask = 0; - finger_num = buf[coordInfoSize - 4] & 0x0F; - finger_on = 1; - AA_press = 1; - for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { - int base = loop_i * 4; - int x = buf[base] << 8 | buf[base + 1]; - int y = (buf[base + 2] << 8 | buf[base + 3]); - int w = buf[(ts->nFinger_support * 4) + loop_i]; - if(x >= 0 && x <= ts->pdata->abs_x_max && y >= 0 && y <= ts->pdata->abs_y_max){ - finger_num--; - - if ((ts->debug_log_level & BIT(3)) > 0) - { - if (old_finger >> loop_i == 0) - { - if (ts->useScreenRes) - { - I("status: Screen:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n", - loop_i+1, x * ts->widthFactor >> SHIFTBITS, - y * ts->heightFactor >> SHIFTBITS, w, EN_NoiseFilter); - } - else - { - I("status: Raw:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n", - loop_i+1, x, y, w, EN_NoiseFilter); - } - } - } - - if (ts->protocol_type == PROTOCOL_TYPE_B) - { - input_mt_slot(ts->input_dev, loop_i); - } - - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, w); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y); - - if (ts->protocol_type == PROTOCOL_TYPE_A) - { - input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, loop_i); - input_mt_sync(ts->input_dev); - } - else - { - ts->last_slot = loop_i; - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1); - } - - if (!ts->first_pressed) - { - ts->first_pressed = 1; - I("S1@%d, %d\n", x, y); - } - - ts->pre_finger_data[loop_i][0] = x; - ts->pre_finger_data[loop_i][1] = y; - - - if (ts->debug_log_level & BIT(1)) - I("Finger %d=> X:%d, Y:%d W:%d, Z:%d, F:%d, N:%d\n", - loop_i + 1, x, y, w, w, loop_i + 1, EN_NoiseFilter); - - ts->pre_finger_mask = ts->pre_finger_mask + (1 << loop_i); - - } else { - if (ts->protocol_type == PROTOCOL_TYPE_B) - { - input_mt_slot(ts->input_dev, loop_i); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); - } - - if (loop_i == 0 && ts->first_pressed == 1) - { - ts->first_pressed = 2; - I("E1@%d, %d\n", - ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]); - } - if ((ts->debug_log_level & BIT(3)) > 0) - { - if (old_finger >> loop_i == 1) - { - if (ts->useScreenRes) - { - I("status: Screen:F:%02d Up, X:%d, Y:%d, N:%d\n", - loop_i+1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS, - ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter); - } - else - { - I("status: Raw:F:%02d Up, X:%d, Y:%d, N:%d\n", - loop_i+1, ts->pre_finger_data[loop_i][0], - ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter); - } - } - } - } - } - - }else if ((tpd_key_old != 0x00)&&(tpd_key == 0x00)) { - //temp_x[0] = 0xFFFF; - //temp_y[0] = 0xFFFF; - //temp_x[1] = 0xFFFF; - //temp_y[1] = 0xFFFF; - himax_ts_button_func(tpd_key,ts); - finger_on = 0; - } - input_report_key(ts->input_dev, BTN_TOUCH, finger_on); - input_sync(ts->input_dev); - } else if (hx_point_num == 0){ - if(AA_press) - { - // leave event - finger_on = 0; - AA_press = 0; - if (ts->protocol_type == PROTOCOL_TYPE_A) - input_mt_sync(ts->input_dev); - - for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { - if (((ts->pre_finger_mask >> loop_i) & 1) == 1) { - if (ts->protocol_type == PROTOCOL_TYPE_B) { - input_mt_slot(ts->input_dev, loop_i); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); - } - } - } - if (ts->pre_finger_mask > 0) { - for (loop_i = 0; loop_i < ts->nFinger_support && (ts->debug_log_level & BIT(3)) > 0; loop_i++) { - if (((ts->pre_finger_mask >> loop_i) & 1) == 1) { - if (ts->useScreenRes) { - I("status:%X, Screen:F:%02d Up, X:%d, Y:%d, N:%d\n", 0, loop_i+1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS, - ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter); - } else { - I("status:%X, Raw:F:%02d Up, X:%d, Y:%d, N:%d\n",0, loop_i+1, ts->pre_finger_data[loop_i][0],ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter); - } - } - } - ts->pre_finger_mask = 0; - } - - if (ts->first_pressed == 1) { - ts->first_pressed = 2; - I("E1@%d, %d\n",ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]); - } - - if (ts->debug_log_level & BIT(1)) - I("All Finger leave\n"); - - } - else if (tpd_key != 0x00) { - himax_ts_button_func(tpd_key,ts); - finger_on = 1; - } - else if ((tpd_key_old != 0x00)&&(tpd_key == 0x00)) { - himax_ts_button_func(tpd_key,ts); - finger_on = 0; - } - input_report_key(ts->input_dev, BTN_TOUCH, finger_on); - input_sync(ts->input_dev); - } - tpd_key_old = tpd_key; - Last_EN_NoiseFilter = EN_NoiseFilter; - -workqueue_out: - return; - -err_workqueue_out: - I("%s: Now reset the Touch chip.\n", __func__); - -#ifdef HX_RST_PIN_FUNC - himax_HW_reset(true,false); -#endif - - goto workqueue_out; -} -enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer) -{ - struct himax_ts_data *ts; - - ts = container_of(timer, struct himax_ts_data, timer); - queue_work(ts->himax_wq, &ts->work); - hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL); - return HRTIMER_NORESTART; -} - -#if defined(HX_USB_DETECT) -static void himax_cable_tp_status_handler_func(int connect_status) -{ - struct himax_ts_data *ts; - I("Touch: cable change to %d\n", connect_status); - ts = private_ts; - if (ts->cable_config) { - if (!atomic_read(&ts->suspend_mode)) { - if ((!!connect_status) != ts->usb_connected) { - if (!!connect_status) { - ts->cable_config[1] = 0x01; - ts->usb_connected = 0x01; - } else { - ts->cable_config[1] = 0x00; - ts->usb_connected = 0x00; - } - - i2c_himax_master_write(ts->client, ts->cable_config, - sizeof(ts->cable_config), HIMAX_I2C_RETRY_TIMES); - - I("%s: Cable status change: 0x%2.2X\n", __func__, ts->cable_config[1]); - } else - I("%s: Cable status is the same as previous one, ignore.\n", __func__); - } else { - if (connect_status) - ts->usb_connected = 0x01; - else - ts->usb_connected = 0x00; - I("%s: Cable status remembered: 0x%2.2X\n", __func__, ts->usb_connected); - } - } -} - -static struct t_cable_status_notifier himax_cable_status_handler = { - .name = "usb_tp_connected", - .func = himax_cable_tp_status_handler_func, -}; - -#endif - -#if defined(HX_USB_DETECT2) -void himax_cable_detect_func(void) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[128]; - struct himax_ts_data *ts; - u32 connect_status = 0; - - connect_status = USB_Flag;//upmu_is_chr_det(); - ts = private_ts; - //I("Touch: cable status=%d, cable_config=%p, usb_connected=%d \n", connect_status,ts->cable_config, ts->usb_connected); - if (ts->cable_config) { - if ((!!connect_status) != ts->usb_connected) { - //notify USB plug/unplug - // 0x9008_8060 ==> 0x0000_0000/0001 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x60; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; - - if (!!connect_status) { - tmp_data[0] = 0x01; - ts->usb_connected = 0x01; - } else { - tmp_data[0] = 0x00; - ts->usb_connected = 0x00; - } - - himax_flash_write_burst(ts->client, tmp_addr, tmp_data); - - I("%s: Cable status change: 0x%2.2X\n", __func__, ts->usb_connected); - } - //else - //I("%s: Cable status is the same as previous one, ignore.\n", __func__); - } -} -#endif - -#ifdef CONFIG_FB -int himax_fb_register(struct himax_ts_data *ts) -{ - int ret = 0; - - I(" %s in", __func__); - ts->fb_notif.notifier_call = fb_notifier_callback; - ret = fb_register_client(&ts->fb_notif); - if (ret) - E(" Unable to register fb_notifier: %d\n", ret); - - return ret; -} -#endif - -#ifdef HX_SMART_WAKEUP -void himax_set_SMWP_func(struct i2c_client *client,uint8_t SMWP_enable) -{ - uint8_t tmp_data[4]; - - if(SMWP_enable) - { - SMWP_bit_retry: - himax_set_SMWP_enable(client, SMWP_enable); - msleep(20); - himax_get_SMWP_enable(client,tmp_data); - I("%s: Read SMWP bit data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); - if(tmp_data[0]!= 0x01) - { - I("%s: retry SMWP bit write data[0]=%x \n",__func__,tmp_data[0]); - goto SMWP_bit_retry; - } - } -} - -static void himax_SMWP_work(struct work_struct *work) -{ - struct himax_ts_data *ts = container_of(work, struct himax_ts_data, - smwp_work.work); - I(" %s in", __func__); - - himax_set_SMWP_func(ts->client,ts->SMWP_enable); - -} -#endif - -#ifdef HX_TP_PROC_FLASH_DUMP -static void himax_ts_flash_work_func(struct work_struct *work) -{ - himax_ts_flash_func(); -} -#endif - -#ifdef HX_TP_PROC_DIAG -static void himax_ts_diag_work_func(struct work_struct *work) -{ - himax_ts_diag_func(); -} -#endif - -void himax_ts_init(struct himax_ts_data *ts) -{ - int ret = 0, err = 0; - struct himax_i2c_platform_data *pdata; - struct i2c_client *client; - - client = ts->client; - pdata = ts->pdata; - - I("%s: Start.\n", __func__); - - /* Set pinctrl in active state */ - if (ts->ts_pinctrl) { - ret = pinctrl_select_state(ts->ts_pinctrl, - ts->pinctrl_state_active); - if (ret < 0) { - E("Failed to set pin in active state %d",ret); - } - } - - himax_burst_enable(client, 0); - - //Get Himax IC Type / FW information / Calculate the point number - if (himax_check_chip_version(ts->client) == false) { - E("Himax chip doesn NOT EXIST"); - goto err_ic_package_failed; - } - if (himax_ic_package_check(ts->client) == false) { - E("Himax chip doesn NOT EXIST"); - goto err_ic_package_failed; - } - - if (pdata->virtual_key) - ts->button = pdata->virtual_key; -#ifdef HX_TP_PROC_FLASH_DUMP - ts->flash_wq = create_singlethread_workqueue("himax_flash_wq"); - if (!ts->flash_wq) - { - E("%s: create flash workqueue failed\n", __func__); - err = -ENOMEM; - goto err_create_wq_failed; - } - - INIT_WORK(&ts->flash_work, himax_ts_flash_work_func); - - setSysOperation(0); - setFlashBuffer(); -#endif - -#ifdef HX_TP_PROC_DIAG - ts->himax_diag_wq = create_singlethread_workqueue("himax_diag"); - if (!ts->himax_diag_wq) - { - E("%s: create diag workqueue failed\n", __func__); - err = -ENOMEM; - goto err_create_wq_failed; - } - INIT_DELAYED_WORK(&ts->himax_diag_delay_wrok, himax_ts_diag_work_func); -#endif - -himax_read_FW_ver(client); - -#ifdef HX_AUTO_UPDATE_FW - I(" %s in", __func__); - if(i_update_FW() == false) - I("NOT Have new FW=NOT UPDATE=\n"); - else - I("Have new FW=UPDATE=\n"); -#endif - - //Himax Power On and Load Config - if (himax_loadSensorConfig(client, pdata) < 0) { - E("%s: Load Sesnsor configuration failed, unload driver.\n", __func__); - goto err_detect_failed; - } - - calculate_point_number(); -#ifdef HX_TP_PROC_DIAG - setXChannel(ic_data->HX_RX_NUM); // X channel - setYChannel(ic_data->HX_TX_NUM); // Y channel - - setMutualBuffer(); - setMutualNewBuffer(); - setMutualOldBuffer(); - if (getMutualBuffer() == NULL) { - E("%s: mutual buffer allocate fail failed\n", __func__); - return; - } -#ifdef HX_TP_PROC_2T2R - if(Is_2T2R){ - setXChannel_2(ic_data->HX_RX_NUM_2); // X channel - setYChannel_2(ic_data->HX_TX_NUM_2); // Y channel - - setMutualBuffer_2(); - - if (getMutualBuffer_2() == NULL) { - E("%s: mutual buffer 2 allocate fail failed\n", __func__); - return; - } - } -#endif -#endif -#ifdef CONFIG_OF - ts->power = pdata->power; -#endif - ts->pdata = pdata; - - ts->x_channel = ic_data->HX_RX_NUM; - ts->y_channel = ic_data->HX_TX_NUM; - ts->nFinger_support = ic_data->HX_MAX_PT; - //calculate the i2c data size - calcDataSize(ts->nFinger_support); - I("%s: calcDataSize complete\n", __func__); -#ifdef CONFIG_OF - ts->pdata->abs_pressure_min = 0; - ts->pdata->abs_pressure_max = 200; - ts->pdata->abs_width_min = 0; - ts->pdata->abs_width_max = 200; - pdata->cable_config[0] = 0x90; - pdata->cable_config[1] = 0x00; -#endif - ts->suspended = false; -#if defined(HX_USB_DETECT)||defined(HX_USB_DETECT2) - ts->usb_connected = 0x00; - ts->cable_config = pdata->cable_config; -#endif - ts->protocol_type = pdata->protocol_type; - I("%s: Use Protocol Type %c\n", __func__, - ts->protocol_type == PROTOCOL_TYPE_A ? 'A' : 'B'); - - ret = himax_input_register(ts); - if (ret) { - E("%s: Unable to register %s input device\n", - __func__, ts->input_dev->name); - goto err_input_register_device_failed; - } -#ifdef HX_SMART_WAKEUP - ts->SMWP_enable=0; - wake_lock_init(&ts->ts_SMWP_wake_lock, WAKE_LOCK_SUSPEND, HIMAX_common_NAME); - - ts->himax_smwp_wq = create_singlethread_workqueue("HMX_SMWP_WORK"); - if (!ts->himax_smwp_wq) { - E(" allocate himax_smwp_wq failed\n"); - err = -ENOMEM; - goto err_smwp_wq_failed; - } - INIT_DELAYED_WORK(&ts->smwp_work, himax_SMWP_work); -#endif -#ifdef HX_HIGH_SENSE - ts->HSEN_enable=0; - ts->himax_hsen_wq = create_singlethread_workqueue("HMX_HSEN_WORK"); - if (!ts->himax_hsen_wq) { - E(" allocate himax_hsen_wq failed\n"); - err = -ENOMEM; - goto err_hsen_wq_failed; - } - INIT_DELAYED_WORK(&ts->hsen_work, himax_HSEN_func); -#endif - -#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) - himax_touch_proc_init(); -#endif - -#if defined(HX_USB_DETECT) - if (ts->cable_config) - cable_detect_register_notifier(&himax_cable_status_handler); -#endif - - err = himax_ts_register_interrupt(ts->client); - if (err) - goto err_register_interrupt_failed; - return; - -err_register_interrupt_failed: -#ifdef HX_HIGH_SENSE -err_hsen_wq_failed: -#endif -#ifdef HX_SMART_WAKEUP -err_smwp_wq_failed: - wake_lock_destroy(&ts->ts_SMWP_wake_lock); -#endif -err_input_register_device_failed: - input_free_device(ts->input_dev); -err_detect_failed: -#ifdef HX_TP_PROC_FLASH_DUMP -err_create_wq_failed: -#endif -err_ic_package_failed: - -return; -} - -int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - int err = 0; - struct himax_ts_data *ts; - struct himax_i2c_platform_data *pdata; - - //Check I2C functionality - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - E("%s: i2c check functionality error\n", __func__); - err = -ENODEV; - goto err_check_functionality_failed; - } - - ts = kzalloc(sizeof(struct himax_ts_data), GFP_KERNEL); - if (ts == NULL) { - E("%s: allocate himax_ts_data failed\n", __func__); - err = -ENOMEM; - goto err_alloc_data_failed; - } - - i2c_set_clientdata(client, ts); - ts->client = client; - ts->dev = &client->dev; - - pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); - if (pdata == NULL) { /*Allocate Platform data space*/ - err = -ENOMEM; - goto err_dt_platform_data_fail; - } - - ic_data = kzalloc(sizeof(*ic_data), GFP_KERNEL); - if (ic_data == NULL) { /*Allocate IC data space*/ - err = -ENOMEM; - goto err_dt_ic_data_fail; - } - -#ifdef CONFIG_OF - if (client->dev.of_node) { /*DeviceTree Init Platform_data*/ - err = himax_parse_dt(ts, pdata); - if (err < 0) { - I(" pdata is NULL for DT\n"); - goto err_alloc_dt_pdata_failed; - } - } -#endif - -#ifdef HX_RST_PIN_FUNC - ts->rst_gpio = pdata->gpio_reset; -#endif - -himax_gpio_power_config(ts->client, pdata); - - err = himax_ts_pinctrl_init(ts); - if (err || ts->ts_pinctrl == NULL) { - E(" Pinctrl init failed\n"); - } - -#ifndef CONFIG_OF - if (pdata->power) { - err = pdata->power(1); - if (err < 0) { - E("%s: power on failed\n", __func__); - goto err_power_failed; - } - } -#endif - ts->pdata = pdata; - private_ts = ts; - - mutex_init(&ts->fb_mutex); - /* ts initialization is deferred till FB_UNBLACK event; - * probe is considered pending till then.*/ - ts->probe_done = false; -#ifdef CONFIG_FB - err = himax_fb_register(ts); - if (err) { - E("Falied to register fb notifier\n"); - err = -ENOMEM; - goto err_fb_notif_wq_create; - } -#endif - - return 0; - -#ifdef CONFIG_FB -err_fb_notif_wq_create: -#endif -#ifdef CONFIG_OF -err_alloc_dt_pdata_failed: -#else -err_power_failed: -err_get_platform_data_fail: -#endif - if (ts->ts_pinctrl) { - if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { - devm_pinctrl_put(ts->ts_pinctrl); - ts->ts_pinctrl = NULL; - } else { - err = pinctrl_select_state(ts->ts_pinctrl, - ts->pinctrl_state_release); - if (err) - E("failed to select relase pinctrl state %d\n", - err); - } - } - kfree(ic_data); - -err_dt_ic_data_fail: - kfree(pdata); - -err_dt_platform_data_fail: - kfree(ts); - -err_alloc_data_failed: - -err_check_functionality_failed: - probe_fail_flag = 1; - return err; - -} - -int himax_chip_common_remove(struct i2c_client *client) -{ - struct himax_ts_data *ts = i2c_get_clientdata(client); - int ret; -#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) - himax_touch_proc_deinit(); -#endif -#ifdef CONFIG_FB - if (fb_unregister_client(&ts->fb_notif)) - dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n"); -#endif - - if (!ts->use_irq) - hrtimer_cancel(&ts->timer); - - destroy_workqueue(ts->himax_wq); - - if (ts->protocol_type == PROTOCOL_TYPE_B) - input_mt_destroy_slots(ts->input_dev); - - input_unregister_device(ts->input_dev); - - if (ts->ts_pinctrl) { - if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { - devm_pinctrl_put(ts->ts_pinctrl); - ts->ts_pinctrl = NULL; - } else { - ret = pinctrl_select_state(ts->ts_pinctrl, - ts->pinctrl_state_release); - if (ret) - E("failed to select relase pinctrl state %d\n", - ret); - } - } -#ifdef HX_SMART_WAKEUP - wake_lock_destroy(&ts->ts_SMWP_wake_lock); -#endif - kfree(ts); - - return 0; - -} - -int himax_chip_common_suspend(struct himax_ts_data *ts) -{ - int ret; - - if(ts->suspended) - { - I("%s: Already suspended. Skipped. \n", __func__); - return 0; - } - else - { - ts->suspended = true; - I("%s: enter \n", __func__); - } - -#ifdef HX_TP_PROC_FLASH_DUMP - if (getFlashDumpGoing()) - { - I("[himax] %s: Flash dump is going, reject suspend\n",__func__); - return 0; - } -#endif -#ifdef HX_TP_PROC_HITOUCH - if(hitouch_is_connect) - { - I("[himax] %s: Hitouch connect, reject suspend\n",__func__); - return 0; - } -#endif -#ifdef HX_SMART_WAKEUP - if(ts->SMWP_enable) - { - atomic_set(&ts->suspend_mode, 1); - ts->pre_finger_mask = 0; - FAKE_POWER_KEY_SEND=false; - I("[himax] %s: SMART_WAKEUP enable, reject suspend\n",__func__); - return 0; - } -#endif -#ifdef HX_ESD_WORKAROUND - ESD_00_counter = 0; - ESD_00_Flag = 0; -#endif - if (!ts->use_irq) { - ret = cancel_work_sync(&ts->work); - if (ret) - himax_int_enable(ts->client->irq,1); - } - - //ts->first_pressed = 0; - atomic_set(&ts->suspend_mode, 1); - ts->pre_finger_mask = 0; - - if (ts->ts_pinctrl) { - ret = pinctrl_select_state(ts->ts_pinctrl, - ts->pinctrl_state_suspend); - if (ret < 0) { - E("Failed to get idle pinctrl state %d\n", ret); - } - } - - if (ts->pdata->powerOff3V3 && ts->pdata->power) - ts->pdata->power(0); - - return 0; -} - -int himax_chip_common_resume(struct himax_ts_data *ts) -{ - int retval; - - I("%s: enter \n", __func__); - - if (ts->pdata->powerOff3V3 && ts->pdata->power) - ts->pdata->power(1); - - - /*************************************/ - if (ts->protocol_type == PROTOCOL_TYPE_A) - input_mt_sync(ts->input_dev); - input_report_key(ts->input_dev, BTN_TOUCH, 0); - input_sync(ts->input_dev); - /*************************************/ - - - if (ts->ts_pinctrl) { - retval = pinctrl_select_state(ts->ts_pinctrl, - ts->pinctrl_state_active); - if (retval < 0) { - E("Cannot get default pinctrl state %d\n", retval); - goto err_pinctrl_select_resume; - } - } - - atomic_set(&ts->suspend_mode, 0); - - himax_int_enable(ts->client->irq,1); - - ts->suspended = false; -#if defined(HX_USB_DETECT2) - ts->usb_connected = 0x00; - himax_cable_detect_func(); -#endif -#ifdef HX_SMART_WAKEUP - queue_delayed_work(ts->himax_smwp_wq, &ts->smwp_work, msecs_to_jiffies(1000)); -#endif -#ifdef HX_HIGH_SENSE - queue_delayed_work(ts->himax_hsen_wq, &ts->hsen_work, msecs_to_jiffies(1000)); -#endif - return 0; -err_pinctrl_select_resume: - if (ts->pdata->powerOff3V3 && ts->pdata->power) - ts->pdata->power(0); - return retval; -} - diff --git a/drivers/input/touchscreen/hxchipset/himax_common.h b/drivers/input/touchscreen/hxchipset/himax_common.h deleted file mode 100644 index 27ce9aafd959..000000000000 --- a/drivers/input/touchscreen/hxchipset/himax_common.h +++ /dev/null @@ -1,395 +0,0 @@ -/* Himax Android Driver Sample Code for Himax chipset -* -* Copyright (C) 2015 Himax Corporation. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#ifndef HIMAX_COMMON_H -#define HIMAX_COMMON_H - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "himax_platform.h" - -#if defined(CONFIG_FB) -#include -#include -#elif defined(CONFIG_HAS_EARLYSUSPEND) -#include -#endif - -#ifdef CONFIG_OF -#include -#endif -#define HIMAX_DRIVER_VER "0.2.4.0" - -#define FLASH_DUMP_FILE "/data/user/Flash_Dump.bin" -#define DIAG_COORDINATE_FILE "/sdcard/Coordinate_Dump.csv" - -#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) - -#define HX_TP_PROC_DIAG -#define HX_TP_PROC_REGISTER -#define HX_TP_PROC_DEBUG -#define HX_TP_PROC_FLASH_DUMP -#define HX_TP_PROC_SELF_TEST -#define HX_TP_PROC_RESET -#define HX_TP_PROC_SENSE_ON_OFF -//#define HX_TP_PROC_2T2R - -int himax_touch_proc_init(void); -void himax_touch_proc_deinit(void); -#endif - -//===========Himax Option function============= -//#define HX_RST_PIN_FUNC -//#define HX_AUTO_UPDATE_FW -//#define HX_HIGH_SENSE -//#define HX_SMART_WAKEUP -//#define HX_USB_DETECT -//#define HX_ESD_WORKAROUND -//#define HX_USB_DETECT2 - -//#define HX_EN_SEL_BUTTON // Support Self Virtual key ,default is close -#define HX_EN_MUT_BUTTON // Support Mutual Virtual Key ,default is close - -#define HX_KEY_MAX_COUNT 4 -#define DEFAULT_RETRY_CNT 3 - -#define HX_VKEY_0 KEY_BACK -#define HX_VKEY_1 KEY_HOME -#define HX_VKEY_2 KEY_RESERVED -#define HX_VKEY_3 KEY_RESERVED -#define HX_KEY_ARRAY {HX_VKEY_0, HX_VKEY_1, HX_VKEY_2, HX_VKEY_3} - -#define SHIFTBITS 5 -//#define FLASH_SIZE 131072 -#define FW_SIZE_60k 61440 -#define FW_SIZE_64k 65536 -#define FW_SIZE_124k 126976 -#define FW_SIZE_128k 131072 - -struct himax_ic_data { - int vendor_fw_ver; - int vendor_config_ver; - int vendor_sensor_id; - int HX_RX_NUM; - int HX_TX_NUM; - int HX_BT_NUM; - int HX_X_RES; - int HX_Y_RES; - int HX_MAX_PT; - bool HX_XY_REVERSE; - bool HX_INT_IS_EDGE; -#ifdef HX_TP_PROC_2T2R - int HX_RX_NUM_2; - int HX_TX_NUM_2; -#endif -}; - -struct himax_virtual_key { - int index; - int keycode; - int x_range_min; - int x_range_max; - int y_range_min; - int y_range_max; -}; - -struct himax_config { - uint8_t default_cfg; - uint8_t sensor_id; - uint8_t fw_ver; - uint16_t length; - uint32_t tw_x_min; - uint32_t tw_x_max; - uint32_t tw_y_min; - uint32_t tw_y_max; - uint32_t pl_x_min; - uint32_t pl_x_max; - uint32_t pl_y_min; - uint32_t pl_y_max; - uint8_t c1[11]; - uint8_t c2[11]; - uint8_t c3[11]; - uint8_t c4[11]; - uint8_t c5[11]; - uint8_t c6[11]; - uint8_t c7[11]; - uint8_t c8[11]; - uint8_t c9[11]; - uint8_t c10[11]; - uint8_t c11[11]; - uint8_t c12[11]; - uint8_t c13[11]; - uint8_t c14[11]; - uint8_t c15[11]; - uint8_t c16[11]; - uint8_t c17[11]; - uint8_t c18[17]; - uint8_t c19[15]; - uint8_t c20[5]; - uint8_t c21[11]; - uint8_t c22[4]; - uint8_t c23[3]; - uint8_t c24[3]; - uint8_t c25[4]; - uint8_t c26[2]; - uint8_t c27[2]; - uint8_t c28[2]; - uint8_t c29[2]; - uint8_t c30[2]; - uint8_t c31[2]; - uint8_t c32[2]; - uint8_t c33[2]; - uint8_t c34[2]; - uint8_t c35[3]; - uint8_t c36[5]; - uint8_t c37[5]; - uint8_t c38[9]; - uint8_t c39[14]; - uint8_t c40[159]; - uint8_t c41[99]; -}; - -struct himax_ts_data { - bool suspended; - bool probe_done; - struct mutex fb_mutex; - atomic_t suspend_mode; - uint8_t x_channel; - uint8_t y_channel; - uint8_t useScreenRes; - uint8_t diag_command; - - uint8_t protocol_type; - uint8_t first_pressed; - uint8_t coord_data_size; - uint8_t area_data_size; - uint8_t raw_data_frame_size; - uint8_t raw_data_nframes; - uint8_t nFinger_support; - uint8_t irq_enabled; - uint8_t diag_self[50]; - - uint16_t finger_pressed; - uint16_t last_slot; - uint16_t pre_finger_mask; - - uint32_t debug_log_level; - uint32_t widthFactor; - uint32_t heightFactor; - uint32_t tw_x_min; - uint32_t tw_x_max; - uint32_t tw_y_min; - uint32_t tw_y_max; - uint32_t pl_x_min; - uint32_t pl_x_max; - uint32_t pl_y_min; - uint32_t pl_y_max; - - int use_irq; - int (*power)(int on); - int pre_finger_data[10][2]; - - struct device *dev; - struct workqueue_struct *himax_wq; - struct work_struct work; - struct input_dev *input_dev; - struct hrtimer timer; - struct i2c_client *client; - struct himax_i2c_platform_data *pdata; - struct himax_virtual_key *button; - -#if defined(CONFIG_FB) - struct notifier_block fb_notif; -#elif defined(CONFIG_HAS_EARLYSUSPEND) - struct early_suspend early_suspend; -#endif - -#ifdef HX_TP_PROC_FLASH_DUMP - struct workqueue_struct *flash_wq; - struct work_struct flash_work; -#endif - -#ifdef HX_RST_PIN_FUNC - int rst_gpio; -#endif - -#ifdef HX_TP_PROC_DIAG - struct workqueue_struct *himax_diag_wq; - struct delayed_work himax_diag_delay_wrok; -#endif -#ifdef HX_SMART_WAKEUP - uint8_t SMWP_enable; - uint8_t gesture_cust_en[16]; - struct wake_lock ts_SMWP_wake_lock; - struct workqueue_struct *himax_smwp_wq; - struct delayed_work smwp_work; -#endif - -#ifdef HX_HIGH_SENSE - uint8_t HSEN_enable; - struct workqueue_struct *himax_hsen_wq; - struct delayed_work hsen_work; -#endif - -#if defined(HX_USB_DETECT)||defined(HX_USB_DETECT2) - uint8_t usb_connected; - uint8_t *cable_config; -#endif - - /* pinctrl data */ - struct pinctrl *ts_pinctrl; - struct pinctrl_state *pinctrl_state_active; - struct pinctrl_state *pinctrl_state_suspend; - struct pinctrl_state *pinctrl_state_release; -}; - -#define HX_CMD_NOP 0x00 -#define HX_CMD_SETMICROOFF 0x35 -#define HX_CMD_SETROMRDY 0x36 -#define HX_CMD_TSSLPIN 0x80 -#define HX_CMD_TSSLPOUT 0x81 -#define HX_CMD_TSSOFF 0x82 -#define HX_CMD_TSSON 0x83 -#define HX_CMD_ROE 0x85 -#define HX_CMD_RAE 0x86 -#define HX_CMD_RLE 0x87 -#define HX_CMD_CLRES 0x88 -#define HX_CMD_TSSWRESET 0x9E -#define HX_CMD_SETDEEPSTB 0xD7 -#define HX_CMD_SET_CACHE_FUN 0xDD -#define HX_CMD_SETIDLE 0xF2 -#define HX_CMD_SETIDLEDELAY 0xF3 -#define HX_CMD_SELFTEST_BUFFER 0x8D -#define HX_CMD_MANUALMODE 0x42 -#define HX_CMD_FLASH_ENABLE 0x43 -#define HX_CMD_FLASH_SET_ADDRESS 0x44 -#define HX_CMD_FLASH_WRITE_REGISTER 0x45 -#define HX_CMD_FLASH_SET_COMMAND 0x47 -#define HX_CMD_FLASH_WRITE_BUFFER 0x48 -#define HX_CMD_FLASH_PAGE_ERASE 0x4D -#define HX_CMD_FLASH_SECTOR_ERASE 0x4E -#define HX_CMD_CB 0xCB -#define HX_CMD_EA 0xEA -#define HX_CMD_4A 0x4A -#define HX_CMD_4F 0x4F -#define HX_CMD_B9 0xB9 -#define HX_CMD_76 0x76 - -enum input_protocol_type { - PROTOCOL_TYPE_A = 0x00, - PROTOCOL_TYPE_B = 0x01, -}; - -#ifdef HX_HIGH_SENSE -void himax_set_HSEN_func(struct i2c_client *client,uint8_t HSEN_enable); -#endif - -#ifdef HX_SMART_WAKEUP -#define GEST_PTLG_ID_LEN (4) -#define GEST_PTLG_HDR_LEN (4) -#define GEST_PTLG_HDR_ID1 (0xCC) -#define GEST_PTLG_HDR_ID2 (0x44) -#define GEST_PT_MAX_NUM (128) - -#ifdef HX_GESTURE_TRACK -static int gest_pt_cnt; -static int gest_pt_x[GEST_PT_MAX_NUM]; -static int gest_pt_y[GEST_PT_MAX_NUM]; -static int gest_start_x,gest_start_y,gest_end_x,gest_end_y; -static int gest_width,gest_height,gest_mid_x,gest_mid_y; -static int gn_gesture_coor[16]; -#endif - -void himax_set_SMWP_func(struct i2c_client *client,uint8_t SMWP_enable); -extern bool FAKE_POWER_KEY_SEND; - - enum gesture_event_type { - EV_GESTURE_01 = 0x01, - EV_GESTURE_02, - EV_GESTURE_03, - EV_GESTURE_04, - EV_GESTURE_05, - EV_GESTURE_06, - EV_GESTURE_07, - EV_GESTURE_08, - EV_GESTURE_09, - EV_GESTURE_10, - EV_GESTURE_11, - EV_GESTURE_12, - EV_GESTURE_13, - EV_GESTURE_14, - EV_GESTURE_15, - EV_GESTURE_PWR = 0x80, - }; - -#define KEY_CUST_01 251 -#define KEY_CUST_02 252 -#define KEY_CUST_03 253 -#define KEY_CUST_04 254 -#define KEY_CUST_05 255 -#define KEY_CUST_06 256 -#define KEY_CUST_07 257 -#define KEY_CUST_08 258 -#define KEY_CUST_09 259 -#define KEY_CUST_10 260 -#define KEY_CUST_11 261 -#define KEY_CUST_12 262 -#define KEY_CUST_13 263 -#define KEY_CUST_14 264 -#define KEY_CUST_15 265 -#endif - -#ifdef HX_ESD_WORKAROUND - extern u8 HX_ESD_RESET_ACTIVATE; -#endif - -extern int irq_enable_count; - -#ifdef QCT -irqreturn_t himax_ts_thread(int irq, void *ptr); -int himax_input_register(struct himax_ts_data *ts); -#endif - -extern int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_id *id); -extern int himax_chip_common_remove(struct i2c_client *client); -extern int himax_chip_common_suspend(struct himax_ts_data *ts); -extern int himax_chip_common_resume(struct himax_ts_data *ts); -int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_data *pdata); - -#ifdef HX_USB_DETECT2 -//extern kal_bool upmu_is_chr_det(void); -void himax_cable_detect_func(void); -#endif - -#endif - diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.c b/drivers/input/touchscreen/hxchipset/himax_debug.c deleted file mode 100644 index f8bee11b4351..000000000000 --- a/drivers/input/touchscreen/hxchipset/himax_debug.c +++ /dev/null @@ -1,2329 +0,0 @@ -/* Himax Android Driver Sample Code for Himax chipset -* -* Copyright (C) 2015 Himax Corporation. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#include "himax_debug.h" -#include "himax_ic.h" - -//struct himax_debug_data* debug_data; - -extern struct himax_ic_data* ic_data; -extern struct himax_ts_data *private_ts; -extern unsigned char IC_TYPE; -extern unsigned char IC_CHECKSUM; -extern int himax_input_register(struct himax_ts_data *ts); -#ifdef QCT -extern irqreturn_t himax_ts_thread(int irq, void *ptr); -#endif -#ifdef MTK -#ifdef CONFIG_OF_TOUCH -extern irqreturn_t tpd_eint_interrupt_handler(int irq, void *desc); -#else -extern void tpd_eint_interrupt_handler(void); -#endif -#endif - -#ifdef HX_TP_PROC_DIAG -#ifdef HX_TP_PROC_2T2R -int HX_RX_NUM_2 = 0; -int HX_TX_NUM_2 = 0; -#endif -int touch_monitor_stop_flag = 0; -int touch_monitor_stop_limit = 5; -uint8_t g_diag_arr_num = 0; -#endif - -#ifdef HX_ESD_WORKAROUND -u8 HX_ESD_RESET_ACTIVATE; -#endif - -#ifdef HX_SMART_WAKEUP -bool FAKE_POWER_KEY_SEND; -#endif - -//============================================================================================================= -// -// Segment : Himax PROC Debug Function -// -//============================================================================================================= -#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) - -static ssize_t himax_vendor_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - ssize_t ret = 0; - char *temp_buf; - - if(!HX_PROC_SEND_FLAG) - { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - - ret += snprintf(temp_buf, len, "%s_FW:%#x_CFG:%#x_SensorId:%#x\n", HIMAX_common_NAME, - ic_data->vendor_fw_ver, ic_data->vendor_config_ver, ic_data->vendor_sensor_id); - HX_PROC_SEND_FLAG=1; - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - } - else - HX_PROC_SEND_FLAG=0; - - return ret; -} - -static const struct file_operations himax_proc_vendor_ops = -{ - .owner = THIS_MODULE, - .read = himax_vendor_read, -}; - -static ssize_t himax_attn_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - ssize_t ret = 0; - struct himax_ts_data *ts_data; - char *temp_buf; - - ts_data = private_ts; - - if (!HX_PROC_SEND_FLAG) { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - ret += snprintf(temp_buf, len, "attn = %x\n", himax_int_gpio_read(ts_data->pdata->gpio_irq)); - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; - - return ret; -} - - -static const struct file_operations himax_proc_attn_ops = -{ - .owner = THIS_MODULE, - .read = himax_attn_read, -}; - -static ssize_t himax_int_en_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts = private_ts; - size_t ret = 0; - char *temp_buf; - - if (!HX_PROC_SEND_FLAG) { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - ret += snprintf(temp_buf, len, "%d ", ts->irq_enabled); - ret += snprintf(temp_buf+ret, len-ret, "\n"); - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; - return ret; -} - -static ssize_t himax_int_en_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts = private_ts; - char buf_tmp[12]= {0}; - int value, ret=0; - - if (len >= 12) - { - I("%s: no command exceeds 12 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf_tmp, buff, len)) - { - return -EFAULT; - } - - if (buf_tmp[0] == '0') - value = false; - else if (buf_tmp[0] == '1') - value = true; - else - return -EINVAL; - - if (value) { - if(ic_data->HX_INT_IS_EDGE) - { -#ifdef MTK -#ifdef CONFIG_OF_TOUCH - himax_int_enable(ts->client->irq,1); -#else - //mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_TYPE); - //mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN); - mt_eint_registration(ts->client->irq, EINTF_TRIGGER_FALLING, tpd_eint_interrupt_handler, 1); -#endif -#endif -#ifdef QCT - ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ts->client->name, ts); -#endif - } - else - { -#ifdef MTK -#ifdef CONFIG_OF_TOUCH - himax_int_enable(ts->client->irq,1); -#else - //mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_TYPE); - //mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN); - mt_eint_registration(ts->client->irq, EINTF_TRIGGER_LOW, tpd_eint_interrupt_handler, 1); -#endif -#endif -#ifdef QCT - ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, ts->client->name, ts); -#endif - } - if (ret == 0) { - ts->irq_enabled = 1; - irq_enable_count = 1; - } - } else { - himax_int_enable(ts->client->irq,0); - free_irq(ts->client->irq, ts); - ts->irq_enabled = 0; - } - - return len; -} - -static const struct file_operations himax_proc_int_en_ops = -{ - .owner = THIS_MODULE, - .read = himax_int_en_read, - .write = himax_int_en_write, -}; - -static ssize_t himax_layout_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts = private_ts; - size_t ret = 0; - char *temp_buf; - - if (!HX_PROC_SEND_FLAG) { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_x_min); - ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_x_max); - ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_y_min); - ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_y_max); - ret += snprintf(temp_buf+ret, len-ret, "\n"); - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; - - return ret; -} - -static ssize_t himax_layout_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts = private_ts; - char buf_tmp[5]; - int i = 0, j = 0, k = 0, ret; - unsigned long value; - int layout[4] = {0}; - char buf[80] = {0}; - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf, buff, len)) - { - return -EFAULT; - } - - for (i = 0; i < 20; i++) { - if (buf[i] == ',' || buf[i] == '\n') { - memset(buf_tmp, 0x0, sizeof(buf_tmp)); - if (i - j <= 5) - memcpy(buf_tmp, buf + j, i - j); - else { - I("buffer size is over 5 char\n"); - return len; - } - j = i + 1; - if (k < 4) { - ret = kstrtoul(buf_tmp, 10, &value); - layout[k++] = value; - } - } - } - if (k == 4) { - ts->pdata->abs_x_min=layout[0]; - ts->pdata->abs_x_max=layout[1]; - ts->pdata->abs_y_min=layout[2]; - ts->pdata->abs_y_max=layout[3]; - I("%d, %d, %d, %d\n",ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); - input_unregister_device(ts->input_dev); - himax_input_register(ts); - } else - I("ERR@%d, %d, %d, %d\n",ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); - return len; -} - -static const struct file_operations himax_proc_layout_ops = -{ - .owner = THIS_MODULE, - .read = himax_layout_read, - .write = himax_layout_write, -}; - -static ssize_t himax_debug_level_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts_data; - size_t ret = 0; - char *temp_buf; - ts_data = private_ts; - - if (!HX_PROC_SEND_FLAG) { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - ret += snprintf(temp_buf, len, "%d\n", ts_data->debug_log_level); - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; - - return ret; -} - -static ssize_t himax_debug_level_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts; - char buf_tmp[11]; - int i; - ts = private_ts; - - if (len >= 12) - { - I("%s: no command exceeds 12 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf_tmp, buff, len)) - { - return -EFAULT; - } - - ts->debug_log_level = 0; - for(i=0; i='0' && buf_tmp[i]<='9' ) - ts->debug_log_level |= (buf_tmp[i]-'0'); - else if( buf_tmp[i]>='A' && buf_tmp[i]<='F' ) - ts->debug_log_level |= (buf_tmp[i]-'A'+10); - else if( buf_tmp[i]>='a' && buf_tmp[i]<='f' ) - ts->debug_log_level |= (buf_tmp[i]-'a'+10); - - if(i!=len-2) - ts->debug_log_level <<= 4; - } - - if (ts->debug_log_level & BIT(3)) { - if (ts->pdata->screenWidth > 0 && ts->pdata->screenHeight > 0 && - (ts->pdata->abs_x_max - ts->pdata->abs_x_min) > 0 && - (ts->pdata->abs_y_max - ts->pdata->abs_y_min) > 0) { - ts->widthFactor = (ts->pdata->screenWidth << SHIFTBITS)/(ts->pdata->abs_x_max - ts->pdata->abs_x_min); - ts->heightFactor = (ts->pdata->screenHeight << SHIFTBITS)/(ts->pdata->abs_y_max - ts->pdata->abs_y_min); - if (ts->widthFactor > 0 && ts->heightFactor > 0) - ts->useScreenRes = 1; - else { - ts->heightFactor = 0; - ts->widthFactor = 0; - ts->useScreenRes = 0; - } - } else - I("Enable finger debug with raw position mode!\n"); - } else { - ts->useScreenRes = 0; - ts->widthFactor = 0; - ts->heightFactor = 0; - } - - return len; -} - -static const struct file_operations himax_proc_debug_level_ops = -{ - .owner = THIS_MODULE, - .read = himax_debug_level_read, - .write = himax_debug_level_write, -}; - -#ifdef HX_TP_PROC_REGISTER -static ssize_t himax_proc_register_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - int ret = 0; - uint16_t loop_i; - uint8_t data[128]; - char *temp_buf; - - memset(data, 0x00, sizeof(data)); - - I("himax_register_show: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]); - if(!HX_PROC_SEND_FLAG) - { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - himax_register_read(private_ts->client, register_command, 1, data); - - ret += snprintf(temp_buf, len, "command: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]); - - for (loop_i = 0; loop_i < 128; loop_i++) { - ret += snprintf(temp_buf+ret, len-ret, "0x%2.2X ", data[loop_i]); - if ((loop_i % 16) == 15) - ret += snprintf(temp_buf+ret, len-ret, "\n"); - } - ret += snprintf(temp_buf+ret, len-ret, "\n"); - HX_PROC_SEND_FLAG=1; - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - } - else - HX_PROC_SEND_FLAG=0; - return ret; -} - -static ssize_t himax_proc_register_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - char buf_tmp[16], length = 0; - unsigned long result = 0; - uint8_t loop_i = 0; - uint16_t base = 5; - uint8_t write_da[128]; - char buf[80] = {0}; - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf, buff, len)) - { - return -EFAULT; - } - - memset(buf_tmp, 0x0, sizeof(buf_tmp)); - memset(write_da, 0x0, sizeof(write_da)); - - I("himax %s \n",buf); - - if ((buf[0] == 'r' || buf[0] == 'w') && buf[1] == ':') { - - if (buf[2] == 'x') { - memcpy(buf_tmp, buf + 3, 8); - if (!kstrtoul(buf_tmp, 16, &result)) - { - register_command[0] = (uint8_t)result; - register_command[1] = (uint8_t)(result >> 8); - register_command[2] = (uint8_t)(result >> 16); - register_command[3] = (uint8_t)(result >> 24); - } - base = 11; - I("CMD: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]); - - for (loop_i = 0; loop_i < 128 && (base+10)<80; loop_i++) { - if (buf[base] == '\n') { - if (buf[0] == 'w') { - himax_register_write(private_ts->client, register_command, 1, write_da); - I("CMD: %x, %x, %x, %x, len=%d\n", write_da[0], write_da[1],write_da[2],write_da[3],length); - } - I("\n"); - return len; - } - if (buf[base + 1] == 'x') { - buf_tmp[10] = '\n'; - buf_tmp[11] = '\0'; - memcpy(buf_tmp, buf + base + 2, 8); - if (!kstrtoul(buf_tmp, 16, &result)) { - write_da[loop_i] = (uint8_t)result; - write_da[loop_i+1] = (uint8_t)(result >> 8); - write_da[loop_i+2] = (uint8_t)(result >> 16); - write_da[loop_i+3] = (uint8_t)(result >> 24); - } - length+=4; - } - base += 10; - } - } - } - return len; -} - -static const struct file_operations himax_proc_register_ops = -{ - .owner = THIS_MODULE, - .read = himax_proc_register_read, - .write = himax_proc_register_write, -}; -#endif - -#ifdef HX_TP_PROC_DIAG -int16_t *getMutualBuffer(void) -{ - return diag_mutual; -} -int16_t *getMutualNewBuffer(void) -{ - return diag_mutual_new; -} -int16_t *getMutualOldBuffer(void) -{ - return diag_mutual_old; -} -int16_t *getSelfBuffer(void) -{ - return &diag_self[0]; -} -uint8_t getXChannel(void) -{ - return x_channel; -} -uint8_t getYChannel(void) -{ - return y_channel; -} -uint8_t getDiagCommand(void) -{ - return diag_command; -} -void setXChannel(uint8_t x) -{ - x_channel = x; -} -void setYChannel(uint8_t y) -{ - y_channel = y; -} -void setMutualBuffer(void) -{ - diag_mutual = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); -} -void setMutualNewBuffer(void) -{ - diag_mutual_new = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); -} -void setMutualOldBuffer(void) -{ - diag_mutual_old = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); -} - -#ifdef HX_TP_PROC_2T2R -int16_t *getMutualBuffer_2(void) -{ - return diag_mutual_2; -} -uint8_t getXChannel_2(void) -{ - return x_channel_2; -} -uint8_t getYChannel_2(void) -{ - return y_channel_2; -} -void setXChannel_2(uint8_t x) -{ - x_channel_2 = x; -} -void setYChannel_2(uint8_t y) -{ - y_channel_2 = y; -} -void setMutualBuffer_2(void) -{ - diag_mutual_2 = kzalloc(x_channel_2 * y_channel_2 * sizeof(int16_t), GFP_KERNEL); -} -#endif - -static ssize_t himax_diag_arrange_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - //struct himax_ts_data *ts = private_ts; - char buf[80] = {0}; - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf, buff, len)) - { - return -EFAULT; - } - - g_diag_arr_num = buf[0] - '0'; - I("%s: g_diag_arr_num = %d \n", __func__,g_diag_arr_num); - - return len; -} - -static const struct file_operations himax_proc_diag_arrange_ops = -{ - .owner = THIS_MODULE, - .write = himax_diag_arrange_write, -}; - -static void himax_diag_arrange_print(struct seq_file *s, int i, int j, int transpose) -{ - if(transpose) - seq_printf(s, "%6d", diag_mutual[ j + i*x_channel]); - else - seq_printf(s, "%6d", diag_mutual[ i + j*x_channel]); -} - -static void himax_diag_arrange_inloop(struct seq_file *s, int in_init,bool transpose, int j) -{ - int i; - int in_max = 0; - - if(transpose) - in_max = y_channel; - else - in_max = x_channel; - - if (in_init > 0) - { - for(i = in_init-1;i >= 0;i--) - { - himax_diag_arrange_print(s, i, j, transpose); - } - } - else - { - for (i = 0; i < in_max; i++) - { - himax_diag_arrange_print(s, i, j, transpose); - } - } -} - -static void himax_diag_arrange_outloop(struct seq_file *s, int transpose, int out_init, int in_init) -{ - int j; - int out_max = 0; - - if(transpose) - out_max = x_channel; - else - out_max = y_channel; - - if(out_init > 0) - { - for(j = out_init-1;j >= 0;j--) - { - himax_diag_arrange_inloop(s, in_init, transpose, j); - seq_printf(s, " %5d\n", diag_self[j]); - } - } - else - { - for(j = 0;j < out_max;j++) - { - himax_diag_arrange_inloop(s, in_init, transpose, j); - seq_printf(s, " %5d\n", diag_self[j]); - } - } -} - -static void himax_diag_arrange(struct seq_file *s) -{ - int bit2,bit1,bit0; - int i; - - bit2 = g_diag_arr_num >> 2; - bit1 = g_diag_arr_num >> 1 & 0x1; - bit0 = g_diag_arr_num & 0x1; - - if (g_diag_arr_num < 4) - { - himax_diag_arrange_outloop(s, bit2, bit1 * y_channel, bit0 * x_channel); - for (i = y_channel; i < x_channel + y_channel; i++) { - seq_printf(s, "%6d", diag_self[i]); - } - } - else - { - himax_diag_arrange_outloop(s, bit2, bit1 * x_channel, bit0 * y_channel); - for (i = x_channel; i < x_channel + y_channel; i++) { - seq_printf(s, "%6d", diag_self[i]); - } - } -} - -static void *himax_diag_seq_start(struct seq_file *s, loff_t *pos) -{ - if (*pos>=1) return NULL; - return (void *)((unsigned long) *pos+1); -} - -static void *himax_diag_seq_next(struct seq_file *s, void *v, loff_t *pos) -{ - return NULL; -} -static void himax_diag_seq_stop(struct seq_file *s, void *v) -{ -} -static int himax_diag_seq_read(struct seq_file *s, void *v) -{ - size_t count = 0; - int32_t loop_i;//,loop_j - uint16_t mutual_num, self_num, width; - -#ifdef HX_TP_PROC_2T2R - if(Is_2T2R && diag_command == 4) - { - mutual_num = x_channel_2 * y_channel_2; - self_num = x_channel_2 + y_channel_2; //don't add KEY_COUNT - width = x_channel_2; - seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel_2, y_channel_2); - } - else -#endif - { - mutual_num = x_channel * y_channel; - self_num = x_channel + y_channel; //don't add KEY_COUNT - width = x_channel; - seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel, y_channel); - } - - // start to show out the raw data in adb shell - if (diag_command >= 1 && diag_command <= 6) { - if (diag_command <= 3) { - himax_diag_arrange(s); - seq_printf(s, "\n\n"); -#ifdef HX_EN_SEL_BUTTON - seq_printf(s, "\n"); - for (loop_i = 0; loop_i < HX_BT_NUM; loop_i++) - seq_printf(s, "%6d", diag_self[HX_RX_NUM + HX_TX_NUM + loop_i]); -#endif -#ifdef HX_TP_PROC_2T2R - }else if(Is_2T2R && diag_command == 4 ) { - for (loop_i = 0; loop_i < mutual_num; loop_i++) { - seq_printf(s, "%4d", diag_mutual_2[loop_i]); - if ((loop_i % width) == (width - 1)) - seq_printf(s, " %6d\n", diag_self[width + loop_i/width]); - } - seq_printf(s, "\n"); - for (loop_i = 0; loop_i < width; loop_i++) { - seq_printf(s, "%6d", diag_self[loop_i]); - if (((loop_i) % width) == (width - 1)) - seq_printf(s, "\n"); - } -#ifdef HX_EN_SEL_BUTTON - seq_printf(s, "\n"); - for (loop_i = 0; loop_i < HX_BT_NUM; loop_i++) - seq_printf(s, "%4d", diag_self[HX_RX_NUM_2 + HX_TX_NUM_2 + loop_i]); -#endif -#endif - } else if (diag_command > 4) { - for (loop_i = 0; loop_i < self_num; loop_i++) { - seq_printf(s, "%4d", diag_self[loop_i]); - if (((loop_i - mutual_num) % width) == (width - 1)) - seq_printf(s, "\n"); - } - } else { - for (loop_i = 0; loop_i < mutual_num; loop_i++) { - seq_printf(s, "%4d", diag_mutual[loop_i]); - if ((loop_i % width) == (width - 1)) - seq_printf(s, "\n"); - } - } - seq_printf(s, "ChannelEnd"); - seq_printf(s, "\n"); - } else if (diag_command == 7) { - for (loop_i = 0; loop_i < 128 ;loop_i++) { - if ((loop_i % 16) == 0) - seq_printf(s, "LineStart:"); - seq_printf(s, "%4d", diag_coor[loop_i]); - if ((loop_i % 16) == 15) - seq_printf(s, "\n"); - } - } else if (diag_command == 9 || diag_command == 91 || diag_command == 92){ - himax_diag_arrange(s); - seq_printf(s, "\n"); - } - - return count; -} -static const struct seq_operations himax_diag_seq_ops = -{ - .start = himax_diag_seq_start, - .next = himax_diag_seq_next, - .stop = himax_diag_seq_stop, - .show = himax_diag_seq_read, -}; -static int himax_diag_proc_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &himax_diag_seq_ops); -}; -bool DSRAM_Flag; - -//DSRAM thread -void himax_ts_diag_func(void) -{ - int i=0, j=0; - unsigned int index = 0; - int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2; - uint8_t info_data[total_size]; - int16_t *mutual_data = NULL; - int16_t *mutual_data_new = NULL; - int16_t *mutual_data_old = NULL; - int16_t new_data; - - himax_burst_enable(private_ts->client, 1); - if(diag_command == 9 || diag_command == 91) - { - mutual_data = getMutualBuffer(); - }else if(diag_command == 92){ - mutual_data = getMutualBuffer(); - mutual_data_new = getMutualNewBuffer(); - mutual_data_old = getMutualOldBuffer(); - } - himax_get_DSRAM_data(private_ts->client, info_data); - - index = 0; - for (i = 0; i < ic_data->HX_TX_NUM; i++) - { - for (j = 0; j < ic_data->HX_RX_NUM; j++) - { - new_data = (short)(info_data[index + 1] << 8 | info_data[index]); - if(diag_command == 9){ - mutual_data[i*ic_data->HX_RX_NUM+j] = new_data; - }else if(diag_command == 91){ //Keep max data for 100 frame - if(mutual_data[i * ic_data->HX_RX_NUM + j] < new_data) - mutual_data[i * ic_data->HX_RX_NUM + j] = new_data; - }else if(diag_command == 92){ //Cal data for [N]-[N-1] frame - mutual_data_new[i * ic_data->HX_RX_NUM + j] = new_data; - mutual_data[i * ic_data->HX_RX_NUM + j] = mutual_data_new[i * ic_data->HX_RX_NUM + j] - mutual_data_old[i * ic_data->HX_RX_NUM + j]; - } - index += 2; - } - } - if(diag_command == 92){ - memcpy(mutual_data_old,mutual_data_new,x_channel * y_channel * sizeof(int16_t)); //copy N data to N-1 array - } - diag_max_cnt++; - if(diag_command == 9 || diag_command == 92){ - queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 1/10*HZ); - }else if(diag_command == 91){ - if(diag_max_cnt > 100) //count for 100 frame - { - //Clear DSRAM flag - DSRAM_Flag = false; - - //Enable ISR - himax_int_enable(private_ts->client->irq,1); - - //===================================== - // test result command : 0x8002_0324 ==> 0x00 - //===================================== - himax_diag_register_set(private_ts->client, 0x00); - }else{ - queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 1/10*HZ); - } - } -} - -static ssize_t himax_diag_write(struct file *filp, const char __user *buff, size_t len, loff_t *data) -{ - char messages[80] = {0}; - - uint8_t command[2] = {0x00, 0x00}; - uint8_t receive[1]; - - memset(receive, 0x00, sizeof(receive)); - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(messages, buff, len)) - { - return -EFAULT; - } - if (messages[1] == 0x0A){ - diag_command =messages[0] - '0'; - }else{ - diag_command =(messages[0] - '0')*10 + (messages[1] - '0'); - } - - I("[Himax]diag_command=0x%x\n",diag_command); - if (diag_command < 0x04){ - if(DSRAM_Flag) - { - //1. Clear DSRAM flag - DSRAM_Flag = false; - - //2. Stop DSRAM thread - cancel_delayed_work_sync(&private_ts->himax_diag_delay_wrok); - - //3. Enable ISR - himax_int_enable(private_ts->client->irq,1); - } - command[0] = diag_command; - himax_diag_register_set(private_ts->client, command[0]); - } - //coordinate dump start - else if (diag_command == 0x08) { - E("%s: coordinate_dump_file_create error\n", __func__); - } - else if (diag_command == 0x09 || diag_command == 91 || diag_command == 92){ - diag_max_cnt = 0; - memset(diag_mutual, 0x00, x_channel * y_channel * sizeof(int16_t)); //Set data 0 everytime - - //1. Disable ISR - himax_int_enable(private_ts->client->irq,0); - - //2. Start DSRAM thread - //himax_diag_register_set(private_ts->client, 0x0A); - - queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 2*HZ/100); - - I("%s: Start get raw data in DSRAM\n", __func__); - - //3. Set DSRAM flag - DSRAM_Flag = true; - }else{ - command[0] = 0x00; - himax_diag_register_set(private_ts->client, command[0]); - E("[Himax]Diag command error!diag_command=0x%x\n",diag_command); - } - return len; -} - -static const struct file_operations himax_proc_diag_ops = -{ - .owner = THIS_MODULE, - .open = himax_diag_proc_open, - .read = seq_read, - .write = himax_diag_write, -}; -#endif - -#ifdef HX_TP_PROC_RESET -static ssize_t himax_reset_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - char buf_tmp[12]; - - if (len >= 12) - { - I("%s: no command exceeds 12 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf_tmp, buff, len)) - { - return -EFAULT; - } - //if (buf_tmp[0] == '1') - // ESD_HW_REST(); - - return len; -} - -static const struct file_operations himax_proc_reset_ops = -{ - .owner = THIS_MODULE, - .write = himax_reset_write, -}; -#endif - -#ifdef HX_TP_PROC_DEBUG -static ssize_t himax_debug_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - size_t count = 0; - char *temp_buf; - - if(!HX_PROC_SEND_FLAG) - { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf){ - HX_PROC_SEND_FLAG=0; - return count; - } - - if (debug_level_cmd == 't') - { - if (fw_update_complete) - count += snprintf(temp_buf+count, len-count, "FW Update Complete "); - else - { - count += snprintf(temp_buf+count, len-count, "FW Update Fail "); - } - } - else if (debug_level_cmd == 'h') - { - if (handshaking_result == 0) - { - count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (MCU Running)\n", handshaking_result); - } - else if (handshaking_result == 1) - { - count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (MCU Stop)\n", handshaking_result); - } - else if (handshaking_result == 2) - { - count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (I2C Error)\n", handshaking_result); - } - else - { - count += snprintf(temp_buf+count, len-count, "Handshaking Result = error\n"); - } - } - else if (debug_level_cmd == 'v') - { - count += snprintf(temp_buf+count, len-count, "FW_VER = "); - count += snprintf(temp_buf+count, len-count, "0x%2.2X\n", ic_data->vendor_fw_ver); - count += snprintf(temp_buf+count, len-count, "CONFIG_VER = "); - count += snprintf(temp_buf+count, len-count, "0x%2.2X\n", ic_data->vendor_config_ver); - count += snprintf(temp_buf+count, len-count, "\n"); - } - else if (debug_level_cmd == 'd') - { - count += snprintf(temp_buf+count, len-count, "Himax Touch IC Information :\n"); - if (IC_TYPE == HX_85XX_D_SERIES_PWON) - { - count += snprintf(temp_buf+count, len-count, "IC Type : D\n"); - } - else if (IC_TYPE == HX_85XX_E_SERIES_PWON) - { - count += snprintf(temp_buf+count, len-count, "IC Type : E\n"); - } - else if (IC_TYPE == HX_85XX_ES_SERIES_PWON) - { - count += snprintf(temp_buf+count, len-count, "IC Type : ES\n"); - } - else if (IC_TYPE == HX_85XX_F_SERIES_PWON) - { - count += snprintf(temp_buf+count, len-count, "IC Type : F\n"); - } - else - { - count += snprintf(temp_buf+count, len-count, "IC Type error.\n"); - } - - if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_SW) - { - count += snprintf(temp_buf+count, len-count, "IC Checksum : SW\n"); - } - else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_HW) - { - count += snprintf(temp_buf+count, len-count, "IC Checksum : HW\n"); - } - else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_CRC) - { - count += snprintf(temp_buf+count, len-count, "IC Checksum : CRC\n"); - } - else - { - count += snprintf(temp_buf+count, len-count, "IC Checksum error.\n"); - } - - if (ic_data->HX_INT_IS_EDGE) - { - count += snprintf(temp_buf+count, len-count, "Interrupt : EDGE TIRGGER\n"); - } - else - { - count += snprintf(temp_buf+count, len-count, "Interrupt : LEVEL TRIGGER\n"); - } - - count += snprintf(temp_buf+count, len-count, "RX Num : %d\n", ic_data->HX_RX_NUM); - count += snprintf(temp_buf+count, len-count, "TX Num : %d\n", ic_data->HX_TX_NUM); - count += snprintf(temp_buf+count, len-count, "BT Num : %d\n", ic_data->HX_BT_NUM); - count += snprintf(temp_buf+count, len-count, "X Resolution : %d\n", ic_data->HX_X_RES); - count += snprintf(temp_buf+count, len-count, "Y Resolution : %d\n", ic_data->HX_Y_RES); - count += snprintf(temp_buf+count, len-count, "Max Point : %d\n", ic_data->HX_MAX_PT); - count += snprintf(temp_buf+count, len-count, "XY reverse : %d\n", ic_data->HX_XY_REVERSE); - #ifdef HX_TP_PROC_2T2R - if(Is_2T2R) - { - count += snprintf(temp_buf+count, len-count, "2T2R panel\n"); - count += snprintf(temp_buf+count, len-count, "RX Num_2 : %d\n", HX_RX_NUM_2); - count += snprintf(temp_buf+count, len-count, "TX Num_2 : %d\n", HX_TX_NUM_2); - } - #endif - } - else if (debug_level_cmd == 'i') - { - count += snprintf(temp_buf+count, len-count, "Himax Touch Driver Version:\n"); - count += snprintf(temp_buf+count, len-count, "%s\n", HIMAX_DRIVER_VER); - } - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG=1; - } - else - HX_PROC_SEND_FLAG=0; - return count; -} - -static ssize_t himax_debug_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - const struct firmware *fw = NULL; - unsigned char *fw_data = NULL; - char fileName[128]; - char buf[80] = {0}; - int result; - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf, buff, len)) - { - return -EFAULT; - } - - if ( buf[0] == 'h') //handshaking - { - debug_level_cmd = buf[0]; - - himax_int_enable(private_ts->client->irq,0); - - handshaking_result = himax_hand_shaking(private_ts->client); //0:Running, 1:Stop, 2:I2C Fail - - himax_int_enable(private_ts->client->irq,1); - - return len; - } - - else if ( buf[0] == 'v') //firmware version - { - debug_level_cmd = buf[0]; - himax_int_enable(private_ts->client->irq,0); -#ifdef HX_RST_PIN_FUNC - himax_HW_reset(false,false); -#endif - himax_read_FW_ver(private_ts->client); - //himax_check_chip_version(); -#ifdef HX_RST_PIN_FUNC - himax_HW_reset(true,false); -#endif - himax_int_enable(private_ts->client->irq,1); - return len; - } - - else if ( buf[0] == 'd') //ic information - { - debug_level_cmd = buf[0]; - return len; - } - - else if ( buf[0] == 'i') //driver version - { - debug_level_cmd = buf[0]; - return len; - } - - else if (buf[0] == 't') - { - - himax_int_enable(private_ts->client->irq,0); - - debug_level_cmd = buf[0]; - fw_update_complete = false; - - memset(fileName, 0, 128); - // parse the file name - snprintf(fileName, len-4, "%s", &buf[4]); - I("%s: upgrade from file(%s) start!\n", __func__, fileName); - // open file - result = request_firmware(&fw, fileName, private_ts->dev); - if (result) { - E("%s: open firmware file failed\n", __func__); - goto firmware_upgrade_done; - //return len; - } - - I("%s: FW len %d\n", __func__, fw->size); - fw_data = (unsigned char *)fw->data; - - I("%s: FW image,len %d: %02X, %02X, %02X, %02X\n", __func__, result, upgrade_fw[0], upgrade_fw[1], upgrade_fw[2], upgrade_fw[3]); - - if (fw_data != NULL) - { - // start to upgrade - himax_int_enable(private_ts->client->irq,0); - - if ((buf[1] == '6') && (buf[2] == '0')) - { - if (fts_ctpm_fw_upgrade_with_sys_fs_60k(private_ts->client,upgrade_fw, result, false) == 0) - { - E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); - fw_update_complete = false; - } - else - { - I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); - fw_update_complete = true; - } - } - else if ((buf[1] == '6') && (buf[2] == '4')) - { - if (fts_ctpm_fw_upgrade_with_sys_fs_64k(private_ts->client,upgrade_fw, result, false) == 0) - { - E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); - fw_update_complete = false; - } - else - { - I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); - fw_update_complete = true; - } - } - else if ((buf[1] == '2') && (buf[2] == '4')) - { - if (fts_ctpm_fw_upgrade_with_sys_fs_124k(private_ts->client,upgrade_fw, result, false) == 0) - { - E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); - fw_update_complete = false; - } - else - { - I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); - fw_update_complete = true; - } - } - else if ((buf[1] == '2') && (buf[2] == '8')) - { - if (fts_ctpm_fw_upgrade_with_sys_fs_128k(private_ts->client,upgrade_fw, result, false) == 0) - { - E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); - fw_update_complete = false; - } - else - { - I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); - fw_update_complete = true; - } - } - else - { - E("%s: Flash command fail: %d\n", __func__, __LINE__); - fw_update_complete = false; - } - release_firmware(fw); - goto firmware_upgrade_done; - //return count; - } - } - - firmware_upgrade_done: - -#ifdef HX_RST_PIN_FUNC - himax_HW_reset(true,false); -#endif - - himax_sense_on(private_ts->client, 0x01); - msleep(120); -#ifdef HX_ESD_WORKAROUND - HX_ESD_RESET_ACTIVATE = 1; -#endif - himax_int_enable(private_ts->client->irq,1); - - //todo himax_chip->tp_firmware_upgrade_proceed = 0; - //todo himax_chip->suspend_state = 0; - //todo enable_irq(himax_chip->irq); - return len; -} - -static const struct file_operations himax_proc_debug_ops = -{ - .owner = THIS_MODULE, - .read = himax_debug_read, - .write = himax_debug_write, -}; - -#endif - -#ifdef HX_TP_PROC_FLASH_DUMP - -static uint8_t getFlashCommand(void) -{ - return flash_command; -} - -static uint8_t getFlashDumpProgress(void) -{ - return flash_progress; -} - -static uint8_t getFlashDumpComplete(void) -{ - return flash_dump_complete; -} - -static uint8_t getFlashDumpFail(void) -{ - return flash_dump_fail; -} - -uint8_t getSysOperation(void) -{ - return sys_operation; -} - -static uint8_t getFlashReadStep(void) -{ - return flash_read_step; -} -/* -static uint8_t getFlashDumpSector(void) -{ - return flash_dump_sector; -} - -static uint8_t getFlashDumpPage(void) -{ - return flash_dump_page; -} -*/ -bool getFlashDumpGoing(void) -{ - return flash_dump_going; -} - -void setFlashBuffer(void) -{ - flash_buffer = kzalloc(Flash_Size * sizeof(uint8_t), GFP_KERNEL); - if (flash_buffer) - memset(flash_buffer,0x00,Flash_Size); -} - -void setSysOperation(uint8_t operation) -{ - sys_operation = operation; -} - -static void setFlashDumpProgress(uint8_t progress) -{ - flash_progress = progress; - //I("setFlashDumpProgress : progress = %d ,flash_progress = %d \n",progress,flash_progress); -} - -static void setFlashDumpComplete(uint8_t status) -{ - flash_dump_complete = status; -} - -static void setFlashDumpFail(uint8_t fail) -{ - flash_dump_fail = fail; -} - -static void setFlashCommand(uint8_t command) -{ - flash_command = command; -} - -static void setFlashReadStep(uint8_t step) -{ - flash_read_step = step; -} - -static void setFlashDumpSector(uint8_t sector) -{ - flash_dump_sector = sector; -} - -static void setFlashDumpPage(uint8_t page) -{ - flash_dump_page = page; -} - -static void setFlashDumpGoing(bool going) -{ - flash_dump_going = going; -} - -static ssize_t himax_proc_flash_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - int ret = 0; - int loop_i; - uint8_t local_flash_read_step=0; - uint8_t local_flash_complete = 0; - uint8_t local_flash_progress = 0; - uint8_t local_flash_command = 0; - uint8_t local_flash_fail = 0; - char *temp_buf; - local_flash_complete = getFlashDumpComplete(); - local_flash_progress = getFlashDumpProgress(); - local_flash_command = getFlashCommand(); - local_flash_fail = getFlashDumpFail(); - - I("flash_progress = %d \n",local_flash_progress); - if(!HX_PROC_SEND_FLAG) - { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - - if (local_flash_fail) - { - ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Fail \n"); - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - return ret; - } - - if (!local_flash_complete) - { - ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Ongoing:0x%2.2x \n",flash_progress); - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - return ret; - } - - if (local_flash_command == 1 && local_flash_complete) - { - ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Complete \n"); - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - return ret; - } - - if (local_flash_command == 3 && local_flash_complete) - { - ret += snprintf(temp_buf+ret, len-ret, "FlashStart: \n"); - for(loop_i = 0; loop_i < 128; loop_i++) - { - ret += snprintf(temp_buf+ret, len-ret, "x%2.2x", flash_buffer[loop_i]); - if ((loop_i % 16) == 15) - { - ret += snprintf(temp_buf+ret, len-ret, "\n"); - } - } - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - return ret; - } - - //flash command == 0 , report the data - local_flash_read_step = getFlashReadStep(); - - ret += snprintf(temp_buf+ret, len-ret, "FlashStart:%2.2x \n",local_flash_read_step); - - for (loop_i = 0; loop_i < 1024; loop_i++) - { - ret += snprintf(temp_buf+ret, len-ret, "x%2.2X", flash_buffer[local_flash_read_step*1024 + loop_i]); - - if ((loop_i % 16) == 15) - { - ret += snprintf(temp_buf+ret, len-ret, "\n"); - } - } - - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; - return ret; -} - -static ssize_t himax_proc_flash_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - char buf_tmp[6]; - unsigned long result = 0; - uint8_t loop_i = 0; - int base = 0; - char buf[80] = {0}; - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf, buff, len)) - { - return -EFAULT; - } - memset(buf_tmp, 0x0, sizeof(buf_tmp)); - - I("%s: buf[0] = %s\n", __func__, buf); - - if (getSysOperation() == 1) - { - E("%s: PROC is busy , return!\n", __func__); - return len; - } - - if (buf[0] == '0') - { - setFlashCommand(0); - if (buf[1] == ':' && buf[2] == 'x') - { - memcpy(buf_tmp, buf + 3, 2); - I("%s: read_Step = %s\n", __func__, buf_tmp); - if (!kstrtoul(buf_tmp, 16, &result)) - { - I("%s: read_Step = %lu \n", __func__, result); - setFlashReadStep(result); - } - } - } - else if (buf[0] == '1')// 1_60,1_64,1_24,1_28 for flash size 60k,64k,124k,128k - { - setSysOperation(1); - setFlashCommand(1); - setFlashDumpProgress(0); - setFlashDumpComplete(0); - setFlashDumpFail(0); - if ((buf[1] == '_' ) && (buf[2] == '6' )){ - if (buf[3] == '0'){ - Flash_Size = FW_SIZE_60k; - }else if (buf[3] == '4'){ - Flash_Size = FW_SIZE_64k; - } - }else if ((buf[1] == '_' ) && (buf[2] == '2' )){ - if (buf[3] == '4'){ - Flash_Size = FW_SIZE_124k; - }else if (buf[3] == '8'){ - Flash_Size = FW_SIZE_128k; - } - } - queue_work(private_ts->flash_wq, &private_ts->flash_work); - } - else if (buf[0] == '2') // 2_60,2_64,2_24,2_28 for flash size 60k,64k,124k,128k - { - setSysOperation(1); - setFlashCommand(2); - setFlashDumpProgress(0); - setFlashDumpComplete(0); - setFlashDumpFail(0); - if ((buf[1] == '_' ) && (buf[2] == '6' )){ - if (buf[3] == '0'){ - Flash_Size = FW_SIZE_60k; - }else if (buf[3] == '4'){ - Flash_Size = FW_SIZE_64k; - } - }else if ((buf[1] == '_' ) && (buf[2] == '2' )){ - if (buf[3] == '4'){ - Flash_Size = FW_SIZE_124k; - }else if (buf[3] == '8'){ - Flash_Size = FW_SIZE_128k; - } - } - queue_work(private_ts->flash_wq, &private_ts->flash_work); - } - else if (buf[0] == '3') - { - setSysOperation(1); - setFlashCommand(3); - setFlashDumpProgress(0); - setFlashDumpComplete(0); - setFlashDumpFail(0); - - memcpy(buf_tmp, buf + 3, 2); - if (!kstrtoul(buf_tmp, 16, &result)) - { - setFlashDumpSector(result); - } - - memcpy(buf_tmp, buf + 7, 2); - if (!kstrtoul(buf_tmp, 16, &result)) - { - setFlashDumpPage(result); - } - - queue_work(private_ts->flash_wq, &private_ts->flash_work); - } - else if (buf[0] == '4') - { - I("%s: command 4 enter.\n", __func__); - setSysOperation(1); - setFlashCommand(4); - setFlashDumpProgress(0); - setFlashDumpComplete(0); - setFlashDumpFail(0); - - memcpy(buf_tmp, buf + 3, 2); - if (!kstrtoul(buf_tmp, 16, &result)) - { - setFlashDumpSector(result); - } - else - { - E("%s: command 4 , sector error.\n", __func__); - return len; - } - - memcpy(buf_tmp, buf + 7, 2); - if (!kstrtoul(buf_tmp, 16, &result)) - { - setFlashDumpPage(result); - } - else - { - E("%s: command 4 , page error.\n", __func__); - return len; - } - - base = 11; - - I("=========Himax flash page buffer start=========\n"); - for(loop_i=0;loop_i<128 && base<80;loop_i++) - { - memcpy(buf_tmp, buf + base, 2); - if (!kstrtoul(buf_tmp, 16, &result)) - { - flash_buffer[loop_i] = result; - I("%d ",flash_buffer[loop_i]); - if (loop_i % 16 == 15) - { - I("\n"); - } - } - base += 3; - } - I("=========Himax flash page buffer end=========\n"); - - queue_work(private_ts->flash_wq, &private_ts->flash_work); - } - return len; -} - -static const struct file_operations himax_proc_flash_ops = -{ - .owner = THIS_MODULE, - .read = himax_proc_flash_read, - .write = himax_proc_flash_write, -}; - -void himax_ts_flash_func(void) -{ - uint8_t local_flash_command = 0; - - himax_int_enable(private_ts->client->irq,0); - setFlashDumpGoing(true); - - //sector = getFlashDumpSector(); - //page = getFlashDumpPage(); - - local_flash_command = getFlashCommand(); - - msleep(100); - - I("%s: local_flash_command = %d enter.\n", __func__,local_flash_command); - - if ((local_flash_command == 1 || local_flash_command == 2)|| (local_flash_command==0x0F)) - { - himax_flash_dump_func(private_ts->client, local_flash_command,Flash_Size, flash_buffer); - } - - I("Complete~~~~~~~~~~~~~~~~~~~~~~~\n"); - - if (local_flash_command == 2) - { - E("Flash dump failed\n"); - } - - himax_int_enable(private_ts->client->irq,1); - setFlashDumpGoing(false); - - setFlashDumpComplete(1); - setSysOperation(0); - return; - -/* Flash_Dump_i2c_transfer_error: - - himax_int_enable(private_ts->client->irq,1); - setFlashDumpGoing(false); - setFlashDumpComplete(0); - setFlashDumpFail(1); - setSysOperation(0); - return; -*/ -} - -#endif - -#ifdef HX_TP_PROC_SELF_TEST -static ssize_t himax_self_test_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - int val=0x00; - int ret = 0; - char *temp_buf; - - I("%s: enter, %d \n", __func__, __LINE__); - if(!HX_PROC_SEND_FLAG) - { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - himax_int_enable(private_ts->client->irq,0);//disable irq - val = himax_chip_self_test(private_ts->client); -#ifdef HX_ESD_WORKAROUND - HX_ESD_RESET_ACTIVATE = 1; -#endif - himax_int_enable(private_ts->client->irq,1);//enable irq - - if (val == 0x01) { - ret += snprintf(temp_buf+ret, len-ret, "Self_Test Pass\n"); - } else { - ret += snprintf(temp_buf+ret, len-ret, "Self_Test Fail\n"); - } - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; - return ret; -} - -/* -static ssize_t himax_chip_self_test_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t count) -{ - char buf_tmp[2]; - unsigned long result = 0; - - memset(buf_tmp, 0x0, sizeof(buf_tmp)); - memcpy(buf_tmp, buf, 2); - if(!kstrtoul(buf_tmp, 16, &result)) - { - sel_type = (uint8_t)result; - } - I("sel_type = %x \r\n", sel_type); - return count; -} -*/ - -static const struct file_operations himax_proc_self_test_ops = -{ - .owner = THIS_MODULE, - .read = himax_self_test_read, -}; -#endif - -#ifdef HX_TP_PROC_SENSE_ON_OFF -static ssize_t himax_sense_on_off_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - char buf[80] = {0}; - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf, buff, len)) - { - return -EFAULT; - } - - if(buf[0] == '0') - { - himax_sense_off(private_ts->client); - I("Sense off \n"); - } - else if(buf[0] == '1') - { - if(buf[1] == '1'){ - himax_sense_on(private_ts->client, 0x01); - I("Sense on re-map off, run flash \n"); - }else if(buf[1] == '0'){ - himax_sense_on(private_ts->client, 0x00); - I("Sense on re-map on, run sram \n"); - }else{ - I("Do nothing \n"); - } - } - else - { - I("Do nothing \n"); - } - return len; -} - -static const struct file_operations himax_proc_sense_on_off_ops = -{ - .owner = THIS_MODULE, - .write = himax_sense_on_off_write, -}; -#endif - -#ifdef HX_HIGH_SENSE -static ssize_t himax_HSEN_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts = private_ts; - size_t count = 0; - char *temp_buf; - - if(!HX_PROC_SEND_FLAG) - { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return count; - } - count = snprintf(temp_buf, len, "%d\n", ts->HSEN_enable); - HX_PROC_SEND_FLAG=1; - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - } - else - HX_PROC_SEND_FLAG=0; - return count; -} - -static ssize_t himax_HSEN_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts = private_ts; - char buf[80] = {0}; - - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf, buff, len)) - { - return -EFAULT; - } - - if (buf[0] == '0'){ - ts->HSEN_enable = 0; - } - else if (buf[0] == '1'){ - ts->HSEN_enable = 1; - } - else - return -EINVAL; - - himax_set_HSEN_func(ts->client, ts->HSEN_enable); - - I("%s: HSEN_enable = %d.\n", __func__, ts->HSEN_enable); - - return len; -} - -static const struct file_operations himax_proc_HSEN_ops = -{ - .owner = THIS_MODULE, - .read = himax_HSEN_read, - .write = himax_HSEN_write, -}; -#endif - -#ifdef HX_SMART_WAKEUP -static ssize_t himax_SMWP_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - size_t count = 0; - struct himax_ts_data *ts = private_ts; - char *temp_buf; - - if(!HX_PROC_SEND_FLAG) - { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return count; - } - count = snprintf(temp_buf, len, "%d\n", ts->SMWP_enable); - - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG=1; - } - else - HX_PROC_SEND_FLAG=0; - - return count; -} - -static ssize_t himax_SMWP_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts = private_ts; - char buf[80] = {0}; - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf, buff, len)) - { - return -EFAULT; - } - - - if (buf[0] == '0') - { - ts->SMWP_enable = 0; - } - else if (buf[0] == '1') - { - ts->SMWP_enable = 1; - } - else - return -EINVAL; - - himax_set_SMWP_func(ts->client, ts->SMWP_enable); - HX_SMWP_EN = ts->SMWP_enable; - I("%s: SMART_WAKEUP_enable = %d.\n", __func__, HX_SMWP_EN); - - return len; -} - -static const struct file_operations himax_proc_SMWP_ops = -{ - .owner = THIS_MODULE, - .read = himax_SMWP_read, - .write = himax_SMWP_write, -}; - -static ssize_t himax_GESTURE_read(struct file *file, char *buf, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts = private_ts; - int i =0; - int ret = 0; - char *temp_buf; - - if(!HX_PROC_SEND_FLAG) - { - temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - for(i=0;i<16;i++) - ret += snprintf(temp_buf+ret, len-ret, "ges_en[%d]=%d\n", i, ts->gesture_cust_en[i]); - HX_PROC_SEND_FLAG = 1; - if (copy_to_user(buf, temp_buf, len)) - { - I("%s,here:%d\n", __func__, __LINE__); - } - - kfree(temp_buf); - HX_PROC_SEND_FLAG = 1; - } - else - { - HX_PROC_SEND_FLAG = 0; - ret = 0; - } - return ret; -} - -static ssize_t himax_GESTURE_write(struct file *file, const char *buff, - size_t len, loff_t *pos) -{ - struct himax_ts_data *ts = private_ts; - int i =0; - char buf[80] = {0}; - - if (len >= 80) - { - I("%s: no command exceeds 80 chars.\n", __func__); - return -EFAULT; - } - if (copy_from_user(buf, buff, len)) - { - return -EFAULT; - } - - I("himax_GESTURE_store= %s \n",buf); - for (i=0;i<16;i++) - { - if (buf[i] == '0') - ts->gesture_cust_en[i]= 0; - else if (buf[i] == '1') - ts->gesture_cust_en[i]= 1; - else - ts->gesture_cust_en[i]= 0; - I("gesture en[%d]=%d \n", i, ts->gesture_cust_en[i]); - } - return len; -} - -static const struct file_operations himax_proc_Gesture_ops = -{ - .owner = THIS_MODULE, - .read = himax_GESTURE_read, - .write = himax_GESTURE_write, -}; -#endif - -int himax_touch_proc_init(void) -{ - himax_touch_proc_dir = proc_mkdir( HIMAX_PROC_TOUCH_FOLDER, NULL); - if (himax_touch_proc_dir == NULL) - { - E(" %s: himax_touch_proc_dir file create failed!\n", __func__); - return -ENOMEM; - } - - himax_proc_debug_level_file = proc_create(HIMAX_PROC_DEBUG_LEVEL_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_level_ops); - if (himax_proc_debug_level_file == NULL) - { - E(" %s: proc debug_level file create failed!\n", __func__); - goto fail_1; - } - - himax_proc_vendor_file = proc_create(HIMAX_PROC_VENDOR_FILE, (S_IRUGO),himax_touch_proc_dir, &himax_proc_vendor_ops); - if(himax_proc_vendor_file == NULL) - { - E(" %s: proc vendor file create failed!\n", __func__); - goto fail_2; - } - - himax_proc_attn_file = proc_create(HIMAX_PROC_ATTN_FILE, (S_IRUGO),himax_touch_proc_dir, &himax_proc_attn_ops); - if(himax_proc_attn_file == NULL) - { - E(" %s: proc attn file create failed!\n", __func__); - goto fail_3; - } - - himax_proc_int_en_file = proc_create(HIMAX_PROC_INT_EN_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_int_en_ops); - if(himax_proc_int_en_file == NULL) - { - E(" %s: proc int en file create failed!\n", __func__); - goto fail_4; - } - - himax_proc_layout_file = proc_create(HIMAX_PROC_LAYOUT_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_layout_ops); - if(himax_proc_layout_file == NULL) - { - E(" %s: proc layout file create failed!\n", __func__); - goto fail_5; - } - -#ifdef HX_TP_PROC_RESET - himax_proc_reset_file = proc_create(HIMAX_PROC_RESET_FILE, (S_IWUSR), himax_touch_proc_dir, &himax_proc_reset_ops); - if(himax_proc_reset_file == NULL) - { - E(" %s: proc reset file create failed!\n", __func__); - goto fail_6; - } -#endif - -#ifdef HX_TP_PROC_DIAG - himax_proc_diag_file = proc_create(HIMAX_PROC_DIAG_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_ops); - if(himax_proc_diag_file == NULL) - { - E(" %s: proc diag file create failed!\n", __func__); - goto fail_7; - } - himax_proc_diag_arrange_file = proc_create(HIMAX_PROC_DIAG_ARR_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_arrange_ops); - if(himax_proc_diag_arrange_file == NULL) - { - E(" %s: proc diag file create failed!\n", __func__); - goto fail_7_1; - } -#endif - -#ifdef HX_TP_PROC_REGISTER - himax_proc_register_file = proc_create(HIMAX_PROC_REGISTER_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_register_ops); - if(himax_proc_register_file == NULL) - { - E(" %s: proc register file create failed!\n", __func__); - goto fail_8; - } -#endif - -#ifdef HX_TP_PROC_DEBUG - himax_proc_debug_file = proc_create(HIMAX_PROC_DEBUG_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_ops); - if(himax_proc_debug_file == NULL) - { - E(" %s: proc debug file create failed!\n", __func__); - goto fail_9; - } -#endif - -#ifdef HX_TP_PROC_FLASH_DUMP - himax_proc_flash_dump_file = proc_create(HIMAX_PROC_FLASH_DUMP_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_flash_ops); - if(himax_proc_flash_dump_file == NULL) - { - E(" %s: proc flash dump file create failed!\n", __func__); - goto fail_10; - } -#endif - -#ifdef HX_TP_PROC_SELF_TEST - himax_proc_self_test_file = proc_create(HIMAX_PROC_SELF_TEST_FILE, (S_IRUGO), himax_touch_proc_dir, &himax_proc_self_test_ops); - if(himax_proc_self_test_file == NULL) - { - E(" %s: proc self_test file create failed!\n", __func__); - goto fail_11; - } -#endif - -#ifdef HX_HIGH_SENSE - himax_proc_HSEN_file = proc_create(HIMAX_PROC_HSEN_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_HSEN_ops); - if(himax_proc_HSEN_file == NULL) - { - E(" %s: proc HSEN file create failed!\n", __func__); - goto fail_12; - } -#endif - -#ifdef HX_SMART_WAKEUP - himax_proc_SMWP_file = proc_create(HIMAX_PROC_SMWP_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_SMWP_ops); - if(himax_proc_SMWP_file == NULL) - { - E(" %s: proc SMWP file create failed!\n", __func__); - goto fail_13; - } - himax_proc_GESTURE_file = proc_create(HIMAX_PROC_GESTURE_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_Gesture_ops); - if(himax_proc_GESTURE_file == NULL) - { - E(" %s: proc GESTURE file create failed!\n", __func__); - goto fail_14; - } -#endif - -#ifdef HX_TP_PROC_SENSE_ON_OFF - himax_proc_SENSE_ON_OFF_file = proc_create(HIMAX_PROC_SENSE_ON_OFF_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_sense_on_off_ops); - if(himax_proc_SENSE_ON_OFF_file == NULL) - { - E(" %s: proc SENSE_ON_OFF file create failed!\n", __func__); - goto fail_15; - } -#endif - - return 0 ; - -#ifdef HX_TP_PROC_SENSE_ON_OFF - fail_15: -#endif -#ifdef HX_SMART_WAKEUP - remove_proc_entry( HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir ); - fail_14: - remove_proc_entry( HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir ); - fail_13: -#endif -#ifdef HX_HIGH_SENSE - remove_proc_entry( HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir ); - fail_12: -#endif -#ifdef HX_TP_PROC_SELF_TEST - remove_proc_entry( HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir ); - fail_11: -#endif -#ifdef HX_TP_PROC_FLASH_DUMP - remove_proc_entry( HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir ); - fail_10: -#endif -#ifdef HX_TP_PROC_DEBUG - remove_proc_entry( HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir ); - fail_9: -#endif -#ifdef HX_TP_PROC_REGISTER - remove_proc_entry( HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir ); - fail_8: -#endif -#ifdef HX_TP_PROC_DIAG - remove_proc_entry( HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir ); - fail_7: - remove_proc_entry( HIMAX_PROC_DIAG_ARR_FILE, himax_touch_proc_dir ); - fail_7_1: -#endif -#ifdef HX_TP_PROC_RESET - remove_proc_entry( HIMAX_PROC_RESET_FILE, himax_touch_proc_dir ); - fail_6: -#endif - remove_proc_entry( HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir ); - fail_5: remove_proc_entry( HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir ); - fail_4: remove_proc_entry( HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir ); - fail_3: remove_proc_entry( HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir ); - fail_2: remove_proc_entry( HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir ); - fail_1: remove_proc_entry( HIMAX_PROC_TOUCH_FOLDER, NULL ); - return -ENOMEM; -} - -void himax_touch_proc_deinit(void) -{ -#ifdef HX_TP_PROC_SENSE_ON_OFF - remove_proc_entry( HIMAX_PROC_SENSE_ON_OFF_FILE, himax_touch_proc_dir ); -#endif -#ifdef HX_SMART_WAKEUP - remove_proc_entry( HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir ); -#endif -#ifdef HX_DOT_VIEW - remove_proc_entry( HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir ); -#endif -#ifdef HX_TP_PROC_SELF_TEST - remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir); -#endif -#ifdef HX_TP_PROC_FLASH_DUMP - remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir); -#endif -#ifdef HX_TP_PROC_DEBUG - remove_proc_entry( HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir ); -#endif -#ifdef HX_TP_PROC_REGISTER - remove_proc_entry(HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir); -#endif -#ifdef HX_TP_PROC_DIAG - remove_proc_entry(HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir); -#endif -#ifdef HX_TP_PROC_RESET - remove_proc_entry( HIMAX_PROC_RESET_FILE, himax_touch_proc_dir ); -#endif - remove_proc_entry( HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_TOUCH_FOLDER, NULL ); -} -#endif diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.h b/drivers/input/touchscreen/hxchipset/himax_debug.h deleted file mode 100644 index 91a7ae2eb7ab..000000000000 --- a/drivers/input/touchscreen/hxchipset/himax_debug.h +++ /dev/null @@ -1,181 +0,0 @@ -/* Himax Android Driver Sample Code for Himax chipset -* -* Copyright (C) 2015 Himax Corporation. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#include "himax_platform.h" -#include "himax_common.h" - -#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) - #define HIMAX_PROC_TOUCH_FOLDER "android_touch" - #define HIMAX_PROC_DEBUG_LEVEL_FILE "debug_level" - #define HIMAX_PROC_VENDOR_FILE "vendor" - #define HIMAX_PROC_ATTN_FILE "attn" - #define HIMAX_PROC_INT_EN_FILE "int_en" - #define HIMAX_PROC_LAYOUT_FILE "layout" - - static struct proc_dir_entry *himax_touch_proc_dir; - static struct proc_dir_entry *himax_proc_debug_level_file; - static struct proc_dir_entry *himax_proc_vendor_file; - static struct proc_dir_entry *himax_proc_attn_file; - static struct proc_dir_entry *himax_proc_int_en_file; - static struct proc_dir_entry *himax_proc_layout_file; - - uint8_t HX_PROC_SEND_FLAG; - -extern int himax_touch_proc_init(void); -extern void himax_touch_proc_deinit(void); -bool getFlashDumpGoing(void); - -#ifdef HX_TP_PROC_REGISTER - #define HIMAX_PROC_REGISTER_FILE "register" - struct proc_dir_entry *himax_proc_register_file; - uint8_t register_command[4]; -#endif - -#ifdef HX_TP_PROC_DIAG - #define HIMAX_PROC_DIAG_FILE "diag" - struct proc_dir_entry *himax_proc_diag_file; - #define HIMAX_PROC_DIAG_ARR_FILE "diag_arr" - struct proc_dir_entry *himax_proc_diag_arrange_file; - -#ifdef HX_TP_PROC_2T2R - static bool Is_2T2R; - static uint8_t x_channel_2; - static uint8_t y_channel_2; - static uint8_t *diag_mutual_2; - - int16_t *getMutualBuffer_2(void); - uint8_t getXChannel_2(void); - uint8_t getYChannel_2(void); - - void setMutualBuffer_2(void); - void setXChannel_2(uint8_t x); - void setYChannel_2(uint8_t y); -#endif - uint8_t x_channel; - uint8_t y_channel; - int16_t *diag_mutual; - int16_t *diag_mutual_new; - int16_t *diag_mutual_old; - uint8_t diag_max_cnt; - - int diag_command; - uint8_t diag_coor[128];// = {0xFF}; - int16_t diag_self[100] = {0}; - - int16_t *getMutualBuffer(void); - int16_t *getMutualNewBuffer(void); - int16_t *getMutualOldBuffer(void); - int16_t *getSelfBuffer(void); - uint8_t getDiagCommand(void); - uint8_t getXChannel(void); - uint8_t getYChannel(void); - - void setMutualBuffer(void); - void setMutualNewBuffer(void); - void setMutualOldBuffer(void); - void setXChannel(uint8_t x); - void setYChannel(uint8_t y); - uint8_t coordinate_dump_enable = 0; - struct file *coordinate_fn; -#endif - -#ifdef HX_TP_PROC_DEBUG - #define HIMAX_PROC_DEBUG_FILE "debug" - struct proc_dir_entry *himax_proc_debug_file = NULL; - - bool fw_update_complete = false; - int handshaking_result = 0; - unsigned char debug_level_cmd = 0; - unsigned char upgrade_fw[128*1024]; -#endif - -#ifdef HX_TP_PROC_FLASH_DUMP - #define HIMAX_PROC_FLASH_DUMP_FILE "flash_dump" - struct proc_dir_entry *himax_proc_flash_dump_file = NULL; - - static int Flash_Size = 131072; - static uint8_t *flash_buffer = NULL; - static uint8_t flash_command = 0; - static uint8_t flash_read_step = 0; - static uint8_t flash_progress = 0; - static uint8_t flash_dump_complete = 0; - static uint8_t flash_dump_fail = 0; - static uint8_t sys_operation = 0; - static uint8_t flash_dump_sector = 0; - static uint8_t flash_dump_page = 0; - static bool flash_dump_going = false; - - static uint8_t getFlashCommand(void); - static uint8_t getFlashDumpComplete(void); - static uint8_t getFlashDumpFail(void); - static uint8_t getFlashDumpProgress(void); - static uint8_t getFlashReadStep(void); - //static uint8_t getFlashDumpSector(void); - //static uint8_t getFlashDumpPage(void); - - void setFlashBuffer(void); - uint8_t getSysOperation(void); - - static void setFlashCommand(uint8_t command); - static void setFlashReadStep(uint8_t step); - static void setFlashDumpComplete(uint8_t complete); - static void setFlashDumpFail(uint8_t fail); - static void setFlashDumpProgress(uint8_t progress); - void setSysOperation(uint8_t operation); - static void setFlashDumpSector(uint8_t sector); - static void setFlashDumpPage(uint8_t page); - static void setFlashDumpGoing(bool going); - -#endif - -#ifdef HX_TP_PROC_SELF_TEST - #define HIMAX_PROC_SELF_TEST_FILE "self_test" - struct proc_dir_entry *himax_proc_self_test_file = NULL; - uint32_t **raw_data_array; - uint8_t X_NUM = 0, Y_NUM = 0; - uint8_t sel_type = 0x0D; -#endif - -#ifdef HX_TP_PROC_RESET -#define HIMAX_PROC_RESET_FILE "reset" -extern void himax_HW_reset(uint8_t loadconfig,uint8_t int_off); -struct proc_dir_entry *himax_proc_reset_file = NULL; -#endif - -#ifdef HX_HIGH_SENSE - #define HIMAX_PROC_HSEN_FILE "HSEN" - struct proc_dir_entry *himax_proc_HSEN_file = NULL; -#endif - -#ifdef HX_TP_PROC_SENSE_ON_OFF - #define HIMAX_PROC_SENSE_ON_OFF_FILE "SenseOnOff" - struct proc_dir_entry *himax_proc_SENSE_ON_OFF_file = NULL; -#endif - -#ifdef HX_RST_PIN_FUNC - void himax_HW_reset(uint8_t loadconfig,uint8_t int_off); -#endif - -#ifdef HX_SMART_WAKEUP -#define HIMAX_PROC_SMWP_FILE "SMWP" -struct proc_dir_entry *himax_proc_SMWP_file = NULL; -#define HIMAX_PROC_GESTURE_FILE "GESTURE" -struct proc_dir_entry *himax_proc_GESTURE_file = NULL; -uint8_t HX_SMWP_EN = 0; -//extern bool FAKE_POWER_KEY_SEND; -#endif - -#endif - diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.c b/drivers/input/touchscreen/hxchipset/himax_ic.c deleted file mode 100644 index 6ad8dc03149b..000000000000 --- a/drivers/input/touchscreen/hxchipset/himax_ic.c +++ /dev/null @@ -1,2118 +0,0 @@ -/* Himax Android Driver Sample Code for HMX83100 chipset -* -* Copyright (C) 2015 Himax Corporation. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#include "himax_ic.h" - -static unsigned char i_TP_CRC_FW_128K[]= -{ - #include "HX_CRC_128.i" -}; -static unsigned char i_TP_CRC_FW_64K[]= -{ - #include "HX_CRC_64.i" -}; -static unsigned char i_TP_CRC_FW_124K[]= -{ - #include "HX_CRC_124.i" -}; -static unsigned char i_TP_CRC_FW_60K[]= -{ - #include "HX_CRC_60.i" -}; - - -unsigned long FW_VER_MAJ_FLASH_ADDR; -unsigned long FW_VER_MAJ_FLASH_LENG; -unsigned long FW_VER_MIN_FLASH_ADDR; -unsigned long FW_VER_MIN_FLASH_LENG; -unsigned long CFG_VER_MAJ_FLASH_ADDR; -unsigned long CFG_VER_MAJ_FLASH_LENG; -unsigned long CFG_VER_MIN_FLASH_ADDR; -unsigned long CFG_VER_MIN_FLASH_LENG; - -unsigned char IC_TYPE = 0; -unsigned char IC_CHECKSUM = 0; - -extern struct himax_ic_data* ic_data; - -int himax_hand_shaking(struct i2c_client *client) //0:Running, 1:Stop, 2:I2C Fail -{ - int ret, result; - uint8_t hw_reset_check[1]; - uint8_t hw_reset_check_2[1]; - uint8_t buf0[2]; - uint8_t IC_STATUS_CHECK = 0xAA; - - memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); - memset(hw_reset_check_2, 0x00, sizeof(hw_reset_check_2)); - - buf0[0] = 0xF2; - if (IC_STATUS_CHECK == 0xAA) { - buf0[1] = 0xAA; - IC_STATUS_CHECK = 0x55; - } else { - buf0[1] = 0x55; - IC_STATUS_CHECK = 0xAA; - } - - ret = i2c_himax_master_write(client, buf0, 2, HIMAX_I2C_RETRY_TIMES); - if (ret < 0) { - E("[Himax]:write 0xF2 failed line: %d \n",__LINE__); - goto work_func_send_i2c_msg_fail; - } - msleep(50); - - buf0[0] = 0xF2; - buf0[1] = 0x00; - ret = i2c_himax_master_write(client, buf0, 2, HIMAX_I2C_RETRY_TIMES); - if (ret < 0) { - E("[Himax]:write 0x92 failed line: %d \n",__LINE__); - goto work_func_send_i2c_msg_fail; - } - usleep_range(2000, 4000); - - ret = i2c_himax_read(client, 0xD1, hw_reset_check, 1, HIMAX_I2C_RETRY_TIMES); - if (ret < 0) { - E("[Himax]:i2c_himax_read 0xD1 failed line: %d \n",__LINE__); - goto work_func_send_i2c_msg_fail; - } - - if ((IC_STATUS_CHECK != hw_reset_check[0])) { - usleep_range(2000, 4000); - ret = i2c_himax_read(client, 0xD1, hw_reset_check_2, 1, HIMAX_I2C_RETRY_TIMES); - if (ret < 0) { - E("[Himax]:i2c_himax_read 0xD1 failed line: %d \n",__LINE__); - goto work_func_send_i2c_msg_fail; - } - - if (hw_reset_check[0] == hw_reset_check_2[0]) { - result = 1; - } else { - result = 0; - } - } else { - result = 0; - } - - return result; - -work_func_send_i2c_msg_fail: - return 2; -} - -void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - - if(diag_command != 0) - diag_command = diag_command + 5; - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0x80; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = diag_command; - himax_flash_write_burst(client, tmp_addr, tmp_data); -} - -void himax_flash_dump_func(struct i2c_client *client, uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer) -{ - //struct himax_ts_data *ts = container_of(work, struct himax_ts_data, flash_work); - -// uint8_t sector = 0; -// uint8_t page = 0; - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - uint8_t out_buffer[20]; - uint8_t in_buffer[260] = {0}; - int page_prog_start = 0; - int i = 0; - - himax_sense_off(client); - himax_burst_enable(client, 0); - /*=============Dump Flash Start=============*/ - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - for (page_prog_start = 0; page_prog_start < Flash_Size; page_prog_start = page_prog_start + 256) - { - //================================= - // SPI Transfer Control - // Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF - // Set read start address : 0x8000_0028 ==> 0x0000_0000 - // Set command : 0x8000_0024 ==> 0x0000_003B - //================================= - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x69; tmp_data[2] = 0x40; tmp_data[1] = 0x02; tmp_data[0] = 0xFF; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - if (page_prog_start < 0x100) - { - tmp_data[3] = 0x00; - tmp_data[2] = 0x00; - tmp_data[1] = 0x00; - tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) - { - tmp_data[3] = 0x00; - tmp_data[2] = 0x00; - tmp_data[1] = (uint8_t)(page_prog_start >> 8); - tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) - { - tmp_data[3] = 0x00; - tmp_data[2] = (uint8_t)(page_prog_start >> 16); - tmp_data[1] = (uint8_t)(page_prog_start >> 8); - tmp_data[0] = (uint8_t)page_prog_start; - } - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x3B; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //================================== - // AHB_I2C Burst Read - // Set SPI data register : 0x8000_002C ==> 0x00 - //================================== - out_buffer[0] = 0x2C; - out_buffer[1] = 0x00; - out_buffer[2] = 0x00; - out_buffer[3] = 0x80; - i2c_himax_write(client, 0x00 ,out_buffer, 4, 3); - - //================================== - // Read access : 0x0C ==> 0x00 - //================================== - out_buffer[0] = 0x00; - i2c_himax_write(client, 0x0C ,out_buffer, 1, 3); - - //================================== - // Read 128 bytes two times - //================================== - i2c_himax_read(client, 0x08 ,in_buffer, 128, 3); - for (i = 0; i < 128; i++) - flash_buffer[i + page_prog_start] = in_buffer[i]; - - i2c_himax_read(client, 0x08 ,in_buffer, 128, 3); - for (i = 0; i < 128; i++) - flash_buffer[(i + 128) + page_prog_start] = in_buffer[i]; - - I("%s:Verify Progress: %x\n", __func__, page_prog_start); - } - -/*=============Dump Flash End=============*/ - //msleep(100); - /* - for( i=0 ; i<8 ;i++) - { - for(j=0 ; j<64 ; j++) - { - setFlashDumpProgress(i*32 + j); - } - } - */ - himax_sense_on(client, 0x01); - - return; - -} - -int himax_chip_self_test(struct i2c_client *client) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[128]; - int pf_value=0x00; - uint8_t test_result_id = 0; - int j; - - memset(tmp_addr, 0x00, sizeof(tmp_addr)); - memset(tmp_data, 0x00, sizeof(tmp_data)); - - himax_interface_on(client); - himax_sense_off(client); - - //Set criteria - himax_burst_enable(client, 1); - - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x94; - tmp_data[3] = 0x14; tmp_data[2] = 0xC8; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_data[7] = 0x13; tmp_data[6] = 0x60; tmp_data[5] = 0x0A; tmp_data[4] = 0x99; - - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 8); - - //start selftest - // 0x9008_805C ==> 0x0000_0001 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x5C; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - himax_sense_on(client, 1); - - msleep(2000); - - himax_sense_off(client); - msleep(20); - - //===================================== - // Read test result ID : 0x9008_8078 ==> 0xA/0xB/0xC/0xF - //===================================== - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x78; - himax_register_read(client, tmp_addr, 1, tmp_data); - - test_result_id = tmp_data[0]; - - I("%s: check test result, test_result_id=%x, test_result=%x\n", __func__ - ,test_result_id,tmp_data[0]); - - if (test_result_id==0xF) { - I("[Himax]: self-test pass\n"); - pf_value = 0x1; - } else { - E("[Himax]: self-test fail\n"); - pf_value = 0x0; - } - himax_burst_enable(client, 1); - - for (j = 0;j < 10; j++){ - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x06; tmp_addr[1] = 0x00; tmp_addr[0] = 0x0C; - himax_register_read(client, tmp_addr, 1, tmp_data); - I("[Himax]: 9006000C = %d\n", tmp_data[0]); - if (tmp_data[0] != 0){ - tmp_data[3] = 0x90; tmp_data[2] = 0x06; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - if ( i2c_himax_write(client, 0x00 ,tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - } - tmp_data[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - } - i2c_himax_read(client, 0x08, tmp_data, 124,HIMAX_I2C_RETRY_TIMES); - }else{ - break; - } - } - - himax_sense_on(client, 1); - msleep(120); - - return pf_value; -} - -void himax_set_HSEN_enable(struct i2c_client *client, uint8_t HSEN_enable) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - - himax_burst_enable(client, 0); - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = HSEN_enable; - himax_flash_write_burst(client, tmp_addr, tmp_data); -} -void himax_get_HSEN_enable(struct i2c_client *client,uint8_t *tmp_data) -{ - uint8_t tmp_addr[4]; - - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; - himax_register_read(client, tmp_addr, 1, tmp_data); -} - -void himax_set_SMWP_enable(struct i2c_client *client, uint8_t SMWP_enable) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = SMWP_enable; - himax_flash_write_burst(client, tmp_addr, tmp_data); -} - -void himax_get_SMWP_enable(struct i2c_client *client,uint8_t *tmp_data) -{ - uint8_t tmp_addr[4]; - - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; - himax_register_read(client, tmp_addr, 1, tmp_data); -} - -int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte) -{ - uint8_t tmp_data[4]; - - tmp_data[0] = 0x31; - if ( i2c_himax_write(client, 0x13 ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return -EBUSY; - } - - tmp_data[0] = (0x10 | auto_add_4_byte); - if ( i2c_himax_write(client, 0x0D ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return -EBUSY; - } - return 0; - -} - -void himax_register_read(struct i2c_client *client, uint8_t *read_addr, int read_length, uint8_t *read_data) -{ - uint8_t tmp_data[4]; - int i = 0; - int address = 0; - - if(read_length>256) - { - E("%s: read len over 256!\n", __func__); - return; - } - if (read_length > 1) - himax_burst_enable(client, 1); - else - himax_burst_enable(client, 0); - address = (read_addr[3] << 24) + (read_addr[2] << 16) + (read_addr[1] << 8) + read_addr[0]; - i = address; - tmp_data[0] = (uint8_t)i; - tmp_data[1] = (uint8_t)(i >> 8); - tmp_data[2] = (uint8_t)(i >> 16); - tmp_data[3] = (uint8_t)(i >> 24); - if ( i2c_himax_write(client, 0x00 ,tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - tmp_data[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_read(client, 0x08 ,read_data, read_length * 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - if (read_length > 1) - himax_burst_enable(client, 0); -} - -void himax_flash_read(struct i2c_client *client, uint8_t *reg_byte, uint8_t *read_data) -{ - uint8_t tmpbyte[2]; - - if ( i2c_himax_write(client, 0x00 ,®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(client, 0x01 ,®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(client, 0x02 ,®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(client, 0x03 ,®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - tmpbyte[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_read(client, 0x08 ,&read_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_read(client, 0x09 ,&read_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_read(client, 0x0A ,&read_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_read(client, 0x0B ,&read_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_read(client, 0x18 ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - }// No bus request - - if ( i2c_himax_read(client, 0x0F ,&tmpbyte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - }// idle state - -} - -void himax_flash_write_burst(struct i2c_client *client, uint8_t * reg_byte, uint8_t * write_data) -{ - uint8_t data_byte[8]; - int i = 0, j = 0; - - for (i = 0; i < 4; i++) - { - data_byte[i] = reg_byte[i]; - } - for (j = 4; j < 8; j++) - { - data_byte[j] = write_data[j-4]; - } - - if ( i2c_himax_write(client, 0x00 ,data_byte, 8, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - -} - -int himax_flash_write_burst_lenth(struct i2c_client *client, uint8_t *reg_byte, uint8_t *write_data, int length) -{ - uint8_t data_byte[256]; - int i = 0, j = 0; - - for (i = 0; i < 4; i++) - { - data_byte[i] = reg_byte[i]; - } - for (j = 4; j < length + 4; j++) - { - data_byte[j] = write_data[j - 4]; - } - - if ( i2c_himax_write(client, 0x00 ,data_byte, length + 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return -EBUSY; - } - - return 0; -} - -int himax_register_write(struct i2c_client *client, uint8_t *write_addr, int write_length, uint8_t *write_data) -{ - int i =0, address = 0; - int ret = 0; - - address = (write_addr[3] << 24) + (write_addr[2] << 16) + (write_addr[1] << 8) + write_addr[0]; - - for (i = address; i < address + write_length * 4; i = i + 4) - { - if (write_length > 1) - { - ret = himax_burst_enable(client, 1); - if(ret) - return ret; - } - else - { - ret = himax_burst_enable(client, 0); - if(ret) - return ret; - } - ret = himax_flash_write_burst_lenth(client, write_addr, write_data, write_length * 4); - if(ret < 0) - return ret; - } - - return 0; -} - -void himax_sense_off(struct i2c_client *client) -{ - uint8_t wdt_off = 0x00; - uint8_t tmp_addr[4]; - uint8_t tmp_data[5]; - - himax_burst_enable(client, 0); - - while(wdt_off == 0x00) - { - // 0x9000_800C ==> 0x0000_AC53 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0xAC; tmp_data[0] = 0x53; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Read Watch Dog disable password : 0x9000_800C ==> 0x0000_AC53 - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; - himax_register_read(client, tmp_addr, 1, tmp_data); - - //Check WDT - if (tmp_data[0] == 0x53 && tmp_data[1] == 0xAC && tmp_data[2] == 0x00 && tmp_data[3] == 0x00) - wdt_off = 0x01; - else - wdt_off = 0x00; - } - - // VCOM //0x9008_806C ==> 0x0000_0001 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x6C; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - msleep(20); - - // 0x9000_0010 ==> 0x0000_00DA - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xDA; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Read CPU clock off password : 0x9000_0010 ==> 0x0000_00DA - //===================================== - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - himax_register_read(client, tmp_addr, 1, tmp_data); - I("%s: CPU clock off password data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); - -} - -void himax_interface_on(struct i2c_client *client) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[5]; - - //=========================================== - // Any Cmd for ineterface on : 0x9000_0000 ==> 0x0000_0000 - //=========================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; - himax_flash_read(client, tmp_addr, tmp_data); //avoid RD/WR fail -} - -bool wait_wip(struct i2c_client *client, int Timing) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - uint8_t in_buffer[10]; - //uint8_t out_buffer[20]; - int retry_cnt = 0; - - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - in_buffer[0] = 0x01; - - do - { - //===================================== - // SPI Transfer Control : 0x8000_0020 ==> 0x4200_0003 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x42; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x03; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // SPI Command : 0x8000_0024 ==> 0x0000_0005 - // read 0x8000_002C for 0x01, means wait success - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x05; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - in_buffer[0] = in_buffer[1] = in_buffer[2] = in_buffer[3] = 0xFF; - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; - himax_register_read(client, tmp_addr, 1, in_buffer); - - if ((in_buffer[0] & 0x01) == 0x00) - return true; - - retry_cnt++; - - if (in_buffer[0] != 0x00 || in_buffer[1] != 0x00 || in_buffer[2] != 0x00 || in_buffer[3] != 0x00) - I("%s:Wait wip retry_cnt:%d, buffer[0]=%d, buffer[1]=%d, buffer[2]=%d, buffer[3]=%d \n", __func__, - retry_cnt,in_buffer[0],in_buffer[1],in_buffer[2],in_buffer[3]); - - if (retry_cnt > 100) - { - E("%s: Wait wip error!\n", __func__); - return false; - } - msleep(Timing); - }while ((in_buffer[0] & 0x01) == 0x01); - return true; -} - -void himax_sense_on(struct i2c_client *client, uint8_t FlashMode) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[128]; - - himax_interface_on(client); - himax_burst_enable(client, 0); - //CPU reset - // 0x9000_0014 ==> 0x0000_00CA - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xCA; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Read pull low CPU reset signal : 0x9000_0014 ==> 0x0000_00CA - //===================================== - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; - himax_register_read(client, tmp_addr, 1, tmp_data); - - I("%s: check pull low CPU reset signal data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); - - // 0x9000_0014 ==> 0x0000_0000 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Read revert pull low CPU reset signal : 0x9000_0014 ==> 0x0000_0000 - //===================================== - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; - himax_register_read(client, tmp_addr, 1, tmp_data); - - I("%s: revert pull low CPU reset signal data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); - - //===================================== - // Reset TCON - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - usleep_range(10000, 20000); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - if (FlashMode == 0x00) //SRAM - { - //===================================== - // Re-map - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xF1; - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); - I("%s:83100_Chip_Re-map ON\n", __func__); - } - else - { - //===================================== - // Re-map off - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); - I("%s:83100_Chip_Re-map OFF\n", __func__); - } - //===================================== - // CPU clock on - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); - -} - -void himax_chip_erase(struct i2c_client *client) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - - himax_burst_enable(client, 0); - - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Chip Erase - // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 - // 2. 0x8000_0024 ==> 0x0000_0006 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Chip Erase - // Erase Command : 0x8000_0024 ==> 0x0000_00C7 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xC7; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - msleep(2000); - - if (!wait_wip(client, 100)) - E("%s:83100_Chip_Erase Fail\n", __func__); - -} - -bool himax_block_erase(struct i2c_client *client) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - - himax_burst_enable(client, 0); - - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Chip Erase - // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 - // 2. 0x8000_0024 ==> 0x0000_0006 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Block Erase - // Erase Command : 0x8000_0028 ==> 0x0000_0000 //SPI addr - // 0x8000_0020 ==> 0x6700_0000 //control - // 0x8000_0024 ==> 0x0000_0052 //BE - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x67; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x52; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - msleep(1000); - - if (!wait_wip(client, 100)) - { - E("%s:83100_Erase Fail\n", __func__); - return false; - } - else - { - return true; - } - -} - -bool himax_sector_erase(struct i2c_client *client, int start_addr) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - int page_prog_start = 0; - - himax_burst_enable(client, 0); - - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; - himax_flash_write_burst(client, tmp_addr, tmp_data); - for (page_prog_start = start_addr; page_prog_start < start_addr + 0x0F000; page_prog_start = page_prog_start + 0x1000) - { - //===================================== - // Chip Erase - // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 - // 2. 0x8000_0024 ==> 0x0000_0006 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Sector Erase - // Erase Command : 0x8000_0028 ==> 0x0000_0000 //SPI addr - // 0x8000_0020 ==> 0x6700_0000 //control - // 0x8000_0024 ==> 0x0000_0020 //SE - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - if (page_prog_start < 0x100) - { - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) - { - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) - { - tmp_data[3] = 0x00; tmp_data[2] = (uint8_t)(page_prog_start >> 16); tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; - } - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x67; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x20; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - msleep(200); - - if (!wait_wip(client, 100)) - { - E("%s:83100_Erase Fail\n", __func__); - return false; - } - } - return true; -} - -void himax_sram_write(struct i2c_client *client, uint8_t *FW_content) -{ - int i = 0; - uint8_t tmp_addr[4]; - uint8_t tmp_data[128]; - int FW_length = 0x4000; // 0x4000 = 16K bin file - - //himax_sense_off(client); - - for (i = 0; i < FW_length; i = i + 128) - { - himax_burst_enable(client, 1); - - if (i < 0x100) - { - tmp_addr[3] = 0x08; - tmp_addr[2] = 0x00; - tmp_addr[1] = 0x00; - tmp_addr[0] = i; - } - else if (i >= 0x100 && i < 0x10000) - { - tmp_addr[3] = 0x08; - tmp_addr[2] = 0x00; - tmp_addr[1] = (i >> 8); - tmp_addr[0] = i; - } - - memcpy(&tmp_data[0], &FW_content[i], 128); - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 128); - - } - - if (!wait_wip(client, 100)) - E("%s:83100_Sram_Write Fail\n", __func__); -} - -bool himax_sram_verify(struct i2c_client *client, uint8_t *FW_File, int FW_Size) -{ - int i = 0; - uint8_t out_buffer[20]; - uint8_t in_buffer[128]; - uint8_t *get_fw_content; - - get_fw_content = kzalloc(0x4000*sizeof(uint8_t), GFP_KERNEL); - if (!get_fw_content) - return false; - - for (i = 0; i < 0x4000; i = i + 128) - { - himax_burst_enable(client, 1); - - //================================== - // AHB_I2C Burst Read - //================================== - if (i < 0x100) - { - out_buffer[3] = 0x08; - out_buffer[2] = 0x00; - out_buffer[1] = 0x00; - out_buffer[0] = i; - } - else if (i >= 0x100 && i < 0x10000) - { - out_buffer[3] = 0x08; - out_buffer[2] = 0x00; - out_buffer[1] = (i >> 8); - out_buffer[0] = i; - } - - if ( i2c_himax_write(client, 0x00 ,out_buffer, 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return false; - } - - out_buffer[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,out_buffer, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return false; - } - - if ( i2c_himax_read(client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return false; - } - memcpy(&get_fw_content[i], &in_buffer[0], 128); - } - - for (i = 0; i < FW_Size; i++) - { - if (FW_File[i] != get_fw_content[i]) - { - E("%s: fail! SRAM[%x]=%x NOT CRC_ifile=%x\n", __func__,i,get_fw_content[i],FW_File[i]); - return false; - } - } - - kfree(get_fw_content); - - return true; -} - -void himax_flash_programming(struct i2c_client *client, uint8_t *FW_content, int FW_Size) -{ - int page_prog_start = 0; - int program_length = 48; - int i = 0, j = 0, k = 0; - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - uint8_t buring_data[256]; // Read for flash data, 128K - // 4 bytes for 0x80002C padding - - //himax_interface_on(client); - himax_burst_enable(client, 0); - - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - for (page_prog_start = 0; page_prog_start < FW_Size; page_prog_start = page_prog_start + 256) - { - //msleep(5); - //===================================== - // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 - // 2. 0x8000_0024 ==> 0x0000_0006 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //================================= - // SPI Transfer Control - // Set 256 bytes page write : 0x8000_0020 ==> 0x610F_F000 - // Set read start address : 0x8000_0028 ==> 0x0000_0000 - //================================= - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x61; tmp_data[2] = 0x0F; tmp_data[1] = 0xF0; tmp_data[0] = 0x00; - // data bytes should be 0x6100_0000 + ((word_number)*4-1)*4096 = 0x6100_0000 + 0xFF000 = 0x610F_F000 - // Programmable size = 1 page = 256 bytes, word_number = 256 byte / 4 = 64 - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - //tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; // Flash start address 1st : 0x0000_0000 - - if (page_prog_start < 0x100) - { - tmp_data[3] = 0x00; - tmp_data[2] = 0x00; - tmp_data[1] = 0x00; - tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) - { - tmp_data[3] = 0x00; - tmp_data[2] = 0x00; - tmp_data[1] = (uint8_t)(page_prog_start >> 8); - tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) - { - tmp_data[3] = 0x00; - tmp_data[2] = (uint8_t)(page_prog_start >> 16); - tmp_data[1] = (uint8_t)(page_prog_start >> 8); - tmp_data[0] = (uint8_t)page_prog_start; - } - - himax_flash_write_burst(client, tmp_addr, tmp_data); - - - //================================= - // Send 16 bytes data : 0x8000_002C ==> 16 bytes data - //================================= - buring_data[0] = 0x2C; - buring_data[1] = 0x00; - buring_data[2] = 0x00; - buring_data[3] = 0x80; - - for (i = /*0*/page_prog_start, j = 0; i < 16 + page_prog_start/**/; i++, j++) /// <------ bin file - { - buring_data[j + 4] = FW_content[i]; - } - - - if ( i2c_himax_write(client, 0x00 ,buring_data, 20, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - //================================= - // Write command : 0x8000_0024 ==> 0x0000_0002 - //================================= - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x02; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //================================= - // Send 240 bytes data : 0x8000_002C ==> 240 bytes data - //================================= - - for (j = 0; j < 5; j++) - { - for (i = (page_prog_start + 16 + (j * 48)), k = 0; i < (page_prog_start + 16 + (j * 48)) + program_length; i++, k++) /// <------ bin file - { - buring_data[k+4] = FW_content[i];//(byte)i; - } - - if ( i2c_himax_write(client, 0x00 ,buring_data, program_length+4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - } - - if (!wait_wip(client, 1)) - E("%s:83100_Flash_Programming Fail\n", __func__); - } -} - -bool himax_check_chip_version(struct i2c_client *client) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - uint8_t ret_data = 0x00; - int i = 0; - int ret = 0; - himax_sense_off(client); - for (i = 0; i < 5; i++) - { - // 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver) - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; - ret = himax_register_write(client, tmp_addr, 1, tmp_data); - if(ret) - return false; - - // 2. Set bank as 0 (0x8001_BD01 = 0x0000_0000) - tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xBD; tmp_addr[0] = 0x01; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - ret = himax_register_write(client, tmp_addr, 1, tmp_data); - if(ret) - return false; - - // 3. Read driver ID register RF4H 1 byte (0x8001_F401) - // Driver register RF4H 1 byte value = 0x84H, read back value will become 0x84848484 - tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xF4; tmp_addr[0] = 0x01; - himax_register_read(client, tmp_addr, 1, tmp_data); - ret_data = tmp_data[0]; - - I("%s:Read driver IC ID = %X\n", __func__, ret_data); - if (ret_data == 0x84) - { - IC_TYPE = HX_83100_SERIES_PWON; - //himax_sense_on(client, 0x01); - ret_data = true; - break; - } - else - { - ret_data = false; - E("%s:Read driver ID register Fail:\n", __func__); - } - } - // 4. After read finish, set DDREG_Req = 0 (0x9000_0020 = 0x0000_0000) (Unlock register R/W from driver) - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_register_write(client, tmp_addr, 1, tmp_data); - //himax_sense_on(client, 0x01); - return ret_data; -} - -#if 1 -int himax_check_CRC(struct i2c_client *client, int mode) -{ - bool burnFW_success = false; - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - int tmp_value; - int CRC_value = 0; - - memset(tmp_data, 0x00, sizeof(tmp_data)); - - if (1) - { - if(mode == fw_image_60k) - { - himax_sram_write(client, (i_TP_CRC_FW_60K)); - burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_60K, 0x4000); - } - else if(mode == fw_image_64k) - { - himax_sram_write(client, (i_TP_CRC_FW_64K)); - burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_64K, 0x4000); - } - else if(mode == fw_image_124k) - { - himax_sram_write(client, (i_TP_CRC_FW_124K)); - burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_124K, 0x4000); - } - else if(mode == fw_image_128k) - { - himax_sram_write(client, (i_TP_CRC_FW_128K)); - burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_128K, 0x4000); - } - if (burnFW_success) - { - I("%s: Start to do CRC FW mode=%d \n", __func__,mode); - himax_sense_on(client, 0x00); // run CRC firmware - - while(true) - { - msleep(100); - - tmp_addr[3] = 0x90; - tmp_addr[2] = 0x08; - tmp_addr[1] = 0x80; - tmp_addr[0] = 0x94; - himax_register_read(client, tmp_addr, 1, tmp_data); - - I("%s: CRC from firmware is %x, %x, %x, %x \n", __func__,tmp_data[3], - tmp_data[2],tmp_data[1],tmp_data[0]); - - if (tmp_data[3] == 0xFF && tmp_data[2] == 0xFF && tmp_data[1] == 0xFF && tmp_data[0] == 0xFF) - { - } - else - break; - } - - CRC_value = tmp_data[3]; - - tmp_value = tmp_data[2] << 8; - CRC_value += tmp_value; - - tmp_value = tmp_data[1] << 16; - CRC_value += tmp_value; - - tmp_value = tmp_data[0] << 24; - CRC_value += tmp_value; - - I("%s: CRC Value is %x \n", __func__, CRC_value); - - //Close Remapping - //===================================== - // Re-map close - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); - return CRC_value; - } - else - { - E("%s: SRAM write fail\n", __func__); - return 0; - } - } - else - I("%s: NO CRC Check File \n", __func__); - - return 0; -} - -bool Calculate_CRC_with_AP(unsigned char *FW_content , int CRC_from_FW, int mode) -{ - uint8_t tmp_data[4]; - int i, j; - int fw_data; - int fw_data_2; - int CRC = 0xFFFFFFFF; - int PolyNomial = 0x82F63B78; - int length = 0; - - if (mode == fw_image_128k) - length = 0x8000; - else if (mode == fw_image_124k) - length = 0x7C00; - else if (mode == fw_image_64k) - length = 0x4000; - else //if (mode == fw_image_60k) - length = 0x3C00; - - for (i = 0; i < length; i++) - { - fw_data = FW_content[i * 4 ]; - - for (j = 1; j < 4; j++) - { - fw_data_2 = FW_content[i * 4 + j]; - fw_data += (fw_data_2) << (8 * j); - } - - CRC = fw_data ^ CRC; - - for (j = 0; j < 32; j++) - { - if ((CRC % 2) != 0) - { - CRC = ((CRC >> 1) & 0x7FFFFFFF) ^ PolyNomial; - } - else - { - CRC = (((CRC >> 1) ^ 0x7FFFFFFF)& 0x7FFFFFFF); - } - } - } - - I("%s: CRC calculate from bin file is %x \n", __func__, CRC); - - tmp_data[0] = (uint8_t)(CRC >> 24); - tmp_data[1] = (uint8_t)(CRC >> 16); - tmp_data[2] = (uint8_t)(CRC >> 8); - tmp_data[3] = (uint8_t) CRC; - - CRC = tmp_data[0]; - CRC += tmp_data[1] << 8; - CRC += tmp_data[2] << 16; - CRC += tmp_data[3] << 24; - - I("%s: CRC calculate from bin file REVERSE %x \n", __func__, CRC); - I("%s: CRC calculate from FWis %x \n", __func__, CRC_from_FW); - if (CRC_from_FW == CRC) - return true; - else - return false; -} -#endif - -int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) -{ - int CRC_from_FW = 0; - int burnFW_success = 0; - - if (len != 0x10000) //64k - { - E("%s: The file size is not 64K bytes\n", __func__); - return false; - } - himax_sense_off(client); - msleep(500); - himax_interface_on(client); - if (!himax_sector_erase(client, 0x00000)) - { - E("%s:Sector erase fail!Please restart the IC.\n", __func__); - return false; - } - himax_flash_programming(client, fw, 0x0F000); - - //burnFW_success = himax_83100_Verify(fw, len); - //if(burnFW_success==false) - // return burnFW_success; - - CRC_from_FW = himax_check_CRC(client,fw_image_60k); - burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_60k); - //himax_sense_on(client, 0x01); - return burnFW_success; -} - -int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) -{ - int CRC_from_FW = 0; - int burnFW_success = 0; - - if (len != 0x10000) //64k - { - E("%s: The file size is not 64K bytes\n", __func__); - return false; - } - himax_sense_off(client); - msleep(500); - himax_interface_on(client); - himax_chip_erase(client); - himax_flash_programming(client, fw, len); - - //burnFW_success = himax_83100_Verify(fw, len); - //if(burnFW_success==false) - // return burnFW_success; - - CRC_from_FW = himax_check_CRC(client,fw_image_64k); - burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_64k); - //himax_sense_on(client, 0x01); - return burnFW_success; -} - -int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) -{ - int CRC_from_FW = 0; - int burnFW_success = 0; - - if (len != 0x20000) //128k - { - E("%s: The file size is not 128K bytes\n", __func__); - return false; - } - himax_sense_off(client); - msleep(500); - himax_interface_on(client); - if (!himax_block_erase(client)) - { - E("%s:Block erase fail!Please restart the IC.\n", __func__); - return false; - } - - if (!himax_sector_erase(client, 0x10000)) - { - E("%s:Sector erase fail!Please restart the IC.\n", __func__); - return false; - } - himax_flash_programming(client, fw, 0x1F000); - - - //burnFW_success = himax_83100_Verify(fw, len); - //if(burnFW_success==false) - // return burnFW_success; - - CRC_from_FW = himax_check_CRC(client,fw_image_124k); - burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_124k); - //himax_sense_on(client, 0x01); - return burnFW_success; -} - -int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) -{ - int CRC_from_FW = 0; - int burnFW_success = 0; - - if (len != 0x20000) //128k - { - E("%s: The file size is not 128K bytes\n", __func__); - return false; - } - himax_sense_off(client); - msleep(500); - himax_interface_on(client); - himax_chip_erase(client); - - himax_flash_programming(client, fw, len); - - //burnFW_success = himax_83100_Verify(fw, len); - //if(burnFW_success==false) - // return burnFW_success; - - CRC_from_FW = himax_check_CRC(client,fw_image_128k); - burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_128k); - //himax_sense_on(client, 0x01); - return burnFW_success; -} - -void himax_touch_information(struct i2c_client *client) -{ - uint8_t cmd[4]; - char data[12] = {0}; - - I("%s:IC_TYPE =%d\n", __func__,IC_TYPE); - - if(IC_TYPE == HX_83100_SERIES_PWON) - { - cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xF8; - himax_register_read(client, cmd, 1, data); - - ic_data->HX_RX_NUM = data[1]; - ic_data->HX_TX_NUM = data[2]; - ic_data->HX_MAX_PT = data[3]; - - cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xFC; - himax_register_read(client, cmd, 1, data); - - if((data[1] & 0x04) == 0x04) { - ic_data->HX_XY_REVERSE = true; - } else { - ic_data->HX_XY_REVERSE = false; - } - ic_data->HX_Y_RES = data[3]*256; - cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x01; cmd[0] = 0x00; - himax_register_read(client, cmd, 1, data); - ic_data->HX_Y_RES = ic_data->HX_Y_RES + data[0]; - ic_data->HX_X_RES = data[1]*256 + data[2]; - cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0x8C; - himax_register_read(client, cmd, 1, data); - if((data[0] & 0x01) == 1) { - ic_data->HX_INT_IS_EDGE = true; - } else { - ic_data->HX_INT_IS_EDGE = false; - } - if (ic_data->HX_RX_NUM > 40) - ic_data->HX_RX_NUM = 29; - if (ic_data->HX_TX_NUM > 20) - ic_data->HX_TX_NUM = 16; - if (ic_data->HX_MAX_PT > 10) - ic_data->HX_MAX_PT = 10; - if (ic_data->HX_Y_RES > 2000) - ic_data->HX_Y_RES = 1280; - if (ic_data->HX_X_RES > 2000) - ic_data->HX_X_RES = 720; -#ifdef HX_EN_MUT_BUTTON - cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xE8; - himax_register_read(client, cmd, 1, data); - ic_data->HX_BT_NUM = data[3]; -#endif - I("%s:HX_RX_NUM =%d,HX_TX_NUM =%d,HX_MAX_PT=%d \n", __func__,ic_data->HX_RX_NUM,ic_data->HX_TX_NUM,ic_data->HX_MAX_PT); - I("%s:HX_XY_REVERSE =%d,HX_Y_RES =%d,HX_X_RES=%d \n", __func__,ic_data->HX_XY_REVERSE,ic_data->HX_Y_RES,ic_data->HX_X_RES); - I("%s:HX_INT_IS_EDGE =%d \n", __func__,ic_data->HX_INT_IS_EDGE); - } - else - { - ic_data->HX_RX_NUM = 0; - ic_data->HX_TX_NUM = 0; - ic_data->HX_BT_NUM = 0; - ic_data->HX_X_RES = 0; - ic_data->HX_Y_RES = 0; - ic_data->HX_MAX_PT = 0; - ic_data->HX_XY_REVERSE = false; - ic_data->HX_INT_IS_EDGE = false; - } -} - -void himax_read_FW_ver(struct i2c_client *client) -{ - uint8_t cmd[4]; - uint8_t data[64] = {0}; - - //===================================== - // Read FW version : 0x0000_E303 - //===================================== - cmd[3] = 0x00; cmd[2] = 0x00; cmd[1] = 0xE3; cmd[0] = 0x00; - himax_register_read(client, cmd, 1, data); - - ic_data->vendor_config_ver = data[3]<<8; - - cmd[3] = 0x00; cmd[2] = 0x00; cmd[1] = 0xE3; cmd[0] = 0x04; - himax_register_read(client, cmd, 1, data); - - ic_data->vendor_config_ver = data[0] | ic_data->vendor_config_ver; - I("CFG_VER : %X \n",ic_data->vendor_config_ver); - - cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0x28; - himax_register_read(client, cmd, 1, data); - - ic_data->vendor_fw_ver = data[0]<<8 | data[1]; - I("FW_VER : %X \n",ic_data->vendor_fw_ver); - - - return; -} - -bool himax_ic_package_check(struct i2c_client *client) -{ -#if 0 - uint8_t cmd[3]; - uint8_t data[3]; - - memset(cmd, 0x00, sizeof(cmd)); - memset(data, 0x00, sizeof(data)); - - if (i2c_himax_read(client, 0xD1, cmd, 3, HIMAX_I2C_RETRY_TIMES) < 0) - return false ; - - if (i2c_himax_read(client, 0x31, data, 3, HIMAX_I2C_RETRY_TIMES) < 0) - return false; - - if((data[0] == 0x85 && data[1] == 0x29)) - { - IC_TYPE = HX_85XX_F_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 64901; //0xFD85 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 64902; //0xFD86 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 64928; //0xFDA0 - CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 64940; //0xFDAC - CFG_VER_MIN_FLASH_LENG = 12; - I("Himax IC package 852x F\n"); - } - if((data[0] == 0x85 && data[1] == 0x30) || (cmd[0] == 0x05 && cmd[1] == 0x85 && cmd[2] == 0x29)) - { - IC_TYPE = HX_85XX_E_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; //0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 134; //0x0086 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 160; //0x00A0 - CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 172; //0x00AC - CFG_VER_MIN_FLASH_LENG = 12; - I("Himax IC package 852x E\n"); - } - else if((data[0] == 0x85 && data[1] == 0x31)) - { - IC_TYPE = HX_85XX_ES_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; //0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 134; //0x0086 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 160; //0x00A0 - CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 172; //0x00AC - CFG_VER_MIN_FLASH_LENG = 12; - I("Himax IC package 852x ES\n"); - } - else if ((data[0] == 0x85 && data[1] == 0x28) || (cmd[0] == 0x04 && cmd[1] == 0x85 && - (cmd[2] == 0x26 || cmd[2] == 0x27 || cmd[2] == 0x28))) { - IC_TYPE = HX_85XX_D_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; // 0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 134; // 0x0086 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 160; // 0x00A0 - CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 172; // 0x00AC - CFG_VER_MIN_FLASH_LENG = 12; - I("Himax IC package 852x D\n"); - } else if ((data[0] == 0x85 && data[1] == 0x23) || (cmd[0] == 0x03 && cmd[1] == 0x85 && - (cmd[2] == 0x26 || cmd[2] == 0x27 || cmd[2] == 0x28 || cmd[2] == 0x29))) { - IC_TYPE = HX_85XX_C_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; // 0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 134; // 0x0086 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 135; // 0x0087 - CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 147; // 0x0093 - CFG_VER_MIN_FLASH_LENG = 12; - I("Himax IC package 852x C\n"); - } else if ((data[0] == 0x85 && data[1] == 0x26) || - (cmd[0] == 0x02 && cmd[1] == 0x85 && - (cmd[2] == 0x19 || cmd[2] == 0x25 || cmd[2] == 0x26))) { - IC_TYPE = HX_85XX_B_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; // 0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 728; // 0x02D8 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 692; // 0x02B4 - CFG_VER_MAJ_FLASH_LENG = 3; - CFG_VER_MIN_FLASH_ADDR = 704; // 0x02C0 - CFG_VER_MIN_FLASH_LENG = 3; - I("Himax IC package 852x B\n"); - } else if ((data[0] == 0x85 && data[1] == 0x20) || (cmd[0] == 0x01 && - cmd[1] == 0x85 && cmd[2] == 0x19)) { - IC_TYPE = HX_85XX_A_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; - I("Himax IC package 852x A\n"); - } else { - E("Himax IC package incorrect!!\n"); - }*/ -#else - IC_TYPE = HX_83100_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 57384; //0xE028 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 57385; //0xE029 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 58115; //0xE303 - CFG_VER_MAJ_FLASH_LENG = 1; - CFG_VER_MIN_FLASH_ADDR = 58116; //0xE304 - CFG_VER_MIN_FLASH_LENG = 1; - I("Himax IC package 83100_in\n"); - -#endif - return true; -} - -void himax_read_event_stack(struct i2c_client *client, uint8_t *buf, uint8_t length) -{ - uint8_t cmd[4]; - - cmd[3] = 0x90; cmd[2] = 0x06; cmd[1] = 0x00; cmd[0] = 0x00; - if ( i2c_himax_write(client, 0x00 ,cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - } - - cmd[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - } - - i2c_himax_read(client, 0x08, buf, length, HIMAX_I2C_RETRY_TIMES); -} - -#if 0 -static void himax_83100_Flash_Write(uint8_t * reg_byte, uint8_t * write_data) -{ - uint8_t tmpbyte[2]; - - if ( i2c_himax_write(private_ts->client, 0x00 ,®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x01 ,®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x02 ,®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x03 ,®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x04 ,&write_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x05 ,&write_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x06 ,&write_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x07 ,&write_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if (isBusrtOn == false) - { - tmpbyte[0] = 0x01; - if ( i2c_himax_write(private_ts->client, 0x0C ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - } -} -#endif -#if 0 -static void himax_83100_Flash_Burst_Write(uint8_t * reg_byte, uint8_t * write_data) -{ - //uint8_t tmpbyte[2]; - int i = 0; - - if ( i2c_himax_write(private_ts->client, 0x00 ,®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x01 ,®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x02 ,®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x03 ,®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - // Write 256 bytes with continue burst mode - for (i = 0; i < 256; i = i + 4) - { - if ( i2c_himax_write(private_ts->client, 0x04 ,&write_data[i], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x05 ,&write_data[i+1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x06 ,&write_data[i+2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_write(private_ts->client, 0x07 ,&write_data[i+3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - } - - //if (isBusrtOn == false) - //{ - // tmpbyte[0] = 0x01; - // if ( i2c_himax_write(private_ts->client, 0x0C ,&tmpbyte[0], 1, 3) < 0) { - // E("%s: i2c access fail!\n", __func__); - // return; - // } - //} - -} -#endif - -#if 0 -static bool himax_83100_Verify(uint8_t *FW_File, int FW_Size) -{ - uint8_t tmp_addr[4]; - uint8_t tmp_data[4]; - uint8_t out_buffer[20]; - uint8_t in_buffer[260]; - - int fail_addr=0, fail_cnt=0; - int page_prog_start = 0; - int i = 0; - - himax_interface_on(private_ts->client); - himax_burst_enable(private_ts->client, 0); - - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; - himax_83100_Flash_Write(tmp_addr, tmp_data); - - for (page_prog_start = 0; page_prog_start < FW_Size; page_prog_start = page_prog_start + 256) - { - //================================= - // SPI Transfer Control - // Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF - // Set read start address : 0x8000_0028 ==> 0x0000_0000 - // Set command : 0x8000_0024 ==> 0x0000_003B - //================================= - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x69; tmp_data[2] = 0x40; tmp_data[1] = 0x02; tmp_data[0] = 0xFF; - himax_83100_Flash_Write(tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - if (page_prog_start < 0x100) - { - tmp_data[3] = 0x00; - tmp_data[2] = 0x00; - tmp_data[1] = 0x00; - tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) - { - tmp_data[3] = 0x00; - tmp_data[2] = 0x00; - tmp_data[1] = (uint8_t)(page_prog_start >> 8); - tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) - { - tmp_data[3] = 0x00; - tmp_data[2] = (uint8_t)(page_prog_start >> 16); - tmp_data[1] = (uint8_t)(page_prog_start >> 8); - tmp_data[0] = (uint8_t)page_prog_start; - } - himax_83100_Flash_Write(tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x3B; - himax_83100_Flash_Write(tmp_addr, tmp_data); - - //================================== - // AHB_I2C Burst Read - // Set SPI data register : 0x8000_002C ==> 0x00 - //================================== - out_buffer[0] = 0x2C; - out_buffer[1] = 0x00; - out_buffer[2] = 0x00; - out_buffer[3] = 0x80; - i2c_himax_write(private_ts->client, 0x00 ,out_buffer, 4, HIMAX_I2C_RETRY_TIMES); - - //================================== - // Read access : 0x0C ==> 0x00 - //================================== - out_buffer[0] = 0x00; - i2c_himax_write(private_ts->client, 0x0C ,out_buffer, 1, HIMAX_I2C_RETRY_TIMES); - - //================================== - // Read 128 bytes two times - //================================== - i2c_himax_read(private_ts->client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES); - for (i = 0; i < 128; i++) - flash_buffer[i + page_prog_start] = in_buffer[i]; - - i2c_himax_read(private_ts->client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES); - for (i = 0; i < 128; i++) - flash_buffer[(i + 128) + page_prog_start] = in_buffer[i]; - - //tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; - //himax_register_read(tmp_addr, 32, out in_buffer); - //for (int i = 0; i < 128; i++) - // flash_buffer[i + page_prog_start] = in_buffer[i]; - //tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; - //himax_register_read(tmp_addr, 32, out in_buffer); - //for (int i = 0; i < 128; i++) - // flash_buffer[i + page_prog_start] = in_buffer[i]; - - I("%s:Verify Progress: %x\n", __func__, page_prog_start); - } - - fail_cnt = 0; - for (i = 0; i < FW_Size; i++) - { - if (FW_File[i] != flash_buffer[i]) - { - if (fail_cnt == 0) - fail_addr = i; - - fail_cnt++; - //E("%s Fail Block:%x\n", __func__, i); - //return false; - } - } - if (fail_cnt > 0) - { - E("%s:Start Fail Block:%x and fail block count=%x\n" , __func__,fail_addr,fail_cnt); - return false; - } - - I("%s:Byte read verify pass.\n", __func__); - return true; - -} -#endif - -void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data) -{ - int i; - int cnt = 0; - unsigned char tmp_addr[4]; - unsigned char tmp_data[4]; - uint8_t max_i2c_size = 32; - int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2; - int total_size_4bytes = total_size / 4; - int total_read_times = 0; - unsigned long address = 0x08000468; - tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x5A; tmp_data[0] = 0xA5; - himax_flash_write_burst(client, tmp_addr, tmp_data); - do - { - cnt++; - himax_register_read(client, tmp_addr, 1, tmp_data); - usleep_range(10000, 20000); - } while ((tmp_data[1] != 0xA5 || tmp_data[0] != 0x5A) && cnt < 100); - tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x68; - if (total_size_4bytes % max_i2c_size == 0) - { - total_read_times = total_size_4bytes / max_i2c_size; - } - else - { - total_read_times = total_size_4bytes / max_i2c_size + 1; - } - for (i = 0; i < (total_read_times); i++) - { - if ( total_size_4bytes >= max_i2c_size) - { - himax_register_read(client, tmp_addr, max_i2c_size, &info_data[i*max_i2c_size*4]); - total_size_4bytes = total_size_4bytes - max_i2c_size; - } - else - { - himax_register_read(client, tmp_addr, total_size_4bytes % max_i2c_size, &info_data[i*max_i2c_size*4]); - } - address += max_i2c_size*4; - tmp_addr[1] = (uint8_t)((address>>8)&0x00FF); - tmp_addr[0] = (uint8_t)((address)&0x00FF); - } - tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; - tmp_data[3] = 0x11; tmp_data[2] = 0x22; tmp_data[1] = 0x33; tmp_data[0] = 0x44; - himax_flash_write_burst(client, tmp_addr, tmp_data); -} -//ts_work -int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max){ - int RawDataLen; - if (raw_cnt_rmd != 0x00) { - RawDataLen = 124 - ((HX_MAX_PT+raw_cnt_max+3)*4) - 1; - }else{ - RawDataLen = 124 - ((HX_MAX_PT+raw_cnt_max+2)*4) - 1; - } - return RawDataLen; -} - -bool read_event_stack(struct i2c_client *client, uint8_t *buf, int length) -{ - uint8_t cmd[4]; - - if(length > 56) - length = 124; - //===================== - //AHB I2C Burst Read - //===================== - cmd[0] = 0x31; - if ( i2c_himax_write(client, 0x13 ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - goto err_workqueue_out; - } - - cmd[0] = 0x10; - if ( i2c_himax_write(client, 0x0D ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - goto err_workqueue_out; - } - //===================== - //Read event stack - //===================== - cmd[3] = 0x90; cmd[2] = 0x06; cmd[1] = 0x00; cmd[0] = 0x00; - if ( i2c_himax_write(client, 0x00 ,cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - goto err_workqueue_out; - } - - cmd[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - goto err_workqueue_out; - } - i2c_himax_read(client, 0x08, buf, length,HIMAX_I2C_RETRY_TIMES); - return 1; - - err_workqueue_out: - return 0; -} - -bool post_read_event_stack(struct i2c_client *client) -{ - return 1; -} -bool diag_check_sum( uint8_t hx_touch_info_size, uint8_t *buf) //return checksum value -{ - uint16_t check_sum_cal = 0; - int i; - - //Check 124th byte CRC - for (i = hx_touch_info_size, check_sum_cal = 0; i < 124; i=i+2) - { - check_sum_cal += (buf[i+1]*256 + buf[i]); - } - if (check_sum_cal % 0x10000 != 0) - { - I("%s: diag check sum fail! check_sum_cal=%X, hx_touch_info_size=%d, \n",__func__,check_sum_cal, hx_touch_info_size); - return 0; - } - return 1; -} - - -void diag_parse_raw_data(int hx_touch_info_size, int RawDataLen, int mul_num, int self_num, uint8_t *buf, uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data) -{ - int RawDataLen_word; - int index = 0; - int temp1, temp2,i; - - if (buf[hx_touch_info_size] == 0x3A && buf[hx_touch_info_size+1] == 0xA3 && buf[hx_touch_info_size+2] > 0 && buf[hx_touch_info_size+3] == diag_cmd+5 ) - { - RawDataLen_word = RawDataLen/2; - index = (buf[hx_touch_info_size+2] - 1) * RawDataLen_word; - //I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num); - for (i = 0; i < RawDataLen_word; i++) - { - temp1 = index + i; - - if (temp1 < mul_num) - { //mutual - mutual_data[index + i] = buf[i*2 + hx_touch_info_size+4+1]*256 + buf[i*2 + hx_touch_info_size+4]; //4: RawData Header, 1:HSB - } - else - {//self - temp1 = i + index; - temp2 = self_num + mul_num; - - if (temp1 >= temp2) - { - break; - } - - self_data[i+index-mul_num] = buf[i*2 + hx_touch_info_size+4]; //4: RawData Header - self_data[i+index-mul_num+1] = buf[i*2 + hx_touch_info_size+4+1]; - } - } - } - else - { - I("[HIMAX TP MSG]%s: header format is wrong!\n", __func__); - I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num); - } -} diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.h b/drivers/input/touchscreen/hxchipset/himax_ic.h deleted file mode 100644 index 18cd12b8b36f..000000000000 --- a/drivers/input/touchscreen/hxchipset/himax_ic.h +++ /dev/null @@ -1,82 +0,0 @@ -/* Himax Android Driver Sample Code for HMX83100 chipset -* -* Copyright (C) 2015 Himax Corporation. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#include "himax_platform.h" -#include "himax_common.h" - -#include - - -#define HX_85XX_A_SERIES_PWON 1 -#define HX_85XX_B_SERIES_PWON 2 -#define HX_85XX_C_SERIES_PWON 3 -#define HX_85XX_D_SERIES_PWON 4 -#define HX_85XX_E_SERIES_PWON 5 -#define HX_85XX_ES_SERIES_PWON 6 -#define HX_85XX_F_SERIES_PWON 7 -#define HX_83100_SERIES_PWON 8 - -#define HX_TP_BIN_CHECKSUM_SW 1 -#define HX_TP_BIN_CHECKSUM_HW 2 -#define HX_TP_BIN_CHECKSUM_CRC 3 - -enum fw_image_type { - fw_image_60k = 0x01, - fw_image_64k, - fw_image_124k, - fw_image_128k, -}; - -int himax_hand_shaking(struct i2c_client *client); -void himax_set_SMWP_enable(struct i2c_client *client,uint8_t SMWP_enable); -void himax_get_SMWP_enable(struct i2c_client *client,uint8_t *tmp_data); -void himax_set_HSEN_enable(struct i2c_client *client,uint8_t HSEN_enable); -void himax_get_HSEN_enable(struct i2c_client *client,uint8_t *tmp_data); -void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command); -void himax_flash_dump_func(struct i2c_client *client, uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer); -int himax_chip_self_test(struct i2c_client *client); -int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte); ////himax_83100_BURST_INC0_EN -void himax_register_read(struct i2c_client *client, uint8_t *read_addr, int read_length, uint8_t *read_data); ////RegisterRead83100 -void himax_flash_read(struct i2c_client *client, uint8_t *reg_byte, uint8_t *read_data); ////himax_83100_Flash_Read -void himax_flash_write_burst(struct i2c_client *client, uint8_t * reg_byte, uint8_t * write_data); ////himax_83100_Flash_Write_Burst -int himax_flash_write_burst_lenth(struct i2c_client *client, uint8_t *reg_byte, uint8_t *write_data, int length); ////himax_83100_Flash_Write_Burst_lenth -int himax_register_write(struct i2c_client *client, uint8_t *write_addr, int write_length, uint8_t *write_data); ////RegisterWrite83100 -void himax_sense_off(struct i2c_client *client); ////himax_83100_SenseOff -void himax_interface_on(struct i2c_client *client); ////himax_83100_Interface_on -bool wait_wip(struct i2c_client *client, int Timing); -void himax_sense_on(struct i2c_client *client, uint8_t FlashMode); ////himax_83100_SenseOn -void himax_chip_erase(struct i2c_client *client); ////himax_83100_Chip_Erase -bool himax_block_erase(struct i2c_client *client); ////himax_83100_Block_Erase -bool himax_sector_erase(struct i2c_client *client, int start_addr); ////himax_83100_Sector_Erase -void himax_sram_write(struct i2c_client *client, uint8_t *FW_content); ////himax_83100_Sram_Write -bool himax_sram_verify(struct i2c_client *client, uint8_t *FW_File, int FW_Size); ////himax_83100_Sram_Verify -void himax_flash_programming(struct i2c_client *client, uint8_t *FW_content, int FW_Size); ////himax_83100_Flash_Programming -bool himax_check_chip_version(struct i2c_client *client); ////himax_83100_CheckChipVersion -int himax_check_CRC(struct i2c_client *client, int mode); ////himax_83100_Check_CRC -bool Calculate_CRC_with_AP(unsigned char *FW_content , int CRC_from_FW, int mode); -int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); -int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); -int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); -int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); -void himax_touch_information(struct i2c_client *client); -void himax_read_FW_ver(struct i2c_client *client); -bool himax_ic_package_check(struct i2c_client *client); -void himax_read_event_stack(struct i2c_client *client, uint8_t *buf, uint8_t length); -int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max); -bool read_event_stack(struct i2c_client *client, uint8_t *buf_ts, int length); -bool post_read_event_stack(struct i2c_client *client); -bool diag_check_sum( uint8_t hx_touch_info_size, uint8_t *buf_ts); //return checksum value -void diag_parse_raw_data(int hx_touch_info_size, int RawDataLen, int mul_num, int self_num, uint8_t *buf_ts, uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data); -void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data); \ No newline at end of file diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.c b/drivers/input/touchscreen/hxchipset/himax_platform.c deleted file mode 100644 index 7e8a1d6572c5..000000000000 --- a/drivers/input/touchscreen/hxchipset/himax_platform.c +++ /dev/null @@ -1,796 +0,0 @@ -/* Himax Android Driver Sample Code for HIMAX chipset -* -* Copyright (C) 2015 Himax Corporation. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#include "himax_platform.h" -#include "himax_common.h" - -int irq_enable_count = 0; -#ifdef HX_SMART_WAKEUP -#define TS_WAKE_LOCK_TIMEOUT (2 * HZ) -#endif - -#define PINCTRL_STATE_ACTIVE "pmx_ts_active" -#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend" -#define PINCTRL_STATE_RELEASE "pmx_ts_release" - -extern struct himax_ic_data* ic_data; -extern void himax_ts_work(struct himax_ts_data *ts); -extern enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer); -extern int himax_ts_init(struct himax_ts_data *ts); - -extern int tp_rst_gpio; - -#ifdef HX_TP_PROC_DIAG -extern uint8_t getDiagCommand(void); -#endif - -void himax_vk_parser(struct device_node *dt, - struct himax_i2c_platform_data *pdata) -{ - u32 data = 0; - uint8_t cnt = 0, i = 0; - uint32_t coords[4] = {0}; - struct device_node *node, *pp = NULL; - struct himax_virtual_key *vk; - - node = of_parse_phandle(dt, "virtualkey", 0); - if (node == NULL) { - I(" DT-No vk info in DT"); - return; - } else { - while ((pp = of_get_next_child(node, pp))) - cnt++; - if (!cnt) - return; - - vk = kzalloc(cnt * (sizeof *vk), GFP_KERNEL); - if (!vk) - return; - pp = NULL; - while ((pp = of_get_next_child(node, pp))) { - if (of_property_read_u32(pp, "idx", &data) == 0) - vk[i].index = data; - if (of_property_read_u32_array(pp, "range", coords, 4) == 0) { - vk[i].x_range_min = coords[0], vk[i].x_range_max = coords[1]; - vk[i].y_range_min = coords[2], vk[i].y_range_max = coords[3]; - } else - I(" range faile"); - i++; - } - pdata->virtual_key = vk; - for (i = 0; i < cnt; i++) - I(" vk[%d] idx:%d x_min:%d, y_max:%d", i,pdata->virtual_key[i].index, - pdata->virtual_key[i].x_range_min, pdata->virtual_key[i].y_range_max); - } -} - -int himax_parse_dt(struct himax_ts_data *ts, - struct himax_i2c_platform_data *pdata) -{ - int rc, coords_size = 0; - uint32_t coords[4] = {0}; - struct property *prop; - struct device_node *dt = ts->client->dev.of_node; - u32 data = 0; - - prop = of_find_property(dt, "himax,panel-coords", NULL); - if (prop) { - coords_size = prop->length / sizeof(u32); - if (coords_size != 4) - D(" %s:Invalid panel coords size %d", __func__, coords_size); - } - - if (of_property_read_u32_array(dt, "himax,panel-coords", coords, coords_size) == 0) { - pdata->abs_x_min = coords[0], pdata->abs_x_max = coords[1]; - pdata->abs_y_min = coords[2], pdata->abs_y_max = coords[3]; - I(" DT-%s:panel-coords = %d, %d, %d, %d\n", __func__, pdata->abs_x_min, - pdata->abs_x_max, pdata->abs_y_min, pdata->abs_y_max); - } - - prop = of_find_property(dt, "himax,display-coords", NULL); - if (prop) { - coords_size = prop->length / sizeof(u32); - if (coords_size != 4) - D(" %s:Invalid display coords size %d", __func__, coords_size); - } - rc = of_property_read_u32_array(dt, "himax,display-coords", coords, coords_size); - if (rc && (rc != -EINVAL)) { - D(" %s:Fail to read display-coords %d\n", __func__, rc); - return rc; - } - pdata->screenWidth = coords[1]; - pdata->screenHeight = coords[3]; - I(" DT-%s:display-coords = (%d, %d)", __func__, pdata->screenWidth, - pdata->screenHeight); - - pdata->gpio_irq = of_get_named_gpio(dt, "himax,irq-gpio", 0); - if (!gpio_is_valid(pdata->gpio_irq)) { - I(" DT:gpio_irq value is not valid\n"); - } - - pdata->gpio_reset = of_get_named_gpio(dt, "himax,rst-gpio", 0); - if (!gpio_is_valid(pdata->gpio_reset)) { - I(" DT:gpio_rst value is not valid\n"); - } - pdata->gpio_3v3_en = of_get_named_gpio(dt, "himax,3v3-gpio", 0); - if (!gpio_is_valid(pdata->gpio_3v3_en)) { - I(" DT:gpio_3v3_en value is not valid\n"); - } - I(" DT:gpio_irq=%d, gpio_rst=%d, gpio_3v3_en=%d", pdata->gpio_irq, pdata->gpio_reset, pdata->gpio_3v3_en); - - if (of_property_read_u32(dt, "report_type", &data) == 0) { - pdata->protocol_type = data; - I(" DT:protocol_type=%d", pdata->protocol_type); - } - - himax_vk_parser(dt, pdata); - - return 0; -} - -int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) -{ - int retry; - struct i2c_msg msg[] = { - { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = &command, - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .len = length, - .buf = data, - } - }; - - for (retry = 0; retry < toRetry; retry++) { - if (i2c_transfer(client->adapter, msg, 2) == 2) - break; - msleep(20); - } - if (retry == toRetry) { - E("%s: i2c_read_block retry over %d\n", - __func__, toRetry); - return -EIO; - } - return 0; - -} - -int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) -{ - int retry/*, loop_i*/; - uint8_t buf[length + 1]; - - struct i2c_msg msg[] = { - { - .addr = client->addr, - .flags = 0, - .len = length + 1, - .buf = buf, - } - }; - - buf[0] = command; - memcpy(buf+1, data, length); - - for (retry = 0; retry < toRetry; retry++) { - if (i2c_transfer(client->adapter, msg, 1) == 1) - break; - msleep(20); - } - - if (retry == toRetry) { - E("%s: i2c_write_block retry over %d\n", - __func__, toRetry); - return -EIO; - } - return 0; - -} - -int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry) -{ - int retry; - struct i2c_msg msg[] = { - { - .addr = client->addr, - .flags = I2C_M_RD, - .len = length, - .buf = data, - } - }; - - for (retry = 0; retry < toRetry; retry++) { - if (i2c_transfer(client->adapter, msg, 1) == 1) - break; - msleep(20); - } - if (retry == toRetry) { - E("%s: i2c_read_block retry over %d\n", - __func__, toRetry); - return -EIO; - } - return 0; -} - -int i2c_himax_write_command(struct i2c_client *client, uint8_t command, uint8_t toRetry) -{ - return i2c_himax_write(client, command, NULL, 0, toRetry); -} - -int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t length, uint8_t toRetry) -{ - int retry/*, loop_i*/; - uint8_t buf[length]; - - struct i2c_msg msg[] = { - { - .addr = client->addr, - .flags = 0, - .len = length, - .buf = buf, - } - }; - - memcpy(buf, data, length); - - for (retry = 0; retry < toRetry; retry++) { - if (i2c_transfer(client->adapter, msg, 1) == 1) - break; - msleep(20); - } - - if (retry == toRetry) { - E("%s: i2c_write_block retry over %d\n", - __func__, toRetry); - return -EIO; - } - return 0; -} - -void himax_int_enable(int irqnum, int enable) -{ - if (enable == 1 && irq_enable_count == 0) { - enable_irq(irqnum); - irq_enable_count++; - } else if (enable == 0 && irq_enable_count == 1) { - disable_irq_nosync(irqnum); - irq_enable_count--; - } - I("irq_enable_count = %d", irq_enable_count); -} - -void himax_rst_gpio_set(int pinnum, uint8_t value) -{ - gpio_direction_output(pinnum, value); -} - -uint8_t himax_int_gpio_read(int pinnum) -{ - return gpio_get_value(pinnum); -} - -#if defined(CONFIG_HMX_DB) -static int himax_regulator_configure(struct i2c_client *client,struct himax_i2c_platform_data *pdata) -{ - int retval; - pdata->vcc_dig = regulator_get(&client->dev, - "vdd"); - if (IS_ERR(pdata->vcc_dig)) - { - E("%s: Failed to get regulator vdd\n", - __func__); - retval = PTR_ERR(pdata->vcc_dig); - return retval; - } - pdata->vcc_ana = regulator_get(&client->dev, - "avdd"); - if (IS_ERR(pdata->vcc_ana)) - { - E("%s: Failed to get regulator avdd\n", - __func__); - retval = PTR_ERR(pdata->vcc_ana); - regulator_put(pdata->vcc_ana); - return retval; - } - - return 0; -}; - -static int himax_power_on(struct himax_i2c_platform_data *pdata, bool on) -{ - int retval; - - if (on) - { - retval = regulator_enable(pdata->vcc_dig); - if (retval) - { - E("%s: Failed to enable regulator vdd\n", - __func__); - return retval; - } - msleep(100); - retval = regulator_enable(pdata->vcc_ana); - if (retval) - { - E("%s: Failed to enable regulator avdd\n", - __func__); - regulator_disable(pdata->vcc_dig); - return retval; - } - } - else - { - regulator_disable(pdata->vcc_dig); - regulator_disable(pdata->vcc_ana); - } - - return 0; -} - -int himax_ts_pinctrl_init(struct himax_ts_data *ts) -{ - int retval; - - /* Get pinctrl if target uses pinctrl */ - ts->ts_pinctrl = devm_pinctrl_get(&(ts->client->dev)); - if (IS_ERR_OR_NULL(ts->ts_pinctrl)) { - retval = PTR_ERR(ts->ts_pinctrl); - dev_dbg(&ts->client->dev, - "Target does not use pinctrl %d\n", retval); - goto err_pinctrl_get; - } - - ts->pinctrl_state_active - = pinctrl_lookup_state(ts->ts_pinctrl, - PINCTRL_STATE_ACTIVE); - if (IS_ERR_OR_NULL(ts->pinctrl_state_active)) { - retval = PTR_ERR(ts->pinctrl_state_active); - dev_err(&ts->client->dev, - "Can not lookup %s pinstate %d\n", - PINCTRL_STATE_ACTIVE, retval); - goto err_pinctrl_lookup; - } - - ts->pinctrl_state_suspend - = pinctrl_lookup_state(ts->ts_pinctrl, - PINCTRL_STATE_SUSPEND); - if (IS_ERR_OR_NULL(ts->pinctrl_state_suspend)) { - retval = PTR_ERR(ts->pinctrl_state_suspend); - dev_err(&ts->client->dev, - "Can not lookup %s pinstate %d\n", - PINCTRL_STATE_SUSPEND, retval); - goto err_pinctrl_lookup; - } - - ts->pinctrl_state_release - = pinctrl_lookup_state(ts->ts_pinctrl, - PINCTRL_STATE_RELEASE); - if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { - retval = PTR_ERR(ts->pinctrl_state_release); - dev_dbg(&ts->client->dev, - "Can not lookup %s pinstate %d\n", - PINCTRL_STATE_RELEASE, retval); - } - - return 0; - -err_pinctrl_lookup: - devm_pinctrl_put(ts->ts_pinctrl); -err_pinctrl_get: - ts->ts_pinctrl = NULL; - return retval; -} - -int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata) -{ - int error; - - error = himax_regulator_configure(client, pdata); - if (error) - { - E("Failed to intialize hardware\n"); - goto err_regulator_not_on; - } - -#ifdef HX_RST_PIN_FUNC - if (gpio_is_valid(pdata->gpio_reset)) - { - /* configure touchscreen reset out gpio */ - error = gpio_request(pdata->gpio_reset, "hmx_reset_gpio"); - if (error) - { - E("unable to request gpio [%d]\n", - pdata->gpio_reset); - goto err_regulator_on; - } - - error = gpio_direction_output(pdata->gpio_reset, 0); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_reset); - goto err_gpio_reset_req; - } - } -#endif - - error = himax_power_on(pdata, true); - if (error) - { - E("Failed to power on hardware\n"); - goto err_gpio_reset_req; - } -#ifdef HX_IRQ_PIN_FUNC - if (gpio_is_valid(pdata->gpio_irq)) - { - /* configure touchscreen irq gpio */ - error = gpio_request(pdata->gpio_irq, "hmx_gpio_irq"); - if (error) - { - E("unable to request gpio [%d]\n", - pdata->gpio_irq); - goto err_power_on; - } - error = gpio_direction_input(pdata->gpio_irq); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_irq); - goto err_gpio_irq_req; - } - client->irq = gpio_to_irq(pdata->gpio_irq); - } - else - { - E("irq gpio not provided\n"); - goto err_power_on; - } -#endif - - msleep(20); - -#ifdef HX_RST_PIN_FUNC - if (gpio_is_valid(pdata->gpio_reset)) - { - error = gpio_direction_output(pdata->gpio_reset, 1); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_reset); - goto err_gpio_irq_req; - } - } -#endif - return 0; -#ifdef HX_RST_PIN_FUNC - err_gpio_irq_req: -#endif -#ifdef HX_IRQ_PIN_FUNC - if (gpio_is_valid(pdata->gpio_irq)) - gpio_free(pdata->gpio_irq); - err_power_on: -#endif - himax_power_on(pdata, false); - err_gpio_reset_req: -#ifdef HX_RST_PIN_FUNC - if (gpio_is_valid(pdata->gpio_reset)) - gpio_free(pdata->gpio_reset); - err_regulator_on: -#endif - err_regulator_not_on: - - return error; -} - -#else -int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata) -{ - int error=0; - -#ifdef HX_RST_PIN_FUNC - if (pdata->gpio_reset >= 0) - { - error = gpio_request(pdata->gpio_reset, "himax-reset"); - if (error < 0) - { - E("%s: request reset pin failed\n", __func__); - return error; - } - error = gpio_direction_output(pdata->gpio_reset, 0); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_reset); - return error; - } - } -#endif - if (pdata->gpio_3v3_en >= 0) - { - error = gpio_request(pdata->gpio_3v3_en, "himax-3v3_en"); - if (error < 0) - { - E("%s: request 3v3_en pin failed\n", __func__); - return error; - } - gpio_direction_output(pdata->gpio_3v3_en, 1); - I("3v3_en pin =%d\n", gpio_get_value(pdata->gpio_3v3_en)); - } - -#ifdef HX_IRQ_PIN_FUNC - if (gpio_is_valid(pdata->gpio_irq)) - { - /* configure touchscreen irq gpio */ - error = gpio_request(pdata->gpio_irq, "himax_gpio_irq"); - if (error) - { - E("unable to request gpio [%d]\n",pdata->gpio_irq); - return error; - } - error = gpio_direction_input(pdata->gpio_irq); - if (error) - { - E("unable to set direction for gpio [%d]\n",pdata->gpio_irq); - return error; - } - client->irq = gpio_to_irq(pdata->gpio_irq); - } - else - { - E("irq gpio not provided\n"); - return error; - } -#endif - - msleep(20); - -#ifdef HX_RST_PIN_FUNC - if (pdata->gpio_reset >= 0) - { - error = gpio_direction_output(pdata->gpio_reset, 1); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_reset); - return error; - } - } - msleep(20); -#endif - - return error; - } -#endif - -static void himax_ts_isr_func(struct himax_ts_data *ts) -{ - himax_ts_work(ts); -} - -irqreturn_t himax_ts_thread(int irq, void *ptr) -{ - uint8_t diag_cmd; - struct himax_ts_data *ts = ptr; - struct timespec timeStart, timeEnd, timeDelta; - - diag_cmd = getDiagCommand(); - - if (ts->debug_log_level & BIT(2)) { - getnstimeofday(&timeStart); - usleep_range(5000, 7000); - //I(" Irq start time = %ld.%06ld s\n", - // timeStart.tv_sec, timeStart.tv_nsec/1000); - } - -#ifdef HX_SMART_WAKEUP - if (atomic_read(&ts->suspend_mode)&&(!FAKE_POWER_KEY_SEND)&&(ts->SMWP_enable)&&(!diag_cmd)) { - wake_lock_timeout(&ts->ts_SMWP_wake_lock, TS_WAKE_LOCK_TIMEOUT); - msleep(200); - himax_wake_check_func(); - return IRQ_HANDLED; - } -#endif - himax_ts_isr_func((struct himax_ts_data *)ptr); - if(ts->debug_log_level & BIT(2)) { - getnstimeofday(&timeEnd); - timeDelta.tv_nsec = (timeEnd.tv_sec*1000000000+timeEnd.tv_nsec) - -(timeStart.tv_sec*1000000000+timeStart.tv_nsec); - //I("Irq finish time = %ld.%06ld s\n", - // timeEnd.tv_sec, timeEnd.tv_nsec/1000); - //I("Touch latency = %ld us\n", timeDelta.tv_nsec/1000); - } - return IRQ_HANDLED; -} - -static void himax_ts_work_func(struct work_struct *work) -{ - struct himax_ts_data *ts = container_of(work, struct himax_ts_data, work); - himax_ts_work(ts); -} - -int tp_irq = -1; - -int himax_ts_register_interrupt(struct i2c_client *client) -{ - struct himax_ts_data *ts = i2c_get_clientdata(client); - int ret = 0; - - ts->irq_enabled = 0; - //Work functon - if (client->irq) {/*INT mode*/ - ts->use_irq = 1; - if(ic_data->HX_INT_IS_EDGE) - { - I("%s edge triiger falling\n ",__func__); - ret = request_threaded_irq(client->irq, NULL, himax_ts_thread,IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, ts); - } - else - { - I("%s level trigger low\n ",__func__); - ret = request_threaded_irq(client->irq, NULL, himax_ts_thread,IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, ts); - } - if (ret == 0) { - ts->irq_enabled = 1; - irq_enable_count = 1; - tp_irq = client->irq; - I("%s: irq enabled at qpio: %d\n", __func__, client->irq); -#ifdef HX_SMART_WAKEUP - irq_set_irq_wake(client->irq, 1); -#endif - } else { - ts->use_irq = 0; - E("%s: request_irq failed\n", __func__); - } - } else { - I("%s: client->irq is empty, use polling mode.\n", __func__); - } - - if (!ts->use_irq) {/*if use polling mode need to disable HX_ESD_WORKAROUND function*/ - ts->himax_wq = create_singlethread_workqueue("himax_touch"); - - INIT_WORK(&ts->work, himax_ts_work_func); - - hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - ts->timer.function = himax_ts_timer_func; - hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); - I("%s: polling mode enabled\n", __func__); - } - return ret; -} - -static int himax_common_suspend(struct device *dev) -{ - struct himax_ts_data *ts = dev_get_drvdata(dev); - - I("%s: enter \n", __func__); - - himax_chip_common_suspend(ts); - return 0; -} - -static int himax_common_resume(struct device *dev) -{ - struct himax_ts_data *ts = dev_get_drvdata(dev); - - I("%s: enter \n", __func__); - - himax_chip_common_resume(ts); - return 0; -} - -#if defined(CONFIG_FB) -int fb_notifier_callback(struct notifier_block *self, - unsigned long event, void *data) -{ - struct fb_event *evdata = data; - int *blank; - struct himax_ts_data *ts= - container_of(self, struct himax_ts_data, fb_notif); - - I(" %s\n", __func__); - if (evdata && evdata->data && event == FB_EVENT_BLANK && ts && - ts->client) { - blank = evdata->data; - - mutex_lock(&ts->fb_mutex); - switch (*blank) { - case FB_BLANK_UNBLANK: - if (!ts->probe_done) { - himax_ts_init(ts); - ts->probe_done = true; - } else { - himax_common_resume(&ts->client->dev); - } - break; - - case FB_BLANK_POWERDOWN: - case FB_BLANK_HSYNC_SUSPEND: - case FB_BLANK_VSYNC_SUSPEND: - case FB_BLANK_NORMAL: - himax_common_suspend(&ts->client->dev); - break; - } - mutex_unlock(&ts->fb_mutex); - } - - return 0; -} -#endif - -static const struct i2c_device_id himax_common_ts_id[] = { - {HIMAX_common_NAME, 0 }, - {} -}; - -static const struct dev_pm_ops himax_common_pm_ops = { -#if (!defined(CONFIG_FB)) - .suspend = himax_common_suspend, - .resume = himax_common_resume, -#endif -}; - -#ifdef CONFIG_OF -static const struct of_device_id himax_match_table[] = { - {.compatible = "himax,hxcommon" }, - {}, -}; -#else -#define himax_match_table NULL -#endif - -static struct i2c_driver himax_common_driver = { - .id_table = himax_common_ts_id, - .probe = himax_chip_common_probe, - .remove = himax_chip_common_remove, - .driver = { - .name = HIMAX_common_NAME, - .owner = THIS_MODULE, - .of_match_table = himax_match_table, -#ifdef CONFIG_PM - .pm = &himax_common_pm_ops, -#endif - }, -}; - -static void __init himax_common_init_async(void *unused, async_cookie_t cookie) -{ - I("%s:Enter \n", __func__); - i2c_add_driver(&himax_common_driver); -} - -static int __init himax_common_init(void) -{ - I("Himax common touch panel driver init\n"); - async_schedule(himax_common_init_async, NULL); - return 0; -} - -static void __exit himax_common_exit(void) -{ - i2c_del_driver(&himax_common_driver); -} - -module_init(himax_common_init); -module_exit(himax_common_exit); - -MODULE_DESCRIPTION("Himax_common driver"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.h b/drivers/input/touchscreen/hxchipset/himax_platform.h deleted file mode 100644 index 1223685683aa..000000000000 --- a/drivers/input/touchscreen/hxchipset/himax_platform.h +++ /dev/null @@ -1,135 +0,0 @@ -/* Himax Android Driver Sample Code for Himax chipset -* -* Copyright (C) 2015 Himax Corporation. -* -* This software is licensed under the terms of the GNU General Public -* License version 2, as published by the Free Software Foundation, and -* may be copied, distributed, and modified under those terms. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ - -#ifndef HIMAX_PLATFORM_H -#define HIMAX_PLATFORM_H - -#include -#include -#include -#include -#include -#include -#if defined(CONFIG_HMX_DB) -#include -#endif - -#define QCT - -#define HIMAX_I2C_RETRY_TIMES 10 - -#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) -#define D(x...) pr_debug("[HXTP] " x) -#define I(x...) pr_info("[HXTP] " x) -#define W(x...) pr_warning("[HXTP][WARNING] " x) -#define E(x...) pr_err("[HXTP][ERROR] " x) -#define DIF(x...) \ -do {\ - if (debug_flag) \ - pr_debug("[HXTP][DEBUG] " x) \ -} while(0) -#else -#define D(x...) -#define I(x...) -#define W(x...) -#define E(x...) -#define DIF(x...) -#endif - -#if defined(CONFIG_HMX_DB) -/* Analog voltage @2.7 V */ -#define HX_VTG_MIN_UV 2700000 -#define HX_VTG_MAX_UV 3300000 -#define HX_ACTIVE_LOAD_UA 15000 -#define HX_LPM_LOAD_UA 10 -/* Digital voltage @1.8 V */ -#define HX_VTG_DIG_MIN_UV 1800000 -#define HX_VTG_DIG_MAX_UV 1800000 -#define HX_ACTIVE_LOAD_DIG_UA 10000 -#define HX_LPM_LOAD_DIG_UA 10 - -#define HX_I2C_VTG_MIN_UV 1800000 -#define HX_I2C_VTG_MAX_UV 1800000 -#define HX_I2C_LOAD_UA 10000 -#define HX_I2C_LPM_LOAD_UA 10 -#endif - -#define HIMAX_common_NAME "himax_tp" -#define HIMAX_I2C_ADDR 0x48 -#define INPUT_DEV_NAME "himax-touchscreen" - -struct himax_i2c_platform_data { - int abs_x_min; - int abs_x_max; - int abs_x_fuzz; - int abs_y_min; - int abs_y_max; - int abs_y_fuzz; - int abs_pressure_min; - int abs_pressure_max; - int abs_pressure_fuzz; - int abs_width_min; - int abs_width_max; - int screenWidth; - int screenHeight; - uint8_t fw_version; - uint8_t tw_id; - uint8_t powerOff3V3; - uint8_t cable_config[2]; - uint8_t protocol_type; - int gpio_irq; - int gpio_reset; - int gpio_3v3_en; - int (*power)(int on); - void (*reset)(void); - struct himax_virtual_key *virtual_key; - struct kobject *vk_obj; - struct kobj_attribute *vk2Use; - - struct himax_config *hx_config; - int hx_config_size; -#if defined(CONFIG_HMX_DB) - bool i2c_pull_up; - bool digital_pwr_regulator; - int reset_gpio; - u32 reset_gpio_flags; - int irq_gpio; - u32 irq_gpio_flags; - - struct regulator *vcc_ana; //For Dragon Board - struct regulator *vcc_dig; //For Dragon Board - struct regulator *vcc_i2c; //For Dragon Board -#endif -}; - - -extern int irq_enable_count; -extern int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); -extern int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); -extern int i2c_himax_write_command(struct i2c_client *client, uint8_t command, uint8_t toRetry); -extern int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t length, uint8_t toRetry); -extern int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry); -extern void himax_int_enable(int irqnum, int enable); -extern int himax_ts_register_interrupt(struct i2c_client *client); -extern void himax_rst_gpio_set(int pinnum, uint8_t value); -extern uint8_t himax_int_gpio_read(int pinnum); - -extern int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata); - -#if defined(CONFIG_FB) -extern int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data); -#endif - -#endif -- GitLab From f5f30dca69a8f15fa7ac39e28d13f5f529f69770 Mon Sep 17 00:00:00 2001 From: Paul Chang Date: Wed, 18 Jul 2018 19:37:26 +0530 Subject: [PATCH 454/604] input: touchscreen: Add himax touchscreen support apq8053-lite FEP-V2 SOM has 2 variants of display Panel - 8" and 10". For 8" display panel the touch vendor is Himax. Add Himax touchscreen support for 8" Display Panel. Change-Id: Icfbf21f800b09d83122795fc26f833d5c3bd6bcb Signed-off-by: Paul Chang Git-commit: aa2965fae3f8d791d0fd4c8105408bee807b540c Git-commit: 714259e2f1eadeb712fdb9cf6e6619fe6eece156 Git-commit: 788fbe836fcabb5493596a2ccc393645665e47c5 Git-commit: 884851757226bb87dd51c5686ee9935a7cd95403 Git-commit: a2b465b13af90f22233943c492b6f09a4fa892e7 Git-commit: 1f5b2aaafa1d9935b0831b641edebd18cf05eb04 Git-commit: 3f6ec12edd3200d6d3c4c32b93e4ed390160403d Git-commit: 7bc077d513ac739518734a4ab7fee80ca63a9d02 Git-commit: 97afcbfbca30b5eeb3b8acc10e2d1b430650e7a0 Git-commit: 566ec5a310816f2527a0f06e164a90fca7c04650 Git-commit: c91150831a152e1123902f36194802124b7d8aca Git-commit: c48e3f6d989efadc818563a154e8c029d6c8acfd Git-commit: fc785e480943fec46cc85a920592de714c9662e9 Git-commit: 2e38029b518618d33b295a9db251fdf183584de5 Git-commit: 6ae46c3501c85b874d0f430ead0ecd0b8a465af2 Git-commit: 2dbe6ff0b26c05930cfeb8079c98968d91f4ae85 Git-commit: 104a28fd7540c4674f8a02f4bad3f8a66b5d92d5 Git-commit: 262492fd69d729acdfef1a223e11155c9ed5301d Git-commit: 887a29104e1d895664642a27db7935c2bbc32d0f Git-commit: 0caefe38fb476103606494e13f830f2690acf430 Git-commit: f855d7e895df3d307ceee5cef69d410e816a4987 Git-Repo: https://github.com/HimaxSoftware/msm-3.18 Signed-off-by: Vijay Navnath Kamble --- .../input/touchscreen/himax_i2c_ts.txt | 57 + .../devicetree/bindings/vendor-prefixes.txt | 1 + drivers/input/touchscreen/Kconfig | 11 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/hxchipset/Kconfig | 46 + drivers/input/touchscreen/hxchipset/Makefile | 4 + .../touchscreen/hxchipset/himax_common.c | 1984 ++++++++++++++ .../touchscreen/hxchipset/himax_common.h | 471 ++++ .../input/touchscreen/hxchipset/himax_debug.c | 2205 +++++++++++++++ .../input/touchscreen/hxchipset/himax_debug.h | 197 ++ .../input/touchscreen/hxchipset/himax_ic.c | 2381 +++++++++++++++++ .../input/touchscreen/hxchipset/himax_ic.h | 148 + .../touchscreen/hxchipset/himax_platform.c | 783 ++++++ .../touchscreen/hxchipset/himax_platform.h | 157 ++ 14 files changed, 8446 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/himax_i2c_ts.txt create mode 100644 drivers/input/touchscreen/hxchipset/Kconfig create mode 100644 drivers/input/touchscreen/hxchipset/Makefile create mode 100644 drivers/input/touchscreen/hxchipset/himax_common.c create mode 100644 drivers/input/touchscreen/hxchipset/himax_common.h create mode 100644 drivers/input/touchscreen/hxchipset/himax_debug.c create mode 100644 drivers/input/touchscreen/hxchipset/himax_debug.h create mode 100644 drivers/input/touchscreen/hxchipset/himax_ic.c create mode 100644 drivers/input/touchscreen/hxchipset/himax_ic.h create mode 100644 drivers/input/touchscreen/hxchipset/himax_platform.c create mode 100644 drivers/input/touchscreen/hxchipset/himax_platform.h diff --git a/Documentation/devicetree/bindings/input/touchscreen/himax_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/himax_i2c_ts.txt new file mode 100644 index 000000000000..9889f55dd4bb --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/himax_i2c_ts.txt @@ -0,0 +1,57 @@ +Himax touch controller + +Required properties: + + - compatible : should be "himax,hxcommon" + - reg : i2c slave address of the device + - interrupt-parent : parent of interrupt + - interrupts : touch sample interrupt to indicate presense or release + of fingers on the panel. + - himax,irq-gpio : irq gpio + - himax,reset-gpio : reset gpio + +Optional property: + - vdd-supply : Analog power supply needed to power device + - vcc_i2c-supply : Power source required to pull up i2c bus + - himax,i2c-pull-up : specify to indicate pull up is needed + - himax,disable-gpios : specify to disable gpios in suspend (power saving) + - himax,button-map : virtual key code mappings to be used + - himax,x-flip : modify orientation of the x axis + - himax,y-flip : modify orientation of the y axis + - himax,panel-coords : touch panel min x, min y, max x and + max y resolution + - himax,display-coords : display min x, min y, max x and + max y resolution + - himax,reset-delay : reset delay for controller (ms), default 100 + - himax,fw-image-name : name of firmware .img file in /etc/firmware + - himax,power-down : fully power down regulators in suspend + - himax,do-lockdown : perform one time lockdown procedure + +Example: + i2c@f9927000 { /* BLSP1 QUP5 */ + cell-index = <5>; + compatible = "himax,hxcommon"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "qup_phys_addr"; + reg = <0xf9927000 0x1000>; + interrupt-names = "qup_err_intr"; + interrupts = <0 99 0>; + gpios = <&msmgpio 19 0>, /* SCL */ + <&msmgpio 18 0>; /* SDA */ + qcom,i2c-bus-freq = <100000>; + qcom,i2c-src-freq = <19200000>; + + himax_ts@20 { + compatible = "himax,hxcommon" + reg = <0x20>; + interrupt-parent = <&tlmm>; + interrupts = <255 0x2008>; + vdd-supply = <&pm8994_l15>; + avdd-supply = <&pm8994_l22>; + himax,panel-coords = <0 720 0 1440>; + himax,display-coords = <0 720 0 1440>; + himax,irq-gpio = <&tlmm 255 0x2008>; + himax,rst-gpio = <&tlmm 8 0x00>; + }; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 559d0909076e..ed51a777f971 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -129,6 +129,7 @@ hitex Hitex Development Tools holt Holt Integrated Circuits, Inc. honeywell Honeywell hp Hewlett Packard +himax Himax Coroporation i2se I2SE GmbH ibm International Business Machines (IBM) idt Integrated Device Technologies, Inc. diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index d9b612dc727f..ea37a9ff857a 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1291,4 +1291,15 @@ config TOUCHSCREEN_GT9XX_v28 source "drivers/input/touchscreen/gt9xx_v2.8/Kconfig" +config TOUCHSCREEN_HIMAX_CHIPSET + bool "Himax touchpanel CHIPSET" + depends on I2C + help + Say Y here if you have a Himax CHIPSET touchscreen. + HIMAX controllers are multi touch controllers which can + report 10 touches at a time. + + If unsure, say N. + +source "drivers/input/touchscreen/hxchipset/Kconfig" endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 1f2faf98eb9b..acd4045a23d2 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -105,3 +105,4 @@ obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_touch/ obj-$(CONFIG_TOUCHSCREEN_GT9XX_v28) += gt9xx_v2.8/ +obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET) += hxchipset/ diff --git a/drivers/input/touchscreen/hxchipset/Kconfig b/drivers/input/touchscreen/hxchipset/Kconfig new file mode 100644 index 000000000000..3dc5a026c851 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/Kconfig @@ -0,0 +1,46 @@ +# +# Himax Touchscreen driver configuration +# + +config TOUCHSCREEN_HIMAX_I2C + tristate "HIMAX chipset i2c touchscreen" + depends on TOUCHSCREEN_HIMAX_CHIPSET + help + Say Y here to enable support for HIMAX CHIPSET over I2C based touchscreens. + If unsure, say N. + + To compile this driver as a module, + This enables support for HIMAX CHIPSET over I2C based touchscreens. + +config TOUCHSCREEN_HIMAX_DEBUG + tristate "HIMAX debug function" + depends on TOUCHSCREEN_HIMAX_I2C + help + Say Y here to enable support for HIMAX debug function. + + If unsure, say N. + + To compile this driver as a module, + This enables support for HIMAX debug function. + +config TOUCHSCREEN_HIMAX_ITO_TEST + tristate "HIMAX driver test over Dragon Board" + depends on TOUCHSCREEN_HIMAX_I2C + help + Say Y here to enable support for HIMAX driver test over Dragon Board. + + If unsure, say N. + + To compile this driver as a module, + this enables support for HIMAX driver test over Dragon Board. + +config HMX_DB + tristate "HIMAX driver test over Dragon Board" + depends on TOUCHSCREEN_HIMAX_I2C + help + Say Y here to enable support for HIMAX driver test over Dragon Board. + + If unsure, say N. + + To compile this driver as a module, + this enables support for HIMAX driver test over Dragon Board. diff --git a/drivers/input/touchscreen/hxchipset/Makefile b/drivers/input/touchscreen/hxchipset/Makefile new file mode 100644 index 000000000000..522907a48956 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/Makefile @@ -0,0 +1,4 @@ +# Makefile for the Himax touchscreen drivers. + +obj-$(CONFIG_TOUCHSCREEN_HIMAX_I2C) += himax_platform.o himax_ic.o himax_common.o himax_debug.o +obj-$(CONFIG_TOUCHSCREEN_HIMAX_ITO_TEST) += himax_ito_test.o \ No newline at end of file diff --git a/drivers/input/touchscreen/hxchipset/himax_common.c b/drivers/input/touchscreen/hxchipset/himax_common.c new file mode 100644 index 000000000000..d4bc5beb0203 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_common.c @@ -0,0 +1,1984 @@ + /* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_common.h" +#include "himax_ic.h" + +#define SUPPORT_FINGER_DATA_CHECKSUM 0x0F +#define TS_WAKE_LOCK_TIMEOUT (2 * HZ) +#define FRAME_COUNT 5 + +#if defined(HX_AUTO_UPDATE_FW) + char *i_CTPM_firmware_name = "HX83100_Amber_0B01_030E.bin"; + const struct firmware *i_CTPM_FW = NULL; +#endif + +/*static int tpd_keys_local[HX_KEY_MAX_COUNT] = HX_KEY_ARRAY; +// for Virtual key array */ + +struct himax_ts_data *private_ts; +struct himax_ic_data *ic_data; + +static int HX_TOUCH_INFO_POINT_CNT; + +static uint8_t vk_press = 0x00; +static uint8_t AA_press = 0x00; +static uint8_t EN_NoiseFilter = 0x00; +static int hx_point_num; /*for himax_ts_work_func use*/ +static int p_point_num = 0xFFFF; +static int tpd_key = 0x00; +static int tpd_key_old = 0x00; +static int probe_fail_flag; +static bool config_load; +static struct himax_config *config_selected; + +/*static int iref_number = 11;*/ +/*static bool iref_found = false;*/ + + +#if defined(CONFIG_FB) +int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); +#elif defined(CONFIG_HAS_EARLYSUSPEND) +static void himax_ts_early_suspend(struct early_suspend *h); +static void himax_ts_late_resume(struct early_suspend *h); +#endif + +int himax_input_register(struct himax_ts_data *ts) +{ + int ret; + + ts->input_dev = input_allocate_device(); + if (ts->input_dev == NULL) { + ret = -ENOMEM; + E("%s: Failed to allocate input device\n", __func__); + return ret; + } + ts->input_dev->name = "himax-touchscreen"; + + set_bit(EV_SYN, ts->input_dev->evbit); + set_bit(EV_ABS, ts->input_dev->evbit); + set_bit(EV_KEY, ts->input_dev->evbit); + + set_bit(KEY_BACK, ts->input_dev->keybit); + set_bit(KEY_HOME, ts->input_dev->keybit); + set_bit(KEY_MENU, ts->input_dev->keybit); + set_bit(KEY_SEARCH, ts->input_dev->keybit); +#if defined(HX_SMART_WAKEUP) + set_bit(KEY_POWER, ts->input_dev->keybit); + set_bit(KEY_CUST_01, ts->input_dev->keybit); + set_bit(KEY_CUST_02, ts->input_dev->keybit); + set_bit(KEY_CUST_03, ts->input_dev->keybit); + set_bit(KEY_CUST_04, ts->input_dev->keybit); + set_bit(KEY_CUST_05, ts->input_dev->keybit); + set_bit(KEY_CUST_06, ts->input_dev->keybit); + set_bit(KEY_CUST_07, ts->input_dev->keybit); + set_bit(KEY_CUST_08, ts->input_dev->keybit); + set_bit(KEY_CUST_09, ts->input_dev->keybit); + set_bit(KEY_CUST_10, ts->input_dev->keybit); + set_bit(KEY_CUST_11, ts->input_dev->keybit); + set_bit(KEY_CUST_12, ts->input_dev->keybit); + set_bit(KEY_CUST_13, ts->input_dev->keybit); + set_bit(KEY_CUST_14, ts->input_dev->keybit); + set_bit(KEY_CUST_15, ts->input_dev->keybit); +#endif + set_bit(BTN_TOUCH, ts->input_dev->keybit); + + set_bit(KEY_F10, ts->input_dev->keybit); + + set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + + if (ts->protocol_type == PROTOCOL_TYPE_A) { + /*ts->input_dev->mtsize = ts->nFinger_support;*/ + input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, + 0, 3, 0, 0); + } else {/* PROTOCOL_TYPE_B */ + set_bit(MT_TOOL_FINGER, ts->input_dev->keybit); + input_mt_init_slots(ts->input_dev, ts->nFinger_support, 0); + } + + I("input_set_abs_params: mix_x %d, max_x %d, min_y %d, max_y %d\n", + ts->pdata->abs_x_min, ts->pdata->abs_x_max, + ts->pdata->abs_y_min, ts->pdata->abs_y_max); + + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, + ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_x_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, + ts->pdata->abs_y_min, ts->pdata->abs_y_max, ts->pdata->abs_y_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, + ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, + ts->pdata->abs_pressure_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, + ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, + ts->pdata->abs_pressure_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, + ts->pdata->abs_width_min, ts->pdata->abs_width_max, + ts->pdata->abs_pressure_fuzz, 0); + +/*input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE, 0, +((ts->pdata->abs_pressure_max << 16) | ts->pdata->abs_width_max), 0, 0);*/ +/*input_set_abs_params(ts->input_dev, ABS_MT_POSITION, 0, +(BIT(31) | (ts->pdata->abs_x_max << 16) | ts->pdata->abs_y_max), 0, 0);*/ + + return input_register_device(ts->input_dev); +} + +static void calcDataSize(uint8_t finger_num) +{ + struct himax_ts_data *ts_data = private_ts; + + ts_data->coord_data_size = 4 * finger_num; + ts_data->area_data_size = ((finger_num / 4) + + (finger_num % 4 ? 1 : 0)) * 4; + ts_data->raw_data_frame_size = 128 - + ts_data->coord_data_size - + ts_data->area_data_size - 4 - 4 - 1; + + ts_data->raw_data_nframes = + ((uint32_t)ts_data->x_channel * + ts_data->y_channel + ts_data->x_channel + ts_data->y_channel) / + ts_data->raw_data_frame_size + (((uint32_t)ts_data->x_channel * + ts_data->y_channel + ts_data->x_channel + ts_data->y_channel) % + ts_data->raw_data_frame_size) ? 1 : 0; + + I("%s: coord_data_size: %d, area_data_size:%d", + __func__, ts_data->coord_data_size, ts_data->area_data_size); + I("raw_data_frame_size:%d, raw_data_nframes:%d", + ts_data->raw_data_frame_size, ts_data->raw_data_nframes); +} + +static void calculate_point_number(void) +{ + HX_TOUCH_INFO_POINT_CNT = ic_data->HX_MAX_PT * 4; + + if ((ic_data->HX_MAX_PT % 4) == 0) + HX_TOUCH_INFO_POINT_CNT += (ic_data->HX_MAX_PT / 4) * 4; + else + HX_TOUCH_INFO_POINT_CNT += ((ic_data->HX_MAX_PT / 4) + 1) * 4; +} + +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH +static int himax_read_Sensor_ID(struct i2c_client *client) +{ + uint8_t val_high[1], val_low[1], ID0 = 0, ID1 = 0; + char data[3]; + const int normalRetry = 10; + int sensor_id; + + data[0] = 0x56; data[1] = 0x02; + data[2] = 0x02;/*ID pin PULL High*/ + i2c_himax_master_write(client, &data[0], 3, normalRetry); + usleep(1000); + + /*read id pin high*/ + i2c_himax_read(client, 0x57, val_high, 1, normalRetry); + + data[0] = 0x56; data[1] = 0x01; + data[2] = 0x01;/*ID pin PULL Low*/ + i2c_himax_master_write(client, &data[0], 3, normalRetry); + usleep(1000); + + /*read id pin low*/ + i2c_himax_read(client, 0x57, val_low, 1, normalRetry); + + if ((val_high[0] & 0x01) == 0) + ID0 = 0x02;/*GND*/ + else if ((val_low[0] & 0x01) == 0) + ID0 = 0x01;/*Floating*/ + else + ID0 = 0x04;/*VCC*/ + + if ((val_high[0] & 0x02) == 0) + ID1 = 0x02;/*GND*/ + else if ((val_low[0] & 0x02) == 0) + ID1 = 0x01;/*Floating*/ + else + ID1 = 0x04;/*VCC*/ + if ((ID0 == 0x04) && (ID1 != 0x04)) { + data[0] = 0x56; data[1] = 0x02; + data[2] = 0x01;/*ID pin PULL High,Low*/ + i2c_himax_master_write(client, + &data[0], 3, normalRetry); + usleep(1000); + + } else if ((ID0 != 0x04) && (ID1 == 0x04)) { + data[0] = 0x56; data[1] = 0x01; + data[2] = 0x02;/*ID pin PULL Low,High*/ + i2c_himax_master_write(client, + &data[0], 3, normalRetry); + usleep(1000); + + } else if ((ID0 == 0x04) && (ID1 == 0x04)) { + data[0] = 0x56; data[1] = 0x02; + data[2] = 0x02;/*ID pin PULL High,High*/ + i2c_himax_master_write(client, + &data[0], 3, normalRetry); + usleep(1000); + + } + sensor_id = (ID1<<4)|ID0; + + data[0] = 0xE4; data[1] = sensor_id; + i2c_himax_master_write(client, + &data[0], 2, normalRetry);/*Write to MCU*/ + usleep(1000); + + return sensor_id; + +} +#endif +static void himax_power_on_initCMD(struct i2c_client *client) +{ + I("%s:\n", __func__); + himax_touch_information(client); + /*himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM */ +} + +#ifdef HX_AUTO_UPDATE_FW +static int i_update_FW(void) +{ + int upgrade_times = 0; + int fullFileLength = 0; + int i_FW_VER = 0, i_CFG_VER = 0; + int ret = -1, result = 0; + /*uint8_t tmp_addr[4];*/ + /*uint8_t tmp_data[4];*/ + int CRC_from_FW = 0; + int CRC_Check_result = 0; + + ret = himax_load_CRC_bin_file(private_ts->client); + if (ret < 0) { + E("%s: himax_load_CRC_bin_file fail Error Code=%d.\n", + __func__, ret); + ret = -1; + return ret; + } + I("file name = %s\n", i_CTPM_firmware_name); + ret = request_firmware(&i_CTPM_FW, + i_CTPM_firmware_name, private_ts->dev); + if (ret < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, ret); + ret = -2; + return ret; + } + + if (i_CTPM_FW == NULL) { + I("%s: i_CTPM_FW = NULL\n", __func__); + ret = -3; + return ret; + } + fullFileLength = i_CTPM_FW->size; + + i_FW_VER = i_CTPM_FW->data[FW_VER_MAJ_FLASH_ADDR]<<8 + | i_CTPM_FW->data[FW_VER_MIN_FLASH_ADDR]; + i_CFG_VER = i_CTPM_FW->data[CFG_VER_MAJ_FLASH_ADDR]<<8 + | i_CTPM_FW->data[CFG_VER_MIN_FLASH_ADDR]; + + I("%s: i_fullFileLength = %d\n", __func__, fullFileLength); + + himax_sense_off(private_ts->client); + msleep(500); + + CRC_from_FW = himax_check_CRC(private_ts->client, fw_image_64k); + CRC_Check_result = + Calculate_CRC_with_AP((unsigned char *)i_CTPM_FW->data, + CRC_from_FW, fw_image_64k); + I("%s: Check sum result = %d\n", __func__, CRC_Check_result); + /*I("%s: ic_data->vendor_fw_ver = %X, i_FW_VER = %X,\n", + __func__, ic_data->vendor_fw_ver, i_FW_VER);*/ + /*I("%s: ic_data->vendor_config_ver = %X, i_CFG_VER = %X,\n", + __func__, ic_data->vendor_config_ver, i_CFG_VER);*/ + + if ((CRC_Check_result == 0) || + (ic_data->vendor_fw_ver < i_FW_VER) || + (ic_data->vendor_config_ver < i_CFG_VER)) { + himax_int_enable(private_ts->client->irq, 0); +update_retry: + if (fullFileLength == FW_SIZE_60k) { + ret = fts_ctpm_fw_upgrade_with_sys_fs_60k + (private_ts->client, + (unsigned char *)i_CTPM_FW->data, + fullFileLength, false); + } else if (fullFileLength == FW_SIZE_64k) { + ret = fts_ctpm_fw_upgrade_with_sys_fs_64k + (private_ts->client, + (unsigned char *)i_CTPM_FW->data, + fullFileLength, false); + } else if (fullFileLength == FW_SIZE_124k) { + ret = fts_ctpm_fw_upgrade_with_sys_fs_124k + (private_ts->client, + (unsigned char *)i_CTPM_FW->data, + fullFileLength, false); + } else if (fullFileLength == FW_SIZE_128k) { + ret = fts_ctpm_fw_upgrade_with_sys_fs_128k + (private_ts->client, + (unsigned char *)i_CTPM_FW->data, + fullFileLength, false); + } + if (ret == 0) { + upgrade_times++; + E("%s: TP upgrade error, upgrade_times = %d\n", + __func__, upgrade_times); + if (upgrade_times < 3) + goto update_retry; + else { + himax_sense_on(private_ts->client, 0x01); + msleep(120); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + result = -1;/*upgrade fail*/ + } + } else if (ret == 1) { + /* + // 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) + (Lock register R/W from driver) + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_register_write(private_ts->client, + tmp_addr, 1, tmp_data); + + // 2. Write driver initial code condition + //write value from AHB I2C:0x8001_C603 = 0x000000FF + tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; + tmp_addr[1] = 0xC6; tmp_addr[0] = 0x03; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xFF; + himax_register_write(private_ts->client, + tmp_addr, 1, tmp_data); + + // 1. Set DDREG_Req = 0(0x9000_0020 = 0x0000_0001) + (Lock register R/W from driver) + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_register_write(private_ts->client, + tmp_addr, 1, tmp_data); + */ + himax_sense_on(private_ts->client, 0x01); + msleep(120); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + + ic_data->vendor_fw_ver = i_FW_VER; + ic_data->vendor_config_ver = i_CFG_VER; + result = 1;/*upgrade success*/ + I("%s: TP upgrade OK\n", __func__); + } + + himax_int_enable(private_ts->client->irq, 1); + return result; + + } else { + himax_sense_on(private_ts->client, 0x01); + return 0;/*NO upgrade*/ + } +} +#endif + +#ifdef HX_RST_PIN_FUNC +void himax_HW_reset(uint8_t loadconfig, uint8_t int_off) +{ + struct himax_ts_data *ts = private_ts; + int ret = 0; + + return; + if (ts->rst_gpio) { + if (int_off) { + if (ts->use_irq) + himax_int_enable(private_ts->client->irq, 0); + else { + hrtimer_cancel(&ts->timer); + ret = cancel_work_sync(&ts->work); + } + } + + I("%s: Now reset the Touch chip.\n", __func__); + + himax_rst_gpio_set(ts->rst_gpio, 0); + msleep(20); + himax_rst_gpio_set(ts->rst_gpio, 1); + msleep(20); + + if (loadconfig) + himax_loadSensorConfig(private_ts->client, + private_ts->pdata); + + if (int_off) { + if (ts->use_irq) + himax_int_enable(private_ts->client->irq, 1); + else + hrtimer_start(&ts->timer, + ktime_set(1, 0), HRTIMER_MODE_REL); + } + } +} +#endif + +int himax_loadSensorConfig(struct i2c_client *client, +struct himax_i2c_platform_data *pdata) +{ + int err = -1; + + if (!client) { + E("%s: Necessary parameters client are null!\n", __func__); + return err; + } + if (config_load == false) { + config_selected = kzalloc(sizeof(*config_selected), GFP_KERNEL); + if (config_selected == NULL) { + E("%s: alloc config_selected fail!\n", __func__); + return err; + } + } + himax_power_on_initCMD(client); + + himax_int_enable(client->irq, 0); + himax_read_FW_ver(client); +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true, false); +#endif + himax_int_enable(client->irq, 1); + I("FW_VER : %X\n", ic_data->vendor_fw_ver); + + ic_data->vendor_sensor_id = 0x2602; + I("sensor_id=%x.\n", ic_data->vendor_sensor_id); + + himax_sense_on(private_ts->client, 0x01);/*1=Flash, 0=SRAM*/ + msleep(120); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + I("%s: initialization complete\n", __func__); + + return 1; +} + +#ifdef HX_ESD_WORKAROUND +void ESD_HW_REST(void) +{ + I("START_Himax TP: ESD - Reset\n"); + + HX_report_ESD_event(); + ESD_00_counter = 0; + ESD_00_Flag = 0; + /*************************************/ + if (private_ts->protocol_type == PROTOCOL_TYPE_A) + input_mt_sync(private_ts->input_dev); + input_report_key(private_ts->input_dev, BTN_TOUCH, 0); + input_sync(private_ts->input_dev); + /*************************************/ + + I("END_Himax TP: ESD - Reset\n"); +} +#endif +#ifdef HX_HIGH_SENSE +void himax_set_HSEN_func(struct i2c_client *client, uint8_t HSEN_enable) +{ + uint8_t tmp_data[4]; + + if (HSEN_enable) { + I(" %s in", __func__); +HSEN_bit_retry: + himax_set_HSEN_enable(client, HSEN_enable); + msleep(20); + himax_get_HSEN_enable(client, tmp_data); + I("%s: Read HSEN bit data[0]=%x data[1]=%x", + __func__, tmp_data[0], tmp_data[1]); + I("data[2]=%x data[3]=%x\n", + tmp_data[2], tmp_data[3]); + + if (tmp_data[0] != 0x01) { + I("%s: retry HSEN bit write data[0]=%x\n", + __func__, tmp_data[0]); + goto HSEN_bit_retry; + } + } +} + +static void himax_HSEN_func(struct work_struct *work) +{ + struct himax_ts_data *ts = + container_of(work, struct himax_ts_data, hsen_work.work); + + himax_set_HSEN_func(ts->client, ts->HSEN_enable); +} + +#endif + +#ifdef HX_SMART_WAKEUP +#ifdef HX_GESTURE_TRACK +static void gest_pt_log_coordinate(int rx, int tx) +{ + /*driver report x y with range 0 - 255*/ + /* And we scale it up to x/y coordinates*/ + gest_pt_x[gest_pt_cnt] = rx * (ic_data->HX_X_RES) / 255; + gest_pt_y[gest_pt_cnt] = tx * (ic_data->HX_Y_RES) / 255; +} +#endif +static int himax_parse_wake_event(struct himax_ts_data *ts) +{ + uint8_t buf[64]; + unsigned char check_sum_cal = 0; +#ifdef HX_GESTURE_TRACK + int tmp_max_x = 0x00, tmp_min_x = 0xFFFF, + tmp_max_y = 0x00, tmp_min_y = 0xFFFF; + int gest_len; +#endif + int i = 0, check_FC = 0, gesture_flag = 0; + + himax_burst_enable(ts->client, 0); + himax_read_event_stack(ts->client, buf, 56); + + for (i = 0 ; i < GEST_PTLG_ID_LEN ; i++) { + if (check_FC == 0) { + if ((buf[0] != 0x00) && + ((buf[0] <= 0x0F) || (buf[0] == 0x80))) { + check_FC = 1; + gesture_flag = buf[i]; + } else { + check_FC = 0; + I("ID START at %x,value = %x skip event\n", + i, buf[i]); + break; + } + } else { + if (buf[i] != gesture_flag) { + check_FC = 0; + I("ID NOT same %x != %x So STOP parse event\n", + buf[i], gesture_flag); + break; + } + } + + I("0x%2.2X ", buf[i]); + if (i % 8 == 7) + I("\n"); + } + I("Himax gesture_flag= %x\n", gesture_flag); + I("Himax check_FC is %d\n", check_FC); + + if (check_FC == 0) + return 0; + if (buf[GEST_PTLG_ID_LEN] != GEST_PTLG_HDR_ID1 + || buf[GEST_PTLG_ID_LEN+1] != GEST_PTLG_HDR_ID2) + return 0; + for (i = 0 ; i < (GEST_PTLG_ID_LEN + GEST_PTLG_HDR_LEN) ; i++) { + I("P[%x]=0x%2.2X\n", i, buf[i]); + I("checksum=0x%2.2X\n", check_sum_cal); + check_sum_cal += buf[i]; + } + if ((check_sum_cal != 0x00)) { + I(" %s : check_sum_cal: 0x%02X\n", __func__ , check_sum_cal); + return 0; + } +#ifdef HX_GESTURE_TRACK + if (buf[GEST_PTLG_ID_LEN] == GEST_PTLG_HDR_ID1 + && buf[GEST_PTLG_ID_LEN+1] == GEST_PTLG_HDR_ID2) { + gest_len = buf[GEST_PTLG_ID_LEN + 2]; + I("gest_len = %d ", gest_len); + i = 0; + gest_pt_cnt = 0; + I("gest doornidate start\n %s", __func__); + while (i < (gest_len + 1) / 2) { + gest_pt_log_coordinate + (buf[GEST_PTLG_ID_LEN + 4 + i * 2], + buf[GEST_PTLG_ID_LEN + 4 + i * 2 + 1]); + i++; + + I("gest_pt_x[%d]=%d\n", + gest_pt_cnt, gest_pt_x[gest_pt_cnt]); + I("gest_pt_y[%d]=%d\n", + gest_pt_cnt, gest_pt_y[gest_pt_cnt]); + + gest_pt_cnt += 1; + } + if (gest_pt_cnt) { + for (i = 0 ; i < gest_pt_cnt ; i++) { + if (tmp_max_x < gest_pt_x[i]) + tmp_max_x = gest_pt_x[i]; + if (tmp_min_x > gest_pt_x[i]) + tmp_min_x = gest_pt_x[i]; + if (tmp_max_y < gest_pt_y[i]) + tmp_max_y = gest_pt_y[i]; + if (tmp_min_y > gest_pt_y[i]) + tmp_min_y = gest_pt_y[i]; + } + I("gest_point x_min= %d, x_max= %d\n", + tmp_min_x, tmp_max_x); + I("y_min= %d, y_max= %d\n", + tmp_min_y, tmp_max_y); + gest_start_x = gest_pt_x[0]; + gn_gesture_coor[0] = gest_start_x; + gest_start_y = gest_pt_y[0]; + gn_gesture_coor[1] = gest_start_y; + gest_end_x = gest_pt_x[gest_pt_cnt - 1]; + gn_gesture_coor[2] = gest_end_x; + gest_end_y = gest_pt_y[gest_pt_cnt - 1]; + gn_gesture_coor[3] = gest_end_y; + gest_width = tmp_max_x - tmp_min_x; + gn_gesture_coor[4] = gest_width; + gest_height = tmp_max_y - tmp_min_y; + gn_gesture_coor[5] = gest_height; + gest_mid_x = (tmp_max_x + tmp_min_x) / 2; + gn_gesture_coor[6] = gest_mid_x; + gest_mid_y = (tmp_max_y + tmp_min_y) / 2; + gn_gesture_coor[7] = gest_mid_y; + /*gest_up_x*/ + gn_gesture_coor[8] = gest_mid_x; + /*gest_up_y*/ + gn_gesture_coor[9] = gest_mid_y - gest_height / 2; + /*gest_down_x*/ + gn_gesture_coor[10] = gest_mid_x; + /*gest_down_y*/ + gn_gesture_coor[11] = gest_mid_y + gest_height / 2; + /*gest_left_x*/ + gn_gesture_coor[12] = gest_mid_x - gest_width / 2; + /*gest_left_y*/ + gn_gesture_coor[13] = gest_mid_y; + /*gest_right_x*/ + gn_gesture_coor[14] = gest_mid_x + gest_width / 2; + /*gest_right_y*/ + gn_gesture_coor[15] = gest_mid_y; + + } + + } +#endif + if (gesture_flag != 0x80) { + if (!ts->gesture_cust_en[gesture_flag]) { + I("%s NOT report customer key\n ", __func__); + return 0;/*NOT report customer key*/ + } + } else { + if (!ts->gesture_cust_en[0]) { + I("%s NOT report report double click\n", __func__); + return 0;/*NOT report power key*/ + } + } + + if (gesture_flag == 0x80) + return EV_GESTURE_PWR; + else + return gesture_flag; +} + +void himax_wake_check_func(void) +{ + int ret_event = 0, KEY_EVENT = 0; + + ret_event = himax_parse_wake_event(private_ts); + switch (ret_event) { + case EV_GESTURE_PWR: + KEY_EVENT = KEY_POWER; + break; + case EV_GESTURE_01: + KEY_EVENT = KEY_CUST_01; + break; + case EV_GESTURE_02: + KEY_EVENT = KEY_CUST_02; + break; + case EV_GESTURE_03: + KEY_EVENT = KEY_CUST_03; + break; + case EV_GESTURE_04: + KEY_EVENT = KEY_CUST_04; + break; + case EV_GESTURE_05: + KEY_EVENT = KEY_CUST_05; + break; + case EV_GESTURE_06: + KEY_EVENT = KEY_CUST_06; + break; + case EV_GESTURE_07: + KEY_EVENT = KEY_CUST_07; + break; + case EV_GESTURE_08: + KEY_EVENT = KEY_CUST_08; + break; + case EV_GESTURE_09: + KEY_EVENT = KEY_CUST_09; + break; + case EV_GESTURE_10: + KEY_EVENT = KEY_CUST_10; + break; + case EV_GESTURE_11: + KEY_EVENT = KEY_CUST_11; + break; + case EV_GESTURE_12: + KEY_EVENT = KEY_CUST_12; + break; + case EV_GESTURE_13: + KEY_EVENT = KEY_CUST_13; + break; + case EV_GESTURE_14: + KEY_EVENT = KEY_CUST_14; + break; + case EV_GESTURE_15: + KEY_EVENT = KEY_CUST_15; + break; + } + if (ret_event) { + I(" %s SMART WAKEUP KEY event %x press\n", + __func__, KEY_EVENT); + input_report_key(private_ts->input_dev, KEY_EVENT, 1); + input_sync(private_ts->input_dev); + /*msleep(100);*/ + I(" %s SMART WAKEUP KEY event %x release\n", + __func__, KEY_EVENT); + input_report_key(private_ts->input_dev, KEY_EVENT, 0); + input_sync(private_ts->input_dev); + FAKE_POWER_KEY_SEND = true; +#ifdef HX_GESTURE_TRACK + I("gest_start_x= %d, gest_start_y= %d\n", + gest_start_x, gest_start_y); + I("gest_end_x= %d, gest_end_y= %d\n", + gest_end_x, gest_end_y); + I("gest_width= %d, gest_height= %d\n", + gest_width, gest_height); + I("gest_mid_x= %d, gest_mid_y= %d\n", + gest_mid_x, gest_mid_y); + I("gest_up_x= %d, gest_up_y= %d\n", + gn_gesture_coor[8], gn_gesture_coor[9]); + I("gest_down_x= %d, gest_down_y= %d\n", + gn_gesture_coor[10], gn_gesture_coor[11]); + I("gest_left_x= %d, gest_left_y= %d\n", + gn_gesture_coor[12], gn_gesture_coor[13]); + I("gest_right_x= %d, gest_right_y= %d\n", + gn_gesture_coor[14], gn_gesture_coor[15]); +#endif + } +} + +#endif +static void himax_ts_button_func(int tp_key_index, struct himax_ts_data *ts) +{ + uint16_t x_position = 0, y_position = 0; + + if (tp_key_index != 0x00) { + I("virtual key index =%x\n", tp_key_index); + if (tp_key_index == 0x01) { + vk_press = 1; + I("back key pressed\n"); + if (ts->pdata->virtual_key) { + if (ts->button[0].index) { + x_position = (ts->button[0].x_range_min + + ts->button[0].x_range_max) / 2; + y_position = (ts->button[0].y_range_min + + ts->button[0].y_range_max) / 2; + } + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type + == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 1); + + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + } + } else + input_report_key(ts->input_dev, KEY_BACK, 1); + } else if (tp_key_index == 0x02) { + vk_press = 1; + I("home key pressed\n"); + if (ts->pdata->virtual_key) { + if (ts->button[1].index) { + x_position = (ts->button[1].x_range_min + + ts->button[1].x_range_max) / 2; + y_position = (ts->button[1].y_range_min + + ts->button[1].y_range_max) / 2; + } + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type + == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 1); + + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + } + } else + input_report_key(ts->input_dev, KEY_HOME, 1); + } else if (tp_key_index == 0x04) { + vk_press = 1; + I("APP_switch key pressed\n"); + if (ts->pdata->virtual_key) { + if (ts->button[2].index) { + x_position = (ts->button[2].x_range_min + + ts->button[2].x_range_max) / 2; + y_position = (ts->button[2].y_range_min + + ts->button[2].y_range_max) / 2; + } + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type == + PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 1); + + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + } + } else + input_report_key(ts->input_dev, KEY_F10, 1); + } + input_sync(ts->input_dev); + } else {/*tp_key_index =0x00*/ + I("virtual key released\n"); + vk_press = 0; + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_FINGER, 0); + } + input_report_key(ts->input_dev, KEY_BACK, 0); + input_report_key(ts->input_dev, KEY_HOME, 0); + input_report_key(ts->input_dev, KEY_F10, 0); + input_sync(ts->input_dev); + } +} + +void himax_ts_work(struct himax_ts_data *ts) +{ + int ret = 0; + uint8_t finger_num, hw_reset_check[2]; + uint8_t buf[128]; + uint8_t finger_on = 0; + int32_t loop_i; + uint16_t check_sum_cal = 0; + int raw_cnt_max; + int raw_cnt_rmd; + int hx_touch_info_size; + uint8_t coordInfoSize = ts->coord_data_size + ts->area_data_size + 4; + +#ifdef HX_TP_PROC_DIAG + int16_t *mutual_data; + int16_t *self_data; + uint8_t diag_cmd; + int i; + int mul_num; + int self_num; + int RawDataLen = 0; + /*coordinate dump start*/ + char coordinate_char[15 + (ic_data->HX_MAX_PT + 5) * 2 * 5 + 2]; + struct timeval t; + struct tm broken; + /*coordinate dump end*/ +#endif + + memset(buf, 0x00, sizeof(buf)); + memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); + + raw_cnt_max = ic_data->HX_MAX_PT / 4; + raw_cnt_rmd = ic_data->HX_MAX_PT % 4; +#if defined(HX_USB_DETECT2) + himax_cable_detect_func(); +#endif + + if (raw_cnt_rmd != 0x00) { /*more than 4 fingers*/ + RawDataLen = cal_data_len(raw_cnt_rmd, + ic_data->HX_MAX_PT, raw_cnt_max); + hx_touch_info_size = (ic_data->HX_MAX_PT + raw_cnt_max + 2) * 4; + } else { /*less than 4 fingers*/ + RawDataLen = cal_data_len(raw_cnt_rmd, + ic_data->HX_MAX_PT, raw_cnt_max); + hx_touch_info_size = (ic_data->HX_MAX_PT + raw_cnt_max + 1) * 4; + } + +#ifdef HX_TP_PROC_DIAG + diag_cmd = getDiagCommand(); + if (diag_cmd) { + ret = read_event_stack(ts->client, buf, 128); + } else { + if (touch_monitor_stop_flag != 0) { + ret = read_event_stack(ts->client, buf, 128); + touch_monitor_stop_flag--; + } else { + ret = read_event_stack(ts->client, + buf, hx_touch_info_size); + } + } + + if (!ret) +#else + if (!read_event_stack(ts->client, buf, hx_touch_info_size)) +#endif + { + E("%s: can't read data from chip!\n", __func__); + goto err_workqueue_out; + } + post_read_event_stack(ts->client); +#ifdef HX_ESD_WORKAROUND + for (i = 0; i < hx_touch_info_size; i++) { + if (buf[i] == 0xED) { /*case 1 ESD recovery flow*/ + check_sum_cal = 1; + + } else if (buf[i] == 0x00) { + ESD_00_Flag = 1; + } else { + check_sum_cal = 0; + ESD_00_counter = 0; + ESD_00_Flag = 0; + i = hx_touch_info_size; + break; + } + } + if (ESD_00_Flag == 1) + ESD_00_counter++; + if (ESD_00_counter > 1) + check_sum_cal = 2; + if (check_sum_cal == 2 && HX_ESD_RESET_ACTIVATE == 0) { + I("[HIMAX TP MSG]: ESD event checked - ALL Zero.\n"); + ESD_HW_REST(); + return; + } + if (check_sum_cal == 1 && HX_ESD_RESET_ACTIVATE == 0) { + I("[HIMAX TP MSG]: ESD event checked - ALL 0xED.\n"); + ESD_HW_REST(); + return; + } else if (HX_ESD_RESET_ACTIVATE) { +#ifdef HX_SMART_WAKEUP + queue_delayed_work(ts->himax_smwp_wq, + &ts->smwp_work, msecs_to_jiffies(50)); +#endif +#ifdef HX_HIGH_SENSE + queue_delayed_work(ts->himax_hsen_wq, + &ts->hsen_work, msecs_to_jiffies(50)); +#endif +/*drop 1st interrupts after chip reset*/ + HX_ESD_RESET_ACTIVATE = 0; + I("[HIMAX TP MSG]:%s: Back from reset,ready to serve.\n", + __func__); + } +#endif + for (loop_i = 0, check_sum_cal = 0; + loop_i < hx_touch_info_size; loop_i++) + check_sum_cal += buf[loop_i]; + + if ((check_sum_cal % 0x100 != 0)) { + I("[HIMAX TP MSG] checksum fail : check_sum_cal: 0x%02X\n", + check_sum_cal); + return; + } + if (ts->debug_log_level & BIT(0)) { + I("%s: raw data:\n", __func__); + for (loop_i = 0; loop_i < hx_touch_info_size; loop_i++) { + I("P %d = 0x%2.2X ", loop_i, buf[loop_i]); + if (loop_i % 8 == 7) + I("\n"); + } + } + + /*touch monitor raw data fetch*/ +#ifdef HX_TP_PROC_DIAG + diag_cmd = getDiagCommand(); + if (diag_cmd >= 1 && diag_cmd <= 6) { + /*Check 124th byte CRC*/ + if (!diag_check_sum(hx_touch_info_size, buf)) + goto bypass_checksum_failed_packet; + +#ifdef HX_TP_PROC_2T2R + if (Is_2T2R && diag_cmd == 4) { + mutual_data = getMutualBuffer_2(); + self_data = getSelfBuffer(); + + /* initiallize the block number of mutual and self*/ + mul_num = getXChannel_2() * getYChannel_2(); + +#ifdef HX_EN_SEL_BUTTON + self_num = getXChannel_2() + + getYChannel_2() + ic_data->HX_BT_NUM; +#else + self_num = getXChannel_2() + getYChannel_2(); +#endif + } else +#endif + { + mutual_data = getMutualBuffer(); + self_data = getSelfBuffer(); + + /* initiallize the block number of mutual and self*/ + mul_num = getXChannel() * getYChannel(); + +#ifdef HX_EN_SEL_BUTTON + self_num = getXChannel() + + getYChannel() + ic_data->HX_BT_NUM; +#else + self_num = getXChannel() + getYChannel(); +#endif + } + + diag_parse_raw_data(hx_touch_info_size, + RawDataLen, mul_num, self_num, buf, + diag_cmd, mutual_data, self_data); + + } else if (diag_cmd == 7) { + memcpy(&(diag_coor[0]), &buf[0], 128); + } + /*coordinate dump start*/ + if (coordinate_dump_enable == 1) { + for (i = 0; i < (15 + (ic_data-> + HX_MAX_PT + 5) * 2 * 5); + i++) { + coordinate_char[i] = 0x20; + } + coordinate_char[15 + + (ic_data->HX_MAX_PT + 5) * 2 * 5] = 0xD; + coordinate_char[15 + + (ic_data->HX_MAX_PT + 5) * 2 * 5 + 1] = 0xA; + } + /*coordinate dump end*/ +bypass_checksum_failed_packet: +#endif + EN_NoiseFilter = (buf[HX_TOUCH_INFO_POINT_CNT + 2] >> 3); + /*I("EN_NoiseFilter=%d\n",EN_NoiseFilter);*/ + EN_NoiseFilter = EN_NoiseFilter & 0x01; + /*I("EN_NoiseFilter2=%d\n",EN_NoiseFilter);*/ + +#if defined(HX_EN_SEL_BUTTON) || defined(HX_EN_MUT_BUTTON) + tpd_key = (buf[HX_TOUCH_INFO_POINT_CNT + 2] >> 4); + if (tpd_key == 0x0F) {/*All (VK+AA)leave*/ + tpd_key = 0x00; + } + /*I("[DEBUG] tpd_key: %x\r\n", tpd_key);*/ +#else + tpd_key = 0x00; +#endif + + p_point_num = hx_point_num; + + if (buf[HX_TOUCH_INFO_POINT_CNT] == 0xff) + hx_point_num = 0; + else + hx_point_num = buf[HX_TOUCH_INFO_POINT_CNT] & 0x0f; + + /* Touch Point information*/ + if ((hx_point_num != 0) && (vk_press == 0x00)) { + uint16_t old_finger = ts->pre_finger_mask; + + ts->pre_finger_mask = 0; + finger_num = buf[coordInfoSize - 4] & 0x0F; + finger_on = 1; + AA_press = 1; + for (i = 0; i < ts->nFinger_support; i++) { + int base = i * 4; + int x = buf[base] << 8 | buf[base + 1]; + int y = (buf[base + 2] << 8 | buf[base + 3]); + int w = buf[(ts->nFinger_support * 4) + i]; + + if (x >= 0 && x <= ts->pdata->abs_x_max + && y >= 0 && y <= ts->pdata->abs_y_max) { + finger_num--; + if ((((ts->debug_log_level & BIT(3)) > 0) + && (old_finger >> i == 0)) + && (ts->useScreenRes)) { + I("status:Screen:F:%02d", i + 1); + I("Down,X:%d,Y:%d,W:%d,N:%d\n", + x * ts->widthFactor >> SHIFTBITS, + y * ts->heightFactor >> SHIFTBITS, + w, EN_NoiseFilter); + } else if ((((ts->debug_log_level & BIT(3)) > 0) + && (old_finger >> i == 0)) + && !(ts->useScreenRes)) { + I("status:Raw:F:%02d", i + 1); + I("Down,X:%d,Y:%d,W:%d,N:%d\n", + x, y, w, EN_NoiseFilter); + } + + if (ts->protocol_type == PROTOCOL_TYPE_B) + input_mt_slot(ts->input_dev, i); + + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, w); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, w); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, w); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y); + + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, i); + input_mt_sync(ts->input_dev); + } else { + ts->last_slot = i; + input_mt_report_slot_state + (ts->input_dev, + MT_TOOL_FINGER, 1); + } + + if (!ts->first_pressed) { + ts->first_pressed = 1; + I("S1@%d, %d\n", x, y); + } + + ts->pre_finger_data[i][0] = x; + ts->pre_finger_data[i][1] = y; + + if (ts->debug_log_level & BIT(1)) { + I("Finger %d=> X:%d,Y:%d,W:%d,", + i + 1, x, y, w); + I("Z:%d,F:%d,N:%d\n", + w, i + 1, EN_NoiseFilter); + } + ts->pre_finger_mask = + ts->pre_finger_mask + (1 << i); + + } else { + if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 0); + } + if (i == 0 && ts->first_pressed == 1) { + ts->first_pressed = 2; + I("E1@%d, %d\n", + ts->pre_finger_data[0][0], + ts->pre_finger_data[0][1]); + } + if ((((ts->debug_log_level & BIT(3)) > 0) + && (old_finger >> i == 1)) + && (ts->useScreenRes)) { + I("status:Screen:F:%02d,Up,X:%d,Y:%d\n", + i + 1, ts->pre_finger_data[i][0] + * ts->widthFactor >> SHIFTBITS, + ts->pre_finger_data[i][1] + * ts->heightFactor >> SHIFTBITS); + } else if ((((ts->debug_log_level & BIT(3)) > 0) + && (old_finger >> i == 1)) + && !(ts->useScreenRes)) { + I("status:Raw:F:%02d,Up,X:%d,Y:%d\n", + i + 1, ts->pre_finger_data[i][0], + ts->pre_finger_data[i][1]); + } + } + } + input_report_key(ts->input_dev, BTN_TOUCH, finger_on); + input_sync(ts->input_dev); + } else if ((hx_point_num != 0) + && ((tpd_key_old != 0x00) && (tpd_key == 0x00))) { + /*temp_x[0] = 0xFFFF;*/ + /*temp_y[0] = 0xFFFF;*/ + /*temp_x[1] = 0xFFFF;*/ + /*temp_y[1] = 0xFFFF;*/ + himax_ts_button_func(tpd_key, ts); + finger_on = 0; + input_report_key(ts->input_dev, BTN_TOUCH, finger_on); + input_sync(ts->input_dev); + } else if (hx_point_num == 0) { + if (AA_press) { + /*leave event*/ + finger_on = 0; + AA_press = 0; + if (ts->protocol_type == PROTOCOL_TYPE_A) + input_mt_sync(ts->input_dev); + + for (i = 0 ; i < ts->nFinger_support ; i++) { + if ((((ts->pre_finger_mask >> i) & 1) == 1) + && (ts->protocol_type == PROTOCOL_TYPE_B)) { + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 0); + } + } + if (ts->pre_finger_mask > 0) { + for (i = 0; i < ts->nFinger_support + && (ts->debug_log_level & BIT(3)) > 0; i++) { + if ((((ts->pre_finger_mask + >> i) & 1) == 1) + && (ts->useScreenRes)) { + I("status:%X,", 0); + I("Screen:F:%02d,", i + 1); + I("Up,X:%d,Y:%d\n", + ts->pre_finger_data[i][0] + * ts->widthFactor >> SHIFTBITS, + ts->pre_finger_data[i][1] + * ts->heightFactor >> SHIFTBITS + ); + } else if ((((ts->pre_finger_mask + >> i) & 1) == 1) + && !(ts->useScreenRes)) { + I("status:%X,", 0); + I("Screen:F:%02d,", i + 1); + I("Up,X:%d,Y:%d\n", + ts->pre_finger_data[i][0], + ts->pre_finger_data[i][1]); + } + } + ts->pre_finger_mask = 0; + } + + if (ts->first_pressed == 1) { + ts->first_pressed = 2; + I("E1@%d, %d\n", ts->pre_finger_data[0][0], + ts->pre_finger_data[0][1]); + } + + if (ts->debug_log_level & BIT(1)) + I("All Finger leave\n"); + +#ifdef HX_TP_PROC_DIAG + /*coordinate dump start*/ + if (coordinate_dump_enable == 1) { + do_gettimeofday(&t); + time_to_tm(t.tv_sec, 0, &broken); + snprintf(&coordinate_char[0], 15, + "%2d:%2d:%2d:%lu,", broken.tm_hour, + broken.tm_min, broken.tm_sec, + t.tv_usec / 1000); + + snprintf(&coordinate_char[15], 10, + "Touch up!"); + + coordinate_fn->f_op->write + (coordinate_fn, &coordinate_char[0], + 15 + (ic_data->HX_MAX_PT + 5) + * 2 * sizeof(char) * 5 + 2, + &coordinate_fn->f_pos); + } + /*coordinate dump end*/ +#endif + } else if (tpd_key != 0x00) { + himax_ts_button_func(tpd_key, ts); + finger_on = 1; + } else if ((tpd_key_old != 0x00) && (tpd_key == 0x00)) { + himax_ts_button_func(tpd_key, ts); + finger_on = 0; + } + input_report_key(ts->input_dev, BTN_TOUCH, finger_on); + input_sync(ts->input_dev); + } + tpd_key_old = tpd_key; + +workqueue_out: + return; + +err_workqueue_out: + I("%s: Now reset the Touch chip.\n", __func__); + +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true, false); +#endif + + goto workqueue_out; +} +enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer) +{ + struct himax_ts_data *ts; + + ts = container_of(timer, struct himax_ts_data, timer); + queue_work(ts->himax_wq, &ts->work); + hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL); + return HRTIMER_NORESTART; +} + +#if defined(HX_USB_DETECT) +static void himax_cable_tp_status_handler_func(int connect_status) +{ + struct himax_ts_data *ts; + + I("Touch: cable change to %d\n", connect_status); + ts = private_ts; + if (ts->cable_config) { + if (!atomic_read(&ts->suspend_mode)) { + if ((!!connect_status) != ts->usb_connected) { + if (!!connect_status) { + ts->cable_config[1] = 0x01; + ts->usb_connected = 0x01; + } else { + ts->cable_config[1] = 0x00; + ts->usb_connected = 0x00; + } + + i2c_himax_master_write(ts->client, + ts->cable_config, + sizeof(ts->cable_config), + HIMAX_I2C_RETRY_TIMES); + + I("%s: Cable status change: 0x%2.2X\n", + __func__, ts->cable_config[1]); + } else + I("%s: Cable status is same, ignore.\n", + __func__); + } else { + if (connect_status) + ts->usb_connected = 0x01; + else + ts->usb_connected = 0x00; + I("%s: Cable status remembered: 0x%2.2X\n", + __func__, ts->usb_connected); + } + } +} + +static struct t_cable_status_notifier himax_cable_status_handler = { + .name = "usb_tp_connected", + .func = himax_cable_tp_status_handler_func, +}; + +#endif + +#if defined(HX_USB_DETECT2) +void himax_cable_detect_func(void) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[128]; + struct himax_ts_data *ts; + u32 connect_status = 0; + + connect_status = USB_Flag;/*upmu_is_chr_det();*/ + ts = private_ts; + /*I("Touch: cable status=%d, cable_config=%p, + usb_connected=%d\n", connect_status, + ts->cable_config, ts->usb_connected);*/ + + if (ts->cable_config) { + if ((!!connect_status) != ts->usb_connected) { + /*notify USB plug/unplug*/ + /*0x9008_8060 ==> 0x0000_0000/0001*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x60; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + if (!!connect_status) { + tmp_data[0] = 0x01; + ts->usb_connected = 0x01; + } else { + tmp_data[0] = 0x00; + ts->usb_connected = 0x00; + } + + himax_flash_write_burst(ts->client, tmp_addr, tmp_data); + + I("%s: Cable status change: 0x%2.2X\n", + __func__, ts->usb_connected); + } + /*else*/ + /*I("%s: Cable status is the same as previous one, + ignore.\n", __func__);*/ + + } +} +#endif + +#ifdef CONFIG_FB +int himax_fb_register(struct himax_ts_data *ts) +{ + int ret = 0; + + I(" %s in", __func__); + ts->fb_notif.notifier_call = fb_notifier_callback; + ret = fb_register_client(&ts->fb_notif); + if (ret) + E(" Unable to register fb_notifier: %d\n", ret); + + return ret; +} +#endif + +#ifdef HX_SMART_WAKEUP +void himax_set_SMWP_func(struct i2c_client *client, uint8_t SMWP_enable) +{ + uint8_t tmp_data[4]; + + if (SMWP_enable) { +SMWP_bit_retry: + himax_set_SMWP_enable(client, SMWP_enable); + msleep(20); + himax_get_SMWP_enable(client, tmp_data); +I("%s: Read SMWP bit data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", +__func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + + if (tmp_data[0] != 0x01) { + I("%s: retry SMWP bit write data[0]=%x\n", + __func__, tmp_data[0]); + goto SMWP_bit_retry; + } + } +} + +static void himax_SMWP_work(struct work_struct *work) +{ + struct himax_ts_data *ts = + container_of(work, struct himax_ts_data, smwp_work.work); + I(" %s in", __func__); + + himax_set_SMWP_func(ts->client, ts->SMWP_enable); + +} +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP +static void himax_ts_flash_work_func(struct work_struct *work) +{ + himax_ts_flash_func(); +} +#endif + +#ifdef HX_TP_PROC_DIAG +static void himax_ts_diag_work_func(struct work_struct *work) +{ + himax_ts_diag_func(); +} +#endif + +bool himax_ts_init(struct himax_ts_data *ts) +{ + int ret = 0, err = 0; + struct himax_i2c_platform_data *pdata; + struct i2c_client *client; + + client = ts->client; + pdata = ts->pdata; + + I("%s: Start.\n", __func__); + + /* Set pinctrl in active state */ + if (ts->ts_pinctrl) { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_active); + if (ret < 0) + E("Failed to set pin in active state %d", ret); + } + + himax_burst_enable(client, 0); + + /*Get Himax IC Type / FW information / Calculate the point number */ + if (himax_check_chip_version(ts->client) == false) { + E("Himax chip doesn NOT EXIST"); + goto err_ic_package_failed; + } + if (himax_ic_package_check(ts->client) == false) { + E("Himax chip doesn NOT EXIST"); + goto err_ic_package_failed; + } + + if (pdata->virtual_key) + ts->button = pdata->virtual_key; +#ifdef HX_TP_PROC_FLASH_DUMP + ts->flash_wq = create_singlethread_workqueue("himax_flash_wq"); + if (!ts->flash_wq) { + E("%s: create flash workqueue failed\n", __func__); + err = -ENOMEM; + goto err_create_wq_failed; + } + + INIT_WORK(&ts->flash_work, himax_ts_flash_work_func); + + setSysOperation(0); + setFlashBuffer(); +#endif + +#ifdef HX_TP_PROC_DIAG + ts->himax_diag_wq = create_singlethread_workqueue("himax_diag"); + if (!ts->himax_diag_wq) { + E("%s: create diag workqueue failed\n", __func__); + err = -ENOMEM; + goto err_create_wq_failed; + } + INIT_DELAYED_WORK(&ts->himax_diag_delay_wrok, himax_ts_diag_work_func); +#endif + +himax_read_FW_ver(client); + +#ifdef HX_AUTO_UPDATE_FW + I(" %s in", __func__); + if (i_update_FW() <= 0) + I("FW NOT UPDATE=\n"); + else + I("Have new FW=UPDATE=\n"); +#endif + + /*Himax Power On and Load Config*/ + if (himax_loadSensorConfig(client, pdata) < 0) { + E("%s: Load Sesnsor config failed,unload driver.\n", + __func__); + goto err_detect_failed; + } + + calculate_point_number(); +#ifdef HX_TP_PROC_DIAG + setXChannel(ic_data->HX_RX_NUM); /*X channel*/ + setYChannel(ic_data->HX_TX_NUM); /*Y channel*/ + + setMutualBuffer(); + setMutualNewBuffer(); + setMutualOldBuffer(); + if (getMutualBuffer() == NULL) { + E("%s: mutual buffer allocate fail failed\n", __func__); + return false; + } +#ifdef HX_TP_PROC_2T2R + if (Is_2T2R) { + setXChannel_2(ic_data->HX_RX_NUM_2); /*X channel*/ + setYChannel_2(ic_data->HX_TX_NUM_2); /*Y channel*/ + + setMutualBuffer_2(); + + if (getMutualBuffer_2() == NULL) { + E("%s: mutual buffer 2 allocate fail failed\n", + __func__); + return false; + } + } +#endif +#endif +#ifdef CONFIG_OF + ts->power = pdata->power; +#endif + ts->pdata = pdata; + + ts->x_channel = ic_data->HX_RX_NUM; + ts->y_channel = ic_data->HX_TX_NUM; + ts->nFinger_support = ic_data->HX_MAX_PT; + /*calculate the i2c data size*/ + calcDataSize(ts->nFinger_support); + I("%s: calcDataSize complete\n", __func__); +#ifdef CONFIG_OF + ts->pdata->abs_pressure_min = 0; + ts->pdata->abs_pressure_max = 200; + ts->pdata->abs_width_min = 0; + ts->pdata->abs_width_max = 200; + pdata->cable_config[0] = 0x90; + pdata->cable_config[1] = 0x00; +#endif + ts->suspended = false; +#if defined(HX_USB_DETECT) || defined(HX_USB_DETECT2) + ts->usb_connected = 0x00; + ts->cable_config = pdata->cable_config; +#endif + ts->protocol_type = pdata->protocol_type; + I("%s: Use Protocol Type %c\n", __func__, + ts->protocol_type == PROTOCOL_TYPE_A ? 'A' : 'B'); + ret = himax_input_register(ts); + if (ret) { + E("%s: Unable to register %s input device\n", + __func__, ts->input_dev->name); + goto err_input_register_device_failed; + } +#ifdef HX_SMART_WAKEUP + ts->SMWP_enable = 0; + wakeup_source_init(&ts->ts_SMWP_wake_lock, + WAKE_LOCK_SUSPEND, HIMAX_common_NAME); + + ts->himax_smwp_wq = create_singlethread_workqueue("HMX_SMWP_WORK"); + if (!ts->himax_smwp_wq) { + E(" allocate himax_smwp_wq failed\n"); + err = -ENOMEM; + goto err_smwp_wq_failed; + } + INIT_DELAYED_WORK(&ts->smwp_work, himax_SMWP_work); +#endif +#ifdef HX_HIGH_SENSE + ts->HSEN_enable = 0; + ts->himax_hsen_wq = create_singlethread_workqueue("HMX_HSEN_WORK"); + if (!ts->himax_hsen_wq) { + E(" allocate himax_hsen_wq failed\n"); + err = -ENOMEM; + goto err_hsen_wq_failed; + } + INIT_DELAYED_WORK(&ts->hsen_work, himax_HSEN_func); +#endif + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + himax_touch_proc_init(); +#endif + +#if defined(HX_USB_DETECT) + if (ts->cable_config) + cable_detect_register_notifier(&himax_cable_status_handler); +#endif + + err = himax_ts_register_interrupt(ts->client); + if (err) + goto err_register_interrupt_failed; + return true; + +err_register_interrupt_failed: +#ifdef HX_HIGH_SENSE +err_hsen_wq_failed: +#endif +#ifdef HX_SMART_WAKEUP +err_smwp_wq_failed: + wakeup_source_trash(&ts->ts_SMWP_wake_lock); +#endif +err_input_register_device_failed: + input_free_device(ts->input_dev); +err_detect_failed: +#ifdef HX_TP_PROC_FLASH_DUMP +err_create_wq_failed: +#endif +err_ic_package_failed: +return false; +} + +int himax_chip_common_probe(struct i2c_client *client, +const struct i2c_device_id *id) +{ + int err = 0; + struct himax_ts_data *ts; + struct himax_i2c_platform_data *pdata; + + /*Check I2C functionality*/ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + E("%s: i2c check functionality error\n", __func__); + err = -ENODEV; + goto err_check_functionality_failed; + } + + ts = kzalloc(sizeof(struct himax_ts_data), GFP_KERNEL); + if (ts == NULL) { + E("%s: allocate himax_ts_data failed\n", __func__); + err = -ENOMEM; + goto err_alloc_data_failed; + } + + i2c_set_clientdata(client, ts); + ts->client = client; + ts->dev = &client->dev; + mutex_init(&ts->rw_lock); + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (pdata == NULL) { /*Allocate Platform data space*/ + err = -ENOMEM; + goto err_dt_platform_data_fail; + } + + ic_data = kzalloc(sizeof(*ic_data), GFP_KERNEL); + if (ic_data == NULL) { /*Allocate IC data space*/ + err = -ENOMEM; + goto err_dt_ic_data_fail; + } + +#ifdef CONFIG_OF + /*DeviceTree Init Platform_data*/ + if (client->dev.of_node) { + err = himax_parse_dt(ts, pdata); + if (err < 0) { + I(" pdata is NULL for DT\n"); + goto err_alloc_dt_pdata_failed; + } + } +#endif + +#ifdef HX_RST_PIN_FUNC + ts->rst_gpio = pdata->gpio_reset; +#endif + + himax_gpio_power_config(ts->client, pdata); + + err = himax_ts_pinctrl_init(ts); + if (err || ts->ts_pinctrl == NULL) + E(" Pinctrl init failed\n"); + +#ifndef CONFIG_OF + if (pdata->power) { + err = pdata->power(1); + if (err < 0) { + E("%s: power on failed\n", __func__); + goto err_power_failed; + } + } +#endif + ts->pdata = pdata; + private_ts = ts; + + mutex_init(&ts->fb_mutex); + /* ts initialization is deferred till FB_UNBLACK event; + * probe is considered pending till then.*/ + ts->probe_done = false; +#ifdef CONFIG_FB + err = himax_fb_register(ts); + if (err) { + E("Falied to register fb notifier\n"); + err = -ENOMEM; + goto err_fb_notif_wq_create; + } +#endif + + return 0; + +#ifdef CONFIG_FB +err_fb_notif_wq_create: +#endif +#ifdef CONFIG_OF +err_alloc_dt_pdata_failed: +#else +err_power_failed: +err_get_platform_data_fail: +#endif + if (ts->ts_pinctrl) { + if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { + devm_pinctrl_put(ts->ts_pinctrl); + ts->ts_pinctrl = NULL; + } else { + err = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_release); + if (err) + E("failed to select relase pinctrl state %d\n", + err); + } + } + kfree(ic_data); + +err_dt_ic_data_fail: + kfree(pdata); + +err_dt_platform_data_fail: + kfree(ts); + +err_alloc_data_failed: + +err_check_functionality_failed: + probe_fail_flag = 1; + return err; + +} + +int himax_chip_common_remove(struct i2c_client *client) +{ + struct himax_ts_data *ts = i2c_get_clientdata(client); + int ret; +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + himax_touch_proc_deinit(); +#endif +#ifdef CONFIG_FB + if (fb_unregister_client(&ts->fb_notif)) { + dev_err(&client->dev, + "Error occurred while unregistering fb_notifier.\n"); + } +#endif + + if (!ts->use_irq) + hrtimer_cancel(&ts->timer); + + destroy_workqueue(ts->himax_wq); + + if (ts->protocol_type == PROTOCOL_TYPE_B) + input_mt_destroy_slots(ts->input_dev); + + input_unregister_device(ts->input_dev); + + if (ts->ts_pinctrl) { + if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { + devm_pinctrl_put(ts->ts_pinctrl); + ts->ts_pinctrl = NULL; + } else { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_release); + if (ret) + E("failed to select relase pinctrl state %d\n", + ret); + } + } +#ifdef HX_SMART_WAKEUP + wakeup_source_trash(&ts->ts_SMWP_wake_lock); +#endif + kfree(ts); + + return 0; + +} + +int himax_chip_common_suspend(struct himax_ts_data *ts) +{ + int ret; + + if (ts->suspended) { + I("%s: Already suspended. Skipped.\n", __func__); + return 0; + + } else { + ts->suspended = true; + I("%s: enter\n", __func__); + } + +#ifdef HX_TP_PROC_FLASH_DUMP + if (getFlashDumpGoing()) { + I("[himax] %s: Flash dump is going,reject suspend\n", + __func__); + return 0; + } +#endif +#ifdef HX_TP_PROC_HITOUCH + if (hitouch_is_connect) { + I("[himax] %s: Hitouch connect,reject suspend\n", + __func__); + return 0; + } +#endif +#ifdef HX_SMART_WAKEUP + if (ts->SMWP_enable) { + atomic_set(&ts->suspend_mode, 1); + ts->pre_finger_mask = 0; + FAKE_POWER_KEY_SEND = false; + I("[himax] %s: SMART_WAKEUP enable,reject suspend\n", + __func__); + return 0; + } +#endif +#ifdef HX_ESD_WORKAROUND + ESD_00_counter = 0; + ESD_00_Flag = 0; +#endif + if (!ts->use_irq) { + ret = cancel_work_sync(&ts->work); + if (ret) + himax_int_enable(ts->client->irq, 1); + } + + /*ts->first_pressed = 0;*/ + atomic_set(&ts->suspend_mode, 1); + ts->pre_finger_mask = 0; + + if (ts->ts_pinctrl) { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_suspend); + if (ret < 0) + E("Failed to get idle pinctrl state %d\n", ret); + } + + if (ts->pdata->powerOff3V3 && ts->pdata->power) + ts->pdata->power(0); + + return 0; +} + +int himax_chip_common_resume(struct himax_ts_data *ts) +{ + int retval; + + I("%s: enter\n", __func__); + + if (ts->pdata->powerOff3V3 && ts->pdata->power) + ts->pdata->power(1); + + if (ts->protocol_type == PROTOCOL_TYPE_A) + input_mt_sync(ts->input_dev); + input_report_key(ts->input_dev, BTN_TOUCH, 0); + input_sync(ts->input_dev); + + if (ts->ts_pinctrl) { + retval = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_active); + if (retval < 0) { + E("Cannot get default pinctrl state %d\n", retval); + goto err_pinctrl_select_resume; + } + } + + atomic_set(&ts->suspend_mode, 0); + + himax_int_enable(ts->client->irq, 1); + + ts->suspended = false; +#if defined(HX_USB_DETECT2) + ts->usb_connected = 0x00; + himax_cable_detect_func(); +#endif +#ifdef HX_SMART_WAKEUP + queue_delayed_work(ts->himax_smwp_wq, + &ts->smwp_work, msecs_to_jiffies(1000)); +#endif +#ifdef HX_HIGH_SENSE + queue_delayed_work(ts->himax_hsen_wq, + &ts->hsen_work, msecs_to_jiffies(1000)); +#endif + return 0; +err_pinctrl_select_resume: + if (ts->pdata->powerOff3V3 && ts->pdata->power) + ts->pdata->power(0); + return retval; +} + diff --git a/drivers/input/touchscreen/hxchipset/himax_common.h b/drivers/input/touchscreen/hxchipset/himax_common.h new file mode 100644 index 000000000000..c4e24ba191bb --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_common.h @@ -0,0 +1,471 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef HIMAX_COMMON_H +#define HIMAX_COMMON_H + +#include "himax_platform.h" + +#include +/*#include */ +/*#include */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_FB) +#include +#include +#elif defined(CONFIG_HAS_EARLYSUSPEND) +#include +#endif + +#ifdef CONFIG_OF +#include +#endif +#define HIMAX_DRIVER_VER "0.3.1.0" + +#define FLASH_DUMP_FILE "/data/user/Flash_Dump.bin" +#define DIAG_COORDINATE_FILE "/sdcard/Coordinate_Dump.csv" + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + +#define HX_TP_PROC_DIAG +#define HX_TP_PROC_REGISTER +#define HX_TP_PROC_DEBUG +#define HX_TP_PROC_FLASH_DUMP +#define HX_TP_PROC_SELF_TEST +#define HX_TP_PROC_RESET +#define HX_TP_PROC_SENSE_ON_OFF +/*#define HX_TP_PROC_2T2R*/ + +int himax_touch_proc_init(void); +void himax_touch_proc_deinit(void); +#endif + +/*===========Himax Option function=============*/ +/*#define HX_RST_PIN_FUNC*/ +#define HX_AUTO_UPDATE_FW +/*#define HX_HIGH_SENSE*/ +/*#define HX_SMART_WAKEUP*/ +/*#define HX_USB_DETECT*/ +/*#define HX_ESD_WORKAROUND*/ +/*#define HX_USB_DETECT2*/ +/*#define HX_EN_SEL_BUTTON*//* Support Self Virtual key ,default is close*/ +#define HX_EN_MUT_BUTTON/* Support Mutual Virtual Key ,default is close*/ +/*#define HX_EN_CHECK_PATCH*/ + +#define HX_KEY_MAX_COUNT 4 +#define DEFAULT_RETRY_CNT 3 + +#define HX_VKEY_0 KEY_BACK +#define HX_VKEY_1 KEY_HOME +#define HX_VKEY_2 KEY_RESERVED +#define HX_VKEY_3 KEY_RESERVED +#define HX_KEY_ARRAY {HX_VKEY_0, HX_VKEY_1, HX_VKEY_2, HX_VKEY_3} + +#define SHIFTBITS 5 +/*#define FLASH_SIZE 131072*/ +#define FW_SIZE_60k 61440 +#define FW_SIZE_64k 65536 +#define FW_SIZE_124k 126976 +#define FW_SIZE_128k 131072 + +struct himax_ic_data { + int vendor_fw_ver; + int vendor_config_ver; + int vendor_sensor_id; + int HX_RX_NUM; + int HX_TX_NUM; + int HX_BT_NUM; + int HX_X_RES; + int HX_Y_RES; + int HX_MAX_PT; + bool HX_XY_REVERSE; + bool HX_INT_IS_EDGE; +#ifdef HX_TP_PROC_2T2R + int HX_RX_NUM_2; + int HX_TX_NUM_2; +#endif +}; + +struct himax_virtual_key { + int index; + int keycode; + int x_range_min; + int x_range_max; + int y_range_min; + int y_range_max; +}; + +struct himax_config { + uint8_t default_cfg; + uint8_t sensor_id; + uint8_t fw_ver; + uint16_t length; + uint32_t tw_x_min; + uint32_t tw_x_max; + uint32_t tw_y_min; + uint32_t tw_y_max; + uint32_t pl_x_min; + uint32_t pl_x_max; + uint32_t pl_y_min; + uint32_t pl_y_max; + uint8_t c1[11]; + uint8_t c2[11]; + uint8_t c3[11]; + uint8_t c4[11]; + uint8_t c5[11]; + uint8_t c6[11]; + uint8_t c7[11]; + uint8_t c8[11]; + uint8_t c9[11]; + uint8_t c10[11]; + uint8_t c11[11]; + uint8_t c12[11]; + uint8_t c13[11]; + uint8_t c14[11]; + uint8_t c15[11]; + uint8_t c16[11]; + uint8_t c17[11]; + uint8_t c18[17]; + uint8_t c19[15]; + uint8_t c20[5]; + uint8_t c21[11]; + uint8_t c22[4]; + uint8_t c23[3]; + uint8_t c24[3]; + uint8_t c25[4]; + uint8_t c26[2]; + uint8_t c27[2]; + uint8_t c28[2]; + uint8_t c29[2]; + uint8_t c30[2]; + uint8_t c31[2]; + uint8_t c32[2]; + uint8_t c33[2]; + uint8_t c34[2]; + uint8_t c35[3]; + uint8_t c36[5]; + uint8_t c37[5]; + uint8_t c38[9]; + uint8_t c39[14]; + uint8_t c40[159]; + uint8_t c41[99]; +}; + +struct himax_ts_data { + bool suspended; + bool probe_done; + struct mutex fb_mutex; + struct mutex rw_lock; + atomic_t suspend_mode; + uint8_t x_channel; + uint8_t y_channel; + uint8_t useScreenRes; + uint8_t diag_command; + uint8_t protocol_type; + uint8_t first_pressed; + uint8_t coord_data_size; + uint8_t area_data_size; + uint8_t raw_data_frame_size; + uint8_t raw_data_nframes; + uint8_t nFinger_support; + uint8_t irq_enabled; + uint8_t diag_self[50]; + uint16_t finger_pressed; + uint16_t last_slot; + uint16_t pre_finger_mask; + uint32_t debug_log_level; + uint32_t widthFactor; + uint32_t heightFactor; + uint32_t tw_x_min; + uint32_t tw_x_max; + uint32_t tw_y_min; + uint32_t tw_y_max; + uint32_t pl_x_min; + uint32_t pl_x_max; + uint32_t pl_y_min; + uint32_t pl_y_max; + + int use_irq; + int (*power)(int on); + int pre_finger_data[10][2]; + + struct device *dev; + struct workqueue_struct *himax_wq; + struct work_struct work; + struct input_dev *input_dev; + struct hrtimer timer; + struct i2c_client *client; + struct himax_i2c_platform_data *pdata; + struct himax_virtual_key *button; + +#if defined(CONFIG_FB) + struct notifier_block fb_notif; +#elif defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + struct workqueue_struct *flash_wq; + struct work_struct flash_work; +#endif + +#ifdef HX_RST_PIN_FUNC + int rst_gpio; +#endif + +#ifdef HX_TP_PROC_DIAG + struct workqueue_struct *himax_diag_wq; + struct delayed_work himax_diag_delay_wrok; +#endif +#ifdef HX_SMART_WAKEUP + uint8_t SMWP_enable; + uint8_t gesture_cust_en[16]; + struct wakeup_source ts_SMWP_wake_lock; + struct workqueue_struct *himax_smwp_wq; + struct delayed_work smwp_work; +#endif + +#ifdef HX_HIGH_SENSE + uint8_t HSEN_enable; + struct workqueue_struct *himax_hsen_wq; + struct delayed_work hsen_work; +#endif + +#if defined(HX_USB_DETECT) || defined(HX_USB_DETECT2) + uint8_t usb_connected; + uint8_t *cable_config; +#endif + + /* pinctrl data */ + struct pinctrl *ts_pinctrl; + struct pinctrl_state *pinctrl_state_active; + struct pinctrl_state *pinctrl_state_suspend; + struct pinctrl_state *pinctrl_state_release; +}; + +#define HX_CMD_NOP 0x00 +#define HX_CMD_SETMICROOFF 0x35 +#define HX_CMD_SETROMRDY 0x36 +#define HX_CMD_TSSLPIN 0x80 +#define HX_CMD_TSSLPOUT 0x81 +#define HX_CMD_TSSOFF 0x82 +#define HX_CMD_TSSON 0x83 +#define HX_CMD_ROE 0x85 +#define HX_CMD_RAE 0x86 +#define HX_CMD_RLE 0x87 +#define HX_CMD_CLRES 0x88 +#define HX_CMD_TSSWRESET 0x9E +#define HX_CMD_SETDEEPSTB 0xD7 +#define HX_CMD_SET_CACHE_FUN 0xDD +#define HX_CMD_SETIDLE 0xF2 +#define HX_CMD_SETIDLEDELAY 0xF3 +#define HX_CMD_SELFTEST_BUFFER 0x8D +#define HX_CMD_MANUALMODE 0x42 +#define HX_CMD_FLASH_ENABLE 0x43 +#define HX_CMD_FLASH_SET_ADDRESS 0x44 +#define HX_CMD_FLASH_WRITE_REGISTER 0x45 +#define HX_CMD_FLASH_SET_COMMAND 0x47 +#define HX_CMD_FLASH_WRITE_BUFFER 0x48 +#define HX_CMD_FLASH_PAGE_ERASE 0x4D +#define HX_CMD_FLASH_SECTOR_ERASE 0x4E +#define HX_CMD_CB 0xCB +#define HX_CMD_EA 0xEA +#define HX_CMD_4A 0x4A +#define HX_CMD_4F 0x4F +#define HX_CMD_B9 0xB9 +#define HX_CMD_76 0x76 + +enum input_protocol_type { + PROTOCOL_TYPE_A = 0x00, + PROTOCOL_TYPE_B = 0x01, +}; + +#ifdef HX_HIGH_SENSE +void himax_set_HSEN_func(struct i2c_client *client, uint8_t HSEN_enable); +#endif + +#ifdef HX_SMART_WAKEUP +#define GEST_PTLG_ID_LEN (4) +#define GEST_PTLG_HDR_LEN (4) +#define GEST_PTLG_HDR_ID1 (0xCC) +#define GEST_PTLG_HDR_ID2 (0x44) +#define GEST_PT_MAX_NUM (128) + +#ifdef HX_GESTURE_TRACK +static int gest_pt_cnt; +static int gest_pt_x[GEST_PT_MAX_NUM]; +static int gest_pt_y[GEST_PT_MAX_NUM]; +static int gest_start_x, gest_start_y, gest_end_x, gest_end_y; +static int gest_width, gest_height, gest_mid_x, gest_mid_y; +static int gn_gesture_coor[16]; +#endif + +void himax_set_SMWP_func(struct i2c_client *client, uint8_t SMWP_enable); +extern bool FAKE_POWER_KEY_SEND; + + enum gesture_event_type { + EV_GESTURE_01 = 0x01, + EV_GESTURE_02, + EV_GESTURE_03, + EV_GESTURE_04, + EV_GESTURE_05, + EV_GESTURE_06, + EV_GESTURE_07, + EV_GESTURE_08, + EV_GESTURE_09, + EV_GESTURE_10, + EV_GESTURE_11, + EV_GESTURE_12, + EV_GESTURE_13, + EV_GESTURE_14, + EV_GESTURE_15, + EV_GESTURE_PWR = 0x80, + }; + +#define KEY_CUST_01 251 +#define KEY_CUST_02 252 +#define KEY_CUST_03 253 +#define KEY_CUST_04 254 +#define KEY_CUST_05 255 +#define KEY_CUST_06 256 +#define KEY_CUST_07 257 +#define KEY_CUST_08 258 +#define KEY_CUST_09 259 +#define KEY_CUST_10 260 +#define KEY_CUST_11 261 +#define KEY_CUST_12 262 +#define KEY_CUST_13 263 +#define KEY_CUST_14 264 +#define KEY_CUST_15 265 +#endif + +#ifdef HX_ESD_WORKAROUND + extern u8 HX_ESD_RESET_ACTIVATE; +#endif + +extern int irq_enable_count; + +#ifdef QCT +irqreturn_t himax_ts_thread(int irq, void *ptr); +int himax_input_register(struct himax_ts_data *ts); +#endif + +int himax_chip_common_probe(struct i2c_client *client, +const struct i2c_device_id *id); +int himax_chip_common_remove(struct i2c_client *client); +int himax_chip_common_suspend(struct himax_ts_data *ts); +int himax_chip_common_resume(struct himax_ts_data *ts); +int himax_loadSensorConfig(struct i2c_client *client, +struct himax_i2c_platform_data *pdata); + +#ifdef HX_USB_DETECT2 +/*extern kal_bool upmu_is_chr_det(void);*/ +void himax_cable_detect_func(void); +#endif + +#ifdef HX_AUTO_UPDATE_FW +extern unsigned long FW_VER_MAJ_FLASH_ADDR; +extern unsigned long FW_VER_MIN_FLASH_ADDR; +extern unsigned long CFG_VER_MAJ_FLASH_ADDR; +extern unsigned long CFG_VER_MIN_FLASH_ADDR; +#endif +extern unsigned long FW_VER_MAJ_FLASH_LENG; +extern unsigned long FW_VER_MIN_FLASH_LENG; +extern unsigned long CFG_VER_MAJ_FLASH_LENG; +extern unsigned long CFG_VER_MIN_FLASH_LENG; +extern unsigned char IC_TYPE; +extern unsigned char IC_CHECKSUM; + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +extern int himax_touch_proc_init(void); +extern void himax_touch_proc_deinit(void); +/*PROC-START*/ +#ifdef HX_TP_PROC_FLASH_DUMP +extern void himax_ts_flash_func(void); +extern void setFlashBuffer(void); +extern bool getFlashDumpGoing(void); +extern uint8_t getSysOperation(void); +extern void setSysOperation(uint8_t operation); +#endif + +#ifdef HX_TP_PROC_HITOUCH +extern bool hitouch_is_connect; +#endif + +#ifdef HX_TP_PROC_DIAG + extern int touch_monitor_stop_flag; + + extern int touch_monitor_stop_limit; + + extern void himax_ts_diag_func(void); + + extern int16_t *getMutualBuffer(void); + extern int16_t *getMutualNewBuffer(void); + extern int16_t *getMutualOldBuffer(void); + extern int16_t *getSelfBuffer(void); + extern uint8_t getXChannel(void); + extern uint8_t getYChannel(void); + extern uint8_t getDiagCommand(void); + extern void setXChannel(uint8_t x); + extern void setYChannel(uint8_t y); + extern void setMutualBuffer(void); + extern void setMutualNewBuffer(void); + extern void setMutualOldBuffer(void); + extern uint8_t coordinate_dump_enable; + extern struct file *coordinate_fn; + extern uint8_t diag_coor[128]; +#ifdef HX_TP_PROC_2T2R + extern int16_t *getMutualBuffer_2(void); + extern uint8_t getXChannel_2(void); + extern uint8_t getYChannel_2(void); + extern void setXChannel_2(uint8_t x); + extern void setYChannel_2(uint8_t y); + extern void setMutualBuffer_2(void); +#endif +#endif +/*PROC-END*/ +#endif + +#ifdef HX_USB_DETECT2 + extern bool USB_Flag; +#endif +#ifdef HX_ESD_WORKAROUND + extern void HX_report_ESD_event(void); + unsigned char ESD_00_counter = 0; + unsigned char ESD_00_Flag = 0; +#endif +bool himax_ts_init(struct himax_ts_data *ts); + +#endif + diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.c b/drivers/input/touchscreen/hxchipset/himax_debug.c new file mode 100644 index 000000000000..a5bdbf207e01 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_debug.c @@ -0,0 +1,2205 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_debug.h" +#include "himax_ic.h" + +/*struct himax_debug_data* debug_data;*/ + +#ifdef HX_TP_PROC_DIAG +#ifdef HX_TP_PROC_2T2R +int HX_RX_NUM_2; +int HX_TX_NUM_2; +#endif +int touch_monitor_stop_flag; +int touch_monitor_stop_limit = 5; +uint8_t g_diag_arr_num; +#endif + +#ifdef HX_ESD_WORKAROUND +u8 HX_ESD_RESET_ACTIVATE; +#endif + +#ifdef HX_SMART_WAKEUP +bool FAKE_POWER_KEY_SEND; +#endif + +/*======================================================== + +Segment : Himax PROC Debug Function + +==========================================================*/ +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + +static ssize_t himax_vendor_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + ssize_t ret = 0; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + ret += snprintf(temp_buf, len, + "%s_FW:%#x_CFG:%#x_SensorId:%#x\n", + HIMAX_common_NAME, ic_data->vendor_fw_ver, + ic_data->vendor_config_ver, ic_data->vendor_sensor_id); + + HX_PROC_SEND_FLAG = 1; + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + } else + HX_PROC_SEND_FLAG = 0; + + return ret; +} + +const struct file_operations himax_proc_vendor_ops = { + .owner = THIS_MODULE, + .read = himax_vendor_read, +}; + +static ssize_t himax_attn_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + ssize_t ret = 0; + struct himax_ts_data *ts_data; + char *temp_buf; + + ts_data = private_ts; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + ret += snprintf(temp_buf, len, "attn = %x\n", + himax_int_gpio_read(ts_data->pdata->gpio_irq)); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; + + return ret; +} + +const struct file_operations himax_proc_attn_ops = { + .owner = THIS_MODULE, + .read = himax_attn_read, +}; + +static ssize_t himax_int_en_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t ret = 0; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + ret += snprintf(temp_buf, len-1, "%d ", ts->irq_enabled); + ret += snprintf(temp_buf, 1, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; + return ret; +} + +static ssize_t himax_int_en_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf_tmp[12] = {0}; + int value, ret = 0; + + if (len >= 12) { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf_tmp, buff, len)) + return -EFAULT; + + if (buf_tmp[0] == '0') + value = false; + else if (buf_tmp[0] == '1') + value = true; + else + return -EINVAL; + + if (value) { + if (ic_data->HX_INT_IS_EDGE) { +#ifdef MTK +#ifdef CONFIG_OF_TOUCH + himax_int_enable(ts->client->irq, 1); +#else + /*mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, + CUST_EINT_TOUCH_PANEL_TYPE); + mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, + CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN);*/ + mt_eint_registration(ts->client->irq, + EINTF_TRIGGER_FALLING, tpd_eint_interrupt_handler, 1); +#endif +#endif +#ifdef QCT + ret = request_threaded_irq(ts->client->irq, + NULL, himax_ts_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + ts->client->name, ts); +#endif + } else { +#ifdef MTK +#ifdef CONFIG_OF_TOUCH + himax_int_enable(ts->client->irq, 1); +#else + /*mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, + CUST_EINT_TOUCH_PANEL_TYPE); + mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, + CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN);*/ + mt_eint_registration(ts->client->irq, + EINTF_TRIGGER_LOW, tpd_eint_interrupt_handler, 1); +#endif +#endif +#ifdef QCT + ret = request_threaded_irq(ts->client->irq, + NULL, himax_ts_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + ts->client->name, ts); +#endif + } + if (ret == 0) { + ts->irq_enabled = 1; + irq_enable_count = 1; + } + } else { + himax_int_enable(ts->client->irq, 0); + free_irq(ts->client->irq, ts); + ts->irq_enabled = 0; + } + + return len; +} + +const struct file_operations himax_proc_int_en_ops = { + .owner = THIS_MODULE, + .read = himax_int_en_read, + .write = himax_int_en_write, +}; + +static ssize_t himax_layout_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t ret = 0; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_x_min); + ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_x_max); + ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_y_min); + ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_y_max); + ret += snprintf(temp_buf, len, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; + + return ret; +} + +static ssize_t himax_layout_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf_tmp[5]; + int i = 0, j = 0, k = 0, ret; + unsigned long value; + int layout[4] = {0}; + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + for (i = 0 ; i < 20 ; i++) { + if (buf[i] == ',' || buf[i] == '\n') { + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + if (i - j <= 5) + memcpy(buf_tmp, buf + j, i - j); + else { + I("buffer size is over 5 char\n"); + return len; + } + j = i + 1; + if (k < 4) { + ret = kstrtoul(buf_tmp, 10, &value); + layout[k++] = value; + } + } + } + if (k == 4) { + ts->pdata->abs_x_min = layout[0]; + ts->pdata->abs_x_max = layout[1]; + ts->pdata->abs_y_min = layout[2]; + ts->pdata->abs_y_max = layout[3]; + I("%d, %d, %d, %d\n", ts->pdata->abs_x_min, + ts->pdata->abs_x_max, ts->pdata->abs_y_min, + ts->pdata->abs_y_max); + input_unregister_device(ts->input_dev); + himax_input_register(ts); + } else { + I("ERR@%d, %d, %d, %d\n", ts->pdata->abs_x_min, + ts->pdata->abs_x_max, ts->pdata->abs_y_min, + ts->pdata->abs_y_max); + } + return len; +} + +const struct file_operations himax_proc_layout_ops = { + .owner = THIS_MODULE, + .read = himax_layout_read, + .write = himax_layout_write, +}; + +static ssize_t himax_debug_level_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts_data; + size_t ret = 0; + char *temp_buf; + + ts_data = private_ts; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + ret += snprintf(temp_buf, len, "%d\n", + ts_data->debug_log_level); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; + + return ret; +} + +static ssize_t himax_debug_level_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts; + char buf_tmp[11]; + int i; + + ts = private_ts; + + if (len >= 12) { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf_tmp, buff, len)) + return -EFAULT; + + ts->debug_log_level = 0; + for (i = 0 ; i < len - 1 ; i++) { + if (buf_tmp[i] >= '0' && buf_tmp[i] <= '9') + ts->debug_log_level |= (buf_tmp[i] - '0'); + else if (buf_tmp[i] >= 'A' && buf_tmp[i] <= 'F') + ts->debug_log_level |= (buf_tmp[i]-'A' + 10); + else if (buf_tmp[i] >= 'a' && buf_tmp[i] <= 'f') + ts->debug_log_level |= (buf_tmp[i] - 'a' + 10); + + if (i != len - 2) + ts->debug_log_level <<= 4; + } + + if (ts->debug_log_level & BIT(3)) { + if (ts->pdata->screenWidth > 0 && ts->pdata->screenHeight > 0 && + (ts->pdata->abs_x_max - ts->pdata->abs_x_min) > 0 && + (ts->pdata->abs_y_max - ts->pdata->abs_y_min) > 0) { + ts->widthFactor = + (ts->pdata->screenWidth << SHIFTBITS) + / (ts->pdata->abs_x_max - ts->pdata->abs_x_min); + ts->heightFactor = + (ts->pdata->screenHeight << SHIFTBITS) + / (ts->pdata->abs_y_max - ts->pdata->abs_y_min); + if (ts->widthFactor > 0 && ts->heightFactor > 0) + ts->useScreenRes = 1; + else { + ts->heightFactor = 0; + ts->widthFactor = 0; + ts->useScreenRes = 0; + } + } else + I("Enable finger debug with raw position mode!\n"); + } else { + ts->useScreenRes = 0; + ts->widthFactor = 0; + ts->heightFactor = 0; + } + + return len; +} + +const struct file_operations himax_proc_debug_level_ops = { + .owner = THIS_MODULE, + .read = himax_debug_level_read, + .write = himax_debug_level_write, +}; + +#ifdef HX_TP_PROC_REGISTER +static ssize_t himax_proc_register_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int ret = 0; + uint16_t loop_i; + uint8_t data[128]; + char *temp_buf; + + memset(data, 0x00, sizeof(data)); + + I("himax_register_show: %x,%x,%x,%x\n", register_command[0], + register_command[1], register_command[2], register_command[3]); + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + himax_register_read(private_ts->client, + register_command, 1, data); + + ret += snprintf(temp_buf, len, "command: %x,%x,%x,%x\n", + register_command[0], register_command[1], + register_command[2], register_command[3]); + + for (loop_i = 0 ; loop_i < 128 ; loop_i++) { + ret += snprintf(temp_buf + ret, + sizeof(data[loop_i]), "0x%2.2X ", data[loop_i]); + if ((loop_i % 16) == 15) + ret += snprintf(temp_buf + ret, 1, "\n"); + } + ret += snprintf(temp_buf + ret, len, "\n"); + HX_PROC_SEND_FLAG = 1; + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + } else + HX_PROC_SEND_FLAG = 0; + return ret; +} + +static ssize_t himax_proc_register_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf_tmp[16], length = 0; + unsigned long result = 0; + uint8_t loop_i = 0; + uint16_t base = 5; + uint8_t write_da[128]; + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + memset(write_da, 0x0, sizeof(write_da)); + + I("himax %s\n", buf); + + if ((buf[0] == 'r' || buf[0] == 'w') && buf[1] == ':') { + + if (buf[2] == 'x') { + memcpy(buf_tmp, buf + 3, 8); + if (!kstrtoul(buf_tmp, 16, &result)) { + register_command[0] = + (uint8_t)result; + register_command[1] = + (uint8_t)(result >> 8); + register_command[2] = + (uint8_t)(result >> 16); + register_command[3] = + (uint8_t)(result >> 24); + } + base = 11; + I("CMD: %x,%x,%x,%x\n", register_command[0], + register_command[1], register_command[2], + register_command[3]); + + for (loop_i = 0 ; loop_i < 128 ; loop_i++) { + if (buf[base] == '\n') { + if (buf[0] == 'w') { + himax_register_write + (private_ts->client, + register_command + , 1, write_da); + I("CMD:%x, %x, %x, %x,len=%d\n", + write_da[0], write_da[1], + write_da[2], write_da[3], + length); + } + I("\n"); + return len; + } + if (buf[base + 1] == 'x') { + buf_tmp[10] = '\n'; + buf_tmp[11] = '\0'; + memcpy(buf_tmp, buf + base + 2, 8); + if (!kstrtoul(buf_tmp, 16, &result)) { + write_da[loop_i] = + (uint8_t)result; + write_da[loop_i+1] = + (uint8_t)(result >> 8); + write_da[loop_i+2] = + (uint8_t)(result >> 16); + write_da[loop_i+3] = + (uint8_t)(result >> 24); + } + length += 4; + } + base += 10; + } + } + } + return len; +} + +const struct file_operations himax_proc_register_ops = { + .owner = THIS_MODULE, + .read = himax_proc_register_read, + .write = himax_proc_register_write, +}; +#endif + +#ifdef HX_TP_PROC_DIAG +int16_t *getMutualBuffer(void) +{ + return diag_mutual; +} +int16_t *getMutualNewBuffer(void) +{ + return diag_mutual_new; +} +int16_t *getMutualOldBuffer(void) +{ + return diag_mutual_old; +} +int16_t *getSelfBuffer(void) +{ + return &diag_self[0]; +} +uint8_t getXChannel(void) +{ + return x_channel; +} +uint8_t getYChannel(void) +{ + return y_channel; +} +uint8_t getDiagCommand(void) +{ + return diag_command; +} +void setXChannel(uint8_t x) +{ + x_channel = x; +} +void setYChannel(uint8_t y) +{ + y_channel = y; +} +void setMutualBuffer(void) +{ + diag_mutual = kzalloc + (x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); +} +void setMutualNewBuffer(void) +{ + diag_mutual_new = kzalloc + (x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); +} +void setMutualOldBuffer(void) +{ + diag_mutual_old = kzalloc + (x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); +} + +#ifdef HX_TP_PROC_2T2R +int16_t *getMutualBuffer_2(void) +{ + return diag_mutual_2; +} +uint8_t getXChannel_2(void) +{ + return x_channel_2; +} +uint8_t getYChannel_2(void) +{ + return y_channel_2; +} +void setXChannel_2(uint8_t x) +{ + x_channel_2 = x; +} +void setYChannel_2(uint8_t y) +{ + y_channel_2 = y; +} +void setMutualBuffer_2(void) +{ + diag_mutual_2 = kzalloc + (x_channel_2 * y_channel_2 * sizeof(int16_t), GFP_KERNEL); +} +#endif + +static ssize_t himax_diag_arrange_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + /*struct himax_ts_data *ts = private_ts;*/ + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + g_diag_arr_num = buf[0] - '0'; + I("%s: g_diag_arr_num = %d\n", __func__, g_diag_arr_num); + + return len; +} + +const struct file_operations himax_proc_diag_arrange_ops = { + .owner = THIS_MODULE, + .write = himax_diag_arrange_write, +}; + +static void himax_diag_arrange_print +(struct seq_file *s, int i, int j, int transpose) +{ + if (transpose) + seq_printf(s, "%6d", diag_mutual[j + i * x_channel]); + else + seq_printf(s, "%6d", diag_mutual[i + j * x_channel]); +} + +static void himax_diag_arrange_inloop +(struct seq_file *s, int in_init, bool transpose, int j) +{ + int i; + int in_max = 0; + + if (transpose) + in_max = y_channel; + else + in_max = x_channel; + + if (in_init > 0) { + for (i = in_init - 1 ; i >= 0 ; i--) + himax_diag_arrange_print(s, i, j, transpose); + } else { + for (i = 0 ; i < in_max ; i++) + himax_diag_arrange_print(s, i, j, transpose); + } +} + +static void himax_diag_arrange_outloop +(struct seq_file *s, int transpose, int out_init, int in_init) +{ + int j; + int out_max = 0; + + if (transpose) + out_max = x_channel; + else + out_max = y_channel; + + if (out_init > 0) { + for (j = out_init - 1 ; j >= 0 ; j--) { + himax_diag_arrange_inloop(s, in_init, transpose, j); + seq_printf(s, " %5d\n", diag_self[j]); + } + } else { + for (j = 0 ; j < out_max ; j++) { + himax_diag_arrange_inloop(s, in_init, transpose, j); + seq_printf(s, " %5d\n", diag_self[j]); + } + } +} + +static void himax_diag_arrange(struct seq_file *s) +{ + int bit2, bit1, bit0; + int i; + + bit2 = g_diag_arr_num >> 2; + bit1 = g_diag_arr_num >> 1 & 0x1; + bit0 = g_diag_arr_num & 0x1; + + if (g_diag_arr_num < 4) { + himax_diag_arrange_outloop(s, + bit2, bit1 * y_channel, bit0 * x_channel); + + for (i = y_channel ; i < x_channel + y_channel ; i++) + seq_printf(s, "%6d", diag_self[i]); + + } else { + himax_diag_arrange_outloop(s, + bit2, bit1 * x_channel, bit0 * y_channel); + + for (i = x_channel ; i < x_channel + y_channel ; i++) + seq_printf(s, "%6d", diag_self[i]); + + } +} + +static void *himax_diag_seq_start(struct seq_file *s, loff_t *pos) +{ + if (*pos >= 1) + return NULL; + return (void *)((unsigned long) *pos + 1); +} + +static void *himax_diag_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + return NULL; +} +static void himax_diag_seq_stop(struct seq_file *s, void *v) +{ +} +static int himax_diag_seq_read(struct seq_file *s, void *v) +{ + size_t count = 0; + int32_t loop_i;/*loop_j*/ + uint16_t mutual_num, self_num, width; + +#ifdef HX_TP_PROC_2T2R + if (Is_2T2R && diag_command == 4) { + mutual_num = x_channel_2 * y_channel_2; + /*don't add KEY_COUNT*/ + self_num = x_channel_2 + y_channel_2; + width = x_channel_2; + seq_printf(s, "ChannelStart: %4d, %4d\n\n", + x_channel_2, y_channel_2); + } else +#endif + { + mutual_num = x_channel * y_channel; + /*don't add KEY_COUNT*/ + self_num = x_channel + y_channel; + width = x_channel; + seq_printf(s, "ChannelStart: %4d, %4d\n\n", + x_channel, y_channel); + } + + /* start to show out the raw data in adb shell*/ + if (diag_command >= 1 && diag_command <= 6) { + if (diag_command <= 3) { + himax_diag_arrange(s); + seq_puts(s, "\n\n"); +#ifdef HX_EN_SEL_BUTTON + seq_putc(s, '\n'); + for (loop_i = 0 ; loop_i < HX_BT_NUM ; loop_i++) + seq_printf(s, "%6d", + diag_self[HX_RX_NUM + HX_TX_NUM + loop_i]); +#endif +#ifdef HX_TP_PROC_2T2R + } else if (Is_2T2R && diag_command == 4) { + for (loop_i = 0 ; loop_i < mutual_num ; loop_i++) { + seq_printf(s, "%4d", diag_mutual_2[loop_i]); + if ((loop_i % width) == (width - 1)) + seq_printf(s, " %6d\n", + diag_self[width + loop_i / width]); + } + seq_putc(s, '\n'); + for (loop_i = 0 ; loop_i < width ; loop_i++) { + seq_printf(s, "%6d", diag_self[loop_i]); + if (((loop_i) % width) == (width - 1)) + seq_putc(s, '\n'); + } +#ifdef HX_EN_SEL_BUTTON + seq_putc(s, '\n'); + for (loop_i = 0 ; loop_i < HX_BT_NUM ; loop_i++) { + seq_printf(s, "%4d", + diag_self[HX_RX_NUM_2 + HX_TX_NUM_2 + loop_i]); + } +#endif +#endif + } else if (diag_command > 4) { + for (loop_i = 0 ; loop_i < self_num ; loop_i++) { + seq_printf(s, "%4d", diag_self[loop_i]); + if (((loop_i - mutual_num) % width) + == (width - 1)) { + seq_putc(s, '\n'); + } + } + } else { + for (loop_i = 0 ; loop_i < mutual_num ; loop_i++) { + seq_printf(s, "%4d", diag_mutual[loop_i]); + if ((loop_i % width) == (width - 1)) + seq_putc(s, '\n'); + } + } + seq_puts(s, "ChannelEnd"); + seq_putc(s, '\n'); + } else if (diag_command == 7) { + for (loop_i = 0; loop_i < 128 ; loop_i++) { + if ((loop_i % 16) == 0) + seq_puts(s, "LineStart:"); + seq_printf(s, "%4d", diag_coor[loop_i]); + if ((loop_i % 16) == 15) + seq_putc(s, '\n'); + } + } else if (diag_command == 9 || + diag_command == 91 || diag_command == 92) { + + himax_diag_arrange(s); + seq_putc(s, '\n'); + } + + return count; +} +const struct seq_operations himax_diag_seq_ops = { + .start = himax_diag_seq_start, + .next = himax_diag_seq_next, + .stop = himax_diag_seq_stop, + .show = himax_diag_seq_read, +}; +static int himax_diag_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &himax_diag_seq_ops); +}; +bool DSRAM_Flag = false; + +/*DSRAM thread*/ +void himax_ts_diag_func(void) +{ + int i = 0, j = 0; + unsigned int index = 0; + int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2; + uint8_t info_data[total_size]; + int16_t *mutual_data = NULL; + int16_t *mutual_data_new = NULL; + int16_t *mutual_data_old = NULL; + int16_t new_data; + + himax_burst_enable(private_ts->client, 1); + if (diag_command == 9 || diag_command == 91) { + mutual_data = getMutualBuffer(); + } else if (diag_command == 92) { + mutual_data = getMutualBuffer(); + mutual_data_new = getMutualNewBuffer(); + mutual_data_old = getMutualOldBuffer(); + } + himax_get_DSRAM_data(private_ts->client, info_data); + + index = 0; + for (i = 0 ; i < ic_data->HX_TX_NUM ; i++) { + for (j = 0 ; j < ic_data->HX_RX_NUM ; j++) { + new_data = (short)(info_data[index + 1] + << 8 | info_data[index]); + if (diag_command == 9) { + mutual_data[i * ic_data->HX_RX_NUM + j] + = new_data; + /*Keep max data for 100 frame*/ + } else if (diag_command == 91) { + if (mutual_data[i * ic_data->HX_RX_NUM + j] + < new_data) { + mutual_data[i * ic_data->HX_RX_NUM + j] + = new_data; + } + /*Cal data for [N]-[N-1] frame*/ + } else if (diag_command == 92) { + mutual_data_new[i * ic_data->HX_RX_NUM + j] + = new_data; + + mutual_data[i * ic_data->HX_RX_NUM + j] = + mutual_data_new[i * ic_data->HX_RX_NUM + j] - + mutual_data_old[i * ic_data->HX_RX_NUM + j]; + } + index += 2; + } + } + /*copy N data to N-1 array*/ + if (diag_command == 92) { + memcpy(mutual_data_old, mutual_data_new, + x_channel * y_channel * sizeof(int16_t)); + } + + diag_max_cnt++; + if (diag_command == 9 || diag_command == 92) { + queue_delayed_work(private_ts->himax_diag_wq, + &private_ts->himax_diag_delay_wrok, 1/10*HZ); + } else if (diag_command == 91) { + if (diag_max_cnt > 100) {/*count for 100 frame*/ + /*Clear DSRAM flag*/ + DSRAM_Flag = false; + + /*Enable ISR*/ + himax_int_enable(private_ts->client->irq, 1); + + /*===================================== + test result command : 0x8002_0324 ==> 0x00 + =====================================*/ + himax_diag_register_set(private_ts->client, 0x00); + } else { + queue_delayed_work(private_ts->himax_diag_wq, + &private_ts->himax_diag_delay_wrok, 1 / 10 * HZ); + } + } +} + +static ssize_t himax_diag_write +(struct file *filp, const char __user *buff, size_t len, loff_t *data) +{ + char messages[80] = {0}; + + uint8_t command[2] = {0x00, 0x00}; + uint8_t receive[1]; + + memset(receive, 0x00, sizeof(receive)); + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(messages, buff, len)) + return -EFAULT; + + if (messages[1] == 0x0A) + diag_command = messages[0] - '0'; + else + diag_command = (messages[0] - '0') * 10 + (messages[1] - '0'); + + + I("[Himax]diag_command=0x%x\n", diag_command); + if (diag_command < 0x04) { + if (DSRAM_Flag) { + /*1. Clear DSRAM flag*/ + DSRAM_Flag = false; + + /*2. Stop DSRAM thread*/ + cancel_delayed_work_sync + (&private_ts->himax_diag_delay_wrok); + + /*3. Enable ISR*/ + himax_int_enable(private_ts->client->irq, 1); + } + command[0] = diag_command; + himax_diag_register_set(private_ts->client, command[0]); + /*coordinate dump start*/ + } else if (diag_command == 0x09 || + diag_command == 91 || diag_command == 92) { + + diag_max_cnt = 0; + /*Set data 0 everytime*/ + memset(diag_mutual, 0x00, + x_channel * y_channel * sizeof(int16_t)); + + /*1. Disable ISR*/ + himax_int_enable(private_ts->client->irq, 0); + + /*2. Start DSRAM thread*/ + /*himax_diag_register_set(private_ts->client, 0x0A);*/ + + queue_delayed_work(private_ts->himax_diag_wq, + &private_ts->himax_diag_delay_wrok, 2 * HZ / 100); + + I("%s: Start get raw data in DSRAM\n", __func__); + + /*3. Set DSRAM flag*/ + DSRAM_Flag = true; + } else { + command[0] = 0x00; + himax_diag_register_set(private_ts->client, command[0]); + E("[Himax]Diag command error!diag_command=0x%x\n", + diag_command); + } + return len; +} + +const struct file_operations himax_proc_diag_ops = { + .owner = THIS_MODULE, + .open = himax_diag_proc_open, + .read = seq_read, + .write = himax_diag_write, +}; +#endif + +#ifdef HX_TP_PROC_RESET +static ssize_t himax_reset_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf_tmp[12]; + + if (len >= 12) { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf_tmp, buff, len)) + return -EFAULT; + + /*if (buf_tmp[0] == '1') + ESD_HW_REST();*/ + + return len; +} + +const struct file_operations himax_proc_reset_ops = { + .owner = THIS_MODULE, + .write = himax_reset_write, +}; +#endif + +#ifdef HX_TP_PROC_DEBUG +static ssize_t himax_debug_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + size_t count = 0; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + if (debug_level_cmd == 't') { + if (fw_update_complete) { + count += snprintf(temp_buf, len, + "FW Update Complete "); + } else { + count += snprintf(temp_buf, len, + "FW Update Fail "); + } + + } else if (debug_level_cmd == 'h') { + if (handshaking_result == 0) { + count += snprintf(temp_buf, len, + "Handshaking Result = %d (MCU Running)\n", + handshaking_result); + } else if (handshaking_result == 1) { + count += snprintf(temp_buf, len, + "Handshaking Result = %d (MCU Stop)\n", + handshaking_result); + } else if (handshaking_result == 2) { + count += snprintf(temp_buf, len, + "Handshaking Result = %d (I2C Error)\n", + handshaking_result); + } else { + count += snprintf(temp_buf, len, + "Handshaking Result = error\n"); + } + } else if (debug_level_cmd == 'v') { + count += snprintf(temp_buf + count, len, + "FW_VER = "); + count += snprintf(temp_buf + count, len, + "0x%2.2X\n", ic_data->vendor_fw_ver); + count += snprintf(temp_buf + count, len, + "CONFIG_VER = "); + count += snprintf(temp_buf + count, len, + "0x%2.2X\n", ic_data->vendor_config_ver); + count += snprintf(temp_buf + count, len, + "\n"); + } else if (debug_level_cmd == 'd') { + count += snprintf(temp_buf + count, len, + "Himax Touch IC Information :\n"); + if (IC_TYPE == HX_85XX_D_SERIES_PWON) { + count += snprintf(temp_buf + count, len, + "IC Type : D\n"); + } else if (IC_TYPE == HX_85XX_E_SERIES_PWON) { + count += snprintf(temp_buf + count, len, + "IC Type : E\n"); + } else if (IC_TYPE == HX_85XX_ES_SERIES_PWON) { + count += snprintf(temp_buf + count, len, + "IC Type : ES\n"); + } else if (IC_TYPE == HX_85XX_F_SERIES_PWON) { + count += snprintf(temp_buf + count, len, + "IC Type : F\n"); + } else { + count += snprintf(temp_buf + count, len, + "IC Type error.\n"); + } + if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_SW) { + count += snprintf(temp_buf + count, len, + "IC Checksum : SW\n"); + } else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_HW) { + count += snprintf(temp_buf + count, len, + "IC Checksum : HW\n"); + } else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_CRC) { + count += snprintf(temp_buf + count, len, + "IC Checksum : CRC\n"); + } else { + count += snprintf(temp_buf + count, len, + "IC Checksum error.\n"); + } + if (ic_data->HX_INT_IS_EDGE) { + count += snprintf(temp_buf + count, len, + "Interrupt : EDGE TIRGGER\n"); + } else { + count += snprintf(temp_buf + count, len, + "Interrupt : LEVEL TRIGGER\n"); + } + count += snprintf(temp_buf + count, len, + "RX Num : %d\n", ic_data->HX_RX_NUM); + count += snprintf(temp_buf + count, len, + "TX Num : %d\n", ic_data->HX_TX_NUM); + count += snprintf(temp_buf + count, len, + "BT Num : %d\n", ic_data->HX_BT_NUM); + count += snprintf(temp_buf + count, len, + "X Resolution : %d\n", ic_data->HX_X_RES); + count += snprintf(temp_buf + count, len, + "Y Resolution : %d\n", ic_data->HX_Y_RES); + count += snprintf(temp_buf + count, len, + "Max Point : %d\n", ic_data->HX_MAX_PT); + count += snprintf(temp_buf + count, len, + "XY reverse : %d\n", ic_data->HX_XY_REVERSE); + #ifdef HX_TP_PROC_2T2R + if (Is_2T2R) { + count += snprintf(temp_buf + count, len, + "2T2R panel\n"); + count += snprintf(temp_buf + count, len, + "RX Num_2 : %d\n", HX_RX_NUM_2); + count += snprintf(temp_buf + count, len, + "TX Num_2 : %d\n", HX_TX_NUM_2); + } + #endif + } else if (debug_level_cmd == 'i') { + count += snprintf(temp_buf + count, len, + "Himax Touch Driver Version:\n"); + count += snprintf(temp_buf + count, len, + "%s\n", HIMAX_DRIVER_VER); + } + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; + return count; +} + +static ssize_t himax_debug_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + int result = 0; + char fileName[128]; + char buf[80] = {0}; + const struct firmware *fw = NULL; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + if (buf[0] == 'h') {/*handshaking*/ + debug_level_cmd = buf[0]; + + himax_int_enable(private_ts->client->irq, 0); + + /*0:Running, 1:Stop, 2:I2C Fail*/ + handshaking_result = himax_hand_shaking(private_ts->client); + + himax_int_enable(private_ts->client->irq, 1); + + return len; + } else if (buf[0] == 'v') { /*firmware version*/ + debug_level_cmd = buf[0]; + himax_int_enable(private_ts->client->irq, 0); +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(false, false); +#endif + himax_read_FW_ver(private_ts->client); + /*himax_check_chip_version();*/ +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true, false); +#endif + himax_int_enable(private_ts->client->irq, 1); + return len; + } else if (buf[0] == 'd') { /*ic information*/ + + debug_level_cmd = buf[0]; + return len; + } else if (buf[0] == 'i') {/*driver version*/ + + debug_level_cmd = buf[0]; + return len; + } else if (buf[0] == 't') { + + himax_int_enable(private_ts->client->irq, 0); + debug_level_cmd = buf[0]; + fw_update_complete = false; + + result = himax_load_CRC_bin_file(private_ts->client); + if (result < 0) { + E("%s: himax_load_CRC_bin_file fail Error Code=%d.\n", + __func__, result); + return result; + } + + memset(fileName, 0, 128); +/* parse the file name*/ + snprintf(fileName, len-4, "%s", &buf[4]); + I("%s: upgrade from file(%s) start!\n", __func__, fileName); + result = request_firmware(&fw, fileName, private_ts->dev); + if (result < 0) { + I("fail to request_firmware fwpath: %s (ret:%d)\n", + fileName, result); + return result; + } + I("%s: FW image: %02X, %02X, %02X, %02X ret=%d\n", __func__, + fw->data[0], fw->data[1], fw->data[2], fw->data[3], result); + if (result >= 0) { + /*start to upgrade*/ + himax_int_enable(private_ts->client->irq, 0); + + if ((buf[1] == '6') && (buf[2] == '0')) { + if (fts_ctpm_fw_upgrade_with_sys_fs_60k + (private_ts->client, (unsigned char *)fw->data, + fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + } else if ((buf[1] == '6') && (buf[2] == '4')) { + if (fts_ctpm_fw_upgrade_with_sys_fs_64k + (private_ts->client, (unsigned char *)fw->data, + fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + } else if ((buf[1] == '2') && (buf[2] == '4')) { + if (fts_ctpm_fw_upgrade_with_sys_fs_124k + (private_ts->client, (unsigned char *)fw->data, + fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + } else if ((buf[1] == '2') && (buf[2] == '8')) { + if (fts_ctpm_fw_upgrade_with_sys_fs_128k + (private_ts->client, (unsigned char *)fw->data, + fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + } else { + E("%s: Flash command fail: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } + release_firmware(fw); + goto firmware_upgrade_done; + /*return count;*/ + } + } + +firmware_upgrade_done: + +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true, false); +#endif + + himax_sense_on(private_ts->client, 0x01); + msleep(120); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + himax_int_enable(private_ts->client->irq, 1); + + /*todo himax_chip->tp_firmware_upgrade_proceed = 0; + todo himax_chip->suspend_state = 0; + todo enable_irq(himax_chip->irq);*/ + return len; +} + +const struct file_operations himax_proc_debug_ops = { + .owner = THIS_MODULE, + .read = himax_debug_read, + .write = himax_debug_write, +}; + +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + +static uint8_t getFlashCommand(void) +{ + return flash_command; +} + +static uint8_t getFlashDumpProgress(void) +{ + return flash_progress; +} + +static uint8_t getFlashDumpComplete(void) +{ + return flash_dump_complete; +} + +static uint8_t getFlashDumpFail(void) +{ + return flash_dump_fail; +} + +uint8_t getSysOperation(void) +{ + return sys_operation; +} + +static uint8_t getFlashReadStep(void) +{ + return flash_read_step; +} +/* +static uint8_t getFlashDumpSector(void) +{ + return flash_dump_sector; +} + +static uint8_t getFlashDumpPage(void) +{ + return flash_dump_page; +} +*/ +bool getFlashDumpGoing(void) +{ + return flash_dump_going; +} + +void setFlashBuffer(void) +{ + flash_buffer = kzalloc + (Flash_Size * sizeof(uint8_t), GFP_KERNEL); + memset(flash_buffer, 0x00, Flash_Size); +} + +void setSysOperation(uint8_t operation) +{ + sys_operation = operation; +} + +static void setFlashDumpProgress(uint8_t progress) +{ + flash_progress = progress; + /*I("setFlashDumpProgress : progress = %d , + flash_progress = %d\n",progress,flash_progress);*/ +} + +static void setFlashDumpComplete(uint8_t status) +{ + flash_dump_complete = status; +} + +static void setFlashDumpFail(uint8_t fail) +{ + flash_dump_fail = fail; +} + +static void setFlashCommand(uint8_t command) +{ + flash_command = command; +} + +static void setFlashReadStep(uint8_t step) +{ + flash_read_step = step; +} + +static void setFlashDumpSector(uint8_t sector) +{ + flash_dump_sector = sector; +} + +static void setFlashDumpPage(uint8_t page) +{ + flash_dump_page = page; +} + +static void setFlashDumpGoing(bool going) +{ + flash_dump_going = going; +} + +static ssize_t himax_proc_flash_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int ret = 0; + int loop_i; + uint8_t local_flash_read_step = 0; + uint8_t local_flash_complete = 0; + uint8_t local_flash_progress = 0; + uint8_t local_flash_command = 0; + uint8_t local_flash_fail = 0; + char *temp_buf; + + local_flash_complete = getFlashDumpComplete(); + local_flash_progress = getFlashDumpProgress(); + local_flash_command = getFlashCommand(); + local_flash_fail = getFlashDumpFail(); + + I("flash_progress = %d\n", local_flash_progress); + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + if (local_flash_fail) { + ret += snprintf(temp_buf + ret, len, + "FlashStart:Fail\n"); + ret += snprintf(temp_buf + ret, len, + "FlashEnd"); + ret += snprintf(temp_buf + ret, len, + "\n"); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + return ret; + } + + if (!local_flash_complete) { + ret += snprintf(temp_buf+ret, len, + "FlashStart:Ongoing:0x%2.2x\n", flash_progress); + ret += snprintf(temp_buf + ret, len, "FlashEnd"); + ret += snprintf(temp_buf + ret, len, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + return ret; + } + + if (local_flash_command == 1 && local_flash_complete) { + ret += snprintf(temp_buf+ret, len, + "FlashStart:Complete\n"); + ret += snprintf(temp_buf + ret, len, "FlashEnd"); + ret += snprintf(temp_buf + ret, len, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + return ret; + } + + if (local_flash_command == 3 && local_flash_complete) { + ret += snprintf(temp_buf+ret, len, "FlashStart:\n"); + for (loop_i = 0 ; loop_i < 128 ; loop_i++) { + ret += snprintf(temp_buf + ret, len, + "x%2.2x", flash_buffer[loop_i]); + if ((loop_i % 16) == 15) + ret += snprintf(temp_buf + ret, len, + "\n"); + } + ret += snprintf(temp_buf + ret, len, "FlashEnd"); + ret += snprintf(temp_buf + ret, len, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + return ret; + } + + /*flash command == 0 , report the data*/ + local_flash_read_step = getFlashReadStep(); + + ret += snprintf(temp_buf + ret, len, + "FlashStart:%2.2x\n", local_flash_read_step); + + for (loop_i = 0 ; loop_i < 1024 ; loop_i++) { + ret += snprintf(temp_buf + ret, len, "x%2.2X", + flash_buffer[local_flash_read_step * 1024 + loop_i]); + + if ((loop_i % 16) == 15) + ret += snprintf(temp_buf + ret, len, "\n"); + } + + ret += snprintf(temp_buf + ret, len, "FlashEnd"); + ret += snprintf(temp_buf + ret, len, "\n"); + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; + return ret; +} + +static ssize_t himax_proc_flash_write(struct file *file, +const char *buff, size_t len, loff_t *pos) +{ + char buf_tmp[6]; + unsigned long result = 0; + uint8_t loop_i = 0; + int base = 0; + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + + I("%s: buf[0] = %s\n", __func__, buf); + + if (getSysOperation() == 1) { + E("%s: PROC is busy , return!\n", __func__); + return len; + } + + if (buf[0] == '0') { + setFlashCommand(0); + if (buf[1] == ':' && buf[2] == 'x') { + memcpy(buf_tmp, buf + 3, 2); + I("%s: read_Step = %s\n", __func__, buf_tmp); + if (!kstrtoul(buf_tmp, 16, &result)) { + I("%s: read_Step = %lu\n", __func__, result); + setFlashReadStep(result); + } + } + /* 1_60,1_64,1_24,1_28 for flash size 60k,64k,124k,128k*/ + } else if (buf[0] == '1') { + + setSysOperation(1); + setFlashCommand(1); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + if ((buf[1] == '_') && (buf[2] == '6')) { + if (buf[3] == '0') + Flash_Size = FW_SIZE_60k; + else if (buf[3] == '4') + Flash_Size = FW_SIZE_64k; + + } else if ((buf[1] == '_') && (buf[2] == '2')) { + if (buf[3] == '4') + Flash_Size = FW_SIZE_124k; + else if (buf[3] == '8') + Flash_Size = FW_SIZE_128k; + } + queue_work(private_ts->flash_wq, &private_ts->flash_work); + /* 2_60,2_64,2_24,2_28 for flash size 60k,64k,124k,128k*/ + } else if (buf[0] == '2') { + setSysOperation(1); + setFlashCommand(2); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + if ((buf[1] == '_') && (buf[2] == '6')) { + if (buf[3] == '0') + Flash_Size = FW_SIZE_60k; + else if (buf[3] == '4') + Flash_Size = FW_SIZE_64k; + + } else if ((buf[1] == '_') && (buf[2] == '2')) { + if (buf[3] == '4') + Flash_Size = FW_SIZE_124k; + else if (buf[3] == '8') + Flash_Size = FW_SIZE_128k; + + } + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } else if (buf[0] == '3') { + setSysOperation(1); + setFlashCommand(3); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + + memcpy(buf_tmp, buf + 3, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + setFlashDumpSector(result); + + memcpy(buf_tmp, buf + 7, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + setFlashDumpPage(result); + + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } else if (buf[0] == '4') { + I("%s: command 4 enter.\n", __func__); + setSysOperation(1); + setFlashCommand(4); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + + memcpy(buf_tmp, buf + 3, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + setFlashDumpSector(result); + else + E("%s: command 4 , sector error.\n", __func__); + return len; + + + memcpy(buf_tmp, buf + 7, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + setFlashDumpPage(result); + else + E("%s: command 4 , page error.\n", __func__); + return len; + + base = 11; + + I("=========Himax flash page buffer start=========\n"); + for (loop_i = 0 ; loop_i < 128 ; loop_i++) { + memcpy(buf_tmp, buf + base, 2); + if (!kstrtoul(buf_tmp, 16, &result)) { + flash_buffer[loop_i] = result; + I("%d ", flash_buffer[loop_i]); + if (loop_i % 16 == 15) + I("\n"); + } + base += 3; + } + I("=========Himax flash page buffer end=========\n"); + + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } + return len; +} + +const struct file_operations himax_proc_flash_ops = { + .owner = THIS_MODULE, + .read = himax_proc_flash_read, + .write = himax_proc_flash_write, +}; + +void himax_ts_flash_func(void) +{ + uint8_t local_flash_command = 0; + + himax_int_enable(private_ts->client->irq, 0); + setFlashDumpGoing(true); + + /*sector = getFlashDumpSector();*/ + /*page = getFlashDumpPage();*/ + + local_flash_command = getFlashCommand(); + + msleep(100); + + I("%s: local_flash_command = %d enter.\n", + __func__, local_flash_command); + + if ((local_flash_command == 1 || local_flash_command == 2) + || (local_flash_command == 0x0F)) { + himax_flash_dump_func(private_ts->client, + local_flash_command, Flash_Size, flash_buffer); + } + + + I("Complete~~~~~~~~~~~~~~~~~~~~~~~\n"); + + if (local_flash_command == 2) { + struct file *fn; + struct filename *vts_name; + + vts_name = getname_kernel(FLASH_DUMP_FILE); + fn = file_open_name(vts_name, O_CREAT | O_WRONLY, 0); + if (!IS_ERR(fn)) { + I("%s create file and ready to write\n", __func__); + fn->f_op->write(fn, flash_buffer, + Flash_Size * sizeof(uint8_t), &fn->f_pos); + + filp_close(fn, NULL); + } + } + + himax_int_enable(private_ts->client->irq, 1); + setFlashDumpGoing(false); + + setFlashDumpComplete(1); + setSysOperation(0); + return; + +/* Flash_Dump_i2c_transfer_error: + + himax_int_enable(private_ts->client->irq, 1); + setFlashDumpGoing(false); + setFlashDumpComplete(0); + setFlashDumpFail(1); + setSysOperation(0); + return; +*/ +} + +#endif + +#ifdef HX_TP_PROC_SELF_TEST +static ssize_t himax_self_test_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int val = 0x00; + int ret = 0; + char *temp_buf; + + I("%s:enter, %d\n", __func__, __LINE__); + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + himax_int_enable(private_ts->client->irq, 0);/*disable irq*/ + val = himax_chip_self_test(private_ts->client); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + himax_int_enable(private_ts->client->irq, 1);/*enable irq*/ + + if (val == 0x01) { + ret += snprintf(temp_buf + ret, len, + "Self_Test Pass\n"); + } else { + ret += snprintf(temp_buf + ret, len, + "Self_Test Fail\n"); + } + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; + return ret; +} + +/* +static ssize_t himax_chip_self_test_store(struct device *dev, +struct device_attribute *attr, const char *buf, size_t count) +{ + char buf_tmp[2]; + unsigned long result = 0; + + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + memcpy(buf_tmp, buf, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + { + sel_type = (uint8_t)result; + } + I("sel_type = %x \r\n", sel_type); + return count; +} +*/ + +const struct file_operations himax_proc_self_test_ops = { + .owner = THIS_MODULE, + .read = himax_self_test_read, +}; +#endif + +#ifdef HX_TP_PROC_SENSE_ON_OFF +static ssize_t himax_sense_on_off_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + if (buf[0] == '0') { + himax_sense_off(private_ts->client); + I("Sense off\n"); + } else if (buf[0] == '1') { + if (buf[1] == '1') { + himax_sense_on(private_ts->client, 0x01); + I("Sense on re-map off, run flash\n"); + } else if (buf[1] == '0') { + himax_sense_on(private_ts->client, 0x00); + I("Sense on re-map on, run sram\n"); + } else { + I("Do nothing\n"); + } + } else { + I("Do nothing\n"); + } + return len; +} + +const struct file_operations himax_proc_sense_on_off_ops = { + .owner = THIS_MODULE, + .write = himax_sense_on_off_write, +}; +#endif + +#ifdef HX_HIGH_SENSE +static ssize_t himax_HSEN_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t count = 0; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + count = snprintf(temp_buf, len, "%d\n", ts->HSEN_enable); + HX_PROC_SEND_FLAG = 1; + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + + kfree(temp_buf); + } else + HX_PROC_SEND_FLAG = 0; + return count; +} + +static ssize_t himax_HSEN_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf[80] = {0}; + + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + if (buf[0] == '0') + ts->HSEN_enable = 0; + else if (buf[0] == '1') + ts->HSEN_enable = 1; + else + return -EINVAL; + + himax_set_HSEN_func(ts->client, ts->HSEN_enable); + + I("%s: HSEN_enable = %d.\n", __func__, ts->HSEN_enable); + + return len; +} + +const struct file_operations himax_proc_HSEN_ops = { + .owner = THIS_MODULE, + .read = himax_HSEN_read, + .write = himax_HSEN_write, +}; +#endif + +#ifdef HX_SMART_WAKEUP +static ssize_t himax_SMWP_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + size_t count = 0; + struct himax_ts_data *ts = private_ts; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + count = snprintf(temp_buf, "%d\n", len, ts->SMWP_enable); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; + + return count; +} + +static ssize_t himax_SMWP_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + if (buf[0] == '0') + ts->SMWP_enable = 0; + else if (buf[0] == '1') + ts->SMWP_enable = 1; + else + return -EINVAL; + + himax_set_SMWP_func(ts->client, ts->SMWP_enable); + HX_SMWP_EN = ts->SMWP_enable; + I("%s: SMART_WAKEUP_enable = %d.\n", __func__, HX_SMWP_EN); + + return len; +} + +const struct file_operations himax_proc_SMWP_ops = { + .owner = THIS_MODULE, + .read = himax_SMWP_read, + .write = himax_SMWP_write, +}; + +static ssize_t himax_GESTURE_read(struct file *file, +char *buf, size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + int i = 0; + int ret = 0; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + for (i = 0 ; i < 16 ; i++) + ret += snprintf(temp_buf + ret, len, + "ges_en[%d]=%d\n", i, ts->gesture_cust_en[i]); + + HX_PROC_SEND_FLAG = 1; + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else { + HX_PROC_SEND_FLAG = 0; + ret = 0; + } + return ret; +} + +static ssize_t himax_GESTURE_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + int i = 0; + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + I("himax_GESTURE_store= %s\n", buf); + for (i = 0 ; i < 16 ; i++) { + if (buf[i] == '0') + ts->gesture_cust_en[i] = 0; + else if (buf[i] == '1') + ts->gesture_cust_en[i] = 1; + else + ts->gesture_cust_en[i] = 0; + I("gesture en[%d]=%d\n", i, ts->gesture_cust_en[i]); + } + return len; +} + +const struct file_operations himax_proc_Gesture_ops = { + .owner = THIS_MODULE, + .read = himax_GESTURE_read, + .write = himax_GESTURE_write, +}; +#endif + +int himax_touch_proc_init(void) +{ + himax_touch_proc_dir = proc_mkdir(HIMAX_PROC_TOUCH_FOLDER, NULL); + if (himax_touch_proc_dir == NULL) { + E(" %s: himax_touch_proc_dir file create failed!\n", __func__); + return -ENOMEM; + } + + himax_proc_debug_level_file = proc_create(HIMAX_PROC_DEBUG_LEVEL_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_level_ops); + + if (himax_proc_debug_level_file == NULL) { + E(" %s: proc debug_level file create failed!\n", __func__); + goto fail_1; + } + + himax_proc_vendor_file = proc_create(HIMAX_PROC_VENDOR_FILE, + (S_IRUGO), himax_touch_proc_dir, &himax_proc_vendor_ops); + + if (himax_proc_vendor_file == NULL) { + E(" %s: proc vendor file create failed!\n", __func__); + goto fail_2; + } + + himax_proc_attn_file = proc_create(HIMAX_PROC_ATTN_FILE, + (S_IRUGO), himax_touch_proc_dir, &himax_proc_attn_ops); + + if (himax_proc_attn_file == NULL) { + E(" %s: proc attn file create failed!\n", __func__); + goto fail_3; + } + + himax_proc_int_en_file = proc_create(HIMAX_PROC_INT_EN_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_int_en_ops); + + if (himax_proc_int_en_file == NULL) { + E(" %s: proc int en file create failed!\n", __func__); + goto fail_4; + } + + himax_proc_layout_file = proc_create(HIMAX_PROC_LAYOUT_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_layout_ops); + + if (himax_proc_layout_file == NULL) { + E(" %s: proc layout file create failed!\n", __func__); + goto fail_5; + } + +#ifdef HX_TP_PROC_RESET + himax_proc_reset_file = proc_create(HIMAX_PROC_RESET_FILE, + (S_IWUSR), himax_touch_proc_dir, &himax_proc_reset_ops); + + if (himax_proc_reset_file == NULL) { + E(" %s: proc reset file create failed!\n", __func__); + goto fail_6; + } +#endif + +#ifdef HX_TP_PROC_DIAG + himax_proc_diag_file = proc_create(HIMAX_PROC_DIAG_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_ops); + + if (himax_proc_diag_file == NULL) { + E(" %s: proc diag file create failed!\n", __func__); + goto fail_7; + } + himax_proc_diag_arrange_file = proc_create(HIMAX_PROC_DIAG_ARR_FILE, + (S_IWUSR | S_IRUGO), + himax_touch_proc_dir, &himax_proc_diag_arrange_ops); + + if (himax_proc_diag_arrange_file == NULL) { + E(" %s: proc diag file create failed!\n", __func__); + goto fail_7_1; + } +#endif + +#ifdef HX_TP_PROC_REGISTER + himax_proc_register_file = proc_create(HIMAX_PROC_REGISTER_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_register_ops); + + if (himax_proc_register_file == NULL) { + E(" %s: proc register file create failed!\n", __func__); + goto fail_8; + } +#endif + +#ifdef HX_TP_PROC_DEBUG + himax_proc_debug_file = proc_create(HIMAX_PROC_DEBUG_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_ops); + + if (himax_proc_debug_file == NULL) { + E(" %s: proc debug file create failed!\n", __func__); + goto fail_9; + } +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + himax_proc_flash_dump_file = proc_create(HIMAX_PROC_FLASH_DUMP_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_flash_ops); + + if (himax_proc_flash_dump_file == NULL) { + E(" %s: proc flash dump file create failed!\n", __func__); + goto fail_10; + } +#endif + +#ifdef HX_TP_PROC_SELF_TEST + himax_proc_self_test_file = proc_create(HIMAX_PROC_SELF_TEST_FILE, + (S_IRUGO), himax_touch_proc_dir, &himax_proc_self_test_ops); + + if (himax_proc_self_test_file == NULL) { + E(" %s: proc self_test file create failed!\n", __func__); + goto fail_11; + } +#endif + +#ifdef HX_HIGH_SENSE + himax_proc_HSEN_file = proc_create(HIMAX_PROC_HSEN_FILE, + (S_IWUSR | S_IRUGO | S_IWUGO), + himax_touch_proc_dir, &himax_proc_HSEN_ops); + + if (himax_proc_HSEN_file == NULL) { + E(" %s: proc HSEN file create failed!\n", __func__); + goto fail_12; + } +#endif + +#ifdef HX_SMART_WAKEUP + himax_proc_SMWP_file = proc_create(HIMAX_PROC_SMWP_FILE, + (S_IWUSR | S_IRUGO | S_IWUGO), + himax_touch_proc_dir, &himax_proc_SMWP_ops); + + if (himax_proc_SMWP_file == NULL) { + E(" %s: proc SMWP file create failed!\n", __func__); + goto fail_13; + } + + himax_proc_GESTURE_file = proc_create(HIMAX_PROC_GESTURE_FILE, + (S_IWUSR | S_IRUGO | S_IWUGO), + himax_touch_proc_dir, &himax_proc_Gesture_ops); + + if (himax_proc_GESTURE_file == NULL) { + E(" %s: proc GESTURE file create failed!\n", __func__); + goto fail_14; + } +#endif + +#ifdef HX_TP_PROC_SENSE_ON_OFF + himax_proc_SENSE_ON_OFF_file = proc_create(HIMAX_PROC_SENSE_ON_OFF_FILE, + (S_IWUSR | S_IRUGO | S_IWUGO), + himax_touch_proc_dir, &himax_proc_sense_on_off_ops); + + if (himax_proc_SENSE_ON_OFF_file == NULL) { + E(" %s: proc SENSE_ON_OFF file create failed!\n", __func__); + goto fail_15; + } +#endif + + return 0; + +#ifdef HX_TP_PROC_SENSE_ON_OFF +fail_15: +#endif +#ifdef HX_SMART_WAKEUP + remove_proc_entry(HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir); +fail_14: + remove_proc_entry(HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir); +fail_13: +#endif +#ifdef HX_HIGH_SENSE + remove_proc_entry(HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir); +fail_12: +#endif +#ifdef HX_TP_PROC_SELF_TEST + remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir); +fail_11: +#endif +#ifdef HX_TP_PROC_FLASH_DUMP + remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir); +fail_10: +#endif +#ifdef HX_TP_PROC_DEBUG + remove_proc_entry(HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir); +fail_9: +#endif +#ifdef HX_TP_PROC_REGISTER + remove_proc_entry(HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir); +fail_8: +#endif +#ifdef HX_TP_PROC_DIAG + remove_proc_entry(HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir); +fail_7: + remove_proc_entry(HIMAX_PROC_DIAG_ARR_FILE, himax_touch_proc_dir); +fail_7_1: +#endif +#ifdef HX_TP_PROC_RESET + remove_proc_entry(HIMAX_PROC_RESET_FILE, himax_touch_proc_dir); +fail_6: +#endif + remove_proc_entry(HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir); +fail_5: remove_proc_entry(HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir); +fail_4: remove_proc_entry(HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir); +fail_3: remove_proc_entry(HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir); +fail_2: remove_proc_entry(HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir); +fail_1: remove_proc_entry(HIMAX_PROC_TOUCH_FOLDER, NULL); + return -ENOMEM; +} + +void himax_touch_proc_deinit(void) +{ +#ifdef HX_TP_PROC_SENSE_ON_OFF + remove_proc_entry(HIMAX_PROC_SENSE_ON_OFF_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_SMART_WAKEUP + remove_proc_entry(HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_DOT_VIEW + remove_proc_entry(HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_SELF_TEST + remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_FLASH_DUMP + remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_DEBUG + remove_proc_entry(HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_REGISTER + remove_proc_entry(HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_DIAG + remove_proc_entry(HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_RESET + remove_proc_entry(HIMAX_PROC_RESET_FILE, himax_touch_proc_dir); +#endif + remove_proc_entry(HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_TOUCH_FOLDER, NULL); +} +#endif diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.h b/drivers/input/touchscreen/hxchipset/himax_debug.h new file mode 100644 index 000000000000..7a24a170eaca --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_debug.h @@ -0,0 +1,197 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_platform.h" +#include "himax_common.h" + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + #define HIMAX_PROC_TOUCH_FOLDER "android_touch" + #define HIMAX_PROC_DEBUG_LEVEL_FILE "debug_level" + #define HIMAX_PROC_VENDOR_FILE "vendor" + #define HIMAX_PROC_ATTN_FILE "attn" + #define HIMAX_PROC_INT_EN_FILE "int_en" + #define HIMAX_PROC_LAYOUT_FILE "layout" + + static struct proc_dir_entry *himax_touch_proc_dir; + static struct proc_dir_entry *himax_proc_debug_level_file; + static struct proc_dir_entry *himax_proc_vendor_file; + static struct proc_dir_entry *himax_proc_attn_file; + static struct proc_dir_entry *himax_proc_int_en_file; + static struct proc_dir_entry *himax_proc_layout_file; + + uint8_t HX_PROC_SEND_FLAG; + + extern int himax_touch_proc_init(void); + extern void himax_touch_proc_deinit(void); + bool getFlashDumpGoing(void); + + extern struct himax_ic_data *ic_data; + extern struct himax_ts_data *private_ts; + extern unsigned char IC_TYPE; + extern unsigned char IC_CHECKSUM; + +#ifdef QCT + extern irqreturn_t himax_ts_thread(int irq, void *ptr); +#endif +#ifdef MTK +#ifdef CONFIG_OF_TOUCH + extern irqreturn_t tpd_eint_interrupt_handler(int irq, void *desc); +#else + extern void tpd_eint_interrupt_handler(void); +#endif +#endif + +#ifdef HX_TP_PROC_REGISTER + #define HIMAX_PROC_REGISTER_FILE "register" + struct proc_dir_entry *himax_proc_register_file = NULL; + uint8_t register_command[4]; +#endif + +#ifdef HX_TP_PROC_DIAG + #define HIMAX_PROC_DIAG_FILE "diag" + struct proc_dir_entry *himax_proc_diag_file = NULL; + #define HIMAX_PROC_DIAG_ARR_FILE "diag_arr" + struct proc_dir_entry *himax_proc_diag_arrange_file = NULL; + +#ifdef HX_TP_PROC_2T2R + static bool Is_2T2R; + static uint8_t x_channel_2; + static uint8_t y_channel_2; + static uint8_t *diag_mutual_2; + + int16_t *getMutualBuffer_2(void); + uint8_t getXChannel_2(void); + uint8_t getYChannel_2(void); + + void setMutualBuffer_2(void); + void setXChannel_2(uint8_t x); + void setYChannel_2(uint8_t y); +#endif + uint8_t x_channel = 0; + uint8_t y_channel = 0; + int16_t *diag_mutual = NULL; + int16_t *diag_mutual_new = NULL; + int16_t *diag_mutual_old = NULL; + uint8_t diag_max_cnt = 0; + + int diag_command = 0; + uint8_t diag_coor[128];/* = {0xFF};*/ + int16_t diag_self[100] = {0}; + + int16_t *getMutualBuffer(void); + int16_t *getMutualNewBuffer(void); + int16_t *getMutualOldBuffer(void); + int16_t *getSelfBuffer(void); + uint8_t getDiagCommand(void); + uint8_t getXChannel(void); + uint8_t getYChannel(void); + + void setMutualBuffer(void); + void setMutualNewBuffer(void); + void setMutualOldBuffer(void); + void setXChannel(uint8_t x); + void setYChannel(uint8_t y); + uint8_t coordinate_dump_enable = 0; + struct file *coordinate_fn; +#endif + +#ifdef HX_TP_PROC_DEBUG + #define HIMAX_PROC_DEBUG_FILE "debug" + struct proc_dir_entry *himax_proc_debug_file = NULL; + + bool fw_update_complete = false; + int handshaking_result = 0; + unsigned char debug_level_cmd = 0; + unsigned char upgrade_fw[128*1024]; +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + #define HIMAX_PROC_FLASH_DUMP_FILE "flash_dump" + struct proc_dir_entry *himax_proc_flash_dump_file = NULL; + + static int Flash_Size = 131072; + static uint8_t *flash_buffer; + static uint8_t flash_command; + static uint8_t flash_read_step; + static uint8_t flash_progress; + static uint8_t flash_dump_complete; + static uint8_t flash_dump_fail; + static uint8_t sys_operation; + static uint8_t flash_dump_sector; + static uint8_t flash_dump_page; + static bool flash_dump_going; + + static uint8_t getFlashCommand(void); + static uint8_t getFlashDumpComplete(void); + static uint8_t getFlashDumpFail(void); + static uint8_t getFlashDumpProgress(void); + static uint8_t getFlashReadStep(void); + /*static uint8_t getFlashDumpSector(void);*/ + /*static uint8_t getFlashDumpPage(void);*/ + + void setFlashBuffer(void); + uint8_t getSysOperation(void); + + static void setFlashCommand(uint8_t command); + static void setFlashReadStep(uint8_t step); + static void setFlashDumpComplete(uint8_t complete); + static void setFlashDumpFail(uint8_t fail); + static void setFlashDumpProgress(uint8_t progress); + void setSysOperation(uint8_t operation); + static void setFlashDumpSector(uint8_t sector); + static void setFlashDumpPage(uint8_t page); + static void setFlashDumpGoing(bool going); + +#endif + +#ifdef HX_TP_PROC_SELF_TEST + #define HIMAX_PROC_SELF_TEST_FILE "self_test" + struct proc_dir_entry *himax_proc_self_test_file = NULL; + uint32_t **raw_data_array; + uint8_t X_NUM = 0, Y_NUM = 0; + uint8_t sel_type = 0x0D; +#endif + +#ifdef HX_TP_PROC_RESET +#define HIMAX_PROC_RESET_FILE "reset" +extern void himax_HW_reset(uint8_t loadconfig, uint8_t int_off); +struct proc_dir_entry *himax_proc_reset_file; +#endif + +#ifdef HX_HIGH_SENSE + #define HIMAX_PROC_HSEN_FILE "HSEN" + struct proc_dir_entry *himax_proc_HSEN_file = NULL; +#endif + +#ifdef HX_TP_PROC_SENSE_ON_OFF + #define HIMAX_PROC_SENSE_ON_OFF_FILE "SenseOnOff" + struct proc_dir_entry *himax_proc_SENSE_ON_OFF_file = NULL; +#endif + +#ifdef HX_RST_PIN_FUNC + void himax_HW_reset(uint8_t loadconfig, uint8_t int_off); +#endif + +#ifdef HX_SMART_WAKEUP +#define HIMAX_PROC_SMWP_FILE "SMWP" +struct proc_dir_entry *himax_proc_SMWP_file; +#define HIMAX_PROC_GESTURE_FILE "GESTURE" +struct proc_dir_entry *himax_proc_GESTURE_file; +uint8_t HX_SMWP_EN; +/*extern bool FAKE_POWER_KEY_SEND;*/ +#endif + +#endif + diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.c b/drivers/input/touchscreen/hxchipset/himax_ic.c new file mode 100644 index 000000000000..e2934c2d2396 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_ic.c @@ -0,0 +1,2381 @@ +/* Himax Android Driver Sample Code for HMX83100 chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_ic.h" + +const struct firmware *i_TP_CRC_FW_128K; +const struct firmware *i_TP_CRC_FW_64K; +const struct firmware *i_TP_CRC_FW_124K; +const struct firmware *i_TP_CRC_FW_60K; + +unsigned long FW_VER_MAJ_FLASH_ADDR; +unsigned long FW_VER_MAJ_FLASH_LENG; +unsigned long FW_VER_MIN_FLASH_ADDR; +unsigned long FW_VER_MIN_FLASH_LENG; +unsigned long CFG_VER_MAJ_FLASH_ADDR; +unsigned long CFG_VER_MAJ_FLASH_LENG; +unsigned long CFG_VER_MIN_FLASH_ADDR; +unsigned long CFG_VER_MIN_FLASH_LENG; + +unsigned char IC_TYPE; +unsigned char IC_CHECKSUM; + + /*0:Running, 1:Stop, 2:I2C Fail*/ +int himax_hand_shaking(struct i2c_client *client) +{ + int ret, result; + uint8_t hw_reset_check[1]; + uint8_t hw_reset_check_2[1]; + uint8_t buf0[2]; + uint8_t IC_STATUS_CHECK = 0xAA; + + memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); + memset(hw_reset_check_2, 0x00, sizeof(hw_reset_check_2)); + + buf0[0] = 0xF2; + if (IC_STATUS_CHECK == 0xAA) { + buf0[1] = 0xAA; + IC_STATUS_CHECK = 0x55; + } else { + buf0[1] = 0x55; + IC_STATUS_CHECK = 0xAA; + } + + ret = i2c_himax_master_write(client, + buf0, 2, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("[Himax]:write 0xF2 failed line: %d\n", __LINE__); + goto work_func_send_i2c_msg_fail; + } + msleep(50); + + buf0[0] = 0xF2; + buf0[1] = 0x00; + ret = i2c_himax_master_write(client, + buf0, 2, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("[Himax]:write 0x92 failed line: %d\n", __LINE__); + goto work_func_send_i2c_msg_fail; + } + usleep_range(1999, 2000); + + ret = i2c_himax_read(client, 0xD1, + hw_reset_check, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("[Himax]:i2c_himax_read 0xD1 failed line: %d\n", __LINE__); + goto work_func_send_i2c_msg_fail; + } + + if (IC_STATUS_CHECK != hw_reset_check[0]) { + usleep_range(1999, 2000); + ret = i2c_himax_read(client, 0xD1, + hw_reset_check_2, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("[Himax]:i2c_himax_read 0xD1 failed line: %d\n", + __LINE__); + goto work_func_send_i2c_msg_fail; + } + + if (hw_reset_check[0] == hw_reset_check_2[0]) + result = 1; + else + result = 0; + + } else { + result = 0; + } + + return result; + +work_func_send_i2c_msg_fail: + return 2; +} + +void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + if (diag_command != 0) + diag_command = diag_command + 5; + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; + tmp_addr[1] = 0x01; tmp_addr[0] = 0x80; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = diag_command; + himax_flash_write_burst(client, tmp_addr, tmp_data); +} + +void himax_flash_dump_func(struct i2c_client *client, +uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer) +{ + /*struct himax_ts_data *ts = + container_of(work, struct himax_ts_data, flash_work);*/ + /*uint8_t sector = 0;*/ + /*uint8_t page = 0;*/ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t out_buffer[20]; + uint8_t in_buffer[260]; + int page_prog_start = 0; + int i = 0; + + himax_sense_off(client); + himax_burst_enable(client, 0); + /*=============Dump Flash Start=============*/ + /*=====================================*/ + /* SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780*/ + /*=====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + for (page_prog_start = 0 ; page_prog_start < Flash_Size; + page_prog_start = page_prog_start + 256) { + /*===================================== + SPI Transfer Control + Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF + Set read start address : 0x8000_0028 ==> 0x0000_0000 + Set command : 0x8000_0024 ==> 0x0000_003B + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x69; tmp_data[2] = 0x40; + tmp_data[1] = 0x02; tmp_data[0] = 0xFF; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + if (page_prog_start < 0x100) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x100 + && page_prog_start < 0x10000) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x10000 + && page_prog_start < 0x1000000) { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x3B; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + AHB_I2C Burst Read + Set SPI data register : 0x8000_002C ==> 0x00 + =====================================*/ + out_buffer[0] = 0x2C; + out_buffer[1] = 0x00; + out_buffer[2] = 0x00; + out_buffer[3] = 0x80; + i2c_himax_write(client, 0x00, out_buffer, 4, 3); + + /*===================================== + Read access : 0x0C ==> 0x00 + =====================================*/ + out_buffer[0] = 0x00; + i2c_himax_write(client, 0x0C, out_buffer, 1, 3); + + /*===================================== + Read 128 bytes two times + =====================================*/ + i2c_himax_read(client, 0x08, in_buffer, 128, 3); + for (i = 0 ; i < 128 ; i++) + flash_buffer[i + page_prog_start] + = in_buffer[i]; + + i2c_himax_read(client, 0x08 , in_buffer, 128, 3); + for (i = 0 ; i < 128 ; i++) + flash_buffer[(i + 128) + page_prog_start] + = in_buffer[i]; + + I("%s:Verify Progress: %x\n", __func__, page_prog_start); + } + +/*=============Dump Flash End=============*/ + /*//msleep(100); + for( i=0 ; i<8 ;i++) + { + for(j=0 ; j<64 ; j++) + { + setFlashDumpProgress(i*32 + j); + } + } + */ + himax_sense_on(client, 0x01); + + return; + +} + +int himax_chip_self_test(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[128]; + int pf_value = 0x00; + uint8_t test_result_id = 0; + int j; + + memset(tmp_addr, 0x00, sizeof(tmp_addr)); + memset(tmp_data, 0x00, sizeof(tmp_data)); + + himax_interface_on(client); + himax_sense_off(client); + + /*Set criteria*/ + himax_burst_enable(client, 1); + + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x94; + tmp_data[3] = 0x14; tmp_data[2] = 0xC8; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_data[7] = 0x13; tmp_data[6] = 0x60; + tmp_data[5] = 0x0A; tmp_data[4] = 0x99; + + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 8); + + /*start selftest*/ + /* 0x9008_805C ==> 0x0000_0001*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x5C; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + himax_sense_on(client, 1); + + msleep(2000); + + himax_sense_off(client); + msleep(20); + + /*===================================== + Read test result ID : 0x9008_8078 ==> 0xA/0xB/0xC/0xF + =====================================*/ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x78; + himax_register_read(client, tmp_addr, 1, tmp_data); + + test_result_id = tmp_data[0]; + + I("%s: check test result, test_result_id=%x, test_result=%x\n", + __func__ , test_result_id, tmp_data[0]); + + if (test_result_id == 0xF) { + I("[Himax]: self-test pass\n"); + pf_value = 0x1; + } else { + E("[Himax]: self-test fail\n"); + pf_value = 0x0; + } + himax_burst_enable(client, 1); + + for (j = 0 ; j < 10 ; j++) { + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x06; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x0C; + himax_register_read(client, tmp_addr, 1, tmp_data); + I("[Himax]: 9006000C = %d\n", tmp_data[0]); + if (tmp_data[0] != 0) { + tmp_data[3] = 0x90; tmp_data[2] = 0x06; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + if (i2c_himax_write(client, 0x00, + tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + tmp_data[0] = 0x00; + if (i2c_himax_write(client, 0x0C, + tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + i2c_himax_read(client, 0x08, + tmp_data, 124, HIMAX_I2C_RETRY_TIMES); + } else { + break; + } + } + + himax_sense_on(client, 1); + msleep(120); + + return pf_value; +} + +void himax_set_HSEN_enable(struct i2c_client *client, uint8_t HSEN_enable) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + himax_burst_enable(client, 0); + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = HSEN_enable; + himax_flash_write_burst(client, tmp_addr, tmp_data); +} +void himax_get_HSEN_enable(struct i2c_client *client, uint8_t *tmp_data) +{ + uint8_t tmp_addr[4]; + + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; + himax_register_read(client, tmp_addr, 1, tmp_data); +} + +void himax_set_SMWP_enable(struct i2c_client *client, uint8_t SMWP_enable) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = SMWP_enable; + himax_flash_write_burst(client, tmp_addr, tmp_data); +} + +void himax_get_SMWP_enable(struct i2c_client *client, +uint8_t *tmp_data) +{ + uint8_t tmp_addr[4]; + + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; + himax_register_read(client, tmp_addr, 1, tmp_data); +} + +int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte) +{ + uint8_t tmp_data[4]; + int err = -1; + + tmp_data[0] = 0x31; + + if (i2c_himax_write(client, 0x13, + tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return err; + } + + tmp_data[0] = (0x10 | auto_add_4_byte); + if (i2c_himax_write(client, 0x0D, + tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return err; + } + return 0; + +} + +void himax_register_read(struct i2c_client *client, +uint8_t *read_addr, int read_length, uint8_t *read_data) +{ + uint8_t tmp_data[4]; + int i = 0; + int address = 0; + + if (read_length > 256) { + E("%s: read len over 256!\n", __func__); + return; + } + if (read_length > 1) + himax_burst_enable(client, 1); + else + himax_burst_enable(client, 0); + + address = (read_addr[3] << 24) + + (read_addr[2] << 16) + + (read_addr[1] << 8) + + read_addr[0]; + + i = address; + tmp_data[0] = (uint8_t)i; + tmp_data[1] = (uint8_t)(i >> 8); + tmp_data[2] = (uint8_t)(i >> 16); + tmp_data[3] = (uint8_t)(i >> 24); + if (i2c_himax_write(client, 0x00, + tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + tmp_data[0] = 0x00; + if (i2c_himax_write(client, 0x0C, + tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + if (i2c_himax_read(client, 0x08, + read_data, read_length * 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + if (read_length > 1) + himax_burst_enable(client, 0); +} + +void himax_flash_read(struct i2c_client *client, +uint8_t *reg_byte, uint8_t *read_data) +{ + uint8_t tmpbyte[2]; + + if (i2c_himax_write(client, 0x00, + ®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(client, 0x01, + ®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(client, 0x02, + ®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(client, 0x03, + ®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + tmpbyte[0] = 0x00; + if (i2c_himax_write(client, 0x0C, + &tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_read(client, 0x08, + &read_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_read(client, 0x09, + &read_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_read(client, 0x0A, + &read_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_read(client, 0x0B, + &read_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_read(client, 0x18, + &tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } /* No bus request*/ + + if (i2c_himax_read(client, 0x0F, + &tmpbyte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } /* idle state*/ + +} + +void himax_flash_write_burst(struct i2c_client *client, +uint8_t *reg_byte, uint8_t *write_data) +{ + uint8_t data_byte[8]; + int i = 0, j = 0; + + for (i = 0 ; i < 4; i++) + data_byte[i] = reg_byte[i]; + + for (j = 4 ; j < 8; j++) + data_byte[j] = write_data[j-4]; + + if (i2c_himax_write(client, 0x00, + data_byte, 8, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + +} + +int himax_flash_write_burst_length(struct i2c_client *client, +uint8_t *reg_byte, uint8_t *write_data, int length) +{ + uint8_t data_byte[256]; + int i = 0, j = 0, err = -1; + + for (i = 0 ; i < 4 ; i++) + data_byte[i] = reg_byte[i]; + + for (j = 4 ; j < length + 4 ; j++) + data_byte[j] = write_data[j - 4]; + + if (i2c_himax_write(client, 0x00, + data_byte, length + 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return err; + } + return 0; +} + +int himax_register_write(struct i2c_client *client, +uint8_t *write_addr, int write_length, uint8_t *write_data) +{ + int i = 0, address = 0; + int ret = 0, err = -1; + + address = (write_addr[3] << 24) + + (write_addr[2] << 16) + + (write_addr[1] << 8) + + write_addr[0]; + + for (i = address ; i < address + write_length * 4; + i = i + 4) { + if (write_length > 1) { + ret = himax_burst_enable(client, 1); + if (ret) + return err; + } else { + ret = himax_burst_enable(client, 0); + if (ret) + return err; + } + ret = himax_flash_write_burst_length(client, + write_addr, write_data, write_length * 4); + if (ret < 0) + return err; + } + + return 0; +} + +void himax_sense_off(struct i2c_client *client) +{ + uint8_t wdt_off = 0x00; + uint8_t tmp_addr[4]; + uint8_t tmp_data[5]; + + himax_burst_enable(client, 0); + + while (wdt_off == 0x00) { + /* 0x9000_800C ==> 0x0000_AC53*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0xAC; tmp_data[0] = 0x53; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*=====================================*/ + /* Read Watch Dog disable password : + 0x9000_800C ==> 0x0000_AC53 */ + /*=====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; + himax_register_read(client, tmp_addr, 1, tmp_data); + + /*Check WDT*/ + if (tmp_data[0] == 0x53 && tmp_data[1] == 0xAC + && tmp_data[2] == 0x00 && tmp_data[3] == 0x00) + wdt_off = 0x01; + else + wdt_off = 0x00; + } + + /* VCOM //0x9008_806C ==> 0x0000_0001*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x6C; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + msleep(20); + + /* 0x9000_0010 ==> 0x0000_00DA*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xDA; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Read CPU clock off password : 0x9000_0010 ==> 0x0000_00DA + =====================================*/ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + himax_register_read(client, tmp_addr, 1, tmp_data); + I("%s: CPU clock off password data[0]=%x", + __func__, tmp_data[0]); + I(" data[1]=%x data[2]=%x data[3]=%x\n", + tmp_data[1], tmp_data[2], tmp_data[3]); + +} + +void himax_interface_on(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[5]; + + /*===================================== + Any Cmd for ineterface on : 0x9000_0000 ==> 0x0000_0000 + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + himax_flash_read(client, tmp_addr, tmp_data); /*avoid RD/WR fail*/ +} + +bool wait_wip(struct i2c_client *client, int Timing) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t in_buffer[10]; + /*uint8_t out_buffer[20];*/ + int retry_cnt = 0; + + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + in_buffer[0] = 0x01; + + do { + /*===================================== + SPI Transfer Control : 0x8000_0020 ==> 0x4200_0003 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x42; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x03; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + SPI Command : 0x8000_0024 ==> 0x0000_0005 + read 0x8000_002C for 0x01, means wait success + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x05; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + in_buffer[0] = in_buffer[1] = + in_buffer[2] = in_buffer[3] = 0xFF; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; + himax_register_read(client, tmp_addr, 1, in_buffer); + + if ((in_buffer[0] & 0x01) == 0x00) + return true; + + retry_cnt++; + + if (in_buffer[0] != 0x00 || in_buffer[1] != 0x00 + || in_buffer[2] != 0x00 || in_buffer[3] != 0x00){ + I("%s:Wait wip retry_cnt:%d, buffer[0]=%d, ", + __func__, retry_cnt, in_buffer[0]); + I("buffer[1]=%d, buffer[2]=%d, buffer[3]=%d\n", + in_buffer[1], in_buffer[2], in_buffer[3]); + } + if (retry_cnt > 100) { + E("%s: Wait wip error!\n", __func__); + return false; + } + msleep(Timing); + } while ((in_buffer[0] & 0x01) == 0x01); + return true; +} + +void himax_sense_on(struct i2c_client *client, uint8_t FlashMode) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[128]; + + himax_interface_on(client); + himax_burst_enable(client, 0); + /*CPU reset*/ + /* 0x9000_0014 ==> 0x0000_00CA*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xCA; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Read pull low CPU reset signal : 0x9000_0014 ==> 0x0000_00CA + =====================================*/ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + himax_register_read(client, tmp_addr, 1, tmp_data); + + I("%s: check pull low CPU reset signal data[0]=%x data[1]=%x ", + __func__, tmp_data[0], tmp_data[1]); + I("data[2]=%x data[3]=%x\n", + tmp_data[2], tmp_data[3]); + + /* 0x9000_0014 ==> 0x0000_0000*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Read revert pull low CPU reset signal : 0x9000_0014 ==> 0x0000_0000 + =====================================*/ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + himax_register_read(client, tmp_addr, 1, tmp_data); + + I("%s: revert pull low CPU reset signal data[0]=%x data[1]=%x ", + __func__, tmp_data[0], tmp_data[1]); + I("data[2]=%x data[3]=%x\n", + tmp_data[2], tmp_data[3]); + + /*===================================== + Reset TCON + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; + tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + usleep_range(9999, 10000); + tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; + tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + if (FlashMode == 0x00) { /*SRAM*/ + /*===================================== + Re-map + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xF1; + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 4); + I("%s:83100_Chip_Re-map ON\n", __func__); + } else { + /*===================================== + Re-map off + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 4); + I("%s:83100_Chip_Re-map OFF\n", __func__); + } + /*===================================== + CPU clock on + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 4); + +} + +void himax_chip_erase(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + himax_burst_enable(client, 0); + + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Chip Erase + Write Enable : + 1. 0x8000_0020 ==> 0x4700_0000 + 2. 0x8000_0024 ==> 0x0000_0006 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x06; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Chip Erase + Erase Command : 0x8000_0024 ==> 0x0000_00C7 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xC7; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + msleep(2000); + + if (!wait_wip(client, 100)) + E("%s:83100_Chip_Erase Fail\n", __func__); + +} + +bool himax_block_erase(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + himax_burst_enable(client, 0); + + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Chip Erase + Write Enable : + 1. 0x8000_0020 ==> 0x4700_0000 + 2. 0x8000_0024 ==> 0x0000_0006 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x06; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Block Erase + Erase Command : + 0x8000_0028 ==> 0x0000_0000 //SPI addr + 0x8000_0020 ==> 0x6700_0000 //control + 0x8000_0024 ==> 0x0000_0052 //BE + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x67; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x52; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + msleep(1000); + + if (!wait_wip(client, 100)) { + E("%s:83100_Erase Fail\n", __func__); + return false; + } else { + return true; + } + +} + +bool himax_sector_erase(struct i2c_client *client, int start_addr) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + int page_prog_start = 0; + + himax_burst_enable(client, 0); + + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + for (page_prog_start = start_addr; + page_prog_start < start_addr + 0x0F000; + page_prog_start = page_prog_start + 0x1000) { + /*===================================== + Chip Erase + Write Enable : + 1. 0x8000_0020 ==> 0x4700_0000 + 2. 0x8000_0024 ==> 0x0000_0006 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x06; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Sector Erase + Erase Command : + 0x8000_0028 ==> 0x0000_0000 //SPI addr + 0x8000_0020 ==> 0x6700_0000 //control + 0x8000_0024 ==> 0x0000_0020 //SE + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + if (page_prog_start < 0x100) { + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x100 + && page_prog_start < 0x10000) { + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x10000 + && page_prog_start < 0x1000000) { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x67; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x20; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + msleep(200); + + if (!wait_wip(client, 100)) { + E("%s:83100_Erase Fail\n", __func__); + return false; + } + } + return true; +} + +void himax_sram_write(struct i2c_client *client, uint8_t *FW_content) +{ + int i = 0; + uint8_t tmp_addr[4]; + uint8_t tmp_data[64]; + int FW_length = 0x4000; /* 0x4000 = 16K bin file */ + + /*himax_sense_off(client);*/ + + for (i = 0; i < FW_length; i = i + 64) { + himax_burst_enable(client, 1); + + if (i < 0x100) { + tmp_addr[3] = 0x08; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = i; + } else if (i >= 0x100 && i < 0x10000) { + tmp_addr[3] = 0x08; + tmp_addr[2] = 0x00; + tmp_addr[1] = (i >> 8); + tmp_addr[0] = i; + } + + memcpy(&tmp_data[0], &FW_content[i], 64); + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 64); + + } + + if (!wait_wip(client, 100)) + E("%s:83100_Sram_Write Fail\n", __func__); +} + +bool himax_sram_verify(struct i2c_client *client, +uint8_t *FW_File, int FW_Size) +{ + int i = 0; + uint8_t out_buffer[20]; + uint8_t in_buffer[128]; + uint8_t *get_fw_content; + + get_fw_content = kzalloc(0x4000 * sizeof(uint8_t), GFP_KERNEL); + + for (i = 0 ; i < 0x4000 ; i = i + 128) { + himax_burst_enable(client, 1); + + /*===================================== + AHB_I2C Burst Read + =====================================*/ + if (i < 0x100) { + out_buffer[3] = 0x08; + out_buffer[2] = 0x00; + out_buffer[1] = 0x00; + out_buffer[0] = i; + } else if (i >= 0x100 && i < 0x10000) { + out_buffer[3] = 0x08; + out_buffer[2] = 0x00; + out_buffer[1] = (i >> 8); + out_buffer[0] = i; + } + + if (i2c_himax_write(client, 0x00, out_buffer, + 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + out_buffer[0] = 0x00; + if (i2c_himax_write(client, 0x0C, out_buffer, + 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + if (i2c_himax_read(client, 0x08, in_buffer, + 128, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + memcpy(&get_fw_content[i], &in_buffer[0], 128); + } + + for (i = 0 ; i < FW_Size ; i++) { + if (FW_File[i] != get_fw_content[i]) { + E("%s: fail! SRAM[%x]=%x NOT CRC_ifile=%x\n", + __func__, i, get_fw_content[i], FW_File[i]); + return false; + } + } + + kfree(get_fw_content); + + return true; +} + +void himax_flash_programming(struct i2c_client *client, +uint8_t *FW_content, int FW_Size) +{ + int page_prog_start = 0; + int program_length = 48; + int i = 0, j = 0, k = 0; + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + /* // Read for flash data, 128K //4 bytes for 0x80002C padding */ + uint8_t buring_data[256]; + + /*himax_interface_on(client);*/ + himax_burst_enable(client, 0); + + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + for (page_prog_start = 0 ; page_prog_start < FW_Size; + page_prog_start = page_prog_start + 256) { + /*msleep(5);*/ + /*===================================== + Write Enable : + 1. 0x8000_0020 ==> 0x4700_0000 + 2. 0x8000_0024 ==> 0x0000_0006 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x06; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + SPI Transfer Control + Set 256 bytes page write : 0x8000_0020 ==> 0x610F_F000 + Set read start address : 0x8000_0028 ==> 0x0000_0000 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x61; tmp_data[2] = 0x0F; + tmp_data[1] = 0xF0; tmp_data[0] = 0x00; + /*data bytes should be 0x6100_0000 + + ((word_number)*4-1)*4096 = 0x6100_0000 + + 0xFF000 = 0x610F_F000 + Programmable size = 1 page = 256 bytes, + word_number = 256 byte / 4 = 64*/ + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + /* tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + // Flash start address 1st : 0x0000_0000 */ + + if (page_prog_start < 0x100) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x100 + && page_prog_start < 0x10000) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x10000 + && page_prog_start < 0x1000000) { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Send 16 bytes data : 0x8000_002C ==> 16 bytes data + =====================================*/ + buring_data[0] = 0x2C; + buring_data[1] = 0x00; + buring_data[2] = 0x00; + buring_data[3] = 0x80; + + for (i = /*0*/page_prog_start, j = 0; + i < 16 + page_prog_start/**/; + i++, j++) { /* <------ bin file*/ + + buring_data[j + 4] = FW_content[i]; + } + + if (i2c_himax_write(client, 0x00, buring_data, + 20, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + /*===================================== + Write command : 0x8000_0024 ==> 0x0000_0002 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x02; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + /*===================================== + Send 240 bytes data : 0x8000_002C ==> 240 bytes data + =====================================*/ + + for (j = 0; j < 5; j++) { + for (i = (page_prog_start + 16 + (j * 48)), k = 0; + i < (page_prog_start + 16 + (j * 48)) + program_length; + i++, k++) { /*<------ bin file*/ + buring_data[k+4] = FW_content[i];/*(byte)i;*/ + } + + if (i2c_himax_write(client, 0x00, buring_data, + program_length + 4, + HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + } + + if (!wait_wip(client, 1)) + E("%s:83100_Flash_Programming Fail\n", __func__); + } +} + +bool himax_check_chip_version(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t ret_data = 0x00; + int i = 0; + int ret = 0; + + himax_sense_off(client); + + for (i = 0 ; i < 5 ; i++) { + /* 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) + (Lock register R/W from driver) */ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; + ret = himax_register_write(client, tmp_addr, 1, tmp_data); + if (ret) + return false; + + /* 2. Set bank as 0 (0x8001_BD01 = 0x0000_0000)*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; + tmp_addr[1] = 0xBD; tmp_addr[0] = 0x01; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + ret = himax_register_write(client, tmp_addr, 1, tmp_data); + if (ret) + return false; + + /* 3. Read driver ID register RF4H 1 byte (0x8001_F401) + // Driver register RF4H 1 byte value = 0x84H, + read back value will become 0x84848484 */ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; + tmp_addr[1] = 0xF4; tmp_addr[0] = 0x01; + himax_register_read(client, tmp_addr, 1, tmp_data); + ret_data = tmp_data[0]; + + I("%s:Read driver IC ID = %X\n", __func__, ret_data); + if (ret_data == 0x84) { + IC_TYPE = HX_83100_SERIES_PWON; + /*himax_sense_on(client, 0x01);*/ + ret_data = true; + break; + + } else { + ret_data = false; + E("%s:Read driver ID register Fail:\n", __func__); + } + } + /* 4. After read finish, set DDREG_Req = 0 + (0x9000_0020 = 0x0000_0000) (Unlock register R/W from driver)*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_register_write(client, tmp_addr, 1, tmp_data); + /*himax_sense_on(client, 0x01);*/ + return ret_data; +} + +/*#if 1*/ +int himax_check_CRC(struct i2c_client *client, int mode) +{ + bool burnFW_success = false; + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + int tmp_value; + int CRC_value = 0; + + memset(tmp_data, 0x00, sizeof(tmp_data)); + if (i_TP_CRC_FW_60K == NULL) { + I("%s: i_TP_CRC_FW_60K = NULL\n", __func__); + return 0; + } else if (i_TP_CRC_FW_64K == NULL) { + I("%s: i_TP_CRC_FW_64K = NULL\n", __func__); + return 0; + } else if (i_TP_CRC_FW_124K == NULL) { + I("%s: i_TP_CRC_FW_124K = NULL\n", __func__); + return 0; + } else if (i_TP_CRC_FW_128K == NULL) { + I("%s: i_TP_CRC_FW_128K = NULL\n", __func__); + return 0; + } + + if (1) { + if (mode == fw_image_60k) { + himax_sram_write(client, + (unsigned char *)i_TP_CRC_FW_60K->data); + burnFW_success = himax_sram_verify(client, + (unsigned char *)i_TP_CRC_FW_60K->data, 0x4000); + } else if (mode == fw_image_64k) { + himax_sram_write(client, + (unsigned char *)i_TP_CRC_FW_64K->data); + burnFW_success = himax_sram_verify(client, + (unsigned char *)i_TP_CRC_FW_64K->data, 0x4000); + } else if (mode == fw_image_124k) { + himax_sram_write(client, + (unsigned char *)i_TP_CRC_FW_124K->data); + burnFW_success = himax_sram_verify(client, + (unsigned char *)i_TP_CRC_FW_124K->data, 0x4000); + } else if (mode == fw_image_128k) { + himax_sram_write(client, + (unsigned char *)i_TP_CRC_FW_128K->data); + burnFW_success = himax_sram_verify(client, + (unsigned char *)i_TP_CRC_FW_128K->data, 0x4000); + } + if (burnFW_success) { + I("%s: Start to do CRC FW mode=%d\n", __func__, mode); + himax_sense_on(client, 0x00); /* run CRC firmware*/ + + while (true) { + msleep(100); + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; + tmp_addr[0] = 0x94; + himax_register_read(client, + tmp_addr, 1, tmp_data); + + I("%s: CRC from firmware is %x, %x, %x, %x\n", + __func__, tmp_data[3], tmp_data[2], + tmp_data[1], tmp_data[0]); +/* + if (tmp_data[3] == 0xFF && tmp_data[2] == 0xFF + && tmp_data[1] == 0xFF && tmp_data[0] == 0xFF) { + } else + break; + */ + if (!(tmp_data[3] == 0xFF + && tmp_data[2] == 0xFF + && tmp_data[1] == 0xFF + && tmp_data[0] == 0xFF)) { + break; + } + } + + CRC_value = tmp_data[3]; + + tmp_value = tmp_data[2] << 8; + CRC_value += tmp_value; + + tmp_value = tmp_data[1] << 16; + CRC_value += tmp_value; + + tmp_value = tmp_data[0] << 24; + CRC_value += tmp_value; + + I("%s: CRC Value is %x\n", __func__, CRC_value); + + /*Close Remapping*/ + /*===================================== + Re-map close + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst_length(client, + tmp_addr, tmp_data, 4); + return CRC_value; + + } else { + E("%s: SRAM write fail\n", __func__); + return 0; + } + } else + I("%s: NO CRC Check File\n", __func__); + + return 0; +} + +bool Calculate_CRC_with_AP(unsigned char *FW_content, +int CRC_from_FW, int mode) +{ + uint8_t tmp_data[4]; + int i, j; + int fw_data; + int fw_data_2; + int CRC = 0xFFFFFFFF; + int PolyNomial = 0x82F63B78; + int length = 0; + + if (mode == fw_image_128k) + length = 0x8000; + else if (mode == fw_image_124k) + length = 0x7C00; + else if (mode == fw_image_64k) + length = 0x4000; + else /*if (mode == fw_image_60k)*/ + length = 0x3C00; + + for (i = 0 ; i < length ; i++) { + fw_data = FW_content[i * 4]; + + for (j = 1 ; j < 4 ; j++) { + fw_data_2 = FW_content[i * 4 + j]; + fw_data += (fw_data_2) << (8 * j); + } + + CRC = fw_data ^ CRC; + + for (j = 0 ; j < 32 ; j++) { + if ((CRC % 2) != 0) + CRC = ((CRC >> 1) & 0x7FFFFFFF) ^ PolyNomial; + else + CRC = (((CRC >> 1) ^ 0x7FFFFFFF) & 0x7FFFFFFF); + } + } + + I("%s: CRC calculate from bin file is %x\n", __func__, CRC); + + tmp_data[0] = (uint8_t)(CRC >> 24); + tmp_data[1] = (uint8_t)(CRC >> 16); + tmp_data[2] = (uint8_t)(CRC >> 8); + tmp_data[3] = (uint8_t) CRC; + + CRC = tmp_data[0]; + CRC += tmp_data[1] << 8; + CRC += tmp_data[2] << 16; + CRC += tmp_data[3] << 24; + + I("%s: CRC calculate from bin file REVERSE %x\n", __func__, CRC); + I("%s: CRC calculate from FWis %x\n", __func__, CRC_from_FW); + if (CRC_from_FW == CRC) + return true; + else + return false; +} +/*#endif*/ + +int himax_load_CRC_bin_file(struct i2c_client *client) +{ + int err = 0; + char *CRC_60_firmware_name = "HX_CRC_60.bin"; + char *CRC_64_firmware_name = "HX_CRC_64.bin"; + char *CRC_124_firmware_name = "HX_CRC_124.bin"; + char *CRC_128_firmware_name = "HX_CRC_128.bin"; + + I("%s,Entering\n", __func__); + if (i_TP_CRC_FW_60K == NULL) { + I("load file name = %s\n", CRC_60_firmware_name); + err = request_firmware(&i_TP_CRC_FW_60K, + CRC_60_firmware_name, private_ts->dev); + if (err < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, err); + err = -1; + goto request_60k_fw_fail; + } + } else + I("%s already load i_TP_CRC_FW_60K\n", __func__); + + if (i_TP_CRC_FW_64K == NULL) { + I("load file name = %s\n", CRC_64_firmware_name); + err = request_firmware(&i_TP_CRC_FW_64K, + CRC_64_firmware_name, private_ts->dev); + if (err < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, err); + err = -2; + goto request_64k_fw_fail; + } + } else + I("%s already load i_TP_CRC_FW_64K\n", __func__); + + if (i_TP_CRC_FW_124K == NULL) { + I("load file name = %s\n", CRC_124_firmware_name); + err = request_firmware(&i_TP_CRC_FW_124K, + CRC_124_firmware_name, private_ts->dev); + if (err < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, err); + err = -3; + goto request_124k_fw_fail; + } + } else + I("%s already load i_TP_CRC_FW_124K\n", __func__); + + if (i_TP_CRC_FW_128K == NULL) { + I("load file name = %s\n", CRC_128_firmware_name); + err = request_firmware(&i_TP_CRC_FW_128K, + CRC_128_firmware_name, private_ts->dev); + if (err < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, err); + err = -4; + goto request_128k_fw_fail; + } + } else + I("%s already load i_TP_CRC_FW_128K\n", __func__); + + return err; + +request_128k_fw_fail: + release_firmware(i_TP_CRC_FW_124K); +request_124k_fw_fail: + release_firmware(i_TP_CRC_FW_64K); +request_64k_fw_fail: + release_firmware(i_TP_CRC_FW_60K); +request_60k_fw_fail: + return err; +} +int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, +unsigned char *fw, int len, bool change_iref) +{ + int CRC_from_FW = 0; + int burnFW_success = 0; + + if (len != 0x10000) {/*64k*/ + E("%s: The file size is not 64K bytes\n", __func__); + return false; + } + himax_sense_off(client); + msleep(500); + himax_interface_on(client); + if (!himax_sector_erase(client, 0x00000)) { + E("%s:Sector erase fail!Please restart the IC.\n", __func__); + return false; + } + himax_flash_programming(client, fw, 0x0F000); + + /*burnFW_success = himax_83100_Verify(fw, len); + if(burnFW_success==false) + return burnFW_success;*/ + + CRC_from_FW = himax_check_CRC(client, fw_image_60k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW, fw_image_60k); + /*himax_sense_on(client, 0x01);*/ + return burnFW_success; +} + +int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, +unsigned char *fw, int len, bool change_iref) +{ + int CRC_from_FW = 0; + int burnFW_success = 0; + + if (len != 0x10000) { /*64k*/ + E("%s: The file size is not 64K bytes\n", __func__); + return false; + } + himax_sense_off(client); + msleep(500); + himax_interface_on(client); + himax_chip_erase(client); + himax_flash_programming(client, fw, len); + + /*burnFW_success = himax_83100_Verify(fw, len); + if(burnFW_success==false) + return burnFW_success;*/ + + CRC_from_FW = himax_check_CRC(client, fw_image_64k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW, fw_image_64k); + /*himax_sense_on(client, 0x01);*/ + return burnFW_success; +} + +int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, +unsigned char *fw, int len, bool change_iref) +{ + int CRC_from_FW = 0; + int burnFW_success = 0; + + if (len != 0x20000) { /*128k*/ + E("%s: The file size is not 128K bytes\n", __func__); + return false; + } + himax_sense_off(client); + msleep(500); + himax_interface_on(client); + if (!himax_block_erase(client)) { + E("%s:Block erase fail!Please restart the IC.\n", __func__); + return false; + } + if (!himax_sector_erase(client, 0x10000)) { + E("%s:Sector erase fail!Please restart the IC.\n", __func__); + return false; + } + himax_flash_programming(client, fw, 0x1F000); + + /*burnFW_success = himax_83100_Verify(fw, len); + if(burnFW_success==false) + return burnFW_success;*/ + + CRC_from_FW = himax_check_CRC(client, fw_image_124k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW, fw_image_124k); + /*himax_sense_on(client, 0x01);*/ + return burnFW_success; +} + +int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, +unsigned char *fw, int len, bool change_iref) +{ + int CRC_from_FW = 0; + int burnFW_success = 0; + + if (len != 0x20000) { /*128k*/ + E("%s: The file size is not 128K bytes\n", __func__); + return false; + } + himax_sense_off(client); + msleep(500); + himax_interface_on(client); + himax_chip_erase(client); + + himax_flash_programming(client, fw, len); + + /*burnFW_success = himax_83100_Verify(fw, len); + if(burnFW_success==false) + return burnFW_success;*/ + + CRC_from_FW = himax_check_CRC(client, fw_image_128k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW, fw_image_128k); + /*himax_sense_on(client, 0x01); */ + return burnFW_success; +} + +void himax_touch_information(struct i2c_client *client) +{ + uint8_t cmd[4]; + char data[12] = {0}; + + I("%s:IC_TYPE =%d\n", __func__, IC_TYPE); + + if (IC_TYPE == HX_83100_SERIES_PWON) { + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xF8; + himax_register_read(client, cmd, 1, data); + + ic_data->HX_RX_NUM = data[1]; + ic_data->HX_TX_NUM = data[2]; + ic_data->HX_MAX_PT = data[3]; + + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xFC; + himax_register_read(client, cmd, 1, data); + + if ((data[1] & 0x04) == 0x04) + ic_data->HX_XY_REVERSE = true; + else + ic_data->HX_XY_REVERSE = false; + + ic_data->HX_Y_RES = data[3]*256; + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x01; cmd[0] = 0x00; + himax_register_read(client, cmd, 1, data); + ic_data->HX_Y_RES = ic_data->HX_Y_RES + data[0]; + ic_data->HX_X_RES = data[1]*256 + data[2]; + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0x8C; + himax_register_read(client, cmd, 1, data); + if ((data[0] & 0x01) == 1) + ic_data->HX_INT_IS_EDGE = true; + else + ic_data->HX_INT_IS_EDGE = false; + + if (ic_data->HX_RX_NUM > 40) + ic_data->HX_RX_NUM = 29; + if (ic_data->HX_TX_NUM > 20) + ic_data->HX_TX_NUM = 16; + if (ic_data->HX_MAX_PT > 10) + ic_data->HX_MAX_PT = 10; + if (ic_data->HX_Y_RES > 2000) + ic_data->HX_Y_RES = 1280; + if (ic_data->HX_X_RES > 2000) + ic_data->HX_X_RES = 720; +#ifdef HX_EN_MUT_BUTTON + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xE8; + himax_register_read(client, cmd, 1, data); + ic_data->HX_BT_NUM = data[3]; +#endif + I("%s:HX_RX_NUM =%d,HX_TX_NUM =%d,HX_MAX_PT=%d\n", + __func__, ic_data->HX_RX_NUM, + ic_data->HX_TX_NUM, ic_data->HX_MAX_PT); + I("%s:HX_XY_REVERSE =%d,HX_Y_RES =%d,HX_X_RES=%d\n", + __func__, ic_data->HX_XY_REVERSE, + ic_data->HX_Y_RES, ic_data->HX_X_RES); + I("%s:HX_INT_IS_EDGE =%d\n", + __func__, ic_data->HX_INT_IS_EDGE); + } else { + ic_data->HX_RX_NUM = 0; + ic_data->HX_TX_NUM = 0; + ic_data->HX_BT_NUM = 0; + ic_data->HX_X_RES = 0; + ic_data->HX_Y_RES = 0; + ic_data->HX_MAX_PT = 0; + ic_data->HX_XY_REVERSE = false; + ic_data->HX_INT_IS_EDGE = false; + } +} + +void himax_read_FW_ver(struct i2c_client *client) +{ + uint8_t cmd[4]; + uint8_t data[64]; + + /*===================================== + Read FW version : 0x0000_E303 + =====================================*/ + cmd[3] = 0x00; cmd[2] = 0x00; cmd[1] = 0xE3; cmd[0] = 0x00; + himax_register_read(client, cmd, 1, data); + + ic_data->vendor_config_ver = data[3] << 8; + + cmd[3] = 0x00; cmd[2] = 0x00; cmd[1] = 0xE3; cmd[0] = 0x04; + himax_register_read(client, cmd, 1, data); + + ic_data->vendor_config_ver = data[0] | ic_data->vendor_config_ver; + I("CFG_VER : %X\n", ic_data->vendor_config_ver); + + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0x28; + himax_register_read(client, cmd, 1, data); + + ic_data->vendor_fw_ver = data[0]<<8 | data[1]; + I("FW_VER : %X\n", ic_data->vendor_fw_ver); + +} + +bool himax_ic_package_check(struct i2c_client *client) +{ +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH + uint8_t cmd[3]; + uint8_t data[3]; + + memset(cmd, 0x00, sizeof(cmd)); + memset(data, 0x00, sizeof(data)); + + if (i2c_himax_read(client, 0xD1, cmd, 3, HIMAX_I2C_RETRY_TIMES) < 0) + return false; + + if (i2c_himax_read(client, 0x31, data, 3, HIMAX_I2C_RETRY_TIMES) < 0) + return false; + + if ((data[0] == 0x85 && data[1] == 0x29)) { + IC_TYPE = HX_85XX_F_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 64901; /*0xFD85*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 64902; /*0xFD86*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 64928; /*0xFDA0*/ + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 64940; /*0xFDAC*/ + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x F\n"); + } + if ((data[0] == 0x85 && data[1] == 0x30) + || (cmd[0] == 0x05 && cmd[1] == 0x85 && cmd[2] == 0x29)) { + IC_TYPE = HX_85XX_E_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; /*0x0086*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; /*0x00A0*/ + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; /*0x00AC*/ + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x E\n"); + } else if ((data[0] == 0x85 && data[1] == 0x31)) { + IC_TYPE = HX_85XX_ES_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; /*0x0086*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; /*0x00A0*/ + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; /*0x00AC*/ + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x ES\n"); + } else if ((data[0] == 0x85 && data[1] == 0x28) + || (cmd[0] == 0x04 && cmd[1] == 0x85 + && (cmd[2] == 0x26 || cmd[2] == 0x27 + || cmd[2] == 0x28))) { + IC_TYPE = HX_85XX_D_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; /*0x0086*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; /*0x00A0*/ + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; /* 0x00AC*/ + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x D\n"); + } else if ((data[0] == 0x85 && data[1] == 0x23) || + (cmd[0] == 0x03 && cmd[1] == 0x85 && + (cmd[2] == 0x26 || cmd[2] == 0x27 || + cmd[2] == 0x28 || cmd[2] == 0x29))) { + IC_TYPE = HX_85XX_C_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; /*0x0086*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 135; /*0x0087*/ + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 147; /*0x0093*/ + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x C\n"); + } else if ((data[0] == 0x85 && data[1] == 0x26) || + (cmd[0] == 0x02 && cmd[1] == 0x85 && + (cmd[2] == 0x19 || cmd[2] == 0x25 || cmd[2] == 0x26))) { + IC_TYPE = HX_85XX_B_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 728; /*0x02D8*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 692; /*0x02B4*/ + CFG_VER_MAJ_FLASH_LENG = 3; + CFG_VER_MIN_FLASH_ADDR = 704; /*0x02C0*/ + CFG_VER_MIN_FLASH_LENG = 3; + I("Himax IC package 852x B\n"); + } else if ((data[0] == 0x85 && data[1] == 0x20) || (cmd[0] == 0x01 && + cmd[1] == 0x85 && cmd[2] == 0x19)) { + IC_TYPE = HX_85XX_A_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; + I("Himax IC package 852x A\n"); + } else { + E("Himax IC package incorrect!!\n"); + } +#else + IC_TYPE = HX_83100_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 57384; /*0xE028*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 57385; /*0xE029*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 58115; /*0xE303*/ + CFG_VER_MAJ_FLASH_LENG = 1; + CFG_VER_MIN_FLASH_ADDR = 58116; /*0xE304*/ + CFG_VER_MIN_FLASH_LENG = 1; + I("Himax IC package 83100_in\n"); + +#endif + return true; +} + +void himax_read_event_stack(struct i2c_client *client, +uint8_t *buf, uint8_t length) +{ + uint8_t cmd[4]; + + cmd[3] = 0x90; cmd[2] = 0x06; + cmd[1] = 0x00; cmd[0] = 0x00; + if (i2c_himax_write(client, 0x00, + cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + + cmd[0] = 0x00; + if (i2c_himax_write(client, 0x0C, + cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + + i2c_himax_read(client, 0x08, + buf, length, HIMAX_I2C_RETRY_TIMES); +} + +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH +static void himax_83100_Flash_Write(uint8_t *reg_byte, uint8_t *write_data) +{ + uint8_t tmpbyte[2]; + + if (i2c_himax_write(private_ts->client, 0x00, + ®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, 0x01, + ®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, 0x02, + ®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, + 0x03, ®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, + 0x04, &write_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, + 0x05, &write_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, + 0x06, &write_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, + 0x07, &write_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (isBusrtOn == false) { + tmpbyte[0] = 0x01; + if (i2c_himax_write(private_ts->client, + 0x0C, &tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + } +} +#endif +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH +static void himax_83100_Flash_Burst_Write +(uint8_t *reg_byte, uint8_t *write_data) +{ + /*uint8_t tmpbyte[2];*/ + int i = 0; + + if (i2c_himax_write(private_ts->client, 0x00, + ®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, 0x01, + ®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, 0x02, + ®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, 0x03, + ®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + /*Write 256 bytes with continue burst mode*/ + for (i = 0 ; i < 256 ; i = i + 4) { + if (i2c_himax_write(private_ts->client, + 0x04, &write_data[i], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, 0x05, + &write_data[i+1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, 0x06, + &write_data[i+2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (i2c_himax_write(private_ts->client, 0x07, + &write_data[i+3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + } + + /*if (isBusrtOn == false) + { + tmpbyte[0] = 0x01; + if (i2c_himax_write(private_ts->client, + 0x0C, &tmpbyte[0], 1, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + }*/ + +} +#endif + +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH +static bool himax_83100_Verify(uint8_t *FW_File, int FW_Size) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t out_buffer[20]; + uint8_t in_buffer[260]; + + int fail_addr = 0, fail_cnt = 0; + int page_prog_start = 0; + int i = 0; + + himax_interface_on(private_ts->client); + himax_burst_enable(private_ts->client, 0); + + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_83100_Flash_Write(tmp_addr, tmp_data); + + for (page_prog_start = 0; page_prog_start < FW_Size; + page_prog_start = page_prog_start + 256) { + /*===================================== + SPI Transfer Control + Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF + Set read start address : 0x8000_0028 ==> 0x0000_0000 + Set command : 0x8000_0024 ==> 0x0000_003B + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x69; tmp_data[2] = 0x40; + tmp_data[1] = 0x02; tmp_data[0] = 0xFF; + himax_83100_Flash_Write(tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + if (page_prog_start < 0x100) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x100 + && page_prog_start < 0x10000) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x10000 + && page_prog_start < 0x1000000) { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + himax_83100_Flash_Write(tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x3B; + himax_83100_Flash_Write(tmp_addr, tmp_data); + + /*================================== + AHB_I2C Burst Read + Set SPI data register : 0x8000_002C ==> 0x00 + ==================================*/ + out_buffer[0] = 0x2C; + out_buffer[1] = 0x00; + out_buffer[2] = 0x00; + out_buffer[3] = 0x80; + i2c_himax_write(private_ts->client, 0x00, + out_buffer, 4, HIMAX_I2C_RETRY_TIMES); + + /*================================== + Read access : 0x0C ==> 0x00 + ==================================*/ + out_buffer[0] = 0x00; + i2c_himax_write(private_ts->client, 0x0C, + out_buffer, 1, HIMAX_I2C_RETRY_TIMES); + + /*================================== + Read 128 bytes two times + ==================================*/ + i2c_himax_read(private_ts->client, 0x08, + in_buffer, 128, HIMAX_I2C_RETRY_TIMES); + for (i = 0; i < 128; i++) + flash_buffer[i + page_prog_start] = in_buffer[i]; + + i2c_himax_read(private_ts->client, 0x08, + in_buffer, 128, HIMAX_I2C_RETRY_TIMES); + for (i = 0; i < 128; i++) + flash_buffer[(i + 128) + + page_prog_start] = in_buffer[i]; + + /*tmp_addr[3] = 0x80; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; + himax_register_read(tmp_addr, 32, out in_buffer); + for (int i = 0; i < 128; i++) + flash_buffer[i + page_prog_start] = in_buffer[i]; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; + himax_register_read(tmp_addr, 32, out in_buffer); + for (int i = 0; i < 128; i++) + flash_buffer[i + page_prog_start] = in_buffer[i]; + */ + I("%s:Verify Progress: %x\n", __func__, page_prog_start); + } + + fail_cnt = 0; + for (i = 0; i < FW_Size; i++) { + if (FW_File[i] != flash_buffer[i]) { + if (fail_cnt == 0) + fail_addr = i; + + fail_cnt++; + /*E("%s Fail Block:%x\n", __func__, i); + return false;*/ + } + } + if (fail_cnt > 0) { + E("%s:Start Fail Block:%x and fail block count=%x\n", + __func__, fail_addr, fail_cnt); + return false; + } + + I("%s:Byte read verify pass.\n", __func__); + return true; + +} +#endif + +void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data) +{ + int i; + int cnt = 0; + unsigned char tmp_addr[4]; + unsigned char tmp_data[4]; + uint8_t max_i2c_size = 32; + int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2; + int total_size_4bytes = total_size / 4; + int total_read_times = 0; + unsigned long address = 0x08000468; + + tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x5A; tmp_data[0] = 0xA5; + himax_flash_write_burst(client, tmp_addr, tmp_data); + do { + cnt++; + himax_register_read(client, tmp_addr, 1, tmp_data); + usleep_range(9999, 10000); + } while ((tmp_data[1] != 0xA5 || tmp_data[0] != 0x5A) && cnt < 100); + tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x04; tmp_addr[0] = 0x68; + if (total_size_4bytes % max_i2c_size == 0) + total_read_times = total_size_4bytes / max_i2c_size; + else + total_read_times = total_size_4bytes / max_i2c_size + 1; + + for (i = 0 ; i < (total_read_times) ; i++) { + if (total_size_4bytes >= max_i2c_size) { + himax_register_read(client, tmp_addr, + max_i2c_size, + &info_data[i*max_i2c_size*4]); + total_size_4bytes = total_size_4bytes - max_i2c_size; + } else { + himax_register_read(client, tmp_addr, + total_size_4bytes % max_i2c_size, + &info_data[i*max_i2c_size*4]); + } + address += max_i2c_size * 4; + tmp_addr[1] = (uint8_t)((address>>8) & 0x00FF); + tmp_addr[0] = (uint8_t)((address) & 0x00FF); + } + tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; + tmp_data[3] = 0x11; tmp_data[2] = 0x22; + tmp_data[1] = 0x33; tmp_data[0] = 0x44; + himax_flash_write_burst(client, tmp_addr, tmp_data); +} +/*ts_work*/ +int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max) +{ + int RawDataLen; + + if (raw_cnt_rmd != 0x00) + RawDataLen = 124 - ((HX_MAX_PT + raw_cnt_max + 3) * 4) - 1; + else + RawDataLen = 124 - ((HX_MAX_PT + raw_cnt_max + 2) * 4) - 1; + + return RawDataLen; +} + +bool read_event_stack(struct i2c_client *client, uint8_t *buf, int length) +{ + uint8_t cmd[4]; + + if (length > 56) + length = 124; + /*===================== + AHB I2C Burst Read + =====================*/ + cmd[0] = 0x31; + if (i2c_himax_write(client, 0x13, cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + goto err_workqueue_out; + } + + cmd[0] = 0x10; + if (i2c_himax_write(client, 0x0D, cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + goto err_workqueue_out; + } + /*===================== + Read event stack + =====================*/ + cmd[3] = 0x90; cmd[2] = 0x06; cmd[1] = 0x00; cmd[0] = 0x00; + if (i2c_himax_write(client, 0x00, cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + goto err_workqueue_out; + } + + cmd[0] = 0x00; + if (i2c_himax_write(client, 0x0C, cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + goto err_workqueue_out; + } + i2c_himax_read(client, 0x08, buf, length, HIMAX_I2C_RETRY_TIMES); + return 1; + +err_workqueue_out: + return 0; +} + +bool post_read_event_stack(struct i2c_client *client) +{ + return 1; +} +bool diag_check_sum(uint8_t hx_touch_info_size, +uint8_t *buf) /*return checksum value*/ +{ + uint16_t check_sum_cal = 0; + int i; + + /*Check 124th byte CRC*/ + for (i = hx_touch_info_size, check_sum_cal = 0 ; i < 124 ; i = i + 2) + check_sum_cal += (buf[i + 1] * 256 + buf[i]); + + if (check_sum_cal % 0x10000 != 0) { + I("%s:diag chksum fail!check_sum_cal=%X,hx_touchinfo_sz=%d,\n", + __func__, check_sum_cal, hx_touch_info_size); + return 0; + } + return 1; +} + +void diag_parse_raw_data(int hx_touch_info_size, +int RawDataLen, int mul_num, int self_num, uint8_t *buf, +uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data) +{ + int RawDataLen_word; + int index = 0; + int temp1, temp2, i; + + if (buf[hx_touch_info_size] == 0x3A && + buf[hx_touch_info_size + 1] == 0xA3 && + buf[hx_touch_info_size + 2] > 0 && + buf[hx_touch_info_size + 3] == diag_cmd + 5) { + RawDataLen_word = RawDataLen / 2; + index = (buf[hx_touch_info_size + 2] - 1) * RawDataLen_word; + /*I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", + index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num);*/ + for (i = 0; i < RawDataLen_word; i++) { + temp1 = index + i; + + if (temp1 < mul_num) { /*mutual*/ + /*4: RawData Header, 1:HSB */ + mutual_data[index + i] + = buf[i*2 + hx_touch_info_size + 4 + 1] + * 256 + + buf[i * 2 + hx_touch_info_size + 4]; + } else { /*self*/ + temp1 = i + index; + temp2 = self_num + mul_num; + + if (temp1 >= temp2) + break; + + /*4: RawData Header*/ + self_data[i + index - mul_num] + = buf[i * 2 + hx_touch_info_size + 4]; + self_data[i + index - mul_num + 1] + = buf[i * 2 + hx_touch_info_size + 4 + 1]; + } + } + } else { + I("[HIMAX TP MSG]%s: header format is wrong!\n", __func__); + I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", + index, buf[56], buf[57], buf[58], buf[59], + mul_num, self_num); + } +} diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.h b/drivers/input/touchscreen/hxchipset/himax_ic.h new file mode 100644 index 000000000000..ce7d0d49c362 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_ic.h @@ -0,0 +1,148 @@ +/* Himax Android Driver Sample Code for HMX83100 chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_platform.h" +#include "himax_common.h" + +#include + +#define HX_85XX_A_SERIES_PWON 1 +#define HX_85XX_B_SERIES_PWON 2 +#define HX_85XX_C_SERIES_PWON 3 +#define HX_85XX_D_SERIES_PWON 4 +#define HX_85XX_E_SERIES_PWON 5 +#define HX_85XX_ES_SERIES_PWON 6 +#define HX_85XX_F_SERIES_PWON 7 +#define HX_83100_SERIES_PWON 8 + +#define HX_TP_BIN_CHECKSUM_SW 1 +#define HX_TP_BIN_CHECKSUM_HW 2 +#define HX_TP_BIN_CHECKSUM_CRC 3 + +enum fw_image_type { + fw_image_60k = 0x01, + fw_image_64k, + fw_image_124k, + fw_image_128k, +}; + +int himax_hand_shaking(struct i2c_client *client); +void himax_set_SMWP_enable(struct i2c_client *client, uint8_t SMWP_enable); +void himax_get_SMWP_enable(struct i2c_client *client, uint8_t *tmp_data); +void himax_set_HSEN_enable(struct i2c_client *client, uint8_t HSEN_enable); +void himax_get_HSEN_enable(struct i2c_client *client, uint8_t *tmp_data); +void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command); + +void himax_flash_dump_func(struct i2c_client *client, +uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer); + +int himax_chip_self_test(struct i2c_client *client); + +/*himax_83100_BURST_INC0_EN*/ +int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte); + +/*RegisterRead83100*/ +void himax_register_read(struct i2c_client *client, + uint8_t *read_addr, int read_length, uint8_t *read_data); + +/*himax_83100_Flash_Read*/ +void himax_flash_read(struct i2c_client *client, + uint8_t *reg_byte, uint8_t *read_data); + +/*himax_83100_Flash_Write_Burst*/ +void himax_flash_write_burst(struct i2c_client *client, + uint8_t *reg_byte, uint8_t *write_data); + +/*himax_83100_Flash_Write_Burst_length*/ +int himax_flash_write_burst_length(struct i2c_client *client, + uint8_t *reg_byte, uint8_t *write_data, int length); + +/*RegisterWrite83100*/ +int himax_register_write(struct i2c_client *client, + uint8_t *write_addr, int write_length, uint8_t *write_data); + +/*himax_83100_SenseOff*/ +void himax_sense_off(struct i2c_client *client); +/*himax_83100_Interface_on*/ +void himax_interface_on(struct i2c_client *client); +bool wait_wip(struct i2c_client *client, int Timing); + +/*himax_83100_SenseOn*/ +void himax_sense_on(struct i2c_client *client, + uint8_t FlashMode); + +/*himax_83100_Chip_Erase*/ +void himax_chip_erase(struct i2c_client *client); +/*himax_83100_Block_Erase*/ +bool himax_block_erase(struct i2c_client *client); + +/*himax_83100_Sector_Erase*/ +bool himax_sector_erase(struct i2c_client *client, int start_addr); + +/*himax_83100_Sram_Write*/ +void himax_sram_write(struct i2c_client *client, uint8_t *FW_content); + +/*himax_83100_Sram_Verify*/ +bool himax_sram_verify(struct i2c_client *client, + uint8_t *FW_File, int FW_Size); + +/*himax_83100_Flash_Programming*/ +void himax_flash_programming(struct i2c_client *client, + uint8_t *FW_content, int FW_Size); + +/*himax_83100_CheckChipVersion*/ +bool himax_check_chip_version(struct i2c_client *client); + +/*himax_83100_Check_CRC*/ +int himax_check_CRC(struct i2c_client *client, int mode); + +bool Calculate_CRC_with_AP(unsigned char *FW_content, + int CRC_from_FW, int mode); + +int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, + unsigned char *fw, int len, bool change_iref); + +int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, + unsigned char *fw, int len, bool change_iref); + +int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, + unsigned char *fw, int len, bool change_iref); + +int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, + unsigned char *fw, int len, bool change_iref); + +void himax_touch_information(struct i2c_client *client); +void himax_read_FW_ver(struct i2c_client *client); +bool himax_ic_package_check(struct i2c_client *client); + +void himax_read_event_stack(struct i2c_client *client, + uint8_t *buf, uint8_t length); + +int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max); +bool read_event_stack(struct i2c_client *client, uint8_t *buf_ts, int length); +bool post_read_event_stack(struct i2c_client *client); + +/*return checksum value*/ +bool diag_check_sum(uint8_t hx_touch_info_size, uint8_t *buf_ts); + +void diag_parse_raw_data(int hx_touch_info_size, int RawDataLen, + int mul_num, int self_num, uint8_t *buf_ts, + uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data); + +void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data); +extern struct himax_ts_data *private_ts; +extern struct himax_ic_data *ic_data; + +int himax_load_CRC_bin_file(struct i2c_client *client); diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.c b/drivers/input/touchscreen/hxchipset/himax_platform.c new file mode 100644 index 000000000000..309bb5e01073 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_platform.c @@ -0,0 +1,783 @@ +/* Himax Android Driver Sample Code for HIMAX chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_platform.h" +#include "himax_common.h" + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +#define D(x...) pr_info("[HXTP][DEBUG] " x) +#define I(x...) pr_info("[HXTP][INFO] " x) +#define W(x...) pr_info("[HXTP][WARNING] " x) +#define E(x...) pr_info("[HXTP][ERROR] " x) +#endif + +int irq_enable_count = 0; +#ifdef HX_SMART_WAKEUP +#define TS_WAKE_LOCK_TIMEOUT (2 * HZ) +#endif + +#define PINCTRL_STATE_ACTIVE "pmx_ts_active" +#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend" +#define PINCTRL_STATE_RELEASE "pmx_ts_release" + +/*extern int himax_ts_init(struct himax_ts_data *ts);*/ + +void himax_vk_parser(struct device_node *dt, + struct himax_i2c_platform_data *pdata) +{ + u32 data = 0; + uint8_t cnt = 0, i = 0; + uint32_t coords[4] = {0}; + struct device_node *node, *pp = NULL; + struct himax_virtual_key *vk; + + node = of_parse_phandle(dt, "virtualkey", 0); + if (node == NULL) { + I(" DT-No vk info in DT"); + return; + + } else { + while ((pp = of_get_next_child(node, pp))) + cnt++; + if (!cnt) + return; + + vk = kcalloc(cnt, sizeof(*vk), GFP_KERNEL); + pp = NULL; + while ((pp = of_get_next_child(node, pp))) { + if (of_property_read_u32(pp, "idx", &data) == 0) + vk[i].index = data; + if (of_property_read_u32_array(pp, "range", + coords, 4) == 0) { + vk[i].x_range_min = coords[0], + vk[i].x_range_max = coords[1]; + vk[i].y_range_min = coords[2], + vk[i].y_range_max = coords[3]; + } else + I(" range faile"); + i++; + } + pdata->virtual_key = vk; + for (i = 0; i < cnt; i++) + I(" vk[%d] idx:%d x_min:%d, y_max:%d", + i, pdata->virtual_key[i].index, + pdata->virtual_key[i].x_range_min, + pdata->virtual_key[i].y_range_max); + } +} + +int himax_parse_dt(struct himax_ts_data *ts, + struct himax_i2c_platform_data *pdata) +{ + int rc, coords_size = 0; + uint32_t coords[4] = {0}; + struct property *prop; + struct device_node *dt = ts->client->dev.of_node; + u32 data = 0; + + prop = of_find_property(dt, "himax,panel-coords", NULL); + if (prop) { + coords_size = prop->length / sizeof(u32); + if (coords_size != 4) + D(" %s:Invalid panel coords size %d", + __func__, coords_size); + } + + if (of_property_read_u32_array(dt, "himax,panel-coords", + coords, coords_size) == 0) { + pdata->abs_x_min = coords[0], pdata->abs_x_max = coords[1]; + pdata->abs_y_min = coords[2], pdata->abs_y_max = coords[3]; + I(" DT-%s:panel-coords = %d, %d, %d, %d\n", + __func__, pdata->abs_x_min, pdata->abs_x_max, + pdata->abs_y_min, pdata->abs_y_max); + } + + prop = of_find_property(dt, "himax,display-coords", NULL); + if (prop) { + coords_size = prop->length / sizeof(u32); + if (coords_size != 4) + D(" %s:Invalid display coords size %d", + __func__, coords_size); + } + rc = of_property_read_u32_array(dt, "himax,display-coords", + coords, coords_size); + if (rc && (rc != -EINVAL)) { + D(" %s:Fail to read display-coords %d\n", + __func__, rc); + return rc; + } + pdata->screenWidth = coords[1]; + pdata->screenHeight = coords[3]; + I(" DT-%s:display-coords = (%d, %d)", __func__, pdata->screenWidth, + pdata->screenHeight); + + pdata->gpio_irq = of_get_named_gpio(dt, "himax,irq-gpio", 0); + if (!gpio_is_valid(pdata->gpio_irq)) + I(" DT:gpio_irq value is not valid\n"); + + pdata->gpio_reset = of_get_named_gpio(dt, "himax,rst-gpio", 0); + if (!gpio_is_valid(pdata->gpio_reset)) + I(" DT:gpio_rst value is not valid\n"); + + pdata->gpio_3v3_en = of_get_named_gpio(dt, "himax,3v3-gpio", 0); + if (!gpio_is_valid(pdata->gpio_3v3_en)) + I(" DT:gpio_3v3_en value is not valid\n"); + + I(" DT:gpio_irq=%d, gpio_rst=%d, gpio_3v3_en=%d", + pdata->gpio_irq, pdata->gpio_reset, pdata->gpio_3v3_en); + + if (of_property_read_u32(dt, "report_type", &data) == 0) { + pdata->protocol_type = data; + I(" DT:protocol_type=%d", pdata->protocol_type); + } + + himax_vk_parser(dt, pdata); + + return 0; +} + +int i2c_himax_read(struct i2c_client *client, +uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) +{ + int retry; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = &command, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = data, + } + }; + mutex_lock(&private_ts->rw_lock); + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 2) == 2) + break; + msleep(20); + } + if (retry == toRetry) { + E("%s: i2c_read_block retry over %d\n", + __func__, toRetry); + mutex_unlock(&private_ts->rw_lock); + return -EIO; + } + mutex_unlock(&private_ts->rw_lock); + return 0; + +} + +int i2c_himax_write(struct i2c_client *client, +uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) +{ + int retry/*, loop_i*/; + uint8_t buf[length + 1]; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = length + 1, + .buf = buf, + } + }; + + buf[0] = command; + memcpy(buf+1, data, length); + mutex_lock(&private_ts->rw_lock); + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) + break; + msleep(20); + } + + if (retry == toRetry) { + E("%s: i2c_write_block retry over %d\n", + __func__, toRetry); + mutex_unlock(&private_ts->rw_lock); + return -EIO; + } + mutex_unlock(&private_ts->rw_lock); + return 0; + +} + +int i2c_himax_read_command(struct i2c_client *client, +uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry) +{ + int retry; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = data, + } + }; + mutex_lock(&private_ts->rw_lock); + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) + break; + msleep(20); + } + if (retry == toRetry) { + E("%s: i2c_read_block retry over %d\n", + __func__, toRetry); + mutex_unlock(&private_ts->rw_lock); + return -EIO; + } + mutex_unlock(&private_ts->rw_lock); + return 0; +} + +int i2c_himax_write_command(struct i2c_client *client, +uint8_t command, uint8_t toRetry) +{ + return i2c_himax_write(client, command, NULL, 0, toRetry); +} + +int i2c_himax_master_write(struct i2c_client *client, +uint8_t *data, uint8_t length, uint8_t toRetry) +{ + int retry/*, loop_i*/; + uint8_t buf[length]; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = length, + .buf = buf, + } + }; + + memcpy(buf, data, length); + mutex_lock(&private_ts->rw_lock); + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) + break; + msleep(20); + } + + if (retry == toRetry) { + E("%s: i2c_write_block retry over %d\n", + __func__, toRetry); + mutex_unlock(&private_ts->rw_lock); + return -EIO; + } + mutex_unlock(&private_ts->rw_lock); + return 0; +} + +void himax_int_enable(int irqnum, int enable) +{ + if (enable == 1 && irq_enable_count == 0) { + enable_irq(irqnum); + irq_enable_count++; + } else if (enable == 0 && irq_enable_count == 1) { + disable_irq_nosync(irqnum); + irq_enable_count--; + } + I("irq_enable_count = %d", irq_enable_count); +} + +void himax_rst_gpio_set(int pinnum, uint8_t value) +{ + gpio_direction_output(pinnum, value); +} + +uint8_t himax_int_gpio_read(int pinnum) +{ + return gpio_get_value(pinnum); +} + +#if defined(CONFIG_HMX_DB) +static int himax_regulator_configure(struct i2c_client *client, +struct himax_i2c_platform_data *pdata) +{ + int retval; + + pdata->vcc_dig = regulator_get(&client->dev, "vdd"); + if (IS_ERR(pdata->vcc_dig)) { + E("%s: Failed to get regulator vdd\n", __func__); + retval = PTR_ERR(pdata->vcc_dig); + return retval; + } + pdata->vcc_ana = regulator_get(&client->dev, "avdd"); + if (IS_ERR(pdata->vcc_ana)) { + E("%s: Failed to get regulator avdd\n", __func__); + retval = PTR_ERR(pdata->vcc_ana); + regulator_put(pdata->vcc_ana); + return retval; + } + + return 0; +}; + +static int himax_power_on(struct himax_i2c_platform_data *pdata, +bool on) +{ + int retval; + + if (on) { + retval = regulator_enable(pdata->vcc_dig); + if (retval) { + E("%s: Failed to enable regulator vdd\n", __func__); + return retval; + } + msleep(100); + retval = regulator_enable(pdata->vcc_ana); + if (retval) { + E("%s: Failed to enable regulator avdd\n", __func__); + regulator_disable(pdata->vcc_dig); + return retval; + } + } else { + regulator_disable(pdata->vcc_dig); + regulator_disable(pdata->vcc_ana); + } + return 0; +} + +int himax_ts_pinctrl_init(struct himax_ts_data *ts) +{ + int retval; + + /* Get pinctrl if target uses pinctrl */ + ts->ts_pinctrl = devm_pinctrl_get(&(ts->client->dev)); + if (IS_ERR_OR_NULL(ts->ts_pinctrl)) { + retval = PTR_ERR(ts->ts_pinctrl); + dev_dbg(&ts->client->dev, "Target does not use pinctrl %d\n", + retval); + goto err_pinctrl_get; + } + + ts->pinctrl_state_active = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_ACTIVE); + if (IS_ERR_OR_NULL(ts->pinctrl_state_active)) { + retval = PTR_ERR(ts->pinctrl_state_active); + dev_err(&ts->client->dev, "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_ACTIVE, retval); + goto err_pinctrl_lookup; + } + + ts->pinctrl_state_suspend = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_SUSPEND); + if (IS_ERR_OR_NULL(ts->pinctrl_state_suspend)) { + retval = PTR_ERR(ts->pinctrl_state_suspend); + dev_err(&ts->client->dev, "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_SUSPEND, retval); + goto err_pinctrl_lookup; + } + + ts->pinctrl_state_release = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_RELEASE); + if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { + retval = PTR_ERR(ts->pinctrl_state_release); + dev_dbg(&ts->client->dev, "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_RELEASE, retval); + } + + return 0; + +err_pinctrl_lookup: + devm_pinctrl_put(ts->ts_pinctrl); +err_pinctrl_get: + ts->ts_pinctrl = NULL; + return retval; +} + +int himax_gpio_power_config(struct i2c_client *client, +struct himax_i2c_platform_data *pdata) +{ + int error; + + error = himax_regulator_configure(client, pdata); + if (error) { + E("Failed to initialize hardware\n"); + goto err_regulator_not_on; + } + +#ifdef HX_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) { + /* configure touchscreen reset out gpio */ + error = gpio_request(pdata->gpio_reset, "hmx_reset_gpio"); + if (error) { + E("unable to request gpio [%d]\n", + pdata->gpio_reset); + goto err_regulator_on; + } + error = gpio_direction_output(pdata->gpio_reset, 0); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_reset_req; + } + } +#endif + + error = himax_power_on(pdata, true); + if (error) { + E("Failed to power on hardware\n"); + goto err_gpio_reset_req; + } +#ifdef HX_IRQ_PIN_FUNC + /* configure touchscreen irq gpio */ + if (gpio_is_valid(pdata->gpio_irq)) { + error = gpio_request(pdata->gpio_irq, "hmx_gpio_irq"); + if (error) { + E("unable to request gpio [%d]\n", pdata->gpio_irq); + goto err_power_on; + } + error = gpio_direction_input(pdata->gpio_irq); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_irq); + goto err_gpio_irq_req; + } + client->irq = gpio_to_irq(pdata->gpio_irq); + } else { + E("irq gpio not provided\n"); + goto err_power_on; + } +#endif + msleep(20); + +#ifdef HX_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) { + error = gpio_direction_output(pdata->gpio_reset, 1); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_irq_req; + } + } +#endif + return 0; +#ifdef HX_RST_PIN_FUNC +err_gpio_irq_req: +#endif +#ifdef HX_IRQ_PIN_FUNC + if (gpio_is_valid(pdata->gpio_irq)) + gpio_free(pdata->gpio_irq); +err_power_on: +#endif + himax_power_on(pdata, false); +err_gpio_reset_req: +#ifdef HX_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) + gpio_free(pdata->gpio_reset); +err_regulator_on: +#endif +err_regulator_not_on: + + return error; +} + +#else +int himax_gpio_power_config(struct i2c_client *client, +struct himax_i2c_platform_data *pdata) +{ + int error = 0; + +#ifdef HX_RST_PIN_FUNC + if (pdata->gpio_reset >= 0) { + error = gpio_request(pdata->gpio_reset, "himax-reset"); + if (error < 0) { + E("%s: request reset pin failed\n", __func__); + return error; + } + error = gpio_direction_output(pdata->gpio_reset, 0); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + return error; + } + } +#endif + if (pdata->gpio_3v3_en >= 0) { + error = gpio_request(pdata->gpio_3v3_en, "himax-3v3_en"); + if (error < 0) { + E("%s: request 3v3_en pin failed\n", __func__); + return error; + } + gpio_direction_output(pdata->gpio_3v3_en, 1); + I("3v3_en pin =%d\n", gpio_get_value(pdata->gpio_3v3_en)); + } + +#ifdef HX_IRQ_PIN_FUNC + if (gpio_is_valid(pdata->gpio_irq)) { + /* configure touchscreen irq gpio */ + error = gpio_request(pdata->gpio_irq, "himax_gpio_irq"); + if (error) { + E("unable to request gpio [%d]\n", pdata->gpio_irq); + return error; + } + error = gpio_direction_input(pdata->gpio_irq); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_irq); + return error; + } + client->irq = gpio_to_irq(pdata->gpio_irq); + } else { + E("irq gpio not provided\n"); + return error; + } +#endif + + msleep(20); + +#ifdef HX_RST_PIN_FUNC + if (pdata->gpio_reset >= 0) { + error = gpio_direction_output(pdata->gpio_reset, 1); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + return error; + } + } + msleep(20); +#endif + + return error; +} +#endif + +static void himax_ts_isr_func(struct himax_ts_data *ts) +{ + himax_ts_work(ts); +} + +irqreturn_t himax_ts_thread(int irq, void *ptr) +{ + uint8_t diag_cmd; + struct himax_ts_data *ts = ptr; + struct timespec timeStart, timeEnd, timeDelta; + + diag_cmd = getDiagCommand(); + + if (ts->debug_log_level & BIT(2)) { + getnstimeofday(&timeStart); + usleep_range(4999, 5000); + /*I(" Irq start time = %ld.%06ld s\n", + timeStart.tv_sec, timeStart.tv_nsec/1000);*/ + } + +#ifdef HX_SMART_WAKEUP + if (atomic_read(&ts->suspend_mode) + && (!FAKE_POWER_KEY_SEND) + && (ts->SMWP_enable) + && (!diag_cmd)) { + __pm_wakeup_event(&ts->ts_SMWP_wake_lock, TS_WAKE_LOCK_TIMEOUT); + msleep(200); + himax_wake_check_func(); + return IRQ_HANDLED; + } +#endif + himax_ts_isr_func((struct himax_ts_data *)ptr); + if (ts->debug_log_level & BIT(2)) { + getnstimeofday(&timeEnd); + timeDelta.tv_nsec + = (timeEnd.tv_sec * 1000000000 + timeEnd.tv_nsec) + - (timeStart.tv_sec * 1000000000 + timeStart.tv_nsec); + /*I("Irq finish time = %ld.%06ld s\n", + timeEnd.tv_sec, timeEnd.tv_nsec/1000); + I("Touch latency = %ld us\n", timeDelta.tv_nsec/1000);*/ + } + return IRQ_HANDLED; +} + +static void himax_ts_work_func(struct work_struct *work) +{ + struct himax_ts_data *ts = + container_of(work, struct himax_ts_data, work); + + himax_ts_work(ts); +} + +int tp_irq = -1; + +int himax_ts_register_interrupt(struct i2c_client *client) +{ + struct himax_ts_data *ts = i2c_get_clientdata(client); + int ret = 0; + + ts->irq_enabled = 0; + /*Work functon*/ + if (client->irq) {/*INT mode*/ + ts->use_irq = 1; + if (ic_data->HX_INT_IS_EDGE) { + I("%s edge triiger falling\n ", __func__); + ret = request_threaded_irq(client->irq, + NULL, himax_ts_thread, IRQF_TRIGGER_FALLING + | IRQF_ONESHOT, client->name, ts); + } else { + I("%s level trigger low\n ", __func__); + ret = request_threaded_irq(client->irq, + NULL, himax_ts_thread, IRQF_TRIGGER_LOW + | IRQF_ONESHOT, client->name, ts); + } + if (ret == 0) { + ts->irq_enabled = 1; + irq_enable_count = 1; + tp_irq = client->irq; + I("%s: irq enabled at qpio: %d\n", + __func__, client->irq); +#ifdef HX_SMART_WAKEUP + irq_set_irq_wake(client->irq, 1); +#endif + } else { + ts->use_irq = 0; + E("%s: request_irq failed\n", __func__); + } + } else { + I("%s: client->irq is empty, use polling mode.\n", __func__); + } + /*if use polling mode need to disable HX_ESD_WORKAROUND function*/ + if (!ts->use_irq) { + ts->himax_wq = create_singlethread_workqueue("himax_touch"); + + INIT_WORK(&ts->work, himax_ts_work_func); + + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ts->timer.function = himax_ts_timer_func; + hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + I("%s: polling mode enabled\n", __func__); + } + return ret; +} + +static int himax_common_suspend(struct device *dev) +{ + struct himax_ts_data *ts = dev_get_drvdata(dev); + + I("%s: enter\n", __func__); + + himax_chip_common_suspend(ts); + return 0; +} + +static int himax_common_resume(struct device *dev) +{ + struct himax_ts_data *ts = dev_get_drvdata(dev); + + I("%s: enter\n", __func__); + + himax_chip_common_resume(ts); + return 0; +} + +#if defined(CONFIG_FB) +int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + struct himax_ts_data *ts + = container_of(self, struct himax_ts_data, fb_notif); + int ERR = 1; + + I(" %s\n", __func__); + if (evdata && evdata->data && event + == FB_EVENT_BLANK && ts && ts->client) { + blank = evdata->data; + + mutex_lock(&ts->fb_mutex); + switch (*blank) { + case FB_BLANK_UNBLANK: + if (!ts->probe_done) { + if (himax_ts_init(ts) == true) { + I("himax_ts_init return OK\n"); + ts->probe_done = true; + } else { + I("himax_ts_init return Fail\n"); + return -ERR; + } + } else + himax_common_resume(&ts->client->dev); + break; + + case FB_BLANK_POWERDOWN: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_NORMAL: + himax_common_suspend(&ts->client->dev); + break; + } + mutex_unlock(&ts->fb_mutex); + } + + return 0; +} +#endif + +static const struct i2c_device_id himax_common_ts_id[] = { + {HIMAX_common_NAME, 0 }, + {} +}; + +static const struct dev_pm_ops himax_common_pm_ops = { +#if (!defined(CONFIG_FB)) + .suspend = himax_common_suspend, + .resume = himax_common_resume, +#endif +}; + +#ifdef CONFIG_OF +static struct of_device_id himax_match_table[] = { + {.compatible = "himax,hxcommon" }, + {}, +}; +#else +#define himax_match_table NULL +#endif + +static struct i2c_driver himax_common_driver = { + .id_table = himax_common_ts_id, + .probe = himax_chip_common_probe, + .remove = himax_chip_common_remove, + .driver = { + .name = HIMAX_common_NAME, + .owner = THIS_MODULE, + .of_match_table = himax_match_table, +#ifdef CONFIG_PM + .pm = &himax_common_pm_ops, +#endif + }, +}; + +static int __init himax_common_init(void) +{ + I("Himax common touch panel driver init\n"); + i2c_add_driver(&himax_common_driver); + return 0; +} + +static void __exit himax_common_exit(void) +{ + i2c_del_driver(&himax_common_driver); +} + +module_init(himax_common_init); +module_exit(himax_common_exit); + +MODULE_DESCRIPTION("Himax_common driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.h b/drivers/input/touchscreen/hxchipset/himax_platform.h new file mode 100644 index 000000000000..6871e53cd1f2 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_platform.h @@ -0,0 +1,157 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef HIMAX_PLATFORM_H +#define HIMAX_PLATFORM_H + +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_HMX_DB) +#include +#endif + +#define QCT + +#define HIMAX_I2C_RETRY_TIMES 10 + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +#define D(x...) pr_info("[HXTP][DEBUG] " x) +#define I(x...) pr_info("[HXTP][INFO] " x) +#define W(x...) pr_info("[HXTP][WARNING] " x) +#define E(x...) pr_info("[HXTP][ERROR] " x) +#define DIF(x...) do { if (debug_flag) pr_info("[HXTP][DEBUG] " x) } while (0) +#else +#define D(x...) +#define I(x...) +#define W(x...) +#define E(x...) +#define DIF(x...) +#endif + +#if defined(CONFIG_HMX_DB) +/* Analog voltage @2.7 V */ +#define HX_VTG_MIN_UV 2700000 +#define HX_VTG_MAX_UV 3300000 +#define HX_ACTIVE_LOAD_UA 15000 +#define HX_LPM_LOAD_UA 10 +/* Digital voltage @1.8 V */ +#define HX_VTG_DIG_MIN_UV 1800000 +#define HX_VTG_DIG_MAX_UV 1800000 +#define HX_ACTIVE_LOAD_DIG_UA 10000 +#define HX_LPM_LOAD_DIG_UA 10 + +#define HX_I2C_VTG_MIN_UV 1800000 +#define HX_I2C_VTG_MAX_UV 1800000 +#define HX_I2C_LOAD_UA 10000 +#define HX_I2C_LPM_LOAD_UA 10 +#endif + +#define HIMAX_common_NAME "himax_tp" +#define HIMAX_I2C_ADDR 0x48 +#define INPUT_DEV_NAME "himax-touchscreen" + +struct himax_i2c_platform_data { + int abs_x_min; + int abs_x_max; + int abs_x_fuzz; + int abs_y_min; + int abs_y_max; + int abs_y_fuzz; + int abs_pressure_min; + int abs_pressure_max; + int abs_pressure_fuzz; + int abs_width_min; + int abs_width_max; + int screenWidth; + int screenHeight; + uint8_t fw_version; + uint8_t tw_id; + uint8_t powerOff3V3; + uint8_t cable_config[2]; + uint8_t protocol_type; + int gpio_irq; + int gpio_reset; + int gpio_3v3_en; + int (*power)(int on); + void (*reset)(void); + struct himax_virtual_key *virtual_key; + struct kobject *vk_obj; + struct kobj_attribute *vk2Use; + + struct himax_config *hx_config; + int hx_config_size; +#if defined(CONFIG_HMX_DB) + bool i2c_pull_up; + bool digital_pwr_regulator; + int reset_gpio; + u32 reset_gpio_flags; + int irq_gpio; + u32 irq_gpio_flags; + + struct regulator *vcc_ana; /*For Dragon Board*/ + struct regulator *vcc_dig; /*For Dragon Board*/ + struct regulator *vcc_i2c; /*For Dragon Board*/ +#endif +}; + + +extern int irq_enable_count; +int i2c_himax_read(struct i2c_client *client, + uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); + +int i2c_himax_write(struct i2c_client *client, + uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); + +int i2c_himax_write_command(struct i2c_client *client, + uint8_t command, uint8_t toRetry); + +int i2c_himax_master_write(struct i2c_client *client, + uint8_t *data, uint8_t length, uint8_t toRetry); + +int i2c_himax_read_command(struct i2c_client *client, + uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry); + +void himax_int_enable(int irqnum, int enable); +int himax_ts_register_interrupt(struct i2c_client *client); +void himax_rst_gpio_set(int pinnum, uint8_t value); +uint8_t himax_int_gpio_read(int pinnum); + +int himax_gpio_power_config(struct i2c_client *client, + struct himax_i2c_platform_data *pdata); + +#if defined(CONFIG_FB) +extern int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); +#endif +extern struct himax_ts_data *private_ts; +extern struct himax_ic_data *ic_data; +extern void himax_ts_work(struct himax_ts_data *ts); +extern enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer); +extern int tp_rst_gpio; + +#ifdef HX_TP_PROC_DIAG +extern uint8_t getDiagCommand(void); +#endif + +int himax_parse_dt(struct himax_ts_data *ts, + struct himax_i2c_platform_data *pdata); +int himax_ts_pinctrl_init(struct himax_ts_data *ts); + +#endif -- GitLab From 6a429755a9889483556f4f523ac02279ee3761b6 Mon Sep 17 00:00:00 2001 From: taojiang Date: Mon, 16 Jul 2018 13:36:21 +0800 Subject: [PATCH 455/604] msm: camera: enable 3 RDI path work concurrently If we use 3 RDI path concurrently, and the lower 8bit of stream_cfg_cmd->axi_stream_handle is assigned to stream_cfg_cmd->stream_src whose value is 7,in this case, the function msm_isp_validate_axi_request() will return error. Change-Id: I1c73192a22cc29c5743618cdc961794e1549657b Signed-off-by: Tao Jiang --- .../msm/camera_v2/isp/msm_isp_axi_util_32.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c index 21bac16e0843..b5a6f44f20fa 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c @@ -25,12 +25,16 @@ int msm_isp_axi_create_stream( struct msm_vfe_axi_shared_data *axi_data, struct msm_vfe32_axi_stream_request_cmd *stream_cfg_cmd) { - uint32_t i = stream_cfg_cmd->stream_src; + int i, rc = -1; - if (i >= VFE_AXI_SRC_MAX) { - pr_err("%s:%d invalid stream_src %d\n", __func__, __LINE__, - stream_cfg_cmd->stream_src); - return -EINVAL; + for (i = 0; i < MAX_NUM_STREAM; i++) { + if (axi_data->stream_info[i].state == AVAILABLE) + break; + } + + if (i == MAX_NUM_STREAM) { + pr_err("%s: No free stream\n", __func__); + return rc; } if ((axi_data->stream_handle_cnt << 8) == 0) -- GitLab From aac6ebb169c63751670c3044ed551a173130b234 Mon Sep 17 00:00:00 2001 From: zhaochen Date: Fri, 20 Jul 2018 12:12:23 +0800 Subject: [PATCH 456/604] icm20602: fix suspend function problem Icm20602 has problem when it excutes suspend function, change the value of ldo in static and resolve this problem. Change-Id: Ib17bdfa43a79e2a3c6c19ed0c80718639f2e0d22 Signed-off-by: zhaochen --- drivers/iio/imu/inv_icm20602/inv_icm20602_core.c | 14 ++++++++------ drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h | 5 ++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c index 7dda14e33428..bf8e9681cae1 100644 --- a/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c @@ -31,6 +31,9 @@ #include "inv_icm20602_iio.h" #include + +static struct regulator *reg_ldo; + /* Attribute of icm20602 device init show */ static ssize_t inv_icm20602_init_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -384,19 +387,19 @@ static int icm20602_ldo_work(struct inv_icm20602_state *st, bool enable) int ret = 0; if (enable) { - ret = regulator_set_voltage(st->reg_ldo, + ret = regulator_set_voltage(reg_ldo, ICM20602_LDO_VTG_MIN_UV, ICM20602_LDO_VTG_MAX_UV); if (ret) pr_err("Failed to request LDO voltage.\n"); - ret = regulator_enable(st->reg_ldo); + ret = regulator_enable(reg_ldo); if (ret) pr_err("Failed to enable LDO %d\n", ret); } else { - ret = regulator_disable(st->reg_ldo); + ret = regulator_disable(reg_ldo); + regulator_set_load(reg_ldo, 0); if (ret) pr_err("Failed to disable LDO %d\n", ret); - regulator_set_load(st->reg_ldo, 0); } return MPU_SUCCESS; @@ -405,14 +408,13 @@ static int icm20602_ldo_work(struct inv_icm20602_state *st, bool enable) static int icm20602_init_regulators(struct inv_icm20602_state *st) { struct regulator *reg; - reg = regulator_get(&st->client->dev, "vdd-ldo"); if (IS_ERR_OR_NULL(reg)) { pr_err("Unable to get regulator for LDO\n"); return -MPU_FAIL; } - st->reg_ldo = reg; + reg_ldo = reg; return MPU_SUCCESS; } diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h b/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h index b369ae4dc0ab..36f8e9c130f0 100644 --- a/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h @@ -41,8 +41,8 @@ #define INV20602_SMD_IRQ_TRIGGER 1 #endif -#define ICM20602_LDO_VTG_MIN_UV 3300000 -#define ICM20602_LDO_VTG_MAX_UV 3300000 +#define ICM20602_LDO_VTG_MIN_UV 1800000 +#define ICM20602_LDO_VTG_MAX_UV 1800000 #define INV_ICM20602_TIME_STAMP_TOR 5 #define ICM20602_PACKAGE_SIZE 14 @@ -220,7 +220,6 @@ struct inv_icm20602_state { struct struct_icm20602_data *data_push; enum inv_devices chip_type; int gpio; - struct regulator *reg_ldo; DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE); }; -- GitLab From 4db6264c3de8b798607494b03c3a330097871d2d Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Mon, 16 Jul 2018 11:21:48 +0530 Subject: [PATCH 457/604] power: qpnp-qg: Add handling for SYS_SOC Use the raw SYS_SOC to calculate the MSOC. Adjust the SOC at cutoff and termination for better user experience. Change-Id: I1d1a0eb19cb89df754a9694c1484de37db2eb218 Signed-off-by: Anirudh Ghayal --- drivers/power/supply/qcom/qg-core.h | 2 ++ drivers/power/supply/qcom/qg-soc.c | 37 ++++++++++++++++++++++++ drivers/power/supply/qcom/qg-soc.h | 1 + drivers/power/supply/qcom/qg-util.c | 22 ++++++++++++++ drivers/power/supply/qcom/qg-util.h | 1 + drivers/power/supply/qcom/qpnp-qg.c | 45 ++++++++++++----------------- include/uapi/linux/qg.h | 3 +- 7 files changed, 83 insertions(+), 28 deletions(-) diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h index b3bf42a2fb2d..91279c05defb 100644 --- a/drivers/power/supply/qcom/qg-core.h +++ b/drivers/power/supply/qcom/qg-core.h @@ -143,6 +143,8 @@ struct qpnp_qg { int batt_soc; int cc_soc; int full_soc; + int sys_soc; + int last_adj_ssoc; struct alarm alarm_timer; u32 sdam_data[SDAM_MAX]; diff --git a/drivers/power/supply/qcom/qg-soc.c b/drivers/power/supply/qcom/qg-soc.c index af8b158b7c95..12e19a58af83 100644 --- a/drivers/power/supply/qcom/qg-soc.c +++ b/drivers/power/supply/qcom/qg-soc.c @@ -17,15 +17,19 @@ #include #include #include +#include #include "fg-alg.h" #include "qg-sdam.h" #include "qg-core.h" #include "qg-reg.h" #include "qg-util.h" #include "qg-defs.h" +#include "qg-soc.h" #define DEFAULT_UPDATE_TIME_MS 64000 #define SOC_SCALE_HYST_MS 2000 +#define VBAT_LOW_HYST_UV 50000 +#define FULL_SOC 100 static int qg_delta_soc_interval_ms = 20000; module_param_named( @@ -37,6 +41,39 @@ module_param_named( soc_cold_interval_ms, qg_delta_soc_cold_interval_ms, int, 0600 ); +int qg_adjust_sys_soc(struct qpnp_qg *chip) +{ + int soc, vbat_uv, rc; + int vcutoff_uv = chip->dt.vbatt_cutoff_mv * 1000; + + chip->sys_soc = CAP(QG_MIN_SOC, QG_MAX_SOC, chip->sys_soc); + + if (chip->sys_soc == QG_MIN_SOC) { + /* Hold SOC to 1% of VBAT has not dropped below cutoff */ + rc = qg_get_battery_voltage(chip, &vbat_uv); + if (!rc && vbat_uv >= (vcutoff_uv + VBAT_LOW_HYST_UV)) + soc = 1; + else + soc = 0; + } else if (chip->sys_soc == QG_MAX_SOC) { + soc = FULL_SOC; + } else if (chip->sys_soc >= (QG_MAX_SOC - 100)) { + /* Hold SOC to 100% if we are dropping from 100 to 99 */ + if (chip->last_adj_ssoc == FULL_SOC) + soc = FULL_SOC; + else /* Hold SOC at 99% until we hit 100% */ + soc = FULL_SOC - 1; + } else { + soc = DIV_ROUND_CLOSEST(chip->sys_soc, 100); + } + + qg_dbg(chip, QG_DEBUG_SOC, "last_adj_sys_soc=%d adj_sys_soc=%d\n", + chip->last_adj_ssoc, soc); + chip->last_adj_ssoc = soc; + + return soc; +} + static void get_next_update_time(struct qpnp_qg *chip) { int soc_points = 0, batt_temp = 0; diff --git a/drivers/power/supply/qcom/qg-soc.h b/drivers/power/supply/qcom/qg-soc.h index 3b4eb6031c1a..cd64bd5de792 100644 --- a/drivers/power/supply/qcom/qg-soc.h +++ b/drivers/power/supply/qcom/qg-soc.h @@ -16,5 +16,6 @@ int qg_scale_soc(struct qpnp_qg *chip, bool force_soc); int qg_soc_init(struct qpnp_qg *chip); void qg_soc_exit(struct qpnp_qg *chip); +int qg_adjust_sys_soc(struct qpnp_qg *chip); #endif /* __QG_SOC_H__ */ diff --git a/drivers/power/supply/qcom/qg-util.c b/drivers/power/supply/qcom/qg-util.c index 85efdbf54efc..a3e045e93f35 100644 --- a/drivers/power/supply/qcom/qg-util.c +++ b/drivers/power/supply/qcom/qg-util.c @@ -367,3 +367,25 @@ int qg_get_battery_current(struct qpnp_qg *chip, int *ibat_ua) BURST_AVG_HOLD_FOR_READ_BIT, 0); return rc; } + +int qg_get_battery_voltage(struct qpnp_qg *chip, int *vbat_uv) +{ + int rc = 0; + u64 last_vbat = 0; + + if (chip->battery_missing) { + *vbat_uv = 3700000; + return 0; + } + + rc = qg_read(chip, chip->qg_base + QG_LAST_ADC_V_DATA0_REG, + (u8 *)&last_vbat, 2); + if (rc < 0) { + pr_err("Failed to read LAST_ADV_V reg, rc=%d\n", rc); + return rc; + } + + *vbat_uv = V_RAW_TO_UV(last_vbat); + + return rc; +} diff --git a/drivers/power/supply/qcom/qg-util.h b/drivers/power/supply/qcom/qg-util.h index 2dbafe7973db..5dd6c85728f8 100644 --- a/drivers/power/supply/qcom/qg-util.h +++ b/drivers/power/supply/qcom/qg-util.h @@ -26,5 +26,6 @@ bool is_parallel_enabled(struct qpnp_qg *chip); 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); #endif diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 41b8d3c0cd7b..39869c140271 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -1029,11 +1029,23 @@ static void process_udata_work(struct work_struct *work) if (chip->udata.param[QG_FULL_SOC].valid) chip->full_soc = chip->udata.param[QG_FULL_SOC].data; - if (chip->udata.param[QG_SOC].valid) { - qg_dbg(chip, QG_DEBUG_SOC, "udata SOC=%d last SOC=%d\n", - chip->udata.param[QG_SOC].data, chip->catch_up_soc); + if (chip->udata.param[QG_SOC].valid || + chip->udata.param[QG_SYS_SOC].valid) { + + qg_dbg(chip, QG_DEBUG_SOC, "udata update: QG_SOC=%d QG_SYS_SOC=%d last_catchup_soc=%d\n", + chip->udata.param[QG_SOC].valid ? + chip->udata.param[QG_SOC].data : -EINVAL, + chip->udata.param[QG_SYS_SOC].valid ? + chip->udata.param[QG_SYS_SOC].data : -EINVAL, + chip->catch_up_soc); + + if (chip->udata.param[QG_SYS_SOC].valid) { + chip->sys_soc = chip->udata.param[QG_SYS_SOC].data; + chip->catch_up_soc = qg_adjust_sys_soc(chip); + } else { + chip->catch_up_soc = chip->udata.param[QG_SOC].data; + } - chip->catch_up_soc = chip->udata.param[QG_SOC].data; qg_scale_soc(chip, false); /* update parameters to SDAM */ @@ -1500,28 +1512,6 @@ static const char *qg_get_battery_type(struct qpnp_qg *chip) return DEFAULT_BATT_TYPE; } -static int qg_get_battery_voltage(struct qpnp_qg *chip, int *vbat_uv) -{ - int rc = 0; - u64 last_vbat = 0; - - if (chip->battery_missing) { - *vbat_uv = 3700000; - return 0; - } - - rc = qg_read(chip, chip->qg_base + QG_LAST_ADC_V_DATA0_REG, - (u8 *)&last_vbat, 2); - if (rc < 0) { - pr_err("Failed to read LAST_ADV_V reg, rc=%d\n", rc); - return rc; - } - - *vbat_uv = V_RAW_TO_UV(last_vbat); - - return rc; -} - #define DEBUG_BATT_SOC 67 #define BATT_MISSING_SOC 50 #define EMPTY_SOC 0 @@ -2620,7 +2610,7 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip) return rc; } - chip->pon_soc = chip->catch_up_soc = chip->msoc = soc; + chip->last_adj_ssoc = chip->catch_up_soc = chip->msoc = soc; chip->kdata.param[QG_PON_OCV_UV].data = ocv_uv; chip->kdata.param[QG_PON_OCV_UV].valid = true; @@ -3606,6 +3596,7 @@ static int qpnp_qg_probe(struct platform_device *pdev) chip->maint_soc = -EINVAL; chip->batt_soc = INT_MIN; chip->cc_soc = INT_MIN; + chip->sys_soc = INT_MIN; chip->full_soc = QG_SOC_FULL; chip->chg_iterm_ma = INT_MIN; chip->soh = -EINVAL; diff --git a/include/uapi/linux/qg.h b/include/uapi/linux/qg.h index 40882a7ae8c4..54aa36261980 100644 --- a/include/uapi/linux/qg.h +++ b/include/uapi/linux/qg.h @@ -20,7 +20,7 @@ enum qg { QG_ESR_DISCHARGE_SF, QG_FULL_SOC, QG_CLEAR_LEARNT_DATA, - QG_RESERVED_9, + QG_SYS_SOC, QG_RESERVED_10, QG_MAX, }; @@ -33,6 +33,7 @@ enum qg { #define QG_ESR_DISCHARGE_SF QG_ESR_DISCHARGE_SF #define QG_FULL_SOC QG_FULL_SOC #define QG_CLEAR_LEARNT_DATA QG_CLEAR_LEARNT_DATA +#define QG_SYS_SOC QG_SYS_SOC struct fifo_data { unsigned int v; -- GitLab From 31009586a22b801ea5343ce4bd9b54281e920da2 Mon Sep 17 00:00:00 2001 From: Rahul Shahare Date: Thu, 19 Jul 2018 10:48:23 +0530 Subject: [PATCH 458/604] perf_defconfig: msm8937: Enable the config QCOM_SHOW_RESUME_IRQ Enable "QCOM_SHOW_RESUME_IRQ", to support msm_show_resume_irq. Change-Id: Ie87905304ce0edd6bf1c4dae91b78f35ba3b769b Signed-off-by: Rahul Shahare --- arch/arm/configs/msm8937-perf_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index 3747ca39cc1f..040ce14b6375 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -585,6 +585,7 @@ CONFIG_IIO=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_PWM_QTI_LPG=y +CONFIG_QCOM_SHOW_RESUME_IRQ=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y -- GitLab From ba1216fb3a9a2f62aec63f1e648bfbc13807326d Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Wed, 18 Jul 2018 16:29:23 -0700 Subject: [PATCH 459/604] drm/msm/sde: update CWB detection logic Modify CWB use case detection based on encoders on a crtc. Other than wb parent encoder, if any other drm encoder is connected to same crtc, treat wb encoder is in clone mode. Change-Id: I05d7b52887aa01df682fe1e93a205efdcc2fa5c0 Signed-off-by: Prabhanjan Kandula Signed-off-by: Jayant Shekhar --- drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c index 82dd64abe66c..4bbcb3ae567c 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c @@ -32,7 +32,6 @@ #define TO_S15D16(_x_) ((_x_) << 7) -#define MULTIPLE_CONN_DETECTED(x) (x > 1) /** * sde_rgb2yuv_601l - rgb to yuv color space conversion matrix * @@ -453,11 +452,9 @@ static void sde_encoder_phys_wb_setup_cdp(struct sde_encoder_phys *phys_enc) static void _sde_enc_phys_wb_detect_cwb(struct sde_encoder_phys *phys_enc, struct drm_crtc_state *crtc_state) { - struct drm_connector *conn; - struct drm_connector_state *conn_state; + struct drm_encoder *encoder; struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); const struct sde_wb_cfg *wb_cfg = wb_enc->hw_wb->caps; - int conn_count = 0; phys_enc->in_clone_mode = false; @@ -465,21 +462,16 @@ static void _sde_enc_phys_wb_detect_cwb(struct sde_encoder_phys *phys_enc, if (!(wb_cfg->features & BIT(SDE_WB_HAS_CWB))) return; - /* Count the number of connectors on the given crtc */ - drm_for_each_connector(conn, crtc_state->crtc->dev) { - conn_state = - drm_atomic_get_connector_state(crtc_state->state, conn); - if ((conn->state && conn->state->crtc == crtc_state->crtc) || - (conn_state && - conn_state->crtc == crtc_state->crtc)) - conn_count++; + /* if any other encoder is connected to same crtc enable clone mode*/ + drm_for_each_encoder(encoder, crtc_state->crtc->dev) { + if (encoder->crtc != crtc_state->crtc) + continue; + if (phys_enc->parent != encoder) { + phys_enc->in_clone_mode = true; + break; + } } - - /* Enable clone mode If crtc has multiple connectors & one is WB */ - if (MULTIPLE_CONN_DETECTED(conn_count)) - phys_enc->in_clone_mode = true; - SDE_DEBUG("detect CWB - status:%d\n", phys_enc->in_clone_mode); } -- GitLab From 87ed6e619834f46c928ff91f346c2cfc1d6e0e02 Mon Sep 17 00:00:00 2001 From: Evgeniy Borisov Date: Tue, 3 Jul 2018 16:30:40 -0700 Subject: [PATCH 460/604] net: wireless: implements host target communication with QCA402x This driver enables support for communication beteween an APQ8053 Host and Qualcomm's QCA402x wireless SoC. Change-Id: I777f89b95094ad1cd72f515bb43a198502d0a12f Signed-off-by: Evgeniy Borisov --- drivers/net/wireless/Kconfig | 2 + drivers/net/wireless/Makefile | 1 + drivers/net/wireless/qca402x/Kconfig | 10 + drivers/net/wireless/qca402x/Makefile | 9 + drivers/net/wireless/qca402x/README.txt | 52 + drivers/net/wireless/qca402x/hif_sdio/hif.c | 1230 +++++++++++++++++ drivers/net/wireless/qca402x/hif_sdio/hif.h | 335 +++++ .../wireless/qca402x/hif_sdio/hif_internal.h | 117 ++ .../qca402x/hif_sdio/hif_sdio_common.h | 43 + drivers/net/wireless/qca402x/htca_mbox/htca.h | 132 ++ .../wireless/qca402x/htca_mbox/htca_mbox.c | 497 +++++++ .../qca402x/htca_mbox/htca_mbox_compl.c | 503 +++++++ .../qca402x/htca_mbox/htca_mbox_events.c | 130 ++ .../qca402x/htca_mbox/htca_mbox_internal.h | 581 ++++++++ .../qca402x/htca_mbox/htca_mbox_intr.c | 627 +++++++++ .../qca402x/htca_mbox/htca_mbox_recv.c | 205 +++ .../qca402x/htca_mbox/htca_mbox_send.c | 392 ++++++ .../qca402x/htca_mbox/htca_mbox_task.c | 340 +++++ .../qca402x/htca_mbox/htca_mbox_utils.c | 182 +++ .../qca402x/htca_mbox/mbox_host_reg.h | 412 ++++++ 20 files changed, 5800 insertions(+) create mode 100644 drivers/net/wireless/qca402x/Kconfig create mode 100644 drivers/net/wireless/qca402x/Makefile create mode 100644 drivers/net/wireless/qca402x/README.txt create mode 100644 drivers/net/wireless/qca402x/hif_sdio/hif.c create mode 100644 drivers/net/wireless/qca402x/hif_sdio/hif.h create mode 100644 drivers/net/wireless/qca402x/hif_sdio/hif_internal.h create mode 100644 drivers/net/wireless/qca402x/hif_sdio/hif_sdio_common.h create mode 100644 drivers/net/wireless/qca402x/htca_mbox/htca.h create mode 100644 drivers/net/wireless/qca402x/htca_mbox/htca_mbox.c create mode 100644 drivers/net/wireless/qca402x/htca_mbox/htca_mbox_compl.c create mode 100644 drivers/net/wireless/qca402x/htca_mbox/htca_mbox_events.c create mode 100644 drivers/net/wireless/qca402x/htca_mbox/htca_mbox_internal.h create mode 100644 drivers/net/wireless/qca402x/htca_mbox/htca_mbox_intr.c create mode 100644 drivers/net/wireless/qca402x/htca_mbox/htca_mbox_recv.c create mode 100644 drivers/net/wireless/qca402x/htca_mbox/htca_mbox_send.c create mode 100644 drivers/net/wireless/qca402x/htca_mbox/htca_mbox_task.c create mode 100644 drivers/net/wireless/qca402x/htca_mbox/htca_mbox_utils.c create mode 100644 drivers/net/wireless/qca402x/htca_mbox/mbox_host_reg.h diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index bb2270bcbafa..c915dedbb3b1 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -114,3 +114,5 @@ source "drivers/net/wireless/cnss_utils/Kconfig" source "drivers/net/wireless/cnss_genl/Kconfig" endif # WLAN + +source "drivers/net/wireless/qca402x/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 917a876062d9..6cf62b660661 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -32,3 +32,4 @@ obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/ obj-$(CONFIG_CNSS_UTILS) += cnss_utils/ obj-$(CONFIG_CNSS_GENL) += cnss_genl/ obj-$(CONFIG_CNSS_CRYPTO) += cnss_crypto/ +obj-$(CONFIG_QCA402X) += qca402x/ diff --git a/drivers/net/wireless/qca402x/Kconfig b/drivers/net/wireless/qca402x/Kconfig new file mode 100644 index 000000000000..bae2a491d75a --- /dev/null +++ b/drivers/net/wireless/qca402x/Kconfig @@ -0,0 +1,10 @@ +config QCA402X + tristate "Qualcomm QCA402X wireless support" + default n + ---help--- + Software for Qualcomm QCA402x including HIF and HTCA. + + Say Y here if support for Qualcomm's QCA402x wireless SoC + via host-target communication protocol is required. + Say N to disable completely if support for that device is + not needed or if not sure. diff --git a/drivers/net/wireless/qca402x/Makefile b/drivers/net/wireless/qca402x/Makefile new file mode 100644 index 000000000000..c052f7327b68 --- /dev/null +++ b/drivers/net/wireless/qca402x/Makefile @@ -0,0 +1,9 @@ +obj-$(CONFIG_QCA402X) += htca_mbox/htca_mbox.o +obj-$(CONFIG_QCA402X) += htca_mbox/htca_mbox_compl.o +obj-$(CONFIG_QCA402X) += htca_mbox/htca_mbox_events.o +obj-$(CONFIG_QCA402X) += htca_mbox/htca_mbox_intr.o +obj-$(CONFIG_QCA402X) += htca_mbox/htca_mbox_recv.o +obj-$(CONFIG_QCA402X) += htca_mbox/htca_mbox_send.o +obj-$(CONFIG_QCA402X) += htca_mbox/htca_mbox_task.o +obj-$(CONFIG_QCA402X) += htca_mbox/htca_mbox_utils.o +obj-$(CONFIG_QCA402X) += hif_sdio/hif.o diff --git a/drivers/net/wireless/qca402x/README.txt b/drivers/net/wireless/qca402x/README.txt new file mode 100644 index 000000000000..50873a816258 --- /dev/null +++ b/drivers/net/wireless/qca402x/README.txt @@ -0,0 +1,52 @@ +This directory contains support to communicate beteween an APQ8053 Host +and Qualcomm's QCA402x wireless SoC. + +QCA4020 SoC supports + 802.11 (i.e. WiFi/WLAN) + 802.15.4 (i.e. Zigbee, Thread) + BT LE + +Contents of this directory may eventually include: + cfg80211 support + SoftMAC wireless driver + Perhaps a mac80211 driver + Zigbee APIs + Thread APIs + BT APIs + +For now, all that is present are the bottommost layers of a communication stack: + + HTCA - Host/Target Communications protocol + htca_mbox + Quartz SDIO/SPI address space + Quartz mailboxes and associated SDIO/SPI registers + Quartz mbox credit-based flow control + htca_uart (TBD) + + HIF - a shim layer which abstracts the underlying Master/Host-side + interconnect controller (e.g. SDIO controller) to provide + an interconnect-independent API for use by HTCA. + hif_sdio + Host Interface layer for SDIO Master controllers + hif_spi (TBD) + Host Interface layer for SPI Master controllers + hif_uart (TBD) + Host Interface layer for UART-based controllers + + qrtzdev-a simple driver used for HTCA TESTING. + +Note: The initial implementation supports HTCA Protocol Version 1 over SDIO. +It is based on previous HTCA implementations for Atheros SoCs, but uses a +revised design which appropriately leverages kernel threads. + +This implementation is likely to evolve with increasing focus on performance, +especially for use cases of current interest such as streaming video from +Host over SDIO to WLAN; however this evolution may differ from the existing +implementation of HTCA Protocol Version 2 used by earlier Atheros SoC's. + +However there are several issues with this code: + it is based on HTCA v2 protocol which adds complexity + it is based on a non-threaded design, originally for a non-threaded RTOS +TBD: Ideally, these two implementations ought to be merged so that the resulting +implementation is based on a proper threaded design and supports both HTCA +protocol v1 and v2. diff --git a/drivers/net/wireless/qca402x/hif_sdio/hif.c b/drivers/net/wireless/qca402x/hif_sdio/hif.c new file mode 100644 index 000000000000..56d3b95d8d33 --- /dev/null +++ b/drivers/net/wireless/qca402x/hif_sdio/hif.c @@ -0,0 +1,1230 @@ +/* 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. + */ + +/* This file was originally distributed by Qualcomm Atheros, Inc. + * before Copyright ownership was assigned to the Linux Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hif_internal.h" +#include "hif.h" + +#if defined(DEBUG) +#define hifdebug(fmt, a...)\ + pr_err("hif %s:%d: " fmt, __func__, __LINE__, ##a) +#else +#define hifdebug(args...) +#endif + +#define MAX_HIF_DEVICES 2 +#define ENABLE_SDIO_TIMEOUT 100 /* ms */ + +static unsigned int hif_mmcbuswidth; +EXPORT_SYMBOL(hif_mmcbuswidth); +module_param(hif_mmcbuswidth, uint, 0644); +MODULE_PARM_DESC(hif_mmcbuswidth, "Set MMC driver Bus Width: 1-1Bit, 4-4Bit, 8-8Bit"); + +static unsigned int hif_mmcclock; +EXPORT_SYMBOL(hif_mmcclock); +module_param(hif_mmcclock, uint, 0644); +MODULE_PARM_DESC(hif_mmcclock, "Set MMC driver Clock value"); + +static unsigned int hif_writecccr1; +module_param(hif_writecccr1, uint, 0644); +static unsigned int hif_writecccr1value; +module_param(hif_writecccr1value, uint, 0644); + +static unsigned int hif_writecccr2; +module_param(hif_writecccr2, uint, 0644); +static unsigned int hif_writecccr2value; +module_param(hif_writecccr2value, uint, 0644); + +static unsigned int hif_writecccr3; +module_param(hif_writecccr3, uint, 0644); +static unsigned int hif_writecccr3value; +module_param(hif_writecccr3value, uint, 0644); + +static unsigned int hif_writecccr4; +module_param(hif_writecccr4, uint, 0644); + +static unsigned int hif_writecccr4value; +module_param(hif_writecccr4value, uint, 0644); + +static int hif_device_inserted(struct sdio_func *func, + const struct sdio_device_id *id); +static void hif_device_removed(struct sdio_func *func); +static void *add_hif_device(struct sdio_func *func); +static struct hif_device *get_hif_device(struct sdio_func *func); +static void del_hif_device(struct hif_device *device); +static int func0_CMD52_write_byte(struct mmc_card *card, unsigned int address, + unsigned char byte); +static int func0_CMD52_read_byte(struct mmc_card *card, unsigned int address, + unsigned char *byte); +static void hif_stop_hif_task(struct hif_device *device); +static struct bus_request *hif_allocate_bus_request(void *device); +static void hif_free_bus_request(struct hif_device *device, + struct bus_request *busrequest); +static void hif_add_to_req_list(struct hif_device *device, + struct bus_request *busrequest); + +static int hif_reset_sdio_on_unload; +module_param(hif_reset_sdio_on_unload, int, 0644); + +static u32 hif_forcedriverstrength = 1; /* force driver strength to type D */ + +static const struct sdio_device_id hif_sdio_id_table[] = { + {SDIO_DEVICE(SDIO_ANY_ID, + SDIO_ANY_ID)}, /* QCA402x IDs are hardwired to 0 */ + {/* null */}, +}; + +MODULE_DEVICE_TABLE(sdio, hif_sdio_id_table); + +static struct sdio_driver hif_sdio_driver = { + .name = "hif_sdio", + .id_table = hif_sdio_id_table, + .probe = hif_device_inserted, + .remove = hif_device_removed, +}; + +/* make sure we unregister only when registered. */ +/* TBD: synchronization needed.... */ +/* device->completion_task, registered, ... */ +static int registered; + +static struct cbs_from_os hif_callbacks; + +static struct hif_device *hif_devices[MAX_HIF_DEVICES]; + +static int hif_disable_func(struct hif_device *device, struct sdio_func *func); +static int hif_enable_func(struct hif_device *device, struct sdio_func *func); + +static int hif_sdio_register_driver(struct cbs_from_os *callbacks) +{ + /* store the callback handlers */ + hif_callbacks = *callbacks; /* structure copy */ + + /* Register with bus driver core */ + registered++; + + return sdio_register_driver(&hif_sdio_driver); +} + +static void hif_sdio_unregister_driver(void) +{ + sdio_unregister_driver(&hif_sdio_driver); + registered--; +} + +int hif_init(struct cbs_from_os *callbacks) +{ + int status; + + hifdebug("Enter\n"); + if (!callbacks) + return HIF_ERROR; + + hifdebug("calling hif_sdio_register_driver\n"); + status = hif_sdio_register_driver(callbacks); + hifdebug("hif_sdio_register_driver returns %d\n", status); + if (status != 0) + return HIF_ERROR; + + return HIF_OK; +} + +static int __hif_read_write(struct hif_device *device, u32 address, + u8 *buffer, u32 length, + u32 request, void *context) +{ + u8 opcode; + int status = HIF_OK; + int ret = 0; + u8 temp[4]; + + if (!device || !device->func) + return HIF_ERROR; + + if (!buffer) + return HIF_EINVAL; + + if (length == 0) + return HIF_EINVAL; + + do { + if (!(request & HIF_EXTENDED_IO)) { + status = HIF_EINVAL; + break; + } + + if (request & HIF_BLOCK_BASIS) { + if (WARN_ON(length & (HIF_MBOX_BLOCK_SIZE - 1))) + return HIF_EINVAL; + } else if (request & HIF_BYTE_BASIS) { + } else { + status = HIF_EINVAL; + break; + } + + if (request & HIF_FIXED_ADDRESS) { + opcode = CMD53_FIXED_ADDRESS; + } else if (request & HIF_INCREMENTAL_ADDRESS) { + opcode = CMD53_INCR_ADDRESS; + } else { + status = HIF_EINVAL; + break; + } + + if (request & HIF_WRITE) { + if (opcode == CMD53_FIXED_ADDRESS) { + /* TBD: Why special handling? */ + if (length == 1) { + memset(temp, *buffer, 4); + ret = sdio_writesb(device->func, + address, temp, 4); + } else { + ret = + sdio_writesb(device->func, address, + buffer, length); + } + } else { + ret = sdio_memcpy_toio(device->func, address, + buffer, length); + } + } else if (request & HIF_READ) { + if (opcode == CMD53_FIXED_ADDRESS) { + if (length == + 1) { /* TBD: Why special handling? */ + memset(temp, 0, 4); + ret = sdio_readsb(device->func, temp, + address, 4); + buffer[0] = temp[0]; + } else { + ret = sdio_readsb(device->func, buffer, + address, length); + } + } else { + ret = sdio_memcpy_fromio(device->func, buffer, + address, length); + } + } else { + status = HIF_EINVAL; /* Neither read nor write */ + break; + } + + if (ret) { + hifdebug("SDIO op returns %d\n", ret); + status = HIF_ERROR; + } + } while (false); + + return status; +} + +/* Add busrequest to tail of sdio_request request list */ +static void hif_add_to_req_list(struct hif_device *device, + struct bus_request *busrequest) +{ + unsigned long flags; + + busrequest->next = NULL; + + spin_lock_irqsave(&device->req_qlock, flags); + if (device->req_qhead) + device->req_qtail->next = (void *)busrequest; + else + device->req_qhead = busrequest; + device->req_qtail = busrequest; + spin_unlock_irqrestore(&device->req_qlock, flags); +} + +int hif_sync_read(void *hif_device, u32 address, u8 *buffer, + u32 length, u32 request, void *context) +{ + int status; + struct hif_device *device = (struct hif_device *)hif_device; + + if (!device || !device->func) + return HIF_ERROR; + + sdio_claim_host(device->func); + status = __hif_read_write(device, address, buffer, length, + request & ~HIF_SYNCHRONOUS, NULL); + sdio_release_host(device->func); + return status; +} + +/* Queue a read/write request and optionally wait for it to complete. */ +int hif_read_write(void *hif_device, u32 address, void *buffer, + u32 length, u32 req_type, void *context) +{ + struct bus_request *busrequest; + int status; + struct hif_device *device = (struct hif_device *)hif_device; + + if (!device || !device->func) + return HIF_ERROR; + + if (!(req_type & HIF_ASYNCHRONOUS) && !(req_type & HIF_SYNCHRONOUS)) + return HIF_EINVAL; + + /* Serialize all requests through the reqlist and HIFtask */ + busrequest = hif_allocate_bus_request(device); + if (!busrequest) + return HIF_ERROR; + + /* TBD: caller may pass buffers ON THE STACK, especially 4 Byte buffers. + * If this is a problem on some platforms/drivers, this is one + * reasonable + * place to handle it. If poentially using DMA + * reject large buffers on stack + * copy 4B buffers allow register writes (no DMA) + */ + + busrequest->address = address; + busrequest->buffer = buffer; + busrequest->length = length; + busrequest->req_type = req_type; + busrequest->context = context; + + hif_add_to_req_list(device, busrequest); + device->hif_task_work = 1; + wake_up(&device->hif_wait); /* Notify HIF task */ + + if (req_type & HIF_ASYNCHRONOUS) + return HIF_PENDING; + + /* Synchronous request -- wait for completion. */ + wait_for_completion(&busrequest->comp_req); + status = busrequest->status; + hif_free_bus_request(device, busrequest); + return status; +} + +/* add_to_completion_list() - Queue a completed request + * @device: context to the hif device. + * @comple: SDIO bus access request. + * + * This function adds an sdio bus access request to the + * completion list. + * + * Return: No return. + */ +static void add_to_completion_list(struct hif_device *device, + struct bus_request *comple) +{ + unsigned long flags; + + comple->next = NULL; + + spin_lock_irqsave(&device->compl_qlock, flags); + if (device->compl_qhead) + device->compl_qtail->next = (void *)comple; + else + device->compl_qhead = comple; + + device->compl_qtail = comple; + spin_unlock_irqrestore(&device->compl_qlock, flags); +} + +/* process_completion_list() - Remove completed requests from + * the completion list, and invoke the corresponding callbacks. + * + * @device: HIF device handle. + * + * Function to clean the completion list. + * + * Return: No + */ +static void process_completion_list(struct hif_device *device) +{ + unsigned long flags; + struct bus_request *next_comple; + struct bus_request *request; + + /* Pull the entire chain of completions from the list */ + spin_lock_irqsave(&device->compl_qlock, flags); + request = device->compl_qhead; + device->compl_qhead = NULL; + device->compl_qtail = NULL; + spin_unlock_irqrestore(&device->compl_qlock, flags); + + while (request) { + int status; + void *context; + + hifdebug("HIF top of loop\n"); + next_comple = (struct bus_request *)request->next; + + status = request->status; + context = request->context; + hif_free_bus_request(device, request); + device->cbs_from_hif.rw_completion_hdl(context, status); + + request = next_comple; + } +} + +/* completion_task() - Thread to process request completions + * + * @param: context to the hif device. + * + * Completed asynchronous requests are added to a completion + * queue where they are processed by this task. This serves + * multiple purposes: + * -minimizes processing by the HIFTask, which allows + * that task to keep SDIO busy + * -allows request processing to be parallelized on + * multiprocessor systems + * -provides a suspendable context for use by the + * caller's callback function, though this should + * not be abused since it will cause requests to + * sit on the completion queue (which makes us + * more likely to exhaust free requests). + * + * Return: 0 thread exits + */ +static int completion_task(void *param) +{ + struct hif_device *device; + + device = (struct hif_device *)param; + set_current_state(TASK_INTERRUPTIBLE); + + for (;;) { + hifdebug("HIF top of loop\n"); + wait_event_interruptible(device->completion_wait, + device->completion_work); + if (!device->completion_work) + break; + + if (device->completion_shutdown) + break; + + device->completion_work = 0; + process_completion_list(device); + } + + /* Process any remaining completions. + * This task should not be shut down + * until after all requests are stopped. + */ + process_completion_list(device); + + complete_and_exit(&device->completion_exit, 0); + return 0; +} + +/* hif_request_complete() - Completion processing after a request + * is processed. + * + * @device: device handle. + * @request: SIDO bus access request. + * + * All completed requests are queued onto a completion list + * which is processed by complete_task. + * + * Return: None. + */ +static inline void hif_request_complete(struct hif_device *device, + struct bus_request *request) +{ + add_to_completion_list(device, request); + device->completion_work = 1; + wake_up(&device->completion_wait); +} + +/* hif_stop_completion_thread() - Destroy the completion task + * @device: device handle. + * + * This function will destroy the completion thread. + * + * Return: None. + */ +static inline void hif_stop_completion_thread(struct hif_device *device) +{ + if (device->completion_task) { + init_completion(&device->completion_exit); + device->completion_shutdown = 1; + + device->completion_work = 1; + wake_up(&device->completion_wait); + wait_for_completion(&device->completion_exit); + device->completion_task = NULL; + } +} + +/* This task tries to keep the SDIO bus as busy as it + * can. It pulls both requests off the request queue and + * it uses the underlying sdio API to make them happen. + * + * Requests may be one of + * synchronous (a thread is suspended until it completes) + * asynchronous (a completion callback will be invoked) + * and one of + * reads (from Target SDIO space into Host RAM) + * writes (from Host RAM into Target SDIO space) + * and it is to one of + * Target's mailbox space + * Target's register space + * and lots of other choices. + */ +static int hif_task(void *param) +{ + struct hif_device *device; + struct bus_request *request; + int status; + unsigned long flags; + + set_user_nice(current, -3); + device = (struct hif_device *)param; + set_current_state(TASK_INTERRUPTIBLE); + + for (;;) { + hifdebug("top of loop\n"); + /* wait for work */ + wait_event_interruptible(device->hif_wait, + device->hif_task_work); + if (!device->hif_task_work) + /* interrupted, exit */ + break; + + if (device->hif_shutdown) + break; + + device->hif_task_work = 0; + + /* We want to hold the host over multiple cmds if possible; + * but holding the host blocks card interrupts. + */ + sdio_claim_host(device->func); + + for (;;) { + hifdebug("pull next request\n"); + /* Pull the next request to work on */ + spin_lock_irqsave(&device->req_qlock, flags); + request = device->req_qhead; + if (!request) { + spin_unlock_irqrestore(&device->req_qlock, + flags); + break; + } + + /* Remove request from queue */ + device->req_qhead = (struct bus_request *)request->next; + /* Note: No need to clean up req_qtail */ + + spin_unlock_irqrestore(&device->req_qlock, flags); + + /* call __hif_read_write to do the work */ + hifdebug("before HIFRW: address=0x%08x buffer=0x%pK\n", + request->address, request->buffer); + hifdebug("before HIFRW: length=%d req_type=0x%08x\n", + request->length, request->req_type); + + if (request->req_type & HIF_WRITE) { + int i; + int dbgcount; + + if (request->length <= 16) + dbgcount = request->length; + else + dbgcount = 16; + + for (i = 0; i < dbgcount; i++) + hifdebug("|0x%02x", request->buffer[i]); + hifdebug("\n"); + } + status = __hif_read_write( + device, request->address, request->buffer, + request->length, + request->req_type & ~HIF_SYNCHRONOUS, NULL); + hifdebug("after HIFRW: address=0x%08x buffer=0x%pK\n", + request->address, request->buffer); + hifdebug("after HIFRW: length=%d req_type=0x%08x\n", + request->length, request->req_type); + + if (request->req_type & HIF_READ) { + int i; + int dbgcount; + + if (request->length <= 16) + dbgcount = request->length; + else + dbgcount = 16; + + for (i = 0; i < dbgcount; i++) + hifdebug("|0x%02x", request->buffer[i]); + hifdebug("\n"); + } + + /* When we return, the read/write is done */ + request->status = status; + + if (request->req_type & HIF_ASYNCHRONOUS) + hif_request_complete(device, request); + else + /* notify thread that's waiting on this request + */ + complete(&request->comp_req); + } + sdio_release_host(device->func); + } + + complete_and_exit(&device->hif_exit, 0); + return 0; +} + +int hif_configure_device(void *hif_device, + enum hif_device_config_opcode opcode, + void *config, u32 config_len) +{ + int status = HIF_OK; + struct hif_device *device = (struct hif_device *)hif_device; + + switch (opcode) { + case HIF_DEVICE_GET_MBOX_BLOCK_SIZE: + ((u32 *)config)[0] = HIF_MBOX0_BLOCK_SIZE; + ((u32 *)config)[1] = HIF_MBOX1_BLOCK_SIZE; + ((u32 *)config)[2] = HIF_MBOX2_BLOCK_SIZE; + ((u32 *)config)[3] = HIF_MBOX3_BLOCK_SIZE; + break; + + case HIF_DEVICE_SET_CONTEXT: + device->context = config; + break; + + case HIF_DEVICE_GET_CONTEXT: + if (!config) + return HIF_ERROR; + *(void **)config = device->context; + break; + + default: + status = HIF_ERROR; + } + + return status; +} + +void hif_shutdown_device(void *device) +{ + if (!device) { + int i; + /* since we are unloading the driver, reset all cards + * in case the SDIO card is externally powered and we + * are unloading the SDIO stack. This avoids the problem + * when the SDIO stack is reloaded and attempts are made + * to re-enumerate a card that is already enumerated. + */ + + /* Unregister with bus driver core */ + if (registered) { + registered = 0; + hif_sdio_unregister_driver(); + WARN_ON(1); + return; + } + + for (i = 0; i < MAX_HIF_DEVICES; ++i) { + if (hif_devices[i] && !hif_devices[i]->func) { + del_hif_device(hif_devices[i]); + hif_devices[i] = NULL; + } + } + } +} + +static void hif_irq_handler(struct sdio_func *func) +{ + int status; + struct hif_device *device; + + device = get_hif_device(func); + device->irq_handling = 1; + /* release the host during ints so we can pick it back up when we + * process cmds + */ + sdio_release_host(device->func); + status = device->cbs_from_hif.dsr_hdl(device->cbs_from_hif.context); + sdio_claim_host(device->func); + device->irq_handling = 0; +} + +static void hif_force_driver_strength(struct sdio_func *func) +{ + unsigned int addr = SDIO_CCCR_DRIVE_STRENGTH; + unsigned char value = 0; + + if (func0_CMD52_read_byte(func->card, addr, &value)) + goto cmd_fail; + + value = (value & (~(SDIO_DRIVE_DTSx_MASK << SDIO_DRIVE_DTSx_SHIFT))) | + SDIO_DTSx_SET_TYPE_D; + if (func0_CMD52_write_byte(func->card, addr, value)) + goto cmd_fail; + + addr = CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR; + value = 0; + if (func0_CMD52_read_byte(func->card, addr, &value)) + goto cmd_fail; + + value = (value & (~CCCR_SDIO_DRIVER_STRENGTH_ENABLE_MASK)) | + CCCR_SDIO_DRIVER_STRENGTH_ENABLE_A | + CCCR_SDIO_DRIVER_STRENGTH_ENABLE_C | + CCCR_SDIO_DRIVER_STRENGTH_ENABLE_D; + if (func0_CMD52_write_byte(func->card, addr, value)) + goto cmd_fail; + return; +cmd_fail: + hifdebug("set fail\n"); +} + +static int hif_set_mmc_buswidth(struct sdio_func *func, + struct hif_device *device) +{ + int ret = -1; + + if (hif_mmcbuswidth == 1) { + ret = func0_CMD52_write_byte(func->card, SDIO_CCCR_IF, + SDIO_BUS_CD_DISABLE | + SDIO_BUS_WIDTH_1BIT); + if (ret) + return ret; + device->host->ios.bus_width = MMC_BUS_WIDTH_1; + device->host->ops->set_ios(device->host, &device->host->ios); + } else if (hif_mmcbuswidth == 4 && + (device->host->caps & MMC_CAP_4_BIT_DATA)) { + ret = func0_CMD52_write_byte(func->card, SDIO_CCCR_IF, + SDIO_BUS_CD_DISABLE | + SDIO_BUS_WIDTH_4BIT); + if (ret) + return ret; + device->host->ios.bus_width = MMC_BUS_WIDTH_4; + device->host->ops->set_ios(device->host, &device->host->ios); + } +#ifdef SDIO_BUS_WIDTH_8BIT + else if (hif_mmcbuswidth == 8 && + (device->host->caps & MMC_CAP_8_BIT_DATA)) { + ret = func0_CMD52_write_byte(func->card, SDIO_CCCR_IF, + SDIO_BUS_CD_DISABLE | + SDIO_BUS_WIDTH_8BIT); + if (ret) + return ret; + device->host->ios.bus_width = MMC_BUS_WIDTH_8; + device->host->ops->set_ios(device->host, &device->host->ios); + } +#endif /* SDIO_BUS_WIDTH_8BIT */ + return ret; +} + +static int hif_device_inserted(struct sdio_func *func, + const struct sdio_device_id *id) +{ + int i; + int ret = -1; + struct hif_device *device = NULL; + int count; + + hifdebug("Enter\n"); + + /* dma_mask should be populated here. + * Use the parent device's setting. + */ + func->dev.dma_mask = mmc_dev(func->card->host)->dma_mask; + + if (!add_hif_device(func)) + return ret; + device = get_hif_device(func); + + for (i = 0; i < MAX_HIF_DEVICES; ++i) { + if (!hif_devices[i]) { + hif_devices[i] = device; + break; + } + } + if (WARN_ON(i >= MAX_HIF_DEVICES)) + return ret; + + device->id = id; + device->host = func->card->host; + device->is_enabled = false; + + { + u32 clock, clock_set = SDIO_CLOCK_FREQUENCY_DEFAULT; + + sdio_claim_host(func); + + /* force driver strength to type D */ + if (hif_forcedriverstrength == 1) + hif_force_driver_strength(func); + + if (hif_writecccr1) + (void)func0_CMD52_write_byte(func->card, hif_writecccr1, + hif_writecccr1value); + if (hif_writecccr2) + (void)func0_CMD52_write_byte(func->card, hif_writecccr2, + hif_writecccr2value); + if (hif_writecccr3) + (void)func0_CMD52_write_byte(func->card, hif_writecccr3, + hif_writecccr3value); + if (hif_writecccr4) + (void)func0_CMD52_write_byte(func->card, hif_writecccr4, + hif_writecccr4value); + /* Set MMC Clock */ + if (hif_mmcclock > 0) + clock_set = hif_mmcclock; + if (mmc_card_hs(func->card)) + clock = 50000000; + else + clock = func->card->cis.max_dtr; + if (clock > device->host->f_max) + clock = device->host->f_max; + hifdebug("clock is %d", clock); + + /* only when hif_mmcclock module parameter is specified, + * set the clock explicitly + */ + if (hif_mmcclock > 0) { + device->host->ios.clock = clock_set; + device->host->ops->set_ios(device->host, + &device->host->ios); + } + /* Set MMC Bus Width: 1-1Bit, 4-4Bit, 8-8Bit */ + if (hif_mmcbuswidth > 0) + ret = hif_set_mmc_buswidth(func, device); + + sdio_release_host(func); + } + + spin_lock_init(&device->req_free_qlock); + spin_lock_init(&device->req_qlock); + + /* Initialize the bus requests to be used later */ + memset(device->bus_request, 0, sizeof(device->bus_request)); + for (count = 0; count < BUS_REQUEST_MAX_NUM; count++) { + init_completion(&device->bus_request[count].comp_req); + hif_free_bus_request(device, &device->bus_request[count]); + } + init_waitqueue_head(&device->hif_wait); + spin_lock_init(&device->compl_qlock); + init_waitqueue_head(&device->completion_wait); + + ret = hif_enable_func(device, func); + if ((ret == HIF_OK) || (ret == HIF_PENDING)) { + hifdebug("Function is ENABLED"); + return 0; + } + + for (i = 0; i < MAX_HIF_DEVICES; i++) { + if (hif_devices[i] == device) { + hif_devices[i] = NULL; + break; + } + } + sdio_set_drvdata(func, NULL); + del_hif_device(device); + return ret; +} + +void hif_un_mask_interrupt(void *hif_device) +{ + struct hif_device *device = (struct hif_device *)hif_device; + + if (!device || !device->func) + return; + + /* Unmask our function IRQ */ + sdio_claim_host(device->func); + device->func->card->host->ops->enable_sdio_irq(device->func->card->host, + 1); + device->is_intr_enb = true; + sdio_release_host(device->func); +} + +void hif_mask_interrupt(void *hif_device) +{ + struct hif_device *device = (struct hif_device *)hif_device; + + if (!device || !device->func) + return; + + /* Mask our function IRQ */ + sdio_claim_host(device->func); + device->func->card->host->ops->enable_sdio_irq(device->func->card->host, + 0); + device->is_intr_enb = false; + sdio_release_host(device->func); +} + +static struct bus_request *hif_allocate_bus_request(void *hif_device) +{ + struct bus_request *busrequest; + unsigned long flag; + struct hif_device *device = (struct hif_device *)hif_device; + + spin_lock_irqsave(&device->req_free_qlock, flag); + /* Remove first in list */ + busrequest = device->bus_req_free_qhead; + if (busrequest) + device->bus_req_free_qhead = + (struct bus_request *)busrequest->next; + spin_unlock_irqrestore(&device->req_free_qlock, flag); + + return busrequest; +} + +static void hif_free_bus_request(struct hif_device *device, + struct bus_request *busrequest) +{ + unsigned long flag; + + if (!busrequest) + return; + + busrequest->next = NULL; + + /* Insert first in list */ + spin_lock_irqsave(&device->req_free_qlock, flag); + busrequest->next = (struct bus_request *)device->bus_req_free_qhead; + device->bus_req_free_qhead = busrequest; + spin_unlock_irqrestore(&device->req_free_qlock, flag); +} + +static int hif_disable_func(struct hif_device *device, struct sdio_func *func) +{ + int ret; + int status = HIF_OK; + + device = get_hif_device(func); + + hif_stop_completion_thread(device); + hif_stop_hif_task(device); + + /* Disable the card */ + sdio_claim_host(device->func); + ret = sdio_disable_func(device->func); + if (ret) + status = HIF_ERROR; + + if (hif_reset_sdio_on_unload && (status == HIF_OK)) { + /* Reset the SDIO interface. This is useful in + * automated testing where the card does not need + * to be removed at the end of the test. It is + * expected that the user will also unload/reload + * the host controller driver to force the bus driver + * to re-enumerate the slot. + */ + + /* NOTE : sdio_f0_writeb() cannot be used here, that API only + * allows access to undefined registers in the range of: + * 0xF0-0xFF + */ + + ret = func0_CMD52_write_byte(device->func->card, + SDIO_CCCR_ABORT, (1 << 3)); + if (ret) + status = HIF_ERROR; + } + + sdio_release_host(device->func); + + if (status == HIF_OK) + device->is_enabled = false; + return status; +} + +static int hif_enable_func(struct hif_device *device, struct sdio_func *func) +{ + int ret = HIF_OK; + + device = get_hif_device(func); + + if (!device) + return HIF_EINVAL; + + if (!device->is_enabled) { + /* enable the SDIO function */ + sdio_claim_host(func); + + /* give us some time to enable, in ms */ + func->enable_timeout = ENABLE_SDIO_TIMEOUT; + ret = sdio_enable_func(func); + if (ret) { + sdio_release_host(func); + return HIF_ERROR; + } + ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE); + + sdio_release_host(func); + if (ret) + return HIF_ERROR; + device->is_enabled = true; + + if (!device->completion_task) { + device->compl_qhead = NULL; + device->compl_qtail = NULL; + device->completion_shutdown = 0; + device->completion_task = kthread_create( + completion_task, (void *)device, "HIFCompl"); + if (IS_ERR(device->completion_task)) { + device->completion_shutdown = 1; + return HIF_ERROR; + } + wake_up_process(device->completion_task); + } + + /* create HIF I/O thread */ + if (!device->hif_task) { + device->hif_shutdown = 0; + device->hif_task = + kthread_create(hif_task, (void *)device, "HIF"); + if (IS_ERR(device->hif_task)) { + device->hif_shutdown = 1; + return HIF_ERROR; + } + wake_up_process(device->hif_task); + } + } + + if (!device->claimed_context) { + ret = hif_callbacks.dev_inserted_hdl(hif_callbacks.context, + device); + if (ret != HIF_OK) { + /* Disable the SDIO func & Reset the sdio + * for automated tests to move ahead, where + * the card does not need to be removed at + * the end of the test. + */ + hif_disable_func(device, func); + } + (void)sdio_claim_irq(func, hif_irq_handler); + } + + return ret; +} + +static void hif_device_removed(struct sdio_func *func) +{ + int i; + int status = HIF_OK; + struct hif_device *device; + + device = get_hif_device(func); + if (!device) + return; + + for (i = 0; i < MAX_HIF_DEVICES; ++i) { + if (hif_devices[i] == device) + hif_devices[i] = NULL; + } + + if (device->claimed_context) { + status = hif_callbacks.dev_removed_hdl( + device->claimed_context, device); + } + + /* TBD: Release IRQ (opposite of sdio_claim_irq) */ + hif_mask_interrupt(device); + + if (device->is_enabled) + status = hif_disable_func(device, func); + + del_hif_device(device); +} + +static void *add_hif_device(struct sdio_func *func) +{ + struct hif_device *hifdevice = NULL; + + if (!func) + return NULL; + + hifdevice = kmalloc(sizeof(*hifdevice), GFP_KERNEL); + if (!hifdevice) + return NULL; + + memset(hifdevice, 0, sizeof(*hifdevice)); + hifdevice->func = func; + sdio_set_drvdata(func, hifdevice); + + return (void *)hifdevice; +} + +static struct hif_device *get_hif_device(struct sdio_func *func) +{ + return (struct hif_device *)sdio_get_drvdata(func); +} + +static void del_hif_device(struct hif_device *device) +{ + if (!device) + return; + kfree(device); +} + +void hif_claim_device(void *hif_device, void *context) +{ + struct hif_device *device = (struct hif_device *)hif_device; + + device->claimed_context = context; +} + +void hif_release_device(void *hif_device) +{ + struct hif_device *device = (struct hif_device *)hif_device; + + device->claimed_context = NULL; +} + +int hif_attach(void *hif_device, struct cbs_from_hif *callbacks) +{ + struct hif_device *device = (struct hif_device *)hif_device; + + if (device->cbs_from_hif.context) { + /* already in use! */ + return HIF_ERROR; + } + device->cbs_from_hif = *callbacks; + return HIF_OK; +} + +static void hif_stop_hif_task(struct hif_device *device) +{ + if (device->hif_task) { + init_completion(&device->hif_exit); + device->hif_shutdown = 1; + device->hif_task_work = 1; + wake_up(&device->hif_wait); + wait_for_completion(&device->hif_exit); + device->hif_task = NULL; + } +} + +/* hif_reset_target() - Reset target device + * @struct hif_device: pointer to struct hif_device structure + * + * Reset the target by invoking power off and power on + * sequence to bring back target into active state. + * This API shall be called only when driver load/unload + * is in progress. + * + * Return: 0 on success, error for failure case. + */ +static int hif_reset_target(struct hif_device *hif_device) +{ + int ret; + + if (!hif_device || !hif_device->func || !hif_device->func->card) + return -ENODEV; + /* Disable sdio func->pull down WLAN_EN-->pull down DAT_2 line */ + ret = mmc_power_save_host(hif_device->func->card->host); + if (ret) + goto done; + + /* pull up DAT_2 line->pull up WLAN_EN-->Enable sdio func */ + ret = mmc_power_restore_host(hif_device->func->card->host); + +done: + return ret; +} + +void hif_detach(void *hif_device) +{ + struct hif_device *device = (struct hif_device *)hif_device; + + hif_stop_hif_task(device); + if (device->ctrl_response_timeout) { + /* Reset the target by invoking power off and power on sequence + * to the card to bring back into active state. + */ + if (hif_reset_target(device)) + panic("BUG"); + device->ctrl_response_timeout = false; + } + + memset(&device->cbs_from_hif, 0, sizeof(device->cbs_from_hif)); +} + +#define SDIO_SET_CMD52_ARG(arg, rw, func, raw, address, writedata) \ + ((arg) = ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | \ + (((raw) & 1) << 27) | (1 << 26) | \ + (((address) & 0x1FFFF) << 9) | (1 << 8) | \ + ((writedata) & 0xFF))) + +#define SDIO_SET_CMD52_READ_ARG(arg, func, address) \ + SDIO_SET_CMD52_ARG(arg, 0, (func), 0, address, 0x00) +#define SDIO_SET_CMD52_WRITE_ARG(arg, func, address, value) \ + SDIO_SET_CMD52_ARG(arg, 1, (func), 0, address, value) + +static int func0_CMD52_write_byte(struct mmc_card *card, unsigned int address, + unsigned char byte) +{ + struct mmc_command ioCmd; + unsigned long arg; + int status; + + memset(&ioCmd, 0, sizeof(ioCmd)); + SDIO_SET_CMD52_WRITE_ARG(arg, 0, address, byte); + ioCmd.opcode = SD_IO_RW_DIRECT; + ioCmd.arg = arg; + ioCmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + status = mmc_wait_for_cmd(card->host, &ioCmd, 0); + + return status; +} + +static int func0_CMD52_read_byte(struct mmc_card *card, unsigned int address, + unsigned char *byte) +{ + struct mmc_command ioCmd; + unsigned long arg; + s32 err; + + memset(&ioCmd, 0, sizeof(ioCmd)); + SDIO_SET_CMD52_READ_ARG(arg, 0, address); + ioCmd.opcode = SD_IO_RW_DIRECT; + ioCmd.arg = arg; + ioCmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(card->host, &ioCmd, 0); + + if ((!err) && (byte)) + *byte = ioCmd.resp[0] & 0xFF; + + return err; +} + +void hif_set_handle(void *hif_handle, void *handle) +{ + struct hif_device *device = (struct hif_device *)hif_handle; + + device->caller_handle = handle; +} + +size_t hif_get_device_size(void) +{ + return sizeof(struct hif_device); +} diff --git a/drivers/net/wireless/qca402x/hif_sdio/hif.h b/drivers/net/wireless/qca402x/hif_sdio/hif.h new file mode 100644 index 000000000000..924d2e4f020b --- /dev/null +++ b/drivers/net/wireless/qca402x/hif_sdio/hif.h @@ -0,0 +1,335 @@ +/* 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. + */ + +/* This file was originally distributed by Qualcomm Atheros, Inc. + * before Copyright ownership was assigned to the Linux Foundation. + */ + +#ifndef _HIF_H_ +#define _HIF_H_ + +#define DEBUG +#undef DEBUG + +#define HIF_OK 0 +#define HIF_PENDING 1 +#define HIF_ERROR 2 +#define HIF_EINVAL 3 + +/* direction - Direction of transfer (HIF_READ/HIF_WRITE). */ +#define HIF_READ 0x00000001 +#define HIF_WRITE 0x00000002 +#define HIF_DIR_MASK (HIF_READ | HIF_WRITE) + +/* type - An interface may support different kind of read/write commands. + * For example: SDIO supports CMD52/CMD53s. In case of MSIO it + * translates to using different kinds of TPCs. The command type + * is thus divided into a basic and an extended command and can + * be specified using HIF_BASIC_IO/HIF_EXTENDED_IO. + */ +#define HIF_BASIC_IO 0x00000004 +#define HIF_EXTENDED_IO 0x00000008 +#define HIF_TYPE_MASK (HIF_BASIC_IO | HIF_EXTENDED_IO) + +/* emode - This indicates the whether the command is to be executed in a + * blocking or non-blocking fashion (HIF_SYNCHRONOUS/ + * HIF_ASYNCHRONOUS). The read/write data paths in HTCA have been + * implemented using the asynchronous mode allowing the the bus + * driver to indicate the completion of operation through the + * registered callback routine. The requirement primarily comes + * from the contexts these operations get called from (a driver's + * transmit context or the ISR context in case of receive). + * Support for both of these modes is essential. + */ +#define HIF_SYNCHRONOUS 0x00000010 +#define HIF_ASYNCHRONOUS 0x00000020 +#define HIF_EMODE_MASK (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS) + +/* dmode - An interface may support different kinds of commands based on + * the tradeoff between the amount of data it can carry and the + * setup time. Byte and Block modes are supported (HIF_BYTE_BASIS/ + * HIF_BLOCK_BASIS). In case of latter, the data is rounded off + * to the nearest block size by padding. The size of the block is + * configurable at compile time using the HIF_BLOCK_SIZE and is + * negotiated with the target during initialization after the + * AR6000 interrupts are enabled. + */ +#define HIF_BYTE_BASIS 0x00000040 +#define HIF_BLOCK_BASIS 0x00000080 +#define HIF_DMODE_MASK (HIF_BYTE_BASIS | HIF_BLOCK_BASIS) + +/* amode - This indicates if the address has to be incremented on AR6000 + * after every read/write operation (HIF?FIXED_ADDRESS/ + * HIF_INCREMENTAL_ADDRESS). + */ +#define HIF_FIXED_ADDRESS 0x00000100 +#define HIF_INCREMENTAL_ADDRESS 0x00000200 +#define HIF_AMODE_MASK (HIF_FIXED_ADDRESS | HIF_INCREMENTAL_ADDRESS) + +#define HIF_WR_ASYNC_BYTE_FIX \ + (HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | \ + HIF_FIXED_ADDRESS) +#define HIF_WR_ASYNC_BYTE_INC \ + (HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | \ + HIF_INCREMENTAL_ADDRESS) +#define HIF_WR_ASYNC_BLOCK_INC \ + (HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | \ + HIF_INCREMENTAL_ADDRESS) +#define HIF_WR_SYNC_BYTE_FIX \ + (HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | \ + HIF_FIXED_ADDRESS) +#define HIF_WR_SYNC_BYTE_INC \ + (HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | \ + HIF_INCREMENTAL_ADDRESS) +#define HIF_WR_SYNC_BLOCK_INC \ + (HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | \ + HIF_INCREMENTAL_ADDRESS) +#define HIF_WR_ASYNC_BLOCK_FIX \ + (HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | \ + HIF_FIXED_ADDRESS) +#define HIF_WR_SYNC_BLOCK_FIX \ + (HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | \ + HIF_FIXED_ADDRESS) +#define HIF_RD_SYNC_BYTE_INC \ + (HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | \ + HIF_INCREMENTAL_ADDRESS) +#define HIF_RD_SYNC_BYTE_FIX \ + (HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | \ + HIF_FIXED_ADDRESS) +#define HIF_RD_ASYNC_BYTE_FIX \ + (HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | \ + HIF_FIXED_ADDRESS) +#define HIF_RD_ASYNC_BLOCK_FIX \ + (HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | \ + HIF_FIXED_ADDRESS) +#define HIF_RD_ASYNC_BYTE_INC \ + (HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | \ + HIF_INCREMENTAL_ADDRESS) +#define HIF_RD_ASYNC_BLOCK_INC \ + (HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | \ + HIF_INCREMENTAL_ADDRESS) +#define HIF_RD_SYNC_BLOCK_INC \ + (HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | \ + HIF_INCREMENTAL_ADDRESS) +#define HIF_RD_SYNC_BLOCK_FIX \ + (HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | \ + HIF_FIXED_ADDRESS) + +enum hif_device_config_opcode { + HIF_DEVICE_GET_MBOX_BLOCK_SIZE, + HIF_DEVICE_SET_CONTEXT, + HIF_DEVICE_GET_CONTEXT, +}; + +/* HIF CONFIGURE definitions: + * + * HIF_DEVICE_GET_MBOX_BLOCK_SIZE + * input : none + * output : array of 4 u32s + * notes: block size is returned for each mailbox (4) + * + * HIF_DEVICE_SET_CONTEXT + * input : arbitrary pointer-sized value + * output: none + * notes: stores an arbitrary value which can be retrieved later + * + * HIF_DEVICE_GET_CONTEXT + * input: none + * output : arbitrary pointer-sized value + * notes: retrieves an arbitrary value which was set earlier + */ +struct cbs_from_hif { + void *context; /* context to pass to the dsrhandler + * note : rw_completion_hdl is provided the context + * passed to hif_read_write + */ + int (*rw_completion_hdl)(void *rw_context, int status); + int (*dsr_hdl)(void *context); +}; + +struct cbs_from_os { + void *context; /* context to pass for all callbacks except + * dev_removed_hdl the dev_removed_hdl is only called if + * the device is claimed + */ + int (*dev_inserted_hdl)(void *context, void *hif_handle); + int (*dev_removed_hdl)(void *claimed_context, void *hif_handle); + int (*dev_suspend_hdl)(void *context); + int (*dev_resume_hdl)(void *context); + int (*dev_wakeup_hdl)(void *context); +#if defined(DEVICE_POWER_CHANGE) + int (*dev_pwr_change_hdl)(void *context, + HIF_DEVICE_POWER_CHANGE_TYPE config); +#endif /* DEVICE_POWER_CHANGE */ +}; + +/* other interrupts (non-Recv) are pending, host + * needs to read the register table to figure out what + */ +#define HIF_OTHER_EVENTS BIT(0) + +#define HIF_RECV_MSG_AVAIL BIT(1) /* pending recv packet */ + +struct hif_pending_events_info { + u32 events; + u32 look_ahead; + u32 available_recv_bytes; +}; + +/* function to get pending events , some HIF modules use special mechanisms + * to detect packet available and other interrupts + */ +typedef int (*HIF_PENDING_EVENTS_FUNC)(void *device, + struct hif_pending_events_info *p_events, + void *async_context); + +#define HIF_MASK_RECV TRUE +#define HIF_UNMASK_RECV FALSE +/* function to mask recv events */ +typedef int (*HIF_MASK_UNMASK_RECV_EVENT)(void *device, bool mask, + void *async_context); + +#ifdef HIF_MBOX_SLEEP_WAR +/* This API is used to update the target sleep state */ +void hif_set_mbox_sleep(void *device, bool sleep, bool wait, + bool cache); +#endif +/* This API is used to perform any global initialization of the HIF layer + * and to set OS driver callbacks (i.e. insertion/removal) to the HIF layer + */ +int hif_init(struct cbs_from_os *callbacks); + +/* This API claims the HIF device and provides a context for handling removal. + * The device removal callback is only called when the OS claims + * a device. The claimed context must be non-NULL + */ +void hif_claim_device(void *device, void *claimed_context); + +/* release the claimed device */ +void hif_release_device(void *device); + +/* This API allows the calling layer to attach callbacks from HIF */ +int hif_attach(void *device, struct cbs_from_hif *callbacks); + +/* This API allows the calling layer to detach callbacks from HIF */ +void hif_detach(void *device); + +void hif_set_handle(void *hif_handle, void *handle); + +int hif_sync_read(void *device, u32 address, u8 *buffer, + u32 length, u32 request, void *context); + +size_t hif_get_device_size(void); + +/* This API is used to provide the read/write interface over the specific bus + * interface. + * address - Starting address in the AR6000's address space. For mailbox + * writes, it refers to the start of the mbox boundary. It should + * be ensured that the last byte falls on the mailbox's EOM. For + * mailbox reads, it refers to the end of the mbox boundary. + * buffer - Pointer to the buffer containg the data to be transmitted or + * received. + * length - Amount of data to be transmitted or received. + * request - Characterizes the attributes of the command. + */ +int hif_read_write(void *device, u32 address, void *buffer, + u32 length, u32 request, void *context); + +/* This can be initiated from the unload driver context when the OS has no more + * use for + * the device. + */ +void hif_shutdown_device(void *device); +void hif_surprise_removed(void *device); + +void hif_mask_interrupt(void *device); + +void hif_un_mask_interrupt(void *device); + +int hif_configure_device(void *device, + enum hif_device_config_opcode opcode, + void *config, u32 config_len); + +/* This API wait for the remaining MBOX messages to be drained + * This should be moved to HTCA AR6K layer + */ +int hif_wait_for_pending_recv(void *device); + +/* BMI and Diag window abstraction + */ + +#define HIF_BMI_EXCHANGE_NO_TIMEOUT ((u32)(0)) + +#define DIAG_TRANSFER_LIMIT 2048U /* maximum number of bytes that can be handled + * atomically by DiagRead/DiagWrite + */ + +#ifdef FEATURE_RUNTIME_PM +/* Runtime power management API of HIF to control + * runtime pm. During Runtime Suspend the get API + * return -EAGAIN. The caller can queue the cmd or return. + * The put API decrements the usage count. + * The get API increments the usage count. + * The API's are exposed to HTT and WMI Services only. + */ +int hif_pm_runtime_get(void *device); +int hif_pm_runtime_put(void *device); +void *hif_runtime_pm_prevent_suspend_init(const char *name); +void hif_runtime_pm_prevent_suspend_deinit(void *data); +int hif_pm_runtime_prevent_suspend(void *ol_sc, void *data); +int hif_pm_runtime_allow_suspend(void *ol_sc, void *data); +int hif_pm_runtime_prevent_suspend_timeout(void *ol_sc, void *data, + unsigned int delay); +void hif_request_runtime_pm_resume(void *ol_sc); +#else +static inline int hif_pm_runtime_get(void *device) +{ + return 0; +} + +static inline int hif_pm_runtime_put(void *device) +{ + return 0; +} + +static inline int hif_pm_runtime_prevent_suspend(void *ol_sc, void *context) +{ + return 0; +} + +static inline int hif_pm_runtime_allow_suspend(void *ol_sc, void *context) +{ + return 0; +} + +static inline int hif_pm_runtime_prevent_suspend_timeout(void *ol_sc, + void *context, + unsigned int msec) +{ + return 0; +} + +static inline void *hif_runtime_pm_prevent_suspend_init(const char *name) +{ + return NULL; +} + +static inline void hif_runtime_pm_prevent_suspend_deinit(void *context) +{ +} + +static inline void hif_request_runtime_pm_resume(void *ol_sc) +{ +} +#endif + +#endif /* _HIF_H_ */ diff --git a/drivers/net/wireless/qca402x/hif_sdio/hif_internal.h b/drivers/net/wireless/qca402x/hif_sdio/hif_internal.h new file mode 100644 index 000000000000..8b4c11e29024 --- /dev/null +++ b/drivers/net/wireless/qca402x/hif_sdio/hif_internal.h @@ -0,0 +1,117 @@ +/* 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. + */ + +/* This file was originally distributed by Qualcomm Atheros, Inc. + * before Copyright ownership was assigned to the Linux Foundation. + */ + +#ifndef _HIF_INTERNAL_H_ +#define _HIF_INTERNAL_H_ + +#include "hif.h" +#include "hif_sdio_common.h" + +/* Make this large enough to avoid ever failing due to lack of bus requests. + * A number that accounts for the total number of credits on the Target plus + * outstanding register requests is good. + * + * FUTURE: could dyanamically allocate busrequest structs as needed. + * FUTURE: would be nice for HIF to use HTCA's htca_request. Seems + * wasteful to use multiple structures -- one for HTCA and another + * for HIF -- and to copy info from one to the other. Maybe should + * semi-merge these layers? + */ +#define BUS_REQUEST_MAX_NUM 128 + +#define SDIO_CLOCK_FREQUENCY_DEFAULT 25000000 /* TBD: Can support 50000000 + * on real HW? + */ +#define SDWLAN_ENABLE_DISABLE_TIMEOUT 20 +#define FLAGS_CARD_ENAB 0x02 +#define FLAGS_CARD_IRQ_UNMSK 0x04 + +/* The block size is an attribute of the SDIO function which is + * shared by all four mailboxes. We cannot support per-mailbox + * block sizes over SDIO. + */ +#define HIF_MBOX_BLOCK_SIZE HIF_DEFAULT_IO_BLOCK_SIZE +#define HIF_MBOX0_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE +#define HIF_MBOX1_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE +#define HIF_MBOX2_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE +#define HIF_MBOX3_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE + +struct bus_request { + /*struct bus_request*/ void *next; /* link list of available requests */ + struct completion comp_req; + u32 address; /* request data */ + u8 *buffer; + u32 length; + u32 req_type; + void *context; + int status; +}; + +struct hif_device { + struct sdio_func *func; + + /* Main HIF task */ + struct task_struct *hif_task; /* task to handle SDIO requests */ + wait_queue_head_t hif_wait; + int hif_task_work; /* Signals HIFtask that there is work */ + int hif_shutdown; /* signals HIFtask to stop */ + struct completion hif_exit; /* HIFtask completion */ + + /* HIF Completion task */ + /* task to handle SDIO completions */ + struct task_struct *completion_task; + wait_queue_head_t completion_wait; + int completion_work; + int completion_shutdown; + struct completion completion_exit; + + /* pending request queue */ + spinlock_t req_qlock; + struct bus_request *req_qhead; /* head of request queue */ + struct bus_request *req_qtail; /* tail of request queue */ + + /* completed request queue */ + spinlock_t compl_qlock; + struct bus_request *compl_qhead; + struct bus_request *compl_qtail; + + /* request free list */ + spinlock_t req_free_qlock; + struct bus_request *bus_req_free_qhead; /* free queue */ + + /* Space for requests, initially queued to busRequestFreeQueue */ + struct bus_request bus_request[BUS_REQUEST_MAX_NUM]; + + void *claimed_context; + struct cbs_from_hif + cbs_from_hif; /* Callbacks made from HIF to caller */ + bool is_enabled; /* device is currently enabled? */ + bool is_intr_enb; /* interrupts are currently unmasked at + * Host - dbg only + */ + int irq_handling; /* currently processing interrupts */ + const struct sdio_device_id *id; + struct mmc_host *host; + void *context; + bool ctrl_response_timeout; + /* for debug; links hif device back to caller (e.g.HTCA target) */ + void *caller_handle; +}; + +#define CMD53_FIXED_ADDRESS 1 +#define CMD53_INCR_ADDRESS 2 + +#endif /* _HIF_INTERNAL_H_ */ diff --git a/drivers/net/wireless/qca402x/hif_sdio/hif_sdio_common.h b/drivers/net/wireless/qca402x/hif_sdio/hif_sdio_common.h new file mode 100644 index 000000000000..c325c068d11d --- /dev/null +++ b/drivers/net/wireless/qca402x/hif_sdio/hif_sdio_common.h @@ -0,0 +1,43 @@ +/* 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. + */ + +/* This file was originally distributed by Qualcomm Atheros, Inc. + * before Copyright ownership was assigned to the Linux Foundation. + */ + +#ifndef _HIF_SDIO_COMMON_H_ +#define _HIF_SDIO_COMMON_H_ + +/* The purpose of these blocks is to amortize SDIO command setup time + * across multiple bytes of data. In byte mode, we must issue a command + * for each byte. In block mode, we issue a command (8B?) for each + * BLOCK_SIZE bytes. + * + * Every mailbox read/write must be padded to this block size. If the + * value is too large, we spend more time sending padding bytes over + * SDIO. If the value is too small we see less benefit from amortizing + * the cost of a command across data bytes. + */ +#define HIF_DEFAULT_IO_BLOCK_SIZE 256 + +#define FIFO_TIMEOUT_AND_CHIP_CONTROL 0x00000868 +#define FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF 0xFFFEFFFF +#define FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_ON 0x10000 + +/* Vendor Specific Driver Strength Settings */ +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR 0xf2 +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_MASK 0x0e +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_A 0x02 +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_C 0x04 +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_D 0x08 + +#endif /* _HIF_SDIO_COMMON_H_ */ diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca.h b/drivers/net/wireless/qca402x/htca_mbox/htca.h new file mode 100644 index 000000000000..ce2e0eb88898 --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca.h @@ -0,0 +1,132 @@ +/* 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. + */ + +/* Host-Target Communication API */ + +#ifndef _HTCA_H_ +#define _HTCA_H_ + +#define DEBUG +#undef DEBUG + +/* The HTCA API is independent of the underlying interconnect and + * independent of the protocols used across that interconnect. + */ + +#define HTCA_OK 0 /* Success */ +#define HTCA_ERROR 1 /* generic error */ +#define HTCA_EINVAL 2 /* Invalid parameter */ +#define HTCA_ECANCELED 3 /* Operation canceled */ +#define HTCA_EPROTO 4 /* Protocol error */ +#define HTCA_ENOMEM 5 /* Memory exhausted */ + +/* Note: An Endpoint ID is always Interconnect-relative. So we + * are likely to see the same Endpoint ID with different Targets + * on a multi-Target system. + */ +#define HTCA_EP_UNUSED (0xff) + +#define HTCA_EVENT_UNUSED 0 + +/* Start global events */ +#define HTCA_EVENT_GLOBAL_START 1 +#define HTCA_EVENT_TARGET_AVAILABLE 1 +#define HTCA_EVENT_TARGET_UNAVAILABLE 2 +#define HTCA_EVENT_GLOBAL_END 2 +#define HTCA_EVENT_GLOBAL_COUNT \ + (HTCA_EVENT_GLOBAL_END - HTCA_EVENT_GLOBAL_START + 1) +/* End global events */ + +/* Start endpoint-specific events */ +#define HTCA_EVENT_EP_START 3 +#define HTCA_EVENT_BUFFER_RECEIVED 3 +#define HTCA_EVENT_BUFFER_SENT 4 +#define HTCA_EVENT_DATA_AVAILABLE 5 +#define HTCA_EVENT_EP_END 5 +#define HTCA_EVENT_EP_COUNT (HTCA_EVENT_EP_END - HTCA_EVENT_EP_START + 1) +/* End endpoint-specific events */ + +/* Maximum size of an HTC header across relevant implementations + * (e.g. across interconnect types and platforms and OSes of interest). + * + * Callers of HTC must leave HTCA_HEADER_LEN_MAX bytes + * reserved BEFORE the start of a buffer passed to HTCA htca_buffer_send + * AT the start of a buffer passed to HTCBufferReceive + * for use by HTC itself. + * + * FUTURE: Investigate ways to remove the need for callers to accommodate + * for HTC headers.* Doesn't seem that hard to do....just tack on the + * length in a separate buffer and send buffer pairs to HIF. When extracting, + * first pull header then pull payload into paired buffers. + */ + +#define HTCA_HEADER_LEN_MAX 2 + +struct htca_event_info { + u8 *buffer; + void *cookie; + u32 buffer_length; + u32 actual_length; + int status; +}; + +typedef void (*htca_event_handler)(void *target, + u8 ep, + u8 event_id, + struct htca_event_info *event_info, + void *context); + +int htca_init(void); + +void htca_shutdown(void); + +int htca_start(void *target); + +void htca_stop(void *target); + +int htca_event_reg(void *target, + u8 end_point_id, + u8 event_id, + htca_event_handler event_handler, void *context); + +/* Notes: + * buffer should be multiple of blocksize. + * buffer should be large enough for header+largest message, rounded up to + * blocksize. + * buffer passed in should be start of the buffer -- where header will go. + * length should be full length, including header. + * On completion, buffer points to start of payload (AFTER header). + * On completion, actual_length is the length of payload. Does not include + * header nor padding. On completion, buffer_length matches the length that + * was passed in here. + */ +int htca_buffer_receive(void *target, + u8 end_point_id, u8 *buffer, + u32 length, void *cookie); + +/* Notes: + * buffer should be multiple of blocksize. + * buffer passed in should be start of payload; header will be tacked on BEFORE + * this. + * extra bytes will be sent, padding the message to blocksize. + * length should be the number of payload bytes to be sent. + * The actual number of bytes that go over SDIO is length+header, rounded up to + * blocksize. + * On completion, buffer points to start of payload (AFTER header). + * On completion, actual_length is the length of payload. Does not include + * header nor padding. On completion buffer_length is irrelevant. + */ +int htca_buffer_send(void *target, + u8 end_point_id, + u8 *buffer, u32 length, void *cookie); + +#endif /* _HTCA_H_ */ diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca_mbox.c b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox.c new file mode 100644 index 000000000000..fbf3549c06eb --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox.c @@ -0,0 +1,497 @@ +/* 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. + */ + +/* Implementation of Host Target Communication + * API v1 and HTCA Protocol v1 + * over Qualcomm QCA mailbox-based SDIO/SPI interconnects. + */ + +#include +#include +#include +#include +#include + +#include "../hif_sdio/hif.h" +#include "htca.h" +#include "htca_mbox_internal.h" + +struct htca_target *htca_target_list[HTCA_NUM_DEVICES_MAX]; + +/* Single thread module initialization, module shutdown, + * target start and target stop. + */ +static DEFINE_MUTEX(htca_startup_mutex); +static bool htca_initialized; + +/* Initialize the HTCA software module. + * Typically invoked exactly once. + */ +int htca_init(void) +{ + struct cbs_from_os callbacks; + + if (mutex_lock_interruptible(&htca_startup_mutex)) + return HTCA_ERROR; /* interrupted */ + + if (htca_initialized) { + mutex_unlock(&htca_startup_mutex); + return HTCA_OK; /* Already initialized */ + } + + htca_initialized = true; + + htca_event_table_init(); + + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.dev_inserted_hdl = htca_target_inserted_handler; + callbacks.dev_removed_hdl = htca_target_removed_handler; + hif_init(&callbacks); + + mutex_unlock(&htca_startup_mutex); + + return HTCA_OK; +} + +/* Shutdown the entire module and free all module data. + * Inverse of htca_init. + * + * May be invoked only after all Targets are stopped. + */ +void htca_shutdown(void) +{ + int i; + + if (mutex_lock_interruptible(&htca_startup_mutex)) + return; /* interrupted */ + + if (!htca_initialized) { + mutex_unlock(&htca_startup_mutex); + return; /* Not initialized, so nothing to shut down */ + } + + for (i = 0; i < HTCA_NUM_DEVICES_MAX; i++) { + if (htca_target_instance(i)) { + /* One or more Targets are still active -- + * cannot shutdown software. + */ + mutex_unlock(&htca_startup_mutex); + WARN_ON(1); + return; + } + } + + hif_shutdown_device(NULL); /* Tell HIF that we're all done */ + htca_initialized = false; + + mutex_unlock(&htca_startup_mutex); +} + +/* Start a Target. This typically happens once per Target after + * the module has been initialized and a Target is powered on. + * + * When a Target starts, it posts a single credit to each mailbox + * and it enters "HTCA configuration". During configuration + * negotiation, block sizes for each HTCA endpoint are established + * that both Host and Target agree. Once this is complete, the + * Target starts normal operation so it can send/receive. + */ +int htca_start(void *tar) +{ + int status; + u32 address; + struct htca_target *target = (struct htca_target *)tar; + + mutex_lock(&htca_startup_mutex); + + if (!htca_initialized) { + mutex_unlock(&htca_startup_mutex); + return HTCA_ERROR; + } + + init_waitqueue_head(&target->target_init_wait); + + /* Unmask Host controller interrupts associated with this Target */ + hif_un_mask_interrupt(target->hif_handle); + + /* Enable all interrupts of interest on the Target. */ + + target->enb.int_status_enb = INT_STATUS_ENABLE_ERROR_SET(0x01) | + INT_STATUS_ENABLE_CPU_SET(0x01) | + INT_STATUS_ENABLE_COUNTER_SET(0x01) | + INT_STATUS_ENABLE_MBOX_DATA_SET(0x0F); + + target->enb.cpu_int_status_enb = CPU_INT_STATUS_ENABLE_BIT_SET(0x00); + + target->enb.err_status_enb = + ERROR_STATUS_ENABLE_RX_UNDERFLOW_SET(0x01) | + ERROR_STATUS_ENABLE_TX_OVERFLOW_SET(0x01); + + target->enb.counter_int_status_enb = + COUNTER_INT_STATUS_ENABLE_BIT_SET(0xFF); + + /* Commit interrupt register values to Target HW. */ + address = get_reg_addr(INTR_ENB_REG, ENDPOINT_UNUSED); + status = + hif_read_write(target->hif_handle, address, &target->enb, + sizeof(target->enb), HIF_WR_SYNC_BYTE_INC, NULL); + if (status != HIF_OK) { + _htca_stop(target); + mutex_unlock(&htca_startup_mutex); + return HTCA_ERROR; + } + + /* At this point, we're waiting for the Target to post + * 1 credit to each mailbox. This allows us to begin + * configuration negotiation. We should see an interrupt + * as soon as the first credit is posted. The remaining + * credits should be posted almost immediately after. + */ + + /* Wait indefinitely until configuration negotiation with + * the Target completes and the Target tells us it is ready to go. + */ + if (!target->ready) { + /* NB: Retain the htca_statup_mutex during this wait. + * This serializes startup but should be OK. + */ + + wait_event_interruptible(target->target_init_wait, + target->ready); + + if (target->ready) { + status = HTCA_OK; + } else { + status = HTCA_ERROR; + _htca_stop(target); + } + } + + mutex_unlock(&htca_startup_mutex); + return status; +} + +void _htca_stop(struct htca_target *target) +{ + uint ep; + struct htca_endpoint *end_point; + u32 address; + + /* Note: htca_startup_mutex must be held on entry */ + if (!htca_initialized) + return; + + htca_work_task_stop(target); + + /* Disable interrupts at source, on Target */ + target->enb.int_status_enb = 0; + target->enb.cpu_int_status_enb = 0; + target->enb.err_status_enb = 0; + target->enb.counter_int_status_enb = 0; + + address = get_reg_addr(INTR_ENB_REG, ENDPOINT_UNUSED); + + /* Try to disable all interrupts on the Target. */ + (void)hif_read_write(target->hif_handle, address, &target->enb, + sizeof(target->enb), HIF_WR_SYNC_BYTE_INC, NULL); + + /* Disable Host controller interrupts */ + hif_mask_interrupt(target->hif_handle); + + /* Flush all the queues and return the buffers to their owner */ + for (ep = 0; ep < HTCA_NUM_MBOX; ep++) { + unsigned long flags; + + end_point = &target->end_point[ep]; + + spin_lock_irqsave(&end_point->tx_credit_lock, flags); + end_point->tx_credits_available = 0; + spin_unlock_irqrestore(&end_point->tx_credit_lock, flags); + + end_point->enabled = false; + + /* Flush the Pending Receive Queue */ + htca_mbox_queue_flush(end_point, &end_point->recv_pending_queue, + &end_point->recv_free_queue, + HTCA_EVENT_BUFFER_RECEIVED); + + /* Flush the Pending Send Queue */ + htca_mbox_queue_flush(end_point, &end_point->send_pending_queue, + &end_point->send_free_queue, + HTCA_EVENT_BUFFER_SENT); + } + + target->ready = false; + + hif_detach(target->hif_handle); + + /* Remove this Target from the global list */ + htca_target_instance_remove(target); + + /* Free target memory */ + kfree(target); +} + +void htca_stop(void *tar) +{ + struct htca_target *target = (struct htca_target *)tar; + + htca_work_task_stop(target); + htca_compl_task_stop(target); + + mutex_lock(&htca_startup_mutex); + _htca_stop(target); + mutex_unlock(&htca_startup_mutex); +} + +/* Provides an interface for the caller to register for + * various events supported by the HTCA module. + */ +int htca_event_reg(void *tar, + u8 end_point_id, + u8 event_id, + htca_event_handler event_handler, void *param) +{ + int status; + struct htca_endpoint *end_point; + struct htca_event_info event_info; + struct htca_target *target = (struct htca_target *)tar; + + /* Register a new handler BEFORE dispatching events. + * UNregister a handler AFTER dispatching events. + */ + if (event_handler) { + /* Register a new event handler */ + + status = htca_add_to_event_table(target, end_point_id, event_id, + event_handler, param); + if (status != HTCA_OK) + return status; /* Fail to register handler */ + } + + /* Handle events associated with this handler */ + switch (event_id) { + case HTCA_EVENT_TARGET_AVAILABLE: + if (event_handler) { + struct htca_target *targ; + int i; + + /* Dispatch a Target Available event for all Targets + * that are already present. + */ + for (i = 0; i < HTCA_NUM_DEVICES_MAX; i++) { + targ = htca_target_list[i]; + if (targ) { + size_t size = hif_get_device_size(); + + htca_frame_event(&event_info, + (u8 *)targ->hif_handle, + size, size, + HTCA_OK, NULL); + + htca_dispatch_event( + targ, ENDPOINT_UNUSED, + HTCA_EVENT_TARGET_AVAILABLE, + &event_info); + } + } + } + break; + + case HTCA_EVENT_TARGET_UNAVAILABLE: + break; + + case HTCA_EVENT_BUFFER_RECEIVED: + if (!event_handler) { + /* Flush the Pending Recv queue before unregistering + * the event handler. + */ + end_point = &target->end_point[end_point_id]; + htca_mbox_queue_flush(end_point, + &end_point->recv_pending_queue, + &end_point->recv_free_queue, + HTCA_EVENT_BUFFER_RECEIVED); + } + break; + + case HTCA_EVENT_BUFFER_SENT: + if (!event_handler) { + /* Flush the Pending Send queue before unregistering + * the event handler. + */ + end_point = &target->end_point[end_point_id]; + htca_mbox_queue_flush(end_point, + &end_point->send_pending_queue, + &end_point->send_free_queue, + HTCA_EVENT_BUFFER_SENT); + } + break; + + case HTCA_EVENT_DATA_AVAILABLE: + /* We could dispatch a data available event. Instead, + * we require users to register this event handler + * before posting receive buffers. + */ + break; + + default: + return HTCA_EINVAL; /* unknown event? */ + } + + if (!event_handler) { + /* Unregister an event handler */ + status = htca_remove_from_event_table(target, + end_point_id, event_id); + if (status != HTCA_OK) + return status; + } + + return HTCA_OK; +} + +/* Enqueue to the endpoint's recv_pending_queue an empty buffer + * which will receive data from the Target. + */ +int htca_buffer_receive(void *tar, + u8 end_point_id, u8 *buffer, + u32 length, void *cookie) +{ + struct htca_endpoint *end_point; + struct htca_mbox_request *mbox_request; + struct htca_event_table_element *ev; + unsigned long flags; + struct htca_target *target = (struct htca_target *)tar; + + end_point = &target->end_point[end_point_id]; + + if (!end_point->enabled) + return HTCA_ERROR; + + /* Length must be a multiple of block_size. + * (Ideally, length should match the largest message that can be sent + * over this endpoint, including HTCA header, rounded up to blocksize.) + */ + if (length % end_point->block_size) + return HTCA_EINVAL; + + if (length > HTCA_MESSAGE_SIZE_MAX) + return HTCA_EINVAL; + + if (length < HTCA_HEADER_LEN_MAX) + return HTCA_EINVAL; + + ev = htca_event_id_to_event(target, end_point_id, + HTCA_EVENT_BUFFER_RECEIVED); + if (!ev->handler) { + /* In order to use this API, caller must + * register an event handler for HTCA_EVENT_BUFFER_RECEIVED. + */ + return HTCA_ERROR; + } + + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + mbox_request = (struct htca_mbox_request *)htca_request_deq_head( + &end_point->recv_free_queue); + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + if (!mbox_request) + return HTCA_ENOMEM; + + if (WARN_ON(mbox_request->req.target != target)) + return HTCA_ERROR; + + mbox_request->buffer = buffer; + /* includes space for HTCA header */ + mbox_request->buffer_length = length; + /* filled in after message is received */ + mbox_request->actual_length = 0; + mbox_request->end_point = end_point; + mbox_request->cookie = cookie; + + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + htca_request_enq_tail(&end_point->recv_pending_queue, + (struct htca_request *)mbox_request); + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + + /* Alert the work_task that there may be work to do */ + htca_work_task_poke(target); + + return HTCA_OK; +} + +/* Enqueue a buffer to be sent to the Target. + * + * Supplied buffer must be preceded by HTCA_HEADER_LEN_MAX bytes for the + * HTCA header (of which HTCA_HEADER_LEN bytes are actually used, and the + * remaining are padding). + * + * Must be followed with sufficient space for block-size padding. + * + * Example: + * To send a 10B message over an endpoint that uses 64B blocks, caller + * specifies length=10. HTCA adds HTCA_HEADER_LEN_MAX bytes just before + * buffer, consisting of HTCA_HEADER_LEN header bytes followed by + * HTCA_HEADER_LEN_MAX-HTCA_HEADER_LEN pad bytes. HTC sends blockSize + * bytes starting at buffer-HTCA_HEADER_LEN_MAX. + */ +int htca_buffer_send(void *tar, + u8 end_point_id, + u8 *buffer, u32 length, void *cookie) +{ + struct htca_endpoint *end_point; + struct htca_mbox_request *mbox_request; + struct htca_event_table_element *ev; + unsigned long flags; + struct htca_target *target = (struct htca_target *)tar; + + end_point = &target->end_point[end_point_id]; + + if (!end_point->enabled) + return HTCA_ERROR; + + if (length + HTCA_HEADER_LEN_MAX > HTCA_MESSAGE_SIZE_MAX) + return HTCA_EINVAL; + + ev = htca_event_id_to_event(target, end_point_id, + HTCA_EVENT_BUFFER_SENT); + if (!ev->handler) { + /* In order to use this API, caller must + * register an event handler for HTCA_EVENT_BUFFER_SENT. + */ + return HTCA_ERROR; + } + + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + mbox_request = (struct htca_mbox_request *)htca_request_deq_head( + &end_point->send_free_queue); + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + if (!mbox_request) + return HTCA_ENOMEM; + + /* Buffer will be adjusted by HTCA_HEADER_LEN later, in + * htca_send_request_to_hif. + */ + mbox_request->buffer = buffer; + mbox_request->buffer_length = length; + mbox_request->actual_length = length; + mbox_request->end_point = end_point; + mbox_request->cookie = cookie; + + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + htca_request_enq_tail(&end_point->send_pending_queue, + (struct htca_request *)mbox_request); + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + + /* Alert the work_task that there may be work to do */ + htca_work_task_poke(target); + + return HTCA_OK; +} diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_compl.c b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_compl.c new file mode 100644 index 000000000000..c7f8e953412c --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_compl.c @@ -0,0 +1,503 @@ +/* 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 +#include +#include +#include +#include + +#include "../hif_sdio/hif.h" +#include "htca.h" +#include "htca_mbox_internal.h" + +/* Host Target Communications Completion Management */ + +/* Top-level callback handler, registered with HIF to be invoked + * whenever a read/write HIF operation completes. Executed in the + * context of an HIF task, so we don't want to take much time + * here. Pass processing to HTCA's compl_task. + * + * Used for both reg_requests and mbox_requests. + */ +int htca_rw_completion_handler(void *context, int status) +{ + struct htca_request *req; + struct htca_target *target; + unsigned long flags; + + req = (struct htca_request *)context; + if (!context) { + /* No completion required for this request. + * (e.g. Fire-and-forget register write.) + */ + return HTCA_OK; + } + + target = req->target; + req->status = status; + + /* Enqueue this completed request on the + * Target completion queue. + */ + spin_lock_irqsave(&target->compl_queue_lock, flags); + htca_request_enq_tail(&target->compl_queue, (struct htca_request *)req); + spin_unlock_irqrestore(&target->compl_queue_lock, flags); + + /* Notify the completion task that it has work */ + htca_compl_task_poke(target); + + return HTCA_OK; +} + +/* Request-specific callback invoked by the HTCA Completion Task + * when a Mbox Send Request completes. Note: Used for Mbox Send + * requests; not used for Reg requests. + * + * Simply dispatch a BUFFER_SENT event to the originator of the request. + */ +void htca_send_compl(struct htca_request *req, int status) +{ + struct htca_target *target; + u8 end_point_id; + struct htca_event_info event_info; + struct htca_endpoint *end_point; + struct htca_mbox_request *mbox_request = + (struct htca_mbox_request *)req; + unsigned long flags; + + end_point = mbox_request->end_point; + target = end_point->target; + end_point_id = get_endpoint_id(end_point); + + /* Strip off the HTCA header that was added earlier */ + mbox_request->buffer += HTCA_HEADER_LEN_MAX; + + /* Prepare event frame to notify caller */ + htca_frame_event(&event_info, mbox_request->buffer, + mbox_request->buffer_length, + mbox_request->actual_length, + (status == HIF_OK) ? HTCA_OK : HTCA_ECANCELED, + mbox_request->cookie); + + /* Recycle the request */ + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + htca_request_enq_tail(&end_point->send_free_queue, + (struct htca_request *)mbox_request); + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + /* Regardless of success/failure, notify caller that HTCA is done + * with his buffer. + */ + htca_dispatch_event(target, end_point_id, HTCA_EVENT_BUFFER_SENT, + &event_info); +} + +/* Request-specific callback invoked by the HTCA Completion Task + * when a Mbox Recv Request completes. Note: Used for Mbox Recv + * requests; not used for Reg requests. + * + * Simply dispatch a BUFFER_RECEIVED event to the originator + * of the request. + */ +void htca_recv_compl(struct htca_request *req, int status) +{ + struct htca_target *target; + struct htca_event_info event_info; + u8 end_point_id; + struct htca_endpoint *end_point; + struct htca_mbox_request *mbox_request = + (struct htca_mbox_request *)req; + unsigned long flags; + + end_point = mbox_request->end_point; + target = end_point->target; + end_point_id = get_endpoint_id(end_point); + + /* Signaling: + * Now that we have consumed recv data, clar rx_frame_length so that + * htca_manage_pending_recvs will not try to re-read the same data. + * + * Set need_register_refresh so we can determine whether or not there + * is additional data waiting to be read. + * + * Clear our endpoint from the pending_recv_mask so + * htca_manage_pending_recvs + * is free to issue another read. + * + * Finally, poke the work_task. + */ + end_point->rx_frame_length = 0; + target->need_register_refresh = 1; + spin_lock_irqsave(&target->pending_op_lock, flags); + target->pending_recv_mask &= ~(1 << end_point_id); + spin_unlock_irqrestore(&target->pending_op_lock, flags); + htca_work_task_poke(target); + + if (status == HIF_OK) { + u32 check_length; + /* Length coming from Target is always LittleEndian */ + check_length = ((mbox_request->buffer[0] << 0) | + (mbox_request->buffer[1] << 8)); + WARN_ON(mbox_request->actual_length != check_length); + } + + /* Strip off header */ + mbox_request->buffer += HTCA_HEADER_LEN_MAX; + + htca_frame_event(&event_info, mbox_request->buffer, + mbox_request->buffer_length, + mbox_request->actual_length, + (status == HIF_OK) ? HTCA_OK : HTCA_ECANCELED, + mbox_request->cookie); + + /* Recycle the request */ + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + htca_request_enq_tail(&end_point->recv_free_queue, + (struct htca_request *)mbox_request); + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + + htca_dispatch_event(target, end_point_id, HTCA_EVENT_BUFFER_RECEIVED, + &event_info); +} + +/* Request-specific callback invoked when a register read/write + * request completes. reg_request structures are not used for + * register WRITE requests so there's not much to do for writes. + * + * Note: For Mbox Request completions see htca_send_compl + * and htca_recv_compl. + */ + +/* Request-specific callback invoked by the HTCA Completion Task + * when a Reg Request completes. Note: Used for Reg requests; + * not used for Mbox requests. + */ +void htca_reg_compl(struct htca_request *req, int status) +{ + struct htca_target *target; + struct htca_reg_request *reg_request = (struct htca_reg_request *)req; + unsigned long flags; + + if (WARN_ON(!reg_request)) + return; + + htcadebug("purpose=0x%x\n", reg_request->purpose); + + /* Process async register read/write completion */ + + target = reg_request->req.target; + if (status != HIF_OK) { + /* Recycle the request */ + reg_request->purpose = UNUSED_PURPOSE; + spin_lock_irqsave(&target->reg_queue_lock, flags); + htca_request_enq_tail(&target->reg_free_queue, + (struct htca_request *)reg_request); + spin_unlock_irqrestore(&target->reg_queue_lock, flags); + + /* A register read/write accepted by HIF + * should never fail. + */ + WARN_ON(1); + return; + } + + switch (reg_request->purpose) { + case INTR_REFRESH: + /* Target register state, including interrupt + * registers, has been fetched. + */ + htca_register_refresh_compl(target, reg_request); + break; + + case CREDIT_REFRESH: + htca_credit_refresh_compl(target, reg_request); + break; + + case UPDATE_TARG_INTRS: + case UPDATE_TARG_AND_ENABLE_HOST_INTRS: + htca_update_intr_enbs_compl(target, reg_request); + break; + + default: + WARN_ON(1); /* unhandled request type */ + break; + } + + /* Recycle this register read/write request */ + reg_request->purpose = UNUSED_PURPOSE; + spin_lock_irqsave(&target->reg_queue_lock, flags); + htca_request_enq_tail(&target->reg_free_queue, + (struct htca_request *)reg_request); + spin_unlock_irqrestore(&target->reg_queue_lock, flags); +} + +/* After a Register Refresh, uppdate tx_credits_to_reap for each end_point. */ +static void htca_update_tx_credits_to_reap(struct htca_target *target, + struct htca_reg_request *reg_request) +{ + struct htca_endpoint *end_point; + int ep; + + for (ep = 0; ep < HTCA_NUM_MBOX; ep++) { + end_point = &target->end_point[ep]; + + if (reg_request->u.reg_table.status.counter_int_status & + (0x10 << ep)) { + end_point->tx_credits_to_reap = true; + } else { + end_point->tx_credits_to_reap = false; + } + } +} + +/* After a Register Refresh, uppdate rx_frame_length for each end_point. */ +static void htca_update_rx_frame_lengths(struct htca_target *target, + struct htca_reg_request *reg_request) +{ + struct htca_endpoint *end_point; + u32 rx_lookahead; + u32 frame_length; + int ep; + + htcadebug("Enter\n"); + for (ep = 0; ep < HTCA_NUM_MBOX; ep++) { + end_point = &target->end_point[ep]; + + if (end_point->rx_frame_length != 0) { + /* NB: Will be cleared in htca_recv_compl after + * frame is read + */ + continue; + } + + if (!(reg_request->u.reg_table.rx_lookahead_valid & + (1 << ep))) { + continue; + } + + /* The length of the incoming message is contained + * in the first two (HTCA_HEADER_LEN) bytes in + * LittleEndian order. + * + * This length does NOT include the HTCA header nor block + * padding. + */ + rx_lookahead = reg_request->u.reg_table.rx_lookahead[ep]; + frame_length = rx_lookahead & 0x0000ffff; + + end_point->rx_frame_length = frame_length; + htcadebug("ep#%d : %d\n", ep, + frame_length); + } +} + +static unsigned int htca_debug_no_pending; /* debug only */ + +/* Completion for a register refresh. + * + * Update rxFrameLengths and tx_credits_to_reap info for + * each endpoint. Then handle all pending interrupts (o + * if interrupts are currently masked at the Host, handle + * all interrupts that would be pending if interrupts + * were enabled). + * + * Called in the context of HIF's completion task whenever + * results from a register refresh are received. + */ +void htca_register_refresh_compl(struct htca_target *target, + struct htca_reg_request *req) +{ + u8 host_int_status; + u8 pnd_enb_intrs; /* pending and enabled interrupts */ + u8 pending_int; + u8 enabled_int; + unsigned long flags; + + htcadebug("Enter\n"); + + if (WARN_ON(target->pending_register_refresh == 0)) + return; + + spin_lock_irqsave(&target->pending_op_lock, flags); + target->pending_register_refresh--; + spin_unlock_irqrestore(&target->pending_op_lock, flags); + + htcadebug( + "REGDUMP: hostis=0x%02x cpuis=0x%02x erris=0x%02x cntris=0x%02x\n", + req->u.reg_table.status.host_int_status, + req->u.reg_table.status.cpu_int_status, + req->u.reg_table.status.err_int_status, + req->u.reg_table.status.counter_int_status); + htcadebug( + "mbox_frame=0x%02x lav=0x%02x la0=0x%08x la1=0x%08x la2=0x%08x la3=0x%08x\n", + req->u.reg_table.mbox_frame, req->u.reg_table.rx_lookahead_valid, + req->u.reg_table.rx_lookahead[0], req->u.reg_table.rx_lookahead[1], + req->u.reg_table.rx_lookahead[2], req->u.reg_table.rx_lookahead[3]); + + /* Update rxFrameLengths */ + htca_update_rx_frame_lengths(target, req); + + /* Update tx_credits_to_reap */ + htca_update_tx_credits_to_reap(target, req); + + /* Process pending Target interrupts. */ + + /* Restrict attention to pending interrupts of interest */ + host_int_status = req->u.reg_table.status.host_int_status; + + /* Unexpected and unhandled */ + if (WARN_ON(host_int_status & HOST_INT_STATUS_DRAGON_INT_MASK)) + return; + + /* Form software's idea of pending and enabled interrupts. + * Start with ERRORs and CPU interrupts. + */ + pnd_enb_intrs = host_int_status & + (HOST_INT_STATUS_ERROR_MASK | HOST_INT_STATUS_CPU_MASK); + + /* Software may have intended to enable/disable credit + * counter interrupts; but we commit these updates to + * Target hardware lazily, just before re-enabling + * interrupts. So registers that we have now may not + * reflect the intended state of interrupt enables. + */ + + /* Based on software credit enable bits, update pnd_enb_intrs + * (which is like a software copy of host_int_status) as if + * all desired interrupt enables had been committed to HW. + */ + pending_int = req->u.reg_table.status.counter_int_status; + enabled_int = target->enb.counter_int_status_enb; + if (pending_int & enabled_int) + pnd_enb_intrs |= HOST_INT_STATUS_COUNTER_MASK; + + /* Based on software recv data enable bits, update + * pnd_enb_intrs AS IF all the interrupt enables had + * been committed to HW. + */ + pending_int = host_int_status; + enabled_int = target->enb.int_status_enb; + pnd_enb_intrs |= (pending_int & enabled_int); + + if (!pnd_enb_intrs) { + /* No enabled interrupts are pending. */ + htca_debug_no_pending++; + } + + /* Invoke specific handlers for each enabled and pending interrupt. + * The goal of each service routine is to clear interrupts at the + * source (on the Target). + * + * We deal with four types of interrupts in the HOST_INT_STATUS + * summary register: + * errors + * This remains set until bits in ERROR_INT_STATUS are cleared + * + * CPU + * This remains set until bits in CPU_INT_STATUS are cleared + * + * rx data available + * These remain set as long as rx data is available. HW clears + * the rx data available enable bits when receive buffers + * are exhausted. If we exhaust Host-side received buffers, we + * mask the rx data available interrupt. + * + * tx credits available + * This remains set until all bits in COUNTER_INT_STATUS are + * cleared by HW after Host SW reaps all credits on a mailbox. + * If credits on an endpoint are sufficient, we mask the + * corresponding COUNTER_INT_STATUS bit. We avoid "dribbling" + * one credit at a time and instead reap them en masse. + * + * The HOST_INT_STATUS register is read-only these bits are cleared + * by HW when the underlying condition is cleared. + */ + + if (HOST_INT_STATUS_ERROR_GET(pnd_enb_intrs)) + htca_service_error_interrupt(target, req); + + if (HOST_INT_STATUS_CPU_GET(pnd_enb_intrs)) + htca_service_cpu_interrupt(target, req); + + if (HOST_INT_STATUS_COUNTER_GET(pnd_enb_intrs)) + htca_service_credit_counter_interrupt(target, req); + + /* Always needed in order to at least unmask Host interrupts */ + htca_work_task_poke(target); +} + +/* Complete an update of interrupt enables. */ +void htca_update_intr_enbs_compl(struct htca_target *target, + struct htca_reg_request *req) +{ + htcadebug("Enter\n"); + if (req->purpose == UPDATE_TARG_AND_ENABLE_HOST_INTRS) { + /* NB: non-intuitive, but correct */ + + /* While waiting for rxdata and txcred + * interrupts to be disabled at the Target, + * we temporarily masked interrupts at + * the Host. It is now safe to allow + * interrupts (esp. ERROR and CPU) at + * the Host. + */ + htcadebug("Unmasking\n"); + hif_un_mask_interrupt(target->hif_handle); + } +} + +/* Called to complete htca_credit_refresh_start. + * + * Ends a credit refresh cycle. Called after decrementing a + * credit counter register (many times in a row). HW atomically + * decrements the counter and returns the OLD value but HW will + * never reduce it below 0. + * + * Called in the context of the work_task when the credit counter + * decrement operation completes synchronously. Called in the + * context of the compl_task when the credit counter decrement + * operation completes asynchronously. + */ +void htca_credit_refresh_compl(struct htca_target *target, + struct htca_reg_request *reg_request) +{ + struct htca_endpoint *end_point; + unsigned long flags; + int reaped; + int i; + + /* A non-zero value indicates 1 credit reaped. + * Typically, we will find monotonically descending + * values that reach 0 with the remaining values + * all zero. But we must scan the entire results + * to handle the case where the Target just happened + * to increment credits simultaneously with our + * series of credit decrement operations. + */ + htcadebug("ep=%d\n", reg_request->epid); + end_point = &target->end_point[reg_request->epid]; + reaped = 0; + for (i = 0; i < HTCA_TX_CREDITS_REAP_MAX; i++) { + htcadebug("|R0x%02x", reg_request->u.credit_dec_results[i]); + if (reg_request->u.credit_dec_results[i]) + reaped++; + } + + htcadebug("\nreaped %d credits on ep=%d\n", reaped, reg_request->epid); + + spin_lock_irqsave(&end_point->tx_credit_lock, flags); + end_point->tx_credits_available += reaped; + end_point->tx_credit_refresh_in_progress = false; + spin_unlock_irqrestore(&end_point->tx_credit_lock, flags); + + htca_work_task_poke(target); +} diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_events.c b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_events.c new file mode 100644 index 000000000000..d034277f2e9f --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_events.c @@ -0,0 +1,130 @@ +/* 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 +#include +#include +#include +#include + +#include "../hif_sdio/hif.h" +#include "htca.h" +#include "htca_mbox_internal.h" + +/* Host Target Communications Event Management */ + +/* Protect all event tables -- global as well as per-endpoint. */ +static spinlock_t event_lock; /* protects all event tables */ + +/* Mapping table for global events -- avail/unavail */ +static struct htca_event_table_element + global_event_table[HTCA_EVENT_GLOBAL_COUNT]; + +struct htca_event_table_element * +htca_event_id_to_event(struct htca_target *target, + u8 end_point_id, + u8 event_id) +{ + struct htca_event_table_element *ev = NULL; + + /* is ep event */ + if ((event_id >= HTCA_EVENT_EP_START) && + (event_id <= HTCA_EVENT_EP_END)) { + struct htca_endpoint *end_point; + int ep_evid; + + ep_evid = event_id - HTCA_EVENT_EP_START; + end_point = &target->end_point[end_point_id]; + ev = &end_point->endpoint_event_tbl[ep_evid]; + /* is global event */ + } else if ((event_id >= HTCA_EVENT_GLOBAL_START) && + (event_id <= HTCA_EVENT_GLOBAL_END)) { + int global_evid; + + global_evid = event_id - HTCA_EVENT_GLOBAL_START; + ev = &global_event_table[global_evid]; + } else { + WARN_ON(1); /* unknown event */ + } + + return ev; +} + +void htca_dispatch_event(struct htca_target *target, + u8 end_point_id, + u8 event_id, + struct htca_event_info *event_info) +{ + struct htca_event_table_element *ev; + + ev = htca_event_id_to_event(target, end_point_id, event_id); + if (!ev) { + panic("BUG"); + return; + } + if (ev->handler) { + htca_event_handler handler; + void *param; + unsigned long flags; + + spin_lock_irqsave(&event_lock, flags); + handler = ev->handler; + param = ev->param; + spin_unlock_irqrestore(&event_lock, flags); + + handler((void *)target, end_point_id, event_id, + event_info, param); + } +} + +int htca_add_to_event_table(struct htca_target *target, + u8 end_point_id, + u8 event_id, + htca_event_handler handler, void *param) { + struct htca_event_table_element *ev; + unsigned long flags; + + ev = htca_event_id_to_event(target, end_point_id, event_id); + if (!ev) + return HTCA_ERROR; + + spin_lock_irqsave(&event_lock, flags); + ev->handler = handler; + ev->param = param; + spin_unlock_irqrestore(&event_lock, flags); + + return HTCA_OK; +} + +int htca_remove_from_event_table(struct htca_target *target, + u8 end_point_id, + u8 event_id) { + struct htca_event_table_element *ev; + unsigned long flags; + + ev = htca_event_id_to_event(target, end_point_id, event_id); + if (!ev) + return HTCA_ERROR; + + spin_lock_irqsave(&event_lock, flags); + /* Clear event handler info */ + memset(ev, 0, sizeof(*ev)); + spin_unlock_irqrestore(&event_lock, flags); + + return HTCA_OK; +} + +/* Called once during module initialization */ +void htca_event_table_init(void) +{ + spin_lock_init(&event_lock); +} diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_internal.h b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_internal.h new file mode 100644 index 000000000000..b1c7c6bbc6a8 --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_internal.h @@ -0,0 +1,581 @@ +/* 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 _HTCA_INTERNAL_H_ +#define _HTCA_INTERNAL_H_ + +#include "mbox_host_reg.h" + +#if defined(DEBUG) +#define htcadebug(fmt, a...) \ + pr_err("htca %s:%d: " fmt, __func__, __LINE__, ##a) +#else +#define htcadebug(args...) +#endif + +/* HTCA internal specific declarations and prototypes */ + +/* Target-side SDIO/SPI (mbox) controller supplies 4 mailboxes */ +#define HTCA_NUM_MBOX 4 + +/* Software supports at most this many Target devices */ +#define HTCA_NUM_DEVICES_MAX 2 + +/* Maximum supported mailbox message size. + * + * Quartz' SDIO/SPI mailbox alias spaces are 2KB each; so changes + * would be required to exceed that. WLAN restricts packets to + * under 1500B. + */ +#define HTCA_MESSAGE_SIZE_MAX 2048 + +#define HTCA_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */ + +/* The maximum number of credits that we will reap + * from the Target at one time. + */ +#define HTCA_TX_CREDITS_REAP_MAX 8 + +/* Mailbox address in SDIO address space */ +#define MBOX_BASE_ADDR 0x800 /* Start of MBOX alias spaces */ +#define MBOX_WIDTH 0x800 /* Width of each mailbox alias space */ + +#define MBOX_START_ADDR(mbox) (MBOX_BASE_ADDR + ((mbox) * (MBOX_WIDTH))) + +/* The byte just before this causes an EndOfMessage interrupt to be generated */ +#define MBOX_END_ADDR(mbox) (MBOX_START_ADDR(mbox) + MBOX_WIDTH) + +/* extended MBOX address for larger MBOX writes to MBOX 0 (not used) */ +#define MBOX0_EXTENDED_BASE_ADDR 0x2800 +#define MBOX0_EXTENDED_WIDTH (6 * 1024) + +/* HTCA message header */ +struct HTCA_header { + u16 total_msg_length; +} __packed; + +#define HTCA_HEADER_LEN sizeof(struct HTCA_header) + +/* Populate an htca_event_info structure to be passed to + * a user's event handler. + */ +static inline void htca_frame_event(struct htca_event_info *event_info, + u8 *buffer, size_t buffer_length, + size_t actual_length, u32 status, + void *cookie) +{ + if (event_info) { + event_info->buffer = buffer; + event_info->buffer_length = buffer_length; + event_info->actual_length = actual_length; + event_info->status = status; + event_info->cookie = cookie; + } +} + +/* Global and endpoint-specific event tables use these to + * map an event ID --> handler + param. + */ +struct htca_event_table_element { + htca_event_handler handler; + void *param; +}; + +/* This layout MUST MATCH Target hardware layout! */ +struct htca_intr_status { + u8 host_int_status; + u8 cpu_int_status; + u8 err_int_status; + u8 counter_int_status; +} __packed; + +/* This layout MUST MATCH Target hardware layout! */ +struct htca_intr_enables { + u8 int_status_enb; + u8 cpu_int_status_enb; + u8 err_status_enb; + u8 counter_int_status_enb; +} __packed; + +/* The Register table contains Target SDIO/SPI interrupt/rxstatus + * registers used by HTCA. Rather than read particular registers, + * we use a bulk "register refresh" to read all at once. + * + * This layout MUST MATCH Target hardware layout! + */ +struct htca_register_table { + struct htca_intr_status status; + + u8 mbox_frame; + u8 rx_lookahead_valid; + u8 hole[2]; + + /* Four lookahead bytes for each mailbox */ + u32 rx_lookahead[HTCA_NUM_MBOX]; +} __packed; + +/* Two types of requests/responses are supported: + * "mbox requests" are messages or data which + * are sent to a Target mailbox + * "register requests" are to read/write Target registers + * + * Mbox requests are managed with a per-endpoint + * pending list and free list. + * + * Register requests are managed with a per-Target + * pending list and free list. + * + * A generic HTCA request -- one which is either an + * htca_mbox_request or an htca_reg_request is represented + * by an htca_request. + */ + +/* Number of mbox_requests and reg_requests allocated initially. */ +#define HTCA_MBOX_REQUEST_COUNT 16 /* per mailbox */ +#define HTCA_REG_REQUEST_COUNT (4 * HTCA_NUM_MBOX) /* per target */ + +/* An htca_request is at the start of a mbox_request structure + * and at the start of a reg_request structure. + * + * Specific request types may be cast to a generic htca_request + * (e.g. in order to invoke the completion callback function) + */ +struct htca_request { + /*struct htca_request*/ void *next; /* linkage */ + struct htca_target *target; + void (*completion_cb)(struct htca_request *req, int status); + int status; /* completion status from HIF */ +}; + +struct htca_endpoint; /* forward reference */ + +/* Mailbox request -- a message or bulk data */ +struct htca_mbox_request { + struct htca_request req; /* Must be first -- (cast to htca_request) */ + + /* Caller-supplied cookie associated with this request */ + void *cookie; + + /* Pointer to the start of the buffer. In the transmit + * direction this points to the start of the payload. In the + * receive direction, however, the buffer when queued up + * points to the start of the HTCA header but when returned + * to the caller points to the start of the payload + * + * Note: buffer is set to NULL whenever this request is free. + */ + u8 *buffer; + + /* length, in bytes, of the buffer */ + u32 buffer_length; + + /* length, in bytes, of the payload within the buffer */ + u32 actual_length; + + struct htca_endpoint *end_point; +}; + +/* Round up a value (e.g. length) to a power of 2 (e.g. block size). */ +static inline u32 htca_round_up(u32 value, u32 pwrof2) +{ + return (((value) + (pwrof2) - 1) & ~((pwrof2) - 1)); +} + +/* Indicates reasons that we might access Target register space */ +enum htca_req_purpose { + UNUSED_PURPOSE, + INTR_REFRESH, /* Fetch latest interrupt/status registers */ + CREDIT_REFRESH, /* Reap credits */ + UPDATE_TARG_INTRS, + UPDATE_TARG_AND_ENABLE_HOST_INTRS, +}; + +/* Register read request -- used to read registers from SDIO/SPI space. + * Register writes are fire and forget; no completion is needed. + * + */ +struct htca_reg_request { + struct htca_request req; /* Must be first -- (cast to htca_request) */ + u8 *buffer; /* register value(s) */ + u32 length; + + /* Indicates the purpose this request was made */ + enum htca_req_purpose purpose; + + /* Which endpoint this read is for. + * Used when processing a completed credit refresh request. + */ + u8 epid; /* which endpoint ID [0..3] */ + + /* A read to Target register space returns + * one specific Target register value OR + * all values in the register_table OR + * a special repeated read-and-dec from a credit register + * + * FUTURE: We could separate these into separate request + * types in order to perhaps save a bit of space.... + * eliminate the union. + */ + union { + struct htca_intr_enables enb; + struct htca_register_table reg_table; + u8 credit_dec_results[HTCA_TX_CREDITS_REAP_MAX]; + } u; +}; + +struct htca_request_queue { + struct htca_request *head; + struct htca_request *tail; +}; + +#define HTCA_IS_QUEUE_EMPTY(q) (!((q)->head)) + +/* List of Target registers in SDIO/SPI space which can be accessed by Host */ +enum target_registers { + UNUSED_REG = 0, + INTR_ENB_REG = INT_STATUS_ENABLE_ADDRESS, + ALL_STATUS_REG = HOST_INT_STATUS_ADDRESS, + ERROR_INT_STATUS_REG = ERROR_INT_STATUS_ADDRESS, + CPU_INT_STATUS_REG = CPU_INT_STATUS_ADDRESS, + TX_CREDIT_COUNTER_DECREMENT_REG = COUNT_DEC_ADDRESS, + INT_TARGET_REG = INT_TARGET_ADDRESS, +}; + +static inline u32 get_reg_addr(enum target_registers which, + u8 epid) +{ + return (((which) == TX_CREDIT_COUNTER_DECREMENT_REG) + ? (COUNT_DEC_ADDRESS + (HTCA_NUM_MBOX + (epid)) * 4) + : (which)); +} + +/* FUTURE: See if we can use lock-free operations + * to manage credits and linked lists. + * FUTURE: Use standard Linux queue ops; ESPECIALLY + * if they support lock-free operation. + */ + +/* One of these per endpoint */ +struct htca_endpoint { + /* Enabled or Disabled */ + bool enabled; + + /* If data is available, rxLengthPending + * indicates the length of the incoming message. + */ + u32 rx_frame_length; /* incoming frame length on this endpoint */ + /* includes HTCA header */ + /* Modified only by compl_task */ + + bool rx_data_alerted; /* Caller was sent a BUFFER_AVAILABLE event */ + /* and has not supplied a new recv buffer */ + /* since that warning was sent. */ + /* Modified only by work_task */ + + bool tx_credits_to_reap; /* At least one credit available at the */ + /* Target waiting to be reaped. */ + /* Modified only by compl_task */ + + /* Guards tx_credits_available and tx_credit_refresh_in_progress */ + spinlock_t tx_credit_lock; + + /* The number of credits that we have already reaped + * from the Target. (i.e. we have decremented the Target's + * count register so that we have ability to send future + * messages). We have the ability to send tx_credits_available + * messages without blocking. + * + * The size of a message is endpoint-dependent and always + * a multiple of the device's block_size. + */ + u32 tx_credits_available; + + /* Maximum message size */ + u32 max_msg_sz; + + /* Indicates that we are in the midst of a credit refresh cycle */ + bool tx_credit_refresh_in_progress; + + /* Free/Pending Send/Recv queues are used for mbox requests. + * An mbox Send request cannot be given to HIF until we have + * a tx credit. An mbox Recv request cannot be given to HIF + * until we have a pending rx msg. + * + * The HIF layer maintains its own queue of requests, which + * it uses to serialize access to SDIO. Its queue contains + * a mixture of sends/recvs and mbox/reg requests. HIF is + * "beyond" flow control so once a requets is given to HIF + * it is guaranteed to complete (after all previous requests + * complete). + */ + + /* Guards Free/Pending send/recv queues */ + spinlock_t mbox_queue_lock; + struct htca_request_queue send_free_queue; + struct htca_request_queue send_pending_queue; + struct htca_request_queue recv_free_queue; + struct htca_request_queue recv_pending_queue; + + /* Inverse reference to the target */ + struct htca_target *target; + + /* Block size configured for the endpoint -- common across all endpoints + */ + u32 block_size; + + /* Mapping table for per-endpoint events */ + struct htca_event_table_element endpoint_event_tbl[HTCA_EVENT_EP_COUNT]; + + /* Location of the endpoint's mailbox space */ + u32 mbox_start_addr; + u32 mbox_end_addr; +}; + +#define ENDPOINT_UNUSED 0 + +/* Target interrupt states. */ +enum intr_state_e { + /* rxdata and txcred interrupts enabled. + * Only the DSR context can switch us to + * polled state. + */ + HTCA_INTERRUPT, + + /* rxdata and txcred interrupts are disabled. + * We are polling (via RegisterRefresh). + * Only the work_task can switch us to + * interrupt state. + */ + HTCA_POLL, +}; + +/* One of these per connected QCA402X device. */ +struct htca_target { + /* Target device is initialized and ready to go? + * This has little o do with Host state; + * it reflects readiness of the Target. + */ + bool ready; + + /* Handle passed to HIF layer for SDIO/SPI Host controller access */ + void *hif_handle; /* hif_device */ + + /* Per-endpoint info */ + struct htca_endpoint end_point[HTCA_NUM_MBOX]; + + /* Used during startup while the Host waits for the + * Target to initialize. + */ + wait_queue_head_t target_init_wait; + + /* Free queue for htca_reg_requests. + * + * We don't need a regPendingQueue because reads/writes to + * Target register space are not flow controlled by the Target. + * There is no need to wait for credits in order to hand off a + * register read/write to HIF. + * + * The register read/write may end up queued in a HIF queue + * behind both register and mbox reads/writes that were + * handed to HIF earlier. But they will never be queued + * by HTCA. + */ + spinlock_t reg_queue_lock; + struct htca_request_queue reg_free_queue; + + /* comp task synchronization */ + struct mutex task_mutex; + + struct task_struct *work_task; + struct task_struct *compl_task; + + /* work_task synchronization */ + wait_queue_head_t work_task_wait; /* wait for work to do */ + bool work_task_has_work; /* work available? */ + bool work_task_shutdown; /* requested stop? */ + struct completion work_task_completion; + + /* compl_task synchronization */ + wait_queue_head_t compl_task_wait; /* wait for work to do */ + bool compl_task_has_work; /* work available? */ + bool compl_task_shutdown; /* requested stop? */ + struct completion compl_cask_completion; + + /* Queue of completed mailbox and register requests */ + spinlock_t compl_queue_lock; + struct htca_request_queue compl_queue; + + /* Software's shadow copy of interrupt enables. + * Only the work_task changes intr_enable bits, + * so no locking necessary. + * + * Committed to Target HW when + * we convert from polling to interrupts or + * we are using interrupts and enables have changed + */ + struct htca_intr_enables enb; + struct htca_intr_enables last_committed_enb; + + enum intr_state_e intr_state; + int need_start_polling; + + /* Set after we read data from a mailbox (to + * update lookahead and mailbox status bits). + * used only by work_task even though refreshes + * may be started in other contexts. + */ + int need_register_refresh; + + /* Guards pending_register_refresh and pending_recv_mask */ + spinlock_t pending_op_lock; + + /* Incremented when a RegisterRefresh is started; + * Decremented when it completes. + */ + int pending_register_refresh; + + /* Non-zero if a recv operation has been started + * but not yet completed. 1 bit for each ep. + */ + int pending_recv_mask; +}; + +/* Convert an endpoint POINTER into an endpoint ID [0..3] */ +static inline u32 get_endpoint_id(struct htca_endpoint *ep) +{ + return (u32)(ep - ep->target->end_point); +} + +void htca_receive_frame(struct htca_endpoint *end_point); + +u32 htca_get_frame_length(struct htca_endpoint *end_point); + +void htca_send_frame(struct htca_endpoint *end_point); + +void htca_send_blk_size(struct htca_endpoint *end_point); + +int htca_rw_completion_handler(void *req, int status); + +void htca_send_compl(struct htca_request *req, int status); + +void htca_recv_compl(struct htca_request *req, int status); + +void htca_reg_compl(struct htca_request *req, int status); + +int htca_target_inserted_handler(void *context, + void *hif_handle); + +int htca_target_removed_handler(void *context, void *hif_handle); + +int htca_dsr_handler(void *target_ctxt); + +void htca_service_cpu_interrupt(struct htca_target *target, + struct htca_reg_request *req); + +void htca_service_error_interrupt(struct htca_target *target, + struct htca_reg_request *req); + +void htca_service_credit_counter_interrupt(struct htca_target *target, + struct htca_reg_request *req); + +void htca_enable_credit_counter_interrupt(struct htca_target *target, + u8 end_point_id); + +void htca_disable_credit_counter_interrupt(struct htca_target *target, + u8 end_point_id); + +int htca_add_to_mbox_queue(struct htca_mbox_request *queue, + u8 *buffer, + u32 buffer_length, + u32 actual_length, void *cookie); + +struct htca_mbox_request * +htca_remove_from_mbox_queue(struct htca_mbox_request *queue); + +void htca_mbox_queue_flush(struct htca_endpoint *end_point, + struct htca_request_queue *pending_queue, + struct htca_request_queue *free_queue, + u8 event_id); + +int htca_add_to_event_table(struct htca_target *target, + u8 end_point_id, + u8 event_id, + htca_event_handler handler, + void *param); + +int htca_remove_from_event_table(struct htca_target *target, + u8 end_point_id, + u8 event_id); + +void htca_dispatch_event(struct htca_target *target, + u8 end_point_id, + u8 event_id, + struct htca_event_info *event_info); + +struct htca_target *htca_target_instance(int i); + +void htca_target_instance_add(struct htca_target *target); + +void htca_target_instance_remove(struct htca_target *target); + +u8 htca_get_bit_num_set(u32 data); + +void htca_register_refresh(struct htca_target *target); + +void free_request(struct htca_request *req, + struct htca_request_queue *queue); + +extern struct htca_target *htca_target_list[HTCA_NUM_DEVICES_MAX]; + +int htca_work_task_start(struct htca_target *target); +int htca_compl_task_start(struct htca_target *target); +void htca_work_task_stop(struct htca_target *target); +void htca_compl_task_stop(struct htca_target *target); +void htca_work_task_poke(struct htca_target *target); +void htca_compl_task_poke(struct htca_target *target); + +void htca_event_table_init(void); +struct htca_event_table_element * +htca_event_id_to_event(struct htca_target *target, + u8 end_point_id, + u8 event_id); + +void htca_request_enq_tail(struct htca_request_queue *queue, + struct htca_request *req); +struct htca_request *htca_request_deq_head(struct htca_request_queue *queue); + +void htca_register_refresh_start(struct htca_target *target); +void htca_register_refresh_compl(struct htca_target *target, + struct htca_reg_request *req); + +int htca_credit_refresh_start(struct htca_endpoint *end_point); +void htca_credit_refresh_compl(struct htca_target *target, + struct htca_reg_request *req); + +void htca_update_intr_enbs(struct htca_target *target, + int enable_host_intrs); +void htca_update_intr_enbs_compl(struct htca_target *target, + struct htca_reg_request *req); + +bool htca_negotiate_config(struct htca_target *target); + +int htca_recv_request_to_hif(struct htca_endpoint *end_point, + struct htca_mbox_request *mbox_request); +int htca_send_request_to_hif(struct htca_endpoint *endpoint, + struct htca_mbox_request *mbox_request); + +int htca_manage_pending_sends(struct htca_target *target, int epid); +int htca_manage_pending_recvs(struct htca_target *target, int epid); + +void _htca_stop(struct htca_target *target); + +#endif /* _HTCA_INTERNAL_H_ */ diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_intr.c b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_intr.c new file mode 100644 index 000000000000..0486f5974a4e --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_intr.c @@ -0,0 +1,627 @@ +/* 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 +#include +#include +#include +#include +#include +#include + +#include "../hif_sdio/hif.h" +#include "htca.h" +#include "htca_mbox_internal.h" + +/* Host Target Communications Interrupt Management */ + +/* Interrupt Management + * When an interrupt occurs at the Host, it is to tell us about + * a high-priority error interrupt + * a CPU interrupt (TBD) + * rx data available + * tx credits available + * + * From an interrupt management perspective, rxdata and txcred + * interrupts are grouped together. When either of these occurs, + * we enter a mode where we repeatedly refresh register state + * and act on all interrupt information in the refreshed registers. + * We are basically polling with rxdata and txcred interrupts + * masked. Eventually, we refresh registers and find no rxdata + * and no txcred interrupts pending. At this point, we unmask + * those types of interrupts. + * + * Unmasking is selective: We unmask only the interrupts that + * we want to receive which include + * -rxdata interrupts for endpoints that have received + * buffers on the recv pending queue + * -txcred interrupts for endpoints with a very low + * count of creditsAvailable + * Other rxdata and txcred interrupts are masked. These include: + * -rxdata interrupts for endpoint that lack recv buffers + * -txcred interrupts for endpoint with lots of credits + * + * Very little activity takes place in the context of the + * interrupt function (Delayed Service Routine). We mask + * interrupts at the Host, send a command to disable all + * rxdata/txcred interrupts and finally start a register + * refresh. When the register refresh completes, we unmask + * interrupts on the Host and poke the work_task which now + * has valid register state to examine. + * + * The work_task repeatedly + * handles outstanding rx and tx service + * starts another register refresh + * Every time a register refresh completes, it pokes the + * work_task. This cycle continues until the work_task finds + * nothing to do after a register refresh. At this point, + * it unmasks rxdata/txcred interrupts at the Target (again, + * selectively). + * + * While in the work_task polling cycle, we maintain a notion + * of interrupt enables in software rather than commit these + * to Target HW. + * + * + * Credit State Machine: + * Credits are + * -Added by the Target whenever a Target-side receive + * buffer is added to a mailbox + * -Never rescinded by the Target + * -Reaped by this software after a credit refresh cycle + * which is initiated + * -as a result of a credit counter interrupt + * -after a send completes and the number of credits + * are below an acceptable threshold + * -used by this software when it sends a message HIF to + * be sent to the Target + * + * The process of "reaping" credits involves first issuing + * a sequence of reads to the COUNTER_DEC register. (This is + * known as the start of a credit refresh.) We issue a large + * number of reads in order to reap as many credits at once + * as we can. When these reads complete, we determine how + * many credits were available and increase software's notion + * of tx_credits_available accordingly. + * + * Note: All Target reads/writes issued from the interrupt path + * should be asynchronous. HIF adds such a request to a queue + * and immediately returns. + * + * TBD: It might be helpful for HIF to support a "priority + * queue" -- requests that should be issued prior to anything + * in its normal queue. Even with this, a request might have + * to wait for a while as the current, read/write request + * completes on SDIO and then wait for all prior priority + * requests to finish. So probably not worth the additional + * complexity. + */ + +/* Maximum message sizes for each endpoint. + * Must be a multiple of the block size. + * Must be no greater than HTCA_MESSAGE_SIZE_MAX. + * + * TBD: These should be tunable. Example anticipated usage: + * ep0: Host-side networking control messages + * ep1: Host-side networking data messages + * ep2: OEM control messages + * ep3: OEM data messages + */ +static u32 htca_msg_size[HTCA_NUM_MBOX] = {256, 3 * 512, 512, 2048}; + +/* Commit the shadow interrupt enables in software to + * Target Hardware. This is where the "lazy commit" + * occurs. Always called in the context of work_task. + * + * When the host's intr_state is POLL: + * -All credit count interrupts and all rx data interrupts + * are disabled at the Target. + * + * When the host's intr_state is INTERRUPT: + * -We commit the shadow copy of interrupt enables. + * -A mailbox with low credit count will have the credit + * interrupt enabled. A mailbox with high credit count + * will have the credit interrupt disabled. + * -A mailbox with no available receive buffers will have + * the mailbox data interrupt disabled. A mailbox with + * at least one receive buffer will have the mailbox + * data interrupt enabled. + */ +void htca_update_intr_enbs(struct htca_target *target, + int enable_host_intrs) +{ + int status; + struct htca_reg_request *reg_request; + struct htca_intr_enables *enbregs; + unsigned long flags; + u32 address; + + htcadebug("Enter: enable_host_intrs=%d\n", + enable_host_intrs); + htcadebug("ints: 0x%02x --> 0x%02x\n", + target->last_committed_enb.int_status_enb, + target->enb.int_status_enb); + htcadebug("cpu: 0x%02x --> 0x%02x\n", + target->last_committed_enb.cpu_int_status_enb, + target->enb.cpu_int_status_enb); + htcadebug("error: 0x%02x --> 0x%02x\n", + target->last_committed_enb.err_status_enb, + target->enb.err_status_enb); + htcadebug("counters: 0x%02x --> 0x%02x\n", + target->last_committed_enb.counter_int_status_enb, + target->enb.counter_int_status_enb); + if ((target->enb.int_status_enb == + target->last_committed_enb.int_status_enb) && + (target->enb.counter_int_status_enb == + target->last_committed_enb.counter_int_status_enb) && + (target->enb.cpu_int_status_enb == + target->last_committed_enb.cpu_int_status_enb) && + (target->enb.err_status_enb == + target->last_committed_enb.err_status_enb)) { + /* No changes to Target-side interrupt enables are required. + * But we must still need to enable Host-side interrupts. + */ + if (enable_host_intrs) { + htcadebug("Unmasking - no change to Target enables\n"); + hif_un_mask_interrupt(target->hif_handle); + } + return; + } + + spin_lock_irqsave(&target->reg_queue_lock, flags); + reg_request = (struct htca_reg_request *)htca_request_deq_head( + &target->reg_free_queue); + spin_unlock_irqrestore(&target->reg_queue_lock, flags); + if (!reg_request) { + WARN_ON(1); + return; + } + if (WARN_ON(reg_request->purpose != UNUSED_PURPOSE)) + return; + + reg_request->buffer = NULL; + reg_request->length = 0; + reg_request->epid = 0; /* unused */ + enbregs = ®_request->u.enb; + + if (target->intr_state == HTCA_INTERRUPT) { + enbregs->int_status_enb = target->enb.int_status_enb; + enbregs->counter_int_status_enb = + target->enb.counter_int_status_enb; + } else { + enbregs->int_status_enb = (target->enb.int_status_enb & + ~HOST_INT_STATUS_MBOX_DATA_MASK); + enbregs->counter_int_status_enb = 0; + } + + enbregs->cpu_int_status_enb = target->enb.cpu_int_status_enb; + enbregs->err_status_enb = target->enb.err_status_enb; + + target->last_committed_enb = *enbregs; /* structure copy */ + + if (enable_host_intrs) + reg_request->purpose = UPDATE_TARG_AND_ENABLE_HOST_INTRS; + else + reg_request->purpose = UPDATE_TARG_INTRS; + + address = get_reg_addr(INTR_ENB_REG, ENDPOINT_UNUSED); + + status = hif_read_write(target->hif_handle, address, enbregs, + sizeof(*enbregs), HIF_WR_ASYNC_BYTE_INC, + reg_request); + if (status == HIF_OK && reg_request->req.completion_cb) { + reg_request->req.completion_cb( + (struct htca_request *)reg_request, HIF_OK); + /* htca_update_intr_enbs_compl */ + } else if (status == HIF_PENDING) { + /* Will complete later */ + } else { /* HIF error */ + WARN_ON(1); + } +} + +/* Delayed Service Routine, invoked from HIF in thread context + * (from sdio's irqhandler) in order to handle interrupts + * caused by the Target. + * + * This serves as a top-level interrupt dispatcher for HTCA. + */ +int htca_dsr_handler(void *htca_handle) +{ + struct htca_target *target = (struct htca_target *)htca_handle; + + htcadebug("Enter\n"); + if (target->ready) { + /* Transition state to polling mode. + * Temporarily disable intrs at Host + * until interrupts are stopped in + * Target HW. + */ + htcadebug("Masking interrupts\n"); + hif_mask_interrupt(target->hif_handle); + target->need_start_polling = 1; + + /* Kick off a register refresh so we + * use updated registers in order to + * figure out what needs to be serviced. + * + * RegisterRefresh completion wakes the + * work_task which re-enables Host-side + * interrupts. + */ + htca_register_refresh_start(target); + } else { /* startup time */ + /* Assumption is that we are receiving an interrupt + * because the Target made a TX Credit available + * on each endpoint (for configuration negotiation). + */ + + hif_mask_interrupt(target->hif_handle); + if (htca_negotiate_config(target)) { + /* All endpoints are configured. + * Target is now ready for normal operation. + */ + /* TBDXXX - Fix Quartz-side and remove this */ + { + /* HACK: Signal Target to read mbox Cfg info. + * TBD: Target should use EOM rather than an + * an explicit Target Interrupt for this. + */ + u8 my_targ_int; + u32 address; + int status; + + /* Set HTCA_INT_TARGET_INIT_HOST_REQ */ + my_targ_int = 1; + + address = + get_reg_addr( + INT_TARGET_REG, ENDPOINT_UNUSED); + status = hif_read_write( + target->hif_handle, address, &my_targ_int, + sizeof(my_targ_int), HIF_WR_SYNC_BYTE_INC, + NULL); + if (WARN_ON(status != HIF_OK)) + return status; + } + target->ready = true; + htcadebug("HTCA TARGET IS READY\n"); + wake_up(&target->target_init_wait); + } + hif_un_mask_interrupt(target->hif_handle); + } + return HTCA_OK; +} + +/* Handler for CPU interrupts that are explicitly + * initiated by Target firmware. Not used by system firmware today. + */ +void htca_service_cpu_interrupt(struct htca_target *target, + struct htca_reg_request *req) +{ + int status; + u32 address; + u8 cpu_int_status; + + htcadebug("Enter\n"); + cpu_int_status = req->u.reg_table.status.cpu_int_status & + target->enb.cpu_int_status_enb; + + /* Clear pending interrupts on Target -- Write 1 to Clear */ + address = get_reg_addr(CPU_INT_STATUS_REG, ENDPOINT_UNUSED); + + status = + hif_read_write(target->hif_handle, address, &cpu_int_status, + sizeof(cpu_int_status), HIF_WR_SYNC_BYTE_INC, NULL); + + WARN_ON(status != HIF_OK); + + /* Handle cpu_int_status actions here. None are currently used */ +} + +/* Handler for error interrupts on Target. + * If everything is working properly we hope never to see these. + */ +void htca_service_error_interrupt(struct htca_target *target, + struct htca_reg_request *req) +{ + int status = HIF_ERROR; + u32 address; + u8 err_int_status; + struct htca_endpoint *end_point; + + htcadebug("Enter\n"); + err_int_status = + req->u.reg_table.status.err_int_status & target->enb.err_status_enb; + + end_point = &target->end_point[req->epid]; + htcadebug("epid=%d txCreditsAvailable=%d\n", + (int)req->epid, end_point->tx_credits_available); + htcadebug("statusregs host=0x%02x cpu=0x%02x err=0x%02x cnt=0x%02x\n", + req->u.reg_table.status.host_int_status, + req->u.reg_table.status.cpu_int_status, + req->u.reg_table.status.err_int_status, + req->u.reg_table.status.counter_int_status); + + /* Clear pending interrupts on Target -- Write 1 to Clear */ + address = get_reg_addr(ERROR_INT_STATUS_REG, ENDPOINT_UNUSED); + status = + hif_read_write(target->hif_handle, address, &err_int_status, + sizeof(err_int_status), HIF_WR_SYNC_BYTE_INC, NULL); + + if (WARN_ON(status != HIF_OK)) + return; + + if (ERROR_INT_STATUS_WAKEUP_GET(err_int_status)) { + /* Wakeup */ + htcadebug("statusregs host=0x%x\n", + ERROR_INT_STATUS_WAKEUP_GET(err_int_status)); + /* Nothing needed here */ + } + + if (ERROR_INT_STATUS_RX_UNDERFLOW_GET(err_int_status)) { + /* TBD: Rx Underflow */ + /* Host posted a read to an empty mailbox? */ + /* Target DMA was not able to keep pace with Host reads? */ + if (WARN_ON(2)) /* TBD */ + return; + } + + if (ERROR_INT_STATUS_TX_OVERFLOW_GET(err_int_status)) { + /* TBD: Tx Overflow */ + /* Host posted a write to a mailbox with no credits? */ + /* Target DMA was not able to keep pace with Host writes? */ + if (WARN_ON(1)) /* TBD */ + return; + } +} + +/* Handler for Credit Counter interrupts from Target. + * + * This occurs when the number of credits available on a mailbox + * increases from 0 to non-zero. (i.e. when Target firmware queues a + * DMA Receive buffer to an endpoint that previously had no buffers.) + * + * This interrupt is masked when we have a sufficient number of + * credits available. It is unmasked only when we have reaped all + * available credits and are still below a desired threshold. + */ +void htca_service_credit_counter_interrupt(struct htca_target *target, + struct htca_reg_request *req) +{ + struct htca_endpoint *end_point; + u8 counter_int_status; + u8 eps_with_credits; + int ep; + + htcadebug("Enter\n"); + counter_int_status = req->u.reg_table.status.counter_int_status; + + /* Service the credit counter interrupt. + * COUNTER bits [4..7] are used for credits on endpoints [0..3]. + */ + eps_with_credits = + counter_int_status & target->enb.counter_int_status_enb; + htcadebug("eps_with_credits=0x%02x\n", eps_with_credits); + htcadebug("counter_int_status=0x%02x\n", counter_int_status); + htcadebug("counter_int_status_enb=0x%02x\n", + target->enb.counter_int_status_enb); + + for (ep = 0; ep < HTCA_NUM_MBOX; ep++) { + if (!(eps_with_credits & (0x10 << ep))) + continue; + + end_point = &target->end_point[ep]; + + /* We need credits on this endpoint AND + * the target tells us that there are some. + * Start a credit refresh cycle on this + * endpoint. + */ + (void)htca_credit_refresh_start(end_point); + } +} + +/* Callback registered with HIF to be invoked when Target + * presence is first detected. + * + * Allocate memory for Target, endpoints, requests, etc. + */ +int htca_target_inserted_handler(void *unused_context, + void *hif_handle) +{ + struct htca_target *target; + struct htca_endpoint *end_point; + int ep; + struct htca_event_info event_info; + struct htca_request_queue *send_free_queue, *recv_free_queue; + struct htca_request_queue *reg_queue; + u32 block_size[HTCA_NUM_MBOX]; + struct cbs_from_hif htca_callbacks; /* Callbacks from HIF to HTCA */ + int status = HTCA_OK; + int i; + + htcadebug("Enter\n"); + + target = kzalloc(sizeof(*target), GFP_KERNEL); + /* target->ready = false; */ + + /* Give a handle to HIF for this target */ + target->hif_handle = hif_handle; + hif_set_handle(hif_handle, (void *)target); + + /* Register htca_callbacks from HIF */ + memset(&htca_callbacks, 0, sizeof(htca_callbacks)); + htca_callbacks.rw_completion_hdl = htca_rw_completion_handler; + htca_callbacks.dsr_hdl = htca_dsr_handler; + htca_callbacks.context = target; + (void)hif_attach(hif_handle, &htca_callbacks); + + /* Get block sizes and start addresses for each mailbox */ + hif_configure_device(hif_handle, + HIF_DEVICE_GET_MBOX_BLOCK_SIZE, &block_size, + sizeof(block_size)); + + /* Initial software copies of interrupt enables */ + target->enb.int_status_enb = + INT_STATUS_ENABLE_ERROR_MASK | INT_STATUS_ENABLE_CPU_MASK | + INT_STATUS_ENABLE_COUNTER_MASK | INT_STATUS_ENABLE_MBOX_DATA_MASK; + + /* All 8 CPU interrupts enabled */ + target->enb.cpu_int_status_enb = CPU_INT_STATUS_ENABLE_BIT_MASK; + + target->enb.err_status_enb = ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK | + ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK; + + /* credit counters in upper bits */ + target->enb.counter_int_status_enb = COUNTER_INT_STATUS_ENABLE_BIT_MASK; + + spin_lock_init(&target->reg_queue_lock); + spin_lock_init(&target->compl_queue_lock); + spin_lock_init(&target->pending_op_lock); + mutex_init(&target->task_mutex); + + status = htca_work_task_start(target); + if (status != HTCA_OK) + goto done; + + status = htca_compl_task_start(target); + if (status != HTCA_OK) + goto done; + + /* Initialize the register request free list */ + reg_queue = &target->reg_free_queue; + for (i = 0; i < HTCA_REG_REQUEST_COUNT; i++) { + struct htca_reg_request *reg_request; + + /* Add a reg_request to the Reg Free Queue */ + reg_request = kzalloc(sizeof(*reg_request), GFP_DMA); + reg_request->req.target = target; + reg_request->req.completion_cb = htca_reg_compl; + + /* no lock required -- startup */ + htca_request_enq_tail(reg_queue, + (struct htca_request *)reg_request); + } + + /* Initialize endpoints, mbox queues and event tables */ + for (ep = 0; ep < HTCA_NUM_MBOX; ep++) { + end_point = &target->end_point[ep]; + + spin_lock_init(&end_point->tx_credit_lock); + spin_lock_init(&end_point->mbox_queue_lock); + + end_point->tx_credits_available = 0; + end_point->max_msg_sz = htca_msg_size[ep]; + end_point->rx_frame_length = 0; + end_point->tx_credits_to_reap = false; + end_point->target = target; + end_point->enabled = false; + end_point->block_size = block_size[ep]; + end_point->mbox_start_addr = MBOX_START_ADDR(ep); + end_point->mbox_end_addr = MBOX_END_ADDR(ep); + + /* Initialize per-endpoint queues */ + end_point->send_pending_queue.head = NULL; + end_point->send_pending_queue.tail = NULL; + end_point->recv_pending_queue.head = NULL; + end_point->recv_pending_queue.tail = NULL; + + send_free_queue = &end_point->send_free_queue; + recv_free_queue = &end_point->recv_free_queue; + for (i = 0; i < HTCA_MBOX_REQUEST_COUNT; i++) { + struct htca_mbox_request *mbox_request; + + /* Add an mbox_request to the mbox SEND Free Queue */ + mbox_request = kzalloc(sizeof(*mbox_request), + GFP_KERNEL); + mbox_request->req.target = target; + mbox_request->req.completion_cb = htca_send_compl; + mbox_request->end_point = end_point; + htca_request_enq_tail( + send_free_queue, + (struct htca_request *)mbox_request); + + /* Add an mbox_request to the mbox RECV Free Queue */ + mbox_request = kzalloc(sizeof(*mbox_request), + GFP_KERNEL); + mbox_request->req.target = target; + mbox_request->req.completion_cb = htca_recv_compl; + mbox_request->end_point = end_point; + htca_request_enq_tail( + recv_free_queue, + (struct htca_request *)mbox_request); + } + } + + /* Target and endpoint structures are now completely initialized. + * Add the target instance to the global list of targets. + */ + htca_target_instance_add(target); + + /* Frame a TARGET_AVAILABLE event and send it to + * the caller. Return the hif_device handle as a + * parameter with the event. + */ + htca_frame_event(&event_info, (u8 *)hif_handle, + hif_get_device_size(), + hif_get_device_size(), HTCA_OK, NULL); + htca_dispatch_event(target, ENDPOINT_UNUSED, + HTCA_EVENT_TARGET_AVAILABLE, &event_info); + +done: + return status; +} + +/* Callback registered with HIF to be invoked when Target + * is removed + * + * Also see htca_stop + * Stop tasks + * Free memory for Target, endpoints, requests, etc. + * + * TBD: Not yet supported + */ +int htca_target_removed_handler(void *unused_context, + void *htca_handle) +{ + struct htca_target *target = (struct htca_target *)htca_handle; + struct htca_event_info event_info; + struct htca_endpoint *end_point; + int ep; + + htcadebug("Enter\n"); + /* Disable each of the endpoints to stop accepting requests. */ + for (ep = 0; ep < HTCA_NUM_MBOX; ep++) { + end_point = &target->end_point[ep]; + end_point->enabled = false; + } + + if (target) { + /* Frame a TARGET_UNAVAILABLE event and send it to the host */ + htca_frame_event(&event_info, NULL, 0, 0, HTCA_OK, NULL); + htca_dispatch_event(target, ENDPOINT_UNUSED, + HTCA_EVENT_TARGET_UNAVAILABLE, &event_info); + } + + /* TBD: call htca_stop? */ + /* TBD: Must be sure that nothing is going on before we free. */ + if (WARN_ON(1)) /* TBD */ + return HTCA_ERROR; + + /* Free everything allocated earlier, including target + * structure and all request structures. + */ + /* TBD: kfree .... */ + + return HTCA_OK; +} diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_recv.c b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_recv.c new file mode 100644 index 000000000000..0d4eae810252 --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_recv.c @@ -0,0 +1,205 @@ +/* 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 +#include +#include +#include +#include + +#include "../hif_sdio/hif.h" +#include "htca.h" +#include "htca_mbox_internal.h" + +/* If there is data available to read on the specified mailbox, + * pull a Mailbox Recv Request off of the PendingRecv queue + * and request HIF to pull data from the mailbox into the + * request's recv buffer. + * + * If we are not aware of data waiting on the endpoint, simply + * return. Note that our awareness is based on slightly stale + * data from Quartz registers. Upper layers insure that we are + * called shortly after data becomes available on an endpoint. + * + * If we exhaust receive buffers, disable the mailbox's interrupt + * until additional buffers are available. + * + * Returns 0 if no request was sent to HIF + * returns 1 if at least one request was sent to HIF + */ +int htca_manage_pending_recvs(struct htca_target *target, int epid) +{ + struct htca_endpoint *end_point; + struct htca_request_queue *recv_queue; + struct htca_mbox_request *mbox_request; + u32 rx_frame_length; + unsigned long flags; + int work_done = 0; + + if (target->pending_recv_mask & (1 << epid)) { + /* Receive operation is already in progress on this endpoint */ + return 0; + } + + end_point = &target->end_point[epid]; + + /* Hand off requests as long as we have both + * something to recv into + * data waiting to be read on the mailbox + */ + + /* rx_frame_length of 0 --> nothing waiting; otherwise, it's + * the length of data waiting to be read, NOT including + * HTCA header nor block padding. + */ + rx_frame_length = end_point->rx_frame_length; + + recv_queue = &end_point->recv_pending_queue; + if (HTCA_IS_QUEUE_EMPTY(recv_queue)) { + htcadebug("no recv buff for ep#%d\n", epid); + /* Not interested in rxdata interrupts + * since we have no recv buffers. + */ + target->enb.int_status_enb &= ~(1 << epid); + + if (rx_frame_length) { + struct htca_event_info event_info; + + htcadebug("frame waiting (%d): %d\n", + epid, rx_frame_length); + /* No buffer ready to receive but data + * is ready. Alert the caller with a + * DATA_AVAILABLE event. + */ + if (!end_point->rx_data_alerted) { + end_point->rx_data_alerted = true; + + htca_frame_event(&event_info, NULL, + rx_frame_length, + 0, HTCA_OK, NULL); + + htca_dispatch_event(target, epid, + HTCA_EVENT_DATA_AVAILABLE, + &event_info); + } + } + return 0; + } + + /* We have recv buffers available, so we are + * interested in rxdata interrupts. + */ + target->enb.int_status_enb |= (1 << epid); + end_point->rx_data_alerted = false; + + if (rx_frame_length == 0) { + htcadebug( + "htca_manage_pending_recvs: buffer available (%d), but no data to recv\n", + epid); + /* We have a buffer but there's nothing + * available on the Target to read. + */ + return 0; + } + + /* There is rxdata waiting and a buffer to read it into */ + + /* Pull the request buffer off the Pending Recv Queue */ + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + mbox_request = + (struct htca_mbox_request *)htca_request_deq_head(recv_queue); + + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + + if (!mbox_request) + goto done; + + htcadebug("ep#%d receiving frame: %d bytes\n", epid, rx_frame_length); + + spin_lock_irqsave(&target->pending_op_lock, flags); + target->pending_recv_mask |= (1 << epid); + spin_unlock_irqrestore(&target->pending_op_lock, flags); + + /* Hand off this Mbox Recv request to HIF */ + mbox_request->actual_length = rx_frame_length; + if (htca_recv_request_to_hif(end_point, mbox_request) == HTCA_ERROR) { + struct htca_event_info event_info; + + /* TBD: Could requeue this at the HEAD of the + * pending recv queue. Try again later? + */ + + /* Frame an event to send to caller */ + htca_frame_event(&event_info, mbox_request->buffer, + mbox_request->buffer_length, + mbox_request->actual_length, HTCA_ECANCELED, + mbox_request->cookie); + + /* Free the Mailbox request */ + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + htca_request_enq_tail(&end_point->recv_free_queue, + (struct htca_request *)mbox_request); + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + + spin_lock_irqsave(&target->pending_op_lock, flags); + target->pending_recv_mask &= ~(1 << epid); + spin_unlock_irqrestore(&target->pending_op_lock, flags); + + htca_dispatch_event(target, epid, HTCA_EVENT_BUFFER_RECEIVED, + &event_info); + goto done; + } else { + work_done = 1; + } + +done: + return work_done; +} + +int htca_recv_request_to_hif(struct htca_endpoint *end_point, + struct htca_mbox_request *mbox_request) +{ + int status; + struct htca_target *target; + u32 padded_length; + u32 mbox_address; + u32 req_type; + + target = end_point->target; + + /* Adjust length for power-of-2 block size */ + padded_length = + htca_round_up(mbox_request->actual_length + HTCA_HEADER_LEN_MAX, + end_point->block_size); + + req_type = (end_point->block_size > 1) ? HIF_RD_ASYNC_BLOCK_INC + : HIF_RD_ASYNC_BYTE_INC; + + mbox_address = end_point->mbox_start_addr; + + status = hif_read_write(target->hif_handle, mbox_address, + &mbox_request->buffer + [HTCA_HEADER_LEN_MAX - HTCA_HEADER_LEN], + padded_length, req_type, mbox_request); + + if (status == HIF_OK && mbox_request->req.completion_cb) { + mbox_request->req.completion_cb( + (struct htca_request *)mbox_request, HTCA_OK); + /* htca_recv_compl */ + } else if (status == HIF_PENDING) { + /* Will complete later */ + } else { /* HIF error */ + return HTCA_ERROR; + } + + return HTCA_OK; +} diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_send.c b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_send.c new file mode 100644 index 000000000000..ebccf72b2144 --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_send.c @@ -0,0 +1,392 @@ +/* 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 +#include +#include +#include +#include + +#include "../hif_sdio/hif.h" +#include "htca.h" +#include "htca_mbox_internal.h" + +/* Decide when an endpoint is low on tx credits and we should + * initiate a credit refresh. If this is set very low, we may + * exhaust credits entirely and pause while we wait for credits + * to be reaped from the Target. If set very high we may end + * up spending excessive time trying to reap when nothing is + * available. + * + * TBD: We could make this something like a percentage of the + * most credits we've ever seen on this endpoint. Or make it + * a value that automatically adjusts -- increase by one whenever + * we exhaust credits; decrease by one whenever a CREDIT_REFRESH + * fails to reap any credits. + * For now, wait until credits are completely exhausted; then + * initiate a credit refresh cycle. + */ +#define HTCA_EP_CREDITS_ARE_LOW(_endp) ((_endp)->tx_credits_available == 0) + +/* Pull as many Mailbox Send Requests off of the PendingSend queue + * as we can (must have a credit for each send) and hand off the + * request to HIF. + * + * This function returns when we exhaust Send Requests OR when we + * exhaust credits. + * + * If we are low on credits, it starts a credit refresh cycle. + * + * Returns 0 if nothing was send to HIF + * returns 1 if at least one request was sent to HIF + */ +int htca_manage_pending_sends(struct htca_target *target, int epid) +{ + struct htca_endpoint *end_point; + struct htca_request_queue *send_queue; + struct htca_mbox_request *mbox_request; + unsigned long flags; + u8 tx_credits_available; + int work_done = 0; + + end_point = &target->end_point[epid]; + send_queue = &end_point->send_pending_queue; + + /* Transmit messages as long as we have both something to send + * tx credits that permit us to send + */ + while (!HTCA_IS_QUEUE_EMPTY(send_queue)) { + spin_lock_irqsave(&end_point->tx_credit_lock, flags); + tx_credits_available = end_point->tx_credits_available; + if (tx_credits_available) + end_point->tx_credits_available--; + spin_unlock_irqrestore(&end_point->tx_credit_lock, flags); + htcadebug("(ep=%d) tx_credits_available=%d\n", + epid, tx_credits_available); + if (!tx_credits_available) { + /* We exhausted tx credits */ + break; + } + + /* Get the request buffer from the Pending Send Queue */ + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + mbox_request = + (struct htca_mbox_request *)htca_request_deq_head( + send_queue); + + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + + if (!mbox_request) + break; + + /* Hand off this Mbox Send request to HIF */ + if (htca_send_request_to_hif(end_point, mbox_request) == + HTCA_ERROR) { + struct htca_event_info event_info; + + /* TBD: Could requeue this at the HEAD of the + * pending send queue. Try again later? + */ + + /* Restore tx credit, since it was not used */ + spin_lock_irqsave(&end_point->tx_credit_lock, flags); + end_point->tx_credits_available++; + spin_unlock_irqrestore(&end_point->tx_credit_lock, + flags); + + /* Frame an event to send to caller */ + htca_frame_event(&event_info, mbox_request->buffer, + mbox_request->buffer_length, + mbox_request->actual_length, + HTCA_ECANCELED, + mbox_request->cookie); + + /* Free the Mailbox request */ + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + htca_request_enq_tail( + &end_point->send_free_queue, + (struct htca_request *)mbox_request); + spin_unlock_irqrestore(&end_point->mbox_queue_lock, + flags); + + htca_dispatch_event( + target, epid, HTCA_EVENT_BUFFER_SENT, &event_info); + goto done; + } + work_done = 1; + } + + htcadebug("ep=%d credsAvail=%d toReap=%d\n", + epid, end_point->tx_credits_available, + end_point->tx_credits_to_reap); + if (HTCA_EP_CREDITS_ARE_LOW(end_point)) { + target->enb.counter_int_status_enb |= (0x10 << epid); + if (end_point->tx_credits_to_reap) + htca_credit_refresh_start(end_point); + } else { + target->enb.counter_int_status_enb &= ~(0x10 << epid); + } + +done: + return work_done; +} + +/* Send one send request to HIF. + * + * Called from the HTCA task while processing requests from + * an endpoint's pendingSendQueue. + * + * Note: May consider calling this in the context of a process + * submitting a new Send Request (i.e. when nothing else is + * pending and credits are available). This would save the + * cost of context switching to the HTCA Work Task; but it would + * require additional synchronization and would add some + * complexity. For the high throughput case this optimization + * would not help since we are likely to have requests + * pending which must be submitted to HIF in the order received. + */ +int htca_send_request_to_hif(struct htca_endpoint *end_point, + struct htca_mbox_request *mbox_request) +{ + int status; + struct htca_target *target; + u32 padded_length; + u32 mbox_address; + u32 req_type; + + target = end_point->target; + + /* Adjust length for power-of-2 block size */ + padded_length = + htca_round_up(mbox_request->actual_length + HTCA_HEADER_LEN_MAX, + end_point->block_size); + + /* Prepend the message's actual length to the outgoing message. + * Caller is REQUIRED to leave HTCA_HEADER_LEN_MAX bytes before + * the message for this purpose (of which the first HTCA_HEADER_LEN + * bytes are actually used). + * + * TBD: We may enhance HIF so that a single write request + * may have TWO consecutive components: one for the HTCA header + * and another for the payload. This would remove the burden + * on callers to reserve space in their buffer for HTCA. + * + * TBD: Since the messaging layer sitting on top of HTCA may + * have this same issue it may make sense to allow a Send + * to pass in a "header buffer" along with a "payload buffer". + * So two buffers (or more generally, a list of buffers) + * rather than one on each call. These buffers would be + * guaranteed to be sent to HIF as a group and they would + * be sent over SDIO back to back. + */ + mbox_request->buffer -= HTCA_HEADER_LEN_MAX; + + if (HTCA_HEADER_LEN_MAX > HTCA_HEADER_LEN) { + /* Sanity: clear padding bytes, if used */ + memset(&mbox_request->buffer[HTCA_HEADER_LEN], 0, + HTCA_HEADER_LEN_MAX - HTCA_HEADER_LEN); + } + /* Target receives length in LittleEndian byte order + * regardeless of Host endianness. + */ + mbox_request->buffer[0] = mbox_request->actual_length & 0xff; + mbox_request->buffer[1] = (mbox_request->actual_length >> 8) & 0xff; + + req_type = (end_point->block_size > 1) ? HIF_WR_ASYNC_BLOCK_INC + : HIF_WR_ASYNC_BYTE_INC; + + /* Arrange for last byte of the message to generate an + * EndOfMessage interrupt to the Target. + */ + mbox_address = end_point->mbox_end_addr - padded_length; + + /* Send the request to HIF */ + status = hif_read_write(target->hif_handle, mbox_address, + mbox_request->buffer, padded_length, req_type, + mbox_request); + + if (status == HIF_OK && mbox_request->req.completion_cb) { + mbox_request->req.completion_cb( + (struct htca_request *)mbox_request, HTCA_OK); + /* htcaSendCompletionCB */ + } else if (status == HIF_PENDING) { + /* Will complete later */ + } else { /* HIF error */ + /* Restore mbox_request buffer */ + mbox_request->buffer += HTCA_HEADER_LEN_MAX; + return HTCA_ERROR; + } + + return HTCA_OK; +} + +/* Start a credit refresh cycle. Credits will appear in + * end_point->tx_credits_available when this refresh completes. + * + * Called in the context of the work_task when we are unable + * to send any more requests because credits are exhausted. + * Also called from HIF completion's context when a credit + * interrupt occurs. + * + * TBD: Consider HTCA v2 features: Quartz FW can send + * in-band TX Credit hint + * RX Length hint + * interrupt status registers + * as opportunistic trailer(s) on an RX message. + * This increases code complexity but may reduce overhead + * since we may reduce the number of explicit SDIO register + * read operations which are relatively expensive "byte basis" + * operations. + */ +int htca_credit_refresh_start(struct htca_endpoint *end_point) +{ + u8 end_point_id; + int status; + struct htca_target *target; + struct htca_reg_request *reg_request; + unsigned long flags; + bool already_in_progress; + u32 address; + + htcadebug("Enter\n"); + + spin_lock_irqsave(&end_point->tx_credit_lock, flags); + already_in_progress = end_point->tx_credit_refresh_in_progress; + end_point->tx_credit_refresh_in_progress = true; + spin_unlock_irqrestore(&end_point->tx_credit_lock, flags); + + if (already_in_progress) + return 0; + + target = end_point->target; + end_point_id = get_endpoint_id(end_point); + htcadebug("on endpoint %d\n", end_point_id); + + spin_lock_irqsave(&target->reg_queue_lock, flags); + reg_request = (struct htca_reg_request *)htca_request_deq_head( + &target->reg_free_queue); + spin_unlock_irqrestore(&target->reg_queue_lock, flags); + + if (!reg_request) { + WARN_ON(1); + return 1; + } + + if (WARN_ON(reg_request->purpose != UNUSED_PURPOSE)) + return 1; + + reg_request->buffer = NULL; + reg_request->length = 0; + reg_request->purpose = CREDIT_REFRESH; + reg_request->epid = end_point_id; + + address = get_reg_addr(TX_CREDIT_COUNTER_DECREMENT_REG, end_point_id); + + /* Note: reading many times FROM a FIXed register address, the + * "atomic decrement address". The function htca_credit_refresh_compl + * examines the results upon completion. + */ + status = hif_read_write( + target->hif_handle, address, reg_request->u.credit_dec_results, + HTCA_TX_CREDITS_REAP_MAX, HIF_RD_ASYNC_BYTE_FIX, reg_request); + if (status == HIF_OK && reg_request->req.completion_cb) { + reg_request->req.completion_cb( + (struct htca_request *)reg_request, HIF_OK); + /* htca_credit_refresh_compl */ + } else if (status == HIF_PENDING) { + /* Will complete later */ + } else { /* HIF error */ + WARN_ON(1); + } + return 1; +} + +/* Used during Configuration Negotiation at startup + * to configure max message sizes for each endpoint. + * + * Returns true if all endpoints have been configured, + * by this pass and/or all earlier calls. (Typically + * there should be only a single call which enables + * all endpoints at once.) + * + * Returns false if at least one endpoint has not + * yet been configured. + */ +bool htca_negotiate_config(struct htca_target *target) +{ + int status; + struct htca_endpoint *end_point; + u32 address; + int enb_count = 0; + int ep; + + htcadebug("Enter\n"); + + /* The Target should have posted 1 credit to + * each endpoint by the time we reach here. + */ + for (ep = 0; ep < HTCA_NUM_MBOX; ep++) { + end_point = &target->end_point[ep]; + if (end_point->enabled) { + /* This endpoint was already enabled */ + enb_count++; + continue; + } + htcadebug("try epid=%d\n", ep); + + address = get_reg_addr(TX_CREDIT_COUNTER_DECREMENT_REG, ep); + end_point->tx_credits_available = 0; + status = + hif_read_write(target->hif_handle, address, + (u8 *)&end_point->tx_credits_available, + 1, HIF_RD_SYNC_BYTE_FIX, NULL); + if (status != HIF_OK) { + htcadebug("DBG: address=0x%08x status=%d\n", address, + status); + } + if (WARN_ON(status != HIF_OK)) + return false; + + if (!end_point->tx_credits_available) { + /* not yet ready -- no credit posted. Odd case. */ + continue; + } + if (WARN_ON(end_point->tx_credits_available != 1)) + return false; + + end_point->tx_credits_available--; + + /* TBD: Tacitly assumes LittleEndian Host. + * This -- rather than an explicit Host interrupt -- is + * what should trigger Target to fetch blocksize. + */ + htcadebug("good to go epid=%d\n", ep); + + /* "Negotiate" the message size for this endpoint by writing + * the maximum message size (and trigger EOM). + */ + address = + end_point->mbox_end_addr - sizeof(end_point->max_msg_sz); + status = hif_read_write(target->hif_handle, address, + (u8 *)&end_point->max_msg_sz, + sizeof(end_point->max_msg_sz), + HIF_WR_SYNC_BYTE_INC, NULL); + if (WARN_ON(status != HIF_OK)) + return false; + + end_point->enabled = true; + enb_count++; + } + + htcadebug("enb_count=%d\n", enb_count); + return (enb_count == HTCA_NUM_MBOX); +} diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_task.c b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_task.c new file mode 100644 index 000000000000..6598cbae4ed4 --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_task.c @@ -0,0 +1,340 @@ +/* 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. + */ + +/* Implementation of Host Target Communication tasks, + * WorkTask and compl_task, which are used to manage + * the Mbox Pending Queues. + * + * A mailbox Send request is queued in arrival order on + * a per-mailbox Send queue until a credit is available + * from the Target. Requests in this queue are + * waiting for the Target to provide tx credits (i.e. recv + * buffers on the Target-side). + * + * A mailbox Recv request is queued in arrival order on + * a per-mailbox Recv queue until a message is available + * to be read. So requests in this queue are waiting for + * the Target to provide rx data. + * + * htca_work_task dequeues requests from the SendPendingQueue + * (once credits are available) and dequeues requests from + * the RecvPendingQueue (once rx data is available) and + * hands them to HIF for processing. + * + * htca_compl_task handles completion processing after + * HIF completes a request. + * + * The main purpose of these tasks is to provide a + * suitable suspendable context for processing requests + * and completions. + */ + +#include +#include +#include +#include +#include +#include + +#include "../hif_sdio/hif.h" +#include "htca.h" +#include "htca_mbox_internal.h" + +/* Wakeup the htca_work_task. + * + * Invoked whenever send/recv state changes: + * new Send buffer added to the send_pending_queue + * new Recv buffer added to the recv_pending_queue + * tx credits are reaped + * rx data available recognized + */ +void htca_work_task_poke(struct htca_target *target) +{ + target->work_task_has_work = true; + wake_up_interruptible_sync(&target->work_task_wait); +} + +/* Body of the htca_work_task, which hands Send and + * Receive requests to HIF. + */ +static int htca_work_task_core(struct htca_target *target) +{ + int ep; + int work_done = 0; + + /* TBD: We might consider alternative ordering policies, here, + * between Sends and Recvs and among mailboxes. The current + * algorithm is simple. + */ + + /* Process sends/recvs */ + for (ep = 0; ep < HTCA_NUM_MBOX; ep++) { + htcadebug("Call (%d)\n", ep); + work_done += htca_manage_pending_sends(target, ep); + htcadebug("Call (%d)\n", ep); + work_done += htca_manage_pending_recvs(target, ep); + } + + return work_done; +} + +/* Only this work_task is permitted to update + * interrupt enables. That restriction eliminates + * complex race conditions. + */ +static int htca_work_task(void *param) +{ + struct htca_target *target = (struct htca_target *)param; + + /* set_user_nice(current, -3); */ + set_current_state(TASK_INTERRUPTIBLE); + + for (;;) { + htcadebug("top of loop. intr_state=%d\n", target->intr_state); + /* Wait for htca_work_task_poke */ + wait_event_interruptible(target->work_task_wait, + target->work_task_has_work); + + if (target->work_task_shutdown) + break; /* htcaTaskStop invoked */ + + if (!target->work_task_has_work) + break; /* exit, if this task was interrupted */ + + /* reset before we start work */ + target->work_task_has_work = false; + barrier(); + + if (target->need_start_polling) { + /* reset for next time */ + target->need_start_polling = 0; + target->intr_state = HTCA_POLL; + htca_update_intr_enbs(target, 1); + } + + while (htca_work_task_core(target)) + ; + + if (target->pending_recv_mask || + target->pending_register_refresh) { + continue; + } + + /* When a Recv completes, it sets need_register_refresh=1 + * and pokes the work_task. + * + * We won't actually initiate a register refresh until + * pending recvs on ALL eps have completed. This may + * increase latency slightly but it increases efficiency + * and reduces chatter which should improve throughput. + * Note that even though we don't initiate the register + * refresh immediately, SDIO is still 100% busy doing + * useful work. The refresh is issued shortly after. + */ + if (target->need_register_refresh) { + /* Continue to poll. When the RegsiterRefresh + * completes, the WorkTask will be poked. + */ + target->need_register_refresh = 0; + htca_register_refresh_start(target); + continue; + } + + /* If more work has arrived since we last checked, + * make another pass. + */ + if (target->work_task_has_work) + continue; + + /* As long as we are constantly refreshing register + * state and reprocessing, there is no need to + * enable interrupts. We are essentially POLLING for + * interrupts anyway. But if + * -we were in POLL mode and + * -we have processed all outstanding sends/recvs and + * -there are no PENDING recv operations and + * -there is no pending register refresh (so + * no recv operations have completed since the + * last time we refreshed register state) + * then we switch to INTERRUPT mode and re-enable + * Target-side interrupts. + * + * We'll sleep until poked: + * -DSR handler receives an interrupt + * -application enqueues a new send/recv buffer + * We must also UPDATE interrupt enables even if we + * were already in INTERRUPT mode, since some bits + * may have changed. + */ + if (target->intr_state == HTCA_POLL) { + target->intr_state = HTCA_INTERRUPT; + htca_update_intr_enbs(target, 0); + } + } + complete_and_exit(&target->work_task_completion, 0); + + return 0; +} + +int htca_work_task_start(struct htca_target *target) +{ + int status = HTCA_ERROR; + + if (mutex_lock_interruptible(&target->task_mutex)) + return HTCA_ERROR; /* interrupted */ + + if (target->work_task) + goto done; /* already started */ + + target->work_task = kthread_create(htca_work_task, target, "htcaWork"); + if (!target->work_task) + goto done; /* Failed to create task */ + + target->work_task_shutdown = false; + init_waitqueue_head(&target->work_task_wait); + init_completion(&target->work_task_completion); + wake_up_process(target->work_task); + status = HTCA_OK; + +done: + mutex_unlock(&target->task_mutex); + return status; +} + +void htca_work_task_stop(struct htca_target *target) +{ + if (mutex_lock_interruptible(&target->task_mutex)) + return; /* interrupted */ + + if (!target->work_task) + goto done; + + target->work_task_shutdown = true; + htca_work_task_poke(target); + wait_for_completion(&target->work_task_completion); + target->work_task = NULL; + +done: + mutex_unlock(&target->task_mutex); +} + +/* Wakeup the compl_task. + * Invoked after adding a new completion to the compl_queue. + */ +void htca_compl_task_poke(struct htca_target *target) +{ + target->compl_task_has_work = true; + wake_up_interruptible_sync(&target->compl_task_wait); +} + +static int htca_manage_compl(struct htca_target *target) +{ + struct htca_request *req; + unsigned long flags; + + /* Pop a request from the completion queue */ + spin_lock_irqsave(&target->compl_queue_lock, flags); + req = htca_request_deq_head(&target->compl_queue); + spin_unlock_irqrestore(&target->compl_queue_lock, flags); + + if (!req) + return 0; /* nothing to do */ + + /* Invoke request's corresponding completion function */ + if (req->completion_cb) + req->completion_cb(req, req->status); + + return 1; +} + +static int htca_compl_task(void *param) +{ + struct htca_target *target = (struct htca_target *)param; + + /* set_user_nice(current, -3); */ + set_current_state(TASK_INTERRUPTIBLE); + + for (;;) { + /* Wait for htca_compl_task_poke */ + wait_event_interruptible(target->compl_task_wait, + target->compl_task_has_work); + if (target->compl_task_shutdown) + break; /* htcaTaskStop invoked */ + + if (!target->compl_task_has_work) + break; /* exit, if this task was interrupted */ + + /* reset before we start work */ + target->compl_task_has_work = false; + barrier(); + + /* TBD: We could try to prioritize completions rather than + * handle them strictly in order. Could use separate queues for + * register completions and mailbox completion on each endpoint. + * In general, completion processing is expected to be short + * so this probably isn't worth the additional complexity. + */ + { + int did_work; + + do { + did_work = htca_manage_compl(target); + } while (did_work); + } + } + complete_and_exit(&target->compl_cask_completion, 0); + + return 0; +} + +int htca_compl_task_start(struct htca_target *target) +{ + int status = HTCA_ERROR; + + if (mutex_lock_interruptible(&target->task_mutex)) + return HTCA_ERROR; /* interrupted */ + + if (target->compl_task) + goto done; /* already started */ + + target->compl_task = + kthread_create(htca_compl_task, target, "htcaCompl"); + if (!target->compl_task) + goto done; /* Failed to create task */ + + target->compl_task_shutdown = false; + init_waitqueue_head(&target->compl_task_wait); + init_completion(&target->compl_cask_completion); + wake_up_process(target->compl_task); + status = HTCA_OK; + +done: + mutex_unlock(&target->task_mutex); + return status; +} + +void htca_compl_task_stop(struct htca_target *target) +{ + if (mutex_lock_interruptible(&target->task_mutex)) + return; /* interrupted */ + + if (!target->compl_task) + goto done; + + target->compl_task_shutdown = true; + htca_compl_task_poke(target); + wait_for_completion(&target->compl_cask_completion); + target->compl_task = NULL; + +done: + mutex_unlock(&target->task_mutex); +} diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_utils.c b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_utils.c new file mode 100644 index 000000000000..4cf137c89d75 --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_utils.c @@ -0,0 +1,182 @@ +/* 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 +#include +#include +#include +#include + +#include "../hif_sdio/hif.h" +#include "htca.h" +#include "htca_mbox_internal.h" + +/* HTCA utility routines */ + +/* Invoked when shutting down */ +void htca_mbox_queue_flush(struct htca_endpoint *end_point, + struct htca_request_queue *pending_queue, + struct htca_request_queue *free_queue, + u8 event_id) +{ + struct htca_event_info event_info; + u8 end_point_id; + struct htca_target *target; + struct htca_mbox_request *mbox_request; + unsigned long flags; + + target = end_point->target; + end_point_id = get_endpoint_id(end_point); + + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + for (;;) { + mbox_request = + (struct htca_mbox_request *)htca_request_deq_head( + pending_queue); + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + + if (!mbox_request) + break; + + htca_frame_event(&event_info, mbox_request->buffer, + mbox_request->buffer_length, 0, HTCA_ECANCELED, + mbox_request->cookie); + + htca_dispatch_event(target, end_point_id, event_id, + &event_info); + + /* Recycle the request */ + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + htca_request_enq_tail(free_queue, + (struct htca_request *)mbox_request); + } + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); +} + +struct htca_target *htca_target_instance(int i) +{ + return htca_target_list[i]; +} + +void htca_target_instance_add(struct htca_target *target) +{ + int i; + + for (i = 0; i < HTCA_NUM_DEVICES_MAX; i++) { + if (!htca_target_list[i]) { + htca_target_list[i] = target; + break; + } + } + WARN_ON(i >= HTCA_NUM_DEVICES_MAX); +} + +void htca_target_instance_remove(struct htca_target *target) +{ + int i; + + for (i = 0; i < HTCA_NUM_DEVICES_MAX; i++) { + if (htca_target_list[i] == target) { + htca_target_list[i] = NULL; + break; + } + } + WARN_ON(i >= HTCA_NUM_DEVICES_MAX); +} + +/* Add a request to the tail of a queue. + * Caller must handle any locking required. + * TBD: Use Linux queue support + */ +void htca_request_enq_tail(struct htca_request_queue *queue, + struct htca_request *req) +{ + req->next = NULL; + + if (queue->tail) + queue->tail->next = (void *)req; + else + queue->head = req; + + queue->tail = req; +} + +/* Remove a request from the start of a queue. + * Caller must handle any locking required. + * TBD: Use Linux queue support + * TBD: If cannot allocate from FREE queue, caller may add more elements. + */ +struct htca_request *htca_request_deq_head(struct htca_request_queue *queue) +{ + struct htca_request *req; + + req = queue->head; + if (!req) + return NULL; + + queue->head = req->next; + if (!queue->head) + queue->tail = NULL; + req->next = NULL; + + return req; +} + +/* Start a Register Refresh cycle. + * + * Submits a request to fetch ALL relevant registers from Target. + * When this completes, we'll take actions based on the new + * register values. + */ +void htca_register_refresh_start(struct htca_target *target) +{ + int status; + struct htca_reg_request *reg_request; + u32 address; + unsigned long flags; + + htcadebug("Enter\n"); + spin_lock_irqsave(&target->reg_queue_lock, flags); + reg_request = (struct htca_reg_request *)htca_request_deq_head( + &target->reg_free_queue); + spin_unlock_irqrestore(&target->reg_queue_lock, flags); + if (!reg_request) { + WARN_ON(1); + return; + } + if (WARN_ON(reg_request->purpose != UNUSED_PURPOSE)) + return; + + spin_lock_irqsave(&target->pending_op_lock, flags); + target->pending_register_refresh++; + spin_unlock_irqrestore(&target->pending_op_lock, flags); + + reg_request->buffer = (u8 *)®_request->u.reg_table; + reg_request->length = sizeof(reg_request->u.reg_table); + reg_request->purpose = INTR_REFRESH; + reg_request->epid = 0; /* not used */ + + address = get_reg_addr(ALL_STATUS_REG, ENDPOINT_UNUSED); + status = hif_read_write(target->hif_handle, address, + ®_request->u.reg_table, + sizeof(reg_request->u.reg_table), + HIF_RD_ASYNC_BYTE_INC, reg_request); + if (status == HIF_OK && reg_request->req.completion_cb) { + reg_request->req.completion_cb( + (struct htca_request *)reg_request, HIF_OK); + /* htca_register_refresh_compl */ + } else if (status == HIF_PENDING) { + /* Will complete later */ + } else { /* HIF error */ + WARN_ON(1); + } +} diff --git a/drivers/net/wireless/qca402x/htca_mbox/mbox_host_reg.h b/drivers/net/wireless/qca402x/htca_mbox/mbox_host_reg.h new file mode 100644 index 000000000000..81ce6325eeb8 --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/mbox_host_reg.h @@ -0,0 +1,412 @@ +/* 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 _MBOX_HOST_REG_REG_H_ +#define _MBOX_HOST_REG_REG_H_ + +/* TBD: REMOVE things that are not needed, especially Diag Window */ + +#define HOST_INT_STATUS_ADDRESS 0x00000400 +#define HOST_INT_STATUS_OFFSET 0x00000400 +#define HOST_INT_STATUS_ERROR_MSB 7 +#define HOST_INT_STATUS_ERROR_LSB 7 +#define HOST_INT_STATUS_ERROR_MASK 0x00000080 +#define HOST_INT_STATUS_ERROR_GET(x) \ + (((x) & HOST_INT_STATUS_ERROR_MASK) >> HOST_INT_STATUS_ERROR_LSB) +#define HOST_INT_STATUS_ERROR_SET(x) \ + (((x) << HOST_INT_STATUS_ERROR_LSB) & HOST_INT_STATUS_ERROR_MASK) +#define HOST_INT_STATUS_CPU_MSB 6 +#define HOST_INT_STATUS_CPU_LSB 6 +#define HOST_INT_STATUS_CPU_MASK 0x00000040 +#define HOST_INT_STATUS_CPU_GET(x) \ + (((x) & HOST_INT_STATUS_CPU_MASK) >> HOST_INT_STATUS_CPU_LSB) +#define HOST_INT_STATUS_CPU_SET(x) \ + (((x) << HOST_INT_STATUS_CPU_LSB) & HOST_INT_STATUS_CPU_MASK) +#define HOST_INT_STATUS_DRAGON_INT_MSB 5 +#define HOST_INT_STATUS_DRAGON_INT_LSB 5 +#define HOST_INT_STATUS_DRAGON_INT_MASK 0x00000020 +#define HOST_INT_STATUS_DRAGON_INT_GET(x) \ + (((x) & HOST_INT_STATUS_DRAGON_INT_MASK) >> \ + HOST_INT_STATUS_DRAGON_INT_LSB) +#define HOST_INT_STATUS_DRAGON_INT_SET(x) \ + (((x) << HOST_INT_STATUS_DRAGON_INT_LSB) & \ + HOST_INT_STATUS_DRAGON_INT_MASK) +#define HOST_INT_STATUS_COUNTER_MSB 4 +#define HOST_INT_STATUS_COUNTER_LSB 4 +#define HOST_INT_STATUS_COUNTER_MASK 0x00000010 +#define HOST_INT_STATUS_COUNTER_GET(x) \ + (((x) & HOST_INT_STATUS_COUNTER_MASK) >> HOST_INT_STATUS_COUNTER_LSB) +#define HOST_INT_STATUS_COUNTER_SET(x) \ + (((x) << HOST_INT_STATUS_COUNTER_LSB) & HOST_INT_STATUS_COUNTER_MASK) +#define HOST_INT_STATUS_MBOX_DATA_MSB 3 +#define HOST_INT_STATUS_MBOX_DATA_LSB 0 +#define HOST_INT_STATUS_MBOX_DATA_MASK 0x0000000f +#define HOST_INT_STATUS_MBOX_DATA_GET(x) \ + (((x) & HOST_INT_STATUS_MBOX_DATA_MASK) >> \ + HOST_INT_STATUS_MBOX_DATA_LSB) +#define HOST_INT_STATUS_MBOX_DATA_SET(x) \ + (((x) << HOST_INT_STATUS_MBOX_DATA_LSB) & \ + HOST_INT_STATUS_MBOX_DATA_MASK) + +#define CPU_INT_STATUS_ADDRESS 0x00000401 +#define CPU_INT_STATUS_OFFSET 0x00000401 +#define CPU_INT_STATUS_BIT_MSB 7 +#define CPU_INT_STATUS_BIT_LSB 0 +#define CPU_INT_STATUS_BIT_MASK 0x000000ff +#define CPU_INT_STATUS_BIT_GET(x) \ + (((x) & CPU_INT_STATUS_BIT_MASK) >> CPU_INT_STATUS_BIT_LSB) +#define CPU_INT_STATUS_BIT_SET(x) \ + (((x) << CPU_INT_STATUS_BIT_LSB) & CPU_INT_STATUS_BIT_MASK) + +#define ERROR_INT_STATUS_ADDRESS 0x00000402 +#define ERROR_INT_STATUS_OFFSET 0x00000402 +#define ERROR_INT_STATUS_SPI_MSB 3 +#define ERROR_INT_STATUS_SPI_LSB 3 +#define ERROR_INT_STATUS_SPI_MASK 0x00000008 +#define ERROR_INT_STATUS_SPI_GET(x) \ + (((x) & ERROR_INT_STATUS_SPI_MASK) >> ERROR_INT_STATUS_SPI_LSB) +#define ERROR_INT_STATUS_SPI_SET(x) \ + (((x) << ERROR_INT_STATUS_SPI_LSB) & ERROR_INT_STATUS_SPI_MASK) +#define ERROR_INT_STATUS_WAKEUP_MSB 2 +#define ERROR_INT_STATUS_WAKEUP_LSB 2 +#define ERROR_INT_STATUS_WAKEUP_MASK 0x00000004 +#define ERROR_INT_STATUS_WAKEUP_GET(x) \ + (((x) & ERROR_INT_STATUS_WAKEUP_MASK) >> ERROR_INT_STATUS_WAKEUP_LSB) +#define ERROR_INT_STATUS_WAKEUP_SET(x) \ + (((x) << ERROR_INT_STATUS_WAKEUP_LSB) & ERROR_INT_STATUS_WAKEUP_MASK) +#define ERROR_INT_STATUS_RX_UNDERFLOW_MSB 1 +#define ERROR_INT_STATUS_RX_UNDERFLOW_LSB 1 +#define ERROR_INT_STATUS_RX_UNDERFLOW_MASK 0x00000002 +#define ERROR_INT_STATUS_RX_UNDERFLOW_GET(x) \ + (((x) & ERROR_INT_STATUS_RX_UNDERFLOW_MASK) >> \ + ERROR_INT_STATUS_RX_UNDERFLOW_LSB) +#define ERROR_INT_STATUS_RX_UNDERFLOW_SET(x) \ + (((x) << ERROR_INT_STATUS_RX_UNDERFLOW_LSB) & \ + ERROR_INT_STATUS_RX_UNDERFLOW_MASK) +#define ERROR_INT_STATUS_TX_OVERFLOW_MSB 0 +#define ERROR_INT_STATUS_TX_OVERFLOW_LSB 0 +#define ERROR_INT_STATUS_TX_OVERFLOW_MASK 0x00000001 +#define ERROR_INT_STATUS_TX_OVERFLOW_GET(x) \ + (((x) & ERROR_INT_STATUS_TX_OVERFLOW_MASK) >> \ + ERROR_INT_STATUS_TX_OVERFLOW_LSB) +#define ERROR_INT_STATUS_TX_OVERFLOW_SET(x) \ + (((x) << ERROR_INT_STATUS_TX_OVERFLOW_LSB) & \ + ERROR_INT_STATUS_TX_OVERFLOW_MASK) + +#define COUNTER_INT_STATUS_ADDRESS 0x00000403 +#define COUNTER_INT_STATUS_OFFSET 0x00000403 +#define COUNTER_INT_STATUS_COUNTER_MSB 7 +#define COUNTER_INT_STATUS_COUNTER_LSB 0 +#define COUNTER_INT_STATUS_COUNTER_MASK 0x000000ff +#define COUNTER_INT_STATUS_COUNTER_GET(x) \ + (((x) & COUNTER_INT_STATUS_COUNTER_MASK) >> \ + COUNTER_INT_STATUS_COUNTER_LSB) +#define COUNTER_INT_STATUS_COUNTER_SET(x) \ + (((x) << COUNTER_INT_STATUS_COUNTER_LSB) & \ + COUNTER_INT_STATUS_COUNTER_MASK) + +#define MBOX_FRAME_ADDRESS 0x00000404 +#define MBOX_FRAME_OFFSET 0x00000404 +#define MBOX_FRAME_RX_EOM_MSB 7 +#define MBOX_FRAME_RX_EOM_LSB 4 +#define MBOX_FRAME_RX_EOM_MASK 0x000000f0 +#define MBOX_FRAME_RX_EOM_GET(x) \ + (((x) & MBOX_FRAME_RX_EOM_MASK) >> MBOX_FRAME_RX_EOM_LSB) +#define MBOX_FRAME_RX_EOM_SET(x) \ + (((x) << MBOX_FRAME_RX_EOM_LSB) & MBOX_FRAME_RX_EOM_MASK) +#define MBOX_FRAME_RX_SOM_MSB 3 +#define MBOX_FRAME_RX_SOM_LSB 0 +#define MBOX_FRAME_RX_SOM_MASK 0x0000000f +#define MBOX_FRAME_RX_SOM_GET(x) \ + (((x) & MBOX_FRAME_RX_SOM_MASK) >> MBOX_FRAME_RX_SOM_LSB) +#define MBOX_FRAME_RX_SOM_SET(x) \ + (((x) << MBOX_FRAME_RX_SOM_LSB) & MBOX_FRAME_RX_SOM_MASK) + +#define RX_LOOKAHEAD_VALID_ADDRESS 0x00000405 +#define RX_LOOKAHEAD_VALID_OFFSET 0x00000405 +#define RX_LOOKAHEAD_VALID_MBOX_MSB 3 +#define RX_LOOKAHEAD_VALID_MBOX_LSB 0 +#define RX_LOOKAHEAD_VALID_MBOX_MASK 0x0000000f +#define RX_LOOKAHEAD_VALID_MBOX_GET(x) \ + (((x) & RX_LOOKAHEAD_VALID_MBOX_MASK) >> RX_LOOKAHEAD_VALID_MBOX_LSB) +#define RX_LOOKAHEAD_VALID_MBOX_SET(x) \ + (((x) << RX_LOOKAHEAD_VALID_MBOX_LSB) & RX_LOOKAHEAD_VALID_MBOX_MASK) + +#define RX_LOOKAHEAD0_ADDRESS 0x00000408 +#define RX_LOOKAHEAD0_OFFSET 0x00000408 +#define RX_LOOKAHEAD0_DATA_MSB 7 +#define RX_LOOKAHEAD0_DATA_LSB 0 +#define RX_LOOKAHEAD0_DATA_MASK 0x000000ff +#define RX_LOOKAHEAD0_DATA_GET(x) \ + (((x) & RX_LOOKAHEAD0_DATA_MASK) >> RX_LOOKAHEAD0_DATA_LSB) +#define RX_LOOKAHEAD0_DATA_SET(x) \ + (((x) << RX_LOOKAHEAD0_DATA_LSB) & RX_LOOKAHEAD0_DATA_MASK) + +#define RX_LOOKAHEAD1_ADDRESS 0x0000040c +#define RX_LOOKAHEAD1_OFFSET 0x0000040c +#define RX_LOOKAHEAD1_DATA_MSB 7 +#define RX_LOOKAHEAD1_DATA_LSB 0 +#define RX_LOOKAHEAD1_DATA_MASK 0x000000ff +#define RX_LOOKAHEAD1_DATA_GET(x) \ + (((x) & RX_LOOKAHEAD1_DATA_MASK) >> RX_LOOKAHEAD1_DATA_LSB) +#define RX_LOOKAHEAD1_DATA_SET(x) \ + (((x) << RX_LOOKAHEAD1_DATA_LSB) & RX_LOOKAHEAD1_DATA_MASK) + +#define RX_LOOKAHEAD2_ADDRESS 0x00000410 +#define RX_LOOKAHEAD2_OFFSET 0x00000410 +#define RX_LOOKAHEAD2_DATA_MSB 7 +#define RX_LOOKAHEAD2_DATA_LSB 0 +#define RX_LOOKAHEAD2_DATA_MASK 0x000000ff +#define RX_LOOKAHEAD2_DATA_GET(x) \ + (((x) & RX_LOOKAHEAD2_DATA_MASK) >> RX_LOOKAHEAD2_DATA_LSB) +#define RX_LOOKAHEAD2_DATA_SET(x) \ + (((x) << RX_LOOKAHEAD2_DATA_LSB) & RX_LOOKAHEAD2_DATA_MASK) + +#define RX_LOOKAHEAD3_ADDRESS 0x00000414 +#define RX_LOOKAHEAD3_OFFSET 0x00000414 +#define RX_LOOKAHEAD3_DATA_MSB 7 +#define RX_LOOKAHEAD3_DATA_LSB 0 +#define RX_LOOKAHEAD3_DATA_MASK 0x000000ff +#define RX_LOOKAHEAD3_DATA_GET(x) \ + (((x) & RX_LOOKAHEAD3_DATA_MASK) >> RX_LOOKAHEAD3_DATA_LSB) +#define RX_LOOKAHEAD3_DATA_SET(x) \ + (((x) << RX_LOOKAHEAD3_DATA_LSB) & RX_LOOKAHEAD3_DATA_MASK) + +#define INT_STATUS_ENABLE_ADDRESS 0x00000418 +#define INT_STATUS_ENABLE_OFFSET 0x00000418 +#define INT_STATUS_ENABLE_ERROR_MSB 7 +#define INT_STATUS_ENABLE_ERROR_LSB 7 +#define INT_STATUS_ENABLE_ERROR_MASK 0x00000080 +#define INT_STATUS_ENABLE_ERROR_GET(x) \ + (((x) & INT_STATUS_ENABLE_ERROR_MASK) >> INT_STATUS_ENABLE_ERROR_LSB) +#define INT_STATUS_ENABLE_ERROR_SET(x) \ + (((x) << INT_STATUS_ENABLE_ERROR_LSB) & INT_STATUS_ENABLE_ERROR_MASK) +#define INT_STATUS_ENABLE_CPU_MSB 6 +#define INT_STATUS_ENABLE_CPU_LSB 6 +#define INT_STATUS_ENABLE_CPU_MASK 0x00000040 +#define INT_STATUS_ENABLE_CPU_GET(x) \ + (((x) & INT_STATUS_ENABLE_CPU_MASK) >> INT_STATUS_ENABLE_CPU_LSB) +#define INT_STATUS_ENABLE_CPU_SET(x) \ + (((x) << INT_STATUS_ENABLE_CPU_LSB) & INT_STATUS_ENABLE_CPU_MASK) +#define INT_STATUS_ENABLE_DRAGON_INT_MSB 5 +#define INT_STATUS_ENABLE_DRAGON_INT_LSB 5 +#define INT_STATUS_ENABLE_DRAGON_INT_MASK 0x00000020 +#define INT_STATUS_ENABLE_DRAGON_INT_GET(x) \ + (((x) & INT_STATUS_ENABLE_DRAGON_INT_MASK) >> \ + INT_STATUS_ENABLE_DRAGON_INT_LSB) +#define INT_STATUS_ENABLE_DRAGON_INT_SET(x) \ + (((x) << INT_STATUS_ENABLE_DRAGON_INT_LSB) & \ + INT_STATUS_ENABLE_DRAGON_INT_MASK) +#define INT_STATUS_ENABLE_COUNTER_MSB 4 +#define INT_STATUS_ENABLE_COUNTER_LSB 4 +#define INT_STATUS_ENABLE_COUNTER_MASK 0x00000010 +#define INT_STATUS_ENABLE_COUNTER_GET(x) \ + (((x) & INT_STATUS_ENABLE_COUNTER_MASK) >> \ + INT_STATUS_ENABLE_COUNTER_LSB) +#define INT_STATUS_ENABLE_COUNTER_SET(x) \ + (((x) << INT_STATUS_ENABLE_COUNTER_LSB) & \ + INT_STATUS_ENABLE_COUNTER_MASK) +#define INT_STATUS_ENABLE_MBOX_DATA_MSB 3 +#define INT_STATUS_ENABLE_MBOX_DATA_LSB 0 +#define INT_STATUS_ENABLE_MBOX_DATA_MASK 0x0000000f +#define INT_STATUS_ENABLE_MBOX_DATA_GET(x) \ + (((x) & INT_STATUS_ENABLE_MBOX_DATA_MASK) >> \ + INT_STATUS_ENABLE_MBOX_DATA_LSB) +#define INT_STATUS_ENABLE_MBOX_DATA_SET(x) \ + (((x) << INT_STATUS_ENABLE_MBOX_DATA_LSB) & \ + INT_STATUS_ENABLE_MBOX_DATA_MASK) + +#define CPU_INT_STATUS_ENABLE_ADDRESS 0x00000419 +#define CPU_INT_STATUS_ENABLE_OFFSET 0x00000419 +#define CPU_INT_STATUS_ENABLE_BIT_MSB 7 +#define CPU_INT_STATUS_ENABLE_BIT_LSB 0 +#define CPU_INT_STATUS_ENABLE_BIT_MASK 0x000000ff +#define CPU_INT_STATUS_ENABLE_BIT_GET(x) \ + (((x) & CPU_INT_STATUS_ENABLE_BIT_MASK) >> \ + CPU_INT_STATUS_ENABLE_BIT_LSB) +#define CPU_INT_STATUS_ENABLE_BIT_SET(x) \ + (((x) << CPU_INT_STATUS_ENABLE_BIT_LSB) & \ + CPU_INT_STATUS_ENABLE_BIT_MASK) + +#define ERROR_STATUS_ENABLE_ADDRESS 0x0000041a +#define ERROR_STATUS_ENABLE_OFFSET 0x0000041a +#define ERROR_STATUS_ENABLE_WAKEUP_MSB 2 +#define ERROR_STATUS_ENABLE_WAKEUP_LSB 2 +#define ERROR_STATUS_ENABLE_WAKEUP_MASK 0x00000004 +#define ERROR_STATUS_ENABLE_WAKEUP_GET(x) \ + (((x) & ERROR_STATUS_ENABLE_WAKEUP_MASK) >> \ + ERROR_STATUS_ENABLE_WAKEUP_LSB) +#define ERROR_STATUS_ENABLE_WAKEUP_SET(x) \ + (((x) << ERROR_STATUS_ENABLE_WAKEUP_LSB) & \ + ERROR_STATUS_ENABLE_WAKEUP_MASK) +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MSB 1 +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB 1 +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK 0x00000002 +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_GET(x) \ + (((x) & ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK) >> \ + ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB) +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_SET(x) \ + (((x) << ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB) & \ + ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK) +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MSB 0 +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB 0 +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK 0x00000001 +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_GET(x) \ + (((x) & ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK) >> \ + ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB) +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_SET(x) \ + (((x) << ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB) & \ + ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK) + +#define COUNTER_INT_STATUS_ENABLE_ADDRESS 0x0000041b +#define COUNTER_INT_STATUS_ENABLE_OFFSET 0x0000041b +#define COUNTER_INT_STATUS_ENABLE_BIT_MSB 7 +#define COUNTER_INT_STATUS_ENABLE_BIT_LSB 0 +#define COUNTER_INT_STATUS_ENABLE_BIT_MASK 0x000000ff +#define COUNTER_INT_STATUS_ENABLE_BIT_GET(x) \ + (((x) & COUNTER_INT_STATUS_ENABLE_BIT_MASK) >> \ + COUNTER_INT_STATUS_ENABLE_BIT_LSB) +#define COUNTER_INT_STATUS_ENABLE_BIT_SET(x) \ + (((x) << COUNTER_INT_STATUS_ENABLE_BIT_LSB) & \ + COUNTER_INT_STATUS_ENABLE_BIT_MASK) + +#define COUNT_ADDRESS 0x00000420 +#define COUNT_OFFSET 0x00000420 +#define COUNT_VALUE_MSB 7 +#define COUNT_VALUE_LSB 0 +#define COUNT_VALUE_MASK 0x000000ff +#define COUNT_VALUE_GET(x) (((x) & COUNT_VALUE_MASK) >> COUNT_VALUE_LSB) +#define COUNT_VALUE_SET(x) (((x) << COUNT_VALUE_LSB) & COUNT_VALUE_MASK) + +#define COUNT_DEC_ADDRESS 0x00000440 +#define COUNT_DEC_OFFSET 0x00000440 +#define COUNT_DEC_VALUE_MSB 7 +#define COUNT_DEC_VALUE_LSB 0 +#define COUNT_DEC_VALUE_MASK 0x000000ff +#define COUNT_DEC_VALUE_GET(x) \ + (((x) & COUNT_DEC_VALUE_MASK) >> COUNT_DEC_VALUE_LSB) +#define COUNT_DEC_VALUE_SET(x) \ + (((x) << COUNT_DEC_VALUE_LSB) & COUNT_DEC_VALUE_MASK) + +#define SCRATCH_ADDRESS 0x00000460 +#define SCRATCH_OFFSET 0x00000460 +#define SCRATCH_VALUE_MSB 7 +#define SCRATCH_VALUE_LSB 0 +#define SCRATCH_VALUE_MASK 0x000000ff +#define SCRATCH_VALUE_GET(x) (((x) & SCRATCH_VALUE_MASK) >> SCRATCH_VALUE_LSB) +#define SCRATCH_VALUE_SET(x) (((x) << SCRATCH_VALUE_LSB) & SCRATCH_VALUE_MASK) + +#define FIFO_TIMEOUT_ADDRESS 0x00000468 +#define FIFO_TIMEOUT_OFFSET 0x00000468 +#define FIFO_TIMEOUT_VALUE_MSB 7 +#define FIFO_TIMEOUT_VALUE_LSB 0 +#define FIFO_TIMEOUT_VALUE_MASK 0x000000ff +#define FIFO_TIMEOUT_VALUE_GET(x) \ + (((x) & FIFO_TIMEOUT_VALUE_MASK) >> FIFO_TIMEOUT_VALUE_LSB) +#define FIFO_TIMEOUT_VALUE_SET(x) \ + (((x) << FIFO_TIMEOUT_VALUE_LSB) & FIFO_TIMEOUT_VALUE_MASK) + +#define FIFO_TIMEOUT_ENABLE_ADDRESS 0x00000469 +#define FIFO_TIMEOUT_ENABLE_OFFSET 0x00000469 +#define FIFO_TIMEOUT_ENABLE_SET_MSB 0 +#define FIFO_TIMEOUT_ENABLE_SET_LSB 0 +#define FIFO_TIMEOUT_ENABLE_SET_MASK 0x00000001 +#define FIFO_TIMEOUT_ENABLE_SET_GET(x) \ + (((x) & FIFO_TIMEOUT_ENABLE_SET_MASK) >> FIFO_TIMEOUT_ENABLE_SET_LSB) +#define FIFO_TIMEOUT_ENABLE_SET_SET(x) \ + (((x) << FIFO_TIMEOUT_ENABLE_SET_LSB) & FIFO_TIMEOUT_ENABLE_SET_MASK) + +#define INT_WLAN_ADDRESS 0x00000472 +#define INT_TARGET_ADDRESS INT_WLAN_ADDRESS +#define INT_WLAN_OFFSET 0x00000472 +#define INT_WLAN_VECTOR_MSB 7 +#define INT_WLAN_VECTOR_LSB 0 +#define INT_WLAN_VECTOR_MASK 0x000000ff +#define INT_WLAN_VECTOR_GET(x) \ + (((x) & INT_WLAN_VECTOR_MASK) >> INT_WLAN_VECTOR_LSB) +#define INT_WLAN_VECTOR_SET(x) \ + (((x) << INT_WLAN_VECTOR_LSB) & INT_WLAN_VECTOR_MASK) + +#define SPI_CONFIG_ADDRESS 0x00000480 +#define SPI_CONFIG_OFFSET 0x00000480 +#define SPI_CONFIG_SPI_RESET_MSB 4 +#define SPI_CONFIG_SPI_RESET_LSB 4 +#define SPI_CONFIG_SPI_RESET_MASK 0x00000010 +#define SPI_CONFIG_SPI_RESET_GET(x) \ + (((x) & SPI_CONFIG_SPI_RESET_MASK) >> SPI_CONFIG_SPI_RESET_LSB) +#define SPI_CONFIG_SPI_RESET_SET(x) \ + (((x) << SPI_CONFIG_SPI_RESET_LSB) & SPI_CONFIG_SPI_RESET_MASK) +#define SPI_CONFIG_INTERRUPT_ENABLE_MSB 3 +#define SPI_CONFIG_INTERRUPT_ENABLE_LSB 3 +#define SPI_CONFIG_INTERRUPT_ENABLE_MASK 0x00000008 +#define SPI_CONFIG_INTERRUPT_ENABLE_GET(x) \ + (((x) & SPI_CONFIG_INTERRUPT_ENABLE_MASK) >> \ + SPI_CONFIG_INTERRUPT_ENABLE_LSB) +#define SPI_CONFIG_INTERRUPT_ENABLE_SET(x) \ + (((x) << SPI_CONFIG_INTERRUPT_ENABLE_LSB) & \ + SPI_CONFIG_INTERRUPT_ENABLE_MASK) +#define SPI_CONFIG_TEST_MODE_MSB 2 +#define SPI_CONFIG_TEST_MODE_LSB 2 +#define SPI_CONFIG_TEST_MODE_MASK 0x00000004 +#define SPI_CONFIG_TEST_MODE_GET(x) \ + (((x) & SPI_CONFIG_TEST_MODE_MASK) >> SPI_CONFIG_TEST_MODE_LSB) +#define SPI_CONFIG_TEST_MODE_SET(x) \ + (((x) << SPI_CONFIG_TEST_MODE_LSB) & SPI_CONFIG_TEST_MODE_MASK) +#define SPI_CONFIG_DATA_SIZE_MSB 1 +#define SPI_CONFIG_DATA_SIZE_LSB 0 +#define SPI_CONFIG_DATA_SIZE_MASK 0x00000003 +#define SPI_CONFIG_DATA_SIZE_GET(x) \ + (((x) & SPI_CONFIG_DATA_SIZE_MASK) >> SPI_CONFIG_DATA_SIZE_LSB) +#define SPI_CONFIG_DATA_SIZE_SET(x) \ + (((x) << SPI_CONFIG_DATA_SIZE_LSB) & SPI_CONFIG_DATA_SIZE_MASK) + +#define SPI_STATUS_ADDRESS 0x00000481 +#define SPI_STATUS_OFFSET 0x00000481 +#define SPI_STATUS_ADDR_ERR_MSB 3 +#define SPI_STATUS_ADDR_ERR_LSB 3 +#define SPI_STATUS_ADDR_ERR_MASK 0x00000008 +#define SPI_STATUS_ADDR_ERR_GET(x) \ + (((x) & SPI_STATUS_ADDR_ERR_MASK) >> SPI_STATUS_ADDR_ERR_LSB) +#define SPI_STATUS_ADDR_ERR_SET(x) \ + (((x) << SPI_STATUS_ADDR_ERR_LSB) & SPI_STATUS_ADDR_ERR_MASK) +#define SPI_STATUS_RD_ERR_MSB 2 +#define SPI_STATUS_RD_ERR_LSB 2 +#define SPI_STATUS_RD_ERR_MASK 0x00000004 +#define SPI_STATUS_RD_ERR_GET(x) \ + (((x) & SPI_STATUS_RD_ERR_MASK) >> SPI_STATUS_RD_ERR_LSB) +#define SPI_STATUS_RD_ERR_SET(x) \ + (((x) << SPI_STATUS_RD_ERR_LSB) & SPI_STATUS_RD_ERR_MASK) +#define SPI_STATUS_WR_ERR_MSB 1 +#define SPI_STATUS_WR_ERR_LSB 1 +#define SPI_STATUS_WR_ERR_MASK 0x00000002 +#define SPI_STATUS_WR_ERR_GET(x) \ + (((x) & SPI_STATUS_WR_ERR_MASK) >> SPI_STATUS_WR_ERR_LSB) +#define SPI_STATUS_WR_ERR_SET(x) \ + (((x) << SPI_STATUS_WR_ERR_LSB) & SPI_STATUS_WR_ERR_MASK) +#define SPI_STATUS_READY_MSB 0 +#define SPI_STATUS_READY_LSB 0 +#define SPI_STATUS_READY_MASK 0x00000001 +#define SPI_STATUS_READY_GET(x) \ + (((x) & SPI_STATUS_READY_MASK) >> SPI_STATUS_READY_LSB) +#define SPI_STATUS_READY_SET(x) \ + (((x) << SPI_STATUS_READY_LSB) & SPI_STATUS_READY_MASK) +#define INT_WLAN_ADDRESS 0x00000472 +#define INT_WLAN_OFFSET 0x00000472 +#define INT_WLAN_VECTOR_MSB 7 +#define INT_WLAN_VECTOR_LSB 0 +#define INT_WLAN_VECTOR_MASK 0x000000ff +#define INT_WLAN_VECTOR_GET(x) \ + (((x) & INT_WLAN_VECTOR_MASK) >> INT_WLAN_VECTOR_LSB) +#define INT_WLAN_VECTOR_SET(x) \ + (((x) << INT_WLAN_VECTOR_LSB) & INT_WLAN_VECTOR_MASK) + +#endif /* _MBOX_HOST_REG_H_ */ -- GitLab From 2b4fee85d2eb331ca87ae2f689a5ac78f3b3e7f2 Mon Sep 17 00:00:00 2001 From: Evgeniy Borisov Date: Tue, 3 Jul 2018 11:43:05 -0700 Subject: [PATCH 461/604] defconfig: msm: Enable qca402x Enable CONFIG_MMC_EMBEDDED_SDIO add CONFIG_QCA402X and CONFIG_QCA402X_DEBUG. Change-Id: Ibd7bb8a031b059a149223130358061a0c27d7725 Signed-off-by: Evgeniy Borisov --- arch/arm/configs/msm8953-perf_defconfig | 2 ++ arch/arm/configs/msm8953_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig index fca07a10e3ba..9cb112299ab2 100644 --- a/arch/arm/configs/msm8953-perf_defconfig +++ b/arch/arm/configs/msm8953-perf_defconfig @@ -303,6 +303,7 @@ CONFIG_USB_USBNET=y # CONFIG_WLAN_VENDOR_ZYDAS is not set CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y +CONFIG_QCA402X=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set @@ -504,6 +505,7 @@ CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y # CONFIG_PWRSEQ_EMMC is not set # CONFIG_PWRSEQ_SIMPLE is not set +CONFIG_MMC_EMBEDDED_SDIO=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_BLOCK_MINORS=32 diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig index 690faf2296f0..12976fb22539 100644 --- a/arch/arm/configs/msm8953_defconfig +++ b/arch/arm/configs/msm8953_defconfig @@ -308,6 +308,7 @@ CONFIG_USB_USBNET=y # CONFIG_WLAN_VENDOR_ZYDAS is not set CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y +CONFIG_QCA402X=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set @@ -513,6 +514,7 @@ CONFIG_MMC_PERF_PROFILING=y # CONFIG_PWRSEQ_EMMC is not set # CONFIG_PWRSEQ_SIMPLE is not set CONFIG_MMC_RING_BUFFER=y +CONFIG_MMC_EMBEDDED_SDIO=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_BLOCK_MINORS=32 -- GitLab From feb53d68838c78e015767ec9b9fec15b86e80b8a Mon Sep 17 00:00:00 2001 From: Santosh Mardi Date: Fri, 20 Jul 2018 12:27:55 +0530 Subject: [PATCH 462/604] ARM: dts: msm: update DDR bw IB votes for sdm439 target Update DDR bw table IB vote with proper calculation from frequency for sdm439 target. Change-Id: I13be739c8d466ec4fd42996cdf7af16c66228c24 Signed-off-by: Santosh Mardi --- arch/arm64/boot/dts/qcom/sdm439.dtsi | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm439.dtsi b/arch/arm64/boot/dts/qcom/sdm439.dtsi index 1448a65b5f1a..89289d949c2a 100644 --- a/arch/arm64/boot/dts/qcom/sdm439.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439.dtsi @@ -78,9 +78,9 @@ < 2929 /* 384 MHz */ >, /* SVS */ < 3221 /* 422.4 MHz */ >, < 4248 /* 556.8 MHz */ >, - < 5126 /* 662.4 MHz */ >, /* SVS+ */ - < 5859 /* 748.8 MHz */ >, /* NOM */ - < 6152 /* 806.4 MHz */ >, /* NOM+ */ + < 5053 /* 662.4 MHz */ >, /* SVS+ */ + < 5712 /* 748.8 MHz */ >, /* NOM */ + < 6079 /* 796.8 MHz */ >, /* NOM+ */ < 6445 /* 844.8 MHz */ >, < 7104 /* 931.2 MHz */ >; /* TURBO */ }; @@ -98,9 +98,9 @@ < 2929 /* 384 MHz */ >, /* SVS */ < 3221 /* 422.4 MHz */ >, < 4248 /* 556.8 MHz */ >, - < 5126 /* 662.4 MHz */ >, /* SVS+ */ - < 5859 /* 748.8 MHz */ >, /* NOM */ - < 6152 /* 806.4 MHz */ >, /* NOM+ */ + < 5053 /* 662.4 MHz */ >, /* SVS+ */ + < 5712 /* 748.8 MHz */ >, /* NOM */ + < 6079 /* 796.8 MHz */ >, /* NOM+ */ < 6445 /* 844.8 MHz */ >, < 7104 /* 931.2 MHz */ >; /* TURBO */ }; -- GitLab From 94af162b22a098c14afc20798cb3575349519c34 Mon Sep 17 00:00:00 2001 From: Santosh Mardi Date: Fri, 20 Jul 2018 12:36:12 +0530 Subject: [PATCH 463/604] ARM: dts: msm: update mincpubw mapping for sdm439 and sdm429 target update mincpubw mapping table for sdm439 and sdm429 target based on proper IB vote calculation. Change-Id: Id78accf95de9445b17d51bf4bef6f58fca8f551d Signed-off-by: Santosh Mardi --- arch/arm64/boot/dts/qcom/sdm429.dtsi | 6 +++--- arch/arm64/boot/dts/qcom/sdm439.dtsi | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index b52ee2d1292e..30dbb0e3edcd 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -69,8 +69,8 @@ target-dev = <&cpubw>; cpu-to-dev-map = < 960000 2929 >, - < 1305600 5126 >, - < 1497600 5859 >, + < 1305600 5053 >, + < 1497600 5712 >, < 1708800 6445 >, < 1804800 7104 >, < 1958400 7104 >; @@ -91,7 +91,7 @@ target-dev = <&mincpubw>; cpu-to-dev-map = < 1305600 2929 >, - < 1804800 5859 >; + < 1804800 5712 >; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm439.dtsi b/arch/arm64/boot/dts/qcom/sdm439.dtsi index 89289d949c2a..55efbb964066 100644 --- a/arch/arm64/boot/dts/qcom/sdm439.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439.dtsi @@ -124,16 +124,16 @@ cpubw-cpufreq { target-dev = <&cpubw>; cpu-to-dev-map-0 = - < 1305600 5126 >, - < 1497600 5859 >, + < 1305600 5053 >, + < 1497600 5712 >, < 1708800 6445 >, < 1804800 7104 >, < 1958400 7104 >; cpu-to-dev-map-4 = < 768000 2929 >, - < 998400 5126 >, - < 1171200 5859 >, - < 1305600 6152 >, + < 998400 5053 >, + < 1171200 5712 >, + < 1305600 6079 >, < 1459200 7104 >; }; @@ -158,10 +158,10 @@ target-dev = <&mincpubw>; cpu-to-dev-map-0 = < 1305600 2929 >, - < 1804800 5859 >; + < 1804800 5712 >; cpu-to-dev-map-4 = < 1171200 2929 >, - < 1459200 5859 >; + < 1459200 5712 >; }; }; }; -- GitLab From 0273d54e273337b904bb25119b85fd12ebcf92ba Mon Sep 17 00:00:00 2001 From: Tiequan Luo Date: Thu, 19 Jul 2018 15:45:48 +0800 Subject: [PATCH 464/604] ARM: dts: msm: Add support for apq8009 pronto variants Add support for apq8009-robot pronto variants with apq8009 ioe reference board. Change-Id: I908a292501e9f3faff6bea9097a9d0a0b0b5359b Signed-off-by: Tiequan Luo --- .../qcom/apq8009-robot-pronto-refboard.dts | 380 ++++++++++++++++++ 1 file changed, 380 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/apq8009-robot-pronto-refboard.dts diff --git a/arch/arm64/boot/dts/qcom/apq8009-robot-pronto-refboard.dts b/arch/arm64/boot/dts/qcom/apq8009-robot-pronto-refboard.dts new file mode 100644 index 000000000000..0ac8a311649c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8009-robot-pronto-refboard.dts @@ -0,0 +1,380 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "msm8909-mtp.dtsi" +#include "8909-pm8916.dtsi" +#include "msm8909-pm8916-mtp.dtsi" +#include "apq8009-audio-external_codec.dtsi" +#include "apq8009-memory.dtsi" +#include +#include "msm8909-pm8916-camera.dtsi" +#include "msm8909-pm8916-camera-sensor-robot.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8009 Robot-pronto RefBoard"; + compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; + qcom,msm-id = <265 2>; + qcom,board-id= <8 0xE>; +}; + +&audio_codec_mtp { + status = "disabled"; +}; + +&pm8916_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + status = "okay"; + }; + }; +}; + +&msm_gpio { + hsuart_active: default { + mux { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + drive-strength = <16>; + bias-disable; + }; + }; + + hsuart_sleep: sleep { + mux { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + drive-strength = <2>; + bias-disable; + }; + }; + + usb_vbus_detect: usb_vbus_detect { + mux { + pins = "gpio97"; + function = "gpio"; + }; + + config { + pins = "gpio97"; + drive-strength = <2>; + bias-disable; + }; + }; + + usb_id_detect: usb_id_detect { + mux { + pins = "gpio110"; + function = "gpio"; + }; + + config { + pins = "gpio110"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; + +&soc { + ext_codec: sound-9335 { + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-gpios = + "us_eu_gpio"; + qcom,pinctrl-names = + "all_off", + "us_eu_gpio_act"; + pinctrl-names = + "all_off", + "us_eu_gpio_act"; + pinctrl-0 = <&cross_conn_det_sus>; + pinctrl-1 = <&cross_conn_det_act>; + qcom,pri-mi2s-gpios = <&cdc_pri_mi2s_gpios>; + qcom,quat-mi2s-gpios = <&cdc_quat_mi2s_gpios>; + + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + }; + + i2c@78b9000 { + synaptics@20 { + status = "disabled"; + }; + }; + + blsp1_uart2_hs: uart@78b0000 { + compatible = "qcom,msm-hsuart-v14"; + reg = <0x78b0000 0x200>, + <0x7884000 0x1f000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart2_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 108 0 + 1 &intc 0 238 0 + 2 &msm_gpio 21 0>; + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>, + <&clock_gcc clk_gcc_blsp1_ahb_clk>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&hsuart_sleep>; + pinctrl-1 = <&hsuart_active>; + qcom,bam-tx-ep-pipe-index = <2>; + qcom,bam-rx-ep-pipe-index = <3>; + qcom,msm-bus,name = "blsp1_uart2_hs"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "ok"; + }; + + bluetooth: bt_qca9379 { + compatible = "qca,qca9379"; + qca,bt-reset-gpio = <&msm_gpio 47 0>; /* BT_EN */ + }; + + cnss_sdio: qcom,cnss_sdio { + compatible = "qcom,cnss_sdio"; + subsys-name = "AR6320"; + /** + * There is no vdd-wlan on board and this is not for DSRC. + * IO and XTAL share the same vreg. + **/ + vdd-wlan-io-supply = <&pm8916_l5>; + qcom,cap-tsf-gpio = <&msm_gpio 42 1>; + qcom,wlan-ramdump-dynamic = <0x200000>; + qcom,msm-bus,name = "msm-cnss"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <79 512 0 0>, /* No vote */ + <79 512 6250 200000>, /* 50 Mbps */ + <79 512 25000 200000>, /* 200 Mbps */ + <79 512 2048000 4096000>; /* MAX */ + }; + + usb_detect: qcom,gpio-usbdetect { + compatible = "qcom,gpio-usbdetect"; + interrupt-parent = <&msm_gpio>; + interrupts = <97 0>; + interrupt-names = "vbus_det_irq"; + pinctrl-names = "usb_vbus_detect", "usb_id_detect"; + pinctrl-0 = <&usb_vbus_detect>; + pinctrl-1 = <&usb_id_detect>; + qcom,gpio-mode-sel = <&msm_gpio 97 0>; + qcom,id-det-gpio = <&msm_gpio 110 0>; + qcom,dpdm_switch_gpio = <&pm8916_gpios 3 0>; + }; + + i2c@78b8000 { + wcd9xxx_codec@d { + status = "okay"; + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + }; + }; + + cdc_pri_mi2s_gpios: msm_cdc_pinctrl_pri { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&pri_mi2s_active &pri_mi2s_ws_active + &pri_mi2s_dout_active &pri_mi2s_din_active>; + pinctrl-1 = <&pri_mi2s_sleep &pri_mi2s_ws_sleep + &pri_mi2s_dout_sleep &pri_mi2s_din_sleep>; + }; + + cdc_quat_mi2s_gpios: msm_cdc_pinctrl_quat { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>; + pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>; + }; + + wcd_rst_gpio: wcd_gpio_ctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_reset_active>; + pinctrl-1 = <&cdc_reset_sleep>; + }; +}; + +&wcnss { + status = "disabled"; +}; + +&msm_gpio { + sdc2_wlan_gpio_on: sdc2_wlan_gpio_on { + mux { + pins = "gpio43"; + function = "gpio"; + }; + config { + pins = "gpio43"; + drive-strength = <10>; + bias-pull-up; + output-high; + }; + }; + + sdc2_wlan_gpio_off: sdc2_wlan_gpio_off { + mux { + pins = "gpio43"; + function = "gpio"; + }; + config { + pins = "gpio43"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; +}; + +&sdhc_2 { + /delete-property/cd-gpios; + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 125 0 + 1 &intc 0 221 0 + 2 &msm_gpio 38 0>; + interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq"; + + qcom,vdd-voltage-level = <1800000 2950000>; + qcom,vdd-current-level = <15000 400000>; + + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 50000>; + qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on + &sdc2_wlan_gpio_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off + &sdc2_wlan_gpio_off>; + qcom,nonremovable; + qcom,core_3_0v_support; + status = "ok"; +}; + +&i2c_4 { + status= "okay"; + smb1360_otg_supply: smb1360-chg-fg@14 { + compatible = "qcom,smb1360-chg-fg"; + reg = <0x14>; + interrupt-parent = <&msm_gpio>; + interrupts = <58 8>; + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default>; + qcom,charging-disabled; + qcom,empty-soc-disabled; + qcom,chg-inhibit-disabled; + qcom,float-voltage-mv = <4200>; + qcom,iterm-ma = <200>; + qcom,recharge-thresh-mv = <100>; + qcom,thermal-mitigation = <1500 700 600 0>; + status= "okay"; + smb1360_vbus: qcom,smb1360-vbus { + regulator-name = "qcom,smb1360-vbus"; + }; + }; +}; + +&usb_otg { + interrupts = <0 134 0>, <0 140 0>, <0 136 0>; + interrupt-names = "core_irq", "async_irq", "phy_irq"; + qcom,hsusb-otg-mode = <3>; + vbus_otg-supply = <&smb1360_vbus>; + extcon = <&smb1360_otg_supply>; +}; + +&mdss_fb0 { + status = "disabled"; + /delete-node/ qcom,cont-splash-memory; +}; + +&mdss_mdp { + status = "disabled"; +}; + +&mdss_dsi0_pll { + status = "disabled"; +}; + +&mdss_dsi0 { + status = "disabled"; +}; + +&i2c_1 { + status = "disabled"; +}; + +&i2c_2 { + status = "disabled"; +}; + +&i2c_5 { + status = "disabled"; +}; + +&spi_0 { + status = "disabled"; +}; + +&wcd_rst_gpio { + status = "okay"; +}; + +&ext_codec { + status = "okay"; +}; + +&blsp1_uart2_hs { + status = "disabled"; +}; + +/delete-node/ &cont_splash_mem; -- GitLab From 9d5f2b319183f1e0af86f6da96efb3c213470513 Mon Sep 17 00:00:00 2001 From: Kaushal Kumar Date: Wed, 22 Jun 2016 11:08:53 +0530 Subject: [PATCH 465/604] arm/arm64: mm: add option to configure TLMM page attrs for 8953 Add and enable option to configure the TLMM register region page attributes as strongly ordered for 8953 as needed for some of CPUSS sub-system functionality. Change-Id: Id600fb5e853ca85e2d3949d0c168247c21d2d64f Signed-off-by: Kaushal Kumar Signed-off-by: Teng Fei Fan --- arch/arm/Kconfig | 10 ++++++++++ arch/arm/mach-qcom/Kconfig | 3 +++ arch/arm/mm/ioremap.c | 10 ++++++++-- arch/arm64/Kconfig | 10 ++++++++++ arch/arm64/Kconfig.platforms | 3 +++ arch/arm64/mm/ioremap.c | 5 +++++ include/linux/mm.h | 7 ++++++- 7 files changed, 45 insertions(+), 3 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 54e93a006618..04b90d375b1f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1412,6 +1412,16 @@ config HAVE_ARM_TWD help This options enables support for the ARM timer and watchdog unit +config ARCH_MSM8953_SOC_SETTINGS + bool "Enable MSM8953 SOC settings" + depends on ARCH_MSM8953 + help + Enable MSM8953 SOC related settings, these generic MSM8953 + related settings are required for some of CPUSS sub-system + functionality. + + If you are not sure what to do, select 'N' here. + config MCPM bool "Multi-Cluster Power Management" depends on CPU_V7 && SMP diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig index d96863ed55bc..7ca91802b274 100644 --- a/arch/arm/mach-qcom/Kconfig +++ b/arch/arm/mach-qcom/Kconfig @@ -64,6 +64,7 @@ config ARCH_MSM8953 select HAVE_CLK select HAVE_CLK_PREPARE select COMMON_CLK_MSM + select ARCH_MSM8953_SOC_SETTINGS config ARCH_MSM8953_BOOT_ORDERING bool "Enable support for MSM8953 device boot ordering" @@ -160,6 +161,7 @@ config ARCH_SDM450 select HAVE_CLK select HAVE_CLK_PREPARE select COMMON_CLK_MSM + select ARCH_MSM8953_SOC_SETTINGS config ARCH_SDM632 bool "Enable Support for Qualcomm Technologies Inc. SDM632" @@ -176,6 +178,7 @@ config ARCH_SDM632 select SND_HWDEP select CPU_FREQ_QCOM select COMMON_CLK_MSM + select ARCH_MSM8953_SOC_SETTINGS config ARCH_SDM670 bool "Enable Support for SDM670" diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 203728dfac97..7fa65aa1aabf 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -265,6 +265,7 @@ static void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn, unsigned long addr; struct vm_struct *area; phys_addr_t paddr = __pfn_to_phys(pfn); + pgprot_t prot; #ifndef CONFIG_ARM_LPAE /* @@ -310,6 +311,12 @@ static void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn, addr = (unsigned long)area->addr; area->phys_addr = paddr; + prot = __pgprot(type->prot_pte); +#ifdef CONFIG_ARCH_MSM8953_SOC_SETTINGS + if (paddr >= MSM8953_TLMM_START_ADDR && + paddr <= MSM8953_TLMM_END_ADDR) + prot = pgprot_stronglyordered(type->prot_pte); +#endif #if !defined(CONFIG_SMP) && !defined(CONFIG_ARM_LPAE) if (DOMAIN_IO == 0 && (((cpu_architecture() >= CPU_ARCH_ARMv6) && (get_cr() & CR_XP)) || @@ -322,8 +329,7 @@ static void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn, err = remap_area_sections(addr, pfn, size, type); } else #endif - err = ioremap_page_range(addr, addr + size, paddr, - __pgprot(type->prot_pte)); + err = ioremap_page_range(addr, addr + size, paddr, prot); if (err) { vunmap((void *)addr); diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index f72ce3009160..ac71d3916ed8 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -554,6 +554,16 @@ config ARM64_64K_PAGES endchoice +config ARCH_MSM8953_SOC_SETTINGS + bool "Enable MSM8953 SOC settings" + depends on ARCH_MSM8953 + help + Enable MSM8953 SOC related settings, these generic MSM8953 + related settings are required for some of CPUSS sub-system + functionality. + + If you are not sure what to do, select 'N' here. + choice prompt "Virtual address space size" default ARM64_VA_BITS_39 if ARM64_4K_PAGES diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index a92f51149a0b..4c013ad50189 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -152,6 +152,7 @@ config ARCH_MSM8953 depends on ARCH_QCOM select CPU_FREQ_QCOM select COMMON_CLK_MSM + select ARCH_MSM8953_SOC_SETTINGS help This enables support for the MSM8953 chipset. If you do not wish to build a kernel that runs on this chipset, say 'N' here. @@ -179,6 +180,7 @@ config ARCH_SDM450 depends on ARCH_QCOM select CPU_FREQ_QCOM select COMMON_CLK_MSM + select ARCH_MSM8953_SOC_SETTINGS help This enables support for the sdm450 chipset. If you do not wish to build a kernel that runs on this chipset, say 'N' here. @@ -188,6 +190,7 @@ config ARCH_SDM632 depends on ARCH_QCOM select CPU_FREQ_QCOM select COMMON_CLK_MSM + select ARCH_MSM8953_SOC_SETTINGS help This enables support for the sdm632 chipset. If you do not wish to build a kernel that runs on this chipset, say 'N' here. diff --git a/arch/arm64/mm/ioremap.c b/arch/arm64/mm/ioremap.c index 01e88c8bcab0..8e2c1d68866c 100644 --- a/arch/arm64/mm/ioremap.c +++ b/arch/arm64/mm/ioremap.c @@ -64,6 +64,11 @@ static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size, addr = (unsigned long)area->addr; area->phys_addr = phys_addr; +#ifdef CONFIG_ARCH_MSM8953_SOC_SETTINGS + if (phys_addr >= MSM8953_TLMM_START_ADDR && + phys_addr <= MSM8953_TLMM_END_ADDR) + prot = __pgprot(PROT_DEVICE_nGnRnE); +#endif err = ioremap_page_range(addr, addr + size, phys_addr, prot); if (err) { vunmap((void *)addr); diff --git a/include/linux/mm.h b/include/linux/mm.h index 9d5d8087b38d..e7b96529374f 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -269,6 +269,11 @@ extern unsigned int kobjsize(const void *objp); /* This mask is used to clear all the VMA flags used by mlock */ #define VM_LOCKED_CLEAR_MASK (~(VM_LOCKED | VM_LOCKONFAULT)) +#ifdef CONFIG_ARCH_MSM8953_SOC_SETTINGS +#define MSM8953_TLMM_START_ADDR 0x01000000 +#define MSM8953_TLMM_END_ADDR (0x01300000 - 1) +#endif + /* * mapping from the currently active vm_flags protection bits (the * low four bits) to a page protection mask.. @@ -360,7 +365,7 @@ struct fault_env { /* * These are the virtual MM functions - opening of an area, closing and * unmapping it (needed to keep files on disk up-to-date etc), pointer - * to the functions called when a no-page or a wp-page exception occurs. + * to the functions called when a no-page or a wp-page exception occurs. */ struct vm_operations_struct { void (*open)(struct vm_area_struct * area); -- GitLab From 8a2c9e93e8dff536149943d25889e86a9f047a53 Mon Sep 17 00:00:00 2001 From: Tiequan Luo Date: Mon, 23 Jul 2018 17:14:14 +0800 Subject: [PATCH 466/604] ARM: dts: msm: Add support for apq8009 rome variants Add support for apq8009-robot rome variants with apq8009 ioe reference board. Change-Id: Ic53e8a602e1c1c736396555b0329d780640d66e2 Signed-off-by: Tiequan Luo --- .../dts/qcom/apq8009-robot-rome-refboard.dts | 380 ++++++++++++++++++ 1 file changed, 380 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/apq8009-robot-rome-refboard.dts diff --git a/arch/arm64/boot/dts/qcom/apq8009-robot-rome-refboard.dts b/arch/arm64/boot/dts/qcom/apq8009-robot-rome-refboard.dts new file mode 100644 index 000000000000..66070b7bb426 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8009-robot-rome-refboard.dts @@ -0,0 +1,380 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "msm8909-mtp.dtsi" +#include "8909-pm8916.dtsi" +#include "msm8909-pm8916-mtp.dtsi" +#include "apq8009-audio-external_codec.dtsi" +#include "apq8009-memory.dtsi" +#include +#include "msm8909-pm8916-camera.dtsi" +#include "msm8909-pm8916-camera-sensor-robot.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8009 Robot-rome RefBoard"; + compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; + qcom,msm-id = <265 2>; + qcom,board-id= <8 0x10>; +}; + +&audio_codec_mtp { + status = "disabled"; +}; + +&pm8916_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + status = "okay"; + }; + }; +}; + +&msm_gpio { + hsuart_active: default { + mux { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + drive-strength = <16>; + bias-disable; + }; + }; + + hsuart_sleep: sleep { + mux { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + drive-strength = <2>; + bias-disable; + }; + }; + + usb_vbus_detect: usb_vbus_detect { + mux { + pins = "gpio97"; + function = "gpio"; + }; + + config { + pins = "gpio97"; + drive-strength = <2>; + bias-disable; + }; + }; + + usb_id_detect: usb_id_detect { + mux { + pins = "gpio110"; + function = "gpio"; + }; + + config { + pins = "gpio110"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; + +&soc { + ext_codec: sound-9335 { + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-gpios = + "us_eu_gpio"; + qcom,pinctrl-names = + "all_off", + "us_eu_gpio_act"; + pinctrl-names = + "all_off", + "us_eu_gpio_act"; + pinctrl-0 = <&cross_conn_det_sus>; + pinctrl-1 = <&cross_conn_det_act>; + qcom,pri-mi2s-gpios = <&cdc_pri_mi2s_gpios>; + qcom,quat-mi2s-gpios = <&cdc_quat_mi2s_gpios>; + + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + }; + + i2c@78b9000 { + synaptics@20 { + status = "disabled"; + }; + }; + + blsp1_uart2_hs: uart@78b0000 { + compatible = "qcom,msm-hsuart-v14"; + reg = <0x78b0000 0x200>, + <0x7884000 0x1f000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart2_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 108 0 + 1 &intc 0 238 0 + 2 &msm_gpio 21 0>; + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>, + <&clock_gcc clk_gcc_blsp1_ahb_clk>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&hsuart_sleep>; + pinctrl-1 = <&hsuart_active>; + qcom,bam-tx-ep-pipe-index = <2>; + qcom,bam-rx-ep-pipe-index = <3>; + qcom,msm-bus,name = "blsp1_uart2_hs"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "ok"; + }; + + bluetooth: bt_qca9379 { + compatible = "qca,qca9379"; + qca,bt-reset-gpio = <&msm_gpio 47 0>; /* BT_EN */ + }; + + cnss_sdio: qcom,cnss_sdio { + compatible = "qcom,cnss_sdio"; + subsys-name = "AR6320"; + /** + * There is no vdd-wlan on board and this is not for DSRC. + * IO and XTAL share the same vreg. + **/ + vdd-wlan-io-supply = <&pm8916_l5>; + qcom,cap-tsf-gpio = <&msm_gpio 42 1>; + qcom,wlan-ramdump-dynamic = <0x200000>; + qcom,msm-bus,name = "msm-cnss"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <79 512 0 0>, /* No vote */ + <79 512 6250 200000>, /* 50 Mbps */ + <79 512 25000 200000>, /* 200 Mbps */ + <79 512 2048000 4096000>; /* MAX */ + }; + + usb_detect: qcom,gpio-usbdetect { + compatible = "qcom,gpio-usbdetect"; + interrupt-parent = <&msm_gpio>; + interrupts = <97 0>; + interrupt-names = "vbus_det_irq"; + pinctrl-names = "usb_vbus_detect", "usb_id_detect"; + pinctrl-0 = <&usb_vbus_detect>; + pinctrl-1 = <&usb_id_detect>; + qcom,gpio-mode-sel = <&msm_gpio 97 0>; + qcom,id-det-gpio = <&msm_gpio 110 0>; + qcom,dpdm_switch_gpio = <&pm8916_gpios 3 0>; + }; + + i2c@78b8000 { + wcd9xxx_codec@d { + status = "okay"; + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + }; + }; + + cdc_pri_mi2s_gpios: msm_cdc_pinctrl_pri { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&pri_mi2s_active &pri_mi2s_ws_active + &pri_mi2s_dout_active &pri_mi2s_din_active>; + pinctrl-1 = <&pri_mi2s_sleep &pri_mi2s_ws_sleep + &pri_mi2s_dout_sleep &pri_mi2s_din_sleep>; + }; + + cdc_quat_mi2s_gpios: msm_cdc_pinctrl_quat { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>; + pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>; + }; + + wcd_rst_gpio: wcd_gpio_ctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_reset_active>; + pinctrl-1 = <&cdc_reset_sleep>; + }; +}; + +&wcnss { + status = "disabled"; +}; + +&msm_gpio { + sdc2_wlan_gpio_on: sdc2_wlan_gpio_on { + mux { + pins = "gpio43"; + function = "gpio"; + }; + config { + pins = "gpio43"; + drive-strength = <10>; + bias-pull-up; + output-high; + }; + }; + + sdc2_wlan_gpio_off: sdc2_wlan_gpio_off { + mux { + pins = "gpio43"; + function = "gpio"; + }; + config { + pins = "gpio43"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; +}; + +&sdhc_2 { + /delete-property/cd-gpios; + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 125 0 + 1 &intc 0 221 0 + 2 &msm_gpio 38 0>; + interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq"; + + qcom,vdd-voltage-level = <1800000 2950000>; + qcom,vdd-current-level = <15000 400000>; + + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 50000>; + qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on + &sdc2_wlan_gpio_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off + &sdc2_wlan_gpio_off>; + qcom,nonremovable; + qcom,core_3_0v_support; + status = "ok"; +}; + +&i2c_4 { + status= "okay"; + smb1360_otg_supply: smb1360-chg-fg@14 { + compatible = "qcom,smb1360-chg-fg"; + reg = <0x14>; + interrupt-parent = <&msm_gpio>; + interrupts = <58 8>; + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default>; + qcom,charging-disabled; + qcom,empty-soc-disabled; + qcom,chg-inhibit-disabled; + qcom,float-voltage-mv = <4200>; + qcom,iterm-ma = <200>; + qcom,recharge-thresh-mv = <100>; + qcom,thermal-mitigation = <1500 700 600 0>; + status= "okay"; + smb1360_vbus: qcom,smb1360-vbus { + regulator-name = "qcom,smb1360-vbus"; + }; + }; +}; + +&usb_otg { + interrupts = <0 134 0>, <0 140 0>, <0 136 0>; + interrupt-names = "core_irq", "async_irq", "phy_irq"; + qcom,hsusb-otg-mode = <3>; + vbus_otg-supply = <&smb1360_vbus>; + extcon = <&smb1360_otg_supply>; +}; + +&mdss_fb0 { + status = "disabled"; + /delete-node/ qcom,cont-splash-memory; +}; + +&mdss_mdp { + status = "disabled"; +}; + +&mdss_dsi0_pll { + status = "disabled"; +}; + +&mdss_dsi0 { + status = "disabled"; +}; + +&i2c_1 { + status = "disabled"; +}; + +&i2c_2 { + status = "disabled"; +}; + +&i2c_5 { + status = "disabled"; +}; + +&spi_0 { + status = "disabled"; +}; + +&wcd_rst_gpio { + status = "okay"; +}; + +&ext_codec { + status = "okay"; +}; + +&blsp1_uart2_hs { + status = "disabled"; +}; + +/delete-node/ &cont_splash_mem; -- GitLab From 4022d2d58c9e7a271e0683bf7f98679f45b0225d Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Mon, 11 Dec 2017 22:48:41 +0100 Subject: [PATCH 467/604] USB: core: only clean up what we allocated When cleaning up the configurations, make sure we only free the number of configurations and interfaces that we could have allocated. Reported-by: Andrey Konovalov Cc: stable Signed-off-by: Greg Kroah-Hartman Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Git-commit: 32fd87b3bbf5f7a045546401dfe2894dbbf4d8c3 Change-Id: I81b9513cc2ccc8bdd5e98982bb66e34711f61883 Signed-off-by: Srinivasa Rao Kuppala --- drivers/usb/core/config.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 876679a84f50..f794741b476a 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -763,18 +763,21 @@ void usb_destroy_configuration(struct usb_device *dev) return; if (dev->rawdescriptors) { - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) + for (i = 0; i < dev->descriptor.bNumConfigurations && + i < USB_MAXCONFIG; i++) kfree(dev->rawdescriptors[i]); kfree(dev->rawdescriptors); dev->rawdescriptors = NULL; } - for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { + for (c = 0; c < dev->descriptor.bNumConfigurations && + c < USB_MAXCONFIG; c++) { struct usb_host_config *cf = &dev->config[c]; kfree(cf->string); - for (i = 0; i < cf->desc.bNumInterfaces; i++) { + for (i = 0; i < cf->desc.bNumInterfaces && + i < USB_MAXINTERFACES; i++) { if (cf->intf_cache[i]) kref_put(&cf->intf_cache[i]->ref, usb_release_interface_cache); -- GitLab From f6912480c81ffae961116271a5a69b34475c4a7f Mon Sep 17 00:00:00 2001 From: Nirmal Abraham Date: Mon, 23 Jul 2018 17:11:05 +0530 Subject: [PATCH 468/604] msm: mdss: use uaccess routines to access user space buffers Use routines defined in uaccess.h (like put_user, get_user) while accessing user space buffers. Otherwise this leads to userspace access violation when PAN is enabled. Change-Id: Iea16e347ee71f0845711a21b6b9b01e16a6ab619 Signed-off-by: Nirmal Abraham --- drivers/video/fbdev/msm/mdss_compat_utils.c | 148 ++++++++++++-------- 1 file changed, 86 insertions(+), 62 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_compat_utils.c b/drivers/video/fbdev/msm/mdss_compat_utils.c index a81f149f59ce..23d4a27233d1 100644 --- a/drivers/video/fbdev/msm/mdss_compat_utils.c +++ b/drivers/video/fbdev/msm/mdss_compat_utils.c @@ -2879,26 +2879,28 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, *pp = compat_alloc_user_space(alloc_size); if (*pp == NULL) return -ENOMEM; - memset(*pp, 0, alloc_size); - - (*pp)->data.lut_cfg_data.data.pgc_lut_data.r_data = - (struct mdp_ar_gc_lut_data *) - ((unsigned long) *pp + - sizeof(struct msmfb_mdp_pp)); - (*pp)->data.lut_cfg_data.data.pgc_lut_data.g_data = - (struct mdp_ar_gc_lut_data *) + if (clear_user(*pp, alloc_size)) + return -EFAULT; + if (put_user((struct mdp_ar_gc_lut_data *) + ((unsigned long) *pp + + sizeof(struct msmfb_mdp_pp)), + &(*pp)->data.lut_cfg_data.data.pgc_lut_data.r_data) || + put_user((struct mdp_ar_gc_lut_data *) ((unsigned long) *pp + sizeof(struct msmfb_mdp_pp) + - pgc_size); - (*pp)->data.lut_cfg_data.data.pgc_lut_data.b_data = - (struct mdp_ar_gc_lut_data *) + pgc_size), + &(*pp)->data.lut_cfg_data.data.pgc_lut_data.g_data) || + put_user((struct mdp_ar_gc_lut_data *) ((unsigned long) *pp + sizeof(struct msmfb_mdp_pp) + - (2 * pgc_size)); - (*pp)->data.lut_cfg_data.data.pgc_lut_data.cfg_payload - = (void *)((unsigned long) *pp + + (2 * pgc_size)), + &(*pp)->data.lut_cfg_data.data.pgc_lut_data.b_data) || + put_user((void *)((unsigned long) *pp + sizeof(struct msmfb_mdp_pp) + - (3 * pgc_size)); + (3 * pgc_size)), + &(*pp)->data.lut_cfg_data.data. + pgc_lut_data.cfg_payload)) + return -EFAULT; break; case mdp_lut_igc: alloc_size += __pp_compat_size_igc(); @@ -2908,10 +2910,13 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, alloc_size); return -ENOMEM; } - memset(*pp, 0, alloc_size); - (*pp)->data.lut_cfg_data.data.igc_lut_data.cfg_payload - = (void *)((unsigned long)(*pp) + - sizeof(struct msmfb_mdp_pp)); + if (clear_user(*pp, alloc_size)) + return -EFAULT; + if (put_user((void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)), + &(*pp)->data.lut_cfg_data.data. + igc_lut_data.cfg_payload)) + return -EFAULT; break; case mdp_lut_hist: alloc_size += __pp_compat_size_hist_lut(); @@ -2921,10 +2926,13 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, alloc_size); return -ENOMEM; } - memset(*pp, 0, alloc_size); - (*pp)->data.lut_cfg_data.data.hist_lut_data.cfg_payload - = (void *)((unsigned long)(*pp) + - sizeof(struct msmfb_mdp_pp)); + if (clear_user(*pp, alloc_size)) + return -EFAULT; + if (put_user((void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)), + &(*pp)->data.lut_cfg_data.data. + hist_lut_data.cfg_payload)) + return -EFAULT; break; default: *pp = compat_alloc_user_space(alloc_size); @@ -2933,7 +2941,8 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, alloc_size, lut_type); return -ENOMEM; } - memset(*pp, 0, alloc_size); + if (clear_user(*pp, alloc_size)) + return -EFAULT; break; } break; @@ -2945,10 +2954,12 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, alloc_size); return -ENOMEM; } - memset(*pp, 0, alloc_size); - (*pp)->data.pcc_cfg_data.cfg_payload = - (void *)((unsigned long)(*pp) + - sizeof(struct msmfb_mdp_pp)); + if (clear_user(*pp, alloc_size)) + return -EFAULT; + if (put_user((void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)), + &(*pp)->data.pcc_cfg_data.cfg_payload)) + return -EFAULT; break; case mdp_op_gamut_cfg: alloc_size += __pp_compat_size_gamut(); @@ -2958,10 +2969,12 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, alloc_size); return -ENOMEM; } - memset(*pp, 0, alloc_size); - (*pp)->data.gamut_cfg_data.cfg_payload = - (void *)((unsigned long)(*pp) + - sizeof(struct msmfb_mdp_pp)); + if (clear_user(*pp, alloc_size)) + return -EFAULT; + if (put_user((void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)), + &(*pp)->data.gamut_cfg_data.cfg_payload)) + return -EFAULT; break; case mdp_op_pa_v2_cfg: alloc_size += __pp_compat_size_pa(); @@ -2971,16 +2984,19 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, alloc_size); return -ENOMEM; } - memset(*pp, 0, alloc_size); - (*pp)->data.pa_v2_cfg_data.cfg_payload = - (void *)((unsigned long)(*pp) + - sizeof(struct msmfb_mdp_pp)); + if (clear_user(*pp, alloc_size)) + return -EFAULT; + if (put_user((void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)), + &(*pp)->data.pa_v2_cfg_data.cfg_payload)) + return -EFAULT; break; default: *pp = compat_alloc_user_space(alloc_size); if (*pp == NULL) return -ENOMEM; - memset(*pp, 0, alloc_size); + if (clear_user(*pp, alloc_size)) + return -EFAULT; break; } return 0; @@ -3398,7 +3414,9 @@ static int mdss_histo_compat_ioctl(struct fb_info *info, unsigned int cmd, sizeof(struct mdp_histogram_start_req)); return -EINVAL; } - memset(hist_req, 0, sizeof(struct mdp_histogram_start_req)); + if (clear_user(hist_req, + sizeof(struct mdp_histogram_start_req))) + return -EFAULT; ret = __from_user_hist_start_req(hist_req32, hist_req); if (ret) goto histo_compat_err; @@ -3418,7 +3436,8 @@ static int mdss_histo_compat_ioctl(struct fb_info *info, unsigned int cmd, sizeof(struct mdp_histogram_data)); return -EINVAL; } - memset(hist, 0, sizeof(struct mdp_histogram_data)); + if (clear_user(hist, sizeof(struct mdp_histogram_data))) + return -EFAULT; ret = __from_user_hist_data(hist32, hist); if (ret) goto histo_compat_err; @@ -3921,7 +3940,7 @@ static int __to_user_mdp_overlay(struct mdp_overlay32 __user *ov32, } -static int __from_user_mdp_overlay(struct mdp_overlay *ov, +static int __from_user_mdp_overlay(struct mdp_overlay __user *ov, struct mdp_overlay32 __user *ov32) { __u32 data; @@ -3980,12 +3999,12 @@ static int __from_user_mdp_overlay(struct mdp_overlay *ov, return 0; } -static int __from_user_mdp_overlaylist(struct mdp_overlay_list *ovlist, - struct mdp_overlay_list32 *ovlist32, +static int __from_user_mdp_overlaylist(struct mdp_overlay_list __user *ovlist, + struct mdp_overlay_list32 __user *ovlist32, struct mdp_overlay **to_list_head) { __u32 i, ret; - unsigned long data, from_list_head; + unsigned long data, from_list_head, num_overlays; struct mdp_overlay32 *iter; if (!to_list_head || !ovlist32 || !ovlist) { @@ -4006,11 +4025,13 @@ static int __from_user_mdp_overlaylist(struct mdp_overlay_list *ovlist, sizeof(ovlist32->processed_overlays))) return -EFAULT; - if (get_user(data, &ovlist32->overlay_list)) { + if (get_user(data, &ovlist32->overlay_list) || + get_user(num_overlays, &ovlist32->num_overlays)) { ret = -EFAULT; goto validate_exit; } - for (i = 0; i < ovlist32->num_overlays; i++) { + + for (i = 0; i < num_overlays; i++) { if (get_user(from_list_head, (__u32 *)data + i)) { ret = -EFAULT; goto validate_exit; @@ -4023,7 +4044,8 @@ static int __from_user_mdp_overlaylist(struct mdp_overlay_list *ovlist, goto validate_exit; } } - ovlist->overlay_list = to_list_head; + if (put_user(to_list_head, &ovlist->overlay_list)) + return -EFAULT; return 0; @@ -4032,8 +4054,8 @@ static int __from_user_mdp_overlaylist(struct mdp_overlay_list *ovlist, return -EFAULT; } -static int __to_user_mdp_overlaylist(struct mdp_overlay_list32 *ovlist32, - struct mdp_overlay_list *ovlist, +static int __to_user_mdp_overlaylist(struct mdp_overlay_list32 __user *ovlist32, + struct mdp_overlay_list __user *ovlist, struct mdp_overlay **l_ptr) { __u32 i, ret; @@ -4106,31 +4128,33 @@ static u32 __pp_sspp_size(void) return size; } -static int __pp_sspp_set_offsets(struct mdp_overlay *ov) +static int __pp_sspp_set_offsets(struct mdp_overlay __user *ov) { if (!ov) { pr_err("invalid overlay pointer\n"); return -EFAULT; } - ov->overlay_pp_cfg.igc_cfg.cfg_payload = (void *)((unsigned long)ov + - sizeof(struct mdp_overlay)); - ov->overlay_pp_cfg.pa_v2_cfg_data.cfg_payload = - ov->overlay_pp_cfg.igc_cfg.cfg_payload + - sizeof(struct mdp_igc_lut_data_v1_7); - ov->overlay_pp_cfg.pcc_cfg_data.cfg_payload = - ov->overlay_pp_cfg.pa_v2_cfg_data.cfg_payload + - sizeof(struct mdp_pa_data_v1_7); - ov->overlay_pp_cfg.hist_lut_cfg.cfg_payload = - ov->overlay_pp_cfg.pcc_cfg_data.cfg_payload + - sizeof(struct mdp_pcc_data_v1_7); + if (put_user((void *)((unsigned long)ov + sizeof(struct mdp_overlay)), + &(ov->overlay_pp_cfg.igc_cfg.cfg_payload)) || + put_user(ov->overlay_pp_cfg.igc_cfg.cfg_payload + + sizeof(struct mdp_igc_lut_data_v1_7), + &(ov->overlay_pp_cfg.pa_v2_cfg_data.cfg_payload)) || + put_user(ov->overlay_pp_cfg.pa_v2_cfg_data.cfg_payload + + sizeof(struct mdp_pa_data_v1_7), + &(ov->overlay_pp_cfg.pcc_cfg_data.cfg_payload)) || + put_user(ov->overlay_pp_cfg.pcc_cfg_data.cfg_payload + + sizeof(struct mdp_pcc_data_v1_7), + &(ov->overlay_pp_cfg.hist_lut_cfg.cfg_payload))) + return -EFAULT; return 0; } int mdss_compat_overlay_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg, struct file *file) { - struct mdp_overlay *ov, **layers_head; - struct mdp_overlay32 *ov32; + struct mdp_overlay **layers_head; + struct mdp_overlay __user *ov; + struct mdp_overlay32 __user *ov32; struct mdp_overlay_list __user *ovlist; struct mdp_overlay_list32 __user *ovlist32; size_t layers_refs_sz, layers_sz, prepare_sz; -- GitLab From 79ff6071d76a9a6f452a5a1aff3c34d33e5280a6 Mon Sep 17 00:00:00 2001 From: Venkataraman Nerellapalli Date: Tue, 17 Jul 2018 17:05:36 +0530 Subject: [PATCH 469/604] defconfig: msm8953: Add goodix touch support Enable goodix touch driver in msm8953_defconfig and msm8953-perf_defconfig. Change-Id: I94e5097c73eab45eb57433b51c8e6f846d5a8b73 Signed-off-by: Venkataraman Nerellapalli Signed-off-by: Vijay Navnath Kamble --- arch/arm/configs/msm8953-perf_defconfig | 3 +++ arch/arm/configs/msm8953_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig index dab1a183c731..3d716a6b191f 100644 --- a/arch/arm/configs/msm8953-perf_defconfig +++ b/arch/arm/configs/msm8953-perf_defconfig @@ -310,6 +310,9 @@ CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_FT5X06=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y +CONFIG_TOUCHSCREEN_GT9XX_v28=y +CONFIG_TOUCHSCREEN_GT9XX_UPDATE=y +CONFIG_TOUCHSCREEN_GT9XX_TOOL=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig index abe1d7786664..34f91220f604 100644 --- a/arch/arm/configs/msm8953_defconfig +++ b/arch/arm/configs/msm8953_defconfig @@ -315,6 +315,9 @@ CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_FT5X06=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y +CONFIG_TOUCHSCREEN_GT9XX_v28=y +CONFIG_TOUCHSCREEN_GT9XX_UPDATE=y +CONFIG_TOUCHSCREEN_GT9XX_TOOL=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y -- GitLab From 78938283004f68e007bfab562594cfe18d9ac73b Mon Sep 17 00:00:00 2001 From: Tirupathi Reddy Date: Thu, 19 Jul 2018 19:26:05 +0530 Subject: [PATCH 470/604] msm: qpnp-power-on: configure KPDPWR_N S2 for HARD_RESET at TWM entry Configure KPDPWR_N to S2 during TWM entry to make sure that PMIC does a HARD_RESET during TWM if S2 reset is initiated. Change-Id: I4731487a2487af8aca8d5c30835ec6d87ee8fdc8 Signed-off-by: Tirupathi Reddy Signed-off-by: Anirudh Ghayal --- drivers/input/misc/qpnp-power-on.c | 39 ++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/input/misc/qpnp-power-on.c b/drivers/input/misc/qpnp-power-on.c index 93c28ef127e2..65379ed8ed35 100644 --- a/drivers/input/misc/qpnp-power-on.c +++ b/drivers/input/misc/qpnp-power-on.c @@ -487,6 +487,19 @@ static ssize_t qpnp_pon_dbc_store(struct device *dev, return size; } +static struct qpnp_pon_config * +qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type) +{ + int i; + + for (i = 0; i < pon->num_pon_config; i++) { + if (pon_type == pon->pon_cfg[i].pon_type) + return &pon->pon_cfg[i]; + } + + return NULL; +} + static DEVICE_ATTR(debounce_us, 0664, qpnp_pon_dbc_show, qpnp_pon_dbc_store); #define PON_TWM_ENTRY_PBS_BIT BIT(0) @@ -496,6 +509,7 @@ static int qpnp_pon_reset_config(struct qpnp_pon *pon, int rc; bool disable = false; u16 rst_en_reg; + struct qpnp_pon_config *cfg; /* Ignore the PS_HOLD reset config if TWM ENTRY is enabled */ if (pon->support_twm_config && pon->twm_state == PMIC_TWM_ENABLE) { @@ -506,6 +520,18 @@ static int qpnp_pon_reset_config(struct qpnp_pon *pon, rc); return rc; } + + cfg = qpnp_get_cfg(pon, PON_KPDPWR); + if (cfg) { + /* configure KPDPWR_S2 to Hard reset */ + rc = qpnp_pon_masked_write(pon, cfg->s2_cntl_addr, + QPNP_PON_S2_CNTL_TYPE_MASK, + PON_POWER_OFF_HARD_RESET); + if (rc < 0) + pr_err("Unable to config KPDPWR_N S2 for hard-reset rc=%d\n", + rc); + } + pr_crit("PMIC configured for TWM entry\n"); return 0; } @@ -901,19 +927,6 @@ static int qpnp_pon_store_and_clear_warm_reset(struct qpnp_pon *pon) return 0; } -static struct qpnp_pon_config * -qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type) -{ - int i; - - for (i = 0; i < pon->num_pon_config; i++) { - if (pon_type == pon->pon_cfg[i].pon_type) - return &pon->pon_cfg[i]; - } - - return NULL; -} - static int qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type) { -- GitLab From 628a5f1a34ec620af96853c4270462dd894e6592 Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Thu, 19 Jul 2018 19:34:41 +0530 Subject: [PATCH 471/604] msm: qpnp-haptic: Force disable haptics during shutdown Force disable haptics during shutdown to avoid the device from vibrating during TWM entry. Change-Id: I6bfdf4d9a634dec1aa56a1fdc5553cefe4a94a73 Signed-off-by: Anirudh Ghayal --- drivers/leds/leds-qpnp-haptics.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/leds/leds-qpnp-haptics.c b/drivers/leds/leds-qpnp-haptics.c index 8a850c526f60..3f97c803586e 100644 --- a/drivers/leds/leds-qpnp-haptics.c +++ b/drivers/leds/leds-qpnp-haptics.c @@ -2515,6 +2515,16 @@ static int qpnp_haptics_remove(struct platform_device *pdev) return 0; } +static void qpnp_haptics_shutdown(struct platform_device *pdev) +{ + struct hap_chip *chip = dev_get_drvdata(&pdev->dev); + + cancel_work_sync(&chip->haptics_work); + + /* disable haptics */ + qpnp_haptics_mod_enable(chip, false); +} + static const struct dev_pm_ops qpnp_haptics_pm_ops = { .suspend = qpnp_haptics_suspend, }; @@ -2532,6 +2542,7 @@ static struct platform_driver qpnp_haptics_driver = { }, .probe = qpnp_haptics_probe, .remove = qpnp_haptics_remove, + .shutdown = qpnp_haptics_shutdown, }; module_platform_driver(qpnp_haptics_driver); -- GitLab From bdf36373d6bfd675c81bd5a479bf0d99f86716df Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Mon, 23 Jul 2018 10:37:20 +0530 Subject: [PATCH 472/604] power: qpnp-qg: Update the recharge/hold-SOC logic In the current code the hold-soc logic scales the SOC when there is a discharge or a re-charge event. However, the expectation is to hold the SOC to 100% until we recharge back to 100%. Only start scaling the SOC if we are indeed discharging (msoc < recharge_soc) or USB is removed. Also, scale the SOC slower if we are in the maintenance mode. Also, the expectation of recharge SOC is to start start recharge at that SOC value and not a point lower, fix it accordingly. Change-Id: Ifb21caf0531fdf042d46a8fd906cb4e067e9910f Signed-off-by: Anirudh Ghayal --- drivers/power/supply/qcom/qg-core.h | 2 ++ drivers/power/supply/qcom/qg-soc.c | 47 ++++++++++++++++++++++---- drivers/power/supply/qcom/qpnp-qg.c | 52 ++++++++++++++++++++--------- 3 files changed, 78 insertions(+), 23 deletions(-) diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h index 91279c05defb..b0ff18c5cdb0 100644 --- a/drivers/power/supply/qcom/qg-core.h +++ b/drivers/power/supply/qcom/qg-core.h @@ -134,6 +134,7 @@ struct qpnp_qg { u32 esr_last; ktime_t last_user_update_time; ktime_t last_fifo_update_time; + unsigned long last_maint_soc_update_time; /* soc params */ int catch_up_soc; @@ -145,6 +146,7 @@ struct qpnp_qg { int full_soc; int sys_soc; int last_adj_ssoc; + int recharge_soc; struct alarm alarm_timer; u32 sdam_data[SDAM_MAX]; diff --git a/drivers/power/supply/qcom/qg-soc.c b/drivers/power/supply/qcom/qg-soc.c index 12e19a58af83..711bd2b9e453 100644 --- a/drivers/power/supply/qcom/qg-soc.c +++ b/drivers/power/supply/qcom/qg-soc.c @@ -41,6 +41,11 @@ module_param_named( soc_cold_interval_ms, qg_delta_soc_cold_interval_ms, int, 0600 ); +static int qg_maint_soc_update_ms = 120000; +module_param_named( + maint_soc_update_ms, qg_maint_soc_update_ms, int, 0600 +); + int qg_adjust_sys_soc(struct qpnp_qg *chip) { int soc, vbat_uv, rc; @@ -93,10 +98,11 @@ static void get_next_update_time(struct qpnp_qg *chip) /* Lower the delta soc interval by half at cold */ rc = qg_get_battery_temp(chip, &batt_temp); - if (rc < 0) - pr_err("Failed to read battery temperature rc=%d\n", rc); - else if (batt_temp < chip->dt.cold_temp_threshold) + if (!rc && batt_temp < chip->dt.cold_temp_threshold) min_delta_soc_interval_ms = qg_delta_soc_cold_interval_ms; + else if (chip->maint_soc > 0 && chip->maint_soc >= chip->recharge_soc) + /* if in maintenance mode scale slower */ + min_delta_soc_interval_ms = qg_maint_soc_update_ms; if (!min_delta_soc_interval_ms) min_delta_soc_interval_ms = 1000; /* 1 second */ @@ -135,9 +141,34 @@ static bool is_scaling_required(struct qpnp_qg *chip) return true; } +static bool maint_soc_timeout(struct qpnp_qg *chip) +{ + unsigned long now; + int rc; + + if (chip->maint_soc < 0) + return false; + + rc = get_rtc_time(&now); + if (rc < 0) + return true; + + /* Do not scale if we have dropped below recharge-soc */ + if (chip->maint_soc < chip->recharge_soc) + return true; + + if ((now - chip->last_maint_soc_update_time) >= + (qg_maint_soc_update_ms / 1000)) { + chip->last_maint_soc_update_time = now; + return true; + } + + return false; +} + static void update_msoc(struct qpnp_qg *chip) { - int rc = 0, batt_temp = 0, batt_soc_32bit = 0; + int rc = 0, sdam_soc, batt_temp = 0, batt_soc_32bit = 0; bool usb_present = is_usb_present(chip); if (chip->catch_up_soc > chip->msoc) { @@ -150,7 +181,8 @@ static void update_msoc(struct qpnp_qg *chip) } chip->msoc = CAP(0, 100, chip->msoc); - if (chip->maint_soc > 0 && chip->msoc < chip->maint_soc) { + if (chip->maint_soc > 0 && chip->msoc < chip->maint_soc + && maint_soc_timeout(chip)) { chip->maint_soc -= chip->dt.delta_soc; chip->maint_soc = CAP(0, 100, chip->maint_soc); } @@ -165,8 +197,9 @@ static void update_msoc(struct qpnp_qg *chip) pr_err("Failed to update MSOC register rc=%d\n", rc); /* update SDAM with the new MSOC */ - chip->sdam_data[SDAM_SOC] = chip->msoc; - rc = qg_sdam_write(SDAM_SOC, chip->msoc); + sdam_soc = (chip->maint_soc > 0) ? chip->maint_soc : chip->msoc; + chip->sdam_data[SDAM_SOC] = sdam_soc; + rc = qg_sdam_write(SDAM_SOC, sdam_soc); if (rc < 0) pr_err("Failed to update SDAM with MSOC rc=%d\n", rc); diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 39869c140271..88f8bb789a4c 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -1858,9 +1858,11 @@ static int qg_charge_full_update(struct qpnp_qg *chip) recharge_soc = DEFAULT_RECHARGE_SOC; } recharge_soc = prop.intval; + chip->recharge_soc = recharge_soc; - qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d health=%d charge_full=%d\n", - chip->msoc, health, chip->charge_full); + qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d health=%d charge_full=%d charge_done=%d\n", + chip->msoc, health, chip->charge_full, + chip->charge_done); if (chip->charge_done && !chip->charge_full) { if (chip->msoc >= 99 && health == POWER_SUPPLY_HEALTH_GOOD) { chip->charge_full = true; @@ -1871,10 +1873,18 @@ static int qg_charge_full_update(struct qpnp_qg *chip) qg_dbg(chip, QG_DEBUG_STATUS, "Terminated charging @ msoc=%d\n", chip->msoc); } - } else if ((!chip->charge_done || chip->msoc < recharge_soc) + } else if ((!chip->charge_done || chip->msoc <= recharge_soc) && chip->charge_full) { - if (chip->wa_flags & QG_RECHARGE_SOC_WA) { + bool usb_present = is_usb_present(chip); + + /* + * force a recharge only if SOC <= recharge SOC and + * we have not started charging. + */ + if ((chip->wa_flags & QG_RECHARGE_SOC_WA) && + usb_present && chip->msoc <= recharge_soc && + chip->charge_status != POWER_SUPPLY_STATUS_CHARGING) { /* Force recharge */ prop.intval = 0; rc = power_supply_set_property(chip->batt_psy, @@ -1882,23 +1892,33 @@ static int qg_charge_full_update(struct qpnp_qg *chip) if (rc < 0) pr_err("Failed to force recharge rc=%d\n", rc); else - qg_dbg(chip, QG_DEBUG_STATUS, - "Forced recharge\n"); + qg_dbg(chip, QG_DEBUG_STATUS, "Forced recharge\n"); } + + if (chip->charge_done) + return 0; /* wait for recharge */ + /* - * If recharge or discharge has started and - * if linearize soc dtsi property defined - * scale msoc from 100% for better UX. + * If SOC has indeed dropped below recharge-SOC or + * the USB is removed, if linearize-soc is set scale + * msoc from 100% for better UX. */ - if (chip->dt.linearize_soc && chip->msoc < 99) { - chip->maint_soc = FULL_SOC; - qg_scale_soc(chip, false); - } - - qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d recharge_soc=%d charge_full (1->0)\n", + if (chip->msoc < recharge_soc || !usb_present) { + if (chip->dt.linearize_soc) { + get_rtc_time(&chip->last_maint_soc_update_time); + chip->maint_soc = FULL_SOC; + qg_scale_soc(chip, false); + } + chip->charge_full = false; + qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d recharge_soc=%d charge_full (1->0)\n", chip->msoc, recharge_soc); - chip->charge_full = false; + } else { + /* continue with charge_full state */ + qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d recharge_soc=%d charge_full=%d usb_present=%d\n", + chip->msoc, recharge_soc, + chip->charge_full, usb_present); + } } out: return 0; -- GitLab From 0c4a0666fc4b0724ea0eb39fab436ee611672acb Mon Sep 17 00:00:00 2001 From: John Dias Date: Fri, 22 Jun 2018 12:27:38 -0700 Subject: [PATCH 473/604] 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 4fe11819e5fc..d2e78d7809b9 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -701,14 +701,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 25e4ce4c717a0940f5f978a75d805f4e4b645ed1 Mon Sep 17 00:00:00 2001 From: Narender Ankam Date: Tue, 24 Jul 2018 14:18:07 +0530 Subject: [PATCH 474/604] drm/msm/dp: clear CP_IRQ bit during hdcp2p2 authentication Though CP_IRQ bit is being cleared during HDCP1.4 authentication, it is not being cleared during HDCP2.2 authentication. This change now clears CP_IRQ bit after processing cp_irq handler during HDCP2.2 authentication. Change-Id: Ice165322d4fc5bfa5c43d62e33d2eab5452d9a29 Signed-off-by: Narender Ankam --- drivers/gpu/drm/msm/dp/dp_hdcp2p2.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c index 2b7b2171351e..f277ac0f36f5 100644 --- a/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c +++ b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c @@ -26,6 +26,9 @@ #define DP_INTR_STATUS2 (0x00000024) #define DP_INTR_STATUS3 (0x00000028) + +#define DP_DPCD_CP_IRQ (0x201) + #define dp_read(offset) readl_relaxed((offset)) #define dp_write(offset, data) writel_relaxed((data), (offset)) #define DP_HDCP_RXCAPS_LENGTH 3 @@ -393,6 +396,7 @@ static int dp_hdcp2p2_aux_write_message(struct dp_hdcp2p2_ctrl *ctrl, if (bytes_written != write_size) { pr_err("fail: offset(0x%x), size(0x%x), rc(0x%x)\n", offset, write_size, bytes_written); + rc = bytes_written; break; } @@ -675,6 +679,18 @@ static int dp_hdcp2p2_read_rx_status(struct dp_hdcp2p2_ctrl *ctrl, return rc; } +static void dp_hdcp2p2_clear_cp_irq(struct dp_hdcp2p2_ctrl *ctrl) +{ + int rc = 0; + u8 buf = BIT(2); + u32 const default_timeout_us = 500; + + rc = dp_hdcp2p2_aux_write_message(ctrl, &buf, 1, + DP_DPCD_CP_IRQ, default_timeout_us); + if (rc) + pr_err("error clearing irq_vector\n"); +} + static int dp_hdcp2p2_cp_irq(void *input) { int rc = 0; @@ -709,6 +725,7 @@ static int dp_hdcp2p2_cp_irq(void *input) kthread_queue_work(&ctrl->worker, &ctrl->link); + dp_hdcp2p2_clear_cp_irq(ctrl); return 0; error: return rc; -- GitLab From c49973490281f950df0a9b58ff6b1d55104e7c55 Mon Sep 17 00:00:00 2001 From: Anurag Chouhan Date: Tue, 17 Jul 2018 14:35:54 +0530 Subject: [PATCH 475/604] icnss: Add a flag to indicare FW rejuvenate Add a flag to maintain fw rejuvenate state, set if fw rejuvenate happens and reset at fw ready. export an API to the wlan host driver to distinguish the case of ssr or pdr with the FW rejuventae. Change-Id: I7a01cc4996f68f78aa13eacf36648331a701882a Signed-off-by: Anurag Chouhan --- drivers/soc/qcom/icnss.c | 14 ++++++++++++++ include/soc/qcom/icnss.h | 1 + 2 files changed, 15 insertions(+) diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 49719decd6ec..39b79f66804e 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -284,6 +284,7 @@ enum icnss_driver_state { ICNSS_HOST_TRIGGERED_PDR, ICNSS_FW_DOWN, ICNSS_DRIVER_UNLOADING, + ICNSS_REJUVENATE, }; struct ce_irq_list { @@ -1172,6 +1173,14 @@ bool icnss_is_fw_down(void) } EXPORT_SYMBOL(icnss_is_fw_down); +bool icnss_is_rejuvenate(void) +{ + if (!penv) + return false; + else + return test_bit(ICNSS_REJUVENATE, &penv->state); +} +EXPORT_SYMBOL(icnss_is_rejuvenate); int icnss_power_off(struct device *dev) { @@ -2093,6 +2102,7 @@ static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle, event_data->crashed = true; event_data->fw_rejuvenate = true; fw_down_data.crashed = true; + set_bit(ICNSS_REJUVENATE, &penv->state); icnss_call_driver_uevent(penv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, @@ -2283,6 +2293,7 @@ static int icnss_pd_restart_complete(struct icnss_priv *priv) icnss_call_driver_shutdown(priv); + clear_bit(ICNSS_REJUVENATE, &penv->state); clear_bit(ICNSS_PD_RESTART, &priv->state); priv->early_crash_ind = false; @@ -4000,6 +4011,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv) case ICNSS_FW_DOWN: seq_puts(s, "FW DOWN"); continue; + case ICNSS_REJUVENATE: + seq_puts(s, "FW REJUVENATE"); + continue; case ICNSS_DRIVER_UNLOADING: seq_puts(s, "DRIVER UNLOADING"); } diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h index 31b4cceec198..7ef3db418100 100644 --- a/include/soc/qcom/icnss.h +++ b/include/soc/qcom/icnss.h @@ -142,5 +142,6 @@ extern unsigned int icnss_socinfo_get_serial_number(struct device *dev); extern bool icnss_is_qmi_disable(struct device *dev); extern bool icnss_is_fw_ready(void); extern bool icnss_is_fw_down(void); +extern bool icnss_is_rejuvenate(void); extern int icnss_trigger_recovery(struct device *dev); #endif /* _ICNSS_WLAN_H_ */ -- GitLab From d71c6a005622ae4c69fa2ad78cdd4ee47da1ee9a Mon Sep 17 00:00:00 2001 From: Mohit Aggarwal Date: Mon, 9 Jul 2018 16:03:37 +0530 Subject: [PATCH 476/604] diag: Featurize IPC logging Currently, in case IPC logging related config is disabled then there are some unwanted error logs in kernel logs. Featurize IPC logging to get rid of error logs. Change-Id: I8455f5e3a13cf58b4d65d1e1a5c4f1ec0adedabf Signed-off-by: Mohit Aggarwal --- drivers/char/diag/diag_debugfs.c | 9 +++++++-- drivers/char/diag/diag_ipc_logging.h | 4 +--- drivers/char/diag/diagchar_core.c | 4 ++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c index a7f29e63e214..acee74a14cda 100644 --- a/drivers/char/diag/diag_debugfs.c +++ b/drivers/char/diag/diag_debugfs.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* 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 @@ -797,6 +797,7 @@ static ssize_t diag_dbgfs_read_glinkinfo(struct file *file, char __user *ubuf, return ret; } +#ifdef CONFIG_IPC_LOGGING static ssize_t diag_dbgfs_write_debug(struct file *fp, const char __user *buf, size_t count, loff_t *ppos) { @@ -827,6 +828,7 @@ static ssize_t diag_dbgfs_write_debug(struct file *fp, const char __user *buf, diag_debug_mask = (uint16_t)value; return count; } +#endif #ifdef CONFIG_DIAGFWD_BRIDGE_CODE #ifdef CONFIG_USB_QCOM_DIAG_BRIDGE @@ -1086,9 +1088,11 @@ const struct file_operations diag_dbgfs_power_ops = { .read = diag_dbgfs_read_power, }; +#ifdef CONFIG_IPC_LOGGING const struct file_operations diag_dbgfs_debug_ops = { .write = diag_dbgfs_write_debug }; +#endif int diag_debugfs_init(void) { @@ -1145,11 +1149,12 @@ int diag_debugfs_init(void) if (!entry) goto err; +#ifdef CONFIG_IPC_LOGGING entry = debugfs_create_file("debug", 0444, diag_dbgfs_dent, 0, &diag_dbgfs_debug_ops); if (!entry) goto err; - +#endif #ifdef CONFIG_DIAGFWD_BRIDGE_CODE entry = debugfs_create_file("bridge", 0444, diag_dbgfs_dent, 0, &diag_dbgfs_bridge_ops); diff --git a/drivers/char/diag/diag_ipc_logging.h b/drivers/char/diag/diag_ipc_logging.h index 4b8dd1b12c1c..839c8ca02e7c 100644 --- a/drivers/char/diag/diag_ipc_logging.h +++ b/drivers/char/diag/diag_ipc_logging.h @@ -26,9 +26,7 @@ #define DIAG_DEBUG_BRIDGE 0x0040 #define DIAG_DEBUG_CONTROL 0x0080 -#define DIAG_DEBUG - -#ifdef DIAG_DEBUG +#ifdef CONFIG_IPC_LOGGING extern uint16_t diag_debug_mask; extern void *diag_ipc_log; diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index a1692300b0f6..8b089eb6c850 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -162,7 +162,7 @@ static struct mutex apps_data_mutex; #define DIAGPKT_MAX_DELAYED_RSP 0xFFFF -#ifdef DIAG_DEBUG +#ifdef CONFIG_IPC_LOGGING uint16_t diag_debug_mask; void *diag_ipc_log; #endif @@ -3804,7 +3804,7 @@ void diag_ws_release(void) pm_relax(driver->diag_dev); } -#ifdef DIAG_DEBUG +#ifdef CONFIG_IPC_LOGGING static void diag_debug_init(void) { diag_ipc_log = ipc_log_context_create(DIAG_IPC_LOG_PAGES, "diag", 0); -- GitLab From 255fa4f1a9ef8db3d35d2dcbcd3051d1f7f34241 Mon Sep 17 00:00:00 2001 From: Naitik Bharadiya Date: Thu, 28 Jun 2018 11:41:39 +0530 Subject: [PATCH 477/604] ARM: dts: msm: Add NFC device node for MSM8917 Add NFC device tree node and associated GPIO configurations for MSM8917 CDP,MTP and QRD platforms. Change-Id: If1f251e8a6779978a407112d79b7046fffba6b42 Signed-off-by: Naitik Bharadiya --- .../dts/qcom/msm8917-cdp-ml-touch-overlay.dts | 1 - arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi | 35 +++++++++ .../boot/dts/qcom/msm8917-mtp-overlay.dts | 1 - arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi | 34 ++++++++ arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi | 78 ++++++++++++------- .../boot/dts/qcom/msm8917-qrd-overlay.dts | 1 - arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi | 34 ++++++++ 7 files changed, 155 insertions(+), 29 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8917-cdp-ml-touch-overlay.dts b/arch/arm64/boot/dts/qcom/msm8917-cdp-ml-touch-overlay.dts index 377eda4ec77b..73ea29b2e200 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-cdp-ml-touch-overlay.dts +++ b/arch/arm64/boot/dts/qcom/msm8917-cdp-ml-touch-overlay.dts @@ -14,7 +14,6 @@ /dts-v1/; /plugin/; -#include #include "msm8917-cdp.dtsi" #include "msm8917-cdp-mirror-lake-touch.dtsi" #include "msm8917-audio-cdp.dtsi" diff --git a/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi index 6a2fecde320d..a804edd3cf89 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi @@ -11,6 +11,8 @@ * GNU General Public License for more details. */ +#include + &soc { gpio_keys { compatible = "gpio-keys"; @@ -156,6 +158,39 @@ }; }; +&pm8937_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio5"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; +}; + +&i2c_5 { /* BLSP2 QUP1 (NFC) */ + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 17 0x00>; + qcom,nq-ven = <&tlmm 16 0x00>; + qcom,nq-firm = <&tlmm 130 0x00>; + qcom,nq-clkreq = <&pm8937_gpios 5 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK2"; + interrupts = <17 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_disable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; + clocks = <&clock_gcc clk_bb_clk2_pin>; + clock-names = "ref_clk"; + }; +}; + &sdhc_1 { /* device core power supply */ vdd-supply = <&pm8937_l8>; diff --git a/arch/arm64/boot/dts/qcom/msm8917-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8917-mtp-overlay.dts index 920bcaed74e7..0540e0925af3 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/msm8917-mtp-overlay.dts @@ -15,7 +15,6 @@ /plugin/; #include -#include #include #include "msm8917-mtp.dtsi" diff --git a/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi index 7f35e1ebcf41..9a3b6daed188 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi @@ -11,6 +11,7 @@ * GNU General Public License for more details. */ +#include #include "msm8917-camera-sensor-mtp.dtsi" &blsp1_uart2 { @@ -19,6 +20,39 @@ pinctrl-0 = <&uart_console_active>; }; +&pm8937_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio5"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; +}; + +&i2c_5 { /* BLSP2 QUP1 (NFC) */ + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 17 0x00>; + qcom,nq-ven = <&tlmm 16 0x00>; + qcom,nq-firm = <&tlmm 130 0x00>; + qcom,nq-clkreq = <&pm8937_gpios 5 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK2"; + interrupts = <17 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_disable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; + clocks = <&clock_gcc clk_bb_clk2_pin>; + clock-names = "ref_clk"; + }; +}; + &sdhc_1 { /* device core power supply */ vdd-supply = <&pm8937_l8>; diff --git a/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi index 858936d86e85..0e613b6c2736 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi @@ -1345,39 +1345,65 @@ }; }; - pmx_rd_nfc_int { - /*qcom,pins = <&gp 17>;*/ - pins = "gpio17"; - qcom,pin-func = <0>; - qcom,num-grp-pins = <1>; - label = "pmx_nfc_int"; - - nfc_int_active: active { - drive-strength = <6>; - bias-pull-up; + nfc { + nfc_int_active: nfc_int_active { + /* active state */ + mux { + /* GPIO 17 NFC Read Interrupt */ + pins = "gpio17"; + function = "gpio"; + }; + + config { + pins = "gpio17"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; }; - nfc_int_suspend: suspend { - drive-strength = <6>; - bias-pull-up; + nfc_int_suspend: nfc_int_suspend { + /* sleep state */ + mux { + /* GPIO 17 NFC Read Interrupt */ + pins = "gpio17"; + function = "gpio"; + }; + + config { + pins = "gpio17"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; }; - }; - pmx_nfc_reset { - /*qcom,pins = <&gp 16>;*/ - pins = "gpio16"; - qcom,pin-func = <0>; - qcom,num-grp-pins = <1>; - label = "pmx_nfc_disable"; + nfc_disable_active: nfc_disable_active { + /* active state */ + mux { + /* 16: NFC ENABLE 130: FW DNLD */ + pins = "gpio16", "gpio130"; + function = "gpio"; + }; - nfc_disable_active: active { - drive-strength = <6>; - bias-pull-up; + config { + pins = "gpio16", "gpio130"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; }; - nfc_disable_suspend: suspend { - drive-strength = <6>; - bias-disable; + nfc_disable_suspend: nfc_disable_suspend { + /* sleep state */ + mux { + /* 16: NFC ENABLE 130: FW DNLD */ + pins = "gpio16", "gpio130"; + function = "gpio"; + }; + + config { + pins = "gpio16", "gpio130"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8917-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/msm8917-qrd-overlay.dts index 651775726979..9b4d8f4b3404 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/msm8917-qrd-overlay.dts @@ -14,7 +14,6 @@ /dts-v1/; /plugin/; -#include #include "msm8917-qrd.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi b/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi index d5fd1ff99cd7..5c63ed376376 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi @@ -10,6 +10,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +#include #include "msm8917-camera-sensor-qrd.dtsi" #include "msm8937-mdss-panels.dtsi" @@ -19,6 +20,39 @@ pinctrl-0 = <&uart_console_active>; }; +&pm8937_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio5"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; +}; + +&i2c_5 { /* BLSP2 QUP1 (NFC) */ + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 17 0x00>; + qcom,nq-ven = <&tlmm 16 0x00>; + qcom,nq-firm = <&tlmm 130 0x00>; + qcom,nq-clkreq = <&pm8937_gpios 5 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK2"; + interrupts = <17 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_disable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; + clocks = <&clock_gcc clk_bb_clk2_pin>; + clock-names = "ref_clk"; + }; +}; + &sdhc_1 { /* device core power supply */ vdd-supply = <&pm8937_l8>; -- GitLab From 03dc235c2bf5137179f87420e003ea034e815b5d Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Tue, 24 Jul 2018 14:45:12 +0530 Subject: [PATCH 478/604] defconfig: Enable PM wakelock config for sdxpoorwills Enable PM wakelock config. Change-Id: I7b4ce4bc2ac9cdddbe93fa359a15c08f9e42d07d Signed-off-by: Maulik Shah --- arch/arm/configs/sdxpoorwills-perf_defconfig | 3 +++ arch/arm/configs/sdxpoorwills_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig index 258b7a260b0b..c63f2e216e50 100644 --- a/arch/arm/configs/sdxpoorwills-perf_defconfig +++ b/arch/arm/configs/sdxpoorwills-perf_defconfig @@ -41,6 +41,9 @@ CONFIG_VFP=y CONFIG_NEON=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig index 687885aa1439..8c14b142c2e1 100644 --- a/arch/arm/configs/sdxpoorwills_defconfig +++ b/arch/arm/configs/sdxpoorwills_defconfig @@ -43,6 +43,9 @@ CONFIG_VFP=y CONFIG_NEON=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y -- GitLab From 06619d65bbc40215c32a1485b96b99b527d13750 Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Thu, 28 Jun 2018 11:27:14 -0700 Subject: [PATCH 479/604] msm: gsi: increase the stop_channel timeout Increase the GSI_STOP_CMD_TIMEOUT_MS from 20 to 50 to resolve the interrupt coming too late issue Change-Id: Iff3303678996a4b4be50740bdb0813f123399d69 Signed-off-by: Skylar Chang --- drivers/platform/msm/gsi/gsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 5d8b12bb52a0..c38f1be7e3fb 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -23,7 +23,7 @@ #include "gsi_emulation.h" #define GSI_CMD_TIMEOUT (5*HZ) -#define GSI_STOP_CMD_TIMEOUT_MS 20 +#define GSI_STOP_CMD_TIMEOUT_MS 50 #define GSI_MAX_CH_LOW_WEIGHT 15 #define GSI_RESET_WA_MIN_SLEEP 1000 -- GitLab From c140b8f8945571f342856d30abdb4d1165d03684 Mon Sep 17 00:00:00 2001 From: Aravind Venkateswaran Date: Thu, 19 Jul 2018 14:53:41 -0700 Subject: [PATCH 480/604] drm/msm/dp: fix error checking for memory allocations Memory allocation using kzalloc can return a valid pointer when a zero size memory is requested. Therefore it is important to use IS_ZERO_OR_NULL macro instead of just checking for a null pointer prior to any use of the allocated memory. CRs-Fixed: 2279573 Change-Id: I3a9526347669d77bd5642195ab2681ef96ce580a Signed-off-by: Aravind Venkateswaran --- drivers/gpu/drm/msm/dp/dp_debug.c | 12 ++++++------ drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c index 359655a8f973..6e6efa5cd416 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.c +++ b/drivers/gpu/drm/msm/dp/dp_debug.c @@ -104,7 +104,7 @@ static ssize_t dp_debug_write_edid(struct file *file, size = min_t(size_t, count, SZ_1K); buf = kzalloc(size, GFP_KERNEL); - if (!buf) { + if (ZERO_OR_NULL_PTR(buf)) { rc = -ENOMEM; goto bail; } @@ -172,7 +172,7 @@ static ssize_t dp_debug_write_dpcd(struct file *file, size = min_t(size_t, count, SZ_2K); buf = kzalloc(size, GFP_KERNEL); - if (!buf) { + if (ZERO_OR_NULL_PTR(buf)) { rc = -ENOMEM; goto bail; } @@ -493,7 +493,7 @@ static ssize_t dp_debug_read_edid_modes(struct file *file, goto error; buf = kzalloc(SZ_4K, GFP_KERNEL); - if (!buf) { + if (ZERO_OR_NULL_PTR(buf)) { rc = -ENOMEM; goto error; } @@ -538,7 +538,7 @@ static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff, return 0; buf = kzalloc(SZ_4K, GFP_KERNEL); - if (!buf) + if (ZERO_OR_NULL_PTR(buf)) return -ENOMEM; rc = snprintf(buf + len, max_size, "\tstate=0x%x\n", debug->aux->state); @@ -624,7 +624,7 @@ static ssize_t dp_debug_bw_code_read(struct file *file, return 0; buf = kzalloc(SZ_4K, GFP_KERNEL); - if (!buf) + if (ZERO_OR_NULL_PTR(buf)) return -ENOMEM; len += snprintf(buf + len, (SZ_4K - len), @@ -745,7 +745,7 @@ static ssize_t dp_debug_read_hdr(struct file *file, goto error; buf = kzalloc(SZ_4K, GFP_KERNEL); - if (!buf) { + if (ZERO_OR_NULL_PTR(buf)) { rc = -ENOMEM; goto error; } diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index d58a7466b7e1..c5a1a9fcc20b 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -1130,7 +1130,7 @@ static ssize_t debugfs_misr_read(struct file *file, return 0; buf = kzalloc(max_len, GFP_KERNEL); - if (!buf) + if (ZERO_OR_NULL_PTR(buf)) return -ENOMEM; mutex_lock(&display->display_lock); @@ -1248,7 +1248,7 @@ static ssize_t debugfs_alter_esd_check_mode(struct file *file, return 0; buf = kzalloc(len, GFP_KERNEL); - if (!buf) + if (ZERO_OR_NULL_PTR(buf)) return -ENOMEM; if (copy_from_user(buf, user_buf, user_len)) { @@ -1320,7 +1320,7 @@ static ssize_t debugfs_read_esd_check_mode(struct file *file, } buf = kzalloc(len, GFP_KERNEL); - if (!buf) + if (ZERO_OR_NULL_PTR(buf)) return -ENOMEM; esd_config = &display->panel->esd_config; -- GitLab From 8ac8fb75e41a60365f02b8a6b205f84a141e384d Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Tue, 17 Jul 2018 19:56:48 +0530 Subject: [PATCH 481/604] ARM: dts: msm: Fix ab/ib values from IPA for sdxpoorwiils Voting svs from IPA including other clients on the platform takes DDR vote to NOM. Tune the AB/IB votes for snoc/ddr/ocimem/cnoc from ipa driver perspective to meet the power requirement. Change-Id: I73be05a11591c10e4c76940c38194f35e917311c Signed-off-by: Mohammed Javid --- arch/arm/boot/dts/qcom/sdxpoorwills.dtsi | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi index 2014885f81cf..82de5d202d27 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi @@ -951,24 +951,24 @@ , /* SVS2 */ - , - , - , - , + , + , + , + , , /* SVS */ - , - , - , - , + , + , + , + , , /* NOMINAL */ - , - , - , - , + , + , + , + , , /* TURBO */ -- GitLab From 1f0f03304e1de5620a012f1b8bf712fecf0370e5 Mon Sep 17 00:00:00 2001 From: Suraj Dongre Date: Fri, 13 Jul 2018 13:54:37 -0700 Subject: [PATCH 482/604] 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 d240b53b7164..152069e3616d 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 68d2677dfd7c3b11c181cb641c966a184b2611a9 Mon Sep 17 00:00:00 2001 From: Vijay Navnath Kamble Date: Mon, 23 Jul 2018 14:40:46 +0530 Subject: [PATCH 483/604] defconfig: msm: enable himax touch driver compilation for msm8953 Add support for compiling of himax touch driver for msm8953. Change-Id: I65b318cd433deac48a658186f15601ebd5b994ac Signed-off-by: Vijay Navnath Kamble --- arch/arm/configs/msm8953-perf_defconfig | 4 ++++ arch/arm/configs/msm8953_defconfig | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig index 3d716a6b191f..4b8d51319944 100644 --- a/arch/arm/configs/msm8953-perf_defconfig +++ b/arch/arm/configs/msm8953-perf_defconfig @@ -313,6 +313,10 @@ CONFIG_TOUCHSCREEN_GEN_VKEYS=y CONFIG_TOUCHSCREEN_GT9XX_v28=y CONFIG_TOUCHSCREEN_GT9XX_UPDATE=y CONFIG_TOUCHSCREEN_GT9XX_TOOL=y +CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y +CONFIG_TOUCHSCREEN_HIMAX_I2C=y +CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y +CONFIG_HMX_DB=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig index 34f91220f604..f3a9a7a0c928 100644 --- a/arch/arm/configs/msm8953_defconfig +++ b/arch/arm/configs/msm8953_defconfig @@ -318,6 +318,10 @@ CONFIG_TOUCHSCREEN_GEN_VKEYS=y CONFIG_TOUCHSCREEN_GT9XX_v28=y CONFIG_TOUCHSCREEN_GT9XX_UPDATE=y CONFIG_TOUCHSCREEN_GT9XX_TOOL=y +CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y +CONFIG_TOUCHSCREEN_HIMAX_I2C=y +CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y +CONFIG_HMX_DB=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y -- GitLab From 3281dc68cb8b7d9fd00b869ce81746131ea02538 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Fri, 20 Jul 2018 19:32:37 -0700 Subject: [PATCH 484/604] arm: mm: dma-mapping: Use iommu_attach_group pci devices may have multiple devices in the same group. Only one device from the group should call arm_iommu_attach_device, in order to prevent overriding the first device's configuration. Change-Id: I883d67a5b42991854b00bef0ea4774f24a55e25e Signed-off-by: Patrick Daly --- arch/arm/mm/dma-mapping.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index e346cf3fb947..a8f8d4610baa 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -2483,7 +2483,10 @@ static int __arm_iommu_attach_device(struct device *dev, { int err; - err = iommu_attach_device(mapping->domain, dev); + if (!dev->iommu_group) + return -EINVAL; + + err = iommu_attach_group(mapping->domain, dev->iommu_group); if (err) return err; -- GitLab From 2ec386cf934025868a9b3f09fb7d61851470fc2b Mon Sep 17 00:00:00 2001 From: Zhang Yuanfang Date: Tue, 24 Jul 2018 15:02:42 +0800 Subject: [PATCH 485/604] soc: qcom: Add check of len and base before dcc_config_add Add check of len and base before dcc_config_add for invalid value. Change-Id: Ia10ea54a24b076184a99096bb7dfc7c2790773c2 Signed-off-by: ZhangYuanfang --- drivers/soc/qcom/dcc_v2.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/soc/qcom/dcc_v2.c b/drivers/soc/qcom/dcc_v2.c index e6412905b0f9..ac509961ecbb 100644 --- a/drivers/soc/qcom/dcc_v2.c +++ b/drivers/soc/qcom/dcc_v2.c @@ -990,6 +990,14 @@ static ssize_t dcc_store_config(struct device *dev, apb_bus = 1; } + if (len == 0) + len = 1; + + if (base == 0) { + dev_err(drvdata->dev, "DCC: Invalid Address\n"); + return -EINVAL; + } + ret = dcc_config_add(drvdata, base, len, apb_bus); if (ret) return ret; -- GitLab From 7f531705ca8391432fb67df39b222e51260b0b01 Mon Sep 17 00:00:00 2001 From: Sunil Paidimarri Date: Mon, 23 Jul 2018 17:50:23 -0700 Subject: [PATCH 486/604] ARM: dts: msm: Update AXI bus votes for EMAC in sdxpoorwills Update ab votes for AXI bus to support bi-directional data rates. Change-Id: I85936c218f51667e8dcc176aa13a41605dd596af CRs-Fixed: 2283650 Acked-by: Rahul Kawadgave Signed-off-by: Sunil Paidimarri --- arch/arm/boot/dts/qcom/sdxpoorwills.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi index ef001fb3e918..94fd1030ff39 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi @@ -1343,9 +1343,9 @@ qcom,msm-bus,num-paths = <2>; qcom,msm-bus,vectors-KBps = <98 512 0 0>, <1 781 0 0>, /* No vote */ - <98 512 1250 0>, <1 781 0 40000>, /* 10Mbps vote */ - <98 512 12500 0>, <1 781 0 40000>, /* 100Mbps vote */ - <98 512 125000 0>, <1 781 0 40000>; /* 1000Mbps vote */ + <98 512 2500 0>, <1 781 0 40000>, /* 10Mbps vote */ + <98 512 25000 0>, <1 781 0 40000>, /* 100Mbps vote */ + <98 512 250000 0>, <1 781 0 40000>; /* 1000Mbps vote */ qcom,bus-vector-names = "0", "10", "100", "1000"; clocks = <&clock_gcc GCC_ETH_AXI_CLK>, <&clock_gcc GCC_ETH_PTP_CLK>, -- GitLab From a154fbabd57484fe19e2109a6f0d45e61df0d466 Mon Sep 17 00:00:00 2001 From: Tang Yingying Date: Wed, 7 Mar 2018 17:27:19 +0800 Subject: [PATCH 487/604] cnss: Add support for PCIe WLAN IPA uc SMMU feature Add support for PCIe WLAN IPA uc SMMU feature. CRs-Fixed: 2266893 Change-Id: I95967d1fa185c5cbb7c25ea7d3ba758758d17331 Signed-off-by: yintang --- drivers/net/wireless/cnss/cnss_pci.c | 102 ++++++++++++++++++++++++--- include/net/cnss.h | 2 + 2 files changed, 95 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index 8797e688241c..39bc2850a723 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -234,8 +234,11 @@ static struct cnss_data { struct pci_dev *pdev; const struct pci_device_id *id; struct dma_iommu_mapping *smmu_mapping; + bool smmu_s1_bypass; dma_addr_t smmu_iova_start; size_t smmu_iova_len; + dma_addr_t smmu_iova_ipa_start; + size_t smmu_iova_ipa_len; struct cnss_wlan_vreg_info vreg_info; bool wlan_en_vreg_support; struct cnss_wlan_gpio_info gpio_info; @@ -1438,6 +1441,8 @@ static int cnss_smmu_init(struct device *dev) { struct dma_iommu_mapping *mapping; int atomic_ctx = 1; + int s1_bypass = 1; + int fast = 1; int ret; mapping = arm_iommu_create_mapping(&platform_bus_type, @@ -1449,13 +1454,33 @@ static int cnss_smmu_init(struct device *dev) goto map_fail; } - ret = iommu_domain_set_attr(mapping->domain, - DOMAIN_ATTR_ATOMIC, - &atomic_ctx); - if (ret) { - pr_err("%s: set atomic_ctx attribute failed, err = %d\n", - __func__, ret); - goto set_attr_fail; + if (penv->smmu_s1_bypass) { + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_S1_BYPASS, + &s1_bypass); + if (ret) { + pr_err("%s: set s1 bypass attr failed, err = %d\n", + __func__, ret); + goto set_attr_fail; + } + } else { + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_ATOMIC, + &atomic_ctx); + if (ret) { + pr_err("%s: set atomic_ctx attr failed, err = %d\n", + __func__, ret); + goto set_attr_fail; + } + + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_FAST, + &fast); + if (ret) { + pr_err("%s: set fast map attr failed, err = %d\n", + __func__, ret); + goto set_attr_fail; + } } ret = arm_iommu_attach_device(dev, mapping); @@ -1618,7 +1643,6 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev, if (ret) { pr_err("%s: SMMU init failed, err = %d\n", __func__, ret); - goto smmu_init_fail; } } @@ -1714,7 +1738,6 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev, dma_free_coherent(dev, EVICT_BIN_MAX_SIZE, cpu_addr, dma_handle); err_unknown: err_pcie_suspend: -smmu_init_fail: cnss_pcie_reset_platform_ops(dev); return ret; } @@ -2867,6 +2890,55 @@ static int cnss_init_dump_entry(void) return msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry); } +struct dma_iommu_mapping *cnss_smmu_get_mapping(void) +{ + if (!penv) { + pr_err("Invalid penv: data %pK\n", penv); + return NULL; + } + + return penv->smmu_mapping; +} +EXPORT_SYMBOL(cnss_smmu_get_mapping); + +int cnss_smmu_map(phys_addr_t paddr, uint32_t *iova_addr, size_t size) +{ + unsigned long iova; + size_t len; + int ret = 0; + + if (!iova_addr) { + pr_err("iova_addr is NULL, paddr %pa, size %zu\n", + &paddr, size); + return -EINVAL; + } + + len = roundup(size + paddr - rounddown(paddr, PAGE_SIZE), PAGE_SIZE); + iova = roundup(penv->smmu_iova_ipa_start, PAGE_SIZE); + + if (iova >= penv->smmu_iova_ipa_start + penv->smmu_iova_ipa_len) { + pr_err("No IOVA space to map, iova %lx, smmu_iova_ipa_start %pad, smmu_iova_ipa_len %zu\n", + iova, + &penv->smmu_iova_ipa_start, + penv->smmu_iova_ipa_len); + return -ENOMEM; + } + + ret = iommu_map(penv->smmu_mapping->domain, iova, + rounddown(paddr, PAGE_SIZE), len, + IOMMU_READ | IOMMU_WRITE); + if (ret) { + pr_err("PA to IOVA mapping failed, ret %d\n", ret); + return ret; + } + + penv->smmu_iova_ipa_start = iova + len; + *iova_addr = (uint32_t)(iova + paddr - rounddown(paddr, PAGE_SIZE)); + + return 0; +} +EXPORT_SYMBOL(cnss_smmu_map); + static int cnss_probe(struct platform_device *pdev) { int ret = 0; @@ -2877,6 +2949,7 @@ static int cnss_probe(struct platform_device *pdev) struct resource *res; u32 ramdump_size = 0; u32 smmu_iova_address[2]; + u32 smmu_iova_ipa[2]; if (penv) return -ENODEV; @@ -3028,6 +3101,17 @@ static int cnss_probe(struct platform_device *pdev) penv->smmu_iova_len = smmu_iova_address[1]; } + if (of_property_read_u32_array(dev->of_node, + "qcom,wlan-smmu-iova-ipa", + smmu_iova_ipa, 2) == 0) { + penv->smmu_iova_ipa_start = smmu_iova_ipa[0]; + penv->smmu_iova_ipa_len = smmu_iova_ipa[1]; + } + + if (of_property_read_bool(dev->of_node, + "qcom,smmu-s1-bypass")) + penv->smmu_s1_bypass = true; + ret = pci_register_driver(&cnss_wlan_pci_driver); if (ret) goto err_pci_reg; diff --git a/include/net/cnss.h b/include/net/cnss.h index 368d01ecc879..39b7f5e54704 100644 --- a/include/net/cnss.h +++ b/include/net/cnss.h @@ -120,6 +120,8 @@ enum cnss_runtime_request { CNSS_PM_GET_NORESUME, }; +extern struct dma_iommu_mapping *cnss_smmu_get_mapping(void); +extern int cnss_smmu_map(phys_addr_t paddr, uint32_t *iova_addr, size_t size); extern int cnss_get_fw_image(struct image_desc_info *image_desc_info); extern void cnss_runtime_init(struct device *dev, int auto_delay); extern void cnss_runtime_exit(struct device *dev); -- GitLab From ede41844ad0cbce279c3bdda5bd3f55883d11c9a Mon Sep 17 00:00:00 2001 From: Tang Yingying Date: Wed, 7 Mar 2018 16:18:10 +0800 Subject: [PATCH 488/604] ARM: dts: cnss: Add SMMU feature in CNSS for sdxpoorwill Add SMMU feature for sdxpoorwill. CRs-Fixed: 2266893 Change-Id: I7dc60ee5f7b722127bf79060e4bcf94a974030ff Signed-off-by: yintang --- arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi | 20 +++++++++++++++++++ arch/arm/boot/dts/qcom/sdxpoorwills.dtsi | 3 +++ 2 files changed, 23 insertions(+) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi index e939bd2edab0..19072090568b 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi @@ -143,6 +143,26 @@ qcom,cpl-timeout = <0x2>; + qcom,smmu-sid-base = <0x00A0>; + + iommu-map = <0x0 &apps_smmu 0x00A0 0x1>, + <0x100 &apps_smmu 0x00A1 0x1>, + <0x200 &apps_smmu 0x00A2 0x1>, + <0x300 &apps_smmu 0x00A3 0x1>, + <0x400 &apps_smmu 0x00A4 0x1>, + <0x500 &apps_smmu 0x00A5 0x1>, + <0x600 &apps_smmu 0x00A6 0x1>, + <0x700 &apps_smmu 0x00A7 0x1>, + <0x800 &apps_smmu 0x00A8 0x1>, + <0x900 &apps_smmu 0x00A9 0x1>, + <0xa00 &apps_smmu 0x00AA 0x1>, + <0xb00 &apps_smmu 0x00AB 0x1>, + <0xc00 &apps_smmu 0x00AC 0x1>, + <0xd00 &apps_smmu 0x00AD 0x1>, + <0xe00 &apps_smmu 0x00AE 0x1>, + <0xf00 &apps_smmu 0x00AF 0x1>; + + qcom,boot-option = <0x1>; linux,pci-domain = <0>; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi index 2014885f81cf..109c0dc76524 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi @@ -1288,6 +1288,9 @@ <45 512 98572 655360>, <1 512 98572 1600000>, /* Upto 800 Mbps */ <45 512 207108 1146880>, <1 512 207108 3124992>; + + qcom,wlan-smmu-iova-address = <0x10000000 0x10000000>; + qcom,wlan-smmu-iova-ipa = <0x20000000 0x10000>; }; cnss_sdio: qcom,cnss_sdio { -- GitLab From 35141c3375c51dc2208abaf3051df59fb71ff1b4 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Thu, 28 Jun 2018 13:45:40 +0530 Subject: [PATCH 489/604] hwmon: qpnp-adc: Update support to read USB_IN_V on PMI632 With existing support to read USB_IN_V, sometimes two consecutive read requests for REG_GND and USB_IN_V are queued, leading to REF_GND channel being read instead of USB_IN_V. Add delay to ensure end of conversion occurs for reading REF_GND before sending conversion request for USB_IN_V channel. Change-Id: I511f64e1cc1f057655eed484f4a39b63fb14d017 Signed-off-by: Jishnu Prakash Signed-off-by: Siva Kumar Akkireddi --- drivers/hwmon/qpnp-adc-voltage.c | 168 +++++++++++++++++++++---------- 1 file changed, 117 insertions(+), 51 deletions(-) diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c index 1ed92d62ebef..53996708a1e3 100644 --- a/drivers/hwmon/qpnp-adc-voltage.c +++ b/drivers/hwmon/qpnp-adc-voltage.c @@ -139,9 +139,9 @@ #define QPNP_VADC_HC1_ADC_CH_SEL_CTL 0x44 #define QPNP_VADC_HC1_DELAY_CTL 0x45 #define QPNP_VADC_HC1_DELAY_CTL_MASK 0xf -#define QPNP_VADC_MC1_EN_CTL1 0x46 +#define QPNP_VADC_HC1_EN_CTL1 0x46 #define QPNP_VADC_HC1_ADC_EN BIT(7) -#define QPNP_VADC_MC1_CONV_REQ 0x47 +#define QPNP_VADC_HC1_CONV_REQ 0x47 #define QPNP_VADC_HC1_CONV_REQ_START BIT(7) #define QPNP_VADC_HC1_VBAT_MIN_THR0 0x48 @@ -421,6 +421,32 @@ static int qpnp_vadc_hc_read_data(struct qpnp_vadc_chip *vadc, int *data) return rc; } +static int qpnp_vadc_wait_for_eoc(struct qpnp_vadc_chip *vadc) +{ + int ret; + + if (vadc->vadc_poll_eoc) { + ret = qpnp_vadc_hc_check_conversion_status(vadc); + if (ret < 0) { + pr_err("polling mode conversion failed\n"); + return ret; + } + } else { + ret = wait_for_completion_timeout( + &vadc->adc->adc_rslt_completion, + QPNP_ADC_COMPLETION_TIMEOUT); + if (!ret) { + ret = qpnp_vadc_hc_check_conversion_status(vadc); + if (ret < 0) { + pr_err("interrupt mode conversion failed\n"); + return ret; + } + pr_debug("End of conversion status set\n"); + } + } + return ret; +} + static void qpnp_vadc_hc_update_adc_dig_param(struct qpnp_vadc_chip *vadc, struct qpnp_adc_amux_properties *amux_prop, u8 *data) { @@ -439,6 +465,78 @@ static void qpnp_vadc_hc_update_adc_dig_param(struct qpnp_vadc_chip *vadc, pr_debug("VADC_DIG_PARAM value:0x%x\n", *data); } +static int qpnp_vadc_hc_pre_configure_usb_in(struct qpnp_vadc_chip *vadc, + int dt_index) +{ + int rc = 0; + u8 buf; + u8 dig_param = 0; + struct qpnp_adc_amux_properties conv; + + /* Setup dig params for USB_IN_V */ + conv.decimation = DECIMATION_TYPE2; + conv.cal_val = ADC_HC_ABS_CAL; + conv.calib_type = vadc->adc->adc_channels[dt_index].calib_type; + + qpnp_vadc_hc_update_adc_dig_param(vadc, &conv, &dig_param); + + /* Increase calib interval and wait for other conversions to complete */ + buf = QPNP_VADC_CAL_DELAY_MEAS_SLOW; + rc = regmap_bulk_write(vadc->adc->regmap, + QPNP_VADC_CAL_DELAY_CTL_1, &buf, 1); + if (rc < 0) { + pr_err("qpnp adc write cal_delay failed with %d\n", rc); + return rc; + } + msleep(20); + + /* Read GND first */ + buf = VADC_VREF_GND; + rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HC1_ADC_CH_SEL_CTL, &buf, 1); + if (rc < 0) + return rc; + + buf = QPNP_VADC_HC1_ADC_EN; + rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HC1_EN_CTL1, &buf, 1); + if (rc < 0) + return rc; + + if (!vadc->vadc_poll_eoc) + reinit_completion(&vadc->adc->adc_rslt_completion); + + buf = QPNP_VADC_HC1_CONV_REQ_START; + rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HC1_CONV_REQ, &buf, 1); + if (rc < 0) + return rc; + + /* Pre-configure USB_IN_V request */ + rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HC1_ADC_DIG_PARAM, + &dig_param, 1); + if (rc < 0) + return rc; + + buf = VADC_USB_IN_V_DIV_16_PM5; + rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HC1_ADC_CH_SEL_CTL, &buf, 1); + if (rc < 0) + return rc; + + /* Wait for GND read to complete */ + rc = qpnp_vadc_wait_for_eoc(vadc); + if (rc < 0) + return rc; + + if (!vadc->vadc_poll_eoc) + reinit_completion(&vadc->adc->adc_rslt_completion); + + /* Start USB_IN_V read */ + buf = QPNP_VADC_HC1_CONV_REQ_START; + rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HC1_CONV_REQ, &buf, 1); + if (rc < 0) + return rc; + + return 0; +} + static int qpnp_vadc_hc_configure(struct qpnp_vadc_chip *vadc, struct qpnp_adc_amux_properties *amux_prop) { @@ -494,7 +592,7 @@ int32_t qpnp_vadc_hc_read(struct qpnp_vadc_chip *vadc, { int rc = 0, scale_type, amux_prescaling, dt_index = 0, calib_type = 0; u8 val = QPNP_VADC_CAL_DELAY_MEAS_SLOW; - struct qpnp_adc_amux_properties amux_prop, conv; + struct qpnp_adc_amux_properties amux_prop; if (qpnp_vadc_is_valid(vadc)) return -EPROBE_DEFER; @@ -532,69 +630,37 @@ int32_t qpnp_vadc_hc_read(struct qpnp_vadc_chip *vadc, if (channel == VADC_USB_IN_V_DIV_16_PM5 && vadc->adc->adc_prop->is_pmic_5) { - rc = regmap_bulk_write(vadc->adc->regmap, - QPNP_VADC_CAL_DELAY_CTL_1, &val, 1); + rc = qpnp_vadc_hc_pre_configure_usb_in(vadc, dt_index); if (rc < 0) { - pr_err("qpnp adc write cal_delay failed with %d\n", rc); - return rc; - } - msleep(20); - - conv.amux_channel = VADC_VREF_GND; - conv.decimation = DECIMATION_TYPE2; - conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT; - conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US; - conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1; - conv.cal_val = ADC_HC_ABS_CAL; - - rc = qpnp_vadc_hc_configure(vadc, &conv); - if (rc) { - pr_err("qpnp_vadc configure failed with %d\n", rc); + pr_err("Configuring VADC channel failed with %d\n", rc); goto fail_unlock; } - - } - - amux_prop.decimation = + } else { + amux_prop.decimation = vadc->adc->adc_channels[dt_index].adc_decimation; - amux_prop.calib_type = vadc->adc->adc_channels[dt_index].calib_type; - amux_prop.cal_val = vadc->adc->adc_channels[dt_index].cal_val; - amux_prop.fast_avg_setup = + amux_prop.calib_type = + vadc->adc->adc_channels[dt_index].calib_type; + amux_prop.cal_val = vadc->adc->adc_channels[dt_index].cal_val; + amux_prop.fast_avg_setup = vadc->adc->adc_channels[dt_index].fast_avg_setup; - amux_prop.amux_channel = channel; - amux_prop.hw_settle_time = + amux_prop.amux_channel = channel; + amux_prop.hw_settle_time = vadc->adc->adc_channels[dt_index].hw_settle_time; - rc = qpnp_vadc_hc_configure(vadc, &amux_prop); - if (rc < 0) { - pr_err("Configuring VADC channel failed with %d\n", rc); - goto fail_unlock; - } - - if (vadc->vadc_poll_eoc) { - rc = qpnp_vadc_hc_check_conversion_status(vadc); + rc = qpnp_vadc_hc_configure(vadc, &amux_prop); if (rc < 0) { - pr_err("polling mode conversion failed\n"); + pr_err("Configuring VADC channel failed with %d\n", rc); goto fail_unlock; } - } else { - rc = wait_for_completion_timeout( - &vadc->adc->adc_rslt_completion, - QPNP_ADC_COMPLETION_TIMEOUT); - if (!rc) { - rc = qpnp_vadc_hc_check_conversion_status(vadc); - if (rc < 0) { - pr_err("interrupt mode conversion failed\n"); - goto fail_unlock; - } - pr_debug("End of conversion status set\n"); - } } - val = QPNP_VADC_CAL_DELAY_MEAS_DEFAULT; + rc = qpnp_vadc_wait_for_eoc(vadc); + if (rc < 0) + goto fail_unlock; if (channel == VADC_USB_IN_V_DIV_16_PM5 && vadc->adc->adc_prop->is_pmic_5) { + val = QPNP_VADC_CAL_DELAY_MEAS_DEFAULT; rc = regmap_bulk_write(vadc->adc->regmap, QPNP_VADC_CAL_DELAY_CTL_1, &val, 1); if (rc < 0) { -- GitLab From 668342206409ce1eb0420821fd36e8a94236afd4 Mon Sep 17 00:00:00 2001 From: Shankar Ravi Date: Mon, 23 Jul 2018 11:30:04 +0530 Subject: [PATCH 490/604] 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 25f2d039b6f738b42ec1bd5df886137cd6cef46f Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Fri, 7 Oct 2016 11:51:15 -0700 Subject: [PATCH 491/604] ion: blacklist %p kptr_restrict Bug: 31494725 Change-Id: I10a0c2aae883dfaa6c235c38689a704064557008 Git-repo: https://android.googlesource.com/kernel/msm.git Git-commit: b57e736e9991b3d0f85c0870b1eff6310a4baa64 [d-cagle@codeaurora.org: Automatic resolve of merge conflicts] Signed-off-by: Dennis Cagle Signed-off-by: Vinayak Menon --- drivers/staging/android/ion/ion.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 60007070a9a2..e35a3c9163af 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -865,7 +865,7 @@ static int ion_debug_client_show(struct seq_file *s, void *unused) struct ion_handle *handle = rb_entry(n, struct ion_handle, node); - seq_printf(s, "%16.16s: %16zx : %16d : %12p", + seq_printf(s, "%16.16s: %16zx : %16d : %12pK", handle->buffer->heap->name, handle->buffer->size, atomic_read(&handle->ref.refcount), -- GitLab From 747bd4ec20164ceda016c5f6df3c84ee8c31dd91 Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Wed, 25 Jul 2018 10:12:01 +0530 Subject: [PATCH 492/604] power: qpnp-qg: Keep GOOD_OCV interrupt enabled at boot GOOD_OCV interrupt is expected to be enabled in active-state and disabled in sleep (@ suspend). Hence, keep it enabled at boot, the logic to disable/enable in suspend/resume already exists. Change-Id: Ifb21caf0531fdf042d46a8fd906cb4e067e9910e Signed-off-by: Anirudh Ghayal --- drivers/power/supply/qcom/qpnp-qg.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 39869c140271..0943273554f9 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -2865,10 +2865,6 @@ static int qg_post_init(struct qpnp_qg *chip) PROFILE_IRQ_DISABLE, true, 0); vote(chip->good_ocv_irq_disable_votable, PROFILE_IRQ_DISABLE, true, 0); - } else { - /* disable GOOD_OCV IRQ at init */ - vote(chip->good_ocv_irq_disable_votable, - QG_INIT_STATE_IRQ_DISABLE, true, 0); } /* restore ESR data */ -- GitLab From a9e32705e2249e2c9a307aeef2ff2fccddc81a49 Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Tue, 3 Jul 2018 15:47:18 +0530 Subject: [PATCH 493/604] USB: pd: Send PS_RDY within tNewSrc after PS_RDY received USBPD spec mentions max time within which device that transitions from sink power role to source needs to send PS_RDY message after PS_RDY received from other device as part of PR_SWAP. Currently USB PD driver is taking time around 380msec i.e greater than tNewSrc (275msec) and resulting in USB PD complaince test "2.2.3.1.2 Procedure/Checks for Tester (Source) Originated Swap" failure. Fix it by waiting only till VBUS voltage reaches VSafe5Vmin. Change-Id: I3138e6d31ba964507230fe5f914aaaf2e261647d Signed-off-by: Vijayavardhan Vennapusa --- drivers/usb/pd/policy_engine.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 6685f05bab57..ecdafd3d79d6 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -1929,6 +1929,22 @@ static int enable_vbus(struct usbpd *pd) else pd->vbus_enabled = true; + count = 10; + /* + * Check to make sure VBUS voltage reaches above Vsafe5Vmin (4.75v) + * before proceeding. + */ + while (count--) { + ret = power_supply_get_property(pd->usb_psy, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &val); + if (ret || val.intval >= 4750000) /*vsafe5Vmin*/ + break; + usleep_range(10000, 12000); /* Delay between two reads */ + } + + if (ret) + msleep(100); /* Delay to wait for VBUS ramp up if read fails */ + return ret; } @@ -2838,7 +2854,6 @@ static void usbpd_sm(struct work_struct *w) case PE_PRS_SNK_SRC_SOURCE_ON: enable_vbus(pd); - msleep(200); /* allow time VBUS ramp-up, must be < tNewSrc */ ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG); if (ret) { -- GitLab From 2f7b52ba8fa24bee1219232993f9c1f6920d1508 Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Wed, 25 Jul 2018 15:21:10 +0530 Subject: [PATCH 494/604] input: focaltech_touch: Reorder MT_PRESSURE and MT_TOOL_FINGER events Report the MT_PRESSURE to be zero before marking the slot as unused. Android's InputReader marks the slot as no longer in use when the driver sets MT_TRACKING_ID to -1. Further MT events will re-mark the slot as in-use, so we should ensure that we complete all coordinate/pressure events before the final MT_TRACKING_ID event. Change-Id: Ia4529b2815e3eda836fa224c859732698f37cefa Signed-off-by: Shantanu Jain --- drivers/input/touchscreen/focaltech_touch/focaltech_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_core.c b/drivers/input/touchscreen/focaltech_touch/focaltech_core.c index b3d7322f42ca..7639c9f11998 100644 --- a/drivers/input/touchscreen/focaltech_touch/focaltech_core.c +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_core.c @@ -514,11 +514,11 @@ static int fts_input_dev_report_b(struct ts_event *event, #endif } else { uppoint++; - input_mt_report_slot_state(data->input_dev, - MT_TOOL_FINGER, false); #if FTS_REPORT_PRESSURE_EN input_report_abs(data->input_dev, ABS_MT_PRESSURE, 0); #endif + input_mt_report_slot_state(data->input_dev, + MT_TOOL_FINGER, false); data->touchs &= ~BIT(event->au8_finger_id[i]); FTS_DEBUG("[B]P%d UP!", event->au8_finger_id[i]); } -- GitLab From daeb5ac709e6c7e0699ad04c26dd82027df86201 Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Fri, 13 Jul 2018 13:04:17 +0530 Subject: [PATCH 495/604] USB: pd: Always set selfpowered bit after explicit contract USB PD spec says after PD explicit contract, device needs to advertise as selfpowered and needs to mark bMaxPower as zero. Otherwise USB PD compliance test 4.10.2 is failing. Fix the failure by advertising as self powered after explicit contract through new extcon property. Change-Id: If3acdc06b4ac8567bb101ecfc23076af4894e776 Signed-off-by: Vijayavardhan Vennapusa --- drivers/usb/dwc3/dwc3-msm.c | 32 ++++++++++++++++++++++++++++++++ drivers/usb/gadget/composite.c | 4 ++++ drivers/usb/pd/policy_engine.c | 26 ++++++++++++++++++++++++++ include/linux/extcon.h | 7 ++++++- include/linux/usb/gadget.h | 1 + 5 files changed, 69 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index bf1baf6f344f..83cc71fa0952 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -255,6 +255,7 @@ struct dwc3_msm { struct notifier_block id_nb; struct notifier_block eud_event_nb; struct notifier_block host_restart_nb; + struct notifier_block self_power_nb; struct notifier_block host_nb; bool xhci_ss_compliance_enable; @@ -296,6 +297,8 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event, unsigned int value); static int dwc3_restart_usb_host_mode(struct notifier_block *nb, unsigned long event, void *ptr); +static int dwc3_notify_pd_status(struct notifier_block *nb, + unsigned long event, void *ptr); /** * @@ -3041,12 +3044,19 @@ static int dwc3_msm_extcon_register(struct dwc3_msm *mdwc, int start_idx) if (!IS_ERR(edev)) { mdwc->extcon_vbus = edev; mdwc->vbus_nb.notifier_call = dwc3_msm_vbus_notifier; + mdwc->self_power_nb.notifier_call = dwc3_notify_pd_status; ret = extcon_register_notifier(edev, EXTCON_USB, &mdwc->vbus_nb); if (ret < 0) { dev_err(mdwc->dev, "failed to register notifier for USB\n"); return ret; } + ret = extcon_register_blocking_notifier(edev, EXTCON_USB, + &mdwc->self_power_nb); + if (ret < 0) { + dev_err(mdwc->dev, "failed to register blocking notifier\n"); + goto err1; + } } /* @@ -4149,6 +4159,28 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on) return 0; } +static int dwc3_notify_pd_status(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct dwc3_msm *mdwc; + struct dwc3 *dwc; + int ret = 0; + union extcon_property_value val; + + mdwc = container_of(nb, struct dwc3_msm, self_power_nb); + dwc = platform_get_drvdata(mdwc->dwc3); + + ret = extcon_get_property(mdwc->extcon_vbus, EXTCON_USB, + EXTCON_PROP_USB_PD_CONTRACT, &val); + + if (!ret) + dwc->gadget.self_powered = val.intval; + else + dwc->gadget.self_powered = 0; + + return ret; +} + /* speed: 0 - USB_SPEED_HIGH, 1 - USB_SPEED_SUPER */ static int dwc3_restart_usb_host_mode(struct notifier_block *nb, unsigned long event, void *ptr) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 3de95d5f23fb..018e4eb15ec8 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -583,6 +583,10 @@ static int config_buf(struct usb_configuration *config, c->iConfiguration = config->iConfiguration; c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes; c->bMaxPower = encode_bMaxPower(speed, config); + if (config->cdev->gadget->self_powered) { + c->bmAttributes |= USB_CONFIG_ATT_SELFPOWER; + c->bMaxPower = 0; + } /* There may be e.g. OTG descriptors */ if (config->descriptors) { diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 6685f05bab57..3c73b4baebd7 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -533,6 +533,22 @@ static inline void start_usb_peripheral(struct usbpd *pd) extcon_set_state_sync(pd->extcon, EXTCON_USB, 1); } +static void notify_pd_contract_status(struct usbpd *pd) +{ + int ret = 0; + union extcon_property_value val; + + if (!pd) + return; + + val.intval = pd->in_explicit_contract; + extcon_set_property(pd->extcon, EXTCON_USB, + EXTCON_PROP_USB_PD_CONTRACT, val); + ret = extcon_blocking_sync(pd->extcon, EXTCON_USB, 0); + if (ret) + usbpd_err(&pd->dev, "err(%d) while notifying pd status", ret); +} + /** * This API allows client driver to request for releasing SS lanes. It should * not be called from atomic context. @@ -1252,6 +1268,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) case PE_SRC_READY: pd->in_explicit_contract = true; + notify_pd_contract_status(pd); if (pd->vdm_tx) kick_sm(pd, 0); @@ -1398,6 +1415,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) case PE_SNK_READY: pd->in_explicit_contract = true; + notify_pd_contract_status(pd); if (pd->vdm_tx) kick_sm(pd, 0); @@ -1433,6 +1451,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) POWER_SUPPLY_PROP_PD_CURRENT_MAX, &val); pd->in_explicit_contract = false; + notify_pd_contract_status(pd); /* * need to update PR bit in message header so that @@ -1996,6 +2015,7 @@ static void usbpd_sm(struct work_struct *w) pd->in_pr_swap = false; pd->pd_connected = false; pd->in_explicit_contract = false; + notify_pd_contract_status(pd); pd->hard_reset_recvd = false; pd->caps_count = 0; pd->hard_reset_count = 0; @@ -2079,6 +2099,7 @@ static void usbpd_sm(struct work_struct *w) POWER_SUPPLY_PROP_PR_SWAP, &val); pd->in_explicit_contract = false; + notify_pd_contract_status(pd); pd->selected_pdo = pd->requested_pdo = 0; pd->rdo = 0; rx_msg_cleanup(pd); @@ -2302,6 +2323,7 @@ static void usbpd_sm(struct work_struct *w) pd_send_hard_reset(pd); pd->in_explicit_contract = false; + notify_pd_contract_status(pd); pd->rdo = 0; rx_msg_cleanup(pd); reset_vdm_state(pd); @@ -2747,6 +2769,7 @@ static void usbpd_sm(struct work_struct *w) pd_send_hard_reset(pd); pd->in_explicit_contract = false; + notify_pd_contract_status(pd); pd->selected_pdo = pd->requested_pdo = 0; pd->rdo = 0; reset_vdm_state(pd); @@ -2778,6 +2801,7 @@ static void usbpd_sm(struct work_struct *w) power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PR_SWAP, &val); pd->in_explicit_contract = false; + notify_pd_contract_status(pd); if (pd->vbus_enabled) { regulator_disable(pd->vbus); @@ -3963,6 +3987,8 @@ struct usbpd *usbpd_create(struct device *parent) /* Support reporting polarity and speed via properties */ extcon_set_property_capability(pd->extcon, EXTCON_USB, EXTCON_PROP_USB_TYPEC_POLARITY); + extcon_set_property_capability(pd->extcon, EXTCON_USB, + EXTCON_PROP_USB_PD_CONTRACT); extcon_set_property_capability(pd->extcon, EXTCON_USB, EXTCON_PROP_USB_SS); extcon_set_property_capability(pd->extcon, EXTCON_USB_HOST, diff --git a/include/linux/extcon.h b/include/linux/extcon.h index a9a16f2b0197..94c7be2d8587 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -113,14 +113,19 @@ * @type: integer (intval) * @value: 0 (USB/USB2) or 1 (USB3) * @default: 0 (USB/USB2) + * -EXTCON_PROP_USB_PD_CONTRACT + * @type: integer (intval) + * @value: 0 (bus powered) or 1 (self powered) + * @default: 0 (bus powered) * */ #define EXTCON_PROP_USB_VBUS 0 #define EXTCON_PROP_USB_TYPEC_POLARITY 1 #define EXTCON_PROP_USB_SS 2 +#define EXTCON_PROP_USB_PD_CONTRACT 3 #define EXTCON_PROP_USB_MIN 0 -#define EXTCON_PROP_USB_MAX 2 +#define EXTCON_PROP_USB_MAX 3 #define EXTCON_PROP_USB_CNT (EXTCON_PROP_USB_MAX - EXTCON_PROP_USB_MIN + 1) /* Properties of EXTCON_TYPE_CHG. */ diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 3f3a7e45c1d2..0267bed4bcf9 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -539,6 +539,7 @@ struct usb_gadget { u32 extra_buf_alloc; bool l1_supported; bool is_chipidea; + bool self_powered; }; #define work_to_gadget(w) (container_of((w), struct usb_gadget, work)) -- GitLab From cce088b123d8217de1cef10447843a22dacc43f4 Mon Sep 17 00:00:00 2001 From: Neeraj Soni Date: Wed, 25 Jul 2018 15:52:51 +0530 Subject: [PATCH 496/604] security: pfe: Disable clocks for crypto engine Even if invalidate key scm call is failed crypto engine clocks should be disabled as fresh set key call will any way enable clocks again. This will also help in power savings. Change-Id: I640150228112a3d36f49cb52a7de0df6cc6a4662 Signed-off-by: Neeraj Soni --- security/pfe/pfk_ice.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/security/pfe/pfk_ice.c b/security/pfe/pfk_ice.c index e1d01004d50e..a86042c98e1f 100644 --- a/security/pfe/pfk_ice.c +++ b/security/pfe/pfk_ice.c @@ -138,9 +138,10 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, if (ret1) pr_err("%s: Invalidate Key Error: %d\n", __func__, ret1); - goto out; } - ret = qcom_ice_setup_ice_hw((const char *)s_type, false); + ret1 = qcom_ice_setup_ice_hw((const char *)s_type, false); + if (ret1) + pr_err("%s: Error %d disabling clocks\n", __func__, ret1); out: return ret; -- GitLab From f61e3b5494379e4c6910dcdd06a60ded5241d086 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Mon, 15 Dec 2014 13:45:19 -0700 Subject: [PATCH 497/604] msm: kgsl: Keep a list of perfcounters per file descriptor We need a list of perfcounters for each kgsl file descriptor, in order to gracefully release any perfcounter allocated using that fd in the event that the process dies unexpectedly or doesn't release the perfcounters properly. This prevents possible leakage of perfcounters referenced by a process. Change-Id: Ib443282f26a0cbdad656fa0f82fb62c6de871fb0 Signed-off-by: Harshdeep Dhatt Signed-off-by: Lynus Vaz --- drivers/gpu/msm/adreno.c | 43 ++++++++++++++++++++++ drivers/gpu/msm/adreno.h | 23 ++++++++++++ drivers/gpu/msm/adreno_ioctl.c | 66 ++++++++++++++++++++++++++++++++-- drivers/gpu/msm/kgsl.c | 5 +-- drivers/gpu/msm/kgsl_device.h | 2 ++ 5 files changed, 134 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 757f9d736d6a..9e47f97c85f2 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -3424,6 +3424,47 @@ static int adreno_readtimestamp(struct kgsl_device *device, return status; } +/** + * adreno_device_private_create(): Allocate an adreno_device_private structure + */ +static struct kgsl_device_private *adreno_device_private_create(void) +{ + struct adreno_device_private *adreno_priv = + kzalloc(sizeof(*adreno_priv), GFP_KERNEL); + + if (adreno_priv) { + INIT_LIST_HEAD(&adreno_priv->perfcounter_list); + return &adreno_priv->dev_priv; + } + return NULL; +} + +/** + * adreno_device_private_destroy(): Destroy an adreno_device_private structure + * and release the perfcounters held by the kgsl fd. + * @dev_priv: The kgsl device private structure + */ +static void adreno_device_private_destroy(struct kgsl_device_private *dev_priv) +{ + struct kgsl_device *device = dev_priv->device; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct adreno_device_private *adreno_priv = + container_of(dev_priv, struct adreno_device_private, + dev_priv); + struct adreno_perfcounter_list_node *p, *tmp; + + mutex_lock(&device->mutex); + list_for_each_entry_safe(p, tmp, &adreno_priv->perfcounter_list, node) { + adreno_perfcounter_put(adreno_dev, p->groupid, + p->countable, PERFCOUNTER_FLAG_NONE); + list_del(&p->node); + kfree(p); + } + mutex_unlock(&device->mutex); + + kfree(adreno_priv); +} + static inline s64 adreno_ticks_to_us(u32 ticks, u32 freq) { freq /= 1000000; @@ -3705,6 +3746,8 @@ static const struct kgsl_functable adreno_functable = { .snapshot = adreno_snapshot, .irq_handler = adreno_irq_handler, .drain = adreno_drain, + .device_private_create = adreno_device_private_create, + .device_private_destroy = adreno_device_private_destroy, /* Optional functions */ .snapshot_gmu = adreno_snapshot_gmu, .drawctxt_create = adreno_drawctxt_create, diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index fbf298d8749b..fc32fb9cf58a 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -326,6 +326,29 @@ struct adreno_firmware { struct kgsl_memdesc memdesc; }; +/** + * struct adreno_perfcounter_list_node - struct to store perfcounters + * allocated by a process on a kgsl fd. + * @groupid: groupid of the allocated perfcounter + * @countable: countable assigned to the allocated perfcounter + * @node: list node for perfcounter_list of a process + */ +struct adreno_perfcounter_list_node { + unsigned int groupid; + unsigned int countable; + struct list_head node; +}; + +/** + * struct adreno_device_private - Adreno private structure per fd + * @dev_priv: the kgsl device private structure + * @perfcounter_list: list of perfcounters used by the process + */ +struct adreno_device_private { + struct kgsl_device_private dev_priv; + struct list_head perfcounter_list; +}; + /** * struct adreno_gpu_core - A specific GPU core definition * @gpurev: Unique GPU revision identifier diff --git a/drivers/gpu/msm/adreno_ioctl.c b/drivers/gpu/msm/adreno_ioctl.c index aa8c2bf76d41..82629c6fcf23 100644 --- a/drivers/gpu/msm/adreno_ioctl.c +++ b/drivers/gpu/msm/adreno_ioctl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-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 @@ -16,6 +16,50 @@ #include "adreno.h" #include "adreno_a5xx.h" +/* + * Add a perfcounter to the per-fd list. + * Call with the device mutex held + */ +static int adreno_process_perfcounter_add(struct kgsl_device_private *dev_priv, + unsigned int groupid, unsigned int countable) +{ + struct adreno_device_private *adreno_priv = container_of(dev_priv, + struct adreno_device_private, dev_priv); + struct adreno_perfcounter_list_node *perfctr; + + perfctr = kmalloc(sizeof(*perfctr), GFP_KERNEL); + if (!perfctr) + return -ENOMEM; + + perfctr->groupid = groupid; + perfctr->countable = countable; + + /* add the pair to process perfcounter list */ + list_add(&perfctr->node, &adreno_priv->perfcounter_list); + return 0; +} + +/* + * Remove a perfcounter from the per-fd list. + * Call with the device mutex held + */ +static int adreno_process_perfcounter_del(struct kgsl_device_private *dev_priv, + unsigned int groupid, unsigned int countable) +{ + struct adreno_device_private *adreno_priv = container_of(dev_priv, + struct adreno_device_private, dev_priv); + struct adreno_perfcounter_list_node *p; + + list_for_each_entry(p, &adreno_priv->perfcounter_list, node) { + if (p->groupid == groupid && p->countable == countable) { + list_del(&p->node); + kfree(p); + return 0; + } + } + return -ENODEV; +} + long adreno_ioctl_perfcounter_get(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) { @@ -42,6 +86,15 @@ long adreno_ioctl_perfcounter_get(struct kgsl_device_private *dev_priv, get->groupid, get->countable, &get->offset, &get->offset_hi, PERFCOUNTER_FLAG_NONE); + /* Add the perfcounter into the list */ + if (!result) { + result = adreno_process_perfcounter_add(dev_priv, get->groupid, + get->countable); + if (result) + adreno_perfcounter_put(adreno_dev, get->groupid, + get->countable, PERFCOUNTER_FLAG_NONE); + } + adreno_perfcntr_active_oob_put(adreno_dev); mutex_unlock(&device->mutex); @@ -58,8 +111,15 @@ long adreno_ioctl_perfcounter_put(struct kgsl_device_private *dev_priv, int result; mutex_lock(&device->mutex); - result = adreno_perfcounter_put(adreno_dev, put->groupid, - put->countable, PERFCOUNTER_FLAG_NONE); + + /* Delete the perfcounter from the process list */ + result = adreno_process_perfcounter_del(dev_priv, put->groupid, + put->countable); + + /* Put the perfcounter refcount */ + if (!result) + adreno_perfcounter_put(adreno_dev, put->groupid, + put->countable, PERFCOUNTER_FLAG_NONE); mutex_unlock(&device->mutex); return (long) result; diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 3b55fc6f74ed..5d590954dfe4 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1119,7 +1119,8 @@ static int kgsl_release(struct inode *inodep, struct file *filep) /* Close down the process wide resources for the file */ kgsl_process_private_close(dev_priv, dev_priv->process_priv); - kfree(dev_priv); + /* Destroy the device-specific structure */ + device->ftbl->device_private_destroy(dev_priv); result = kgsl_close_device(device); pm_runtime_put(&device->pdev->dev); @@ -1187,7 +1188,7 @@ static int kgsl_open(struct inode *inodep, struct file *filep) } result = 0; - dev_priv = kzalloc(sizeof(struct kgsl_device_private), GFP_KERNEL); + dev_priv = device->ftbl->device_private_create(); if (dev_priv == NULL) { result = -ENOMEM; goto err; diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index c8c6456343e5..4a98a240810a 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -156,6 +156,8 @@ struct kgsl_functable { struct kgsl_snapshot *snapshot); irqreturn_t (*irq_handler)(struct kgsl_device *device); int (*drain)(struct kgsl_device *device); + struct kgsl_device_private * (*device_private_create)(void); + void (*device_private_destroy)(struct kgsl_device_private *dev_priv); /* * Optional functions - these functions are not mandatory. The * driver will check that the function pointer is not NULL before -- GitLab From 43b0d91f72d32f704c132974faaa2662940127b0 Mon Sep 17 00:00:00 2001 From: Ramesh Yadav Javadi Date: Wed, 18 Jul 2018 13:10:56 +0530 Subject: [PATCH 498/604] defconfig: Add WCNSS related config parameter in MSM8909 Add WCNSS related config parameter to compile the wlan platform driver. Change-Id: I02f74db7978e96b5f2da77de9d29a5f0c1131370 Signed-off-by: Ramesh Yadav Javadi --- arch/arm/configs/msm8909-perf_defconfig | 3 +++ arch/arm/configs/msm8909_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 5f655b47e4ed..e473a970075d 100644 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -424,6 +424,9 @@ CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_MSM_EVENT_TIMER=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MSM_BAM_DMUX=y +CONFIG_WCNSS_CORE=y +CONFIG_WCNSS_CORE_PRONTO=y +CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y CONFIG_CNSS_CRYPTO=y CONFIG_PWM=y CONFIG_PWM_QPNP=y diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index a87599f26d8d..009ead21b860 100644 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -460,6 +460,9 @@ CONFIG_MSM_EVENT_TIMER=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MSM_BAM_DMUX=y +CONFIG_WCNSS_CORE=y +CONFIG_WCNSS_CORE_PRONTO=y +CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y CONFIG_CNSS_CRYPTO=y CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_IIO=y -- GitLab From 6f551173d95a7998bb983d5f6c3fb8ff98ffcfa2 Mon Sep 17 00:00:00 2001 From: Alok Pandey Date: Mon, 16 Jul 2018 23:11:08 +0530 Subject: [PATCH 499/604] 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 | 21 +- 3 files changed, 100 insertions(+), 182 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..81d0075a6885 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c @@ -36,7 +36,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); @@ -166,6 +167,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); @@ -220,20 +222,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 @@ -244,15 +262,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 @@ -337,10 +353,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; } @@ -352,7 +366,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 ae7d5421e6b7..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 @@ -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 @@ -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 30874eb97458f61f5bdb953adde3bc17941cab04 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Thu, 31 May 2018 13:33:31 -0700 Subject: [PATCH 500/604] drm/msm/sde: increase ahb bus vote on first frame Increase ahb bus vote on first frame after idle pc because that will program the complete mdss register space. Change-Id: I360d43656f753c70acb51395a978998412354b64 Signed-off-by: Dhaval Patel --- drivers/gpu/drm/msm/sde/sde_encoder.c | 19 +++++++++++++++++++ drivers/gpu/drm/msm/sde/sde_kms.c | 8 ++++++++ drivers/gpu/drm/msm/sde/sde_kms.h | 2 ++ 3 files changed, 29 insertions(+) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 73864b617cc4..829d9eb20f76 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -265,6 +265,8 @@ struct sde_encoder_virt { struct sde_rect cur_conn_roi; struct sde_rect prv_conn_roi; struct drm_crtc *crtc; + + bool elevated_ahb_vote; }; #define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base) @@ -1849,6 +1851,7 @@ static int _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc, return rc; } + sde_enc->elevated_ahb_vote = true; /* enable DSI clks */ rc = sde_connector_clk_ctrl(sde_enc->cur_master->connector, true); @@ -3298,6 +3301,8 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc) struct sde_hw_ctl *ctl; uint32_t i, pending_flush; unsigned long lock_flags; + struct msm_drm_private *priv = NULL; + struct sde_kms *sde_kms = NULL; if (!sde_enc) { SDE_ERROR("invalid encoder\n"); @@ -3375,6 +3380,20 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc) _sde_encoder_trigger_start(sde_enc->cur_master); spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags); + + if (sde_enc->elevated_ahb_vote) { + priv = sde_enc->base.dev->dev_private; + if (priv != NULL) { + sde_kms = to_sde_kms(priv->kms); + if (sde_kms != NULL) { + sde_power_scale_reg_bus(&priv->phandle, + sde_kms->core_client, + VOTE_INDEX_LOW, + false); + } + } + sde_enc->elevated_ahb_vote = false; + } } static void _sde_encoder_ppsplit_swap_intf_for_right_only_update( diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index 620aae9bffcf..2ba941032b07 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -926,6 +926,12 @@ static void sde_kms_prepare_commit(struct msm_kms *kms, return; } + if (sde_kms->first_kickoff) { + sde_power_scale_reg_bus(&priv->phandle, sde_kms->core_client, + VOTE_INDEX_HIGH, false); + sde_kms->first_kickoff = false; + } + for_each_crtc_in_state(state, crtc, crtc_state, i) { list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { @@ -3073,8 +3079,10 @@ static void sde_kms_handle_power_event(u32 event_type, void *usr) if (event_type == SDE_POWER_EVENT_POST_ENABLE) { sde_irq_update(msm_kms, true); sde_vbif_init_memtypes(sde_kms); + sde_kms->first_kickoff = true; } else if (event_type == SDE_POWER_EVENT_PRE_DISABLE) { sde_irq_update(msm_kms, false); + sde_kms->first_kickoff = false; } } diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h index 450695dd4ce3..b5d5aed470ff 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.h +++ b/drivers/gpu/drm/msm/sde/sde_kms.h @@ -288,6 +288,8 @@ struct sde_kms { atomic_t detach_sec_cb; atomic_t detach_all_cb; struct mutex secure_transition_lock; + + bool first_kickoff; }; struct vsync_info { -- GitLab From 419504a2709e8312c01847c4d0fea39ccc312540 Mon Sep 17 00:00:00 2001 From: Devi Sandeep Endluri V V Date: Thu, 26 Jul 2018 03:32:35 +0530 Subject: [PATCH 501/604] defconfig: msm8953: 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: I32634b34e42691f9df7741f7ea8d16c6d051a46c Signed-off-by: Devi Sandeep Endluri V V --- arch/arm/configs/msm8953-perf_defconfig | 2 ++ arch/arm/configs/msm8953_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig index 3d716a6b191f..f5423687ae5f 100644 --- a/arch/arm/configs/msm8953-perf_defconfig +++ b/arch/arm/configs/msm8953-perf_defconfig @@ -102,6 +102,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 @@ -113,6 +114,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/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig index 34f91220f604..8abade293de7 100644 --- a/arch/arm/configs/msm8953_defconfig +++ b/arch/arm/configs/msm8953_defconfig @@ -106,6 +106,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 @@ -117,6 +118,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 e8da6fde9c969ec64584e4f7880dcee4ab9a0a7c Mon Sep 17 00:00:00 2001 From: Devi Sandeep Endluri V V Date: Thu, 26 Jul 2018 03:26:01 +0530 Subject: [PATCH 502/604] defconfig: msm8937: 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: Icdcfe7c7d4e651fd3c764aedcd55092b723c6a6d Signed-off-by: Devi Sandeep Endluri V V --- arch/arm/configs/msm8937-perf_defconfig | 2 ++ arch/arm/configs/msm8937_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index 040ce14b6375..e89c50cb5557 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -104,6 +104,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 @@ -115,6 +116,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/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index a33bdbdd8f8c..eca6d3231368 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -108,6 +108,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 @@ -119,6 +120,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 f7d5501119d9d311a2225157c337822583ed495d Mon Sep 17 00:00:00 2001 From: Qian Zhang Date: Wed, 18 Jul 2018 14:57:51 +0800 Subject: [PATCH 503/604] net: Add CLD_USB_CORE for USB Wlan card MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add CLD_USB_CORE and select WIRELESS_EXT, WEXT_PRIV,WEXT_CORE, WEXT_SPY and NL80211_TESTMODE. Change-Id: Ibf8e4b2391c840b28795985272187cba503325a4 Signed-off-by: Qian Zhang CRs-Fixed: 2281614 --- drivers/net/wireless/cnss/Kconfig | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/net/wireless/cnss/Kconfig b/drivers/net/wireless/cnss/Kconfig index 0b37af67415c..c18cea7be491 100644 --- a/drivers/net/wireless/cnss/Kconfig +++ b/drivers/net/wireless/cnss/Kconfig @@ -61,6 +61,19 @@ config CLD_DEBUG Say N, if you are building a release kernel for production use. Only say Y, if you are building a kernel with debug support. +config CLD_USB_CORE + tristate "Qualcomm Technologies Inc. Core wlan driver for QCA USB interface" + select WIRELESS_EXT + select WEXT_PRIV + select WEXT_CORE + select WEXT_SPY + select NL80211_TESTMODE + ---help--- + This section contains the necessary modules needed to enable the + core WLAN driver for Qualcomm Technologies Inc USB wlan chipset. + Select Y to compile the driver in order to have WLAN functionality + support. + config CLD_HL_SDIO_CORE tristate "Qualcomm Technologies Inc. Core wlan driver for QCA SDIO interface" select WIRELESS_EXT -- GitLab From 3b15377e9e8c8455bc93b7730408064a3c49c08a Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Thu, 26 Jul 2018 11:47:39 +0800 Subject: [PATCH 504/604] ARM: dts: msm: Enable bluetooth for sdxpoorwills variants Enable bluetooth UART blsp1_uart2b and configure bluetooth RFKILL for sdxpoorwills variants. CRs-Fixed: 2284667 Change-Id: I0bf32169265a0e3e7933f99a147a9bad25b2e2e7 Signed-off-by: Zijun Hu --- arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts | 4 ++++ arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi | 8 ++++++++ arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dtsi | 8 -------- arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-mtp.dtsi | 8 -------- arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts | 4 ++++ arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi | 8 ++++++++ arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp-256.dts | 4 ++++ arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts | 3 +++ arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp-256.dts | 4 ++++ arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts | 4 ++++ arch/arm/boot/dts/qcom/sdxpoorwills-ttp.dts | 4 ++++ 11 files changed, 43 insertions(+), 16 deletions(-) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts index 99e3faafd389..eb282823e563 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts @@ -22,3 +22,7 @@ "qcom,sdxpoorwills", "qcom,cdp"; qcom,board-id = <1 0x102>; }; + +&blsp1_uart2b_hs { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi index 8c506b921b3b..c836f94b7927 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi @@ -141,3 +141,11 @@ extcon = <&smb1381_charger>; vbus_dwc3-supply = <&smb138x_vbus>; }; + +&soc { + bluetooth: bt_qca6174 { + compatible = "qca,qca6174"; + qca,bt-reset-gpio = <&pmxpoorwills_gpios 4 0>; /* BT_EN */ + qca,bt-vdd-pa-supply = <&vreg_wlan>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dtsi index 16f933f687ce..d447724fb66a 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dtsi @@ -36,11 +36,3 @@ /delete-property/ qcom,devfreq,freq-table; /delete-property/ cd-gpios; }; - -&soc { - bluetooth: bt_qca6174 { - compatible = "qca,qca6174"; - qca,bt-reset-gpio = <&pmxpoorwills_gpios 4 0>; /* BT_EN */ - qca,bt-vdd-pa-supply = <&vreg_wlan>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-mtp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-mtp.dtsi index 252fb04d2940..b60225ac8d56 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-mtp.dtsi @@ -36,11 +36,3 @@ /delete-property/ qcom,devfreq,freq-table; /delete-property/ cd-gpios; }; - -&soc { - bluetooth: bt_qca6174 { - compatible = "qca,qca6174"; - qca,bt-reset-gpio = <&pmxpoorwills_gpios 4 0>; /* BT_EN */ - qca,bt-vdd-pa-supply = <&vreg_wlan>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts index 3ae5b2c82df8..a383f3e237ba 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts @@ -24,3 +24,7 @@ &qcom_seecom { status = "okay"; }; + +&blsp1_uart2b_hs { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi index ef1150ac2734..a6d2463ead26 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi @@ -141,3 +141,11 @@ extcon = <&smb1381_charger>; vbus_dwc3-supply = <&smb138x_vbus>; }; + +&soc { + bluetooth: bt_qca6174 { + compatible = "qca,qca6174"; + qca,bt-reset-gpio = <&pmxpoorwills_gpios 4 0>; /* BT_EN */ + qca,bt-vdd-pa-supply = <&vreg_wlan>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp-256.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp-256.dts index cbbf585bea94..d23275e7ad98 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp-256.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp-256.dts @@ -20,3 +20,7 @@ "qcom,sdxpoorwills", "qcom,cdp"; qcom,board-id = <1 0x1>; }; + +&blsp1_uart2b_hs { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts index 2a2e496fbc21..521d948f6428 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts @@ -21,3 +21,6 @@ qcom,board-id = <1 0x106>; }; +&blsp1_uart2b_hs { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp-256.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp-256.dts index 6b6aab50eba4..236ce73e46f2 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp-256.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp-256.dts @@ -20,3 +20,7 @@ "qcom,sdxpoorwills", "qcom,mtp"; qcom,board-id = <8 0x1>; }; + +&blsp1_uart2b_hs { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts index 8c223489fe3a..11c4e62749ba 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts @@ -20,3 +20,7 @@ "qcom,sdxpoorwills", "qcom,mtp"; qcom,board-id = <8 0x105>; }; + +&blsp1_uart2b_hs { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-ttp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-ttp.dts index 775be9636262..f0363c08935d 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-ttp.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-ttp.dts @@ -20,3 +20,7 @@ "qcom,sdxpoorwills", "qcom,ttp"; qcom,board-id = <30 0x100>; }; + +&blsp1_uart2b_hs { + status = "okay"; +}; -- GitLab From c7376ebdacfeb005fa63f5d9747e20a084d532a3 Mon Sep 17 00:00:00 2001 From: Tiequan Luo Date: Wed, 25 Jul 2018 19:40:00 +0800 Subject: [PATCH 505/604] ARM: dts: msm: enable apq8009 robot variants dts Enable complication of 2 more apq8009 based robot variants. Change-Id: Ifde371abdb05094457ad916074ab25fd3a488a2a Signed-off-by: Tiequan Luo --- arch/arm64/boot/dts/qcom/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 8b0cb9f639d2..a798b5d5a575 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -504,6 +504,8 @@ dtb-$(CONFIG_ARCH_MSM8909) += msm8909w-bg-wtp-v2.dtb \ apq8009w-bg-alpha.dtb \ apq8009-mtp-wcd9326-refboard.dtb \ apq8009-robot-som-refboard.dtb \ + apq8009-robot-rome-refboard.dtb \ + apq8009-robot-pronto-refboard.dtb \ apq8009-dragon.dtb \ apq8009-lat-v1.0.dtb \ sdw3100-msm8909w-1gb-wtp.dtb -- GitLab From 6afbfb22bee29a71b2b7d052c64d319237b72cc5 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Wed, 25 Jul 2018 15:01:38 +0530 Subject: [PATCH 506/604] net: usb: ax88179: Change to check if the packets are coming from gsb Packets from gsb are cloned packets, which has been done to optimize the dl data path. The check for cloned skb calls pskb_expand_head which gives penalty in the throughput. GSB driver data path does not consume the skb so, reallocation of skb is not necessary here. For that reason the check for all packets from gsb is introduced here. This check improves the throughput to about 150 Mbps. Change-Id: Ic1d7cc9c94605f1902ba212aac52d535d0ff84a7 Acked-by: Rishav LNU Signed-off-by: Mohammed Javid --- drivers/net/usb/ax88179_178a.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 8a6675d92b98..f9f69d536dfe 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -1435,7 +1435,8 @@ ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) headroom = skb_headroom(skb) - 8; - if ((skb_header_cloned(skb) || headroom < 0) && + if (((!(skb->fast_forwarded) && skb_header_cloned(skb)) || + headroom < 0) && pskb_expand_head(skb, headroom < 0 ? 8 : 0, 0, GFP_ATOMIC)) { dev_kfree_skb_any(skb); return NULL; -- GitLab From de64234328d901b0587af839a925695c7762a395 Mon Sep 17 00:00:00 2001 From: Tirupathi Reddy Date: Thu, 26 Jul 2018 10:47:22 +0530 Subject: [PATCH 507/604] ARM: dts: msm: pass VDD_MX sleep request for msm8909-pm8916 VDD_MX sleep vote (atleast one) is required for allowing system enter VDD_MIN state. Change-Id: I9b7c63600e4ce973c8876de1f71e3884bbc7598b Signed-off-by: Tirupathi Reddy --- arch/arm64/boot/dts/qcom/msm8916-regulator.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/msm8916-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8916-regulator.dtsi index 36a67af768bf..7c3e932e52d8 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916-regulator.dtsi @@ -214,7 +214,7 @@ regulator-min-microvolt = <1>; regulator-max-microvolt = <7>; qcom,use-voltage-corner; - qcom,init-voltage = <1>; + qcom,init-voltage-corner = <1>; }; }; -- GitLab From c40b40a76b62d1c055dea7cd920d536d53c71651 Mon Sep 17 00:00:00 2001 From: Liangliang Lu Date: Thu, 26 Jul 2018 17:13:11 +0800 Subject: [PATCH 508/604] ARM: dts: msm: Update HS USB PHY parameters for HDK670 In the case efuse value take effect, we should not rely on HSTX_TRIM for the tuning, we can adjust the emphasis setting for the tuning. Apply new tuning value which can pass eye diagram test on different efuse value boards. Change-Id: Iffc2eb37016f0d1b9d2d07d1266bf4ab8ba52538 Signed-off-by: Liangliang Lu --- arch/arm64/boot/dts/qcom/sda670-hdk.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi b/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi index fcffd447881a..ea385bd3f02c 100644 --- a/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi +++ b/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi @@ -97,9 +97,9 @@ 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ 0x20 0x198 /* PLL_BIAS_CONTROL_2 */ 0x21 0x214 /* PWR_CTRL2 */ - 0x00 0x220 /* IMP_CTRL1 */ + 0x0f 0x220 /* IMP_CTRL1 */ 0x58 0x224 /* IMP_CTRL2 */ - 0x77 0x240 /* TUNE1 */ + 0xc5 0x240 /* TUNE1 */ 0x29 0x244 /* TUNE2 */ 0xca 0x248 /* TUNE3 */ 0x04 0x24c /* TUNE4 */ @@ -117,9 +117,9 @@ 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ 0x20 0x198 /* PLL_BIAS_CONTROL_2 */ 0x21 0x214 /* PWR_CTRL2 */ - 0x25 0x220 /* IMP_CTRL1 */ + 0x00 0x220 /* IMP_CTRL1 */ 0x58 0x224 /* IMP_CTRL2 */ - 0x65 0x240 /* TUNE1 */ + 0x67 0x240 /* TUNE1 */ 0x29 0x244 /* TUNE2 */ 0xca 0x248 /* TUNE3 */ 0x04 0x24c /* TUNE4 */ -- GitLab From d35fc8ec4573ca46354e1fa0777c8272a40ee4e7 Mon Sep 17 00:00:00 2001 From: "Joel Fernandes (Google)" Date: Mon, 18 Jun 2018 11:54:56 -0700 Subject: [PATCH 509/604] ANDROID: sched/fair: Fix incorrect usage of RCU in CPU select path The RCU readlock needs to be acquired before accessing schedtune, if not its possible we may access stale/corrupted data. Move up the rcu_read_lock to fix the issue. Issue found with lockdep, which fires a warning on boot: [ 0.132198] include/linux/cgroup.h:455 suspicious rcu_dereference_check() usage! [ 0.132203] aother info that might help us debug this:a [ 0.132211] arcu_scheduler_active = 1, debug_locks = 0 [ 0.132219] 3 locks held by swapper/0/1: [ 0.132225] #0: (cpu_hotplug.dep_map){.+.+.+}, at: [] [ 0.132261] #1: (smpboot_threads_lock){+.+.+.}, at: [] [ 0.132282] #2: (&p->pi_lock){......}, at: [] try_to_wake_up+0x4c/0x598 [ 0.132298] astack backtrace: [ 0.132307] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.9.84-g6cedde4aedec [ 0.132314] Hardware name: MSM sdm845 C1 EVT v1.0 (DT) [ 0.132322] Call trace: [ 0.132337] [] dump_backtrace+0x0/0x3c0 [ 0.132344] [] show_stack+0x20/0x2c [ 0.132357] [] dump_stack+0xdc/0x12c [ 0.132367] [] lockdep_rcu_suspicious+0x13c/0x154 [ 0.132377] [] task_sched_boost+0x88/0xa0 [ 0.132386] [] select_energy_cpu_brute+0x284/0x23a4 [ 0.132390] [] select_task_rq_fair+0x390/0x1434 [ 0.132395] [] try_to_wake_up+0x2ec/0x598 [ 0.132403] [] wake_up_process+0x24/0x30 [ 0.132412] [] __kthread_create_on_node+0xbc/0x1a8 [ 0.132418] [] kthread_create_on_node+0xa4/0xd4 [ 0.132424] [] kthread_create_on_cpu+0x40/0xe4 [ 0.132432] [] __smpboot_create_thread+0x8c/0x10c [ 0.132437] [] smpboot_register_percpu_thread_cpumask+0x90/0x14c [ 0.132450] [] spawn_ksoftirqd+0x40/0x5c [ 0.132456] [] do_one_initcall+0x118/0x1d8 [ 0.132466] [] kernel_init_freeable+0x12c/0x290 [ 0.132479] [] kernel_init+0x14/0x220 Bug: 110360156 Change-Id: Ie908090225e491fde6e0c0c836e3e986b262ca85 Signed-off-by: Joel Fernandes (Google) [clingutla@codeaurora.org: Moved up RCU readlock to 'select_task_rq_fair' to protect total function.] Signed-off-by: Lingutla Chandrasekhar --- kernel/sched/fair.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 38fed13db70f..ca683db582bb 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -7451,12 +7451,10 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync goto out; } - rcu_read_lock(); - sd = rcu_dereference(per_cpu(sd_ea, prev_cpu)); if (!sd) { target_cpu = prev_cpu; - goto unlock; + goto out; } sync_entity_load_avg(&p->se); @@ -7466,14 +7464,14 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync &fbt_env); if (next_cpu == -1) { target_cpu = prev_cpu; - goto unlock; + goto out; } if (fbt_env.placement_boost || fbt_env.need_idle || fbt_env.avoid_prev_cpu || (rtg_target && !cpumask_test_cpu(prev_cpu, rtg_target))) { target_cpu = next_cpu; - goto unlock; + goto out; } /* Unconditionally prefer IDLE CPUs for boosted/prefer_idle tasks */ @@ -7481,7 +7479,7 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync schedstat_inc(p->se.statistics.nr_wakeups_secb_idle_bt); schedstat_inc(this_rq()->eas_stats.secb_idle_bt); target_cpu = next_cpu; - goto unlock; + goto out; } target_cpu = prev_cpu; @@ -7515,7 +7513,7 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync schedstat_inc(p->se.statistics.nr_wakeups_secb_insuff_cap); schedstat_inc(this_rq()->eas_stats.secb_insuff_cap); target_cpu = next_cpu; - goto unlock; + goto out; } /* Check if EAS_CPU_NXT is a more energy efficient CPU */ @@ -7523,20 +7521,18 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync schedstat_inc(p->se.statistics.nr_wakeups_secb_nrg_sav); schedstat_inc(this_rq()->eas_stats.secb_nrg_sav); target_cpu = eenv.cpu[eenv.next_idx].cpu_id; - goto unlock; + goto out; } schedstat_inc(p->se.statistics.nr_wakeups_secb_no_nrg_sav); schedstat_inc(this_rq()->eas_stats.secb_no_nrg_sav); target_cpu = prev_cpu; - goto unlock; + goto out; } schedstat_inc(p->se.statistics.nr_wakeups_secb_count); schedstat_inc(this_rq()->eas_stats.secb_count); -unlock: - rcu_read_unlock(); out: trace_sched_task_util(p, next_cpu, backup_cpu, target_cpu, sync, fbt_env.need_idle, fastpath, @@ -7572,8 +7568,12 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f cpumask_test_cpu(cpu, tsk_cpus_allowed(p))); } - if (energy_aware()) - return select_energy_cpu_brute(p, prev_cpu, sync); + if (energy_aware()) { + rcu_read_lock(); + new_cpu = select_energy_cpu_brute(p, prev_cpu, sync); + rcu_read_unlock(); + return new_cpu; + } rcu_read_lock(); for_each_domain(cpu, tmp) { -- GitLab From 031ce459e67bb8a5abf79451951ab53c9924f0d1 Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Thu, 26 Jul 2018 22:59:15 +0530 Subject: [PATCH 510/604] ARM: dts: msm: Update gpu thermal zone trip for QCS605 Update gpu step wise thermal zone trip threshold for QCS605 based on latest recommendation. Change-Id: I4a568acbc2d86cff6409b4ae3c35d4ba4e27b0c3 Signed-off-by: Manaf Meethalavalappu Pallikunhi --- arch/arm64/boot/dts/qcom/qcs605.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs605.dtsi b/arch/arm64/boot/dts/qcom/qcs605.dtsi index 61ea299dde2c..7801775c7e3b 100644 --- a/arch/arm64/boot/dts/qcom/qcs605.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs605.dtsi @@ -108,6 +108,14 @@ }; }; }; + + gpu-virt-max-step { + trips { + gpu-trip0 { + temperature = <100000>; + }; + }; + }; }; &msm_gpu { -- GitLab From e8c46e6172e0ea1f4b89b2f7adfa0105e9245f44 Mon Sep 17 00:00:00 2001 From: Harsh Shah Date: Tue, 10 Jul 2018 15:28:33 -0700 Subject: [PATCH 511/604] 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 3538e75822e5..f6becfbf41a1 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 8c26cab12854b71e378579dcd2af515681e7f134 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Mon, 23 Jul 2018 15:55:07 -0700 Subject: [PATCH 512/604] 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 | 3 ++- drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf.c | 3 ++- 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 + .../media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c | 3 ++- .../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_csid170.c | 3 ++- .../isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.c | 3 ++- .../cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c | 3 ++- .../cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c | 3 ++- 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 | 3 ++- .../msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c | 1 + .../media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c | 2 ++ .../camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c | 1 + .../msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c | 1 + .../msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c | 3 ++- .../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 | 3 ++- .../msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c | 3 ++- drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c | 1 + drivers/media/platform/msm/camera/cam_sync/cam_sync.c | 1 + 29 files changed, 41 insertions(+), 11 deletions(-) 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 29de3159e5a7..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 @@ -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 @@ -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 fa98be2285b7..e4ec08b41504 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 @@ -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 @@ -561,6 +561,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 fd94e7c235c8..c7ef37c65659 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 @@ -217,6 +217,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 4f91f734e989..7df806b1b7a3 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 @@ -236,6 +236,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 14c3c9c5815b..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 @@ -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 @@ -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 e775daac6fbe..a067915bed7d 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 @@ -136,6 +136,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_csid170.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.c index bdd59d232f70..70223f1427f5 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.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 @@ -41,6 +41,7 @@ static struct platform_driver cam_ife_csid170_driver = { .name = CAM_CSID_DRV_NAME, .owner = THIS_MODULE, .of_match_table = cam_ife_csid170_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_lite170.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.c index 36c6df0ae194..6c39bd84e47f 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.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 @@ -39,6 +39,7 @@ static struct platform_driver cam_ife_csid_lite170_driver = { .name = CAM_CSID_LITE_DRV_NAME, .owner = THIS_MODULE, .of_match_table = cam_ife_csid_lite170_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c index 0af32ad5d546..d002f84015de 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.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 @@ -32,6 +32,7 @@ static struct platform_driver cam_vfe170_driver = { .name = "cam_vfe170", .owner = THIS_MODULE, .of_match_table = cam_vfe170_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c index 3c8abbf065ab..ab692cf095e4 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.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 @@ -32,6 +32,7 @@ static struct platform_driver cam_vfe170_driver = { .name = "cam_vfe_lite170", .owner = THIS_MODULE, .of_match_table = cam_vfe170_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 5be16ef6a174..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 @@ -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 @@ -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 c8ca85dafdba..ce7ac3f0b820 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 @@ -373,6 +373,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 e2f061f49a31..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 @@ -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 @@ -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 b8c32d4ce3b7..cc34a70893db 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 @@ -508,6 +508,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 bb3789b12dcc..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 @@ -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 @@ -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 b60111af1620..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 @@ -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 @@ -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 c46ebe4d6f62..46463faaa296 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 @@ -3384,6 +3384,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 55896f497c59..fb69fdc1d80c 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c @@ -1053,6 +1053,7 @@ static struct platform_driver cam_sync_driver = { .driver = { .name = "cam_sync", .owner = THIS_MODULE, + .suppress_bind_attrs = true, }, }; -- GitLab From 980118215f391218a56d510efdb73c3615da2fb3 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 25 Jul 2018 16:17:25 -0700 Subject: [PATCH 513/604] 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 Signed-off-by: Vishalsingh Hajeri --- 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 407462d42605..212065050d81 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 @@ -595,7 +595,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 021b617a35b1e0f2a68f08672f89db6cec79f823 Mon Sep 17 00:00:00 2001 From: Madhukar Sandi Date: Fri, 27 Jul 2018 14:05:27 +0530 Subject: [PATCH 514/604] defconfig: msm: enable serial config in 8909 perf build Enable CONFIG_SERIAL_MSM_HS in perf config file. This flag is required for BT driver has to work in LAT Change-Id: I5b3f1a130b5862518eccb830b4cb4a554480a468 Signed-off-by: Madhukar Sandi --- arch/arm/configs/msm8909-perf_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 5f655b47e4ed..b6630221db20 100644 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -259,6 +259,7 @@ CONFIG_INPUT_TOUCHSCREEN=y CONFIG_INPUT_MISC=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y +CONFIG_SERIAL_MSM_HS=y CONFIG_SERIAL_MSM_SMD=y CONFIG_DIAG_CHAR=y CONFIG_DIAG_USES_SMD=y -- GitLab From 56c447b78ffe98f58a403dbb1bc756b061d66b7e Mon Sep 17 00:00:00 2001 From: Prakash Gupta Date: Fri, 27 Jul 2018 14:09:46 +0530 Subject: [PATCH 515/604] iommu: arm-smmu: fix device remove cleanup smmu devices are added to arm_smmu_devices list during device probe. This needs to be cleaned up during device remove. In absence of that we can see list corruption. register_client_adhoc:Client handle 1 apps_smmu list_add corruption. next->prev should be prev (ffffff8ee36ed1e8), but was 6b6b6b6b6b6b6b6b. (next=ffffffdf7004a590). PC is at __list_add+0xd8/0xe0 LR is at __list_add+0xd8/0xe0 __list_add+0xd8/0xe0 arm_smmu_device_dt_probe+0x334/0x1290 platform_drv_probe+0x58/0xd0 driver_probe_device+0x254/0x438 bind_store+0x168/0x1c4 drv_attr_store+0x48/0x5c sysfs_kf_write+0x5c/0x74 [...] CRs-Fixed: 2262423 Change-Id: I48dedc44e427f061af86e994756a3e95afdb3ac5 Signed-off-by: Prakash Gupta --- drivers/iommu/arm-smmu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 3359afbb1c77..a83616951d47 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -4864,6 +4864,10 @@ static int arm_smmu_device_remove(struct platform_device *pdev) arm_smmu_exit_power_resources(smmu->pwr); + spin_lock(&arm_smmu_devices_lock); + list_del(&smmu->list); + spin_unlock(&arm_smmu_devices_lock); + return 0; } -- GitLab From 96233a07fd1b080ceb68c2f60e7b6fe4426d1118 Mon Sep 17 00:00:00 2001 From: Venkataraman Nerellapalli Date: Thu, 26 Jul 2018 11:58:08 +0530 Subject: [PATCH 516/604] ARM: dts: msm: add Elan_Sparrow support for apq8053-lite-dragon-v2.1 Add Elan_Sparrow touch screen support for apq8053-lite-dragon-v2.1. Change-Id: Ie9154fc11c3a63ac162d504cadb1c6e38f74196a Signed-off-by: Venkataraman Nerellapalli --- .../boot/dts/qcom/apq8053-lite-dragon-v2.1.dts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dts index 6c9c26698071..63a364addf9a 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dts +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dts @@ -25,3 +25,17 @@ &blsp2_uart0 { status = "okay"; }; + +&i2c_3 { + status = "okay"; + elan_ktf@10 { + compatible = "elan,ekth3500"; + reg = <0x10>; + vdd-supply = <&pm8953_l10>; + vccio-supply = <&pm8953_l6>; + interrupt-parent = <&tlmm>; + reset-gpio = <&tlmm 64 GPIO_ACTIVE_LOW>; + elan,irq-gpio = <&tlmm 65 0x2008>; + interrupts = <65 0x2>; + }; +}; -- GitLab From c63e97f2189c6fb87799d45e66dba79c8bfb1fd3 Mon Sep 17 00:00:00 2001 From: Vikas Reddy Pachika Date: Fri, 27 Jul 2018 14:50:22 +0530 Subject: [PATCH 517/604] msm: vidc: Use inbuilt math function for doing division operation Division of 64bit dividend is causing compilation failure for 32bit kernel. Using math function to support division for both 64 and 32-bit kernels. Change-Id: Ia12d55c49e7c2448a9125154a56a2d36159b8857 Signed-off-by: Vikas Reddy Pachika --- drivers/media/platform/msm/vidc/msm_vidc_clocks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c index a665978157aa..c15a2e9d12fc 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c @@ -643,8 +643,8 @@ static unsigned long msm_vidc_calc_freq(struct msm_vidc_inst *inst, vsp_factor_num = vsp_factor_num * 13 / 10; vsp_factor_den *= 2; } - vsp_cycles += ((u64)inst->clk_data.bitrate * vsp_factor_num) / - vsp_factor_den; + vsp_cycles += div_u64((u64)inst->clk_data.bitrate * + vsp_factor_num, vsp_factor_den); } else if (inst->session_type == MSM_VIDC_DECODER) { vpp_cycles = mbs_per_second * inst->clk_data.entry->vpp_cycles; -- GitLab From 92b5e138d1530c5b891aa408c85cdfb87fbb551c Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Wed, 18 Jul 2018 15:03:35 +0530 Subject: [PATCH 518/604] msm: ADSPRPC: Handle map and unmap in 32 bit images Copy data to architecture specific structures from default 64 bit structures, as 32 bit image structures will result in buffer overflow when copied from 64 bit default structures. Change-Id: I68e51fd128142e075528315f99bd34dd6b423239 Acked-by: Himateja Reddy Signed-off-by: Tharun Kumar Merugu --- drivers/char/adsprpc.c | 48 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 6aa60b1eb5af..c3d7c68167a3 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -2487,6 +2487,31 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va, static void fastrpc_mmap_add(struct fastrpc_mmap *map); +static inline void get_fastrpc_ioctl_mmap_64( + struct fastrpc_ioctl_mmap_64 *mmap64, + struct fastrpc_ioctl_mmap *immap) +{ + immap->fd = mmap64->fd; + immap->flags = mmap64->flags; + immap->vaddrin = (uintptr_t)mmap64->vaddrin; + immap->size = mmap64->size; +} + +static inline void put_fastrpc_ioctl_mmap_64( + struct fastrpc_ioctl_mmap_64 *mmap64, + struct fastrpc_ioctl_mmap *immap) +{ + mmap64->vaddrout = (uint64_t)immap->vaddrout; +} + +static inline void get_fastrpc_ioctl_munmap_64( + struct fastrpc_ioctl_munmap_64 *munmap64, + struct fastrpc_ioctl_munmap *imunmap) +{ + imunmap->vaddrout = (uintptr_t)munmap64->vaddrout; + imunmap->size = munmap64->size; +} + static int fastrpc_internal_munmap(struct fastrpc_file *fl, struct fastrpc_ioctl_munmap *ud) { @@ -3209,12 +3234,18 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, union { struct fastrpc_ioctl_invoke_crc inv; struct fastrpc_ioctl_mmap mmap; + struct fastrpc_ioctl_mmap_64 mmap64; struct fastrpc_ioctl_munmap munmap; + struct fastrpc_ioctl_munmap_64 munmap64; struct fastrpc_ioctl_munmap_fd munmap_fd; struct fastrpc_ioctl_init_attrs init; struct fastrpc_ioctl_perf perf; struct fastrpc_ioctl_control cp; } p; + union { + struct fastrpc_ioctl_mmap mmap; + struct fastrpc_ioctl_munmap munmap; + } i; void *param = (char *)ioctl_param; struct fastrpc_file *fl = (struct fastrpc_file *)file->private_data; int size = 0, err = 0; @@ -3278,24 +3309,27 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, goto bail; break; case FASTRPC_IOCTL_MMAP_64: - K_COPY_FROM_USER(err, 0, &p.mmap, param, - sizeof(p.mmap)); + K_COPY_FROM_USER(err, 0, &p.mmap64, param, + sizeof(p.mmap64)); if (err) goto bail; - VERIFY(err, 0 == (err = fastrpc_internal_mmap(fl, &p.mmap))); + get_fastrpc_ioctl_mmap_64(&p.mmap64, &i.mmap); + VERIFY(err, 0 == (err = fastrpc_internal_mmap(fl, &i.mmap))); if (err) goto bail; - K_COPY_TO_USER(err, 0, param, &p.mmap, sizeof(p.mmap)); + put_fastrpc_ioctl_mmap_64(&p.mmap64, &i.mmap); + K_COPY_TO_USER(err, 0, param, &p.mmap64, sizeof(p.mmap64)); if (err) goto bail; break; case FASTRPC_IOCTL_MUNMAP_64: - K_COPY_FROM_USER(err, 0, &p.munmap, param, - sizeof(p.munmap)); + K_COPY_FROM_USER(err, 0, &p.munmap64, param, + sizeof(p.munmap64)); if (err) goto bail; + get_fastrpc_ioctl_munmap_64(&p.munmap64, &i.munmap); VERIFY(err, 0 == (err = fastrpc_internal_munmap(fl, - &p.munmap))); + &i.munmap))); if (err) goto bail; break; -- GitLab From 461e9ea4d8dedbfdfef3fce0a7c58285702877ab Mon Sep 17 00:00:00 2001 From: Umang Agrawal Date: Thu, 5 Jul 2018 18:50:13 +0530 Subject: [PATCH 519/604] power: smb5: Add moisture detection support for pmi632 Presence of moisture expedites the corrosion of Type-C/uUSB ID pins due to constant DRP toggling. To reduce the effect of corrosion, set DRP toggling duty cycle to 1% and suspend usb input on water detection. Use property MOISTURE_DETECTED to reflect moisture detection status. Change-Id: I3bb41564cf67127ae2c0bb27089a1e8b5d722df6 Signed-off-by: Umang Agrawal --- .../bindings/power/supply/qcom/qpnp-smb5.txt | 6 + drivers/power/supply/qcom/qpnp-smb5.c | 48 +++- drivers/power/supply/qcom/smb5-lib.c | 230 +++++++++++++++++- drivers/power/supply/qcom/smb5-lib.h | 9 + drivers/power/supply/qcom/smb5-reg.h | 12 + 5 files changed, 293 insertions(+), 12 deletions(-) diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt index 65dcf593372b..12455522a51e 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt @@ -220,6 +220,12 @@ Charger specific properties: connector THERM, only valid values are (0/30/100/400). If not specified 100K is used as default pull-up. +- qcom,moisture-protection-enable + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables mositure protection + feature. + ============================================= Second Level Nodes - SMB5 Charger Peripherals ============================================= diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 2a997ddf60f6..aa50be72f282 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -280,6 +280,8 @@ static int smb5_chg_config_init(struct smb5 *chip) case PMI632_SUBTYPE: chip->chg.smb_version = PMI632_SUBTYPE; chg->wa_flags |= WEAK_ADAPTER_WA; + if (pmic_rev_id->rev4 >= 2) + chg->wa_flags |= MOISTURE_PROTECTION_WA; chg->param = smb5_pmi632_params; chg->use_extcon = true; chg->name = "pmi632_charger"; @@ -484,6 +486,9 @@ static int smb5_parse_dt(struct smb5 *chip) of_property_read_u32(node, "qcom,connector-internal-pull-kohm", &chg->connector_pull_up); + chg->moisture_protection_enabled = of_property_read_bool(node, + "qcom,moisture-protection-enable"); + return 0; } @@ -604,6 +609,7 @@ static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_HVDCP_OPTI_ALLOWED, POWER_SUPPLY_PROP_QC_OPTI_DISABLE, + POWER_SUPPLY_PROP_MOISTURE_DETECTED, }; static int smb5_usb_get_prop(struct power_supply *psy, @@ -742,6 +748,9 @@ static int smb5_usb_get_prop(struct power_supply *psy, if (chg->hw_connector_mitigation) val->intval |= POWER_SUPPLY_QC_CTM_DISABLE; break; + case POWER_SUPPLY_PROP_MOISTURE_DETECTED: + val->intval = chg->moisture_present; + break; default: pr_err("get prop %d is not supported in usb\n", psp); rc = -EINVAL; @@ -1629,14 +1638,6 @@ static int smb5_configure_typec(struct smb_charger *chg) return rc; } - rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, - TYPEC_WATER_DETECTION_INT_EN_BIT); - if (rc < 0) { - dev_err(chg->dev, - "Couldn't configure Type-C interrupts rc=%d\n", rc); - return rc; - } - rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, EN_TRY_SNK_BIT, EN_TRY_SNK_BIT); if (rc < 0) { @@ -1675,6 +1676,37 @@ static int smb5_configure_micro_usb(struct smb_charger *chg) return rc; } + if (chg->moisture_protection_enabled && + (chg->wa_flags & MOISTURE_PROTECTION_WA)) { + /* Enable moisture detection interrupt */ + rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, + TYPEC_WATER_DETECTION_INT_EN_BIT, + TYPEC_WATER_DETECTION_INT_EN_BIT); + if (rc < 0) { + dev_err(chg->dev, "Couldn't enable moisture detection interrupt rc=%d\n", + rc); + return rc; + } + + /* Enable uUSB factory mode */ + rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, + EN_MICRO_USB_FACTORY_MODE_BIT, + EN_MICRO_USB_FACTORY_MODE_BIT); + if (rc < 0) { + dev_err(chg->dev, "Couldn't enable uUSB factory mode c=%d\n", + rc); + return rc; + } + + /* Disable periodic monitoring of CC_ID pin */ + rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0); + if (rc < 0) { + dev_err(chg->dev, "Couldn't disable periodic monitoring of CC_ID rc=%d\n", + rc); + return rc; + } + } + return rc; } diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 23070e6962a1..57d070ad9f5a 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "smb5-lib.h" #include "smb5-reg.h" #include "battery.h" @@ -1045,6 +1046,100 @@ int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua) return 0; } +/******************** + * Moisture Protection * + ********************/ +#define MICRO_USB_DETECTION_ON_TIME_20_MS 0x08 +#define MICRO_USB_DETECTION_PERIOD_X_100 0x03 +#define U_USB_STATUS_WATER_PRESENT 0x00 +static int smblib_set_moisture_protection(struct smb_charger *chg, + bool enable) +{ + int rc = 0; + + if (chg->moisture_present == enable) { + smblib_dbg(chg, PR_MISC, "No change in moisture protection status\n"); + return rc; + } + + if (enable) { + chg->moisture_present = true; + + /* Disable uUSB factory mode detection */ + rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, + EN_MICRO_USB_FACTORY_MODE_BIT, 0); + if (rc < 0) { + smblib_err(chg, "Couldn't disable uUSB factory mode detection rc=%d\n", + rc); + return rc; + } + + /* Disable moisture detection and uUSB state change interrupt */ + rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, + TYPEC_WATER_DETECTION_INT_EN_BIT | + MICRO_USB_STATE_CHANGE_INT_EN_BIT, 0); + if (rc < 0) { + smblib_err(chg, "Couldn't disable moisture detection interrupt rc=%d\n", + rc); + return rc; + } + + /* Set 1% duty cycle on ID detection */ + rc = smblib_masked_write(chg, + TYPEC_U_USB_WATER_PROTECTION_CFG_REG, + EN_MICRO_USB_WATER_PROTECTION_BIT | + MICRO_USB_DETECTION_ON_TIME_CFG_MASK | + MICRO_USB_DETECTION_PERIOD_CFG_MASK, + EN_MICRO_USB_WATER_PROTECTION_BIT | + MICRO_USB_DETECTION_ON_TIME_20_MS | + MICRO_USB_DETECTION_PERIOD_X_100); + if (rc < 0) { + smblib_err(chg, "Couldn't set 1 percent CC_ID duty cycle rc=%d\n", + rc); + return rc; + } + + vote(chg->usb_icl_votable, MOISTURE_VOTER, true, 0); + } else { + chg->moisture_present = false; + vote(chg->usb_icl_votable, MOISTURE_VOTER, false, 0); + + /* Enable moisture detection and uUSB state change interrupt */ + rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, + TYPEC_WATER_DETECTION_INT_EN_BIT | + MICRO_USB_STATE_CHANGE_INT_EN_BIT, + TYPEC_WATER_DETECTION_INT_EN_BIT | + MICRO_USB_STATE_CHANGE_INT_EN_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't enable moisture detection and uUSB state change interrupt rc=%d\n", + rc); + return rc; + } + + /* Disable periodic monitoring of CC_ID pin */ + rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0); + if (rc < 0) { + smblib_err(chg, "Couldn't disable 1 percent CC_ID duty cycle rc=%d\n", + rc); + return rc; + } + + /* Enable uUSB factory mode detection */ + rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, + EN_MICRO_USB_FACTORY_MODE_BIT, + EN_MICRO_USB_FACTORY_MODE_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't disable uUSB factory mode detection rc=%d\n", + rc); + return rc; + } + } + + smblib_dbg(chg, PR_MISC, "Moisture protection %s\n", + chg->moisture_present ? "enabled" : "disabled"); + return rc; +} + /********************* * VOTABLE CALLBACKS * *********************/ @@ -3454,11 +3549,28 @@ irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data) struct smb_charger *chg = irq_data->parent_data; if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) { + if (chg->moisture_protection_enabled && + (chg->wa_flags & MOISTURE_PROTECTION_WA)) { + /* + * Adding pm_stay_awake as because pm_relax is called + * on exit path from the work routine. + */ + pm_stay_awake(chg->dev); + schedule_work(&chg->moisture_protection_work); + } + cancel_delayed_work_sync(&chg->uusb_otg_work); - vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0); - smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n"); - schedule_delayed_work(&chg->uusb_otg_work, - msecs_to_jiffies(chg->otg_delay_ms)); + /* + * Skip OTG enablement if RID interrupt triggers with moisture + * protection still enabled. + */ + if (!chg->moisture_present) { + vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0); + smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n"); + schedule_delayed_work(&chg->uusb_otg_work, + msecs_to_jiffies(chg->otg_delay_ms)); + } + return IRQ_HANDLED; } @@ -3826,6 +3938,96 @@ static void smblib_pl_enable_work(struct work_struct *work) vote(chg->awake_votable, PL_DELAY_VOTER, false, 0); } +#define MOISTURE_PROTECTION_CHECK_DELAY_MS 300000 /* 5 mins */ +static void smblib_moisture_protection_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + moisture_protection_work); + int rc; + bool usb_plugged_in; + u8 stat; + + /* + * Disable 1% duty cycle on CC_ID pin and enable uUSB factory mode + * detection to track any change on RID, as interrupts are disable. + */ + rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0); + if (rc < 0) { + smblib_err(chg, "Couldn't disable periodic monitoring of CC_ID rc=%d\n", + rc); + goto out; + } + + rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, + EN_MICRO_USB_FACTORY_MODE_BIT, + EN_MICRO_USB_FACTORY_MODE_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't enable uUSB factory mode detection rc=%d\n", + rc); + goto out; + } + + /* + * Add a delay of 100ms to allow change in rid to reflect on + * status registers. + */ + msleep(100); + + rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc); + goto out; + } + usb_plugged_in = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT); + + /* Check uUSB status for moisture presence */ + rc = smblib_read(chg, TYPEC_U_USB_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read TYPE_C_U_USB_STATUS_REG rc=%d\n", + rc); + goto out; + } + + /* + * Factory mode detection happens in case of USB plugged-in by using + * a different current source of 2uA which can hamper moisture + * detection. Since factory mode is not supported in kernel, factory + * mode detection can be considered as equivalent to presence of + * moisture. + */ + if (stat == U_USB_STATUS_WATER_PRESENT || stat == U_USB_FMB1_BIT || + stat == U_USB_FMB2_BIT || (usb_plugged_in && + stat == U_USB_FLOAT1_BIT)) { + smblib_set_moisture_protection(chg, true); + alarm_start_relative(&chg->moisture_protection_alarm, + ms_to_ktime(MOISTURE_PROTECTION_CHECK_DELAY_MS)); + } else { + smblib_set_moisture_protection(chg, false); + rc = alarm_cancel(&chg->moisture_protection_alarm); + if (rc < 0) + smblib_err(chg, "Couldn't cancel moisture protection alarm\n"); + } + +out: + pm_relax(chg->dev); +} + +static enum alarmtimer_restart moisture_protection_alarm_cb(struct alarm *alarm, + ktime_t now) +{ + struct smb_charger *chg = container_of(alarm, struct smb_charger, + moisture_protection_alarm); + + smblib_dbg(chg, PR_MISC, "moisture Protection Alarm Triggered %lld\n", + ktime_to_ms(now)); + + /* Atomic context, cannot use voter */ + pm_stay_awake(chg->dev); + schedule_work(&chg->moisture_protection_work); + + return ALARMTIMER_NORESTART; +} + #define JEITA_SOFT 0 #define JEITA_HARD 1 static int smblib_update_jeita(struct smb_charger *chg, u32 *thresholds, @@ -4028,6 +4230,21 @@ int smblib_init(struct smb_charger *chg) INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work); INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work); INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work); + + if (chg->moisture_protection_enabled && + (chg->wa_flags & MOISTURE_PROTECTION_WA)) { + INIT_WORK(&chg->moisture_protection_work, + smblib_moisture_protection_work); + + if (alarmtimer_get_rtcdev()) { + alarm_init(&chg->moisture_protection_alarm, + ALARM_BOOTTIME, moisture_protection_alarm_cb); + } else { + smblib_err(chg, "Failed to initialize moisture protection alarm\n"); + return -ENODEV; + } + } + chg->fake_capacity = -EINVAL; chg->fake_input_current_limited = -EINVAL; chg->fake_batt_status = -EINVAL; @@ -4089,6 +4306,11 @@ int smblib_deinit(struct smb_charger *chg) { switch (chg->mode) { case PARALLEL_MASTER: + if (chg->moisture_protection_enabled && + (chg->wa_flags & MOISTURE_PROTECTION_WA)) { + alarm_cancel(&chg->moisture_protection_alarm); + cancel_work_sync(&chg->moisture_protection_work); + } cancel_work_sync(&chg->bms_update_work); cancel_work_sync(&chg->jeita_update_work); cancel_work_sync(&chg->pl_update_work); diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index e59b11b15376..8cd679a03ce3 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -18,6 +18,7 @@ #include #include #include +#include #include "storm-watch.h" enum print_reason { @@ -68,6 +69,7 @@ enum print_reason { #define HW_LIMIT_VOTER "HW_LIMIT_VOTER" #define FORCE_RECHARGE_VOTER "FORCE_RECHARGE_VOTER" #define AICL_THRESHOLD_VOTER "AICL_THRESHOLD_VOTER" +#define MOISTURE_VOTER "MOISTURE_VOTER" #define BOOST_BACK_STORM_COUNT 3 #define WEAK_CHG_STORM_COUNT 8 @@ -98,6 +100,7 @@ enum sink_src_mode { enum { BOOST_BACK_WA = BIT(0), WEAK_ADAPTER_WA = BIT(1), + MOISTURE_PROTECTION_WA = BIT(2), }; enum { @@ -331,6 +334,7 @@ struct smb_charger { struct work_struct bms_update_work; struct work_struct pl_update_work; struct work_struct jeita_update_work; + struct work_struct moisture_protection_work; struct delayed_work ps_change_timeout_work; struct delayed_work clear_hdc_work; struct delayed_work icl_change_work; @@ -338,6 +342,9 @@ struct smb_charger { struct delayed_work uusb_otg_work; struct delayed_work bb_removal_work; + /* alarm */ + struct alarm moisture_protection_alarm; + /* pd */ int voltage_min_uv; int voltage_max_uv; @@ -386,6 +393,8 @@ struct smb_charger { int aicl_cont_threshold_mv; int default_aicl_cont_threshold_mv; bool aicl_max_reached; + bool moisture_present; + bool moisture_protection_enabled; /* workaround flag */ u32 wa_flags; diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index e8cdda3a4441..285fea66d2e7 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -117,6 +117,7 @@ enum { #define USBIN_SUSPEND_STS_BIT BIT(6) #define USE_USBIN_BIT BIT(4) #define USE_DCIN_BIT BIT(3) +#define POWER_PATH_MASK GENMASK(2, 1) #define VALID_INPUT_POWER_SOURCE_STS_BIT BIT(0) #define DCDC_CMD_OTG_REG (DCDC_BASE + 0x40) @@ -284,6 +285,7 @@ enum { #define TYPEC_ATTACH_DETACH_STATE_BIT BIT(5) #define TYPE_C_MISC_STATUS_REG (TYPEC_BASE + 0x0B) +#define TYPEC_WATER_DETECTION_STATUS_BIT BIT(7) #define SNK_SRC_MODE_BIT BIT(6) #define TYPEC_VBUS_ERROR_STATUS_BIT BIT(4) #define CC_ORIENTATION_BIT BIT(1) @@ -296,6 +298,10 @@ enum { #define TYPEC_U_USB_STATUS_REG (TYPEC_BASE + 0x0F) #define U_USB_GROUND_NOVBUS_BIT BIT(6) #define U_USB_GROUND_BIT BIT(4) +#define U_USB_FMB1_BIT BIT(3) +#define U_USB_FLOAT1_BIT BIT(2) +#define U_USB_FMB2_BIT BIT(1) +#define U_USB_FLOAT2_BIT BIT(0) #define TYPE_C_MODE_CFG_REG (TYPEC_BASE + 0x44) #define TYPEC_POWER_ROLE_CMD_MASK GENMASK(2, 1) @@ -341,8 +347,14 @@ enum { #define REDUCE_TCCDEBOUNCE_TO_2MS_BIT BIT(2) #define TYPEC_U_USB_CFG_REG (TYPEC_BASE + 0x70) +#define EN_MICRO_USB_FACTORY_MODE_BIT BIT(1) #define EN_MICRO_USB_MODE_BIT BIT(0) +#define TYPEC_U_USB_WATER_PROTECTION_CFG_REG (TYPEC_BASE + 0x72) +#define EN_MICRO_USB_WATER_PROTECTION_BIT BIT(4) +#define MICRO_USB_DETECTION_ON_TIME_CFG_MASK GENMASK(3, 2) +#define MICRO_USB_DETECTION_PERIOD_CFG_MASK GENMASK(1, 0) + #define TYPEC_MICRO_USB_MODE_REG (TYPEC_BASE + 0x73) #define MICRO_USB_MODE_ONLY_BIT BIT(0) /******************************** -- GitLab From 033c1202d3c398e08cf423262688d9224b802024 Mon Sep 17 00:00:00 2001 From: Dennis Cagle Date: Fri, 27 Jul 2018 14:20:42 -0700 Subject: [PATCH 520/604] defconfig: sdxpoorwills: Remove AUDITSYSCALL CONFIG_AUDITSYSCALL adds unnecessary overhead Change-Id: I547cc87f7decceb6850052eee68f3c6bd05a5693 Signed-off-by: Dennis Cagle --- arch/arm/configs/sdxpoorwills-perf_defconfig | 1 + arch/arm/configs/sdxpoorwills_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig index d5930a7c48e1..dc3a914f0429 100644 --- a/arch/arm/configs/sdxpoorwills-perf_defconfig +++ b/arch/arm/configs/sdxpoorwills-perf_defconfig @@ -1,4 +1,5 @@ CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig index f5abbb436d2c..a72ecf0d068a 100644 --- a/arch/arm/configs/sdxpoorwills_defconfig +++ b/arch/arm/configs/sdxpoorwills_defconfig @@ -1,4 +1,5 @@ CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y -- GitLab From 139475795176cbd0929f58f6d9626a6152f24f26 Mon Sep 17 00:00:00 2001 From: "Joel Fernandes (Google)" Date: Mon, 18 Jun 2018 11:36:21 -0700 Subject: [PATCH 521/604] ANDROID: sched/walt: Fix lockdep warning When lockdep enabled, a warning fires on boot up in the WALT code. This is because the walt_irq_work handler acquires rq-locks in succession however, this is forbidden. To fix the warning, we use the raw_spin_lock_nested API to tell lockdep we are intentionally acquiring the rq-lock in a nested fashion. Bug: 110360156 Change-Id: I8598d79632991d799edcc8808d2e2f383b7a7ad3 Signed-off-by: Joel Fernandes (Google) Signed-off-by: Lingutla Chandrasekhar --- kernel/sched/walt.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index d2e78d7809b9..bd4ca5b9e38c 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -3170,13 +3170,19 @@ void walt_irq_work(struct irq_work *irq_work) u64 wc; int flag = SCHED_CPUFREQ_WALT; bool is_migration = false; + int level = 0; /* Am I the window rollover work or the migration work? */ if (irq_work == &walt_migration_irq_work) is_migration = true; - for_each_cpu(cpu, cpu_possible_mask) - raw_spin_lock(&cpu_rq(cpu)->lock); + for_each_cpu(cpu, cpu_possible_mask) { + if (level == 0) + raw_spin_lock(&cpu_rq(cpu)->lock); + else + raw_spin_lock_nested(&cpu_rq(cpu)->lock, level); + level++; + } wc = sched_ktime_clock(); walt_load_reported_window = atomic64_read(&walt_irq_work_lastq_ws); -- GitLab From 56384aa506941818bdc19a0f25b780753d8b69b4 Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Fri, 20 Jul 2018 11:05:35 +0530 Subject: [PATCH 522/604] tracing: irqsoff: Fix compilation warning When PROVE_LOCKING enabled, tracing_irq_cpu would be unused variable, so move it under proper condition checks. Change-Id: Ifb48dac8628a0084ed74930445fa95b35c661511 Signed-off-by: Lingutla Chandrasekhar --- kernel/trace/trace_irqsoff.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c index 59b482f7eba7..de63dab41193 100644 --- a/kernel/trace/trace_irqsoff.c +++ b/kernel/trace/trace_irqsoff.c @@ -804,10 +804,9 @@ static inline void tracer_preempt_on(unsigned long a0, unsigned long a1) { } static inline void tracer_preempt_off(unsigned long a0, unsigned long a1) { } #endif +#if defined(CONFIG_TRACE_IRQFLAGS) && !defined(CONFIG_PROVE_LOCKING) /* Per-cpu variable to prevent redundant calls when IRQs already off */ static DEFINE_PER_CPU(int, tracing_irq_cpu); - -#if defined(CONFIG_TRACE_IRQFLAGS) && !defined(CONFIG_PROVE_LOCKING) void trace_hardirqs_on(void) { if (!this_cpu_read(tracing_irq_cpu)) -- GitLab From 071be09fac6091a1c1793d4bc0ef92de80dd4619 Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Fri, 20 Jul 2018 15:23:35 +0530 Subject: [PATCH 523/604] sched: Fix lockdep warning for rq locks WALT tries to acquire all possible cpu's runqueue locks to update cluster stats or capacities. When lockdep enabled, it reports below warning. Fix it by using raw_spinlock_nested API to inform lockdep it is intentional. Report: [1.365691] May be due to missing lock nesting notation\x0a [1.372528] 1 lock held by swapper/0/1: [1.376399] #0: (&rq->lock){-.-...}, at: [] acquire_rq_locks_irqsave.constprop.22+0x64/0x9c [1.386649] \x0astack backtrace: [1.391054] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.9.106+ #10 [1.397282] Hardware name: Qualcomm Technologies, Inc. SDM845 v2.1 MTP (DT) [1.404295] Call trace: [1.406769] [] dump_backtrace+0x0/0x2c0 [1.412217] [] show_stack+0x20/0x28 [1.417315] [] dump_stack+0xa8/0xe0 [1.422412] [] __lock_acquire+0x18fc/0x1d74 [1.428204] [] lock_acquire+0xe0/0x288 [1.433569] [] _raw_spin_lock+0x44/0x58 [1.439009] [] acquire_rq_locks_irqsave.constprop.22+0x64/0x9c [1.446458] [] update_all_clusters_stats+0x3c/0x1f8 [1.452953] [] update_cluster_topology+0x2a0/0x300 [1.459363] [] sched_init_smp+0xc4/0x11c [1.464896] [] kernel_init_freeable+0x150/0x2bc [1.471044] [] kernel_init+0x18/0x100 [1.476308] [] ret_from_fork+0x10/0x50 Change-Id: Ibc5726e0f50f0135fd9b46c8065ee0f52dd5d5e7 Signed-off-by: Lingutla Chandrasekhar --- kernel/sched/walt.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index bd4ca5b9e38c..4afefd629f39 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -87,11 +87,16 @@ late_initcall(sched_init_ops); static void acquire_rq_locks_irqsave(const cpumask_t *cpus, unsigned long *flags) { - int cpu; + int cpu, level = 0; local_irq_save(*flags); - for_each_cpu(cpu, cpus) - raw_spin_lock(&cpu_rq(cpu)->lock); + for_each_cpu(cpu, cpus) { + if (level == 0) + raw_spin_lock(&cpu_rq(cpu)->lock); + else + raw_spin_lock_nested(&cpu_rq(cpu)->lock, level); + level++; + } } static void release_rq_locks_irqrestore(const cpumask_t *cpus, -- GitLab From 0cdc29e21c95dac9eaeacc47a265f6fb1e7e34d3 Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Fri, 20 Jul 2018 15:39:22 +0530 Subject: [PATCH 524/604] sched: rt: Use RCU lock in rt task cpu select path RT energy aware cpu selection tries to get cpu idle state without holding rcu read lock, it may get stale/corrupted value. Fix it by moving rcu unlock to end for energy aware cpu selection. Change-Id: Ia219062db6b97b9a44681647cea077c45c29cff2 Signed-off-by: Lingutla Chandrasekhar --- kernel/sched/rt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 44c767afdb87..95b68bdc9215 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -1805,7 +1805,6 @@ static int find_lowest_rq(struct task_struct *task) } } } while (sg = sg->next, sg != sd->groups); - rcu_read_unlock(); if (sg_target) { cpumask_and(&search_cpu, lowest_mask, @@ -1894,6 +1893,7 @@ static int find_lowest_rq(struct task_struct *task) } if (best_cpu != -1 && placement_boost != SCHED_BOOST_ON_ALL) { + rcu_read_unlock(); return best_cpu; } else if (!cpumask_empty(&backup_search_cpu)) { cpumask_copy(&search_cpu, &backup_search_cpu); @@ -1902,6 +1902,7 @@ static int find_lowest_rq(struct task_struct *task) placement_boost = SCHED_BOOST_NONE; goto retry; } + rcu_read_unlock(); } noea: -- GitLab From 143322b12335354e4571e02d2a778eda6363c5dc Mon Sep 17 00:00:00 2001 From: Monika Singh Date: Wed, 13 Jun 2018 11:09:45 +0530 Subject: [PATCH 525/604] ARM: dts: Mount system as root for sdm450 System needs to be mounted as root with the System-As-Root feature for non-A/B builds. Change-Id: If07a2c238f1861d61295a4b662463ae8fb9722fc Signed-off-by: Monika Singh --- arch/arm64/boot/dts/qcom/msm8953.dtsi | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index 3ab3b2b8007e..efe01f710ccd 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -55,14 +55,6 @@ fsmgr_flags = "wait,avb"; status = "ok"; }; - system { - compatible = "android,system"; - dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system"; - type = "ext4"; - mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait,avb"; - status = "ok"; - }; }; }; -- GitLab From 514b9294d8586f1072550c92c3964079b9d55d74 Mon Sep 17 00:00:00 2001 From: Monika Singh Date: Wed, 13 Jun 2018 12:10:46 +0530 Subject: [PATCH 526/604] ARM: dts: Mount system as root for sdm439 System needs to be mounted as root with the System-As-Root feature for non-A/B builds. Change-Id: I6eee9a6cbb9a68d9e3f0b8d4135b9aac30f13a14 Signed-off-by: Monika Singh --- arch/arm64/boot/dts/qcom/msm8937.dtsi | 9 --------- 1 file changed, 9 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8937.dtsi b/arch/arm64/boot/dts/qcom/msm8937.dtsi index 85e304319757..5180d1a66957 100644 --- a/arch/arm64/boot/dts/qcom/msm8937.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937.dtsi @@ -45,15 +45,6 @@ fsmgr_flags = "wait,avb"; status = "ok"; }; - system { - compatible = "android,system"; - dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system"; - type = "ext4"; - mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait,avb"; - status = "ok"; - }; - }; }; }; -- GitLab From 47b4fb5095e55f0662225afbeaf0fea98f4131a0 Mon Sep 17 00:00:00 2001 From: Ramesh Yadav Javadi Date: Fri, 27 Jul 2018 13:17:42 +0530 Subject: [PATCH 527/604] ARM: dts: msm: Add common CMA device configuration for msm8909w & apq8909 TZ expects firmware regions under 512MB. BG firmware region is allocated from common CMA region. Add common CMA configuration and restrict it within 512MB region for msm8909w and apq8009. Change-Id: Ifbd10b8af041b397851e983cdb9fc05d17dfe4a3 Signed-off-by: Ramesh Yadav Javadi --- arch/arm64/boot/dts/qcom/apq8009w-bg-memory.dtsi | 11 +++++++++++ arch/arm64/boot/dts/qcom/msm8909.dtsi | 2 +- arch/arm64/boot/dts/qcom/msm8909w-bg-memory.dtsi | 11 +++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/apq8009w-bg-memory.dtsi b/arch/arm64/boot/dts/qcom/apq8009w-bg-memory.dtsi index d83ae5c0e971..fef9f4528f17 100644 --- a/arch/arm64/boot/dts/qcom/apq8009w-bg-memory.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8009w-bg-memory.dtsi @@ -22,3 +22,14 @@ &peripheral_mem { reg = <0x0 0x8a300000 0x0 0x0600000>; }; + +&reserved_mem { + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xa0000000>; + reusable; + alignment = <0 0x400000>; + size = <0 0x1000000>; + linux,cma-default; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8909.dtsi b/arch/arm64/boot/dts/qcom/msm8909.dtsi index 1e3e49796713..8c06c93783fa 100644 --- a/arch/arm64/boot/dts/qcom/msm8909.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8909.dtsi @@ -163,7 +163,7 @@ }; }; - reserved-memory { + reserved_mem: reserved-memory { #address-cells = <2>; #size-cells = <2>; ranges; diff --git a/arch/arm64/boot/dts/qcom/msm8909w-bg-memory.dtsi b/arch/arm64/boot/dts/qcom/msm8909w-bg-memory.dtsi index f8410974ed81..3389d298b276 100644 --- a/arch/arm64/boot/dts/qcom/msm8909w-bg-memory.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8909w-bg-memory.dtsi @@ -22,3 +22,14 @@ &peripheral_mem { reg = <0x0 0x8d200000 0x0 0x0600000>; }; + +&reserved_mem { + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xa0000000>; + reusable; + alignment = <0 0x400000>; + size = <0 0x1000000>; + linux,cma-default; + }; +}; -- GitLab From d4893d03f63dfe8ae4a48e1b961fdf86ee927fe5 Mon Sep 17 00:00:00 2001 From: Devi Sandeep Endluri V V Date: Sat, 28 Jul 2018 16:47:14 +0530 Subject: [PATCH 528/604] defconfig: msm8937: Enable GCM crypto configs Enable GCM crypto support to keep it up-to-date with android recommended configs and pass testKernelConfigs CTS test. CRs-Fixed: 2263373 Change-Id: I3b09d444375e59e5e4e2cc3415950474a9be5b2c Signed-off-by: Devi Sandeep Endluri V V --- arch/arm/configs/msm8937-perf_defconfig | 1 + arch/arm/configs/msm8937_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index 040ce14b6375..49643dfd737c 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -639,6 +639,7 @@ CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index a33bdbdd8f8c..49cb030ad813 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -705,6 +705,7 @@ CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y -- GitLab From ea564e25170fc9321c31cbf95e54753c9f7a3e9a Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Thu, 26 Jul 2018 15:17:33 +0530 Subject: [PATCH 529/604] ARM: dts: msm: Disable temperature based CPR adjustments for 8953/450 There are no significant savings using temperature (tsens) based adjustments to CPR. Disable it for SDM450/MSM8953. Change-Id: I7a01cc4996f68f78aa13eacf36648331a701882b Signed-off-by: Anirudh Ghayal --- .../boot/dts/qcom/msm8953-regulator.dtsi | 56 ------------------- 1 file changed, 56 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi index 5a4f024226cc..31e882fd8ae2 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi @@ -388,9 +388,6 @@ "APCS_ALIAS0_APM_CTLER_STATUS", "APCS0_CPR_CORE_ADJ_MODE_REG"; - qcom,cpr-temp-point-map = <250 650 850>; - qcom,cpr-initial-temp-band = <0>; - /* Turbo (corner 6) ceiling voltage */ qcom,cpr-aging-ref-voltage = <990000>; @@ -795,59 +792,6 @@ qcom,allow-quotient-interpolation; qcom,cpr-scaled-open-loop-voltage-as-ceiling; - qcom,corner-allow-temp-adjustment = - /* Speed bin 0; CPR rev 0..7 */ - <0 0 0 0 0 0 0 0 0>, - <0 0 0 0 0 0 0 0 0>, - <0 0 0 0 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>, - - /* Speed bin 2; CPR rev 0..7 */ - <0 0 0 0 0 0 0>, - <0 0 0 0 0 0 0>, - <0 0 0 0 0 0 0>, - <1 1 1 1 0 0 0>, - <1 1 1 1 0 0 0>, - <1 1 1 1 0 0 0>, - <1 1 1 1 0 0 0>, - <1 1 1 1 0 0 0>, - - /* Speed bin 6; CPR rev 0..7 */ - <0 0 0 0 0 0 0>, - <0 0 0 0 0 0 0>, - <0 0 0 0 0 0 0>, - <1 1 1 1 0 0 0>, - <1 1 1 1 0 0 0>, - <1 1 1 1 0 0 0>, - <1 1 1 1 0 0 0>, - <1 1 1 1 0 0 0>, - - /* Speed bin 7; CPR rev 0..7 */ - <0 0 0 0 0 0 0 0 0>, - <0 0 0 0 0 0 0 0 0>, - <0 0 0 0 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>; - - qcom,cpr-corner1-temp-core-voltage-adjustment = - <(0) (-5000) (-15000) (-20000)>; - - qcom,cpr-corner2-temp-core-voltage-adjustment = - <(0) (-5000) (-15000) (-15000)>; - - qcom,cpr-corner3-temp-core-voltage-adjustment = - <(0) (-5000) (-15000) (0)>; - - qcom,cpr-corner4-temp-core-voltage-adjustment = - <(0) (-5000) (-15000) (0)>; - qcom,cpr-aging-max-voltage-adjustment = <15000>; qcom,cpr-aging-ref-corner = <6>; /* Turbo */ qcom,cpr-aging-ro-scaling-factor = <2800>; -- GitLab From d4813d80905e4cafbf74fd4d7c2f10f2d69bfcc9 Mon Sep 17 00:00:00 2001 From: Devi Sandeep Endluri V V Date: Sat, 28 Jul 2018 16:53:54 +0530 Subject: [PATCH 530/604] defconfig: msm8953: Enable GCM crypto configs Enable GCM crypto support to keep it up-to-date with android recommended configs and pass testKernelConfigs CTS test. CRs-Fixed: 2263373 Change-Id: I2ea8f6dbc4ff03dd7db60649fa90de06eae606d6 Signed-off-by: Devi Sandeep Endluri V V --- arch/arm64/configs/msm8953-perf_defconfig | 1 + arch/arm64/configs/msm8953_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig index eeb1d74c3398..3f4c163dbc4c 100644 --- a/arch/arm64/configs/msm8953-perf_defconfig +++ b/arch/arm64/configs/msm8953-perf_defconfig @@ -644,6 +644,7 @@ CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig index d0783cd63972..129b36b61b40 100644 --- a/arch/arm64/configs/msm8953_defconfig +++ b/arch/arm64/configs/msm8953_defconfig @@ -711,6 +711,7 @@ CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y -- GitLab From d7788b558beb932b71f61d52819cfc320144fb1f Mon Sep 17 00:00:00 2001 From: Devi Sandeep Endluri V V Date: Sat, 28 Jul 2018 16:50:07 +0530 Subject: [PATCH 531/604] defconfig: msm8953: Enable GCM crypto configs Enable GCM crypto support to keep it up-to-date with android recommended configs and pass testKernelConfigs CTS test. CRs-Fixed: 2263373 Change-Id: I4bfbbe8cef18d5d8383cf93d7ccc69784712cec5 Signed-off-by: Devi Sandeep Endluri V V --- arch/arm/configs/msm8953-perf_defconfig | 1 + arch/arm/configs/msm8953_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig index 3d716a6b191f..fe4238036a08 100644 --- a/arch/arm/configs/msm8953-perf_defconfig +++ b/arch/arm/configs/msm8953-perf_defconfig @@ -646,6 +646,7 @@ CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig index 34f91220f604..f108065d4d46 100644 --- a/arch/arm/configs/msm8953_defconfig +++ b/arch/arm/configs/msm8953_defconfig @@ -710,6 +710,7 @@ CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y -- GitLab From c415534bc5c7c24d49323364189f48ad19aa428b Mon Sep 17 00:00:00 2001 From: Devi Sandeep Endluri V V Date: Sat, 28 Jul 2018 16:57:58 +0530 Subject: [PATCH 532/604] defconfig: msm8937: Enable GCM crypto configs Enable GCM crypto support to keep it up-to-date with android recommended configs and pass testKernelConfigs CTS test. CRs-Fixed: 2263373 Change-Id: I4b63c8bf3175049284d8fc771e89b667e8a40fd5 Signed-off-by: Devi Sandeep Endluri V V --- arch/arm64/configs/msm8937-perf_defconfig | 1 + arch/arm64/configs/msm8937_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig index bf35544ee133..1b3882203348 100644 --- a/arch/arm64/configs/msm8937-perf_defconfig +++ b/arch/arm64/configs/msm8937-perf_defconfig @@ -631,6 +631,7 @@ CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig index ba390c4d34e6..fde5d2146c56 100644 --- a/arch/arm64/configs/msm8937_defconfig +++ b/arch/arm64/configs/msm8937_defconfig @@ -697,6 +697,7 @@ CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y -- GitLab From 40b5d1608d92685c9271d5f8787ffe1a26ea6da9 Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Wed, 25 Jul 2018 15:06:11 +0530 Subject: [PATCH 533/604] diag: Modify md_info and diag client map synchronization Extend the scope of protection to md_info till queueing the write to sdcard. Patch adds protection to diag client map synchronizing access by various clients. CRs-Fixed: 2282558 Change-Id: If076af2d09180a282a9077b4ebcda0184e9f67b5 Signed-off-by: Manoj Prabhu B --- drivers/char/diag/diag_memorydevice.c | 2 ++ drivers/char/diag/diagfwd_peripheral.c | 20 ++++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c index c00fbfc0324b..992faf7c6f8e 100644 --- a/drivers/char/diag/diag_memorydevice.c +++ b/drivers/char/diag/diag_memorydevice.c @@ -202,6 +202,7 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) } found = 0; + mutex_lock(&driver->diagchar_mutex); for (i = 0; i < driver->num_clients && !found; i++) { if ((driver->client_map[i].pid != pid) || (driver->client_map[i].pid == 0)) @@ -215,6 +216,7 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) pr_debug("diag: wake up logging process\n"); wake_up_interruptible(&driver->wait_q); } + mutex_unlock(&driver->diagchar_mutex); if (!found) return -EINVAL; diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index 2022e7be73b5..23524bb094c2 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -385,6 +385,8 @@ static void diagfwd_data_process_done(struct diagfwd_info *fwd_info, goto end; } } + mutex_unlock(&fwd_info->data_mutex); + mutex_unlock(&driver->hdlc_disable_mutex); if (write_len > 0) { err = diag_mux_write(DIAG_LOCAL_PROC, write_buf, write_len, @@ -392,18 +394,18 @@ static void diagfwd_data_process_done(struct diagfwd_info *fwd_info, if (err) { pr_err_ratelimited("diag: In %s, unable to write to mux error: %d\n", __func__, err); - goto end; + goto end_write; } } - mutex_unlock(&fwd_info->data_mutex); - mutex_unlock(&driver->hdlc_disable_mutex); + diagfwd_queue_read(fwd_info); return; end: - diag_ws_release(); mutex_unlock(&fwd_info->data_mutex); mutex_unlock(&driver->hdlc_disable_mutex); +end_write: + diag_ws_release(); if (buf) { DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "Marking buffer as free p: %d, t: %d, buf_num: %d\n", @@ -690,24 +692,26 @@ static void diagfwd_data_read_done(struct diagfwd_info *fwd_info, } } + mutex_unlock(&fwd_info->data_mutex); + mutex_unlock(&driver->hdlc_disable_mutex); + if (write_len > 0) { err = diag_mux_write(DIAG_LOCAL_PROC, write_buf, write_len, temp_buf->ctxt); if (err) { pr_err_ratelimited("diag: In %s, unable to write to mux error: %d\n", __func__, err); - goto end; + goto end_write; } } - mutex_unlock(&fwd_info->data_mutex); - mutex_unlock(&driver->hdlc_disable_mutex); diagfwd_queue_read(fwd_info); return; end: - diag_ws_release(); mutex_unlock(&fwd_info->data_mutex); mutex_unlock(&driver->hdlc_disable_mutex); +end_write: + diag_ws_release(); if (temp_buf) { DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "Marking buffer as free p: %d, t: %d, buf_num: %d\n", -- GitLab From 487cc4d7765f138f4801624d468e2ac6da477d72 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Mon, 30 Jul 2018 08:59:10 +0800 Subject: [PATCH 534/604] defconfig: msm: Enable QPNP_PBS and SPMI_SDAM drivers for PMI632 devices Enable QPNP_PBS and NVMEM_SPMI_SDAM drivers for pwm-qti-lpg driver to be able to use the SDAM module for pattern generation. Change-Id: If876454687e42452d361fe3dd4a1f2a4575da084 Signed-off-by: Fenglin Wu --- arch/arm64/configs/msm8937-perf_defconfig | 3 +++ arch/arm64/configs/msm8937_defconfig | 3 +++ arch/arm64/configs/msm8953-perf_defconfig | 3 +++ arch/arm64/configs/msm8953_defconfig | 3 +++ 4 files changed, 12 insertions(+) diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig index bf35544ee133..e0fa9be97d30 100644 --- a/arch/arm64/configs/msm8937-perf_defconfig +++ b/arch/arm64/configs/msm8937-perf_defconfig @@ -543,6 +543,7 @@ CONFIG_MSM_L2_SPM=y CONFIG_QCOM_SCM=y CONFIG_MSM_BOOT_STATS=y CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QPNP_PBS=y CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_MSM_RPM_SMD=y CONFIG_QCOM_BUS_SCALING=y @@ -587,6 +588,8 @@ CONFIG_ARM_GIC_V3_ACL=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_NVMEM=y +CONFIG_NVMEM_SPMI_SDAM=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig index ba390c4d34e6..f79870258bcc 100644 --- a/arch/arm64/configs/msm8937_defconfig +++ b/arch/arm64/configs/msm8937_defconfig @@ -560,6 +560,7 @@ CONFIG_QCOM_SCM=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QPNP_PBS=y CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_MSM_DEBUG_LAR_UNLOCK=y CONFIG_MSM_RPM_SMD=y @@ -606,6 +607,8 @@ CONFIG_ARM_GIC_V3_ACL=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_NVMEM=y +CONFIG_NVMEM_SPMI_SDAM=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig index eeb1d74c3398..97d69375fe83 100644 --- a/arch/arm64/configs/msm8953-perf_defconfig +++ b/arch/arm64/configs/msm8953-perf_defconfig @@ -556,6 +556,7 @@ CONFIG_MSM_L2_SPM=y CONFIG_QCOM_SCM=y CONFIG_MSM_BOOT_STATS=y CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QPNP_PBS=y CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_MSM_RPM_SMD=y CONFIG_QCOM_BUS_SCALING=y @@ -600,6 +601,8 @@ CONFIG_ARM_GIC_V3_ACL=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_NVMEM=y +CONFIG_NVMEM_SPMI_SDAM=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig index d0783cd63972..04a142b3abbb 100644 --- a/arch/arm64/configs/msm8953_defconfig +++ b/arch/arm64/configs/msm8953_defconfig @@ -572,6 +572,7 @@ CONFIG_QCOM_SCM=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QPNP_PBS=y CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_MSM_DEBUG_LAR_UNLOCK=y CONFIG_MSM_RPM_SMD=y @@ -619,6 +620,8 @@ CONFIG_ARM_GIC_V3_ACL=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_NVMEM=y +CONFIG_NVMEM_SPMI_SDAM=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y -- GitLab From 84d278421cbc30136c9a37a3c85459059a18230f Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Wed, 25 Jul 2018 15:00:19 +0530 Subject: [PATCH 535/604] diag: Protect md_info structure while reallocation The possibility of md_info structure being accessed simultaneously by two threads is prevented by synchronizing while buffer reallocation for hdlc encoding. Extend the scope of protection to md_info till queueing the write to sdcard. CRs-Fixed: 2279473 Change-Id: I75ddb102adfc6c79f35ed69914c9140cb82894c9 Signed-off-by: Manoj Prabhu B --- drivers/char/diag/diag_memorydevice.c | 10 +++++++--- drivers/char/diag/diagfwd_peripheral.c | 16 +++++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c index c00fbfc0324b..4c77f2f0bf4c 100644 --- a/drivers/char/diag/diag_memorydevice.c +++ b/drivers/char/diag/diag_memorydevice.c @@ -160,11 +160,12 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) return -EIO; } pid = session_info->pid; - mutex_unlock(&driver->md_session_lock); ch = &diag_md[id]; - if (!ch || !ch->md_info_inited) + if (!ch || !ch->md_info_inited) { + mutex_unlock(&driver->md_session_lock); return -EINVAL; + } spin_lock_irqsave(&ch->lock, flags); for (i = 0; i < ch->num_tbl_entries && !found; i++) { @@ -180,8 +181,10 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) } spin_unlock_irqrestore(&ch->lock, flags); - if (found) + if (found) { + mutex_unlock(&driver->md_session_lock); return -ENOMEM; + } spin_lock_irqsave(&ch->lock, flags); for (i = 0; i < ch->num_tbl_entries && !found; i++) { @@ -194,6 +197,7 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) } } spin_unlock_irqrestore(&ch->lock, flags); + mutex_unlock(&driver->md_session_lock); if (!found) { pr_err_ratelimited("diag: Unable to find an empty space in table, please reduce logging rate, proc: %d\n", diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index 2022e7be73b5..5fc862561549 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -191,6 +191,7 @@ static int check_bufsize_for_encoding(struct diagfwd_buf_t *buf, uint32_t len) { int i, ctx = 0; uint32_t max_size = 0; + unsigned long flags; unsigned char *temp_buf = NULL; struct diag_md_info *ch = NULL; @@ -205,12 +206,17 @@ static int check_bufsize_for_encoding(struct diagfwd_buf_t *buf, uint32_t len) max_size = MAX_PERIPHERAL_HDLC_BUF_SZ; } + mutex_lock(&driver->md_session_lock); if (buf->len < max_size) { if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE || driver->logging_mode == DIAG_MULTI_MODE) { ch = &diag_md[DIAG_LOCAL_PROC]; - for (i = 0; ch != NULL && - i < ch->num_tbl_entries; i++) { + if (!ch || !ch->md_info_inited) { + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } + spin_lock_irqsave(&ch->lock, flags); + for (i = 0; i < ch->num_tbl_entries; i++) { if (ch->tbl[i].buf == buf->data) { ctx = ch->tbl[i].ctx; ch->tbl[i].buf = NULL; @@ -223,18 +229,22 @@ static int check_bufsize_for_encoding(struct diagfwd_buf_t *buf, uint32_t len) break; } } + spin_unlock_irqrestore(&ch->lock, flags); } temp_buf = krealloc(buf->data, max_size + APF_DIAG_PADDING, GFP_KERNEL); - if (!temp_buf) + if (!temp_buf) { + mutex_unlock(&driver->md_session_lock); return -ENOMEM; + } DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "Reallocated data buffer: %pK with size: %d\n", temp_buf, max_size); buf->data = temp_buf; buf->len = max_size; } + mutex_unlock(&driver->md_session_lock); } return buf->len; -- GitLab From 9eb50aa74560337c9d430baed4aa12e155976248 Mon Sep 17 00:00:00 2001 From: Rashi Bindra Date: Thu, 19 Jul 2018 12:40:52 +0530 Subject: [PATCH 536/604] msm: mdss: Change function from disbale_irq_nosync to disbale_irq Potential deadlock can happen while we disable irq and at the same time an irq is triggered to request for the same resource. Thus, it will pre-empt the spin-lock. Hence, change the function call to disbale_irq to prevent local interrupts. Change-Id: I7b80810b13660df8801533d418c78f2db75dd5b6 Signed-off-by: Rashi Bindra --- drivers/video/fbdev/msm/mdss_dsi_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index 751a463edb60..a470656ea182 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -2218,7 +2218,7 @@ static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl, /* clear CMD DMA and BTA_DONE isr only */ reg_val |= (DSI_INTR_CMD_DMA_DONE | DSI_INTR_BTA_DONE); MIPI_OUTP(ctrl->ctrl_base + 0x0110, reg_val); - mdss_dsi_disable_irq_nosync(ctrl, DSI_CMD_TERM); + mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM); complete(&ctrl->dma_comp); pr_warn("%s: dma tx done but irq not triggered\n", -- GitLab From aaadfc02fe65f30a530b7416bb3ce34742633ef0 Mon Sep 17 00:00:00 2001 From: Venkataraman Nerellapalli Date: Mon, 30 Jul 2018 14:04:48 +0530 Subject: [PATCH 537/604] ARM: dts: msm: move Goodix node to apq8053-lite-dragon-v2.2.dts Goodix touch node need not to be in parent file as it is applicable only for apq8053-lite-dragon-v2.2.dts. Change-Id: I833bb5f44399e4b3226d6d14c48333428d6368f4 Signed-off-by: Venkataraman Nerellapalli --- .../dts/qcom/apq8053-lite-dragon-v2.2.dts | 71 +++++++++++++++++- .../boot/dts/qcom/apq8053-lite-dragon.dtsi | 73 ------------------- 2 files changed, 70 insertions(+), 74 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dts index 599f3ef97af3..8b5dd2b00cfb 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dts +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dts @@ -30,7 +30,76 @@ status = "okay"; /delete-node/ himax_ts@48; gt9xx-i2c@14 { + compatible = "goodix,gt9xx"; status = "okay"; + reg = <0x14>; + vdd_ana-supply = <&pm8953_l10>; + vcc_i2c-supply = <&pm8953_l6>; + interrupt-parent = <&tlmm>; + interrupts = <65 0x2008>; + pinctrl-names = "gdix_ts_int_default", "gdix_ts_int_output_low", + "gdix_ts_int_output_high", "gdix_ts_int_input", + "gdix_ts_rst_default", "gdix_ts_rst_output_low", + "gdix_ts_rst_output_high", "gdix_ts_rst_input"; + pinctrl-0 = <&ts_int_default>; + pinctrl-1 = <&ts_int_output_low>; + pinctrl-2 = <&ts_int_output_high>; + pinctrl-3 = <&ts_int_input>; + pinctrl-4 = <&ts_rst_default>; + pinctrl-5 = <&ts_rst_output_low>; + pinctrl-6 = <&ts_rst_output_high>; + pinctrl-7 = <&ts_rst_input>; + + reset-gpios = <&tlmm 64 0x00>; + irq-gpios = <&tlmm 65 0x2008>; + irq-flags = <2>; + + touchscreen-max-id = <11>; + touchscreen-size-x = <1200>; + touchscreen-size-y = <1920>; + touchscreen-max-w = <1024>; + touchscreen-max-p = <1024>; + + goodix,type-a-report = <0>; + goodix,driver-send-cfg = <1>; + goodix,wakeup-with-reset = <0>; + goodix,resume-in-workqueue = <0>; + goodix,int-sync = <1>; + goodix,swap-x2y = <0>; + goodix,esd-protect = <1>; + goodix,pen-suppress-finger = <0>; + goodix,auto-update = <1>; + goodix,auto-update-cfg = <0>; + goodix,power-off-sleep = <0>; + + goodix,cfg-group0 = [ + 5A B0 04 80 07 0A 35 10 22 08 32 0D 50 3C 0A 04 + 01 01 00 B4 11 11 44 15 19 1B 14 95 35 FF 3A 3C + 39 13 00 00 00 98 03 1C 00 00 00 00 03 00 00 00 + 00 80 0A 37 46 40 E5 52 23 28 00 04 81 38 00 7F + 3B 00 7D 3E 00 7C 41 00 7A 44 0C 7A 00 50 33 50 + 0B 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 55 00 01 00 00 02 00 00 00 + 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 0F 0E + 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00 2A 29 + 28 27 26 25 24 23 22 21 20 1F 1E 1D 1C 1B 19 18 + 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 + 07 06 05 04 03 02 01 00 08 01 + ]; + + goodix,cfg-group2 = [ + 5B B0 04 80 07 0A 35 10 22 08 32 0D 50 32 0A 04 + 01 01 00 B4 11 11 44 2B 31 36 28 95 35 FF 3E 40 + 39 13 00 00 00 DA 03 1C 00 00 00 00 03 00 00 00 + 00 80 0A 32 42 40 E5 52 23 28 00 04 7D 33 00 7D + 36 00 7E 39 00 7F 3C 00 80 40 0C 80 00 50 33 50 + 0B 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 55 00 01 00 00 02 00 00 00 + 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 0F 0E + 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00 2A 29 + 28 27 26 25 24 23 22 21 20 1F 1E 1D 1C 1B 19 18 + 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 + 07 06 05 04 03 02 01 00 81 01 + ]; }; }; - diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi index f7a2026f7588..90b1d4fad300 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi @@ -223,79 +223,6 @@ himax,irq-gpio = <&tlmm 65 0x2008>; report_type = <1>; }; - - gt9xx-i2c@14 { - compatible = "goodix,gt9xx"; - reg = <0x14>; - vdd_ana-supply = <&pm8953_l10>; - vcc_i2c-supply = <&pm8953_l6>; - interrupt-parent = <&tlmm>; - interrupts = <65 0x2008>; - pinctrl-names = "gdix_ts_int_default", "gdix_ts_int_output_low", - "gdix_ts_int_output_high", "gdix_ts_int_input", - "gdix_ts_rst_default", "gdix_ts_rst_output_low", - "gdix_ts_rst_output_high", "gdix_ts_rst_input"; - pinctrl-0 = <&ts_int_default>; - pinctrl-1 = <&ts_int_output_low>; - pinctrl-2 = <&ts_int_output_high>; - pinctrl-3 = <&ts_int_input>; - pinctrl-4 = <&ts_rst_default>; - pinctrl-5 = <&ts_rst_output_low>; - pinctrl-6 = <&ts_rst_output_high>; - pinctrl-7 = <&ts_rst_input>; - - reset-gpios = <&tlmm 64 0x00>; - irq-gpios = <&tlmm 65 0x2008>; - irq-flags = <2>; - - touchscreen-max-id = <11>; - touchscreen-size-x = <1200>; - touchscreen-size-y = <1920>; - touchscreen-max-w = <1024>; - touchscreen-max-p = <1024>; - - goodix,type-a-report = <0>; - goodix,driver-send-cfg = <1>; - goodix,wakeup-with-reset = <0>; - goodix,resume-in-workqueue = <0>; - goodix,int-sync = <1>; - goodix,swap-x2y = <0>; - goodix,esd-protect = <1>; - goodix,pen-suppress-finger = <0>; - goodix,auto-update = <1>; - goodix,auto-update-cfg = <0>; - goodix,power-off-sleep = <0>; - - goodix,cfg-group0 = [ - 5A B0 04 80 07 0A 35 10 22 08 32 0D 50 3C 0A 04 - 01 01 00 B4 11 11 44 15 19 1B 14 95 35 FF 3A 3C - 39 13 00 00 00 98 03 1C 00 00 00 00 03 00 00 00 - 00 80 0A 37 46 40 E5 52 23 28 00 04 81 38 00 7F - 3B 00 7D 3E 00 7C 41 00 7A 44 0C 7A 00 50 33 50 - 0B 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 55 00 01 00 00 02 00 00 00 - 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 0F 0E - 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00 2A 29 - 28 27 26 25 24 23 22 21 20 1F 1E 1D 1C 1B 19 18 - 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 - 07 06 05 04 03 02 01 00 08 01 - ]; - - goodix,cfg-group2 = [ - 5B B0 04 80 07 0A 35 10 22 08 32 0D 50 32 0A 04 - 01 01 00 B4 11 11 44 2B 31 36 28 95 35 FF 3E 40 - 39 13 00 00 00 DA 03 1C 00 00 00 00 03 00 00 00 - 00 80 0A 32 42 40 E5 52 23 28 00 04 7D 33 00 7D - 36 00 7E 39 00 7F 3C 00 80 40 0C 80 00 50 33 50 - 0B 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 55 00 01 00 00 02 00 00 00 - 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 0F 0E - 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00 2A 29 - 28 27 26 25 24 23 22 21 20 1F 1E 1D 1C 1B 19 18 - 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 - 07 06 05 04 03 02 01 00 81 01 - ]; - }; }; &soc { -- GitLab From a06d00c4ed86e391661e84879ebc5f59fcbc1bcc Mon Sep 17 00:00:00 2001 From: Vara Reddy Date: Tue, 27 Mar 2018 07:18:53 -0700 Subject: [PATCH 538/604] drm/msm/dsi-staging: free pps command transmit buffer Change frees tx_buf after sending the pps command. Without this memory was leaking for everytime pps command was sent. CRs-Fixed: 2211837 Change-Id: I081f958075e7fdf863ae5647fcbd142e91f6e59b Signed-off-by: Vara Reddy --- drivers/gpu/drm/msm/dsi-staging/dsi_panel.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index 1880ad119feb..bf511e3ece77 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -1566,7 +1566,7 @@ static int dsi_panel_create_cmd_packets(const char *data, return rc; } -void dsi_panel_destroy_cmd_packets(struct dsi_panel_cmd_set *set) +static void dsi_panel_destroy_cmd_packets(struct dsi_panel_cmd_set *set) { u32 i = 0; struct dsi_cmd_desc *cmd; @@ -1575,7 +1575,10 @@ void dsi_panel_destroy_cmd_packets(struct dsi_panel_cmd_set *set) cmd = &set->cmds[i]; kfree(cmd->msg.tx_buf); } +} +static void dsi_panel_dealloc_cmd_packets(struct dsi_panel_cmd_set *set) +{ kfree(set->cmds); } @@ -3160,8 +3163,10 @@ void dsi_panel_put_mode(struct dsi_display_mode *mode) if (!mode->priv_info) return; - for (i = 0; i < DSI_CMD_SET_MAX; i++) + for (i = 0; i < DSI_CMD_SET_MAX; i++) { dsi_panel_destroy_cmd_packets(&mode->priv_info->cmd_sets[i]); + dsi_panel_dealloc_cmd_packets(&mode->priv_info->cmd_sets[i]); + } kfree(mode->priv_info); } @@ -3363,9 +3368,9 @@ int dsi_panel_update_pps(struct dsi_panel *panel) if (rc) { pr_err("[%s] failed to send DSI_CMD_SET_PPS cmds, rc=%d\n", panel->name, rc); - goto error; } + dsi_panel_destroy_cmd_packets(set); error: mutex_unlock(&panel->panel_lock); return rc; -- GitLab From 632aef1e0504f2c5a95fa8740c8bc489ab5187ee Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Tue, 15 May 2018 10:14:00 +0530 Subject: [PATCH 539/604] mmc: block: Don't unhalt if switch to CQ mode fails There's no reason to unhalt if switching to CQ mode fails. Since card is not in CQ mode, let the controller be halted. The caller will handle this error. CRs-fixed: 2241401 Change-Id: I307753ad66d291168a55f760565cc141d7c83c31 Signed-off-by: Asutosh Das --- drivers/mmc/card/block.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index f78b659fbd4f..a1488fe62e98 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -3994,6 +3994,7 @@ static inline int mmc_blk_cmdq_part_switch(struct mmc_card *card, pr_err("%s: %s: mmc_blk_cmdq_switch failed: %d\n", mmc_hostname(host), __func__, err); ret = err; + goto out; } cmdq_unhalt: err = mmc_cmdq_halt(host, false); -- GitLab From 5783b8132fd18411d0df79975537e5965f9f366b Mon Sep 17 00:00:00 2001 From: Wenjun Zhang Date: Wed, 4 Jul 2018 07:24:47 -0400 Subject: [PATCH 540/604] ARM: dts: msm: decrease porch to fix screen flicker on sdm429 Decrease porch value to fix DUT screen flicker during long time stability test on hx8399c hd+ panel. Change-Id: I93f88514cfea16d74db8f071f51799016a4e92cb Signed-off-by: Wenjun Zhang --- arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-hd-plus-video.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-hd-plus-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-hd-plus-video.dtsi index 89c51783459d..7a711543a6ab 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-hd-plus-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-hd-plus-video.dtsi @@ -25,7 +25,7 @@ qcom,mdss-dsi-h-pulse-width = <16>; qcom,mdss-dsi-h-sync-skew = <0>; qcom,mdss-dsi-v-back-porch = <40>; - qcom,mdss-dsi-v-front-porch = <60>; + qcom,mdss-dsi-v-front-porch = <36>; qcom,mdss-dsi-v-pulse-width = <4>; qcom,mdss-dsi-h-left-border = <0>; qcom,mdss-dsi-h-right-border = <0>; -- GitLab From 39e8d0baf906d2cab892b679a144813d0f18a0c0 Mon Sep 17 00:00:00 2001 From: Sahitya Tummala Date: Fri, 21 Apr 2017 21:56:19 +0530 Subject: [PATCH 541/604] fs/dcache: Fix indefinite wait in d_invalidate() In the path of task exit, the proc dentries corresponding to this task will be killed by moving it to a shrink list. If those dentries are already claimed by another task for shrinking, the exiting task waits in a tight loop until those dentries are killed. This can potentially result in a deadlock if those dentries are corresponding to an RT task but the task which is shrinking those dentries is a lower priority task. Fix this by not doing tight loop, if our dentries are claimed by other task. Change-Id: If6848521469db7dea2bbba0dbaf8597094716267 Signed-off-by: Sahitya Tummala --- fs/dcache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/dcache.c b/fs/dcache.c index 5ff9b417f836..3c8c1a1b7d55 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1412,7 +1412,7 @@ static enum d_walk_ret select_collect(void *_data, struct dentry *dentry) goto out; if (dentry->d_flags & DCACHE_SHRINK_LIST) { - data->found++; + goto out; } else { if (dentry->d_flags & DCACHE_LRU_LIST) d_lru_del(dentry); -- GitLab From 1102e8092628dc648a6b4e72564669ea36991466 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Mon, 25 Jun 2018 18:58:20 +0530 Subject: [PATCH 542/604] 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_v2/ipa_debugfs.c | 1 + drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c | 1 + include/uapi/linux/msm_ipa.h | 8 +++++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c index 7d315a4b0c0c..0224f98f2812 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c @@ -91,6 +91,7 @@ const char *ipa_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 *ipa_hdr_l2_type_name[] = { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index 3728a4376087..0925e8c885b9 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 be4cb02f7e34..34ecd82ec7f0 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -520,7 +520,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 698ed7e15445dfa058173c4d35d29b93e0b97337 Mon Sep 17 00:00:00 2001 From: Hardik Arya Date: Mon, 30 Jul 2018 17:18:05 +0530 Subject: [PATCH 543/604] defconfig: qcs605: Enable Diag for qcs605 32 bit Enable diag for qcs605 in config file for 32 bit build. Change-Id: I7c4fb904b22b90599b34c0c15fdb2fd7e881f803 Signed-off-by: Hardik Arya --- arch/arm/configs/sdm670_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/sdm670_defconfig b/arch/arm/configs/sdm670_defconfig index 082a53a7c4ec..1831c49c6e52 100644 --- a/arch/arm/configs/sdm670_defconfig +++ b/arch/arm/configs/sdm670_defconfig @@ -300,6 +300,7 @@ CONFIG_INPUT_UINPUT=y # CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_MSM_GENI=y CONFIG_SERIAL_MSM_GENI_CONSOLE=y +CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_MSM_ADSPRPC=y -- GitLab From e54678dc2943ef59d109f049927298a2669bbd32 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Mon, 30 Jul 2018 15:18:17 +0530 Subject: [PATCH 544/604] msm: kgsl: Fix the missing IBs from the snapshot We missed updating index for internal IBs like setstate or power-on fixup. The index value was never updated after that, so all the IBs after that index were never parsed, and are missing from the snapshot. Change-Id: I61db75f33630db322fe5ee1adce9f120987d32ee Signed-off-by: Sunil Khatri --- drivers/gpu/msm/adreno_snapshot.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c index b5999e6fb6a2..22939199c28c 100644 --- a/drivers/gpu/msm/adreno_snapshot.c +++ b/drivers/gpu/msm/adreno_snapshot.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* 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 @@ -400,6 +400,8 @@ static void snapshot_rb_ibs(struct kgsl_device *device, ibsize = rbptr[index + 3]; } + index = (index + 1) % KGSL_RB_DWORDS; + /* Don't parse known global IBs */ if (iommu_is_setstate_addr(device, ibaddr, ibsize)) continue; @@ -410,9 +412,8 @@ static void snapshot_rb_ibs(struct kgsl_device *device, parse_ib(device, snapshot, snapshot->process, ibaddr, ibsize); - } - - index = (index + 1) % KGSL_RB_DWORDS; + } else + index = (index + 1) % KGSL_RB_DWORDS; } } -- GitLab From 4a94d5bb77edaadad0b2bec1993c747df05a5d8c Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Wed, 25 Jul 2018 16:18:45 -0700 Subject: [PATCH 545/604] drm/msm/sde: fix the sui in-progress check Check the intermediate and changed smmu state, while determining if secure display session is in progress to give the correct state information. Change-Id: I662f50c7f74c5f0f8b5f61aee51e4b115f14b350 Signed-off-by: Veera Sundaram Sankaran --- drivers/gpu/drm/msm/sde/sde_kms.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h index 450695dd4ce3..2344d897b3ec 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.h +++ b/drivers/gpu/drm/msm/sde/sde_kms.h @@ -374,7 +374,8 @@ static inline bool sde_kms_is_secure_session_inprogress(struct sde_kms *sde_kms) return false; mutex_lock(&sde_kms->secure_transition_lock); - if (sde_kms->smmu_state.state == DETACHED) + if ((sde_kms->smmu_state.state == DETACHED) + || (sde_kms->smmu_state.state == DETACH_ALL_REQ)) ret = true; mutex_unlock(&sde_kms->secure_transition_lock); -- GitLab From a2c20317f61242b61dd8a7dc8e3eac9c6b6f4aa1 Mon Sep 17 00:00:00 2001 From: zhaochen Date: Thu, 26 Jul 2018 14:22:52 +0800 Subject: [PATCH 546/604] icm20602: fix NULL point in suspend Icm20602 has problem when it excutes suspend function, change the value of st in static and resolve this problem. Change-Id: I2374f6cefb14ebde2aaa96418852bda58d49b32a Signed-off-by: zhaochen --- .../iio/imu/inv_icm20602/inv_icm20602_core.c | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c index bf8e9681cae1..15d52dc88213 100644 --- a/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c @@ -33,6 +33,7 @@ static struct regulator *reg_ldo; +static struct inv_icm20602_state *st; /* Attribute of icm20602 device init show */ static ssize_t inv_icm20602_init_show(struct device *dev, @@ -382,10 +383,13 @@ static const struct iio_info icm20602_info = { .validate_trigger = inv_icm20602_validate_trigger, }; -static int icm20602_ldo_work(struct inv_icm20602_state *st, bool enable) +static int icm20602_ldo_work(bool enable) { int ret = 0; + if (reg_ldo == NULL) + return MPU_FAIL; + if (enable) { ret = regulator_set_voltage(reg_ldo, ICM20602_LDO_VTG_MIN_UV, ICM20602_LDO_VTG_MAX_UV); @@ -465,7 +469,6 @@ static int of_populate_icm20602_dt(struct inv_icm20602_state *st) static int inv_icm20602_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct inv_icm20602_state *st; struct iio_dev *indio_dev; int result = MPU_SUCCESS; @@ -507,7 +510,7 @@ static int inv_icm20602_probe(struct i2c_client *client, goto out_remove_trigger; } icm20602_init_regulators(st); - icm20602_ldo_work(st, true); + icm20602_ldo_work(true); result = inv_icm20602_probe_trigger(indio_dev); if (result) { @@ -551,20 +554,19 @@ static int inv_icm20602_remove(struct i2c_client *client) static int inv_icm20602_suspend(struct device *dev) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct inv_icm20602_state *st = iio_priv(indio_dev); + icm20602_ldo_work(false); - icm20602_stop_fifo(st); - icm20602_ldo_work(st, false); return 0; } static int inv_icm20602_resume(struct device *dev) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct inv_icm20602_state *st = iio_priv(indio_dev); + int ret; + + ret = icm20602_ldo_work(true); + if (ret == MPU_FAIL) + return 0; - icm20602_ldo_work(st, true); icm20602_detect(st); icm20602_init_device(st); icm20602_start_fifo(st); -- GitLab From 4fe147ae6c140e310045b9b5fa47817ef5e78156 Mon Sep 17 00:00:00 2001 From: gaolez Date: Tue, 31 Jul 2018 13:45:42 +0800 Subject: [PATCH 547/604] msm: wlan: Update regulatory database Update ch36~ch48 txpower in countrycode LC as 23dBm. Change-Id: Ic00f5193d37732105d135a69b74138c93c9a9c57 CRs-Fixed: 2287339 Signed-off-by: Gaole Zhang --- net/wireless/db.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/db.txt b/net/wireless/db.txt index d82f8b4c814c..eaa185f44c9f 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -653,7 +653,7 @@ country LB: DFS-FCC country LC: DFS-FCC (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (30), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS (5735 - 5815 @ 80), (30) -- GitLab From 3ce711e00ad6b4e34d857552ff095573cabec1d0 Mon Sep 17 00:00:00 2001 From: gaolez Date: Tue, 31 Jul 2018 14:04:45 +0800 Subject: [PATCH 548/604] msm: wlan: Update regulatory database Enable DFS flag for TT. Change-Id: I291dd2927ff0c92b243ee9c009b1549fb203165b CRs-Fixed: 2287335 Signed-off-by: Gaole Zhang --- net/wireless/db.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/wireless/db.txt b/net/wireless/db.txt index d82f8b4c814c..62a9d08f7c65 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -1138,10 +1138,11 @@ country TR: DFS-ETSI (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) -country TT: +country TT: DFS-FCC (2402 - 2482 @ 40), (20) - (5170 - 5330 @ 160), (24) - (5490 - 5730 @ 160), (24) + (5170 - 5250 @ 80), (24) + (5250 - 5330 @ 80), (24), DFS + (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) -- GitLab From 050116a0143578642b0c765362a9ada034167995 Mon Sep 17 00:00:00 2001 From: Petar Sivenov Date: Tue, 5 Jun 2018 12:28:53 +0300 Subject: [PATCH 549/604] ARM: dts: qca402x: adds dts entry for qca402 Add device entry for qca402x Host Target communication device for high level data transfer via QCA402x Quartz Wifi SoC. Change-Id: I9f62c3fdff7907287b6fa74b8934375f58c65fd9 Signed-off-by: Petar Sivenov --- .../devicetree/bindings/media/qca402x.txt | 14 ++++++++++++++ arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi | 5 +++++ 2 files changed, 19 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/qca402x.txt diff --git a/Documentation/devicetree/bindings/media/qca402x.txt b/Documentation/devicetree/bindings/media/qca402x.txt new file mode 100644 index 000000000000..f803b029eb29 --- /dev/null +++ b/Documentation/devicetree/bindings/media/qca402x.txt @@ -0,0 +1,14 @@ +* Qualcomm Technologies, Inc. MSM QCA402x + +Required properties for parent node: +- compatible : + - "qcom,qca402" + +Optional properties +- endpoints : Number of endpoints used for communication with the QCA402x + device +Example: +qcom,qca402x { + compatible = "qcom,qca402"; + endpoints = <1>; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi index f7a2026f7588..e74c4290c3c5 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi @@ -123,6 +123,11 @@ qcom,rmnet-ipa { status = "disabled"; }; + + qcom,qca402x { + compatible = "qcom,qca402"; + endpoints = <1>; + }; }; &firmware { -- GitLab From 17022f785d93b5f946260c60515690d40c997579 Mon Sep 17 00:00:00 2001 From: Arjun Singh Date: Tue, 24 Jul 2018 16:32:49 +0530 Subject: [PATCH 550/604] soc: qcom: bgcom: allocate a fixed buffer to avoid allocation delay Allocaes a fixed size buffer to avoid allocation delay while ahb write to BG. Change-Id: I810abdd9482b2de02d374b4b98b8c2436fb07862 Signed-off-by: Arjun Singh --- drivers/soc/qcom/bgcom_spi.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/drivers/soc/qcom/bgcom_spi.c b/drivers/soc/qcom/bgcom_spi.c index d2dc05f39d99..446669f30a97 100644 --- a/drivers/soc/qcom/bgcom_spi.c +++ b/drivers/soc/qcom/bgcom_spi.c @@ -47,6 +47,7 @@ #define HED_EVENT_ID_LEN (0x02) #define HED_EVENT_SIZE_LEN (0x02) #define HED_EVENT_DATA_STRT_LEN (0x05) +#define CMA_BFFR_POOL_SIZE (128*1024) #define MAX_RETRY 500 @@ -116,6 +117,9 @@ static struct mutex bg_resume_mutex; static atomic_t bg_is_spi_active; static int bg_irq; +static uint8_t *fxd_mem_buffer; +static struct mutex cma_buffer_lock; + static struct spi_device *get_spi_device(void) { struct bg_spi_priv *bg_spi = container_of(bg_com_drv, @@ -529,6 +533,7 @@ int bgcom_ahb_write(void *handle, uint32_t ahb_start_addr, uint8_t *tx_buf; uint32_t size; int ret; + bool is_cma_used = false; uint8_t cmnd = 0; uint32_t ahb_addr = 0; struct spi_device *spi = get_spi_device(); @@ -552,11 +557,22 @@ int bgcom_ahb_write(void *handle, uint32_t ahb_start_addr, return -EBUSY; } + + mutex_lock(&cma_buffer_lock); size = num_words*BG_SPI_WORD_SIZE; txn_len = BG_SPI_AHB_CMD_LEN + size; - tx_buf = dma_zalloc_coherent(&spi->dev, txn_len, &dma_hndl, GFP_KERNEL); - if (!tx_buf) + if (fxd_mem_buffer != NULL && txn_len <= CMA_BFFR_POOL_SIZE) { + memset(fxd_mem_buffer, 0, txn_len); + tx_buf = fxd_mem_buffer; + is_cma_used = true; + } else + tx_buf = dma_zalloc_coherent(&spi->dev, txn_len, + &dma_hndl, GFP_KERNEL); + + if (!tx_buf) { + mutex_unlock(&cma_buffer_lock); return -ENOMEM; + } cmnd |= BG_SPI_AHB_WRITE_CMD; ahb_addr |= ahb_start_addr; @@ -566,7 +582,9 @@ int bgcom_ahb_write(void *handle, uint32_t ahb_start_addr, memcpy(tx_buf+BG_SPI_AHB_CMD_LEN, write_buf, size); ret = bgcom_transfer(handle, tx_buf, NULL, txn_len); - dma_free_coherent(&spi->dev, txn_len, tx_buf, dma_hndl); + if (!is_cma_used) + dma_free_coherent(&spi->dev, txn_len, tx_buf, dma_hndl); + mutex_unlock(&cma_buffer_lock); return ret; } EXPORT_SYMBOL(bgcom_ahb_write); @@ -943,6 +961,10 @@ static void bg_spi_init(struct bg_spi_priv *bg_spi) bg_com_drv = &bg_spi->lhandle; mutex_init(&bg_resume_mutex); + + fxd_mem_buffer = kmalloc(CMA_BFFR_POOL_SIZE, GFP_KERNEL | GFP_ATOMIC); + + mutex_init(&cma_buffer_lock); } static int bg_spi_probe(struct spi_device *spi) @@ -1006,7 +1028,9 @@ static int bg_spi_remove(struct spi_device *spi) mutex_destroy(&bg_spi->xfer_mutex); devm_kfree(&spi->dev, bg_spi); spi_set_drvdata(spi, NULL); - + if (fxd_mem_buffer != NULL) + kfree(fxd_mem_buffer); + mutex_destroy(&cma_buffer_lock); return 0; } -- GitLab From c12bc4a2792351802e722c271ef74548006cccce Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Mon, 30 Jul 2018 20:01:04 +0530 Subject: [PATCH 551/604] msm: mhi_dev: Handle wrap-around case for event ring updates Asynchronous reads/writes may result in multiple elements being added to the event ring in a single update. This change accounts for the wrap-around case when updating a ring with multiple elements. Change-Id: I4fca542da488ae812dbb57f2d651a472092b39eb Signed-off-by: Siva Kumar Akkireddi --- drivers/platform/msm/mhi_dev/mhi_ring.c | 71 ++++++++++++++++++------- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi_ring.c b/drivers/platform/msm/mhi_dev/mhi_ring.c index d6791eab3a10..92b061648cd8 100644 --- a/drivers/platform/msm/mhi_dev/mhi_ring.c +++ b/drivers/platform/msm/mhi_dev/mhi_ring.c @@ -278,11 +278,12 @@ EXPORT_SYMBOL(mhi_dev_process_ring); int mhi_dev_add_element(struct mhi_dev_ring *ring, union mhi_dev_ring_element_type *element, - struct event_req *ereq, int evt_offset) + struct event_req *ereq, int size) { uint32_t old_offset = 0; struct mhi_addr host_addr; - uint32_t num_elem = 0; + uint32_t num_elem = 1; + uint32_t num_free_elem; if (!ring || !element) { pr_err("%s: Invalid context\n", __func__); @@ -291,16 +292,24 @@ int mhi_dev_add_element(struct mhi_dev_ring *ring, mhi_dev_update_wr_offset(ring); - if ((ring->rd_offset + 1) % ring->ring_size == ring->wr_offset) { - mhi_log(MHI_MSG_VERBOSE, "ring full to insert element\n"); + if (ereq) + num_elem = size / (sizeof(union mhi_dev_ring_element_type)); + + if (ring->rd_offset < ring->wr_offset) + num_free_elem = ring->wr_offset - ring->rd_offset - 1; + else + num_free_elem = ring->ring_size - ring->rd_offset + + ring->wr_offset - 1; + + if (num_free_elem < num_elem) { + mhi_log(MHI_MSG_ERROR, "No space to add %d elem in ring (%d)\n", + num_elem, ring->id); return -EINVAL; } old_offset = ring->rd_offset; - if (evt_offset) { - num_elem = evt_offset / - (sizeof(union mhi_dev_ring_element_type)); + if (ereq) { ring->rd_offset += num_elem; if (ring->rd_offset >= ring->ring_size) ring->rd_offset -= ring->ring_size; @@ -322,23 +331,47 @@ int mhi_dev_add_element(struct mhi_dev_ring *ring, host_addr.device_va = ring->ring_shadow.device_va + sizeof(union mhi_dev_ring_element_type) * old_offset; - host_addr.virt_addr = element; - - if (evt_offset) - host_addr.size = evt_offset; - else + if (!ereq) { + /* We're adding only a single ring element */ + host_addr.virt_addr = element; host_addr.size = sizeof(union mhi_dev_ring_element_type); - mhi_log(MHI_MSG_VERBOSE, "adding element to ring (%d)\n", ring->id); - mhi_log(MHI_MSG_VERBOSE, "rd_ofset %d\n", ring->rd_offset); - mhi_log(MHI_MSG_VERBOSE, "type %d\n", element->generic.type); + mhi_log(MHI_MSG_VERBOSE, "adding element to ring (%d)\n", + ring->id); + mhi_log(MHI_MSG_VERBOSE, "rd_ofset %d\n", ring->rd_offset); + mhi_log(MHI_MSG_VERBOSE, "type %d\n", element->generic.type); - if (ereq) mhi_dev_write_to_host(ring->mhi_dev, &host_addr, - ereq, MHI_DEV_DMA_ASYNC); - else + NULL, MHI_DEV_DMA_SYNC); + return 0; + } + + /* Adding multiple ring elements */ + if (ring->rd_offset == 0 || (ring->rd_offset > old_offset)) { + /* No wrap-around case */ + host_addr.virt_addr = element; + host_addr.size = size; + mhi_dev_write_to_host(ring->mhi_dev, &host_addr, + ereq, MHI_DEV_DMA_ASYNC); + } else { + /* Wrap-around case - first chunk uses dma sync */ + host_addr.virt_addr = element; + host_addr.size = (ring->ring_size - old_offset) * + sizeof(union mhi_dev_ring_element_type); + mhi_dev_write_to_host(ring->mhi_dev, &host_addr, + NULL, MHI_DEV_DMA_SYNC); + + /* Copy remaining elements */ + if (ring->mhi_dev->use_ipa) + host_addr.host_pa = ring->ring_shadow.host_pa; + else + host_addr.device_va = ring->ring_shadow.device_va; + host_addr.virt_addr = element + (ring->ring_size - old_offset); + host_addr.size = ring->rd_offset * + sizeof(union mhi_dev_ring_element_type); mhi_dev_write_to_host(ring->mhi_dev, &host_addr, - NULL, MHI_DEV_DMA_SYNC); + ereq, MHI_DEV_DMA_ASYNC); + } return 0; } EXPORT_SYMBOL(mhi_dev_add_element); -- GitLab From 37c552198ad1a7711fb2497af722cea4d3a41758 Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Tue, 31 Jul 2018 14:28:47 +0530 Subject: [PATCH 552/604] thermal: qpnp-temp-alarm: Configure TEMP ALARM in the shutdown path Force the TEMP ALARM into FOLLOW_HW_EN mode in the system shutdown path, to avoid leakage when device is powered-off. CRs-Fixed: 1059981 Change-Id: I7017d7ecc9b75570c41a13c49ac67045052630e9 Signed-off-by: Anirudh Ghayal --- drivers/thermal/qpnp-temp-alarm.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/thermal/qpnp-temp-alarm.c b/drivers/thermal/qpnp-temp-alarm.c index 7398b7b5d391..e8a89078d395 100644 --- a/drivers/thermal/qpnp-temp-alarm.c +++ b/drivers/thermal/qpnp-temp-alarm.c @@ -586,6 +586,20 @@ static int qpnp_tm_remove(struct platform_device *pdev) return 0; } +static void qpnp_tm_shutdown(struct platform_device *pdev) +{ + struct qpnp_tm_chip *chip = dev_get_drvdata(&pdev->dev); + int rc; + u8 reg; + + /* configure TEMP_ALARM to follow HW_EN */ + reg = ALARM_CTRL_FOLLOW_HW_ENABLE; + rc = qpnp_tm_write(chip, QPNP_TM_REG_ALARM_CTRL, ®, 1); + if (rc) + pr_err("Failed to cfg. TEMP_ALARM to follow HW_EN rc=%d\n", rc); +} + + static const struct of_device_id qpnp_tm_match_table[] = { { .compatible = QPNP_TM_DRIVER_NAME, }, {} @@ -604,6 +618,7 @@ static struct platform_driver qpnp_tm_driver = { }, .probe = qpnp_tm_probe, .remove = qpnp_tm_remove, + .shutdown = qpnp_tm_shutdown, .id_table = qpnp_tm_id, }; -- GitLab From 48116cc0db2f8a04ff7fd5eb4276184106cb47d9 Mon Sep 17 00:00:00 2001 From: Zhang Chuming Date: Wed, 25 Jul 2018 14:05:15 +0530 Subject: [PATCH 553/604] input: touchscreen: Add Elan_Sparrow touchscreen support Add Elan_Sparrow touchscreen support for apq8053-lite 8" Panel display variant. Signed-off-by: Zhang Chuming Git-commit: 936a3d5db58d87c58bb6871cff06537af45d2d60 Git-Repo: https://github.com/ElanDriver/Sparrow/tree/Sparrow_ElanDriver Change-Id: I971c9f45b6e4263a05bc4837c2c17f2f8970ef1e Signed-off-by: Venkataraman Nerellapalli --- .../bindings/input/touchscreen/elants_i2c.txt | 34 + drivers/input/touchscreen/ektf3xxx/Makefile | 3 + .../touchscreen/ektf3xxx/elan_cros_i2c.c | 1520 +++++++++++++++++ 3 files changed, 1557 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/elants_i2c.txt create mode 100644 drivers/input/touchscreen/ektf3xxx/Makefile create mode 100644 drivers/input/touchscreen/ektf3xxx/elan_cros_i2c.c diff --git a/Documentation/devicetree/bindings/input/touchscreen/elants_i2c.txt b/Documentation/devicetree/bindings/input/touchscreen/elants_i2c.txt new file mode 100644 index 000000000000..3fcaaad476c6 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/elants_i2c.txt @@ -0,0 +1,34 @@ +Elan Ektf3xx series touch controller + + Required properties: + + - compatible : Should be "elan,ekth3500" + - reg : I2C slave address of the device. + - interrupt-parent : Parent of interrupt. + - interrupts : Configuration of touch panel controller interrupt GPIO. + - elan,irq-gpio : Interrupt gpio which is to provide interrupts to + host, same as "interrupts" node.It will also contain + active low or active high information + + Optional properties: + + - vdd-supply : Power supply needed to power up the device, when use + external regulator, do not add this property. + - vccio-supply : Power source required to power up i2c bus. + Ekth3500 series can provide 1.8V from internal + LDO, add this properties base on hardware design. + - reset-gpio : Reset gpio to control the reset of chip. + + Example: + i2c@f9923000{ + elan_ktf@10 { + compatible = "elan,ekth3500"; + reg = <0x10>; + vdd-supply = <&pm8110_l19>; + vccio-supply = <&pm8110_l14>; + reset-gpio = <&msmgpio 0 GPIO_ACTIVE_LOW>; + interrupt-parent = <&msmgpio>; + interrupts = <1 0x2>; + elan,irq-gpio = <&tlmm 65 0x2008>;> + }; + }; diff --git a/drivers/input/touchscreen/ektf3xxx/Makefile b/drivers/input/touchscreen/ektf3xxx/Makefile new file mode 100644 index 000000000000..715b8918442c --- /dev/null +++ b/drivers/input/touchscreen/ektf3xxx/Makefile @@ -0,0 +1,3 @@ +# Makefile for the Elan touchscreen drivers. + +obj-$(CONFIG_TOUCHSCREEN_EKTF3XXX_CHIPSET) += elan_cros_i2c.o diff --git a/drivers/input/touchscreen/ektf3xxx/elan_cros_i2c.c b/drivers/input/touchscreen/ektf3xxx/elan_cros_i2c.c new file mode 100644 index 000000000000..3098941fa90f --- /dev/null +++ b/drivers/input/touchscreen/ektf3xxx/elan_cros_i2c.c @@ -0,0 +1,1520 @@ +/* + * Elan Microelectronics touch panels with I2C interface + * + * Copyright (C) 2014 Elan Microelectronics Corporation. + * Chuming Zhang + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Device, Driver information */ +#define DEVICE_NAME "elants_i2c" +#define DRV_VERSION "1.0.9" + +/* Convert from rows or columns into resolution */ +#define ELAN_TS_RESOLUTION(n, m) (((n) - 1) * (m)) +#define ELAN_VTG_MAX_UV 3300000 + +/* FW header data */ +#define HEADER_SIZE 4 +#define FW_HDR_TYPE 0 +#define FW_HDR_COUNT 1 +#define FW_HDR_LENGTH 2 + +/* Buffer mode Queue Header information */ +#define QUEUE_HEADER_SINGLE 0x62 +#define QUEUE_HEADER_NORMAL 0X63 +#define QUEUE_HEADER_WAIT 0x64 + +/* Command header definition */ +#define CMD_HEADER_WRITE 0x54 +#define CMD_HEADER_READ 0x53 +#define CMD_HEADER_6B_READ 0x5B +#define CMD_HEADER_RESP 0x52 +#define CMD_HEADER_6B_RESP 0x9B +#define CMD_HEADER_HELLO 0x55 +#define CMD_HEADER_REK 0x66 + +/* FW position data */ +#define PACKET_SIZE 55 +#define MAX_CONTACT_NUM 10 +#define FW_POS_HEADER 0 +#define FW_POS_STATE 1 +#define FW_POS_TOTAL 2 +#define FW_POS_XY 3 +#define FW_POS_CHECKSUM 34 +#define FW_POS_WIDTH 35 +#define FW_POS_PRESSURE 45 + +#define HEADER_REPORT_10_FINGER 0x62 + +/* Header (4 bytes) plus 3 fill 10-finger packets */ +#define MAX_PACKET_SIZE 169 + +#define BOOT_TIME_DELAY_MS 50 + +/* FW read command, 0x53 0x?? 0x0, 0x01 */ +#define E_ELAN_INFO_FW_VER 0x00 +#define E_ELAN_INFO_BC_VER 0x10 +#define E_ELAN_INFO_TEST_VER 0xE0 +#define E_ELAN_INFO_FW_ID 0xF0 +#define E_INFO_OSR 0xD6 +#define E_INFO_PHY_SCAN 0xD7 +#define E_INFO_PHY_DRIVER 0xD8 + +#define MAX_RETRIES 3 +#define MAX_FW_UPDATE_RETRIES 30 + +#define ELAN_FW_PAGESIZE 132 + +/* calibration timeout definition */ +#define ELAN_CALI_TIMEOUT_MSEC 12000 + +#define ELAN_POWERON_DELAY_USEC 500 +#define ELAN_RESET_DELAY_MSEC 20 + +/* define print buf size*/ +#define ELAN_PRINT_SIZE 1024 + +enum elants_state { + ELAN_STATE_NORMAL, + ELAN_WAIT_QUEUE_HEADER, + ELAN_WAIT_RECALIBRATION, +}; + +enum elants_iap_mode { + ELAN_IAP_OPERATIONAL, + ELAN_IAP_RECOVERY, +}; + +/* struct elants_data - represents state of Elan touchscreen device */ +struct elants_data { + struct i2c_client *client; + struct input_dev *input; + + struct regulator *vdd; + struct regulator *vccio; + struct gpio_desc *reset_gpio; + + u16 fw_version; + u8 test_version; + u8 solution_version; + u8 bc_version; + u8 iap_version; + u16 hw_version; + unsigned int x_res; /* resolution in units/mm */ + unsigned int y_res; + unsigned int x_max; + unsigned int y_max; + + enum elants_state state; + enum elants_iap_mode iap_mode; + + /* Guards against concurrent access to the device via sysfs */ + struct mutex sysfs_mutex; + + u8 cmd_resp[HEADER_SIZE]; + struct completion cmd_done; + + u8 buf[MAX_PACKET_SIZE]; + + bool wake_irq_enabled; + bool keep_power_in_suspend; + struct workqueue_struct *elan_ic_update; + struct delayed_work delay_work; +}; + +static int elants_i2c_send(struct i2c_client *client, + const void *data, size_t size) +{ + int ret; + + ret = i2c_master_send(client, data, size); + if (ret == size) + return 0; + + if (ret >= 0) + ret = -EIO; + + dev_err(&client->dev, "%s failed (%*ph): %d\n", + __func__, (int)size, data, ret); + + return ret; +} + +static int elants_i2c_read(struct i2c_client *client, void *data, size_t size) +{ + int ret; + + ret = i2c_master_recv(client, data, size); + if (ret == size) + return 0; + + if (ret >= 0) + ret = -EIO; + + dev_err(&client->dev, "%s failed: %d\n", __func__, ret); + + return ret; +} + +static int elants_i2c_execute_command(struct i2c_client *client, + const u8 *cmd, size_t cmd_size, + u8 *resp, size_t resp_size) +{ + struct i2c_msg msgs[2]; + int ret; + u8 expected_response; + + switch (cmd[0]) { + case CMD_HEADER_READ: + expected_response = CMD_HEADER_RESP; + break; + + case CMD_HEADER_6B_READ: + expected_response = CMD_HEADER_6B_RESP; + break; + + default: + dev_err(&client->dev, "%s: invalid command %*ph\n", + __func__, (int)cmd_size, cmd); + return -EINVAL; + } + + msgs[0].addr = client->addr; + msgs[0].flags = client->flags & I2C_M_TEN; + msgs[0].len = cmd_size; + msgs[0].buf = (u8 *)cmd; + + msgs[1].addr = client->addr; + msgs[1].flags = client->flags & I2C_M_TEN; + msgs[1].flags |= I2C_M_RD; + msgs[1].len = resp_size; + msgs[1].buf = resp; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) + return ret; + + if (ret != ARRAY_SIZE(msgs) || resp[FW_HDR_TYPE] != expected_response) + return -EIO; + + return 0; +} + +static int elants_i2c_calibrate(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int ret, error; + static const u8 w_flashkey[] = { 0x54, 0xC0, 0xE1, 0x5A }; + static const u8 rek[] = { 0x54, 0x29, 0x00, 0x01 }; + static const u8 rek_resp[] = { CMD_HEADER_REK, 0x66, 0x66, 0x66 }; + + disable_irq(client->irq); + + ts->state = ELAN_WAIT_RECALIBRATION; + reinit_completion(&ts->cmd_done); + + elants_i2c_send(client, w_flashkey, sizeof(w_flashkey)); + elants_i2c_send(client, rek, sizeof(rek)); + + enable_irq(client->irq); + + ret = wait_for_completion_interruptible_timeout(&ts->cmd_done, + msecs_to_jiffies(ELAN_CALI_TIMEOUT_MSEC)); + + ts->state = ELAN_STATE_NORMAL; + + if (ret <= 0) { + error = ret < 0 ? ret : -ETIMEDOUT; + dev_err(&client->dev, + "error while waiting for calibration to complete: %d\n", + error); + return error; + } + + if (memcmp(rek_resp, ts->cmd_resp, sizeof(rek_resp))) { + dev_err(&client->dev, + "unexpected calibration response: %*ph\n", + (int)sizeof(ts->cmd_resp), ts->cmd_resp); + return -EINVAL; + } + + return 0; +} + +static int elants_i2c_sw_reset(struct i2c_client *client) +{ + const u8 soft_rst_cmd[] = { 0x77, 0x77, 0x77, 0x77 }; + int error; + + error = elants_i2c_send(client, soft_rst_cmd, + sizeof(soft_rst_cmd)); + if (error) { + dev_err(&client->dev, "software reset failed: %d\n", error); + return error; + } + + /* + * We should wait at least 10 msec (but no more than 40) before + * sending fastboot or IAP command to the device. + */ + msleep(30); + + return 0; +} + +static u16 elants_i2c_parse_version(u8 *buf) +{ + return get_unaligned_be32(buf) >> 4; +} + +static int elants_i2c_query_hw_version(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int error, retry_cnt; + const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_FW_ID, 0x00, 0x01 }; + u8 resp[HEADER_SIZE]; + + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_execute_command(client, cmd, sizeof(cmd), + resp, sizeof(resp)); + if (!error) { + ts->hw_version = elants_i2c_parse_version(resp); + if (ts->hw_version != 0xffff) + return 0; + } + dev_dbg(&client->dev, "read fw id error=%d, buf=%*phC\n", + error, (int)sizeof(resp), resp); + } + + if (error) { + dev_err(&client->dev, + "Failed to read fw id: %d\n", error); + return error; + } + dev_err(&client->dev, "Invalid fw id: %#04x\n", ts->hw_version); + return -EINVAL; +} + + +static int elants_i2c_query_fw_version(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int error, retry_cnt; + const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_FW_VER, 0x00, 0x01 }; + u8 resp[HEADER_SIZE]; + + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_execute_command(client, cmd, sizeof(cmd), + resp, sizeof(resp)); + if (!error) { + ts->fw_version = elants_i2c_parse_version(resp); + if (ts->fw_version != 0x0000 && + ts->fw_version != 0xffff) + return 0; + } + + dev_dbg(&client->dev, "read fw version error=%d, buf=%*phC\n", + error, (int)sizeof(resp), resp); + } + + dev_err(&client->dev, + "Failed to read fw version or fw version is invalid\n"); + + return -EINVAL; +} + +static int elants_i2c_query_test_version(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int error, retry_cnt; + u16 version; + const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_TEST_VER, 0x00, 0x01 }; + u8 resp[HEADER_SIZE]; + + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_execute_command(client, cmd, sizeof(cmd), + resp, sizeof(resp)); + if (!error) { + version = elants_i2c_parse_version(resp); + ts->test_version = version >> 8; + ts->solution_version = version & 0xff; + + return 0; + } + + dev_dbg(&client->dev, + "read test version error rc=%d, buf=%*phC\n", + error, (int)sizeof(resp), resp); + } + + dev_err(&client->dev, "Failed to read test version\n"); + + return -EINVAL; +} + +static int elants_i2c_query_bc_version(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_BC_VER, 0x00, 0x01 }; + u8 resp[HEADER_SIZE]; + u16 version; + int error; + + error = elants_i2c_execute_command(client, cmd, sizeof(cmd), + resp, sizeof(resp)); + if (error) { + dev_err(&client->dev, + "read BC version error=%d, buf=%*phC\n", + error, (int)sizeof(resp), resp); + return error; + } + + version = elants_i2c_parse_version(resp); + ts->bc_version = version >> 8; + ts->iap_version = version & 0xff; + + return 0; +} + +static int elants_i2c_query_ts_info(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int error; + u8 resp[17]; + u16 phy_x, phy_y, rows, cols, osr; + const u8 get_resolution_cmd[] = { + CMD_HEADER_6B_READ, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const u8 get_osr_cmd[] = { + CMD_HEADER_READ, E_INFO_OSR, 0x00, 0x01 + }; + const u8 get_physical_scan_cmd[] = { + CMD_HEADER_READ, E_INFO_PHY_SCAN, 0x00, 0x01 + }; + const u8 get_physical_drive_cmd[] = { + CMD_HEADER_READ, E_INFO_PHY_DRIVER, 0x00, 0x01 + }; + + /* Get trace number */ + error = elants_i2c_execute_command(client, + get_resolution_cmd, + sizeof(get_resolution_cmd), + resp, sizeof(resp)); + if (error) { + dev_err(&client->dev, "get resolution command failed: %d\n", + error); + return error; + } + + rows = resp[2] + resp[6] + resp[10]; + cols = resp[3] + resp[7] + resp[11]; + + /* Process mm_to_pixel information */ + error = elants_i2c_execute_command(client, + get_osr_cmd, sizeof(get_osr_cmd), + resp, sizeof(resp)); + if (error) { + dev_err(&client->dev, "get osr command failed: %d\n", + error); + return error; + } + + osr = resp[3]; + + error = elants_i2c_execute_command(client, + get_physical_scan_cmd, + sizeof(get_physical_scan_cmd), + resp, sizeof(resp)); + if (error) { + dev_err(&client->dev, "get physical scan command failed: %d\n", + error); + return error; + } + + phy_x = get_unaligned_be16(&resp[2]); + + error = elants_i2c_execute_command(client, + get_physical_drive_cmd, + sizeof(get_physical_drive_cmd), + resp, sizeof(resp)); + if (error) { + dev_err(&client->dev, "get physical drive command failed: %d\n", + error); + return error; + } + + phy_y = get_unaligned_be16(&resp[2]); + + dev_dbg(&client->dev, "phy_x=%d, phy_y=%d\n", phy_x, phy_y); + + if (rows == 0 || cols == 0 || osr == 0) { + dev_warn(&client->dev, + "invalid trace number data: %d, %d, %d\n", + rows, cols, osr); + } else { + /* translate trace number to TS resolution */ + ts->y_max = ELAN_TS_RESOLUTION(rows, osr); + ts->y_res = DIV_ROUND_CLOSEST(ts->y_max, phy_y); + ts->x_max = ELAN_TS_RESOLUTION(cols, osr); + ts->x_res = DIV_ROUND_CLOSEST(ts->x_max, phy_x); + } + + return 0; +} + +static int elants_i2c_fastboot(struct i2c_client *client) +{ + const u8 boot_cmd[] = { 0x4D, 0x61, 0x69, 0x6E }; + int error; + + error = elants_i2c_send(client, boot_cmd, sizeof(boot_cmd)); + if (error) { + dev_err(&client->dev, "boot failed: %d\n", error); + return error; + } + + dev_dbg(&client->dev, "boot success -- 0x%x\n", client->addr); + return 0; +} + +static int elants_i2c_initialize(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int error, error2, retry_cnt; + const u8 hello_packet[] = { 0x55, 0x55, 0x55, 0x55 }; + const u8 recov_packet[] = { 0x55, 0x55, 0x80, 0x80 }; + u8 buf[HEADER_SIZE]; + + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_sw_reset(client); + if (error) { + /* Continue initializing if it's the last try */ + if (retry_cnt < MAX_RETRIES - 1) + continue; + } + + error = elants_i2c_fastboot(client); + if (error) { + /* Continue initializing if it's the last try */ + if (retry_cnt < MAX_RETRIES - 1) + continue; + } + + /* Wait for Hello packet */ + msleep(BOOT_TIME_DELAY_MS); + + error = elants_i2c_read(client, buf, sizeof(buf)); + if (error) { + dev_err(&client->dev, + "failed to read 'hello' packet: %d\n", error); + continue; + } else if (!memcmp(buf, hello_packet, sizeof(hello_packet))) { + ts->iap_mode = ELAN_IAP_OPERATIONAL; + break; + } else if (!memcmp(buf, recov_packet, sizeof(recov_packet))) { + /* + * Setting error code will mark device + * in recovery mode below. + */ + error = -EIO; + break; + } + error = -EINVAL; + dev_err(&client->dev, + "invalid 'hello' packet: %*ph\n", + (int)sizeof(buf), buf); + } + + error2 = elants_i2c_query_hw_version(ts); + if (!error) + error = error2; + if (!error) + error = elants_i2c_query_fw_version(ts); + if (!error) + error = elants_i2c_query_test_version(ts); + if (!error) + error = elants_i2c_query_bc_version(ts); + if (!error) + error = elants_i2c_query_ts_info(ts); + if (error) + ts->iap_mode = ELAN_IAP_RECOVERY; + return 0; +} + +/* + * Firmware update interface. + */ + +static int elants_i2c_fw_write_page(struct i2c_client *client, + const void *page, int page_num) +{ + const u8 ack_ok[] = { 0xaa, 0xaa }; + u8 buf[2]; + int retry; + int error; + int curIndex = 0; + const u8 *szBuff; + int byte_count; + + for (retry = 0; retry < MAX_FW_UPDATE_RETRIES; retry++) { + for (byte_count = 1; byte_count <= 5; byte_count++) { + if (byte_count != 5) { + szBuff = page + curIndex; + curIndex = curIndex + 32; + error = elants_i2c_send(client, szBuff, 32); + } else { + szBuff = page + curIndex; + curIndex = curIndex + 4; + error = elants_i2c_send(client, szBuff, 4); + } + + if (error) { + curIndex = 0; + continue; + } + } + + if (error) { + dev_err(&client->dev, + "IAP Write Page failed: %d\n", error); + continue; + } + + if (page_num == 1) + msleep(600); + else + msleep(50); + error = elants_i2c_read(client, buf, 2); + if (error) { + dev_err(&client->dev, + "IAP Ack read failed: %d\n", error); + return error; + } + + if (!memcmp(buf, ack_ok, sizeof(ack_ok))) + return 0; + + error = -EIO; + dev_err(&client->dev, + "IAP Get Ack Error [%02x:%02x]\n", + buf[0], buf[1]); + } + + return error; +} + +static int elants_i2c_do_update_firmware(struct i2c_client *client, + const struct firmware *fw, + bool force) +{ + const u8 enter_iap[] = { 0x45, 0x49, 0x41, 0x50 }; + const u8 enter_iap2[] = { 0x54, 0x00, 0x12, 0x34 }; + const u8 iap_ack[] = { 0x55, 0xaa, 0x33, 0xcc }; + const u8 close_idle[] = {0x54, 0x2c, 0x01, 0x01}; + u8 buf[HEADER_SIZE]; + u16 send_id; + int page, n_fw_pages; + int error; + + /* Recovery mode detection! */ + if (force) { + dev_dbg(&client->dev, "Recovery mode procedure\n"); + error = elants_i2c_send(client, enter_iap2, sizeof(enter_iap2)); + } else { + /* Start IAP Procedure */ + dev_dbg(&client->dev, "Normal IAP procedure\n"); + /* Close idle mode */ + error = elants_i2c_send(client, close_idle, sizeof(close_idle)); + if (error) + dev_err(&client->dev, "Failed close idle: %d\n", error); + msleep(60); + elants_i2c_sw_reset(client); + msleep(20); + error = elants_i2c_send(client, enter_iap, sizeof(enter_iap)); + } + + if (error) { + dev_err(&client->dev, "failed to enter IAP mode: %d\n", error); + return error; + } + + msleep(20); + + /* check IAP state */ + error = elants_i2c_read(client, buf, 4); + if (error) { + dev_err(&client->dev, + "failed to read IAP acknowledgment: %d\n", + error); + return error; + } + + if (memcmp(buf, iap_ack, sizeof(iap_ack))) { + dev_err(&client->dev, + "failed to enter IAP: %*ph (expected %*ph)\n", + (int)sizeof(buf), buf, (int)sizeof(iap_ack), iap_ack); + return -EIO; + } + + dev_info(&client->dev, "successfully entered IAP mode"); + + send_id = client->addr; + error = elants_i2c_send(client, &send_id, 1); + if (error) { + dev_err(&client->dev, "sending dummy byte failed: %d\n", + error); + return error; + } + + /* Clear the last page of Master */ + error = elants_i2c_send(client, fw->data, ELAN_FW_PAGESIZE); + if (error) { + dev_err(&client->dev, "clearing of the last page failed: %d\n", + error); + return error; + } + + error = elants_i2c_read(client, buf, 2); + if (error) { + dev_err(&client->dev, + "failed to read ACK for clearing the last page: %d\n", + error); + return error; + } + + n_fw_pages = fw->size / ELAN_FW_PAGESIZE; + dev_dbg(&client->dev, "IAP Pages = %d\n", n_fw_pages); + + for (page = 0; page < n_fw_pages; page++) { + error = elants_i2c_fw_write_page(client, + fw->data + page * ELAN_FW_PAGESIZE, + page); + if (error) { + dev_err(&client->dev, + "failed to write FW page %d: %d\n", + page, error); + return error; + } + } + + /* Old iap needs to wait 200ms for WDT and rest is for hello packets */ + msleep(300); + + dev_info(&client->dev, "firmware update completed\n"); + return 0; +} + +static int elants_i2c_fw_update(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + const struct firmware *fw; + char *fw_name; + int error; + + fw_name = kasprintf(GFP_KERNEL, "elants_i2c_%04x.bin", ts->hw_version); + if (!fw_name) + return -ENOMEM; + + dev_info(&client->dev, "requesting fw name = %s\n", fw_name); + error = request_firmware(&fw, fw_name, &client->dev); + kfree(fw_name); + if (error) { + dev_err(&client->dev, "failed to request firmware: %d\n", + error); + return error; + } + + if (fw->size % ELAN_FW_PAGESIZE) { + dev_err(&client->dev, "invalid firmware length: %zu\n", + fw->size); + error = -EINVAL; + goto out; + } + + disable_irq(client->irq); + + error = elants_i2c_do_update_firmware(client, fw, + ts->iap_mode == ELAN_IAP_RECOVERY); + if (error) { + dev_err(&client->dev, "firmware update failed: %d\n", error); + ts->iap_mode = ELAN_IAP_RECOVERY; + goto out_enable_irq; + } + + error = elants_i2c_initialize(ts); + if (error) { + dev_err(&client->dev, + "failed to initialize device after firmware update: %d\n", + error); + ts->iap_mode = ELAN_IAP_RECOVERY; + goto out_enable_irq; + } + + ts->iap_mode = ELAN_IAP_OPERATIONAL; + +out_enable_irq: + ts->state = ELAN_STATE_NORMAL; + enable_irq(client->irq); + msleep(100); + + if (!error) + elants_i2c_calibrate(ts); +out: + release_firmware(fw); + return error; +} + +static void elants_i2c_auto_update(struct work_struct *work) +{ + struct elants_data *ts = container_of(work, + struct elants_data, delay_work.work); + struct i2c_client *client = ts->client; + const struct firmware *fw; + char *fw_name; + int error; + u8 *fw_data; + u16 new_fw_version; + u16 new_hw_version; + + if (ts->fw_version == 0x0000 || + ts->fw_version == 0xffff) { + dev_err(&client->dev, "invalid firmware version: %04x\n", + ts->fw_version); + return; + } + + fw_name = kasprintf(GFP_KERNEL, "elants_i2c_%04x.bin", ts->hw_version); + if (!fw_name) + return; + + dev_info(&client->dev, "requesting fw name = %s\n", fw_name); + error = request_firmware(&fw, fw_name, &client->dev); + kfree(fw_name); + if (error) { + dev_err(&client->dev, "failed to request firmware: %d\n", + error); + return; + } + + if (fw->size % ELAN_FW_PAGESIZE) { + dev_err(&client->dev, "invalid firmware length: %zu\n", + fw->size); + error = -EINVAL; + goto out; + } + + fw_data = (u8 *)fw->data; + + new_hw_version = fw_data[0xE2CF] << 8 | fw_data[0xE2CE]; + new_fw_version = fw_data[0xDEC3] << 8 | fw_data[0xDEC2]; + dev_dbg(&client->dev, "hw version=0x%x, new hw version=0x%x\n", + ts->hw_version, new_hw_version); + dev_dbg(&client->dev, "fw version=0x%x, new fw version=0x%x\n", + ts->fw_version, new_fw_version); + if ((ts->hw_version == new_hw_version) && + ((ts->fw_version & 0xff) < (new_fw_version & 0xff))) { + dev_dbg(&ts->client->dev, "start auto update\n"); + release_firmware(fw); + + error = mutex_lock_interruptible(&ts->sysfs_mutex); + if (error) + return; + + error = elants_i2c_fw_update(ts); + dev_dbg(&client->dev, "firmware update result: %d\n", error); + + mutex_unlock(&ts->sysfs_mutex); + return; + } + +out: + release_firmware(fw); +} + + + +/* + * Event reporting. + */ + +static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf) +{ + struct input_dev *input = ts->input; + unsigned int n_fingers; + u16 finger_state; + int i; + + n_fingers = buf[FW_POS_STATE + 1] & 0x0f; + finger_state = ((buf[FW_POS_STATE + 1] & 0x30) << 4) | + buf[FW_POS_STATE]; + + dev_dbg(&ts->client->dev, + "n_fingers: %u, state: %04x\n", n_fingers, finger_state); + + for (i = 0; i < MAX_CONTACT_NUM && n_fingers; i++) { + if (finger_state & 1) { + unsigned int x, y, p, w; + u8 *pos; + + pos = &buf[FW_POS_XY + i * 3]; + x = (((u16)pos[0] & 0xf0) << 4) | pos[1]; + y = (((u16)pos[0] & 0x0f) << 8) | pos[2]; + p = buf[FW_POS_PRESSURE + i]; + w = buf[FW_POS_WIDTH + i]; + + dev_dbg(&ts->client->dev, "i=%d x=%d y=%d p=%d w=%d\n", + i, x, y, p, w); + + input_mt_slot(input, i); + input_mt_report_slot_state(input, MT_TOOL_FINGER, true); + input_event(input, EV_ABS, ABS_MT_POSITION_X, x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, y); + input_event(input, EV_ABS, ABS_MT_PRESSURE, p); + input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, w); + + n_fingers--; + } + + finger_state >>= 1; + } + + input_mt_sync_frame(input); + input_sync(input); +} + +static u8 elants_i2c_calculate_checksum(u8 *buf) +{ + u8 checksum = 0; + u8 i; + + for (i = 0; i < FW_POS_CHECKSUM; i++) + checksum += buf[i]; + + return checksum; +} + +static void elants_i2c_event(struct elants_data *ts, u8 *buf) +{ + u8 checksum = elants_i2c_calculate_checksum(buf); + + if (unlikely(buf[FW_POS_CHECKSUM] != checksum)) + dev_warn(&ts->client->dev, + "%s: invalid checksum for packet %02x: %02x vs. %02x\n", + __func__, buf[FW_POS_HEADER], + checksum, buf[FW_POS_CHECKSUM]); + else if (unlikely(buf[FW_POS_HEADER] != HEADER_REPORT_10_FINGER)) + dev_warn(&ts->client->dev, + "%s: unknown packet type: %02x\n", + __func__, buf[FW_POS_HEADER]); + else + elants_i2c_mt_event(ts, buf); +} + +static irqreturn_t elants_i2c_irq(int irq, void *_dev) +{ + const u8 wait_packet[] = { 0x64, 0x64, 0x64, 0x64 }; + struct elants_data *ts = _dev; + struct i2c_client *client = ts->client; + int report_count, report_len; + int i; + int len; + + len = i2c_master_recv(client, ts->buf, sizeof(ts->buf)); + if (len < 0) { + dev_err(&client->dev, "%s: failed to read data: %d\n", + __func__, len); + goto out; + } + + dev_dbg(&client->dev, "%s: packet %*ph\n", + __func__, HEADER_SIZE, ts->buf); + + + switch (ts->state) { + case ELAN_WAIT_RECALIBRATION: + if (ts->buf[FW_HDR_TYPE] == CMD_HEADER_REK) { + memcpy(ts->cmd_resp, ts->buf, sizeof(ts->cmd_resp)); + complete(&ts->cmd_done); + ts->state = ELAN_STATE_NORMAL; + } + break; + + case ELAN_WAIT_QUEUE_HEADER: + if (ts->buf[FW_HDR_TYPE] != QUEUE_HEADER_NORMAL) + break; + + ts->state = ELAN_STATE_NORMAL; + /* fall through */ + + case ELAN_STATE_NORMAL: + + switch (ts->buf[FW_HDR_TYPE]) { + case CMD_HEADER_HELLO: + case CMD_HEADER_RESP: + case CMD_HEADER_REK: + break; + + case QUEUE_HEADER_WAIT: + if (memcmp(ts->buf, wait_packet, sizeof(wait_packet))) { + dev_err(&client->dev, + "invalid wait packet %*ph\n", + HEADER_SIZE, ts->buf); + } else { + ts->state = ELAN_WAIT_QUEUE_HEADER; + udelay(30); + } + break; + + case QUEUE_HEADER_SINGLE: + elants_i2c_event(ts, &ts->buf[FW_HDR_TYPE]); + break; + + case QUEUE_HEADER_NORMAL: + report_count = ts->buf[FW_HDR_COUNT]; + if (report_count == 0 || report_count > 3) { + dev_err(&client->dev, + "bad report count: %*ph\n", + HEADER_SIZE, ts->buf); + break; + } + + report_len = ts->buf[FW_HDR_LENGTH] / report_count; + if (report_len != PACKET_SIZE) { + dev_err(&client->dev, + "mismatching report length: %*ph\n", + HEADER_SIZE, ts->buf); + break; + } + + for (i = 0; i < report_count; i++) { + u8 *buf = ts->buf + HEADER_SIZE + + i * PACKET_SIZE; + elants_i2c_event(ts, buf); + } + break; + + default: + dev_err(&client->dev, "unknown packet %*ph\n", + HEADER_SIZE, ts->buf); + break; + } + break; + } + +out: + return IRQ_HANDLED; +} + +/* + * sysfs interface + */ +static ssize_t calibrate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elants_data *ts = i2c_get_clientdata(client); + int error; + + error = mutex_lock_interruptible(&ts->sysfs_mutex); + if (error) + return error; + + error = elants_i2c_calibrate(ts); + + mutex_unlock(&ts->sysfs_mutex); + return error ?: count; +} + +static ssize_t write_update_fw(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elants_data *ts = i2c_get_clientdata(client); + int error; + + error = mutex_lock_interruptible(&ts->sysfs_mutex); + if (error) + return error; + + error = elants_i2c_fw_update(ts); + dev_dbg(dev, "firmware update result: %d\n", error); + + mutex_unlock(&ts->sysfs_mutex); + return error ?: count; +} + +static ssize_t show_iap_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elants_data *ts = i2c_get_clientdata(client); + + return snprintf(buf, ELAN_PRINT_SIZE, "%s\n", + ts->iap_mode == ELAN_IAP_OPERATIONAL ? + "Normal" : "Recovery"); +} + +static DEVICE_ATTR(calibrate, 0200, NULL, calibrate_store); +static DEVICE_ATTR(iap_mode, 0444, show_iap_mode, NULL); +static DEVICE_ATTR(update_fw, 0200, NULL, write_update_fw); + +struct elants_version_attribute { + struct device_attribute dattr; + size_t field_offset; + size_t field_size; +}; + +#define __ELANTS_FIELD_SIZE(_field) \ + sizeof(((struct elants_data *)NULL)->_field) +#define __ELANTS_VERIFY_SIZE(_field) \ + (BUILD_BUG_ON_ZERO(__ELANTS_FIELD_SIZE(_field) > 2) + \ + __ELANTS_FIELD_SIZE(_field)) +#define ELANTS_VERSION_ATTR(_field) \ + struct elants_version_attribute elants_ver_attr_##_field = { \ + .dattr = __ATTR(_field, 0444, \ + elants_version_attribute_show, NULL), \ + .field_offset = offsetof(struct elants_data, _field), \ + .field_size = __ELANTS_VERIFY_SIZE(_field), \ + } + +static ssize_t elants_version_attribute_show(struct device *dev, + struct device_attribute *dattr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elants_data *ts = i2c_get_clientdata(client); + struct elants_version_attribute *attr = + container_of(dattr, struct elants_version_attribute, dattr); + u8 *field = (u8 *)((char *)ts + attr->field_offset); + unsigned int fmt_size; + unsigned int val; + + if (attr->field_size == 1) { + val = *field; + fmt_size = 2; /* 2 HEX digits */ + } else { + val = *(u16 *)field; + fmt_size = 4; /* 4 HEX digits */ + } + + return snprintf(buf, ELAN_PRINT_SIZE, "%0*x\n", fmt_size, val); +} + +static ELANTS_VERSION_ATTR(fw_version); +static ELANTS_VERSION_ATTR(hw_version); +static ELANTS_VERSION_ATTR(test_version); +static ELANTS_VERSION_ATTR(solution_version); +static ELANTS_VERSION_ATTR(bc_version); +static ELANTS_VERSION_ATTR(iap_version); + +static struct attribute *elants_attributes[] = { + &dev_attr_calibrate.attr, + &dev_attr_update_fw.attr, + &dev_attr_iap_mode.attr, + + &elants_ver_attr_fw_version.dattr.attr, + &elants_ver_attr_hw_version.dattr.attr, + &elants_ver_attr_test_version.dattr.attr, + &elants_ver_attr_solution_version.dattr.attr, + &elants_ver_attr_bc_version.dattr.attr, + &elants_ver_attr_iap_version.dattr.attr, + NULL +}; + +static struct attribute_group elants_attribute_group = { + .attrs = elants_attributes, +}; + +static void elants_i2c_remove_sysfs_group(void *_data) +{ + struct elants_data *ts = _data; + + sysfs_remove_group(&ts->client->dev.kobj, &elants_attribute_group); +} + +static int elants_i2c_power_on(struct elants_data *ts) +{ + int error; + + /* + * If we do not have reset gpio assume platform firmware + * controls regulators and does power them on for us. + */ + if (IS_ERR_OR_NULL(ts->reset_gpio)) + return 0; + + gpiod_set_value_cansleep(ts->reset_gpio, 1); + + if (regulator_count_voltages(ts->vdd) > 0) { + error = regulator_set_voltage(ts->vdd, + ELAN_VTG_MAX_UV, ELAN_VTG_MAX_UV); + if (error) { + dev_err(&ts->client->dev, + "Regulator set_vtg failed vdd ret=%d\n", + error); + goto release_reset_gpio; + } + } + + error = regulator_enable(ts->vdd); + if (error) { + dev_err(&ts->client->dev, + "failed to enable vdd regulator: %d\n", + error); + goto release_reset_gpio; + } + + error = regulator_enable(ts->vccio); + if (error) { + dev_err(&ts->client->dev, + "failed to enable vccio regulator: %d\n", + error); + regulator_disable(ts->vdd); + goto release_reset_gpio; + } + + /* + * We need to wait a bit after powering on controller before + * we are allowed to release reset GPIO. + */ + udelay(ELAN_POWERON_DELAY_USEC); + +release_reset_gpio: + gpiod_set_value_cansleep(ts->reset_gpio, 0); + if (error) + return error; + + msleep(ELAN_RESET_DELAY_MSEC); + + return 0; +} + +static void elants_i2c_power_off(void *_data) +{ + struct elants_data *ts = _data; + + if (!IS_ERR_OR_NULL(ts->reset_gpio)) { + /* + * Activate reset gpio to prevent leakage through the + * pin once we shut off power to the controller. + */ + gpiod_set_value_cansleep(ts->reset_gpio, 1); + regulator_disable(ts->vccio); + regulator_disable(ts->vdd); + } +} + +static int elants_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + union i2c_smbus_data dummy; + struct elants_data *ts; + unsigned long irqflags; + int error; + unsigned long delay = 3*HZ; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, + "%s: i2c check functionality error\n", DEVICE_NAME); + return -ENXIO; + } + + ts = devm_kzalloc(&client->dev, sizeof(struct elants_data), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + mutex_init(&ts->sysfs_mutex); + init_completion(&ts->cmd_done); + + ts->client = client; + i2c_set_clientdata(client, ts); + + ts->vdd = devm_regulator_get(&client->dev, "vdd"); + if (IS_ERR(ts->vdd)) { + error = PTR_ERR(ts->vdd); + if (error != -EPROBE_DEFER) + dev_err(&client->dev, + "Failed to get 'vdd' regulator: %d\n", + error); + return error; + } + + ts->vccio = devm_regulator_get(&client->dev, "vccio"); + if (IS_ERR(ts->vccio)) { + error = PTR_ERR(ts->vccio); + if (error != -EPROBE_DEFER) + dev_err(&client->dev, + "Failed to get 'vccio' regulator: %d\n", + error); + return error; + } + + ts->reset_gpio = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ts->reset_gpio)) { + error = PTR_ERR(ts->reset_gpio); + + if (error == -EPROBE_DEFER) + return error; + + if (error != -ENOENT) { + dev_err(&client->dev, + "failed to get reset gpio: %d\n", + error); + return error; + } + + ts->keep_power_in_suspend = true; + } + error = elants_i2c_power_on(ts); + if (error) + return error; + + error = devm_add_action(&client->dev, elants_i2c_power_off, ts); + if (error) { + dev_err(&client->dev, + "failed to install power off action: %d\n", error); + elants_i2c_power_off(ts); + return error; + } + + /* Make sure there is something at this address */ + if (i2c_smbus_xfer(client->adapter, client->addr, 0, + I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) { + dev_err(&client->dev, "nothing at this address\n"); + return -ENXIO; + } + + error = elants_i2c_initialize(ts); + if (error) { + dev_err(&client->dev, "failed to initialize: %d\n", error); + return error; + } + + INIT_DELAYED_WORK(&ts->delay_work, elants_i2c_auto_update); + ts->elan_ic_update = create_singlethread_workqueue("elan_ic_update"); + queue_delayed_work(ts->elan_ic_update, &ts->delay_work, delay); + + ts->input = devm_input_allocate_device(&client->dev); + if (!ts->input) { + dev_err(&client->dev, "Failed to allocate input device\n"); + return -ENOMEM; + } + + ts->input->name = "Elan Touchscreen"; + ts->input->id.bustype = BUS_I2C; + + __set_bit(BTN_TOUCH, ts->input->keybit); + __set_bit(EV_ABS, ts->input->evbit); + __set_bit(EV_KEY, ts->input->evbit); + + /* Single touch input params setup */ + input_set_abs_params(ts->input, ABS_X, 0, ts->x_max, 0, 0); + input_set_abs_params(ts->input, ABS_Y, 0, ts->y_max, 0, 0); + input_set_abs_params(ts->input, ABS_PRESSURE, 0, 255, 0, 0); + input_abs_set_res(ts->input, ABS_X, ts->x_res); + input_abs_set_res(ts->input, ABS_Y, ts->y_res); + + /* Multitouch input params setup */ + error = input_mt_init_slots(ts->input, MAX_CONTACT_NUM, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (error) { + dev_err(&client->dev, + "failed to initialize MT slots: %d\n", error); + return error; + } + + input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, ts->x_max, 0, 0); + input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, ts->y_max, 0, 0); + input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0); + input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res); + input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res); + + input_set_drvdata(ts->input, ts); + + error = input_register_device(ts->input); + if (error) { + dev_err(&client->dev, + "unable to register input device: %d\n", error); + return error; + } + + /* + * Systems using device tree should set up interrupt via DTS, + * the rest will use the default falling edge interrupts. + */ + irqflags = client->dev.of_node ? 0 : IRQF_TRIGGER_FALLING; + + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, elants_i2c_irq, + irqflags | IRQF_ONESHOT, + client->name, ts); + if (error) { + dev_err(&client->dev, "Failed to register interrupt\n"); + return error; + } + + /* + * Systems using device tree should set up wakeup via DTS, + * the rest will configure device as wakeup source by default. + */ + if (!client->dev.of_node) + device_init_wakeup(&client->dev, true); + + error = sysfs_create_group(&client->dev.kobj, &elants_attribute_group); + if (error) { + dev_err(&client->dev, "failed to create sysfs attributes: %d\n", + error); + return error; + } + + error = devm_add_action(&client->dev, + elants_i2c_remove_sysfs_group, ts); + if (error) { + elants_i2c_remove_sysfs_group(ts); + dev_err(&client->dev, + "Failed to add sysfs cleanup action: %d\n", + error); + return error; + } + + return 0; +} + +static int __maybe_unused elants_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elants_data *ts = i2c_get_clientdata(client); + const u8 set_sleep_cmd[] = { 0x54, 0x50, 0x00, 0x01 }; + int retry_cnt; + int error; + + /* Command not support in IAP recovery mode */ + if (ts->iap_mode != ELAN_IAP_OPERATIONAL) + return -EBUSY; + + disable_irq(client->irq); + + if (device_may_wakeup(dev)) { + /* + * The device will automatically enter idle mode + * that has reduced power consumption. + */ + ts->wake_irq_enabled = (enable_irq_wake(client->irq) == 0); + } else if (ts->keep_power_in_suspend) { + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_send(client, set_sleep_cmd, + sizeof(set_sleep_cmd)); + if (!error) + break; + + dev_err(&client->dev, + "suspend command failed: %d\n", error); + } + } else { + elants_i2c_power_off(ts); + } + + return 0; +} + +static int __maybe_unused elants_i2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elants_data *ts = i2c_get_clientdata(client); + const u8 set_active_cmd[] = { 0x54, 0x58, 0x00, 0x01 }; + int retry_cnt; + int error; + + if (device_may_wakeup(dev)) { + if (ts->wake_irq_enabled) + disable_irq_wake(client->irq); + elants_i2c_sw_reset(client); + } else if (ts->keep_power_in_suspend) { + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_send(client, set_active_cmd, + sizeof(set_active_cmd)); + if (!error) + break; + + dev_err(&client->dev, + "resume command failed: %d\n", error); + } + } else { + elants_i2c_power_on(ts); + elants_i2c_initialize(ts); + } + + ts->state = ELAN_STATE_NORMAL; + enable_irq(client->irq); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops, + elants_i2c_suspend, elants_i2c_resume); + +static const struct i2c_device_id elants_i2c_id[] = { + { DEVICE_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, elants_i2c_id); + +#ifdef CONFIG_ACPI +static const struct acpi_device_id elants_acpi_id[] = { + { "ELAN0001", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, elants_acpi_id); +#endif + +#ifdef CONFIG_OF +static const struct of_device_id elants_of_match[] = { + { .compatible = "elan,ekth3500" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, elants_of_match); +#endif + +static struct i2c_driver elants_i2c_driver = { + .probe = elants_i2c_probe, + .id_table = elants_i2c_id, + .driver = { + .name = DEVICE_NAME, + .pm = &elants_i2c_pm_ops, + .acpi_match_table = ACPI_PTR(elants_acpi_id), + .of_match_table = of_match_ptr(elants_of_match), + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, +}; +module_i2c_driver(elants_i2c_driver); + +MODULE_AUTHOR("Chuming Zhang "); +MODULE_DESCRIPTION("Elan I2c Touchscreen driver"); +MODULE_VERSION(DRV_VERSION); +MODULE_LICENSE("GPL"); -- GitLab From 0d19582eb78758d4e39716204cf48c9c45cd73c6 Mon Sep 17 00:00:00 2001 From: Nirmal Abraham Date: Tue, 17 Jul 2018 15:49:19 +0530 Subject: [PATCH 554/604] msm: mdss: cleanup used pipes during overlay off During overlay off, cleanup pipes which are currently active in used pipes list. This is to avoid to a race condition wherein the pipe params gets changed in prepare cycle, but the commit cylce has not executed to queue the buffers associated with the pipe and the same pipe which has old buffer(stale content) gets used from overlay_off flow. Change-Id: I117e6ee9854ff287f7bb1055ca745760db980bed Signed-off-by: Nirmal Abraham --- drivers/video/fbdev/msm/mdss_mdp_overlay.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index af6e4ce3e7b2..74ca83294fa3 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -6011,6 +6011,7 @@ static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd) struct mdss_overlay_private *mdp5_data; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); struct mdss_mdp_mixer *mixer; + struct mdss_mdp_pipe *pipe, *tmp; int need_cleanup; int retire_cnt; bool destroy_ctl = false; @@ -6054,6 +6055,13 @@ static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd) mixer->cursor_enabled = 0; mutex_lock(&mdp5_data->list_lock); + if (!list_empty(&mdp5_data->pipes_used)) { + list_for_each_entry_safe( + pipe, tmp, &mdp5_data->pipes_used, list) { + pipe->file = NULL; + list_move(&pipe->list, &mdp5_data->pipes_cleanup); + } + } need_cleanup = !list_empty(&mdp5_data->pipes_cleanup); mutex_unlock(&mdp5_data->list_lock); mutex_unlock(&mdp5_data->ov_lock); -- GitLab From b0eda804d2f9e494fe442c7d2c0dbae4fb206627 Mon Sep 17 00:00:00 2001 From: Animesh Kishore Date: Tue, 24 Jul 2018 11:59:14 +0530 Subject: [PATCH 555/604] msm: mdss: Constant fetch across dfps Timing engine HW restricts changing programmable fetch start when off. Program constant fetch start in SW drivers. Fix fetch start is calculated based on panel DT timings. Change-Id: I2124c92b2f83d9c963e05c14421f61a08878d63b Signed-off-by: Animesh Kishore --- drivers/video/fbdev/msm/mdss_mdp.h | 2 +- drivers/video/fbdev/msm/mdss_mdp_ctl.c | 8 ++++++-- drivers/video/fbdev/msm/mdss_mdp_intf_video.c | 14 +++++++++----- drivers/video/fbdev/msm/mdss_mdp_overlay.c | 3 +-- drivers/video/fbdev/msm/mdss_panel.c | 1 + drivers/video/fbdev/msm/mdss_panel.h | 18 ++++++++++++++++++ 6 files changed, 36 insertions(+), 10 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 78ee489c28b2..e72a315f73f5 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -1713,7 +1713,7 @@ int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff); int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl, int panel_power_mode); int mdss_mdp_ctl_intf_event(struct mdss_mdp_ctl *ctl, int event, void *arg, u32 flags); -int mdss_mdp_get_prefetch_lines(struct mdss_panel_info *pinfo); +int mdss_mdp_get_prefetch_lines(struct mdss_panel_info *pinfo, bool is_fixed); int mdss_mdp_perf_bw_check(struct mdss_mdp_ctl *ctl, struct mdss_mdp_pipe **left_plist, int left_cnt, struct mdss_mdp_pipe **right_plist, int right_cnt); diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 0b6195d536af..4683c7158dcc 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -1506,7 +1506,7 @@ static bool is_mdp_prefetch_needed(struct mdss_panel_info *pinfo) * the mdp fetch lines as the last (25 - vbp - vpw) lines of vertical * front porch. */ -int mdss_mdp_get_prefetch_lines(struct mdss_panel_info *pinfo) +int mdss_mdp_get_prefetch_lines(struct mdss_panel_info *pinfo, bool is_fixed) { int prefetch_avail = 0; int v_total, vfp_start; @@ -1515,7 +1515,11 @@ int mdss_mdp_get_prefetch_lines(struct mdss_panel_info *pinfo) if (!is_mdp_prefetch_needed(pinfo)) return 0; - v_total = mdss_panel_get_vtotal(pinfo); + if (is_fixed) + v_total = mdss_panel_get_vtotal_fixed(pinfo); + else + v_total = mdss_panel_get_vtotal(pinfo); + vfp_start = (pinfo->lcdc.v_back_porch + pinfo->lcdc.v_pulse_width + pinfo->yres); diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index dba3b0dbc37e..783755995e3c 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -959,6 +959,7 @@ static void mdss_mdp_video_vsync_intr_done(void *arg) struct mdss_mdp_video_ctx *ctx = ctl->intf_ctx[MASTER_CTX]; struct mdss_mdp_vsync_handler *tmp; ktime_t vsync_time; + u32 ctl_flush_bits = 0; if (!ctx) { pr_err("invalid ctx\n"); @@ -970,10 +971,13 @@ static void mdss_mdp_video_vsync_intr_done(void *arg) mdss_debug_frc_add_vsync_sample(ctl, vsync_time); - MDSS_XLOG(ctl->num, ctl->vsync_cnt, ctl->vsync_cnt); + ctl_flush_bits = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_FLUSH); - pr_debug("intr ctl=%d vsync cnt=%u vsync_time=%d\n", - ctl->num, ctl->vsync_cnt, (int)ktime_to_ms(vsync_time)); + MDSS_XLOG(ctl->num, ctl->vsync_cnt, ctl_flush_bits); + + pr_debug("intr ctl=%d vsync cnt=%u vsync_time=%d ctl_flush=%d\n", + ctl->num, ctl->vsync_cnt, (int)ktime_to_ms(vsync_time), + ctl_flush_bits); ctx->polling_en = false; complete_all(&ctx->vsync_comp); @@ -1716,7 +1720,7 @@ static void mdss_mdp_fetch_start_config(struct mdss_mdp_video_ctx *ctx, mdata = ctl->mdata; - pinfo->prg_fet = mdss_mdp_get_prefetch_lines(pinfo); + pinfo->prg_fet = mdss_mdp_get_prefetch_lines(pinfo, true); if (!pinfo->prg_fet) { pr_debug("programmable fetch is not needed/supported\n"); @@ -1735,7 +1739,7 @@ static void mdss_mdp_fetch_start_config(struct mdss_mdp_video_ctx *ctx, * Fetch should always be outside the active lines. If the fetching * is programmed within active region, hardware behavior is unknown. */ - v_total = mdss_panel_get_vtotal(pinfo); + v_total = mdss_panel_get_vtotal_fixed(pinfo); h_total = mdss_panel_get_htotal(pinfo, true); fetch_start = (v_total - pinfo->prg_fet) * h_total + 1; diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 74ca83294fa3..3de390608179 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -3760,8 +3760,7 @@ static void dfps_update_panel_params(struct mdss_panel_data *pdata, dfps_update_fps(&pdata->panel_info, new_fps); pdata->panel_info.prg_fet = - mdss_mdp_get_prefetch_lines(&pdata->panel_info); - + mdss_mdp_get_prefetch_lines(&pdata->panel_info, false); } else if (pdata->panel_info.dfps_update == DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP) { int add_h_pixels; diff --git a/drivers/video/fbdev/msm/mdss_panel.c b/drivers/video/fbdev/msm/mdss_panel.c index de69d632b6b0..4e61fd85b7a0 100644 --- a/drivers/video/fbdev/msm/mdss_panel.c +++ b/drivers/video/fbdev/msm/mdss_panel.c @@ -633,6 +633,7 @@ void mdss_panel_info_from_timing(struct mdss_panel_timing *pt, pinfo->yres = pt->yres; pinfo->lcdc.v_front_porch = pt->v_front_porch; + pinfo->lcdc.v_front_porch_fixed = pt->v_front_porch; pinfo->lcdc.v_back_porch = pt->v_back_porch; pinfo->lcdc.v_pulse_width = pt->v_pulse_width; diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index c66d5aba790a..be6d44f0196a 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -289,6 +289,7 @@ struct lcd_panel_info { u32 h_pulse_width; u32 v_back_porch; u32 v_front_porch; + u32 v_front_porch_fixed; u32 v_pulse_width; u32 border_clr; u32 underflow_clr; @@ -926,6 +927,23 @@ static inline u32 mdss_panel_get_framerate(struct mdss_panel_info *panel_info, return frame_rate; } +/* + * mdss_panel_get_vtotal_fixed() - return panel device tree vertical height + * @pinfo: Pointer to panel info containing all panel information + * + * Returns the total height as defined in panel device tree including any + * blanking regions which are not visible to user but used to calculate + * panel clock. + */ +static inline int mdss_panel_get_vtotal_fixed(struct mdss_panel_info *pinfo) +{ + return pinfo->yres + pinfo->lcdc.v_back_porch + + pinfo->lcdc.v_front_porch_fixed + + pinfo->lcdc.v_pulse_width+ + pinfo->lcdc.border_top + + pinfo->lcdc.border_bottom; +} + /* * mdss_panel_get_vtotal() - return panel vertical height * @pinfo: Pointer to panel info containing all panel information -- GitLab From 9379f1ed4167052214a34771d9ab6338411eb67e Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Wed, 18 Jul 2018 15:20:43 +0530 Subject: [PATCH 556/604] diag: Add NULL checks for the mask and mask pointer The chances of accessing uninitialized mask is prevented by adding null pointer checks for the mask structure and its member pointer. Change-Id: Ibf0467228794b773fc2537d34f1da6719bbb975a Signed-off-by: Manoj Prabhu B --- drivers/char/diag/diag_masks.c | 23 ++++++++++++++++++++--- drivers/char/diag/diagfwd_cntl.c | 4 ++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index 44cf56cd8921..a3c19c4a6e5c 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -169,6 +169,9 @@ static void diag_send_log_mask_update(uint8_t peripheral, int equip_id) mutex_lock(&mask_info->lock); for (i = 0; i < MAX_EQUIP_ID; i++, mask++) { + if (!mask->ptr) + continue; + if (equip_id != i && equip_id != ALL_EQUIP_ID) continue; @@ -399,6 +402,8 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) } for (i = 0; i < msg_mask_tbl_count_local; i++, mask++) { + if (!mask->ptr) + continue; mutex_lock(&driver->msg_mask_lock); if (((mask->ssid_first > first) || (mask->ssid_last_tools < last)) && first != ALL_SSID) { @@ -642,6 +647,8 @@ static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len, rsp.padding = 0; build_mask = (struct diag_msg_mask_t *)msg_bt_mask.ptr; for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) { + if (!build_mask->ptr) + continue; if (build_mask->ssid_first != req->ssid_first) continue; num_entries = req->ssid_last - req->ssid_first + 1; @@ -718,6 +725,8 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, return -EINVAL; } for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + if (!mask->ptr) + continue; if ((req->ssid_first < mask->ssid_first) || (req->ssid_first > mask->ssid_last_tools)) { continue; @@ -784,6 +793,8 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, return -EINVAL; } for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + if (!mask->ptr) + continue; if (i < (driver->msg_mask_tbl_count - 1)) { mask_next = mask; mask_next++; @@ -1551,7 +1562,8 @@ static int diag_create_msg_mask_table(void) mutex_lock(&msg_mask.lock); mutex_lock(&driver->msg_mask_lock); driver->msg_mask_tbl_count = MSG_MASK_TBL_CNT; - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + for (i = 0; (i < driver->msg_mask_tbl_count) && mask; + i++, mask++) { range.ssid_first = msg_mask_tbl[i].ssid_first; range.ssid_last = msg_mask_tbl[i].ssid_last; err = diag_create_msg_mask_table_entry(mask, &range); @@ -1575,7 +1587,8 @@ static int diag_create_build_time_mask(void) mutex_lock(&driver->msg_mask_lock); driver->bt_msg_mask_tbl_count = MSG_MASK_TBL_CNT; build_mask = (struct diag_msg_mask_t *)msg_bt_mask.ptr; - for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) { + for (i = 0; (i < driver->bt_msg_mask_tbl_count) && build_mask; + i++, build_mask++) { range.ssid_first = msg_mask_tbl[i].ssid_first; range.ssid_last = msg_mask_tbl[i].ssid_last; err = diag_create_msg_mask_table_entry(build_mask, &range); @@ -1698,7 +1711,7 @@ static int diag_create_log_mask_table(void) mutex_lock(&log_mask.lock); mask = (struct diag_log_mask_t *)(log_mask.ptr); - for (i = 0; i < MAX_EQUIP_ID; i++, mask++) { + for (i = 0; (i < MAX_EQUIP_ID) && mask; i++, mask++) { mask->equip_id = i; mask->num_items = LOG_GET_ITEM_NUM(log_code_last_tbl[i]); mask->num_items_tools = mask->num_items; @@ -2080,6 +2093,8 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, return -EINVAL; } for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + if (!mask->ptr) + continue; ptr = mask_info->update_buf; len = 0; mutex_lock(&mask->lock); @@ -2151,6 +2166,8 @@ int diag_copy_to_user_log_mask(char __user *buf, size_t count, return -EINVAL; } for (i = 0; i < MAX_EQUIP_ID; i++, mask++) { + if (!mask->ptr) + continue; ptr = mask_info->update_buf; len = 0; mutex_lock(&mask->lock); diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c index ac4394b308ba..a6d5ca8a952a 100644 --- a/drivers/char/diag/diagfwd_cntl.c +++ b/drivers/char/diag/diagfwd_cntl.c @@ -668,7 +668,7 @@ static void process_ssid_range_report(uint8_t *buf, uint32_t len, mask_ptr = (struct diag_msg_mask_t *)msg_mask.ptr; found = 0; for (j = 0; j < driver->msg_mask_tbl_count; j++, mask_ptr++) { - if (!mask_ptr || !ssid_range) { + if (!mask_ptr->ptr || !ssid_range) { found = 1; break; } @@ -747,7 +747,7 @@ static void diag_build_time_mask_update(uint8_t *buf, num_items = range->ssid_last - range->ssid_first + 1; for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) { - if (!build_mask) { + if (!build_mask->ptr) { found = 1; break; } -- GitLab From 6fb2e4dc2af9fe4f42fbc56ab612d20394ad3e44 Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Tue, 31 Jul 2018 15:25:06 +0530 Subject: [PATCH 557/604] msm: mhi_dev: Update channel numbers for ADB client Update ADB client channel numbers to 36 and 37 to align with the MHI specification. Change-Id: I5535913d413cffa814fb72192089244628cadae4 Signed-off-by: Siva Kumar Akkireddi --- drivers/platform/msm/mhi_dev/mhi.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.h b/drivers/platform/msm/mhi_dev/mhi.h index 35590210bfe6..26baa6472636 100644 --- a/drivers/platform/msm/mhi_dev/mhi.h +++ b/drivers/platform/msm/mhi_dev/mhi.h @@ -698,8 +698,8 @@ enum mhi_client_channel { MHI_CLIENT_DUN_IN = 33, MHI_CLIENT_IP_SW_0_OUT = 34, MHI_CLIENT_IP_SW_0_IN = 35, - MHI_CLIENT_IP_SW_1_OUT = 36, - MHI_CLIENT_IP_SW_1_IN = 37, + MHI_CLIENT_ADB_OUT = 36, + MHI_CLIENT_ADB_IN = 37, MHI_CLIENT_IP_SW_2_OUT = 38, MHI_CLIENT_IP_SW_2_IN = 39, MHI_CLIENT_IP_SW_3_OUT = 40, @@ -710,8 +710,6 @@ enum mhi_client_channel { MHI_CLIENT_SMCT_IN = 45, MHI_CLIENT_IP_SW_4_OUT = 46, MHI_CLIENT_IP_SW_4_IN = 47, - MHI_CLIENT_ADB_OUT = 48, - MHI_CLIENT_ADB_IN = 49, MHI_MAX_SOFTWARE_CHANNELS, MHI_CLIENT_TEST_OUT = 60, MHI_CLIENT_TEST_IN = 61, -- GitLab From 00b41115f1d5320c8b0356e60ecaa1de27ec8675 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Mon, 30 Jul 2018 17:45:11 +0800 Subject: [PATCH 558/604] power: smb5-lib: Load HW JEITA config in general psy events Currently, JEITA configuration is updated with a BMS event. There is a chance that BMS is not updating with a long time and that would cause the JEITA configuration is not loaded and JEITA is mis-triggered, so update the JEITA configuration in general power supply events and defer the updating if BMS power supply is not ready. Change-Id: Ib3b792ea8fc64083ea14b7ea5a00565815a0cec6 Signed-off-by: Fenglin Wu --- drivers/power/supply/qcom/smb5-lib.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index be0832ee9228..457a04fcad94 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -688,10 +688,11 @@ static int smblib_notifier_call(struct notifier_block *nb, chg->bms_psy = psy; if (ev == PSY_EVENT_PROP_CHANGED) schedule_work(&chg->bms_update_work); - if (!chg->jeita_configured) - schedule_work(&chg->jeita_update_work); } + if (!chg->jeita_configured) + schedule_work(&chg->jeita_update_work); + if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel")) { chg->pl.psy = psy; schedule_work(&chg->pl_update_work); @@ -3919,6 +3920,10 @@ static void jeita_update_work(struct work_struct *work) goto out; } + /* if BMS is not ready, defer the work */ + if (!chg->bms_psy) + return; + rc = power_supply_get_property(chg->bms_psy, POWER_SUPPLY_PROP_RESISTANCE_ID, &val); if (rc < 0) { @@ -3926,6 +3931,10 @@ static void jeita_update_work(struct work_struct *work) goto out; } + /* if BMS hasn't read out the batt_id yet, defer the work */ + if (val.intval <= 0) + return; + pnode = of_batterydata_get_best_profile(batt_node, val.intval / 1000, NULL); if (IS_ERR(pnode)) { -- GitLab From dab14290e0743fa08789c501762337391881b399 Mon Sep 17 00:00:00 2001 From: Rajeswari Konda Date: Fri, 6 Jul 2018 17:56:00 +0530 Subject: [PATCH 559/604] defconfig: disable DEBUG PAGEALLOC configs for msm8909w To improve performance on 8909w devices Change-Id: I4debe05e5463b36b5a8a85c476560df2d86fe2b7 Signed-off-by: Rajeswari Konda --- arch/arm/configs/msm8909w_defconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig index 2e545d8d18cf..2abc5c08c23d 100644 --- a/arch/arm/configs/msm8909w_defconfig +++ b/arch/arm/configs/msm8909w_defconfig @@ -462,9 +462,7 @@ CONFIG_DEBUG_INFO=y CONFIG_FRAME_WARN=2048 CONFIG_PAGE_OWNER=y CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y -CONFIG_DEBUG_PAGEALLOC=y CONFIG_SLUB_DEBUG_PANIC_ON=y -CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y CONFIG_DEBUG_STACK_USAGE=y CONFIG_DEBUG_MEMORY_INIT=y CONFIG_LOCKUP_DETECTOR=y -- GitLab From 20e714b5fe959ad832cef3d700a71ced8f630bc3 Mon Sep 17 00:00:00 2001 From: Petar Sivenov Date: Tue, 5 Jun 2018 12:20:24 +0300 Subject: [PATCH 560/604] qca402x: qca402 driver interface header qca402 Quartz communication driver interface header. Contains ioctl and type definitions for buffer and message operations. Change-Id: I2f2894ad555cb58c64c68b94e2b74f24ca6b4b67 Signed-off-by: Petar Sivenov --- include/uapi/media/Kbuild | 1 + include/uapi/media/msmb_qca.h | 62 +++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 include/uapi/media/msmb_qca.h diff --git a/include/uapi/media/Kbuild b/include/uapi/media/Kbuild index 1aa2a1962ca2..7f93c1c25b99 100644 --- a/include/uapi/media/Kbuild +++ b/include/uapi/media/Kbuild @@ -26,5 +26,6 @@ header-y += msm_media_info.h header-y += msmb_camera.h header-y += msmb_generic_buf_mgr.h header-y += msmb_isp.h +header-y += msmb_qca.h header-y += msmb_ispif.h header-y += msmb_pproc.h \ No newline at end of file diff --git a/include/uapi/media/msmb_qca.h b/include/uapi/media/msmb_qca.h new file mode 100644 index 000000000000..02a6b1f6d380 --- /dev/null +++ b/include/uapi/media/msmb_qca.h @@ -0,0 +1,62 @@ +/* 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 __UAPI_LINUX_MSMB_QCA402X_H +#define __UAPI_LINUX_MSMB_QCA402X_H + +#include +#include +#define QCA402X_HTC + +#define MSM_QCA_EVENT_ENQ_BUF 0 +#define MSM_QCA_EVENT_SEND_MSG 1 +#define MSM_QCA_EVENT_RECV_MSG 2 + +struct msm_qca_message_type { + __u64 header; + __u64 buff_addr; + int fd; + __u32 header_size; + __u32 data_size; + __u8 cmd; + __u8 channel_id; + __u8 is_ion_data; + __u8 last_data; +}; + +struct msm_qca_event_type { + __u8 cmd; + __u8 channel_id; +}; + +struct msm_qca_event_list_type { + __u64 events; + __u32 num_events; +}; + +#define MSM_QCA402X_ENQUEUE_BUFFER \ + _IOWR(0xdd, 1, struct msm_qca_message_type) +#define MSM_QCA402X_SEND_MESSAGE \ + _IOWR(0xdd, 2, struct msm_qca_message_type) +#define MSM_QCA402X_RECEIVE_MESSAGE \ + _IOWR(0xdd, 3, struct msm_qca_message_type) +#define MSM_QCA402X_FLUSH_BUFFERS \ + _IOWR(0xdd, 4, struct msm_qca_event_list_type) +#define MSM_QCA402X_ABORT_MESSAGE \ + _IOWR(0xdd, 5, struct msm_qca_event_list_type) +#define MSM_QCA402X_REGISTER_EVENT \ + _IOWR(0xdd, 6, struct msm_qca_event_list_type) +#define MSM_QCA402X_UNREGISTER_EVENT \ + _IOWR(0xdd, 7, struct msm_qca_event_list_type) +#endif /*__UAPI_LINUX_MSMB_QCA402X_H*/ + -- GitLab From 9f4718f4b1de5f1a2190de9be799af4885798014 Mon Sep 17 00:00:00 2001 From: Sayali Lokhande Date: Tue, 31 Jul 2018 13:27:18 +0530 Subject: [PATCH 561/604] scsi: ufs: Avoid writing null to Boot LUN enable attribute In ufshcd_query_ioctl(), if attribute value passed in user buffer is null, boot feature will be disabled and device enters in EDL mode. To fix this, add check in ioctl path to avoid writing 00h to Boot LUN enable attribute. Change-Id: Ib7983075de3d6968a215cbc8b79c42a20fcc71a4 Signed-off-by: Sayali Lokhande --- drivers/scsi/ufs/ufshcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 0d72cd07e9b7..8bdcbad69dd7 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -8368,7 +8368,7 @@ static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer) switch (ioctl_data->idn) { case QUERY_ATTR_IDN_BOOT_LU_EN: index = 0; - if (att > QUERY_ATTR_IDN_BOOT_LU_EN_MAX) { + if (!att || att > QUERY_ATTR_IDN_BOOT_LU_EN_MAX) { dev_err(hba->dev, "%s: Illegal ufs query ioctl data, opcode 0x%x, idn 0x%x, att 0x%x\n", __func__, ioctl_data->opcode, -- GitLab From 10e2bc5d343d4e788d0565e912e5f26ada7eadd0 Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Wed, 1 Aug 2018 11:57:33 +0530 Subject: [PATCH 562/604] msm: kgsl: Don't halt dispatcher if device is not in SUSPEND state Add a check to make sure device actually transitioned to SUSPEND state before halting dispatcher. kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND) can return zero without actually changing state to SUSPEND if device state is NONE or INIT. Change-Id: I4a5a69007c71651ea2cf7fa7360c960c6856031e Signed-off-by: Deepak Kumar --- drivers/gpu/msm/kgsl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 3b55fc6f74ed..a355eb191499 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -764,7 +764,7 @@ static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state) mutex_lock(&device->mutex); status = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); - if (status == 0) + if (status == 0 && device->state == KGSL_STATE_SUSPEND) device->ftbl->dispatcher_halt(device); mutex_unlock(&device->mutex); -- GitLab From 4fae0d130fa38d32da174621c864f84809a7ada9 Mon Sep 17 00:00:00 2001 From: Frank Liu Date: Fri, 27 Jul 2018 14:32:53 +0800 Subject: [PATCH 563/604] cnss2: Add support for PCIe WLAN IPA uc SMMU feature To add support for PCIe WLAN IPA uc SMMU feature, prvoide related platform api for wlan driver to get the smmu map handle and do the mapping. Change-Id: I672b1a48879ada65b3ddb3f16c4bd787dc1b70a6 Signed-off-by: Frank Liu --- drivers/net/wireless/cnss2/pci.c | 66 ++++++++++++++++++++++++++++++++ drivers/net/wireless/cnss2/pci.h | 2 + include/net/cnss2.h | 3 ++ 3 files changed, 71 insertions(+) diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 161e68eefa65..c1fc8ba3e4a2 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -1357,6 +1357,61 @@ void cnss_pci_fw_boot_timeout_hdlr(struct cnss_pci_data *pci_priv) CNSS_REASON_TIMEOUT); } +struct dma_iommu_mapping *cnss_smmu_get_mapping(struct device *dev) +{ + struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev)); + + if (!pci_priv) + return NULL; + + return pci_priv->smmu_mapping; +} +EXPORT_SYMBOL(cnss_smmu_get_mapping); + +int cnss_smmu_map(struct device *dev, + phys_addr_t paddr, uint32_t *iova_addr, size_t size) +{ + struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev)); + unsigned long iova; + size_t len; + int ret = 0; + + if (!pci_priv) + return -ENODEV; + + if (!iova_addr) { + cnss_pr_err("iova_addr is NULL, paddr %pa, size %zu\n", + &paddr, size); + return -EINVAL; + } + + len = roundup(size + paddr - rounddown(paddr, PAGE_SIZE), PAGE_SIZE); + iova = roundup(pci_priv->smmu_iova_ipa_start, PAGE_SIZE); + + if (iova >= + (pci_priv->smmu_iova_ipa_start + pci_priv->smmu_iova_ipa_len)) { + cnss_pr_err("No IOVA space to map, iova %lx, smmu_iova_ipa_start %pad, smmu_iova_ipa_len %zu\n", + iova, + &pci_priv->smmu_iova_ipa_start, + pci_priv->smmu_iova_ipa_len); + return -ENOMEM; + } + + ret = iommu_map(pci_priv->smmu_mapping->domain, iova, + rounddown(paddr, PAGE_SIZE), len, + IOMMU_READ | IOMMU_WRITE); + if (ret) { + cnss_pr_err("PA to IOVA mapping failed, ret %d\n", ret); + return ret; + } + + pci_priv->smmu_iova_ipa_start = iova + len; + *iova_addr = (uint32_t)(iova + paddr - rounddown(paddr, PAGE_SIZE)); + + return 0; +} +EXPORT_SYMBOL(cnss_smmu_map); + int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info) { struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev)); @@ -2150,6 +2205,17 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, &pci_priv->smmu_iova_start, pci_priv->smmu_iova_len); + res = platform_get_resource_byname(plat_priv->plat_dev, + IORESOURCE_MEM, + "smmu_iova_ipa"); + if (res) { + pci_priv->smmu_iova_ipa_start = res->start; + pci_priv->smmu_iova_ipa_len = resource_size(res); + cnss_pr_dbg("smmu_iova_ipa_start: %pa, smmu_iova_ipa_len: %zu\n", + &pci_priv->smmu_iova_ipa_start, + pci_priv->smmu_iova_ipa_len); + } + ret = cnss_pci_init_smmu(pci_priv); if (ret) { cnss_pr_err("Failed to init SMMU, err = %d\n", ret); diff --git a/drivers/net/wireless/cnss2/pci.h b/drivers/net/wireless/cnss2/pci.h index 79f66ac1bb99..c8de4d74a187 100644 --- a/drivers/net/wireless/cnss2/pci.h +++ b/drivers/net/wireless/cnss2/pci.h @@ -63,6 +63,8 @@ struct cnss_pci_data { bool smmu_s1_enable; dma_addr_t smmu_iova_start; size_t smmu_iova_len; + dma_addr_t smmu_iova_ipa_start; + size_t smmu_iova_ipa_len; void __iomem *bar; struct cnss_msi_config *msi_config; u32 msi_ep_base_data; diff --git a/include/net/cnss2.h b/include/net/cnss2.h index 342907d3a68d..c5ccee4db262 100644 --- a/include/net/cnss2.h +++ b/include/net/cnss2.h @@ -159,6 +159,9 @@ extern int cnss_get_fw_files_for_target(struct device *dev, u32 target_type, u32 target_version); extern int cnss_get_platform_cap(struct device *dev, struct cnss_platform_cap *cap); +extern struct dma_iommu_mapping *cnss_smmu_get_mapping(struct device *dev); +extern int cnss_smmu_map(struct device *dev, + phys_addr_t paddr, uint32_t *iova_addr, size_t size); extern int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info); extern int cnss_request_bus_bandwidth(struct device *dev, int bandwidth); extern int cnss_power_up(struct device *dev); -- GitLab From 1318a174141eb742035de5e595e19962d39b049e Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Wed, 1 Aug 2018 18:42:20 +0530 Subject: [PATCH 564/604] power: qpnp-qg: Skip reading battery-temp in the resume path Reading the battery-temperature in the system_resume path is not required. This also leads to VADC stalling as the EOC irq is not enabled in the no_irq() callback. Change-Id: I417d46cc07f455792906a18f4b6dc8e5ca8ca3df Signed-off-by: Anirudh Ghayal --- drivers/power/supply/qcom/qpnp-qg.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 613fb74263ab..fede66fd5741 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -3442,7 +3442,7 @@ static int process_resume(struct qpnp_qg *chip) { u8 status2 = 0, rt_status = 0; u32 ocv_uv = 0, ocv_raw = 0; - int rc, batt_temp = 0; + int rc; /* skip if profile is not loaded */ if (!chip->profile_loaded) @@ -3460,11 +3460,6 @@ static int process_resume(struct qpnp_qg *chip) pr_err("Failed to read good_ocv, rc=%d\n", rc); return rc; } - rc = qg_get_battery_temp(chip, &batt_temp); - if (rc < 0) { - pr_err("Failed to read BATT_TEMP, rc=%d\n", rc); - return rc; - } /* Clear suspend data as there has been a GOOD OCV */ memset(&chip->kdata, 0, sizeof(chip->kdata)); -- GitLab From 14baf84a1d52364d1e38ec4accda8c978cc1619c Mon Sep 17 00:00:00 2001 From: Karthik Parsha Date: Wed, 11 Jun 2014 22:13:01 -0700 Subject: [PATCH 565/604] qcom: rpm-smd: Force smd channel update in interrupt lock context In the power collapse path, when checking for availability of an ack from rpm, use smd_is_pkt_avail. This api is designed to be used with interrupts disabled, and will be able to poll for acks from rpm. Check for upto 500us to check availability of this ack. Change-Id: Ie99d0bb9ae17445872e0c37f0797cac3a221daa4 Signed-off-by: Karthik Parsha Signed-off-by: Maulik Shah --- drivers/soc/qcom/rpm-smd.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/soc/qcom/rpm-smd.c b/drivers/soc/qcom/rpm-smd.c index 675551af1b79..7a4ab97aca6b 100644 --- a/drivers/soc/qcom/rpm-smd.c +++ b/drivers/soc/qcom/rpm-smd.c @@ -751,6 +751,33 @@ static int msm_rpm_read_sleep_ack(void) if (glink_enabled) ret = msm_rpm_glink_rx_poll(glink_data->glink_handle); else { + int timeout = 10; + + while (timeout) { + if (smd_is_pkt_avail(msm_rpm_data.ch_info)) + break; + /* + * Sleep for 50us at a time before checking + * for packet availability. The 50us is based + * on the the max time rpm could take to process + * and send an ack for sleep set request. + */ + udelay(50); + timeout--; + } + + /* + * On timeout return an error and exit the spinlock + * control on this cpu. This will allow any other + * core that has wokenup and trying to acquire the + * spinlock from being locked out. + */ + + if (!timeout) { + pr_err("Timed out waiting for RPM ACK\n"); + return -EAGAIN; + } + ret = msm_rpm_read_smd_data(buf); if (!ret) ret = smd_is_pkt_avail(msm_rpm_data.ch_info); -- GitLab From 914d085861c56585c3c2f9f1ce49bbb9547fb87f Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Wed, 13 Dec 2017 11:11:16 +0100 Subject: [PATCH 566/604] sched: fix softirq time accounting softirq time accounting is broken on v4.9.x if ksoftirqd runs. With CONFIG_IRQ_TIME_ACCOUNTING=y # CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set this test code: struct tasklet_struct tasklet; static void delay_tasklet(unsigned long data) { udelay(10); tasklet_schedule(&tasklet); } tasklet_init(&tasklet, delay_tasklet, 0); tasklet_schedule(&tasklet); results in: $ while :; do grep cpu0 /proc/stat; done cpu0 5 0 80 25 16 107 1 0 0 0 cpu0 5 0 80 25 16 107 0 0 0 0 cpu0 5 0 80 25 16 107 0 0 0 0 cpu0 5 0 80 25 16 107 0 0 0 0 cpu0 5 0 81 25 16 107 0 0 0 0 cpu0 5 0 81 25 16 107 1 0 0 0 cpu0 5 0 81 25 16 108 18446744073709551615 0 0 0 cpu0 5 0 81 25 16 108 18446744073709551615 0 0 0 cpu0 5 0 81 25 16 108 18446744073709551615 0 0 0 cpu0 5 0 81 25 16 108 0 0 0 0 cpu0 6 0 81 25 16 108 0 0 0 0 cpu0 6 0 81 25 16 108 0 0 0 0 As can be seen, the softirq numbers are totally bogus. When ksoftirq is running, irqtime_account_process_tick() increments cpustat[CPUSTAT_SOFTIRQ]. This causes the "nsecs_to_cputime64(irqtime) - cpustat[CPUSTAT_SOFTIRQ]" calculation in irqtime_account_update() to underflow the next time a softirq is handled leading to the above values. The underflow bug was added by 57430218317e5b280 ("sched/cputime: Count actually elapsed irq & softirq time"). But ksoftirqd accounting was wrong even in earlier kernels. In earlier kernels, after a ksoftirq run, the kernel would simply stop accounting softirq time spent outside of ksoftirqd until that (accumulated) time exceeded the time for which ksofirqd previously had run. Fix both the underflow and the wrong accounting by using a counter specifically for the non-ksoftirqd softirq case. This code has been fixed in current mainline by a499a5a14db ("sched/cputime: Increment kcpustat directly on irqtime account") [note also the followup 25e2d8c1b9e327e ("sched/cputime: Fix ksoftirqd cputime accounting regression")], but that patch is a part of the many changes for eliminating of cputime_t so it does not seem suitable for backport. Change-Id: I231b4e95df1201119360dee44e6d0847b2795ac5 Signed-off-by: Rabin Vincent Patch-mainline: linux-kernel @ 13 Dec 2017 11:11:16 Signed-off-by: Pavankumar Kondeti --- include/linux/kernel_stat.h | 1 + kernel/sched/cputime.c | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index 44fda64ad434..d0826f1739ac 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h @@ -33,6 +33,7 @@ enum cpu_usage_stat { struct kernel_cpustat { u64 cpustat[NR_STATS]; + u64 softirq_no_ksoftirqd; }; struct kernel_stat { diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 50f2ea890b6a..a7c4b4caf108 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -84,12 +84,19 @@ EXPORT_SYMBOL_GPL(irqtime_account_irq); static cputime_t irqtime_account_update(u64 irqtime, int idx, cputime_t maxtime) { u64 *cpustat = kcpustat_this_cpu->cpustat; + u64 base = cpustat[idx]; cputime_t irq_cputime; - irq_cputime = nsecs_to_cputime64(irqtime) - cpustat[idx]; + if (idx == CPUTIME_SOFTIRQ) + base = kcpustat_this_cpu->softirq_no_ksoftirqd; + + irq_cputime = nsecs_to_cputime64(irqtime) - base; irq_cputime = min(irq_cputime, maxtime); cpustat[idx] += irq_cputime; + if (idx == CPUTIME_SOFTIRQ) + kcpustat_this_cpu->softirq_no_ksoftirqd += irq_cputime; + return irq_cputime; } -- GitLab From 578e1a4293eea0791fe02a7732572a28b464c0b0 Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Fri, 15 Jun 2018 10:33:26 -0700 Subject: [PATCH 567/604] msm: ipa3: fix the fast_map issue Currently ipa driver AP-CB always enables fast_map flag when calling smmu API. Make fix to enable it when IPA dtsi specifies fast_map flag. CRs-Fixed: 2261733 Change-Id: I325ead58b6873f798af14ffe2182aa48a008141d Signed-off-by: Skylar Chang --- drivers/platform/msm/ipa/ipa_v3/ipa.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 8a773e4d84c6..5bfb8e4d0304 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -6205,15 +6205,17 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) } IPADBG("AP/USB SMMU atomic set\n"); - if (iommu_domain_set_attr(cb->mapping->domain, + if (smmu_info.fast_map) { + if (iommu_domain_set_attr(cb->mapping->domain, DOMAIN_ATTR_FAST, &fast)) { - IPAERR("couldn't set fast map\n"); - arm_iommu_release_mapping(cb->mapping); - cb->valid = false; - return -EIO; + IPAERR("couldn't set fast map\n"); + arm_iommu_release_mapping(cb->mapping); + cb->valid = false; + return -EIO; + } + IPADBG("SMMU fast map set\n"); } - IPADBG("SMMU fast map set\n"); } pr_info("IPA smmu_info.s1_bypass_arr[AP]=%d smmu_info.fast_map=%d\n", -- GitLab From 9a9a6b415bfe6114fb703f3b272710cec474e1e4 Mon Sep 17 00:00:00 2001 From: Himanshu Agrawal Date: Fri, 29 Jun 2018 13:08:52 +0530 Subject: [PATCH 568/604] ARM: dts: msm: Correct the haptics DT properties for PMI8937 - Include msm8917-pmi8937.dtsi in msm8917-qrd.dtsi for vibrator driver to probe as overlay is enabled. - Correct the haptics device tree properties to be aligned with the leds-qpnp-haptics driver. - Included spmi.h and irq.h as fix for compilation. - Removed led_flash0 entry from msm8917-qrd-overlay.dts as being duplicated after including msm8917-pmi8937.dtsi. Change-Id: If88648dcf799d40817e14c823aec1e1b8787feaa Signed-off-by: Himanshu Agrawal Signed-off-by: Naitik Bharadiya --- .../boot/dts/qcom/msm8917-qrd-overlay.dts | 9 -------- arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi | 1 + arch/arm64/boot/dts/qcom/pmi8937.dtsi | 22 ++++++++----------- 3 files changed, 10 insertions(+), 22 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8917-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/msm8917-qrd-overlay.dts index 9b4d8f4b3404..c0dc21787dd4 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/msm8917-qrd-overlay.dts @@ -110,13 +110,4 @@ qcom,key-codes = <139 172 158>; qcom,y-offset = <0>; }; - - led_flash0: qcom,camera-flash { - cell-index = <0>; - compatible = "qcom,camera-flash"; - qcom,flash-type = <1>; - qcom,flash-source = <&pmi8937_flash0>; - qcom,torch-source = <&pmi8937_torch0>; - qcom,switch-source = <&pmi8937_switch>; - }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi b/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi index 5c63ed376376..6a4c10e4aaba 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi @@ -13,6 +13,7 @@ #include #include "msm8917-camera-sensor-qrd.dtsi" #include "msm8937-mdss-panels.dtsi" +#include "msm8917-pmi8937.dtsi" &blsp1_uart2 { status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/pmi8937.dtsi b/arch/arm64/boot/dts/qcom/pmi8937.dtsi index c72225d3369a..829e73364538 100644 --- a/arch/arm64/boot/dts/qcom/pmi8937.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi8937.dtsi @@ -12,6 +12,8 @@ */ #include +#include +#include &spmi_bus { @@ -491,34 +493,28 @@ }; }; - pmi_haptic: qcom,haptic@c000 { - compatible = "qcom,qpnp-haptic"; + pmi_haptic: qcom,haptics@c000 { + compatible = "qcom,qpnp-haptics"; reg = <0xc000 0x100>; interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>, <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>; - interrupt-names = "sc-irq", "play-irq"; + interrupt-names = "hap-sc-irq", "hap-play-irq"; qcom,pmic-revid = <&pmi8937_revid>; vcc_pon-supply = <&pon_perph_reg>; qcom,play-mode = "direct"; qcom,wave-play-rate-us = <5263>; - qcom,actuator-type = "lra"; + qcom,actuator-type = <0>; qcom,wave-shape = "square"; qcom,vmax-mv = <2000>; qcom,ilim-ma = <800>; qcom,sc-deb-cycles = <8>; qcom,int-pwm-freq-khz = <505>; qcom,en-brake; - qcom,brake-pattern = [03 03 00 00]; - qcom,use-play-irq; - qcom,use-sc-irq; - qcom,wave-samples = [3e 3e 3e 3e 3e 3e 3e 3e]; + qcom,brake-pattern = <0x3 0x3 0x0 0x0>; + qcom,wave-samples = <0x3e 0x3e 0x3e 0x3e 0x3e + 0x3e 0x3e 0x3e>; qcom,wave-rep-cnt = <1>; qcom,wave-samp-rep-cnt = <1>; - qcom,lra-auto-res-mode="qwd"; - qcom,lra-high-z="opt1"; - qcom,lra-res-cal-period = <4>; - qcom,correct-lra-drive-freq; - qcom,misc-trim-error-rc19p2-clk-reg-present; }; }; }; -- GitLab From 6204ea6d4d02040a21ba92d37a4765819934dfed Mon Sep 17 00:00:00 2001 From: Qing Huang Date: Wed, 25 Jul 2018 14:25:39 +0800 Subject: [PATCH 569/604] drm/msm/sde: Fix race condition between enable/disable hist irq IPC suspend/resume will disable/enable hist interrupt by traversing the user_event_list. Hist interrupt mask register is also cleared and set in IPC suspend/resume. When register hist event is called from userspace, it will enable IRQ and mark irq state as enabled, then add it into user_event_list. If IPC suspend is coming before event is added into user_event_list and after enable IRQ, Hist interrupt mask register will be cleared but state has not been marked as disabled. Hence hist interrupt mask register will not be set when IPC resume since state was marked as enabled. Change-Id: I7dd9295af699ac408666a268d8f9aadc7b2e5e70 Signed-off-by: Qing Huang --- drivers/gpu/drm/msm/sde/sde_crtc.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index 8af82989ded7..cb4e82d30c56 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -6189,6 +6189,7 @@ static int _sde_crtc_event_enable(struct sde_kms *kms, unsigned long flags; bool found = false; int ret, i = 0; + bool add_event = false; crtc = to_sde_crtc(crtc_drm); spin_lock_irqsave(&crtc->spin_lock, flags); @@ -6238,11 +6239,24 @@ static int _sde_crtc_event_enable(struct sde_kms *kms, } INIT_LIST_HEAD(&node->irq.list); + + mutex_lock(&crtc->crtc_lock); ret = node->func(crtc_drm, true, &node->irq); + if (!ret) { + spin_lock_irqsave(&crtc->spin_lock, flags); + list_add_tail(&node->list, &crtc->user_event_list); + add_event = true; + spin_unlock_irqrestore(&crtc->spin_lock, flags); + } + mutex_unlock(&crtc->crtc_lock); + sde_power_resource_enable(&priv->phandle, kms->core_client, false); } + if (add_event) + return 0; + if (!ret) { spin_lock_irqsave(&crtc->spin_lock, flags); list_add_tail(&node->list, &crtc->user_event_list); -- GitLab From 15fb394fbc20d621e282d04ded4ca71f662e2f1f Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Thu, 2 Aug 2018 13:33:35 +0530 Subject: [PATCH 570/604] dma: qcom: Fix GPI compile errors for 32-bit builds Update format specifiers to conform to those recommended in the kernel documentation. Set upper 32-bit addresses to 0 on 32-bit builds. Change-Id: I076ce1f9930ea421d33d9f6e8f08d713176cc3fb Signed-off-by: Siva Kumar Akkireddi --- drivers/dma/qcom/gpi.c | 55 +++++++++++++++++++++++++---------------- include/linux/msm_gpi.h | 6 +++++ 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c index fff2ae91470a..0ce5bd95d25b 100644 --- a/drivers/dma/qcom/gpi.c +++ b/drivers/dma/qcom/gpi.c @@ -559,6 +559,7 @@ static inline u32 gpi_read_reg(struct gpii *gpii, void __iomem *addr) { u64 time = sched_clock(); unsigned int index = atomic_inc_return(&gpii->dbg_index) - 1; + unsigned long offset = addr - gpii->regs; u32 val; val = readl_relaxed(addr); @@ -568,13 +569,14 @@ static inline u32 gpi_read_reg(struct gpii *gpii, void __iomem *addr) (gpii->dbg_log + index)->val = val; (gpii->dbg_log + index)->read = true; GPII_REG(gpii, GPI_DBG_COMMON, "offset:0x%lx val:0x%x\n", - addr - gpii->regs, val); + offset, val); return val; } static inline void gpi_write_reg(struct gpii *gpii, void __iomem *addr, u32 val) { u64 time = sched_clock(); unsigned int index = atomic_inc_return(&gpii->dbg_index) - 1; + unsigned long offset = addr - gpii->regs; index &= (GPI_DBG_LOG_SIZE - 1); (gpii->dbg_log + index)->addr = addr; @@ -583,7 +585,7 @@ static inline void gpi_write_reg(struct gpii *gpii, void __iomem *addr, u32 val) (gpii->dbg_log + index)->read = false; GPII_REG(gpii, GPI_DBG_COMMON, "offset:0x%lx val:0x%x\n", - addr - gpii->regs, val); + offset, val); writel_relaxed(val, addr); } #else @@ -1244,11 +1246,13 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan, /* Event TR RP gen. don't match descriptor TR */ if (gpi_desc->wp != tre) { + phys_addr_t p_wp = to_physical(ch_ring, gpi_desc->wp); + phys_addr_t p_tre = to_physical(ch_ring, tre); + spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); GPII_ERR(gpii, gpii_chan->chid, - "EOT/EOB received for wrong TRE 0x%0llx != 0x%0llx\n", - to_physical(ch_ring, gpi_desc->wp), - to_physical(ch_ring, tre)); + "EOT/EOB received for wrong TRE %pa != %pa\n", + &p_wp, &p_tre); gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_EOT_DESC_MISMATCH, __LINE__); return; @@ -1331,11 +1335,13 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan, /* TRE Event generated didn't match descriptor's TRE */ if (gpi_desc->wp != ev_rp) { + phys_addr_t p_wp = to_physical(ch_ring, gpi_desc->wp); + phys_addr_t p_ev_rp = to_physical(ch_ring, ev_rp); + spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); GPII_ERR(gpii, gpii_chan->chid, - "EOT\EOB received for wrong TRE 0x%0llx != 0x%0llx\n", - to_physical(ch_ring, gpi_desc->wp), - to_physical(ch_ring, ev_rp)); + "EOT\EOB received for wrong TRE %pa != %pa\n", + &p_wp, &p_ev_rp); gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_EOT_DESC_MISMATCH, __LINE__); return; @@ -1588,12 +1594,12 @@ static int gpi_alloc_chan(struct gpii_chan *gpii_chan, bool send_alloc_cmd) { gpii_chan->ch_cntxt_base_reg, CNTXT_3_RING_BASE_MSB, - (u32)(ring->phys_addr >> 32), + MSM_GPI_RING_PHYS_ADDR_UPPER(ring), }, { /* program MSB of DB register with ring base */ gpii_chan->ch_cntxt_db_reg, CNTXT_5_RING_RP_MSB - CNTXT_4_RING_RP_LSB, - (u32)(ring->phys_addr >> 32), + MSM_GPI_RING_PHYS_ADDR_UPPER(ring), }, { gpii->regs, @@ -1682,13 +1688,13 @@ static int gpi_alloc_ev_chan(struct gpii *gpii) { gpii->ev_cntxt_base_reg, CNTXT_3_RING_BASE_MSB, - (u32)(ring->phys_addr >> 32), + MSM_GPI_RING_PHYS_ADDR_UPPER(ring), }, { /* program db msg with ring base msb */ gpii->ev_cntxt_db_reg, CNTXT_5_RING_RP_MSB - CNTXT_4_RING_RP_LSB, - (u32)(ring->phys_addr >> 32), + MSM_GPI_RING_PHYS_ADDR_UPPER(ring), }, { gpii->ev_cntxt_base_reg, @@ -1825,7 +1831,7 @@ static int gpi_alloc_ring(struct gpi_ring *ring, len = 1 << bit; ring->alloc_size = (len + (len - 1)); GPII_INFO(gpii, GPI_DBG_COMMON, - "#el:%u el_size:%u len:%u actual_len:%llu alloc_size:%lu\n", + "#el:%u el_size:%u len:%u actual_len:%llu alloc_size:%zx\n", elements, el_size, (elements * el_size), len, ring->alloc_size); ring->pre_aligned = dma_alloc_coherent(gpii->gpi_dev->dev, @@ -1833,7 +1839,7 @@ static int gpi_alloc_ring(struct gpi_ring *ring, &ring->dma_handle, GFP_KERNEL); if (!ring->pre_aligned) { GPII_CRITIC(gpii, GPI_DBG_COMMON, - "could not alloc size:%lu mem for ring\n", + "could not alloc size:%zx mem for ring\n", ring->alloc_size); return -ENOMEM; } @@ -1853,8 +1859,8 @@ static int gpi_alloc_ring(struct gpi_ring *ring, smp_wmb(); GPII_INFO(gpii, GPI_DBG_COMMON, - "phy_pre:0x%0llx phy_alig:0x%0llx len:%u el_size:%u elements:%u\n", - ring->dma_handle, ring->phys_addr, ring->len, ring->el_size, + "phy_pre:%pad phy_alig:%pa len:%u el_size:%u elements:%u\n", + &ring->dma_handle, &ring->phys_addr, ring->len, ring->el_size, ring->elements); return 0; @@ -2064,6 +2070,10 @@ struct dma_async_tx_descriptor *gpi_prep_slave_sg(struct dma_chan *chan, void *tre, *wp = NULL; const gfp_t gfp = GFP_ATOMIC; struct gpi_desc *gpi_desc; +#ifdef CONFIG_QCOM_GPI_DMA_DEBUG + phys_addr_t p_wp, p_rp; +#endif + GPII_VERB(gpii, gpii_chan->chid, "enter\n"); @@ -2106,9 +2116,12 @@ struct dma_async_tx_descriptor *gpi_prep_slave_sg(struct dma_chan *chan, gpi_desc->db = ch_ring->wp; gpi_desc->wp = wp; gpi_desc->gpii_chan = gpii_chan; - GPII_VERB(gpii, gpii_chan->chid, "exit wp:0x%0llx rp:0x%0llx\n", - to_physical(ch_ring, ch_ring->wp), - to_physical(ch_ring, ch_ring->rp)); +#ifdef CONFIG_QCOM_GPI_DMA_DEBUG + p_wp = to_physical(ch_ring, ch_ring->wp); + p_rp = to_physical(ch_ring, ch_ring->rp); +#endif + GPII_VERB(gpii, gpii_chan->chid, "exit wp:%pa rp:%pa\n", + &p_wp, &p_rp); return vchan_tx_prep(&gpii_chan->vc, &gpi_desc->vd, flags); } @@ -2558,8 +2571,8 @@ static struct dma_iommu_mapping *gpi_create_mapping(struct gpi_dev *gpi_dev) size = gpi_dev->iova_size; } - GPI_LOG(gpi_dev, "Creating iommu mapping of base:0x%llx size:%lu\n", - base, size); + GPI_LOG(gpi_dev, "Creating iommu mapping of base:%pad size:%zx\n", + &base, size); return arm_iommu_create_mapping(&platform_bus_type, base, size); } diff --git a/include/linux/msm_gpi.h b/include/linux/msm_gpi.h index 6fe4a4e81a51..08e34b60d762 100644 --- a/include/linux/msm_gpi.h +++ b/include/linux/msm_gpi.h @@ -151,6 +151,12 @@ enum msm_gpi_tre_type { #define MSM_GPI_I2C_CONFIG0_TRE_DWORD3(bei, ieot, ieob, ch) ((0x2 << 20) | \ (0x2 << 16) | (bei << 10) | (ieot << 9) | (ieob << 8) | ch) +#ifdef CONFIG_ARM64 +#define MSM_GPI_RING_PHYS_ADDR_UPPER(ring) ((u32)(ring->phys_addr >> 32)) +#else +#define MSM_GPI_RING_PHYS_ADDR_UPPER(ring) 0 +#endif + /* cmds to perform by using dmaengine_slave_config() */ enum msm_gpi_ctrl_cmd { MSM_GPI_INIT, -- GitLab From b83163e13809437a065f7e08b83554688cca35ad Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Thu, 2 Aug 2018 13:50:14 +0530 Subject: [PATCH 571/604] defconfig: msm: Enable GPI DMA for SDM670 Enable GPI driver in 32-bit builds for SDM670. Change-Id: I67570f1a04867d401f0fb7f8006a9757e5723051 Signed-off-by: Siva Kumar Akkireddi --- arch/arm/configs/sdm670_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/sdm670_defconfig b/arch/arm/configs/sdm670_defconfig index 082a53a7c4ec..0f60fd2ecc20 100644 --- a/arch/arm/configs/sdm670_defconfig +++ b/arch/arm/configs/sdm670_defconfig @@ -434,6 +434,8 @@ CONFIG_EDAC_MM_EDAC=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y CONFIG_DMADEVICES=y +CONFIG_QCOM_GPI_DMA=y +CONFIG_QCOM_GPI_DMA_DEBUG=y CONFIG_UIO=y CONFIG_UIO_MSM_SHAREDMEM=y CONFIG_STAGING=y -- GitLab From 47cdaad8eac601f91addbbadc01f95b8282b3e64 Mon Sep 17 00:00:00 2001 From: Animesh Kishore Date: Mon, 9 Jul 2018 20:32:06 +0530 Subject: [PATCH 572/604] mdss: mdp: Check for null pointer before access Check for null pointer before proceeding with register dump. Change-Id: Ic7785045676c8d73c065414a5470ea5dfb26936a Signed-off-by: Animesh Kishore --- drivers/video/fbdev/msm/mdss_mdp_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/msm/mdss_mdp_debug.c b/drivers/video/fbdev/msm/mdss_mdp_debug.c index bd4ee23ab23c..e7bd94a616aa 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_debug.c +++ b/drivers/video/fbdev/msm/mdss_mdp_debug.c @@ -1140,7 +1140,7 @@ static void __dump_mixer(struct seq_file *s, struct mdss_mdp_mixer *mixer, struct mdss_mdp_pipe *pipe; int i, cnt = 0; - if (!mixer) + if (!mixer || !mfd) return; seq_printf(s, "\n%s Mixer #%d res=%dx%d roi[%d, %d, %d, %d] %s\n", -- GitLab From 174e54129bf38036ee1091af4b222ced7fcbe35e Mon Sep 17 00:00:00 2001 From: Swetha Chikkaboraiah Date: Wed, 11 Jul 2018 16:59:58 +0530 Subject: [PATCH 573/604] ARM: dts: msm: add device tree for apq8017 Add device tree overlay support support for apq8017. Change-Id: I6b0850f9bb0ca79545425aeba7a2ad0422da8699 Signed-off-by: Swetha Chikkaboraiah --- arch/arm64/boot/dts/qcom/Makefile | 5 ++++- arch/arm64/boot/dts/qcom/apq8017-cdp-overlay.dts | 1 + arch/arm64/boot/dts/qcom/apq8017-cdp-wcd-rome-overlay.dts | 1 + arch/arm64/boot/dts/qcom/apq8017-mtp-overlay.dts | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index a798b5d5a575..fb44bce32661 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -304,7 +304,10 @@ dtbo-$(CONFIG_ARCH_MSM8917) += msm8917-mtp-overlay.dtbo \ msm8917-cdp-overlay.dtbo \ msm8917-cdp-ext-codec-overlay.dtbo \ msm8917-cdp-ml-touch-overlay.dtbo \ - msm8917-rcm-overlay.dtbo + msm8917-rcm-overlay.dtbo \ + apq8017-mtp-overlay.dtbo \ + apq8017-cdp-overlay.dtbo \ + apq8017-cdp-wcd-rome-overlay.dtbo dtbo-$(CONFIG_ARCH_MSM8953) += msm8953-mtp-overlay.dtbo \ msm8953-cdp-overlay.dtbo \ diff --git a/arch/arm64/boot/dts/qcom/apq8017-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/apq8017-cdp-overlay.dts index 6c8bef4ffafa..21e47bf556e8 100644 --- a/arch/arm64/boot/dts/qcom/apq8017-cdp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/apq8017-cdp-overlay.dts @@ -19,6 +19,7 @@ / { model = "Qualcomm Technologies, Inc. APQ8017-CDP"; qcom,board-id = <1 0>; + qcom,msm-id = <307 0x0>; }; &mdss_fb0 { diff --git a/arch/arm64/boot/dts/qcom/apq8017-cdp-wcd-rome-overlay.dts b/arch/arm64/boot/dts/qcom/apq8017-cdp-wcd-rome-overlay.dts index 055c457733ee..4f07399dfa15 100644 --- a/arch/arm64/boot/dts/qcom/apq8017-cdp-wcd-rome-overlay.dts +++ b/arch/arm64/boot/dts/qcom/apq8017-cdp-wcd-rome-overlay.dts @@ -21,6 +21,7 @@ model = "Qualcomm Technologies, Inc. APQ8017-CDP \ with WCD codec/Rome card"; qcom,board-id = <1 2>; + qcom,msm-id = <307 0x0>; }; &blsp1_uart1 { diff --git a/arch/arm64/boot/dts/qcom/apq8017-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/apq8017-mtp-overlay.dts index 23bbb0f91189..0b958ee7cdfa 100644 --- a/arch/arm64/boot/dts/qcom/apq8017-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/apq8017-mtp-overlay.dts @@ -19,6 +19,7 @@ / { model = "Qualcomm Technologies, Inc. APQ8017-MTP"; qcom,board-id = <8 0>; + qcom,msm-id = <307 0x0>; }; &blsp1_uart1 { -- GitLab From 9bb342c0abd5a5f5f5b38c24280a289821959d5e Mon Sep 17 00:00:00 2001 From: Abhijith Desai Date: Tue, 15 May 2018 12:35:41 +0530 Subject: [PATCH 574/604] fbdev: msm: Add null check for sctl Check and flag error when sctl is NULL. CRs-Fixed: 2242140 Change-Id: Idd6cdbcbff61fb0047ef565094deb044d393fd70 Signed-off-by: Abhijith Desai --- drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index 947a3fe650ee..0ffe89c724c4 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -1677,6 +1677,11 @@ static void clk_ctrl_delayed_off_work(struct work_struct *work) /* re-assign to have the correct order in the context */ ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX]; + if (!sctl) { + pr_err("invalid sctl\n"); + goto exit; + } + sctx = (struct mdss_mdp_cmd_ctx *) sctl->intf_ctx[MASTER_CTX]; if (!ctx || !sctx) { pr_err("invalid %s %s\n", @@ -1784,6 +1789,11 @@ static void clk_ctrl_gate_work(struct work_struct *work) /* re-assign to have the correct order in the context */ ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX]; + if (!sctl) { + pr_err("invalid sctl\n"); + goto exit; + } + sctx = (struct mdss_mdp_cmd_ctx *) sctl->intf_ctx[MASTER_CTX]; if (!ctx || !sctx) { pr_err("%s ERROR invalid %s %s\n", __func__, -- GitLab From 88187e95b92b8eaf96766ecd49d2e4ac8ac94e6d Mon Sep 17 00:00:00 2001 From: Vijay Navnath Kamble Date: Fri, 3 Aug 2018 13:26:56 +0530 Subject: [PATCH 575/604] ARM: dts: msm: Add MPM interrupt controller for apq8053 hw variants Add mpm interrupt controller as SOC interrupt parent and as a child domain under intc for apq8053 hw variants. Change-Id: I64856629e45dce8ad896361bcc473720e0cdd1a0 Signed-off-by: Vijay Navnath Kamble --- arch/arm64/boot/dts/qcom/apq8053-lite.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite.dtsi index 5be35e72c7a9..c9d716063a82 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8053-lite.dtsi @@ -18,7 +18,7 @@ model = "Qualcomm Technologies, Inc. APQ 8953 Lite"; compatible = "qcom,apq8053"; qcom,msm-id = <304 0x0>; - interrupt-parent = <&intc>; + interrupt-parent = <&wakegic>; soc: soc { }; }; -- GitLab From 67b9efb3c02b51459cb688e854213da755cc5905 Mon Sep 17 00:00:00 2001 From: Ramesh Yadav Javadi Date: Wed, 1 Aug 2018 15:00:52 +0530 Subject: [PATCH 576/604] ARM: dts: qcom: Rename 8909w/8009w dts files Renamed all 3100 dts files with the chipset numbers this has done to reduce the confusion on dts files for customers. Change-Id: Iaf5c14422f4b12fb8bd280aedf87a5252305fc29 Signed-off-by: Ramesh Yadav Javadi --- arch/arm64/boot/dts/qcom/Makefile | 6 +++--- .../{apq8009w-bg-alpha.dts => sdw3100-apq8009w-alpha.dts} | 2 +- .../{apq8009w-bg-wtp-v2.dts => sdw3100-apq8009w-wtp.dts} | 2 +- .../{msm8909w-bg-wtp-v2.dts => sdw3100-msm8909w-wtp.dts} | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) rename arch/arm64/boot/dts/qcom/{apq8009w-bg-alpha.dts => sdw3100-apq8009w-alpha.dts} (98%) rename arch/arm64/boot/dts/qcom/{apq8009w-bg-wtp-v2.dts => sdw3100-apq8009w-wtp.dts} (98%) rename arch/arm64/boot/dts/qcom/{msm8909w-bg-wtp-v2.dts => sdw3100-msm8909w-wtp.dts} (99%) diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index a798b5d5a575..3e97a4991900 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -499,9 +499,9 @@ dtb-$(CONFIG_ARCH_MSM8917) += msm8917-pmi8950-mtp.dtb \ msm8917-pmi8940-cdp.dtb \ msm8917-pmi8940-rcm.dtb -dtb-$(CONFIG_ARCH_MSM8909) += msm8909w-bg-wtp-v2.dtb \ - apq8009w-bg-wtp-v2.dtb \ - apq8009w-bg-alpha.dtb \ +dtb-$(CONFIG_ARCH_MSM8909) += sdw3100-msm8909w-wtp.dtb \ + sdw3100-apq8009w-wtp.dtb \ + sdw3100-apq8009w-alpha.dtb \ apq8009-mtp-wcd9326-refboard.dtb \ apq8009-robot-som-refboard.dtb \ apq8009-robot-rome-refboard.dtb \ diff --git a/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts b/arch/arm64/boot/dts/qcom/sdw3100-apq8009w-alpha.dts similarity index 98% rename from arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts rename to arch/arm64/boot/dts/qcom/sdw3100-apq8009w-alpha.dts index 20878c02864f..be8416f75a92 100644 --- a/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts +++ b/arch/arm64/boot/dts/qcom/sdw3100-apq8009w-alpha.dts @@ -20,7 +20,7 @@ #include "msm8909-audio-bg_codec.dtsi" / { - model = "Qualcomm Technologies, Inc. APQ8009W-PM660 BG Alpha"; + model = "Qualcomm Technologies, Inc. APQ8009W-PM660 BG Alpha SDW3100"; compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; qcom,msm-id = <265 0>, <301 0>; diff --git a/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/sdw3100-apq8009w-wtp.dts similarity index 98% rename from arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts rename to arch/arm64/boot/dts/qcom/sdw3100-apq8009w-wtp.dts index e7af39f46abf..2b3fd84b498c 100644 --- a/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts +++ b/arch/arm64/boot/dts/qcom/sdw3100-apq8009w-wtp.dts @@ -20,7 +20,7 @@ #include "msm8909-audio-bg_codec.dtsi" / { - model = "Qualcomm Technologies, Inc. APQ8009W-PM660 BLACKGHOST WTP"; + model = "Qualcomm Technologies, Inc. APQ8009W-PM660 BG WTP SDW3100"; compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; qcom,msm-id = <265 0>, <301 0>; diff --git a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/sdw3100-msm8909w-wtp.dts similarity index 99% rename from arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts rename to arch/arm64/boot/dts/qcom/sdw3100-msm8909w-wtp.dts index 255c146e7fbb..89f0bb84b2cd 100644 --- a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts +++ b/arch/arm64/boot/dts/qcom/sdw3100-msm8909w-wtp.dts @@ -21,7 +21,7 @@ #include "msm8909-audio-bg_codec.dtsi" / { - model = "Qualcomm Technologies, Inc. MSM8909W-PM660 BLACKGHOST WTP"; + model = "Qualcomm Technologies, Inc. MSM8909W-PM660 BG WTP SDW3100"; compatible = "qcom,msm8909-mtp", "qcom,msm8909", "qcom,mtp"; qcom,msm-id = <245 0>, <258 0>, -- GitLab From 3b524f79224194197c9745bf9898b29ed4b71cbf Mon Sep 17 00:00:00 2001 From: Umang Agrawal Date: Tue, 22 May 2018 17:05:14 +0530 Subject: [PATCH 577/604] 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 8281c413ca34..a0b9bca138b3 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -339,6 +339,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(esr_nominal), POWER_SUPPLY_ATTR(soh), POWER_SUPPLY_ATTR(qc_opti_disable), + 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 94124807b2b1..4c0778848426 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -302,6 +302,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_ESR_NOMINAL, POWER_SUPPLY_PROP_SOH, POWER_SUPPLY_PROP_QC_OPTI_DISABLE, + 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 c2cb4675c466c73b5c66a8b6a377662f0df3866b Mon Sep 17 00:00:00 2001 From: Yue Ma Date: Thu, 2 Aug 2018 16:35:20 -0700 Subject: [PATCH 578/604] cnss2: Add module parameter to support different BDF types Add module parameter bdf_type so that different kinds of board data files can be runtime selected to download. Change-Id: I8947fb8191f0d6b99f95f8b7fda3836185027528 Signed-off-by: Yue Ma --- drivers/net/wireless/cnss2/qmi.c | 63 +++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index 3fbad1f98457..2c375bb1bd38 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -23,8 +23,17 @@ #define WLFW_SERVICE_INS_ID_V01 1 #define WLFW_CLIENT_ID 0x4b4e454c #define MAX_BDF_FILE_NAME 11 -#define DEFAULT_BDF_FILE_NAME "bdwlan.elf" -#define BDF_FILE_NAME_PREFIX "bdwlan.e" +#define ELF_BDF_FILE_NAME "bdwlan.elf" +#define ELF_BDF_FILE_NAME_PREFIX "bdwlan.e" +#define BIN_BDF_FILE_NAME "bdwlan.bin" +#define BIN_BDF_FILE_NAME_PREFIX "bdwlan.b" +#define DUMMY_BDF_FILE_NAME "bdwlan.dmy" + +enum cnss_bdf_type { + CNSS_BDF_BIN, + CNSS_BDF_ELF, + CNSS_BDF_DUMMY = 255, +}; #ifdef CONFIG_CNSS2_DEBUG static unsigned int qmi_timeout = 10000; @@ -40,17 +49,12 @@ static bool daemon_support; module_param(daemon_support, bool, 0600); MODULE_PARM_DESC(daemon_support, "User space has cnss-daemon support or not"); -static bool bdf_bypass; +static unsigned int bdf_type = CNSS_BDF_ELF; #ifdef CONFIG_CNSS2_DEBUG -module_param(bdf_bypass, bool, 0600); -MODULE_PARM_DESC(bdf_bypass, "If BDF is not found, send dummy BDF to FW"); +module_param(bdf_type, uint, 0600); +MODULE_PARM_DESC(bdf_type, "Type of board data file to be downloaded"); #endif -enum cnss_bdf_type { - CNSS_BDF_BIN, - CNSS_BDF_ELF, -}; - static char *cnss_qmi_mode_to_str(enum cnss_driver_mode mode) { switch (mode) { @@ -515,18 +519,33 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv) goto out; } - if (plat_priv->board_info.board_id == 0xFF) - snprintf(filename, sizeof(filename), DEFAULT_BDF_FILE_NAME); - else - snprintf(filename, sizeof(filename), - BDF_FILE_NAME_PREFIX "%02x", - plat_priv->board_info.board_id); - - if (bdf_bypass) { - cnss_pr_info("bdf_bypass is enabled, sending dummy BDF\n"); - temp = filename; + switch (bdf_type) { + case CNSS_BDF_ELF: + if (plat_priv->board_info.board_id == 0xFF) + snprintf(filename, sizeof(filename), ELF_BDF_FILE_NAME); + else + snprintf(filename, sizeof(filename), + ELF_BDF_FILE_NAME_PREFIX "%02x", + plat_priv->board_info.board_id); + break; + case CNSS_BDF_BIN: + if (plat_priv->board_info.board_id == 0xFF) + snprintf(filename, sizeof(filename), BIN_BDF_FILE_NAME); + else + snprintf(filename, sizeof(filename), + BIN_BDF_FILE_NAME_PREFIX "%02x", + plat_priv->board_info.board_id); + break; + case CNSS_BDF_DUMMY: + cnss_pr_dbg("CNSS_BDF_DUMMY is set, sending dummy BDF\n"); + snprintf(filename, sizeof(filename), DUMMY_BDF_FILE_NAME); + temp = DUMMY_BDF_FILE_NAME; remaining = MAX_BDF_FILE_NAME; goto bypass_bdf; + default: + cnss_pr_err("Invalid BDF type: %d\n", bdf_type); + ret = -EINVAL; + goto err_req_fw; } ret = request_firmware(&fw_entry, filename, &plat_priv->plat_dev->dev); @@ -561,7 +580,7 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv) req->data_valid = 1; req->end_valid = 1; req->bdf_type_valid = 1; - req->bdf_type = CNSS_BDF_ELF; + req->bdf_type = bdf_type; if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) { req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01; @@ -594,7 +613,7 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv) } err_send: - if (!bdf_bypass) + if (bdf_type != CNSS_BDF_DUMMY) release_firmware(fw_entry); err_req_fw: kfree(req); -- GitLab From 8d488173ae1b9dc5df3030f8f39b4a51ca1eab68 Mon Sep 17 00:00:00 2001 From: Anurag Chouhan Date: Wed, 25 Jul 2018 14:50:31 +0530 Subject: [PATCH 579/604] icnss: Avoid sending mode on twice Do not send mode on request to the firmware, if sent already. Keep a flag maintianing mode on state, check before sending mode on request to the firmware and clear the flag once FW ready is received or mode off is sent to the firmware. Change-Id: I66ff348b1b25046ee3a40971458475e6b9699c40 Signed-off-by: Anurag Chouhan --- drivers/soc/qcom/icnss.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 39b79f66804e..b9572bdeede3 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -285,6 +285,7 @@ enum icnss_driver_state { ICNSS_FW_DOWN, ICNSS_DRIVER_UNLOADING, ICNSS_REJUVENATE, + ICNSS_MODE_ON, }; struct ce_irq_list { @@ -1610,6 +1611,16 @@ static int wlfw_wlan_mode_send_sync_msg(enum wlfw_driver_mode_enum_v01 mode) } penv->stats.mode_resp++; + if (mode == QMI_WLFW_OFF_V01) { + icnss_pr_dbg("Clear mode on 0x%lx, mode: %d\n", + penv->state, mode); + clear_bit(ICNSS_MODE_ON, &penv->state); + } else { + icnss_pr_dbg("Set mode on 0x%lx, mode: %d\n", + penv->state, mode); + set_bit(ICNSS_MODE_ON, &penv->state); + } + return 0; out: @@ -2344,6 +2355,7 @@ static int icnss_driver_event_fw_ready_ind(void *data) return -ENODEV; set_bit(ICNSS_FW_READY, &penv->state); + clear_bit(ICNSS_MODE_ON, &penv->state); icnss_pr_info("WLAN FW is ready: 0x%lx\n", penv->state); @@ -3298,6 +3310,12 @@ int icnss_wlan_enable(struct device *dev, struct icnss_wlan_enable_cfg *config, return -EINVAL; } + if (test_bit(ICNSS_MODE_ON, &penv->state)) { + icnss_pr_err("Already Mode on, ignoring wlan_enable state: 0x%lx\n", + penv->state); + return -EINVAL; + } + icnss_pr_dbg("Mode: %d, config: %p, host_version: %s\n", mode, config, host_version); @@ -4016,6 +4034,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv) continue; case ICNSS_DRIVER_UNLOADING: seq_puts(s, "DRIVER UNLOADING"); + continue; + case ICNSS_MODE_ON: + seq_puts(s, "MODE ON DONE"); } seq_printf(s, "UNKNOWN-%d", i); -- GitLab From 639e0d05b6f978e98b4fd8fc04e9d9adb4e489fd Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Thu, 2 Aug 2018 18:55:19 +0530 Subject: [PATCH 580/604] msm: kgsl: Make sure gpu-speed-bin-vectors has the correct size Total number of elements in the gpu-speed-bin-vectors array should be multiple of number of elements in a speed bin vector. If number of elements is not a multiple of vector size then there is a possibilty of out of bound access in the speed-bin vector array. Also rectify the memory allocated for it. Change-Id: I9158e4f883eca400a46663b07326fb6f6020155c Signed-off-by: Sunil Khatri --- drivers/gpu/msm/adreno.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 757f9d736d6a..59dbdc4dcccc 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -294,11 +294,11 @@ void adreno_efuse_speed_bin_array(struct adreno_device *adreno_dev) */ count = of_property_count_u32_elems(device->pdev->dev.of_node, "qcom,gpu-speed-bin-vectors"); - if (count <= 0) + + if ((count <= 0) || (count % vector_size)) return; - bin_vector = kmalloc(sizeof(count * sizeof(unsigned int)), - GFP_KERNEL); + bin_vector = kmalloc_array(count, sizeof(unsigned int), GFP_KERNEL); if (bin_vector == NULL) { KGSL_DRV_ERR(device, "Unable to allocate memory for speed-bin vector\n"); -- GitLab From 62ed171153d71d27e10fd0d5fadca3c9b9defa3e Mon Sep 17 00:00:00 2001 From: Zhang Chuming Date: Wed, 25 Jul 2018 14:34:46 +0530 Subject: [PATCH 581/604] defconfig: msm8953: Add Elan_Sparrow touch support Update Kconfig/defaultconfig/Makefile Signed-off-by: Zhang Chuming Git-commit: 38edbff223738995a8824cad087368b5d25fc72f Git-Repo: https://github.com/ElanDriver/Sparrow/tree/Sparrow_ElanDriver Change-Id: If37e3b32e63f81883455a61f0039be241e401aa8 Signed-off-by: Venkataraman Nerellapalli --- arch/arm/configs/msm8953-perf_defconfig | 1 + arch/arm/configs/msm8953_defconfig | 1 + drivers/input/touchscreen/Kconfig | 11 +++++++++++ drivers/input/touchscreen/Makefile | 1 + 4 files changed, 14 insertions(+) diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig index e4bae9fc0578..344ab3d60f51 100644 --- a/arch/arm/configs/msm8953-perf_defconfig +++ b/arch/arm/configs/msm8953-perf_defconfig @@ -320,6 +320,7 @@ CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y CONFIG_TOUCHSCREEN_HIMAX_I2C=y CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y CONFIG_HMX_DB=y +CONFIG_TOUCHSCREEN_EKTF3XXX_CHIPSET=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig index 1dea4b9f4207..f0508d6d5728 100644 --- a/arch/arm/configs/msm8953_defconfig +++ b/arch/arm/configs/msm8953_defconfig @@ -325,6 +325,7 @@ CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y CONFIG_TOUCHSCREEN_HIMAX_I2C=y CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y CONFIG_HMX_DB=y +CONFIG_TOUCHSCREEN_EKTF3XXX_CHIPSET=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index ea37a9ff857a..a259ef356dca 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1302,4 +1302,15 @@ config TOUCHSCREEN_HIMAX_CHIPSET If unsure, say N. source "drivers/input/touchscreen/hxchipset/Kconfig" + +config TOUCHSCREEN_EKTF3XXX_CHIPSET + bool "Elan EKTF3XXX touchpanel CHIPSET" + depends on I2C + help + Say Y here if you have a Elan CHIPSET touchscreen. + ELAN controllers are multi touch controllers which can + report 10 touches at a time. + + If unusre, say N. + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index acd4045a23d2..2579346cf53e 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -106,3 +106,4 @@ obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_touch/ obj-$(CONFIG_TOUCHSCREEN_GT9XX_v28) += gt9xx_v2.8/ obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET) += hxchipset/ +obj-$(CONFIG_TOUCHSCREEN_EKTF3XXX_CHIPSET) += ektf3xxx/ -- GitLab From d4f86c7202356e71f1b48304fa5b8c85d37ad672 Mon Sep 17 00:00:00 2001 From: Sankeerth Billakanti Date: Mon, 30 Jul 2018 16:12:07 +0530 Subject: [PATCH 582/604] 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 d9839e7e994d..a0a0daf42c6a 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -1462,6 +1462,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 024798be064aa1bd486f879c8d8b177af63a247b Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Fri, 13 Jul 2018 18:14:26 -0700 Subject: [PATCH 583/604] qseecom: check if app is blocked when unloading app When TA client crashes, qseecom_release() will be called to unload this TA and release its allocated buffer. But if at the same time, there is another client still waiting to check if this TA is blocked, the TA should not be unloaded, otherwise the checking client may access freed buffer. Thus, add a TA "check_block" flag to indicate if a client is still checking TA's block state, and not to unload TA if this flag is true. Change-Id: I8bd4baae44d5e333cedb54048501efd4cff29a72 Signed-off-by: Zhen Kong --- drivers/misc/qseecom.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 0ee8208fdc19..eab3b5959d05 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -199,6 +199,7 @@ struct qseecom_registered_app_list { char app_name[MAX_APP_NAME_SIZE]; u32 app_arch; bool app_blocked; + bool check_block; u32 blocked_on_listener_id; }; @@ -2185,6 +2186,7 @@ static void __qseecom_reentrancy_check_if_this_app_blocked( sigset_t new_sigset, old_sigset; if (qseecom.qsee_reentrancy_support) { + ptr_app->check_block = true; while (ptr_app->app_blocked || qseecom.app_block_ref_cnt > 1) { /* thread sleep until this app unblocked */ sigfillset(&new_sigset); @@ -2199,6 +2201,7 @@ static void __qseecom_reentrancy_check_if_this_app_blocked( mutex_lock(&app_access_lock); sigprocmask(SIG_SETMASK, &old_sigset, NULL); } + ptr_app->check_block = false; } } @@ -2577,7 +2580,8 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, if (!strcmp((void *)ptr_app->app_name, (void *)data->client.app_name)) { found_app = true; - if (ptr_app->app_blocked) + if (ptr_app->app_blocked || + ptr_app->check_block) app_crash = false; if (app_crash || ptr_app->ref_cnt == 1) unload = true; -- GitLab From dea105918aa47098ccf54facf7ac2f33291e7bcf Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Mon, 30 Jul 2018 17:50:10 -0700 Subject: [PATCH 584/604] qseecom: change check_blocked flag to an u32 value Change app entry's check_blocked flag to u32 to indicate the total number of clients being blocked on this app; then this app can only be unloaded if this flag is 0. Change-Id: I0370b25657b6dfdc40a738c784e601907c9b4dd4 Signed-off-by: Zhen Kong --- drivers/misc/qseecom.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index eab3b5959d05..d0b5a0e67304 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -199,7 +199,7 @@ struct qseecom_registered_app_list { char app_name[MAX_APP_NAME_SIZE]; u32 app_arch; bool app_blocked; - bool check_block; + u32 check_block; u32 blocked_on_listener_id; }; @@ -2186,7 +2186,7 @@ static void __qseecom_reentrancy_check_if_this_app_blocked( sigset_t new_sigset, old_sigset; if (qseecom.qsee_reentrancy_support) { - ptr_app->check_block = true; + ptr_app->check_block++; while (ptr_app->app_blocked || qseecom.app_block_ref_cnt > 1) { /* thread sleep until this app unblocked */ sigfillset(&new_sigset); @@ -2201,7 +2201,7 @@ static void __qseecom_reentrancy_check_if_this_app_blocked( mutex_lock(&app_access_lock); sigprocmask(SIG_SETMASK, &old_sigset, NULL); } - ptr_app->check_block = false; + ptr_app->check_block--; } } @@ -2470,6 +2470,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) MAX_APP_NAME_SIZE); entry->app_blocked = false; entry->blocked_on_listener_id = 0; + entry->check_block = 0; /* Deallocate the handle */ if (!IS_ERR_OR_NULL(ihandle)) @@ -4532,6 +4533,7 @@ int qseecom_start_app(struct qseecom_handle **handle, entry->app_arch = app_arch; entry->app_blocked = false; entry->blocked_on_listener_id = 0; + entry->check_block = 0; spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); list_add_tail(&entry->list, &qseecom.registered_app_list_head); spin_unlock_irqrestore(&qseecom.registered_app_list_lock, @@ -5446,6 +5448,7 @@ static int qseecom_query_app_loaded(struct qseecom_dev_handle *data, MAX_APP_NAME_SIZE); entry->app_blocked = false; entry->blocked_on_listener_id = 0; + entry->check_block = 0; spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); list_add_tail(&entry->list, -- GitLab From c858082e235fa1aea37732ddd466a89e1af2d862 Mon Sep 17 00:00:00 2001 From: Bojun Pan Date: Wed, 27 Jun 2018 17:33:31 -0700 Subject: [PATCH 585/604] msm: ipa: add NULL pointer check to ipa gsb Add useful NULL pointer check on IPA GSB functions, add spin/mutex interface locks to avoid race condition. Change-Id: If5a7a304accf006ef320c65e851eea47978c38b4 Signed-off-by: Bojun Pan --- .../platform/msm/ipa/ipa_clients/ipa_gsb.c | 169 ++++++++++++++---- 1 file changed, 131 insertions(+), 38 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c index 5812d8df9c9a..4e3a565e1a0a 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c @@ -132,7 +132,7 @@ struct ipa_gsb_iface_info { * struct ipa_gsb_context - GSB driver context information * @logbuf: buffer of ipc logging * @logbuf_low: buffer of ipc logging (low priority) - * @lock: mutex lock + * @lock: global mutex lock for global variables * @prod_hdl: handle for prod pipe * @cons_hdl: handle for cons pipe * @ipa_sys_desc_size: sys pipe desc size @@ -141,6 +141,8 @@ struct ipa_gsb_iface_info { * @num_connected_iface: number of connected interface * @num_resumed_iface: number of resumed interface * @iface: interface information + * @iface_lock: interface mutex lock for control path + * @iface_spinlock: interface spinlock for data path * @pm_hdl: IPA PM handle */ struct ipa_gsb_context { @@ -155,6 +157,8 @@ struct ipa_gsb_context { int num_connected_iface; int num_resumed_iface; struct ipa_gsb_iface_info *iface[MAX_SUPPORTED_IFACE]; + struct mutex iface_lock[MAX_SUPPORTED_IFACE]; + spinlock_t iface_spinlock[MAX_SUPPORTED_IFACE]; u32 pm_hdl; }; @@ -240,6 +244,7 @@ static void ipa_gsb_debugfs_destroy(void) static int ipa_gsb_driver_init(struct odu_bridge_params *params) { + int i; if (!ipa_is_ready()) { IPA_GSB_ERR("IPA is not ready\n"); return -EFAULT; @@ -252,6 +257,10 @@ static int ipa_gsb_driver_init(struct odu_bridge_params *params) return -ENOMEM; mutex_init(&ipa_gsb_ctx->lock); + for (i = 0; i < MAX_SUPPORTED_IFACE; i++) { + mutex_init(&ipa_gsb_ctx->iface_lock[i]); + spin_lock_init(&ipa_gsb_ctx->iface_spinlock[i]); + } ipa_gsb_debugfs_init(); return 0; @@ -475,7 +484,7 @@ int ipa_bridge_init(struct ipa_bridge_init_params *params, u32 *hdl) if (!params || !params->wakeup_request || !hdl || !params->info.netdev_name || !params->info.tx_dp_notify || !params->info.send_dl_skb) { - IPA_GSB_ERR("NULL parameters\n"); + IPA_GSB_ERR("Invalid parameters\n"); return -EINVAL; } @@ -596,6 +605,7 @@ static void ipa_gsb_deregister_pm(void) int ipa_bridge_cleanup(u32 hdl) { + int i; if (!ipa_gsb_ctx) { IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n"); return -EFAULT; @@ -606,39 +616,44 @@ int ipa_bridge_cleanup(u32 hdl) return -EINVAL; } - if (ipa_gsb_ctx->iface[hdl] == NULL) { - IPA_GSB_ERR("fail to find interface\n"); + mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); + if (!ipa_gsb_ctx->iface[hdl]) { + IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } IPA_GSB_DBG("client hdl: %d\n", hdl); - mutex_lock(&ipa_gsb_ctx->lock); if (ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_ERR("cannot cleanup when iface is connected\n"); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } - ipa_gsb_dereg_intf_props(ipa_gsb_ctx->iface[hdl]); ipa_gsb_delete_partial_hdr(ipa_gsb_ctx->iface[hdl]); + spin_lock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); kfree(ipa_gsb_ctx->iface[hdl]); ipa_gsb_ctx->iface[hdl] = NULL; ipa_gsb_ctx->iface_hdl[hdl] = false; + spin_unlock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); + mutex_lock(&ipa_gsb_ctx->lock); ipa_gsb_ctx->num_iface--; IPA_GSB_DBG("num_iface %d\n", ipa_gsb_ctx->num_iface); - if (ipa_gsb_ctx->num_iface == 0) { ipa_gsb_deregister_pm(); ipa_gsb_debugfs_destroy(); ipc_log_context_destroy(ipa_gsb_ctx->logbuf); ipc_log_context_destroy(ipa_gsb_ctx->logbuf_low); mutex_unlock(&ipa_gsb_ctx->lock); + mutex_destroy(&ipa_gsb_ctx->lock); + for (i = 0; i < MAX_SUPPORTED_IFACE; i++) + mutex_destroy(&ipa_gsb_ctx->iface_lock[i]); kfree(ipa_gsb_ctx); ipa_gsb_ctx = NULL; return 0; } - mutex_unlock(&ipa_gsb_ctx->lock); return 0; } @@ -670,6 +685,10 @@ static void ipa_gsb_cons_cb(void *priv, enum ipa_dp_evt_type evt, (pkt_size + sizeof(*mux_hdr) + ETH_HLEN + IPA_GSB_SKB_DUMMY_HEADER); hdl = mux_hdr->iface_hdl; + if (hdl >= MAX_SUPPORTED_IFACE) { + IPA_GSB_ERR("invalid hdl: %d\n", hdl); + break; + } IPA_GSB_DBG_LOW("pkt_size: %d, pad_byte: %d, hdl: %d\n", pkt_size, pad_byte, hdl); @@ -683,11 +702,21 @@ static void ipa_gsb_cons_cb(void *priv, enum ipa_dp_evt_type evt, break; } skb_trim(skb2, pkt_size + ETH_HLEN); - ipa_gsb_ctx->iface[hdl]->send_dl_skb( - ipa_gsb_ctx->iface[hdl]->priv, skb2); - ipa_gsb_ctx->iface[hdl]->iface_stats.num_dl_packets++; - skb_pull(skb, pkt_size + ETH_HLEN + pad_byte); + spin_lock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); + if (ipa_gsb_ctx->iface[hdl] != NULL) { + ipa_gsb_ctx->iface[hdl]->send_dl_skb( + ipa_gsb_ctx->iface[hdl]->priv, skb2); + ipa_gsb_ctx->iface[hdl]->iface_stats.num_dl_packets++; + spin_unlock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); + skb_pull(skb, pkt_size + ETH_HLEN + pad_byte); + } else { + IPA_GSB_ERR("Invalid hdl: %d, drop the skb\n", hdl); + spin_unlock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); + dev_kfree_skb_any(skb2); + break; + } } + if (skb) { dev_kfree_skb_any(skb); skb = NULL; @@ -695,7 +724,7 @@ static void ipa_gsb_cons_cb(void *priv, enum ipa_dp_evt_type evt, } static void ipa_gsb_tx_dp_notify(void *priv, enum ipa_dp_evt_type evt, - unsigned long data) + unsigned long data) { struct sk_buff *skb; struct ipa_gsb_mux_hdr *mux_hdr; @@ -714,13 +743,18 @@ static void ipa_gsb_tx_dp_notify(void *priv, enum ipa_dp_evt_type evt, /* change to host order */ *(u32 *)mux_hdr = ntohl(*(u32 *)mux_hdr); hdl = mux_hdr->iface_hdl; + if (!ipa_gsb_ctx->iface[hdl]) { + IPA_GSB_ERR("invalid hdl: %d and cb, drop the skb\n", hdl); + dev_kfree_skb_any(skb); + return; + } IPA_GSB_DBG_LOW("evt: %d, hdl in tx_dp_notify: %d\n", evt, hdl); /* remove 4 byte mux header */ skb_pull(skb, sizeof(struct ipa_gsb_mux_hdr)); ipa_gsb_ctx->iface[hdl]->tx_dp_notify( - ipa_gsb_ctx->iface[hdl]->priv, evt, - (unsigned long)skb); + ipa_gsb_ctx->iface[hdl]->priv, evt, + (unsigned long)skb); } static int ipa_gsb_connect_sys_pipe(void) @@ -797,13 +831,23 @@ int ipa_bridge_connect(u32 hdl) return -EFAULT; } + if (hdl >= MAX_SUPPORTED_IFACE) { + IPA_GSB_ERR("invalid hdl: %d\n", hdl); + return -EINVAL; + } + IPA_GSB_DBG("client hdl: %d\n", hdl); - mutex_lock(&ipa_gsb_ctx->lock); + mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); + if (!ipa_gsb_ctx->iface[hdl]) { + IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); + return -EFAULT; + } if (ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_DBG("iface was already connected\n"); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } @@ -811,13 +855,13 @@ int ipa_bridge_connect(u32 hdl) ret = ipa_pm_activate_sync(ipa_gsb_ctx->pm_hdl); if (ret) { IPA_GSB_ERR("failed to activate ipa pm\n"); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } ret = ipa_gsb_connect_sys_pipe(); if (ret) { IPA_GSB_ERR("fail to connect pipe\n"); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } } @@ -833,7 +877,7 @@ int ipa_bridge_connect(u32 hdl) IPA_GSB_DBG("num resumed iface: %d\n", ipa_gsb_ctx->num_resumed_iface); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } EXPORT_SYMBOL(ipa_bridge_connect); @@ -871,13 +915,23 @@ int ipa_bridge_disconnect(u32 hdl) return -EFAULT; } + if (hdl >= MAX_SUPPORTED_IFACE) { + IPA_GSB_ERR("invalid hdl: %d\n", hdl); + return -EINVAL; + } + IPA_GSB_DBG("client hdl: %d\n", hdl); - mutex_lock(&ipa_gsb_ctx->lock); + mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); + if (!ipa_gsb_ctx->iface[hdl]) { + IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); + return -EFAULT; + } if (!ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_DBG("iface was not connected\n"); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } @@ -885,14 +939,14 @@ int ipa_bridge_disconnect(u32 hdl) ret = ipa_gsb_disconnect_sys_pipe(); if (ret) { IPA_GSB_ERR("fail to discon pipes\n"); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } ret = ipa_pm_deactivate_sync(ipa_gsb_ctx->pm_hdl); if (ret) { IPA_GSB_ERR("failed to deactivate ipa pm\n"); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } } @@ -910,7 +964,7 @@ int ipa_bridge_disconnect(u32 hdl) ipa_gsb_ctx->num_resumed_iface); } - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } EXPORT_SYMBOL(ipa_bridge_disconnect); @@ -924,25 +978,37 @@ int ipa_bridge_resume(u32 hdl) return -EFAULT; } + if (hdl >= MAX_SUPPORTED_IFACE) { + IPA_GSB_ERR("invalid hdl: %d\n", hdl); + return -EINVAL; + } + IPA_GSB_DBG_LOW("client hdl: %d\n", hdl); + mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); + if (!ipa_gsb_ctx->iface[hdl]) { + IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); + return -EFAULT; + } + if (!ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_ERR("iface is not connected\n"); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } if (ipa_gsb_ctx->iface[hdl]->is_resumed) { IPA_GSB_DBG_LOW("iface was already resumed\n"); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } - mutex_lock(&ipa_gsb_ctx->lock); - if (ipa_gsb_ctx->num_resumed_iface == 0) { ret = ipa_pm_activate_sync(ipa_gsb_ctx->pm_hdl); if (ret) { IPA_GSB_ERR("fail to activate ipa pm\n"); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } @@ -952,7 +1018,7 @@ int ipa_bridge_resume(u32 hdl) IPA_GSB_ERR( "fail to start con ep %d\n", ret); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } } @@ -962,7 +1028,7 @@ int ipa_bridge_resume(u32 hdl) IPA_GSB_DBG_LOW("num resumed iface: %d\n", ipa_gsb_ctx->num_resumed_iface); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } EXPORT_SYMBOL(ipa_bridge_resume); @@ -976,20 +1042,32 @@ int ipa_bridge_suspend(u32 hdl) return -EFAULT; } + if (hdl >= MAX_SUPPORTED_IFACE) { + IPA_GSB_ERR("invalid hdl: %d\n", hdl); + return -EINVAL; + } + IPA_GSB_DBG_LOW("client hdl: %d\n", hdl); + mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); + if (!ipa_gsb_ctx->iface[hdl]) { + IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); + return -EFAULT; + } + if (!ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_ERR("iface is not connected\n"); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } if (!ipa_gsb_ctx->iface[hdl]->is_resumed) { IPA_GSB_DBG_LOW("iface was already suspended\n"); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } - mutex_lock(&ipa_gsb_ctx->lock); - if (ipa_gsb_ctx->num_resumed_iface == 1) { ret = ipa_stop_gsi_channel( ipa_gsb_ctx->cons_hdl); @@ -997,7 +1075,7 @@ int ipa_bridge_suspend(u32 hdl) IPA_GSB_ERR( "fail to stop cons ep %d\n", ret); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } @@ -1005,7 +1083,7 @@ int ipa_bridge_suspend(u32 hdl) if (ret) { IPA_GSB_ERR("fail to deactivate ipa pm\n"); ipa_start_gsi_channel(ipa_gsb_ctx->cons_hdl); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } } @@ -1015,7 +1093,7 @@ int ipa_bridge_suspend(u32 hdl) IPA_GSB_DBG_LOW("num resumed iface: %d\n", ipa_gsb_ctx->num_resumed_iface); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } EXPORT_SYMBOL(ipa_bridge_suspend); @@ -1024,16 +1102,26 @@ int ipa_bridge_set_perf_profile(u32 hdl, u32 bandwidth) { int ret; + if (!ipa_gsb_ctx) { + IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n"); + return -EFAULT; + } + + if (hdl >= MAX_SUPPORTED_IFACE) { + IPA_GSB_ERR("invalid hdl: %d\n", hdl); + return -EINVAL; + } + IPA_GSB_DBG("client hdl: %d, BW: %d\n", hdl, bandwidth); - mutex_lock(&ipa_gsb_ctx->lock); + mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); ret = ipa_pm_set_perf_profile(ipa_gsb_ctx->pm_hdl, bandwidth); if (ret) IPA_GSB_ERR("fail to set perf profile\n"); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } EXPORT_SYMBOL(ipa_bridge_set_perf_profile); @@ -1047,6 +1135,11 @@ int ipa_bridge_tx_dp(u32 hdl, struct sk_buff *skb, IPA_GSB_DBG_LOW("client hdl: %d\n", hdl); + if (!ipa_gsb_ctx->iface[hdl]) { + IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); + return -EFAULT; + } + /* make sure skb has enough headroom */ if (unlikely(skb_headroom(skb) < sizeof(struct ipa_gsb_mux_hdr))) { IPA_GSB_DBG_LOW("skb doesn't have enough headroom\n"); -- GitLab From 17d98bcb9500a63f0d756bd1f8dce89798b6aaf0 Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Tue, 7 Aug 2018 08:54:30 +0530 Subject: [PATCH 586/604] scsi: ufs: set load before setting voltage in regulators This sequence change is required to avoid dips in voltage during boot-up. Apparently, this dip is caused because in the original sequence, the regulators are initialized in lpm mode. And then when the load is set to high, and more current is drawn, than is allowed in lpm, the dip is seen. CRs-fixed: 2279027 Change-Id: Ic531a1e6788d6288071f93d5002613855c2667f5 Signed-off-by: Asutosh Das --- drivers/scsi/ufs/ufshcd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index c6cfd18c6510..e9927ac59602 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -8611,6 +8611,11 @@ static int ufshcd_config_vreg(struct device *dev, name = vreg->name; if (regulator_count_voltages(reg) > 0) { + uA_load = on ? vreg->max_uA : 0; + ret = ufshcd_config_vreg_load(dev, vreg, uA_load); + if (ret) + goto out; + min_uV = on ? vreg->min_uV : 0; ret = regulator_set_voltage(reg, min_uV, vreg->max_uV); if (ret) { @@ -8618,11 +8623,6 @@ static int ufshcd_config_vreg(struct device *dev, __func__, name, ret); goto out; } - - uA_load = on ? vreg->max_uA : 0; - ret = ufshcd_config_vreg_load(dev, vreg, uA_load); - if (ret) - goto out; } out: return ret; -- GitLab From 4e8e9e5c1f70b9440545cc84f3bcfcfb9bac2889 Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Tue, 7 Aug 2018 09:31:42 +0530 Subject: [PATCH 587/604] ufs: qcom: set load before setting voltage in regulator This sequence change is required to avoid dips in voltage during boot-up. Apparently, this dip is caused because in the original sequence, the regulators are initialized in lpm mode. And then when the load is set to high, and more current is drawn, than is allowed in lpm, the dip is seen. CRs-fixed: 2279027 Change-Id: Ie6cbc332cbee8227e16636219e375b18c796a12f Signed-off-by: Asutosh Das --- drivers/scsi/ufs/ufs-qcom.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 93c3af09b6d3..0ae6979b5fc5 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -727,6 +727,11 @@ static int ufs_qcom_config_vreg(struct device *dev, reg = vreg->reg; if (regulator_count_voltages(reg) > 0) { + uA_load = on ? vreg->max_uA : 0; + ret = regulator_set_load(vreg->reg, uA_load); + if (ret) + goto out; + min_uV = on ? vreg->min_uV : 0; ret = regulator_set_voltage(reg, min_uV, vreg->max_uV); if (ret) { @@ -734,11 +739,6 @@ static int ufs_qcom_config_vreg(struct device *dev, __func__, vreg->name, ret); goto out; } - - uA_load = on ? vreg->max_uA : 0; - ret = regulator_set_load(vreg->reg, uA_load); - if (ret) - goto out; } out: return ret; -- GitLab From a651ace3c30c635ab89b4e3afb59f025fd7a8da5 Mon Sep 17 00:00:00 2001 From: Zhang Chuming Date: Wed, 25 Jul 2018 14:19:24 +0530 Subject: [PATCH 588/604] input: touchscreen: Remove single touch input params Remove single touch input params. Firmare isn't reported pressure, remove pressure params. Signed-off-by: Zhang Chuming Git-commit: 0ed6d0dfe23a0281fe3707922882033e523ab525 Git-Repo: https://github.com/ElanDriver/Sparrow/tree/Sparrow_ElanDriver Change-Id: I9171be65fbf632ba5bffcc9bf087ea81d55354cb Signed-off-by: Venkataraman Nerellapalli --- drivers/input/touchscreen/ektf3xxx/elan_cros_i2c.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/input/touchscreen/ektf3xxx/elan_cros_i2c.c b/drivers/input/touchscreen/ektf3xxx/elan_cros_i2c.c index 3098941fa90f..71a30f2719d5 100644 --- a/drivers/input/touchscreen/ektf3xxx/elan_cros_i2c.c +++ b/drivers/input/touchscreen/ektf3xxx/elan_cros_i2c.c @@ -892,7 +892,7 @@ static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf) input_mt_report_slot_state(input, MT_TOOL_FINGER, true); input_event(input, EV_ABS, ABS_MT_POSITION_X, x); input_event(input, EV_ABS, ABS_MT_POSITION_Y, y); - input_event(input, EV_ABS, ABS_MT_PRESSURE, p); + /* input_event(input, EV_ABS, ABS_MT_PRESSURE, p);*/ input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, w); n_fingers--; @@ -1333,11 +1333,12 @@ static int elants_i2c_probe(struct i2c_client *client, __set_bit(EV_KEY, ts->input->evbit); /* Single touch input params setup */ - input_set_abs_params(ts->input, ABS_X, 0, ts->x_max, 0, 0); +/* input_set_abs_params(ts->input, ABS_X, 0, ts->x_max, 0, 0); input_set_abs_params(ts->input, ABS_Y, 0, ts->y_max, 0, 0); input_set_abs_params(ts->input, ABS_PRESSURE, 0, 255, 0, 0); input_abs_set_res(ts->input, ABS_X, ts->x_res); input_abs_set_res(ts->input, ABS_Y, ts->y_res); +*/ /* Multitouch input params setup */ error = input_mt_init_slots(ts->input, MAX_CONTACT_NUM, @@ -1351,7 +1352,7 @@ static int elants_i2c_probe(struct i2c_client *client, input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, ts->x_max, 0, 0); input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, ts->y_max, 0, 0); input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); - input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0); +/* input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0);*/ input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res); input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res); -- GitLab From 3b6b326020a79c4ef0429062369b3300a0ae41d4 Mon Sep 17 00:00:00 2001 From: Jayant Shekhar Date: Mon, 6 Aug 2018 18:36:02 +0530 Subject: [PATCH 589/604] drm/msm/sde: Use primary display for splash In current implementation, splash uses single display path, so for allocating resources for splash, ensure primary display is used as otherwise there are chances of mixer allocation failures. Change-Id: I63554fce4b39fe1dc94d0648eb69a4007616378d Signed-off-by: Jayant Shekhar --- drivers/gpu/drm/msm/sde/sde_kms.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index 9a4c7857d023..36f6a5ba2d5b 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -2658,7 +2658,15 @@ static int sde_kms_cont_splash_config(struct msm_kms *kms) SDE_DEBUG("info.is_connected = %s, info.is_primary = %s\n", ((info.is_connected) ? "true" : "false"), ((info.is_primary) ? "true" : "false")); - break; + + /** + * Since we are supporting one DSI for splash, use the display + * which is marked as primary. + */ + if (!info.is_primary) + continue; + else + break; } if (!encoder) { -- GitLab From c5b7de052f94ab5cb1fed3f5a2ddc0074f0d6b2d Mon Sep 17 00:00:00 2001 From: Zhenhua Huang Date: Tue, 7 Aug 2018 11:16:19 +0800 Subject: [PATCH 590/604] defconfig: msm8953: Turn off slub debug on by default Due to scm call request, 1 page is allocated frequently. With slub debug on enabled by default, we will get order 1 pages increased from order 0. To avoid the potential issue of alloc pages, turn off the config by default. CRs-Fixed: 2252427 Change-Id: Ia70f3934f29fcf8eb6546115cb8021fdd3c95860 Signed-off-by: Zhenhua Huang --- arch/arm/configs/msm8953_defconfig | 1 - arch/arm64/configs/msm8953_defconfig | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig index 1dea4b9f4207..1684a443509d 100644 --- a/arch/arm/configs/msm8953_defconfig +++ b/arch/arm/configs/msm8953_defconfig @@ -660,7 +660,6 @@ CONFIG_DEBUG_OBJECTS_TIMERS=y CONFIG_DEBUG_OBJECTS_WORK=y CONFIG_DEBUG_OBJECTS_RCU_HEAD=y CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y -CONFIG_SLUB_DEBUG_ON=y CONFIG_DEBUG_KMEMLEAK=y CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig index c8691903065a..3cc3576d2898 100644 --- a/arch/arm64/configs/msm8953_defconfig +++ b/arch/arm64/configs/msm8953_defconfig @@ -659,7 +659,6 @@ CONFIG_DEBUG_OBJECTS_TIMERS=y CONFIG_DEBUG_OBJECTS_WORK=y CONFIG_DEBUG_OBJECTS_RCU_HEAD=y CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y -CONFIG_SLUB_DEBUG_ON=y CONFIG_DEBUG_KMEMLEAK=y CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y -- GitLab From 5c5ba27184d3f7c11fc6545de32dd5174a053ad1 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Mon, 23 Jul 2018 14:54:20 +0530 Subject: [PATCH 591/604] 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 18c5c72fa93d..71a4369be1eb 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -1257,6 +1257,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, @@ -1305,14 +1306,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, @@ -1322,7 +1325,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; @@ -1351,14 +1354,20 @@ 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; 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 5106cef8fbfa..054d153ae05f 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -587,6 +587,21 @@ int smblib_set_aicl_cont_threshold(struct smb_chg_param *param, /******************** * 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; @@ -816,7 +831,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); @@ -1367,9 +1382,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; } @@ -1512,7 +1526,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 @@ -1583,32 +1598,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) { @@ -1648,19 +1637,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) { @@ -1679,32 +1655,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 * ***********************/ @@ -4126,7 +4076,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 c5458d7cf2d7..c252ef008a3b 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -500,18 +500,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, @@ -585,6 +575,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_stat_sw_override_cfg(struct smb_charger *chg, bool override); int smblib_configure_wdog(struct smb_charger *chg, bool enable); int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val); -- GitLab From 038109f11b8530c69d4c93f138a59d1a2263ab3b Mon Sep 17 00:00:00 2001 From: AnilKumar Chimata Date: Tue, 7 Aug 2018 15:58:21 +0530 Subject: [PATCH 592/604] crypto: qce50: Fix unclocked access in unbind path In unbind path crypto registers are accessed even if clocks are disabled which results unclocked access to crypto register, this patch fixes the same. Change-Id: Ie56d4f2f0d4118e7d8efbd81b6aa128b1708e74b Signed-off-by: AnilKumar Chimata --- drivers/crypto/msm/qce50.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c index 8643667a65e1..19f2289a64e9 100644 --- a/drivers/crypto/msm/qce50.c +++ b/drivers/crypto/msm/qce50.c @@ -1,7 +1,7 @@ /* * QTI Crypto Engine driver. * - * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * 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 @@ -6118,13 +6118,15 @@ EXPORT_SYMBOL(qce_open); int qce_close(void *handle) { struct qce_device *pce_dev = (struct qce_device *) handle; + int ret = -1; if (handle == NULL) return -ENODEV; mutex_lock(&qce_iomap_mutex); - qce_enable_clk(pce_dev); - qce_sps_exit(pce_dev); + ret = qce_enable_clk(pce_dev); + if (!ret) + qce_sps_exit(pce_dev); if (pce_dev->iobase) iounmap(pce_dev->iobase); @@ -6137,7 +6139,8 @@ int qce_close(void *handle) if (pce_dev->enable_s1_smmu) qce_iommu_release_iomapping(pce_dev); - qce_disable_clk(pce_dev); + if (!ret) + qce_disable_clk(pce_dev); __qce_deinit_clk(pce_dev); mutex_unlock(&qce_iomap_mutex); kfree(handle); -- GitLab From 85b6ea70fee03b8715ca5f6a4acc42a9c433a6c4 Mon Sep 17 00:00:00 2001 From: Kaushal Kumar Date: Wed, 6 Jun 2018 12:21:15 +0530 Subject: [PATCH 593/604] ARM: dts: msm: Add device tree support for sxr1130 Add base device tree and overlay support for sxr1130 MTP and CDP board variants. Support both internal and external audio codec variants. Support USB type-C connector as well. Also support both PM660L and PM660A. Change-Id: I8973c0cce404813033436bc060b8bfcabcf61840 Signed-off-by: Kaushal Kumar --- .../devicetree/bindings/arm/msm/msm.txt | 5 ++ arch/arm64/boot/dts/qcom/Makefile | 37 ++++++++- .../boot/dts/qcom/sxr1130-cdp-overlay.dts | 78 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sxr1130-cdp.dts | 72 +++++++++++++++++ .../sxr1130-external-codec-cdp-overlay.dts | 34 ++++++++ .../dts/qcom/sxr1130-external-codec-cdp.dts | 28 +++++++ .../sxr1130-external-codec-mtp-overlay.dts | 34 ++++++++ .../dts/qcom/sxr1130-external-codec-mtp.dts | 28 +++++++ ...1130-external-codec-pm660a-mtp-overlay.dts | 35 +++++++++ .../sxr1130-external-codec-pm660a-mtp.dts | 29 +++++++ .../boot/dts/qcom/sxr1130-mtp-overlay.dts | 78 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sxr1130-mtp.dts | 72 +++++++++++++++++ .../dts/qcom/sxr1130-pm660a-mtp-overlay.dts | 35 +++++++++ .../boot/dts/qcom/sxr1130-pm660a-mtp.dts | 29 +++++++ ...xr1130-usbc-external-codec-cdp-overlay.dts | 35 +++++++++ .../qcom/sxr1130-usbc-external-codec-cdp.dts | 29 +++++++ ...xr1130-usbc-external-codec-mtp-overlay.dts | 34 ++++++++ .../qcom/sxr1130-usbc-external-codec-mtp.dts | 29 +++++++ ...usbc-external-codec-pm660a-mtp-overlay.dts | 36 +++++++++ ...sxr1130-usbc-external-codec-pm660a-mtp.dts | 30 +++++++ .../dts/qcom/sxr1130-usbc-mtp-overlay.dts | 34 ++++++++ arch/arm64/boot/dts/qcom/sxr1130-usbc-mtp.dts | 28 +++++++ .../qcom/sxr1130-usbc-pm660a-mtp-overlay.dts | 35 +++++++++ .../boot/dts/qcom/sxr1130-usbc-pm660a-mtp.dts | 29 +++++++ arch/arm64/boot/dts/qcom/sxr1130.dts | 22 ++++++ arch/arm64/boot/dts/qcom/sxr1130.dtsi | 19 +++++ 26 files changed, 952 insertions(+), 2 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-cdp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-cdp.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-external-codec-cdp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-external-codec-cdp.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-external-codec-mtp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-external-codec-mtp.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-external-codec-pm660a-mtp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-external-codec-pm660a-mtp.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-mtp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-mtp.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-pm660a-mtp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-pm660a-mtp.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-cdp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-cdp.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-mtp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-mtp.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-pm660a-mtp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-pm660a-mtp.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-usbc-mtp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-usbc-mtp.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-usbc-pm660a-mtp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130-usbc-pm660a-mtp.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130.dts create mode 100644 arch/arm64/boot/dts/qcom/sxr1130.dtsi diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index b2640dab324d..74e90e64ee9d 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -101,6 +101,9 @@ SoCs: - SDA670 compatible = "qcom,sda670" +- SXR1130 + compatible = "qcom,sxr1130" + - MSM8952 compatible = "qcom,msm8952" @@ -321,6 +324,8 @@ compatible = "qcom,sda845-mtp" compatible = "qcom,sda845-qrd" compatible = "qcom,sda845-hdk" compatible = "qcom,sda845-svr" +compatible = "qcom,sxr1130-cdp" +compatible = "qcom,sxr1130-mtp" compatible = "qcom,sdm670-rumi" compatible = "qcom,sdm670-cdp" compatible = "qcom,sdm670-mtp" diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index dbaf7cd3e7be..15f53ee7b147 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -174,7 +174,18 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) sdm710-tasha-codec-cdp-overlay.dtbo \ sdm710-pm660a-tasha-codec-cdp-overlay.dtbo \ sdm710-aqt1000-cdp-overlay.dtbo \ - sdm710-pm660a-aqt1000-cdp-overlay.dtbo + sdm710-pm660a-aqt1000-cdp-overlay.dtbo \ + sxr1130-cdp-overlay.dtbo \ + sxr1130-external-codec-cdp-overlay.dtbo \ + sxr1130-mtp-overlay.dtbo \ + sxr1130-external-codec-mtp-overlay.dtbo \ + sxr1130-external-codec-pm660a-mtp-overlay.dtbo \ + sxr1130-pm660a-mtp-overlay.dtbo \ + sxr1130-usbc-external-codec-cdp-overlay.dtbo \ + sxr1130-usbc-external-codec-mtp-overlay.dtbo \ + sxr1130-usbc-external-codec-pm660a-mtp-overlay.dtbo \ + sxr1130-usbc-mtp-overlay.dtbo \ + sxr1130-usbc-pm660a-mtp-overlay.dtbo sdm670-cdp-overlay.dtbo-base := sdm670.dtb sdm670-mtp-overlay.dtbo-base := sdm670.dtb @@ -237,6 +248,17 @@ sdm710-tasha-codec-cdp-overlay.dtbo-base := sdm710.dtb sdm710-pm660a-tasha-codec-cdp-overlay.dtbo-base := sdm710.dtb sdm710-aqt1000-cdp-overlay.dtbo-base := sdm710.dtb sdm710-pm660a-aqt1000-cdp-overlay.dtbo-base := sdm710.dtb +sxr1130-cdp-overlay.dtbo-base := sxr1130.dtb +sxr1130-external-codec-cdp-overlay.dtbo-base := sxr1130.dtb +sxr1130-mtp-overlay.dtbo-base := sxr1130.dtb +sxr1130-external-codec-mtp-overlay.dtbo-base := sxr1130.dtb +sxr1130-external-codec-pm660a-mtp-overlay.dtbo-base := sxr1130.dtb +sxr1130-pm660a-mtp-overlay.dtbo-base := sxr1130.dtb +sxr1130-usbc-external-codec-cdp-overlay.dtbo-base := sxr1130.dtb +sxr1130-usbc-external-codec-mtp-overlay.dtbo-base := sxr1130.dtb +sxr1130-usbc-external-codec-pm660a-mtp-overlay.dtbo-base := sxr1130.dtb +sxr1130-usbc-mtp-overlay.dtbo-base := sxr1130.dtb +sxr1130-usbc-pm660a-mtp-overlay.dtbo-base := sxr1130.dtb else dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \ @@ -295,7 +317,18 @@ dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \ sdm710-usbc-pm660a-cdp.dtb \ sdm710-usbc-pm660a-mtp.dtb \ sdm710-tasha-codec-cdp.dtb \ - sdm710-pm660a-tasha-codec-cdp.dtb + sdm710-pm660a-tasha-codec-cdp.dtb \ + sxr1130-cdp.dtb \ + sxr1130-external-codec-cdp.dtb \ + sxr1130-mtp.dtb \ + sxr1130-external-codec-mtp.dtb \ + sxr1130-external-codec-pm660a-mtp.dtb \ + sxr1130-pm660a-mtp.dtb \ + sxr1130-usbc-external-codec-cdp.dtb \ + sxr1130-usbc-external-codec-mtp.dtb \ + sxr1130-usbc-external-codec-pm660a-mtp.dtb \ + sxr1130-usbc-mtp.dtb \ + sxr1130-usbc-pm660a-mtp.dtb endif ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) diff --git a/arch/arm64/boot/dts/qcom/sxr1130-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-cdp-overlay.dts new file mode 100644 index 000000000000..5fc70df26374 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-cdp-overlay.dts @@ -0,0 +1,78 @@ +/* + * 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 +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L CDP"; + compatible = "qcom,sxr1130-cdp", "qcom,sxr1130", "qcom,cdp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&cam_cci { + /delete-node/ qcom,cam-sensor@1; + 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>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_rear_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-cdp.dts b/arch/arm64/boot/dts/qcom/sxr1130-cdp.dts new file mode 100644 index 000000000000..7bcd1b62b5d3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-cdp.dts @@ -0,0 +1,72 @@ +/* + * 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 "sxr1130.dtsi" +#include "sdm670-cdp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L CDP"; + compatible = "qcom,sxr1130-cdp", "qcom,sxr1130", "qcom,cdp"; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&cam_cci { + /delete-node/ qcom,cam-sensor@1; + 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>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_rear_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-external-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-cdp-overlay.dts new file mode 100644 index 000000000000..d2153c5af43c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-cdp-overlay.dts @@ -0,0 +1,34 @@ +/* + * 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 +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L Ext. Audio Codec CDP"; + compatible = "qcom,sxr1130-cdp", "qcom,sxr1130", "qcom,cdp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <1 1>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-external-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-cdp.dts new file mode 100644 index 000000000000..b1d701e80c9a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-cdp.dts @@ -0,0 +1,28 @@ +/* + * 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 "sxr1130.dtsi" +#include "sdm670-cdp.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L Ext. Audio Codec CDP"; + compatible = "qcom,sxr1130-cdp", "qcom,sxr1130", "qcom,cdp"; + qcom,board-id = <1 1>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-mtp-overlay.dts new file mode 100644 index 000000000000..3288a64fbe68 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-mtp-overlay.dts @@ -0,0 +1,34 @@ +/* + * 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 +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L Ext. Audio Codec MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <8 1>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-mtp.dts new file mode 100644 index 000000000000..6dbb766b2c91 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-mtp.dts @@ -0,0 +1,28 @@ +/* + * 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 "sxr1130.dtsi" +#include "sdm670-mtp.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L Ext. Audio Codec MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,board-id = <8 1>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-external-codec-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-pm660a-mtp-overlay.dts new file mode 100644 index 000000000000..432035f0ce15 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-pm660a-mtp-overlay.dts @@ -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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660A Ext. Audio Codec MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <8 1>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-external-codec-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-pm660a-mtp.dts new file mode 100644 index 000000000000..4e134c5e4de8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-pm660a-mtp.dts @@ -0,0 +1,29 @@ +/* + * 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 "sxr1130.dtsi" +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660A Ext. Audio Codec MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,board-id = <8 1>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-mtp-overlay.dts new file mode 100644 index 000000000000..f8a2a9abe487 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-mtp-overlay.dts @@ -0,0 +1,78 @@ +/* + * 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 +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&cam_cci { + /delete-node/ qcom,cam-sensor@1; + 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>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-mtp.dts b/arch/arm64/boot/dts/qcom/sxr1130-mtp.dts new file mode 100644 index 000000000000..7f9f15521666 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-mtp.dts @@ -0,0 +1,72 @@ +/* + * 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 "sxr1130.dtsi" +#include "sdm670-mtp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&cam_cci { + /delete-node/ qcom,cam-sensor@1; + 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>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-pm660a-mtp-overlay.dts new file mode 100644 index 000000000000..288f0ed604f4 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-pm660a-mtp-overlay.dts @@ -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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660A MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sxr1130-pm660a-mtp.dts new file mode 100644 index 000000000000..ea5f197dc247 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-pm660a-mtp.dts @@ -0,0 +1,29 @@ +/* + * 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 "sxr1130.dtsi" +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660A MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-cdp-overlay.dts new file mode 100644 index 000000000000..9d7a70648c7a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-cdp-overlay.dts @@ -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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660+PM660L, USB-C Audio, Ext. Audio Codec CDP"; + compatible = "qcom,sxr1130-cdp", "qcom,sxr1130", "qcom,cdp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <1 3>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-cdp.dts new file mode 100644 index 000000000000..04a045f0c21b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-cdp.dts @@ -0,0 +1,29 @@ +/* + * 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 "sxr1130.dtsi" +#include "sdm670-cdp.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660+PM660L, USB-C Audio, Ext. Audio Codec CDP"; + compatible = "qcom,sxr1130-cdp", "qcom,sxr1130", "qcom,cdp"; + qcom,board-id = <1 3>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-mtp-overlay.dts new file mode 100644 index 000000000000..7d92bfc9739a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-mtp-overlay.dts @@ -0,0 +1,34 @@ +/* + * 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 +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660+PM660L, USB-C Audio, Ext. Audio Codec MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <8 3>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-mtp.dts new file mode 100644 index 000000000000..c551ef9e16a3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-mtp.dts @@ -0,0 +1,29 @@ +/* + * 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 "sxr1130.dtsi" +#include "sdm670-mtp.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660+PM660L, USB-C Audio, Ext. Audio Codec MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,board-id = <8 3>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-pm660a-mtp-overlay.dts new file mode 100644 index 000000000000..a3f8044b1564 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-pm660a-mtp-overlay.dts @@ -0,0 +1,36 @@ +/* + * 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 +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660+PM660A, USB-C Audio, Ext. Audio Codec MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <8 3>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-pm660a-mtp.dts new file mode 100644 index 000000000000..a3c56fcda163 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-pm660a-mtp.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/; + +#include "sxr1130.dtsi" +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660+PM660A, USB-C Audio, Ext. Audio Codec MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,board-id = <8 3>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-mtp-overlay.dts new file mode 100644 index 000000000000..a90d5506ca80 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-mtp-overlay.dts @@ -0,0 +1,34 @@ +/* + * 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 +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "sdm670-int-cdc-usbc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L, USB-C Audio, MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <8 2>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-mtp.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-mtp.dts new file mode 100644 index 000000000000..c3bf64b48070 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-mtp.dts @@ -0,0 +1,28 @@ +/* + * 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 "sxr1130.dtsi" +#include "sdm670-mtp.dtsi" +#include "sdm670-int-cdc-usbc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L, USB-C Audio, MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,board-id = <8 2>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-pm660a-mtp-overlay.dts new file mode 100644 index 000000000000..4b07f5ad1362 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-pm660a-mtp-overlay.dts @@ -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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-int-cdc-usbc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660A, USB-C Audio, MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <8 2>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-pm660a-mtp.dts new file mode 100644 index 000000000000..e311b61a870e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-pm660a-mtp.dts @@ -0,0 +1,29 @@ +/* + * 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 "sxr1130.dtsi" +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-int-cdc-usbc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660A, USB-C Audio, MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,board-id = <8 2>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130.dts b/arch/arm64/boot/dts/qcom/sxr1130.dts new file mode 100644 index 000000000000..abbf33424444 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130.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 "sxr1130.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 SoC"; + compatible = "qcom,sxr1130"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130.dtsi b/arch/arm64/boot/dts/qcom/sxr1130.dtsi new file mode 100644 index 000000000000..75707b197902 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130.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 "qcs605.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130"; + qcom,msm-id = <371 0x0>; +}; -- GitLab From 7e4d4ac8b4a9289cd2779c105eaa28dae883f5f4 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Fri, 3 Aug 2018 14:56:35 +0530 Subject: [PATCH 594/604] 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_v2/rmnet_ipa.c | 4 +++- drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c index 130afc729c21..e7abbe9410fa 100644 --- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c @@ -53,6 +53,7 @@ #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_DEVICE_COUNT (1) @@ -790,7 +791,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 IPA_UPSTEAM_MAX; diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index f1e2e6df037f..5ec331c1fb0b 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -53,6 +53,7 @@ #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 @@ -820,7 +821,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 a911b08d0e5681aae51163f6b66196cf5384058c Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Mon, 6 Aug 2018 15:00:46 +0530 Subject: [PATCH 595/604] ARM: dts: msm: Add camera support for MSM8917 CDP device Add camera device tree changes for MSM8917 CDP. Port msm-3.18 camera kernel on msm-4.9 kernel This snapshot is taken from msm-3.18 branch as of: 'commit 3e917a308af6 ("ARM: dts: msm: Add camera device tree files for MSMgold")'. Change-Id: Ic6944310e120175695351b91e1558cf20e474c5e Signed-off-by: Abhishek Jain --- .../dts/qcom/msm8917-camera-sensor-cdp.dtsi | 283 ++++++++++++++++++ arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi | 1 + 2 files changed, 284 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/msm8917-camera-sensor-cdp.dtsi diff --git a/arch/arm64/boot/dts/qcom/msm8917-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-camera-sensor-cdp.dtsi new file mode 100644 index 000000000000..23545f9d194d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-camera-sensor-cdp.dtsi @@ -0,0 +1,283 @@ +/* + * 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. + */ + +&cci { + actuator0: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + qcom,cci-master = <0>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <2850000>; + qcom,cam-vreg-max-voltage = <2850000>; + qcom,cam-vreg-op-mode = <80000>; + }; + + actuator1: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + qcom,cci-master = <0>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <2850000>; + qcom,cam-vreg-max-voltage = <2850000>; + qcom,cam-vreg-op-mode = <80000>; + }; + + eeprom0: qcom,eeprom@0 { + cell-index = <0>; + compatible = "qcom,eeprom"; + qcom,cci-master = <0>; + reg = <0x0>; + cam_vdig-supply = <&pm8937_l23>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio", + "cam_vaf"; + qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-op-mode = <200000 0 80000 100000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_default + &cam_sensor_rear_default>; + pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; + gpios = <&tlmm 26 0>, + <&tlmm 36 0>, + <&tlmm 35 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_STANDBY0"; + status = "ok"; + clocks = <&clock_gcc clk_mclk0_clk_src>, + <&clock_gcc clk_gcc_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <19200000 0>; + }; + + eeprom1: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + qcom,eeprom-name = "sunny_8865"; + compatible = "qcom,eeprom"; + qcom,slave-addr = <0x6c>; + qcom,cci-master = <0>; + qcom,num-blocks = <8>; + + qcom,page0 = <1 0x0100 2 0x01 1 1>; + qcom,poll0 = <0 0x0 2 0x0 1 0>; + qcom,mem0 = <0 0x0 2 0x0 1 0>; + + qcom,page1 = <1 0x5002 2 0x00 1 0>; + qcom,poll1 = <0 0x0 2 0x0 1 0>; + qcom,mem1 = <0 0x0 2 0x0 1 0>; + + qcom,page2 = <1 0x3d84 2 0xc0 1 0>; + qcom,poll2 = <0 0x0 2 0x0 1 0>; + qcom,mem2 = <0 0x0 2 0x0 1 0>; + + qcom,page3 = <1 0x3d88 2 0x70 1 0>; + qcom,poll3 = <0 0x0 2 0x0 1 0>; + qcom,mem3 = <0 0x0 2 0x0 1 0>; + + qcom,page4 = <1 0x3d89 2 0x10 1 0>; + qcom,poll4 = <0 0x0 2 0x0 1 0>; + qcom,mem4 = <0 0x0 2 0x0 1 0>; + + qcom,page5 = <1 0x3d8a 2 0x70 1 0>; + qcom,poll5 = <0 0x0 2 0x0 1 0>; + qcom,mem5 = <0 0x0 2 0x0 1 0>; + + qcom,page6 = <1 0x3d8b 2 0xf4 1 0>; + qcom,poll6 = <0 0x0 2 0x0 1 0>; + qcom,mem6 = <0 0x0 2 0x0 1 0>; + + qcom,page7 = <1 0x3d81 2 0x01 1 10>; + qcom,poll7 = <0 0x0 2 0x0 1 1>; + qcom,mem7 = <1536 0x7010 2 0 1 0>; + + cam_vdig-supply = <&pm8937_l23>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", + "cam_vaf"; + qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-op-mode = <105000 0 80000 100000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_default + &cam_sensor_front1_default>; + pinctrl-1 = <&cam_sensor_mclk2_sleep &cam_sensor_front1_sleep>; + gpios = <&tlmm 28 0>, + <&tlmm 40 0>, + <&tlmm 39 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_STANDBY2"; + qcom,cam-power-seq-type = "sensor_vreg", "sensor_vreg", + "sensor_vreg", + "sensor_gpio", "sensor_gpio" , "sensor_clk"; + qcom,cam-power-seq-val = "cam_vdig", "cam_vana", "cam_vio", + "sensor_gpio_reset", "sensor_gpio_standby", + "sensor_cam_mclk"; + qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>; + qcom,cam-power-seq-delay = <1 1 1 30 30 5>; + status = "ok"; + clocks = <&clock_gcc clk_mclk2_clk_src>, + <&clock_gcc clk_gcc_camss_mclk2_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <19200000 0>; + }; + + qcom,camera@0 { + cell-index = <0>; + compatible = "qcom,camera"; + reg = <0x0>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <270>; + qcom,led-flash-src = <&led_flash0>; + qcom,eeprom-src = <&eeprom0>; + qcom,actuator-src = <&actuator0>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vaf"; + qcom,cam-vreg-min-voltage = <0 2800000 2850000>; + qcom,cam-vreg-max-voltage = <0 2800000 2850000>; + qcom,cam-vreg-op-mode = <0 80000 100000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_default + &cam_sensor_rear_default + &cam_sensor_rear_vdig>; + pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep + &cam_sensor_rear_vdig_sleep>; + gpios = <&tlmm 26 0>, + <&tlmm 36 0>, + <&tlmm 35 0>, + <&tlmm 62 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-vdig = <3>; + qcom,gpio-req-tbl-num = <0 1 2 3>; + qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_STANDBY0", + "CAM_VDIG"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_gcc clk_mclk0_clk_src>, + <&clock_gcc clk_gcc_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@1 { + cell-index = <1>; + compatible = "qcom,camera"; + reg = <0x1>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <1>; + qcom,mount-angle = <90>; + cam_vdig-supply = <&pm8937_l23>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", + "cam_vaf"; + qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-op-mode = <200000 0 80000 100000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_default + &cam_sensor_front_default>; + pinctrl-1 = <&cam_sensor_mclk1_sleep + &cam_sensor_front_sleep>; + gpios = <&tlmm 27 0>, + <&tlmm 38 0>, + <&tlmm 50 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_STANDBY1"; + qcom,sensor-position = <0x100>; + qcom,sensor-mode = <1>; + qcom,cci-master = <1>; + clocks = <&clock_gcc clk_mclk1_clk_src>, + <&clock_gcc clk_gcc_camss_mclk1_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@2 { + cell-index = <2>; + compatible = "qcom,camera"; + reg = <0x02>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <1>; + qcom,mount-angle = <90>; + qcom,eeprom-src = <&eeprom1>; + qcom,actuator-src = <&actuator1>; + cam_vdig-supply = <&pm8937_l23>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", + "cam_vaf"; + qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-op-mode = <105000 0 80000 100000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_default + &cam_sensor_front1_default>; + pinctrl-1 = <&cam_sensor_mclk2_sleep + &cam_sensor_front1_sleep>; + gpios = <&tlmm 28 0>, + <&tlmm 40 0>, + <&tlmm 39 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_STANDBY2"; + qcom,sensor-position = <1>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_gcc clk_mclk2_clk_src>, + <&clock_gcc clk_gcc_camss_mclk2_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi index a804edd3cf89..7690931e65a3 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi @@ -12,6 +12,7 @@ */ #include +#include "msm8917-camera-sensor-cdp.dtsi" &soc { gpio_keys { -- GitLab From d5a10e49968056220ba1309f68aa54dec7d71ed6 Mon Sep 17 00:00:00 2001 From: Zhenhua Huang Date: Tue, 3 Jul 2018 18:40:59 +0800 Subject: [PATCH 596/604] ARM: dts: msm: Remove secure mem region for SDM429 Secure video CMA occupies above ~100MB memory. It has a terrible effect on page frame reclaim. So let us have secure CMA disabled on this 2GB memory target, and enable it when needed. CRs-Fixed: 2271462 Change-Id: I1094b8cefec3dbf9ec9c7c68223efa665a1d5b02 Signed-off-by: Zhenhua Huang --- arch/arm64/boot/dts/qcom/sdm429.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index 65f7b5e5edf7..9bb8a6cff0ee 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -94,6 +94,18 @@ < 1804800 5712 >; }; }; + + qcom,ion { + /delete-node/ qcom,ion-heap@8; + }; +}; + +&secure_mem { + status = "disabled"; +}; + +&kgsl_msm_iommu { + /delete-node/ gfx3d_secure; }; &funnel_apss { -- GitLab From 6c98c9e80a54eca32f34d8fb1e33b73d27e02a9e Mon Sep 17 00:00:00 2001 From: Pratham Pratap Date: Thu, 28 Jun 2018 14:26:24 +0530 Subject: [PATCH 597/604] defconfig: enable USB_LINK_LAYER_TEST on msm8953 Enable the LVS test driver which is used to validate USB SuperSpeed link layer compliance when running against a supported test system. Change-Id: I05c724e1752257eb0b4cb471b16beb6a66983e1d Signed-off-by: Pratham Pratap --- arch/arm64/configs/msm8953-perf_defconfig | 1 + arch/arm64/configs/msm8953_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig index 8004333b0038..f3c1e7b5923d 100644 --- a/arch/arm64/configs/msm8953-perf_defconfig +++ b/arch/arm64/configs/msm8953-perf_defconfig @@ -471,6 +471,7 @@ CONFIG_USB_DWC3=y CONFIG_USB_DWC3_MSM=y CONFIG_USB_SERIAL=y CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y CONFIG_NOP_USB_XCEIV=y CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_MSM_SSPHY_QMP=y diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig index c8691903065a..09aeb2e72c52 100644 --- a/arch/arm64/configs/msm8953_defconfig +++ b/arch/arm64/configs/msm8953_defconfig @@ -481,6 +481,7 @@ CONFIG_USB_DWC3=y CONFIG_USB_DWC3_MSM=y CONFIG_USB_SERIAL=y CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y CONFIG_NOP_USB_XCEIV=y CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_MSM_SSPHY_QMP=y -- GitLab From 852548eaf15805fc4b3f1e53ea55c7674baaab46 Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Wed, 8 Aug 2018 13:23:23 +0530 Subject: [PATCH 598/604] 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 e97ad01ef148..1ccfaa10e2e2 100644 --- a/mm/cma.c +++ b/mm/cma.c @@ -466,7 +466,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 e4648711ce691a18b3e1378418f51fa4fed7660e Mon Sep 17 00:00:00 2001 From: Kiran Gunda Date: Thu, 19 Jul 2018 15:02:59 +0530 Subject: [PATCH 599/604] leds: qpnp-wled: Add sysfs property to enable/disable the irq WLED interrupts need to be disabled and enabled during the entry and exit of the secure display use case respectively. Add sysfs property to allow the userspace to perform this operation. To disable the interrupts: echo 1 > /sys/class/leds/wled/secure_mode To enable the interrupts: echo 0 > /sys/class/leds/wled/secure_mode Change-Id: Iedf70bcf2fecefcd2e58c213a17bd8b545f93c7a Signed-off-by: Kiran Gunda --- drivers/leds/leds-qpnp-wled.c | 51 +++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c index 861d9876cf0b..d272ca6ac1d0 100644 --- a/drivers/leds/leds-qpnp-wled.c +++ b/drivers/leds/leds-qpnp-wled.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -420,6 +421,7 @@ struct qpnp_wled { bool prev_state; bool stepper_en; bool ovp_irq_disabled; + bool secure_mode; bool auto_calib_enabled; bool auto_calib_done; bool module_dis_perm; @@ -936,6 +938,46 @@ static ssize_t qpnp_wled_ramp_step_store(struct device *dev, return count; } +/* sysfs function for irqs enable/disable */ +static ssize_t qpnp_wled_irq_control(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct qpnp_wled *wled = dev_get_drvdata(dev); + int val, rc; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + if (val != 0 && val != 1) + return count; + + mutex_lock(&wled->lock); + /* Disable irqs */ + if (val == 1 && !wled->secure_mode) { + if (wled->ovp_irq > 0) + disable_irq(wled->ovp_irq); + + if (wled->sc_irq > 0) + disable_irq(wled->sc_irq); + + wled->secure_mode = true; + } else if (val == 0 && wled->secure_mode) { + if (wled->ovp_irq > 0) + enable_irq(wled->ovp_irq); + + if (wled->sc_irq > 0) + enable_irq(wled->sc_irq); + + wled->secure_mode = false; + } + + mutex_unlock(&wled->lock); + + return count; +} + /* sysfs show function for dim mode */ static ssize_t qpnp_wled_dim_mode_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1055,6 +1097,7 @@ static struct device_attribute qpnp_wled_attrs[] = { __ATTR(ramp_ms, 0664, qpnp_wled_ramp_ms_show, qpnp_wled_ramp_ms_store), __ATTR(ramp_step, 0664, qpnp_wled_ramp_step_show, qpnp_wled_ramp_step_store), + __ATTR(secure_mode, 0664, NULL, qpnp_wled_irq_control), }; /* worker for setting wled brightness */ @@ -1066,6 +1109,12 @@ static void qpnp_wled_work(struct work_struct *work) wled = container_of(work, struct qpnp_wled, work); mutex_lock(&wled->lock); + + if (wled->secure_mode) { + pr_debug("Can not set brightness in secure_mode\n "); + goto unlock_mutex; + } + level = wled->cdev.brightness; if (wled->brt_map_table) { @@ -2162,6 +2211,7 @@ static int qpnp_wled_config(struct qpnp_wled *wled) /* setup ovp and sc irqs */ if (wled->ovp_irq >= 0) { + irq_set_status_flags(wled->ovp_irq, IRQ_DISABLE_UNLAZY); rc = devm_request_threaded_irq(&wled->pdev->dev, wled->ovp_irq, NULL, qpnp_wled_ovp_irq_handler, IRQF_ONESHOT, "qpnp_wled_ovp_irq", wled); @@ -2182,6 +2232,7 @@ static int qpnp_wled_config(struct qpnp_wled *wled) if (wled->sc_irq >= 0) { wled->sc_cnt = 0; + irq_set_status_flags(wled->sc_irq, IRQ_DISABLE_UNLAZY); rc = devm_request_threaded_irq(&wled->pdev->dev, wled->sc_irq, NULL, qpnp_wled_sc_irq_handler, IRQF_ONESHOT, "qpnp_wled_sc_irq", wled); -- GitLab From fe6ba9b91913d330f937747cc1e9d8c3cde67b04 Mon Sep 17 00:00:00 2001 From: Kiran Gunda Date: Thu, 19 Jul 2018 15:16:28 +0530 Subject: [PATCH 600/604] regulator: qpnp-labibb: Add sysfs class to enable/disable the irq LAB/IBB interrupts need to be disabled and enabled during the entry and exit of the secure display use case respectively. Add sysfs property to allow the userspace to perform this operation To disable the interrupts: echo 1 > /sys/class/lcd_bias/secure_mode To enable the interrupts: echo 0 > /sys/class/lcd_bias/secure_mode Change-Id: Iddd5630c0ff6d3191f2cc0d45bd4e72b938728b0 Signed-off-by: Kiran Gunda --- drivers/regulator/qpnp-labibb-regulator.c | 79 ++++++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/qpnp-labibb-regulator.c b/drivers/regulator/qpnp-labibb-regulator.c index 88c5697c9386..d72af2095593 100644 --- a/drivers/regulator/qpnp-labibb-regulator.c +++ b/drivers/regulator/qpnp-labibb-regulator.c @@ -597,6 +597,7 @@ struct qpnp_labibb { struct device *dev; struct platform_device *pdev; struct regmap *regmap; + struct class labibb_class; struct pmic_revid_data *pmic_rev_id; u16 lab_base; u16 ibb_base; @@ -624,6 +625,8 @@ struct qpnp_labibb { bool notify_lab_vreg_ok_sts; bool detect_lab_sc; bool sc_detected; + /* Tracks the secure UI mode entry/exit */ + bool secure_mode; u32 swire_2nd_cmd_delay; u32 swire_ibb_ps_enable_delay; }; @@ -2463,6 +2466,9 @@ static int qpnp_lab_regulator_enable(struct regulator_dev *rdev) int rc; struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); + if (labibb->secure_mode) + return 0; + if (labibb->sc_detected) { pr_info("Short circuit detected: disabled LAB/IBB rails\n"); return 0; @@ -2500,6 +2506,9 @@ static int qpnp_lab_regulator_disable(struct regulator_dev *rdev) u8 val; struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); + if (labibb->secure_mode) + return 0; + if (labibb->lab_vreg.vreg_enabled && !labibb->swire_control) { if (!labibb->standalone) @@ -2693,7 +2702,7 @@ static int qpnp_lab_regulator_set_voltage(struct regulator_dev *rdev, u8 val; struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); - if (labibb->swire_control) + if (labibb->swire_control || labibb->secure_mode) return 0; if (min_uV < labibb->lab_vreg.min_volt) { @@ -3072,6 +3081,8 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, } if (is_lab_vreg_ok_irq_available(labibb)) { + irq_set_status_flags(labibb->lab_vreg.lab_vreg_ok_irq, + IRQ_DISABLE_UNLAZY); rc = devm_request_threaded_irq(labibb->dev, labibb->lab_vreg.lab_vreg_ok_irq, NULL, lab_vreg_ok_handler, @@ -3085,6 +3096,8 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, } if (labibb->lab_vreg.lab_sc_irq != -EINVAL) { + irq_set_status_flags(labibb->lab_vreg.lab_sc_irq, + IRQ_DISABLE_UNLAZY); rc = devm_request_threaded_irq(labibb->dev, labibb->lab_vreg.lab_sc_irq, NULL, labibb_sc_err_handler, @@ -3568,6 +3581,9 @@ static int qpnp_ibb_regulator_enable(struct regulator_dev *rdev) int rc = 0; struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); + if (labibb->secure_mode) + return 0; + if (labibb->sc_detected) { pr_info("Short circuit detected: disabled LAB/IBB rails\n"); return 0; @@ -3593,6 +3609,9 @@ static int qpnp_ibb_regulator_disable(struct regulator_dev *rdev) int rc; struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); + if (labibb->secure_mode) + return 0; + if (labibb->ibb_vreg.vreg_enabled && !labibb->swire_control) { if (!labibb->standalone) @@ -3626,7 +3645,7 @@ static int qpnp_ibb_regulator_set_voltage(struct regulator_dev *rdev, struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); - if (labibb->swire_control) + if (labibb->swire_control || labibb->secure_mode) return 0; rc = labibb->ibb_ver_ops->set_voltage(labibb, min_uV, max_uV); @@ -3855,6 +3874,8 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, } if (labibb->ibb_vreg.ibb_sc_irq != -EINVAL) { + irq_set_status_flags(labibb->ibb_vreg.ibb_sc_irq, + IRQ_DISABLE_UNLAZY); rc = devm_request_threaded_irq(labibb->dev, labibb->ibb_vreg.ibb_sc_irq, NULL, labibb_sc_err_handler, @@ -4016,6 +4037,49 @@ static int qpnp_labibb_check_ttw_supported(struct qpnp_labibb *labibb) return rc; } +static ssize_t qpnp_labibb_irq_control(struct class *c, + struct class_attribute *attr, + const char *buf, size_t count) +{ + struct qpnp_labibb *labibb = container_of(c, struct qpnp_labibb, + labibb_class); + int val, rc; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + if (val != 0 && val != 1) + return count; + + /* Disable irqs */ + if (val == 1 && !labibb->secure_mode) { + if (labibb->lab_vreg.lab_vreg_ok_irq > 0) + disable_irq(labibb->lab_vreg.lab_vreg_ok_irq); + if (labibb->lab_vreg.lab_sc_irq > 0) + disable_irq(labibb->lab_vreg.lab_sc_irq); + if (labibb->ibb_vreg.ibb_sc_irq > 0) + disable_irq(labibb->ibb_vreg.ibb_sc_irq); + labibb->secure_mode = true; + } else if (val == 0 && labibb->secure_mode) { + if (labibb->lab_vreg.lab_vreg_ok_irq > 0) + enable_irq(labibb->lab_vreg.lab_vreg_ok_irq); + if (labibb->lab_vreg.lab_sc_irq > 0) + enable_irq(labibb->lab_vreg.lab_sc_irq); + if (labibb->ibb_vreg.ibb_sc_irq > 0) + enable_irq(labibb->ibb_vreg.ibb_sc_irq); + labibb->secure_mode = false; + } + + return count; +} + +static struct class_attribute labibb_attributes[] = { + [0] = __ATTR(secure_mode, 0664, NULL, + qpnp_labibb_irq_control), + __ATTR_NULL, +}; + static int qpnp_labibb_regulator_probe(struct platform_device *pdev) { struct qpnp_labibb *labibb; @@ -4208,6 +4272,17 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) CLOCK_MONOTONIC, HRTIMER_MODE_REL); labibb->sc_err_check_timer.function = labibb_check_sc_err_count; dev_set_drvdata(&pdev->dev, labibb); + + labibb->labibb_class.name = "lcd_bias"; + labibb->labibb_class.owner = THIS_MODULE; + labibb->labibb_class.class_attrs = labibb_attributes; + + rc = class_register(&labibb->labibb_class); + if (rc < 0) { + pr_err("Failed to register labibb class rc=%d\n", rc); + return rc; + } + pr_info("LAB/IBB registered successfully, lab_vreg enable=%d ibb_vreg enable=%d swire_control=%d\n", labibb->lab_vreg.vreg_enabled, labibb->ibb_vreg.vreg_enabled, -- GitLab From f4584e1bcae1345474563923bdc3687bfd3b61c2 Mon Sep 17 00:00:00 2001 From: Rama Krishna Phani A Date: Fri, 1 Jun 2018 20:17:32 +0530 Subject: [PATCH 601/604] msm: mhi_dev: Reorganize the mhi header file Reorganize the mhi header file. Change-Id: If21a778ee7f5935b9fbe257fbb4f3cc5a9944778 Signed-off-by: Rama Krishna Phani A --- drivers/platform/msm/mhi_dev/mhi.c | 2 +- drivers/platform/msm/mhi_dev/mhi_dev_net.c | 2 +- drivers/platform/msm/mhi_dev/mhi_mmio.c | 2 +- drivers/platform/msm/mhi_dev/mhi_ring.c | 2 +- drivers/platform/msm/mhi_dev/mhi_sm.h | 4 ++-- drivers/platform/msm/mhi_dev/mhi_uci.c | 2 +- .../platform/msm/mhi_dev/mhi.h => include/linux/msm_mhi_dev.h | 0 7 files changed, 7 insertions(+), 7 deletions(-) rename drivers/platform/msm/mhi_dev/mhi.h => include/linux/msm_mhi_dev.h (100%) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 3e245cc25e45..bc506b1b2eb0 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -29,7 +29,7 @@ #include #include -#include "mhi.h" +#include #include "mhi_hwio.h" #include "mhi_sm.h" diff --git a/drivers/platform/msm/mhi_dev/mhi_dev_net.c b/drivers/platform/msm/mhi_dev/mhi_dev_net.c index d8dc85f72ba0..d5cc14809184 100644 --- a/drivers/platform/msm/mhi_dev/mhi_dev_net.c +++ b/drivers/platform/msm/mhi_dev/mhi_dev_net.c @@ -28,7 +28,7 @@ #include #include -#include "mhi.h" +#include #define MHI_NET_DRIVER_NAME "mhi_dev_net_drv" #define MHI_NET_DEV_NAME "mhi_dev_net%d" diff --git a/drivers/platform/msm/mhi_dev/mhi_mmio.c b/drivers/platform/msm/mhi_dev/mhi_mmio.c index 559fa8411a01..21cca6e1c133 100644 --- a/drivers/platform/msm/mhi_dev/mhi_mmio.c +++ b/drivers/platform/msm/mhi_dev/mhi_mmio.c @@ -25,7 +25,7 @@ #include #include -#include "mhi.h" +#include #include "mhi_hwio.h" int mhi_dev_mmio_read(struct mhi_dev *dev, uint32_t offset, diff --git a/drivers/platform/msm/mhi_dev/mhi_ring.c b/drivers/platform/msm/mhi_dev/mhi_ring.c index 92b061648cd8..27993dfa3c4c 100644 --- a/drivers/platform/msm/mhi_dev/mhi_ring.c +++ b/drivers/platform/msm/mhi_dev/mhi_ring.c @@ -24,7 +24,7 @@ #include #include -#include "mhi.h" +#include static uint32_t mhi_dev_ring_addr2ofst(struct mhi_dev_ring *ring, uint64_t p) { diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.h b/drivers/platform/msm/mhi_dev/mhi_sm.h index 01e127b77f20..07e74448eef9 100644 --- a/drivers/platform/msm/mhi_dev/mhi_sm.h +++ b/drivers/platform/msm/mhi_dev/mhi_sm.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015,2017-2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -13,7 +13,7 @@ #ifndef MHI_SM_H #define MHI_SM_H -#include "mhi.h" +#include #include #include diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c index 52d324ef93c5..4e219a6d9c88 100644 --- a/drivers/platform/msm/mhi_dev/mhi_uci.c +++ b/drivers/platform/msm/mhi_dev/mhi_uci.c @@ -27,7 +27,7 @@ #include #include #include -#include "mhi.h" +#include #define MHI_SOFTWARE_CLIENT_START 0 #define MHI_SOFTWARE_CLIENT_LIMIT (MHI_MAX_SOFTWARE_CHANNELS/2) diff --git a/drivers/platform/msm/mhi_dev/mhi.h b/include/linux/msm_mhi_dev.h similarity index 100% rename from drivers/platform/msm/mhi_dev/mhi.h rename to include/linux/msm_mhi_dev.h -- GitLab From a39a433bc54f992ad17ff4b17bdb05e83daa6944 Mon Sep 17 00:00:00 2001 From: Rama Krishna Phani A Date: Tue, 26 Jun 2018 20:27:01 +0530 Subject: [PATCH 602/604] msm: mhi_dev: Reorganize the mhi header file Reorganize the mhi header file. Expose MHI api's that are required for clients. Change-Id: I707dedfe621770da69e46c9bdbd09d657af76184 Signed-off-by: Rama Krishna Phani A --- drivers/platform/msm/mhi_dev/mhi.c | 2 +- drivers/platform/msm/mhi_dev/mhi.h | 1090 +++++++++++++++++++ drivers/platform/msm/mhi_dev/mhi_dev_net.c | 2 +- drivers/platform/msm/mhi_dev/mhi_mmio.c | 2 +- drivers/platform/msm/mhi_dev/mhi_ring.c | 2 +- drivers/platform/msm/mhi_dev/mhi_sm.h | 2 +- drivers/platform/msm/mhi_dev/mhi_uci.c | 2 +- include/linux/msm_mhi_dev.h | 1143 +------------------- 8 files changed, 1148 insertions(+), 1097 deletions(-) create mode 100644 drivers/platform/msm/mhi_dev/mhi.h diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index bc506b1b2eb0..3e245cc25e45 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -29,7 +29,7 @@ #include #include -#include +#include "mhi.h" #include "mhi_hwio.h" #include "mhi_sm.h" diff --git a/drivers/platform/msm/mhi_dev/mhi.h b/drivers/platform/msm/mhi_dev/mhi.h new file mode 100644 index 000000000000..6cb2d7d270d3 --- /dev/null +++ b/drivers/platform/msm/mhi_dev/mhi.h @@ -0,0 +1,1090 @@ +/* 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 __MHI_H +#define __MHI_H + +#include +#include +#include + +/** + * MHI control data structures alloted by the host, including + * channel context array, event context array, command context and rings. + */ + +/* Channel context state */ +enum mhi_dev_ch_ctx_state { + MHI_DEV_CH_STATE_DISABLED, + MHI_DEV_CH_STATE_ENABLED, + MHI_DEV_CH_STATE_RUNNING, + MHI_DEV_CH_STATE_SUSPENDED, + MHI_DEV_CH_STATE_STOP, + MHI_DEV_CH_STATE_ERROR, + MHI_DEV_CH_STATE_RESERVED, + MHI_DEV_CH_STATE_32BIT = 0x7FFFFFFF +}; + +/* Channel type */ +enum mhi_dev_ch_ctx_type { + MHI_DEV_CH_TYPE_NONE, + MHI_DEV_CH_TYPE_OUTBOUND_CHANNEL, + MHI_DEV_CH_TYPE_INBOUND_CHANNEL, + MHI_DEV_CH_RESERVED +}; + +/* Channel context type */ +struct mhi_dev_ch_ctx { + enum mhi_dev_ch_ctx_state ch_state; + enum mhi_dev_ch_ctx_type ch_type; + uint32_t err_indx; + uint64_t rbase; + uint64_t rlen; + uint64_t rp; + uint64_t wp; +} __packed; + +enum mhi_dev_ring_element_type_id { + MHI_DEV_RING_EL_INVALID = 0, + MHI_DEV_RING_EL_NOOP = 1, + MHI_DEV_RING_EL_TRANSFER = 2, + MHI_DEV_RING_EL_RESET = 16, + MHI_DEV_RING_EL_STOP = 17, + MHI_DEV_RING_EL_START = 18, + MHI_DEV_RING_EL_MHI_STATE_CHG = 32, + MHI_DEV_RING_EL_CMD_COMPLETION_EVT = 33, + MHI_DEV_RING_EL_TRANSFER_COMPLETION_EVENT = 34, + MHI_DEV_RING_EL_EE_STATE_CHANGE_NOTIFY = 64, + MHI_DEV_RING_EL_UNDEF +}; + +enum mhi_dev_ring_state { + RING_STATE_UINT = 0, + RING_STATE_IDLE, + RING_STATE_PENDING, +}; + +enum mhi_dev_ring_type { + RING_TYPE_CMD = 0, + RING_TYPE_ER, + RING_TYPE_CH, + RING_TYPE_INVAL +}; + +/* Event context interrupt moderation */ +enum mhi_dev_evt_ctx_int_mod_timer { + MHI_DEV_EVT_INT_MODERATION_DISABLED +}; + +/* Event ring type */ +enum mhi_dev_evt_ctx_event_ring_type { + MHI_DEV_EVT_TYPE_DEFAULT, + MHI_DEV_EVT_TYPE_VALID, + MHI_DEV_EVT_RESERVED +}; + +/* Event ring context type */ +struct mhi_dev_ev_ctx { + uint32_t res1:16; + enum mhi_dev_evt_ctx_int_mod_timer intmodt:16; + enum mhi_dev_evt_ctx_event_ring_type ertype; + uint32_t msivec; + uint64_t rbase; + uint64_t rlen; + uint64_t rp; + uint64_t wp; +} __packed; + +/* Command context */ +struct mhi_dev_cmd_ctx { + uint32_t res1; + uint32_t res2; + uint32_t res3; + uint64_t rbase; + uint64_t rlen; + uint64_t rp; + uint64_t wp; +} __packed; + +/* generic context */ +struct mhi_dev_gen_ctx { + uint32_t res1; + uint32_t res2; + uint32_t res3; + uint64_t rbase; + uint64_t rlen; + uint64_t rp; + uint64_t wp; +} __packed; + +/* Transfer ring element */ +struct mhi_dev_transfer_ring_element { + uint64_t data_buf_ptr; + uint32_t len:16; + uint32_t res1:16; + uint32_t chain:1; + uint32_t res2:7; + uint32_t ieob:1; + uint32_t ieot:1; + uint32_t bei:1; + uint32_t res3:5; + enum mhi_dev_ring_element_type_id type:8; + uint32_t res4:8; +} __packed; + +/* Command ring element */ +/* Command ring No op command */ +struct mhi_dev_cmd_ring_op { + uint64_t res1; + uint32_t res2; + uint32_t res3:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t chid:8; +} __packed; + +/* Command ring reset channel command */ +struct mhi_dev_cmd_ring_reset_channel_cmd { + uint64_t res1; + uint32_t res2; + uint32_t res3:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t chid:8; +} __packed; + +/* Command ring stop channel command */ +struct mhi_dev_cmd_ring_stop_channel_cmd { + uint64_t res1; + uint32_t res2; + uint32_t res3:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t chid:8; +} __packed; + +/* Command ring start channel command */ +struct mhi_dev_cmd_ring_start_channel_cmd { + uint64_t res1; + uint32_t seqnum; + uint32_t reliable:1; + uint32_t res2:15; + enum mhi_dev_ring_element_type_id type:8; + uint32_t chid:8; +} __packed; + +enum mhi_dev_cmd_completion_code { + MHI_CMD_COMPL_CODE_INVALID = 0, + MHI_CMD_COMPL_CODE_SUCCESS = 1, + MHI_CMD_COMPL_CODE_EOT = 2, + MHI_CMD_COMPL_CODE_OVERFLOW = 3, + MHI_CMD_COMPL_CODE_EOB = 4, + MHI_CMD_COMPL_CODE_UNDEFINED = 16, + MHI_CMD_COMPL_CODE_RING_EL = 17, + MHI_CMD_COMPL_CODE_RES +}; + +/* Event ring elements */ +/* Transfer completion event */ +struct mhi_dev_event_ring_transfer_completion { + uint64_t ptr; + uint32_t len:16; + uint32_t res1:8; + enum mhi_dev_cmd_completion_code code:8; + uint32_t res2:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t chid:8; +} __packed; + +/* Command completion event */ +struct mhi_dev_event_ring_cmd_completion { + uint64_t ptr; + uint32_t res1:24; + enum mhi_dev_cmd_completion_code code:8; + uint32_t res2:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t res3:8; +} __packed; + +enum mhi_dev_state { + MHI_DEV_RESET_STATE = 0, + MHI_DEV_READY_STATE, + MHI_DEV_M0_STATE, + MHI_DEV_M1_STATE, + MHI_DEV_M2_STATE, + MHI_DEV_M3_STATE, + MHI_DEV_MAX_STATE, + MHI_DEV_SYSERR_STATE = 0xff +}; + +/* MHI state change event */ +struct mhi_dev_event_ring_state_change { + uint64_t ptr; + uint32_t res1:24; + enum mhi_dev_state mhistate:8; + uint32_t res2:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t res3:8; +} __packed; + +enum mhi_dev_execenv { + MHI_DEV_SBL_EE = 1, + MHI_DEV_AMSS_EE = 2, + MHI_DEV_UNRESERVED +}; + +/* EE state change event */ +struct mhi_dev_event_ring_ee_state_change { + uint64_t ptr; + uint32_t res1:24; + enum mhi_dev_execenv execenv:8; + uint32_t res2:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t res3:8; +} __packed; + +/* Generic cmd to parse common details like type and channel id */ +struct mhi_dev_ring_generic { + uint64_t ptr; + uint32_t res1:24; + enum mhi_dev_state mhistate:8; + uint32_t res2:16; + enum mhi_dev_ring_element_type_id type:8; + uint32_t chid:8; +} __packed; + +struct mhi_config { + uint32_t mhi_reg_len; + uint32_t version; + uint32_t event_rings; + uint32_t channels; + uint32_t chdb_offset; + uint32_t erdb_offset; +}; + +#define NUM_CHANNELS 128 +#define HW_CHANNEL_BASE 100 +#define HW_CHANNEL_END 107 +#define MHI_ENV_VALUE 2 +#define MHI_MASK_ROWS_CH_EV_DB 4 +#define TRB_MAX_DATA_SIZE 8192 +#define MHI_CTRL_STATE 100 + +/*maximum trasnfer completion events buffer*/ +#define MAX_TR_EVENTS 50 +/*maximum event requests */ +#define MHI_MAX_EVT_REQ 50 + +/* Possible ring element types */ +union mhi_dev_ring_element_type { + struct mhi_dev_cmd_ring_op cmd_no_op; + struct mhi_dev_cmd_ring_reset_channel_cmd cmd_reset; + struct mhi_dev_cmd_ring_stop_channel_cmd cmd_stop; + struct mhi_dev_cmd_ring_start_channel_cmd cmd_start; + struct mhi_dev_transfer_ring_element tre; + struct mhi_dev_event_ring_transfer_completion evt_tr_comp; + struct mhi_dev_event_ring_cmd_completion evt_cmd_comp; + struct mhi_dev_event_ring_state_change evt_state_change; + struct mhi_dev_event_ring_ee_state_change evt_ee_state; + struct mhi_dev_ring_generic generic; +}; + +/* Transfer ring element type */ +union mhi_dev_ring_ctx { + struct mhi_dev_cmd_ctx cmd; + struct mhi_dev_ev_ctx ev; + struct mhi_dev_ch_ctx ch; + struct mhi_dev_gen_ctx generic; +}; + +/* MHI host Control and data address region */ +struct mhi_host_addr { + uint32_t ctrl_base_lsb; + uint32_t ctrl_base_msb; + uint32_t ctrl_limit_lsb; + uint32_t ctrl_limit_msb; + uint32_t data_base_lsb; + uint32_t data_base_msb; + uint32_t data_limit_lsb; + uint32_t data_limit_msb; +}; + +/* MHI physical and virtual address region */ +struct mhi_meminfo { + struct device *dev; + uintptr_t pa_aligned; + uintptr_t pa_unaligned; + uintptr_t va_aligned; + uintptr_t va_unaligned; + uintptr_t size; +}; + +struct mhi_addr { + uint64_t host_pa; + uintptr_t device_pa; + uintptr_t device_va; + size_t size; + dma_addr_t phy_addr; + void *virt_addr; + bool use_ipa_dma; +}; + +struct mhi_interrupt_state { + uint32_t mask; + uint32_t status; +}; + +enum mhi_dev_channel_state { + MHI_DEV_CH_UNINT, + MHI_DEV_CH_STARTED, + MHI_DEV_CH_PENDING_START, + MHI_DEV_CH_PENDING_STOP, + MHI_DEV_CH_STOPPED, + MHI_DEV_CH_CLOSED, +}; + +enum mhi_dev_ch_operation { + MHI_DEV_OPEN_CH, + MHI_DEV_CLOSE_CH, + MHI_DEV_READ_CH, + MHI_DEV_READ_WR, + MHI_DEV_POLL, +}; + +enum mhi_dev_tr_compl_evt_type { + SEND_EVENT_BUFFER, + SEND_EVENT_RD_OFFSET, +}; + +enum mhi_dev_transfer_type { + MHI_DEV_DMA_SYNC, + MHI_DEV_DMA_ASYNC, +}; + +struct mhi_dev_channel; + +struct mhi_dev_ring { + struct list_head list; + struct mhi_dev *mhi_dev; + + uint32_t id; + uint32_t rd_offset; + uint32_t wr_offset; + uint32_t ring_size; + + enum mhi_dev_ring_type type; + enum mhi_dev_ring_state state; + + /* device virtual address location of the cached host ring ctx data */ + union mhi_dev_ring_element_type *ring_cache; + /* Physical address of the cached ring copy on the device side */ + dma_addr_t ring_cache_dma_handle; + /* Physical address of the host where we will write/read to/from */ + struct mhi_addr ring_shadow; + /* Ring type - cmd, event, transfer ring and its rp/wp... */ + union mhi_dev_ring_ctx *ring_ctx; + /* ring_ctx_shadow -> tracking ring_ctx in the host */ + union mhi_dev_ring_ctx *ring_ctx_shadow; + void (*ring_cb)(struct mhi_dev *dev, + union mhi_dev_ring_element_type *el, + void *ctx); +}; + +static inline void mhi_dev_ring_inc_index(struct mhi_dev_ring *ring, + uint32_t rd_offset) +{ + ring->rd_offset++; + if (ring->rd_offset == ring->ring_size) + ring->rd_offset = 0; +} + +/* trace information planned to use for read/write */ +#define TRACE_DATA_MAX 128 +#define MHI_DEV_DATA_MAX 512 + +#define MHI_DEV_MMIO_RANGE 0xc80 + +struct ring_cache_req { + struct completion *done; + void *context; +}; + +struct event_req { + union mhi_dev_ring_element_type *tr_events; + u32 num_events; + dma_addr_t dma; + u32 dma_len; + dma_addr_t event_rd_dma; + void *context; + enum mhi_dev_tr_compl_evt_type event_type; + u32 event_ring; + void (*client_cb)(void *req); + struct list_head list; +}; + +struct mhi_dev_channel { + struct list_head list; + struct list_head clients; + /* synchronization for changing channel state, + * adding/removing clients, mhi_dev callbacks, etc + */ + struct mhi_dev_ring *ring; + + enum mhi_dev_channel_state state; + uint32_t ch_id; + enum mhi_dev_ch_ctx_type ch_type; + struct mutex ch_lock; + /* client which the current inbound/outbound message is for */ + struct mhi_dev_client *active_client; + /* + * Pointer to event request structs used to temporarily store + * completion events and meta data before sending them to host + */ + struct event_req *ereqs; + /* Pointer to completion event buffers */ + union mhi_dev_ring_element_type *tr_events; + struct list_head event_req_buffers; + struct event_req *curr_ereq; + + /* current TRE being processed */ + uint64_t tre_loc; + /* current TRE size */ + uint32_t tre_size; + /* tre bytes left to read/write */ + uint32_t tre_bytes_left; + /* td size being read/written from/to so far */ + uint32_t td_size; + bool wr_request_active; + bool skip_td; +}; + +/* Structure device for mhi dev */ +struct mhi_dev { + struct platform_device *pdev; + struct device *dev; + /* MHI MMIO related members */ + phys_addr_t mmio_base_pa_addr; + void *mmio_base_addr; + phys_addr_t ipa_uc_mbox_crdb; + phys_addr_t ipa_uc_mbox_erdb; + + uint32_t *mmio_backup; + struct mhi_config cfg; + bool mmio_initialized; + + spinlock_t lock; + /* Host control base information */ + struct mhi_host_addr host_addr; + struct mhi_addr ctrl_base; + struct mhi_addr data_base; + struct mhi_addr ch_ctx_shadow; + struct mhi_dev_ch_ctx *ch_ctx_cache; + dma_addr_t ch_ctx_cache_dma_handle; + struct mhi_addr ev_ctx_shadow; + struct mhi_dev_ch_ctx *ev_ctx_cache; + dma_addr_t ev_ctx_cache_dma_handle; + + struct mhi_addr cmd_ctx_shadow; + struct mhi_dev_ch_ctx *cmd_ctx_cache; + dma_addr_t cmd_ctx_cache_dma_handle; + struct mhi_dev_ring *ring; + int mhi_irq; + struct mhi_dev_channel *ch; + + int ctrl_int; + int cmd_int; + /* CHDB and EVDB device interrupt state */ + struct mhi_interrupt_state chdb[4]; + struct mhi_interrupt_state evdb[4]; + + /* Scheduler work */ + struct work_struct chdb_ctrl_work; + + struct mutex mhi_lock; + struct mutex mhi_event_lock; + + /* process a ring element */ + struct workqueue_struct *pending_ring_wq; + struct work_struct pending_work; + + struct list_head event_ring_list; + struct list_head process_ring_list; + + uint32_t cmd_ring_idx; + uint32_t ev_ring_start; + uint32_t ch_ring_start; + + /* IPA Handles */ + u32 ipa_clnt_hndl[4]; + struct workqueue_struct *ring_init_wq; + struct work_struct ring_init_cb_work; + struct work_struct re_init; + + /* EP PCIe registration */ + struct workqueue_struct *pcie_event_wq; + struct ep_pcie_register_event event_reg; + u32 ifc_id; + struct ep_pcie_hw *phandle; + struct work_struct pcie_event; + struct ep_pcie_msi_config msi_cfg; + + atomic_t write_active; + atomic_t is_suspended; + atomic_t mhi_dev_wake; + atomic_t re_init_done; + struct mutex mhi_write_test; + u32 device_local_pa_base; + u32 mhi_ep_msi_num; + u32 mhi_version; + void *dma_cache; + void *read_handle; + void *write_handle; + /* Physical scratch buffer for writing control data to the host */ + dma_addr_t cache_dma_handle; + /* + * Physical scratch buffer address used when picking host data + * from the host used in mhi_read() + */ + dma_addr_t read_dma_handle; + /* + * Physical scratch buffer address used when writing to the host + * region from device used in mhi_write() + */ + dma_addr_t write_dma_handle; + + /* Use IPA DMA for Software channel data transfer */ + bool use_ipa; + + /* iATU is required to map control and data region */ + bool config_iatu; + + /* MHI state info */ + enum mhi_ctrl_info ctrl_info; + + /*Register for interrupt*/ + bool mhi_int; + bool mhi_int_en; + /* Registered client callback list */ + struct list_head client_cb_list; + + struct kobj_uevent_env kobj_env; +}; + + +enum mhi_msg_level { + MHI_MSG_VERBOSE = 0x0, + MHI_MSG_INFO = 0x1, + MHI_MSG_DBG = 0x2, + MHI_MSG_WARNING = 0x3, + MHI_MSG_ERROR = 0x4, + MHI_MSG_CRITICAL = 0x5, + MHI_MSG_reserved = 0x80000000 +}; + +extern enum mhi_msg_level mhi_msg_lvl; +extern enum mhi_msg_level mhi_ipc_msg_lvl; +extern void *mhi_ipc_log; + +#define mhi_log(_msg_lvl, _msg, ...) do { \ + if (_msg_lvl >= mhi_msg_lvl) { \ + pr_err("[%s] "_msg, __func__, ##__VA_ARGS__); \ + } \ + if (mhi_ipc_log && (_msg_lvl >= mhi_ipc_msg_lvl)) { \ + ipc_log_string(mhi_ipc_log, \ + "[%s] " _msg, __func__, ##__VA_ARGS__); \ + } \ +} while (0) + + +/* Use ID 0 for legacy /dev/mhi_ctrl. Channel 0 used for internal only */ +#define MHI_DEV_UEVENT_CTRL 0 + +struct mhi_dev_uevent_info { + enum mhi_client_channel channel; + enum mhi_ctrl_info ctrl_info; +}; + +struct mhi_dev_iov { + void *addr; + uint32_t buf_size; +}; + + +struct mhi_dev_trace { + unsigned int timestamp; + uint32_t data[TRACE_DATA_MAX]; +}; + +/* MHI Ring related functions */ + +/** + * mhi_ring_init() - Initializes the Ring id to the default un-initialized + * state. Once a start command is received, the respective ring + * is then prepared by fetching the context and updating the + * offset. + * @ring: Ring for the respective context - Channel/Event/Command. + * @type: Command/Event or Channel transfer ring. + * @id: Index to the ring id. For command its usually 1, Event rings + * may vary from 1 to 128. Channels vary from 1 to 256. + */ +void mhi_ring_init(struct mhi_dev_ring *ring, + enum mhi_dev_ring_type type, int id); + +/** + * mhi_ring_start() - Fetches the respective transfer ring's context from + * the host and updates the write offset. + * @ring: Ring for the respective context - Channel/Event/Command. + * @ctx: Transfer ring of type mhi_dev_ring_ctx. + * @dev: MHI device structure. + */ +int mhi_ring_start(struct mhi_dev_ring *ring, + union mhi_dev_ring_ctx *ctx, struct mhi_dev *mhi); + +/** + * mhi_dev_cache_ring() - Cache the data for the corresponding ring locally. + * @ring: Ring for the respective context - Channel/Event/Command. + * @wr_offset: Cache the TRE's upto the write offset value. + */ +int mhi_dev_cache_ring(struct mhi_dev_ring *ring, uint32_t wr_offset); + +/** + * mhi_dev_update_wr_offset() - Check for any updates in the write offset. + * @ring: Ring for the respective context - Channel/Event/Command. + */ +int mhi_dev_update_wr_offset(struct mhi_dev_ring *ring); + +/** + * mhi_dev_process_ring() - Update the Write pointer, fetch the ring elements + * and invoke the clients callback. + * @ring: Ring for the respective context - Channel/Event/Command. + */ +int mhi_dev_process_ring(struct mhi_dev_ring *ring); + +/** + * mhi_dev_process_ring_element() - Fetch the ring elements and invoke the + * clients callback. + * @ring: Ring for the respective context - Channel/Event/Command. + * @offset: Offset index into the respective ring's cache element. + */ +int mhi_dev_process_ring_element(struct mhi_dev_ring *ring, uint32_t offset); + +/** + * mhi_dev_add_element() - Copy the element to the respective transfer rings + * read pointer and increment the index. + * @ring: Ring for the respective context - Channel/Event/Command. + * @element: Transfer ring element to be copied to the host memory. + */ +int mhi_dev_add_element(struct mhi_dev_ring *ring, + union mhi_dev_ring_element_type *element, + struct event_req *ereq, int evt_offset); +/** + * mhi_transfer_device_to_host() - memcpy equivalent API to transfer data + * from device to the host. + * @dst_pa: Physical destination address. + * @src: Source virtual address. + * @len: Numer of bytes to be transferred. + * @mhi: MHI dev structure. + * @req: mhi_req structure + */ +int mhi_transfer_device_to_host(uint64_t dst_pa, void *src, uint32_t len, + struct mhi_dev *mhi, struct mhi_req *req); + +/** + * mhi_transfer_host_to_dev() - memcpy equivalent API to transfer data + * from host to the device. + * @dst: Physical destination virtual address. + * @src_pa: Source physical address. + * @len: Numer of bytes to be transferred. + * @mhi: MHI dev structure. + * @req: mhi_req structure + */ +int mhi_transfer_host_to_device(void *device, uint64_t src_pa, uint32_t len, + struct mhi_dev *mhi, struct mhi_req *mreq); + +/** + * mhi_dev_write_to_host() - Transfer data from device to host. + * Based on support available, either IPA DMA or memcpy is used. + * @host: Host and device address details. + * @buf: Data buffer that needs to be written to the host. + * @size: Data buffer size. + */ +void mhi_dev_write_to_host(struct mhi_dev *mhi, struct mhi_addr *mhi_transfer, + struct event_req *ereq, enum mhi_dev_transfer_type type); +/** + * mhi_dev_read_from_host() - memcpy equivalent API to transfer data + * from host to device. + * @host: Host and device address details. + * @buf: Data buffer that needs to be read from the host. + * @size: Data buffer size. + */ +void mhi_dev_read_from_host(struct mhi_dev *mhi, + struct mhi_addr *mhi_transfer); + +/** + * mhi_dev_read_from_host() - memcpy equivalent API to transfer data + * from host to device. + * @host: Host and device address details. + * @buf: Data buffer that needs to be read from the host. + * @size: Data buffer size. + */ + +void mhi_ring_set_cb(struct mhi_dev_ring *ring, + void (*ring_cb)(struct mhi_dev *dev, + union mhi_dev_ring_element_type *el, void *ctx)); + +/** + * mhi_ring_set_state() - Sets internal state of the ring for tracking whether + * a ring is being processed, idle or uninitialized. + * @ring: Ring for the respective context - Channel/Event/Command. + * @state: state of type mhi_dev_ring_state. + */ +void mhi_ring_set_state(struct mhi_dev_ring *ring, + enum mhi_dev_ring_state state); + +/** + * mhi_ring_get_state() - Obtains the internal state of the ring. + * @ring: Ring for the respective context - Channel/Event/Command. + */ +enum mhi_dev_ring_state mhi_ring_get_state(struct mhi_dev_ring *ring); + +/* MMIO related functions */ + +/** + * mhi_dev_mmio_read() - Generic MHI MMIO register read API. + * @dev: MHI device structure. + * @offset: MHI address offset from base. + * @reg_val: Pointer the register value is stored to. + */ +int mhi_dev_mmio_read(struct mhi_dev *dev, uint32_t offset, + uint32_t *reg_value); + +/** + * mhi_dev_mmio_read() - Generic MHI MMIO register write API. + * @dev: MHI device structure. + * @offset: MHI address offset from base. + * @val: Value to be written to the register offset. + */ +int mhi_dev_mmio_write(struct mhi_dev *dev, uint32_t offset, + uint32_t val); + +/** + * mhi_dev_mmio_masked_write() - Generic MHI MMIO register write masked API. + * @dev: MHI device structure. + * @offset: MHI address offset from base. + * @mask: Register field mask. + * @shift: Register field mask shift value. + * @val: Value to be written to the register offset. + */ +int mhi_dev_mmio_masked_write(struct mhi_dev *dev, uint32_t offset, + uint32_t mask, uint32_t shift, + uint32_t val); +/** + * mhi_dev_mmio_masked_read() - Generic MHI MMIO register read masked API. + * @dev: MHI device structure. + * @offset: MHI address offset from base. + * @mask: Register field mask. + * @shift: Register field mask shift value. + * @reg_val: Pointer the register value is stored to. + */ +int mhi_dev_mmio_masked_read(struct mhi_dev *dev, uint32_t offset, + uint32_t mask, uint32_t shift, + uint32_t *reg_val); +/** + * mhi_dev_mmio_enable_ctrl_interrupt() - Enable Control interrupt. + * @dev: MHI device structure. + */ + +int mhi_dev_mmio_enable_ctrl_interrupt(struct mhi_dev *dev); + +/** + * mhi_dev_mmio_disable_ctrl_interrupt() - Disable Control interrupt. + * @dev: MHI device structure. + */ +int mhi_dev_mmio_disable_ctrl_interrupt(struct mhi_dev *dev); + +/** + * mhi_dev_mmio_read_ctrl_status_interrupt() - Read Control interrupt status. + * @dev: MHI device structure. + */ +int mhi_dev_mmio_read_ctrl_status_interrupt(struct mhi_dev *dev); + +/** + * mhi_dev_mmio_enable_cmdb_interrupt() - Enable Command doorbell interrupt. + * @dev: MHI device structure. + */ +int mhi_dev_mmio_enable_cmdb_interrupt(struct mhi_dev *dev); + +/** + * mhi_dev_mmio_disable_cmdb_interrupt() - Disable Command doorbell interrupt. + * @dev: MHI device structure. + */ +int mhi_dev_mmio_disable_cmdb_interrupt(struct mhi_dev *dev); + +/** + * mhi_dev_mmio_read_cmdb_interrupt() - Read Command doorbell status. + * @dev: MHI device structure. + */ +int mhi_dev_mmio_read_cmdb_status_interrupt(struct mhi_dev *dev); + +/** + * mhi_dev_mmio_enable_chdb_a7() - Enable Channel doorbell for a given + * channel id. + * @dev: MHI device structure. + * @chdb_id: Channel id number. + */ +int mhi_dev_mmio_enable_chdb_a7(struct mhi_dev *dev, uint32_t chdb_id); +/** + * mhi_dev_mmio_disable_chdb_a7() - Disable Channel doorbell for a given + * channel id. + * @dev: MHI device structure. + * @chdb_id: Channel id number. + */ +int mhi_dev_mmio_disable_chdb_a7(struct mhi_dev *dev, uint32_t chdb_id); + +/** + * mhi_dev_mmio_enable_erdb_a7() - Enable Event ring doorbell for a given + * event ring id. + * @dev: MHI device structure. + * @erdb_id: Event ring id number. + */ +int mhi_dev_mmio_enable_erdb_a7(struct mhi_dev *dev, uint32_t erdb_id); + +/** + * mhi_dev_mmio_disable_erdb_a7() - Disable Event ring doorbell for a given + * event ring id. + * @dev: MHI device structure. + * @erdb_id: Event ring id number. + */ +int mhi_dev_mmio_disable_erdb_a7(struct mhi_dev *dev, uint32_t erdb_id); + +/** + * mhi_dev_mmio_enable_chdb_interrupts() - Enable all Channel doorbell + * interrupts. + * @dev: MHI device structure. + */ +int mhi_dev_mmio_enable_chdb_interrupts(struct mhi_dev *dev); + +/** + * mhi_dev_mmio_mask_chdb_interrupts() - Mask all Channel doorbell + * interrupts. + * @dev: MHI device structure. + */ +int mhi_dev_mmio_mask_chdb_interrupts(struct mhi_dev *dev); + +/** + * mhi_dev_mmio_read_chdb_interrupts() - Read all Channel doorbell + * interrupts. + * @dev: MHI device structure. + */ +int mhi_dev_mmio_read_chdb_status_interrupts(struct mhi_dev *dev); + +/** + * mhi_dev_mmio_enable_erdb_interrupts() - Enable all Event doorbell + * interrupts. + * @dev: MHI device structure. + */ +int mhi_dev_mmio_enable_erdb_interrupts(struct mhi_dev *dev); + +/** + *mhi_dev_mmio_mask_erdb_interrupts() - Mask all Event doorbell + * interrupts. + * @dev: MHI device structure. + */ +int mhi_dev_mmio_mask_erdb_interrupts(struct mhi_dev *dev); + +/** + * mhi_dev_mmio_read_erdb_interrupts() - Read all Event doorbell + * interrupts. + * @dev: MHI device structure. + */ +int mhi_dev_mmio_read_erdb_status_interrupts(struct mhi_dev *dev); + +/** + * mhi_dev_mmio_clear_interrupts() - Clear all doorbell interrupts. + * @dev: MHI device structure. + */ +int mhi_dev_mmio_clear_interrupts(struct mhi_dev *dev); + +/** + * mhi_dev_mmio_get_chc_base() - Fetch the Channel ring context base address. + @dev: MHI device structure. + */ +int mhi_dev_mmio_get_chc_base(struct mhi_dev *dev); + +/** + * mhi_dev_mmio_get_erc_base() - Fetch the Event ring context base address. + * @dev: MHI device structure. + */ +int mhi_dev_mmio_get_erc_base(struct mhi_dev *dev); + +/** + * mhi_dev_get_crc_base() - Fetch the Command ring context base address. + * @dev: MHI device structure. + */ +int mhi_dev_mmio_get_crc_base(struct mhi_dev *dev); + +/** + * mhi_dev_mmio_get_ch_db() - Fetch the Write offset of the Channel ring ID. + * @dev: MHI device structure. + * @wr_offset: Pointer of the write offset to be written to. + */ +int mhi_dev_mmio_get_ch_db(struct mhi_dev_ring *ring, uint64_t *wr_offset); + +/** + * mhi_dev_get_erc_base() - Fetch the Write offset of the Event ring ID. + * @dev: MHI device structure. + * @wr_offset: Pointer of the write offset to be written to. + */ +int mhi_dev_mmio_get_erc_db(struct mhi_dev_ring *ring, uint64_t *wr_offset); + +/** + * mhi_dev_get_cmd_base() - Fetch the Write offset of the Command ring ID. + * @dev: MHI device structure. + * @wr_offset: Pointer of the write offset to be written to. + */ +int mhi_dev_mmio_get_cmd_db(struct mhi_dev_ring *ring, uint64_t *wr_offset); + +/** + * mhi_dev_mmio_set_env() - Write the Execution Enviornment. + * @dev: MHI device structure. + * @value: Value of the EXEC EVN. + */ +int mhi_dev_mmio_set_env(struct mhi_dev *dev, uint32_t value); + +/** + * mhi_dev_mmio_reset() - Reset the MMIO done as part of initialization. + * @dev: MHI device structure. + */ +int mhi_dev_mmio_reset(struct mhi_dev *dev); + +/** + * mhi_dev_get_mhi_addr() - Fetches the Data and Control region from the Host. + * @dev: MHI device structure. + */ +int mhi_dev_get_mhi_addr(struct mhi_dev *dev); + +/** + * mhi_dev_get_mhi_state() - Fetches the MHI state such as M0/M1/M2/M3. + * @dev: MHI device structure. + * @state: Pointer of type mhi_dev_state + * @mhi_reset: MHI device reset from host. + */ +int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state, + bool *mhi_reset); + +/** + * mhi_dev_mmio_init() - Initializes the MMIO and reads the Number of event + * rings, support number of channels, and offsets to the Channel + * and Event doorbell from the host. + * @dev: MHI device structure. + */ +int mhi_dev_mmio_init(struct mhi_dev *dev); + +/** + * mhi_dev_update_ner() - Update the number of event rings (NER) programmed by + * the host. + * @dev: MHI device structure. + */ +int mhi_dev_update_ner(struct mhi_dev *dev); + +/** + * mhi_dev_restore_mmio() - Restores the MMIO when MHI device comes out of M3. + * @dev: MHI device structure. + */ +int mhi_dev_restore_mmio(struct mhi_dev *dev); + +/** + * mhi_dev_backup_mmio() - Backup MMIO before a MHI transition to M3. + * @dev: MHI device structure. + */ +int mhi_dev_backup_mmio(struct mhi_dev *dev); + +/** + * mhi_dev_dump_mmio() - Memory dump of the MMIO region for debug. + * @dev: MHI device structure. + */ +int mhi_dev_dump_mmio(struct mhi_dev *dev); + +/** + * mhi_dev_config_outbound_iatu() - Configure Outbound Address translation + * unit between device and host to map the Data and Control + * information. + * @dev: MHI device structure. + */ +int mhi_dev_config_outbound_iatu(struct mhi_dev *mhi); + +/** + * mhi_dev_send_state_change_event() - Send state change event to the host + * such as M0/M1/M2/M3. + * @dev: MHI device structure. + * @state: MHI state of type mhi_dev_state + */ +int mhi_dev_send_state_change_event(struct mhi_dev *mhi, + enum mhi_dev_state state); +/** + * mhi_dev_send_ee_event() - Send Execution enviornment state change + * event to the host. + * @dev: MHI device structure. + * @state: MHI state of type mhi_dev_execenv + */ +int mhi_dev_send_ee_event(struct mhi_dev *mhi, + enum mhi_dev_execenv exec_env); +/** + * mhi_dev_syserr() - System error when unexpected events are received. + * @dev: MHI device structure. + */ +int mhi_dev_syserr(struct mhi_dev *mhi); + +/** + * mhi_dev_suspend() - MHI device suspend to stop channel processing at the + * Transfer ring boundary, update the channel state to suspended. + * @dev: MHI device structure. + */ +int mhi_dev_suspend(struct mhi_dev *mhi); + +/** + * mhi_dev_resume() - MHI device resume to update the channel state to running. + * @dev: MHI device structure. + */ +int mhi_dev_resume(struct mhi_dev *mhi); + +/** + * mhi_dev_trigger_hw_acc_wakeup() - Notify State machine there is HW + * accelerated data to be send and prevent MHI suspend. + * @dev: MHI device structure. + */ +int mhi_dev_trigger_hw_acc_wakeup(struct mhi_dev *mhi); + +/** + * mhi_pcie_config_db_routing() - Configure Doorbell for Event and Channel + * context with IPA when performing a MHI resume. + * @dev: MHI device structure. + */ +int mhi_pcie_config_db_routing(struct mhi_dev *mhi); + +/** + * mhi_uci_init() - Initializes the User control interface (UCI) which + * exposes device nodes for the supported MHI software + * channels. + */ +int mhi_uci_init(void); + +/** + * mhi_dev_net_interface_init() - Initializes the mhi device network interface + * which exposes the virtual network interface (mhi_dev_net0). + * data packets will transfer between MHI host interface (mhi_swip) + * and mhi_dev_net interface using software path + */ +int mhi_dev_net_interface_init(void); + +void mhi_dev_notify_a7_event(struct mhi_dev *mhi); + +void uci_ctrl_update(struct mhi_dev_client_cb_reason *reason); + +#endif /* _MHI_H */ diff --git a/drivers/platform/msm/mhi_dev/mhi_dev_net.c b/drivers/platform/msm/mhi_dev/mhi_dev_net.c index d5cc14809184..d8dc85f72ba0 100644 --- a/drivers/platform/msm/mhi_dev/mhi_dev_net.c +++ b/drivers/platform/msm/mhi_dev/mhi_dev_net.c @@ -28,7 +28,7 @@ #include #include -#include +#include "mhi.h" #define MHI_NET_DRIVER_NAME "mhi_dev_net_drv" #define MHI_NET_DEV_NAME "mhi_dev_net%d" diff --git a/drivers/platform/msm/mhi_dev/mhi_mmio.c b/drivers/platform/msm/mhi_dev/mhi_mmio.c index 21cca6e1c133..559fa8411a01 100644 --- a/drivers/platform/msm/mhi_dev/mhi_mmio.c +++ b/drivers/platform/msm/mhi_dev/mhi_mmio.c @@ -25,7 +25,7 @@ #include #include -#include +#include "mhi.h" #include "mhi_hwio.h" int mhi_dev_mmio_read(struct mhi_dev *dev, uint32_t offset, diff --git a/drivers/platform/msm/mhi_dev/mhi_ring.c b/drivers/platform/msm/mhi_dev/mhi_ring.c index 27993dfa3c4c..92b061648cd8 100644 --- a/drivers/platform/msm/mhi_dev/mhi_ring.c +++ b/drivers/platform/msm/mhi_dev/mhi_ring.c @@ -24,7 +24,7 @@ #include #include -#include +#include "mhi.h" static uint32_t mhi_dev_ring_addr2ofst(struct mhi_dev_ring *ring, uint64_t p) { diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.h b/drivers/platform/msm/mhi_dev/mhi_sm.h index 07e74448eef9..4b9307d6c71d 100644 --- a/drivers/platform/msm/mhi_dev/mhi_sm.h +++ b/drivers/platform/msm/mhi_dev/mhi_sm.h @@ -13,7 +13,7 @@ #ifndef MHI_SM_H #define MHI_SM_H -#include +#include "mhi.h" #include #include diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c index 4e219a6d9c88..52d324ef93c5 100644 --- a/drivers/platform/msm/mhi_dev/mhi_uci.c +++ b/drivers/platform/msm/mhi_dev/mhi_uci.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include "mhi.h" #define MHI_SOFTWARE_CLIENT_START 0 #define MHI_SOFTWARE_CLIENT_LIMIT (MHI_MAX_SOFTWARE_CHANNELS/2) diff --git a/include/linux/msm_mhi_dev.h b/include/linux/msm_mhi_dev.h index 26baa6472636..b96591b27f6a 100644 --- a/include/linux/msm_mhi_dev.h +++ b/include/linux/msm_mhi_dev.h @@ -10,416 +10,15 @@ * GNU General Public License for more details. */ -#ifndef __MHI_H -#define __MHI_H +#ifndef __MSM_MHI_DEV_H +#define __MSM_MHI_DEV_H -#include #include -#include #include -/** - * MHI control data structures alloted by the host, including - * channel context array, event context array, command context and rings. - */ - -/* Channel context state */ -enum mhi_dev_ch_ctx_state { - MHI_DEV_CH_STATE_DISABLED, - MHI_DEV_CH_STATE_ENABLED, - MHI_DEV_CH_STATE_RUNNING, - MHI_DEV_CH_STATE_SUSPENDED, - MHI_DEV_CH_STATE_STOP, - MHI_DEV_CH_STATE_ERROR, - MHI_DEV_CH_STATE_RESERVED, - MHI_DEV_CH_STATE_32BIT = 0x7FFFFFFF -}; - -/* Channel type */ -enum mhi_dev_ch_ctx_type { - MHI_DEV_CH_TYPE_NONE, - MHI_DEV_CH_TYPE_OUTBOUND_CHANNEL, - MHI_DEV_CH_TYPE_INBOUND_CHANNEL, - MHI_DEV_CH_RESERVED -}; - -/* Channel context type */ -struct mhi_dev_ch_ctx { - enum mhi_dev_ch_ctx_state ch_state; - enum mhi_dev_ch_ctx_type ch_type; - uint32_t err_indx; - uint64_t rbase; - uint64_t rlen; - uint64_t rp; - uint64_t wp; -} __packed; - -enum mhi_dev_ring_element_type_id { - MHI_DEV_RING_EL_INVALID = 0, - MHI_DEV_RING_EL_NOOP = 1, - MHI_DEV_RING_EL_TRANSFER = 2, - MHI_DEV_RING_EL_RESET = 16, - MHI_DEV_RING_EL_STOP = 17, - MHI_DEV_RING_EL_START = 18, - MHI_DEV_RING_EL_MHI_STATE_CHG = 32, - MHI_DEV_RING_EL_CMD_COMPLETION_EVT = 33, - MHI_DEV_RING_EL_TRANSFER_COMPLETION_EVENT = 34, - MHI_DEV_RING_EL_EE_STATE_CHANGE_NOTIFY = 64, - MHI_DEV_RING_EL_UNDEF -}; - -enum mhi_dev_ring_state { - RING_STATE_UINT = 0, - RING_STATE_IDLE, - RING_STATE_PENDING, -}; - -enum mhi_dev_ring_type { - RING_TYPE_CMD = 0, - RING_TYPE_ER, - RING_TYPE_CH, - RING_TYPE_INVAL -}; - -/* Event context interrupt moderation */ -enum mhi_dev_evt_ctx_int_mod_timer { - MHI_DEV_EVT_INT_MODERATION_DISABLED -}; - -/* Event ring type */ -enum mhi_dev_evt_ctx_event_ring_type { - MHI_DEV_EVT_TYPE_DEFAULT, - MHI_DEV_EVT_TYPE_VALID, - MHI_DEV_EVT_RESERVED -}; - -/* Event ring context type */ -struct mhi_dev_ev_ctx { - uint32_t res1:16; - enum mhi_dev_evt_ctx_int_mod_timer intmodt:16; - enum mhi_dev_evt_ctx_event_ring_type ertype; - uint32_t msivec; - uint64_t rbase; - uint64_t rlen; - uint64_t rp; - uint64_t wp; -} __packed; - -/* Command context */ -struct mhi_dev_cmd_ctx { - uint32_t res1; - uint32_t res2; - uint32_t res3; - uint64_t rbase; - uint64_t rlen; - uint64_t rp; - uint64_t wp; -} __packed; - -/* generic context */ -struct mhi_dev_gen_ctx { - uint32_t res1; - uint32_t res2; - uint32_t res3; - uint64_t rbase; - uint64_t rlen; - uint64_t rp; - uint64_t wp; -} __packed; - -/* Transfer ring element */ -struct mhi_dev_transfer_ring_element { - uint64_t data_buf_ptr; - uint32_t len:16; - uint32_t res1:16; - uint32_t chain:1; - uint32_t res2:7; - uint32_t ieob:1; - uint32_t ieot:1; - uint32_t bei:1; - uint32_t res3:5; - enum mhi_dev_ring_element_type_id type:8; - uint32_t res4:8; -} __packed; - -/* Command ring element */ -/* Command ring No op command */ -struct mhi_dev_cmd_ring_op { - uint64_t res1; - uint32_t res2; - uint32_t res3:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t chid:8; -} __packed; - -/* Command ring reset channel command */ -struct mhi_dev_cmd_ring_reset_channel_cmd { - uint64_t res1; - uint32_t res2; - uint32_t res3:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t chid:8; -} __packed; - -/* Command ring stop channel command */ -struct mhi_dev_cmd_ring_stop_channel_cmd { - uint64_t res1; - uint32_t res2; - uint32_t res3:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t chid:8; -} __packed; - -/* Command ring start channel command */ -struct mhi_dev_cmd_ring_start_channel_cmd { - uint64_t res1; - uint32_t seqnum; - uint32_t reliable:1; - uint32_t res2:15; - enum mhi_dev_ring_element_type_id type:8; - uint32_t chid:8; -} __packed; - -enum mhi_dev_cmd_completion_code { - MHI_CMD_COMPL_CODE_INVALID = 0, - MHI_CMD_COMPL_CODE_SUCCESS = 1, - MHI_CMD_COMPL_CODE_EOT = 2, - MHI_CMD_COMPL_CODE_OVERFLOW = 3, - MHI_CMD_COMPL_CODE_EOB = 4, - MHI_CMD_COMPL_CODE_UNDEFINED = 16, - MHI_CMD_COMPL_CODE_RING_EL = 17, - MHI_CMD_COMPL_CODE_RES -}; - -/* Event ring elements */ -/* Transfer completion event */ -struct mhi_dev_event_ring_transfer_completion { - uint64_t ptr; - uint32_t len:16; - uint32_t res1:8; - enum mhi_dev_cmd_completion_code code:8; - uint32_t res2:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t chid:8; -} __packed; - -/* Command completion event */ -struct mhi_dev_event_ring_cmd_completion { - uint64_t ptr; - uint32_t res1:24; - enum mhi_dev_cmd_completion_code code:8; - uint32_t res2:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t res3:8; -} __packed; - -enum mhi_dev_state { - MHI_DEV_RESET_STATE = 0, - MHI_DEV_READY_STATE, - MHI_DEV_M0_STATE, - MHI_DEV_M1_STATE, - MHI_DEV_M2_STATE, - MHI_DEV_M3_STATE, - MHI_DEV_MAX_STATE, - MHI_DEV_SYSERR_STATE = 0xff -}; - -/* MHI state change event */ -struct mhi_dev_event_ring_state_change { - uint64_t ptr; - uint32_t res1:24; - enum mhi_dev_state mhistate:8; - uint32_t res2:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t res3:8; -} __packed; - -enum mhi_dev_execenv { - MHI_DEV_SBL_EE = 1, - MHI_DEV_AMSS_EE = 2, - MHI_DEV_UNRESERVED -}; - -/* EE state change event */ -struct mhi_dev_event_ring_ee_state_change { - uint64_t ptr; - uint32_t res1:24; - enum mhi_dev_execenv execenv:8; - uint32_t res2:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t res3:8; -} __packed; - -/* Generic cmd to parse common details like type and channel id */ -struct mhi_dev_ring_generic { - uint64_t ptr; - uint32_t res1:24; - enum mhi_dev_state mhistate:8; - uint32_t res2:16; - enum mhi_dev_ring_element_type_id type:8; - uint32_t chid:8; -} __packed; - -struct mhi_config { - uint32_t mhi_reg_len; - uint32_t version; - uint32_t event_rings; - uint32_t channels; - uint32_t chdb_offset; - uint32_t erdb_offset; -}; - -#define NUM_CHANNELS 128 -#define HW_CHANNEL_BASE 100 -#define HW_CHANNEL_END 107 -#define MHI_ENV_VALUE 2 -#define MHI_MASK_ROWS_CH_EV_DB 4 -#define TRB_MAX_DATA_SIZE 8192 -#define MHI_CTRL_STATE 100 #define IPA_DMA_SYNC 1 #define IPA_DMA_ASYNC 0 -/*maximum trasnfer completion events buffer*/ -#define MAX_TR_EVENTS 50 -/*maximum event requests */ -#define MHI_MAX_EVT_REQ 50 - -/* Possible ring element types */ -union mhi_dev_ring_element_type { - struct mhi_dev_cmd_ring_op cmd_no_op; - struct mhi_dev_cmd_ring_reset_channel_cmd cmd_reset; - struct mhi_dev_cmd_ring_stop_channel_cmd cmd_stop; - struct mhi_dev_cmd_ring_start_channel_cmd cmd_start; - struct mhi_dev_transfer_ring_element tre; - struct mhi_dev_event_ring_transfer_completion evt_tr_comp; - struct mhi_dev_event_ring_cmd_completion evt_cmd_comp; - struct mhi_dev_event_ring_state_change evt_state_change; - struct mhi_dev_event_ring_ee_state_change evt_ee_state; - struct mhi_dev_ring_generic generic; -}; - -/* Transfer ring element type */ -union mhi_dev_ring_ctx { - struct mhi_dev_cmd_ctx cmd; - struct mhi_dev_ev_ctx ev; - struct mhi_dev_ch_ctx ch; - struct mhi_dev_gen_ctx generic; -}; - -/* MHI host Control and data address region */ -struct mhi_host_addr { - uint32_t ctrl_base_lsb; - uint32_t ctrl_base_msb; - uint32_t ctrl_limit_lsb; - uint32_t ctrl_limit_msb; - uint32_t data_base_lsb; - uint32_t data_base_msb; - uint32_t data_limit_lsb; - uint32_t data_limit_msb; -}; - -/* MHI physical and virtual address region */ -struct mhi_meminfo { - struct device *dev; - uintptr_t pa_aligned; - uintptr_t pa_unaligned; - uintptr_t va_aligned; - uintptr_t va_unaligned; - uintptr_t size; -}; - -struct mhi_addr { - uint64_t host_pa; - uintptr_t device_pa; - uintptr_t device_va; - size_t size; - dma_addr_t phy_addr; - void *virt_addr; - bool use_ipa_dma; -}; - -struct mhi_interrupt_state { - uint32_t mask; - uint32_t status; -}; - -enum mhi_dev_channel_state { - MHI_DEV_CH_UNINT, - MHI_DEV_CH_STARTED, - MHI_DEV_CH_PENDING_START, - MHI_DEV_CH_PENDING_STOP, - MHI_DEV_CH_STOPPED, - MHI_DEV_CH_CLOSED, -}; - -enum mhi_dev_ch_operation { - MHI_DEV_OPEN_CH, - MHI_DEV_CLOSE_CH, - MHI_DEV_READ_CH, - MHI_DEV_READ_WR, - MHI_DEV_POLL, -}; - -enum mhi_ctrl_info { - MHI_STATE_CONFIGURED = 0, - MHI_STATE_CONNECTED = 1, - MHI_STATE_DISCONNECTED = 2, - MHI_STATE_INVAL, -}; - -enum mhi_dev_tr_compl_evt_type { - SEND_EVENT_BUFFER, - SEND_EVENT_RD_OFFSET, -}; - -enum mhi_dev_transfer_type { - MHI_DEV_DMA_SYNC, - MHI_DEV_DMA_ASYNC, -}; - -struct mhi_dev_channel; - -struct mhi_dev_ring { - struct list_head list; - struct mhi_dev *mhi_dev; - - uint32_t id; - uint32_t rd_offset; - uint32_t wr_offset; - uint32_t ring_size; - - enum mhi_dev_ring_type type; - enum mhi_dev_ring_state state; - - /* device virtual address location of the cached host ring ctx data */ - union mhi_dev_ring_element_type *ring_cache; - /* Physical address of the cached ring copy on the device side */ - dma_addr_t ring_cache_dma_handle; - /* Physical address of the host where we will write/read to/from */ - struct mhi_addr ring_shadow; - /* Ring type - cmd, event, transfer ring and its rp/wp... */ - union mhi_dev_ring_ctx *ring_ctx; - /* ring_ctx_shadow -> tracking ring_ctx in the host */ - union mhi_dev_ring_ctx *ring_ctx_shadow; - void (*ring_cb)(struct mhi_dev *dev, - union mhi_dev_ring_element_type *el, - void *ctx); -}; - -static inline void mhi_dev_ring_inc_index(struct mhi_dev_ring *ring, - uint32_t rd_offset) -{ - ring->rd_offset++; - if (ring->rd_offset == ring->ring_size) - ring->rd_offset = 0; -} - -/* trace information planned to use for read/write */ -#define TRACE_DATA_MAX 128 -#define MHI_DEV_DATA_MAX 512 - -#define MHI_DEV_MMIO_RANGE 0xc80 - enum cb_reason { MHI_DEV_TRE_AVAILABLE = 0, MHI_DEV_CTRL_UPDATE, @@ -452,171 +51,11 @@ struct mhi_dev_client { uint32_t nr_iov; }; -struct ring_cache_req { - struct completion *done; - void *context; -}; - -struct event_req { - union mhi_dev_ring_element_type *tr_events; - u32 num_events; - dma_addr_t dma; - u32 dma_len; - dma_addr_t event_rd_dma; - void *context; - enum mhi_dev_tr_compl_evt_type event_type; - u32 event_ring; - void (*client_cb)(void *req); - struct list_head list; -}; - -struct mhi_dev_channel { - struct list_head list; - struct list_head clients; - /* synchronization for changing channel state, - * adding/removing clients, mhi_dev callbacks, etc - */ - struct mhi_dev_ring *ring; - - enum mhi_dev_channel_state state; - uint32_t ch_id; - enum mhi_dev_ch_ctx_type ch_type; - struct mutex ch_lock; - /* client which the current inbound/outbound message is for */ - struct mhi_dev_client *active_client; - /* - * Pointer to event request structs used to temporarily store - * completion events and meta data before sending them to host - */ - struct event_req *ereqs; - /* Pointer to completion event buffers */ - union mhi_dev_ring_element_type *tr_events; - struct list_head event_req_buffers; - struct event_req *curr_ereq; - - /* current TRE being processed */ - uint64_t tre_loc; - /* current TRE size */ - uint32_t tre_size; - /* tre bytes left to read/write */ - uint32_t tre_bytes_left; - /* td size being read/written from/to so far */ - uint32_t td_size; - bool wr_request_active; - bool skip_td; -}; - -/* Structure device for mhi dev */ -struct mhi_dev { - struct platform_device *pdev; - struct device *dev; - /* MHI MMIO related members */ - phys_addr_t mmio_base_pa_addr; - void *mmio_base_addr; - phys_addr_t ipa_uc_mbox_crdb; - phys_addr_t ipa_uc_mbox_erdb; - - uint32_t *mmio_backup; - struct mhi_config cfg; - bool mmio_initialized; - - spinlock_t lock; - /* Host control base information */ - struct mhi_host_addr host_addr; - struct mhi_addr ctrl_base; - struct mhi_addr data_base; - struct mhi_addr ch_ctx_shadow; - struct mhi_dev_ch_ctx *ch_ctx_cache; - dma_addr_t ch_ctx_cache_dma_handle; - struct mhi_addr ev_ctx_shadow; - struct mhi_dev_ch_ctx *ev_ctx_cache; - dma_addr_t ev_ctx_cache_dma_handle; - - struct mhi_addr cmd_ctx_shadow; - struct mhi_dev_ch_ctx *cmd_ctx_cache; - dma_addr_t cmd_ctx_cache_dma_handle; - struct mhi_dev_ring *ring; - int mhi_irq; - struct mhi_dev_channel *ch; - - int ctrl_int; - int cmd_int; - /* CHDB and EVDB device interrupt state */ - struct mhi_interrupt_state chdb[4]; - struct mhi_interrupt_state evdb[4]; - - /* Scheduler work */ - struct work_struct chdb_ctrl_work; - - struct mutex mhi_lock; - struct mutex mhi_event_lock; - - /* process a ring element */ - struct workqueue_struct *pending_ring_wq; - struct work_struct pending_work; - - struct list_head event_ring_list; - struct list_head process_ring_list; - - uint32_t cmd_ring_idx; - uint32_t ev_ring_start; - uint32_t ch_ring_start; - - /* IPA Handles */ - u32 ipa_clnt_hndl[4]; - struct workqueue_struct *ring_init_wq; - struct work_struct ring_init_cb_work; - struct work_struct re_init; - - /* EP PCIe registration */ - struct workqueue_struct *pcie_event_wq; - struct ep_pcie_register_event event_reg; - u32 ifc_id; - struct ep_pcie_hw *phandle; - struct work_struct pcie_event; - struct ep_pcie_msi_config msi_cfg; - - atomic_t write_active; - atomic_t is_suspended; - atomic_t mhi_dev_wake; - atomic_t re_init_done; - struct mutex mhi_write_test; - u32 device_local_pa_base; - u32 mhi_ep_msi_num; - u32 mhi_version; - void *dma_cache; - void *read_handle; - void *write_handle; - /* Physical scratch buffer for writing control data to the host */ - dma_addr_t cache_dma_handle; - /* - * Physical scratch buffer address used when picking host data - * from the host used in mhi_read() - */ - dma_addr_t read_dma_handle; - /* - * Physical scratch buffer address used when writing to the host - * region from device used in mhi_write() - */ - dma_addr_t write_dma_handle; - - /* Use IPA DMA for Software channel data transfer */ - bool use_ipa; - - /* iATU is required to map control and data region */ - bool config_iatu; - - /* MHI state info */ - enum mhi_ctrl_info ctrl_info; - - /*Register for interrupt */ - bool mhi_int; - bool mhi_int_en; - - /* Registered client callback list */ - struct list_head client_cb_list; - - struct kobj_uevent_env kobj_env; +enum mhi_ctrl_info { + MHI_STATE_CONFIGURED = 0, + MHI_STATE_CONNECTED = 1, + MHI_STATE_DISCONNECTED = 2, + MHI_STATE_INVAL, }; struct mhi_req { @@ -636,30 +75,6 @@ struct mhi_req { void (*client_cb)(void *req); }; -enum mhi_msg_level { - MHI_MSG_VERBOSE = 0x0, - MHI_MSG_INFO = 0x1, - MHI_MSG_DBG = 0x2, - MHI_MSG_WARNING = 0x3, - MHI_MSG_ERROR = 0x4, - MHI_MSG_CRITICAL = 0x5, - MHI_MSG_reserved = 0x80000000 -}; - -extern enum mhi_msg_level mhi_msg_lvl; -extern enum mhi_msg_level mhi_ipc_msg_lvl; -extern void *mhi_ipc_log; - -#define mhi_log(_msg_lvl, _msg, ...) do { \ - if (_msg_lvl >= mhi_msg_lvl) { \ - pr_err("[%s] "_msg, __func__, ##__VA_ARGS__); \ - } \ - if (mhi_ipc_log && (_msg_lvl >= mhi_ipc_msg_lvl)) { \ - ipc_log_string(mhi_ipc_log, \ - "[%s] " _msg, __func__, ##__VA_ARGS__); \ - } \ -} while (0) - /* SW channel client list */ enum mhi_client_channel { MHI_CLIENT_LOOPBACK_OUT = 0, @@ -723,19 +138,6 @@ enum mhi_client_channel { MHI_CLIENT_INVALID = 0xFFFFFFFF }; -/* Use ID 0 for legacy /dev/mhi_ctrl. Channel 0 is used for internal only */ -#define MHI_DEV_UEVENT_CTRL 0 - -struct mhi_dev_uevent_info { - enum mhi_client_channel channel; - enum mhi_ctrl_info ctrl_info; -}; - -struct mhi_dev_iov { - void *addr; - uint32_t buf_size; -}; - struct mhi_dev_client_cb_data { void *user_data; enum mhi_client_channel channel; @@ -750,6 +152,7 @@ struct mhi_dev_ready_cb_info { struct mhi_dev_client_cb_data cb_data; }; +#if defined(CONFIG_MSM_MHI_DEV) /** * mhi_dev_open_channel() - Channel open for a given client done prior * to read/write. @@ -760,6 +163,7 @@ struct mhi_dev_ready_cb_info { int mhi_dev_open_channel(uint32_t chan_id, struct mhi_dev_client **handle_client, void (*event_trigger)(struct mhi_dev_client_cb_reason *cb)); + /** * mhi_dev_close_channel() - Channel close for a given client. */ @@ -789,485 +193,6 @@ int mhi_dev_write_channel(struct mhi_req *wreq); */ int mhi_dev_channel_isempty(struct mhi_dev_client *handle); -struct mhi_dev_trace { - unsigned int timestamp; - uint32_t data[TRACE_DATA_MAX]; -}; - -/* MHI Ring related functions */ - -/** - * mhi_ring_init() - Initializes the Ring id to the default un-initialized - * state. Once a start command is received, the respective ring - * is then prepared by fetching the context and updating the - * offset. - * @ring: Ring for the respective context - Channel/Event/Command. - * @type: Command/Event or Channel transfer ring. - * @id: Index to the ring id. For command its usually 1, Event rings - * may vary from 1 to 128. Channels vary from 1 to 256. - */ -void mhi_ring_init(struct mhi_dev_ring *ring, - enum mhi_dev_ring_type type, int id); - -/** - * mhi_ring_start() - Fetches the respective transfer ring's context from - * the host and updates the write offset. - * @ring: Ring for the respective context - Channel/Event/Command. - * @ctx: Transfer ring of type mhi_dev_ring_ctx. - * @dev: MHI device structure. - */ -int mhi_ring_start(struct mhi_dev_ring *ring, - union mhi_dev_ring_ctx *ctx, struct mhi_dev *mhi); - -/** - * mhi_dev_cache_ring() - Cache the data for the corresponding ring locally. - * @ring: Ring for the respective context - Channel/Event/Command. - * @wr_offset: Cache the TRE's upto the write offset value. - */ -int mhi_dev_cache_ring(struct mhi_dev_ring *ring, uint32_t wr_offset); - -/** - * mhi_dev_update_wr_offset() - Check for any updates in the write offset. - * @ring: Ring for the respective context - Channel/Event/Command. - */ -int mhi_dev_update_wr_offset(struct mhi_dev_ring *ring); - -/** - * mhi_dev_process_ring() - Update the Write pointer, fetch the ring elements - * and invoke the clients callback. - * @ring: Ring for the respective context - Channel/Event/Command. - */ -int mhi_dev_process_ring(struct mhi_dev_ring *ring); - -/** - * mhi_dev_process_ring_element() - Fetch the ring elements and invoke the - * clients callback. - * @ring: Ring for the respective context - Channel/Event/Command. - * @offset: Offset index into the respective ring's cache element. - */ -int mhi_dev_process_ring_element(struct mhi_dev_ring *ring, uint32_t offset); - -/** - * mhi_dev_add_element() - Copy the element to the respective transfer rings - * read pointer and increment the index. - * @ring: Ring for the respective context - Channel/Event/Command. - * @element: Transfer ring element to be copied to the host memory. - */ -int mhi_dev_add_element(struct mhi_dev_ring *ring, - union mhi_dev_ring_element_type *element, - struct event_req *ereq, int evt_offset); -/** - * mhi_transfer_device_to_host() - memcpy equivalent API to transfer data - * from device to the host. - * @dst_pa: Physical destination address. - * @src: Source virtual address. - * @len: Numer of bytes to be transferred. - * @mhi: MHI dev structure. - * @req: mhi_req structure - */ -int mhi_transfer_device_to_host(uint64_t dst_pa, void *src, uint32_t len, - struct mhi_dev *mhi, struct mhi_req *req); - -/** - * mhi_transfer_host_to_dev() - memcpy equivalent API to transfer data - * from host to the device. - * @dst: Physical destination virtual address. - * @src_pa: Source physical address. - * @len: Numer of bytes to be transferred. - * @mhi: MHI dev structure. - * @req: mhi_req structure - */ -int mhi_transfer_host_to_device(void *device, uint64_t src_pa, uint32_t len, - struct mhi_dev *mhi, struct mhi_req *mreq); - -/** - * mhi_dev_write_to_host() - Transfer data from device to host. - * Based on support available, either IPA DMA or memcpy is used. - * @host: Host and device address details. - * @buf: Data buffer that needs to be written to the host. - * @size: Data buffer size. - */ -void mhi_dev_write_to_host(struct mhi_dev *mhi, struct mhi_addr *mhi_transfer, - struct event_req *ereq, enum mhi_dev_transfer_type type); -/** - * mhi_dev_read_from_host() - memcpy equivalent API to transfer data - * from host to device. - * @host: Host and device address details. - * @buf: Data buffer that needs to be read from the host. - * @size: Data buffer size. - */ -void mhi_dev_read_from_host(struct mhi_dev *mhi, - struct mhi_addr *mhi_transfer); - -/** - * mhi_dev_read_from_host() - memcpy equivalent API to transfer data - * from host to device. - * @host: Host and device address details. - * @buf: Data buffer that needs to be read from the host. - * @size: Data buffer size. - */ - -void mhi_ring_set_cb(struct mhi_dev_ring *ring, - void (*ring_cb)(struct mhi_dev *dev, - union mhi_dev_ring_element_type *el, void *ctx)); - -/** - * mhi_ring_set_state() - Sets internal state of the ring for tracking whether - * a ring is being processed, idle or uninitialized. - * @ring: Ring for the respective context - Channel/Event/Command. - * @state: state of type mhi_dev_ring_state. - */ -void mhi_ring_set_state(struct mhi_dev_ring *ring, - enum mhi_dev_ring_state state); - -/** - * mhi_ring_get_state() - Obtains the internal state of the ring. - * @ring: Ring for the respective context - Channel/Event/Command. - */ -enum mhi_dev_ring_state mhi_ring_get_state(struct mhi_dev_ring *ring); - -/* MMIO related functions */ - -/** - * mhi_dev_mmio_read() - Generic MHI MMIO register read API. - * @dev: MHI device structure. - * @offset: MHI address offset from base. - * @reg_val: Pointer the register value is stored to. - */ -int mhi_dev_mmio_read(struct mhi_dev *dev, uint32_t offset, - uint32_t *reg_value); - -/** - * mhi_dev_mmio_read() - Generic MHI MMIO register write API. - * @dev: MHI device structure. - * @offset: MHI address offset from base. - * @val: Value to be written to the register offset. - */ -int mhi_dev_mmio_write(struct mhi_dev *dev, uint32_t offset, - uint32_t val); - -/** - * mhi_dev_mmio_masked_write() - Generic MHI MMIO register write masked API. - * @dev: MHI device structure. - * @offset: MHI address offset from base. - * @mask: Register field mask. - * @shift: Register field mask shift value. - * @val: Value to be written to the register offset. - */ -int mhi_dev_mmio_masked_write(struct mhi_dev *dev, uint32_t offset, - uint32_t mask, uint32_t shift, - uint32_t val); -/** - * mhi_dev_mmio_masked_read() - Generic MHI MMIO register read masked API. - * @dev: MHI device structure. - * @offset: MHI address offset from base. - * @mask: Register field mask. - * @shift: Register field mask shift value. - * @reg_val: Pointer the register value is stored to. - */ -int mhi_dev_mmio_masked_read(struct mhi_dev *dev, uint32_t offset, - uint32_t mask, uint32_t shift, - uint32_t *reg_val); -/** - * mhi_dev_mmio_enable_ctrl_interrupt() - Enable Control interrupt. - * @dev: MHI device structure. - */ - -int mhi_dev_mmio_enable_ctrl_interrupt(struct mhi_dev *dev); - -/** - * mhi_dev_mmio_disable_ctrl_interrupt() - Disable Control interrupt. - * @dev: MHI device structure. - */ -int mhi_dev_mmio_disable_ctrl_interrupt(struct mhi_dev *dev); - -/** - * mhi_dev_mmio_read_ctrl_status_interrupt() - Read Control interrupt status. - * @dev: MHI device structure. - */ -int mhi_dev_mmio_read_ctrl_status_interrupt(struct mhi_dev *dev); - -/** - * mhi_dev_mmio_enable_cmdb_interrupt() - Enable Command doorbell interrupt. - * @dev: MHI device structure. - */ -int mhi_dev_mmio_enable_cmdb_interrupt(struct mhi_dev *dev); - -/** - * mhi_dev_mmio_disable_cmdb_interrupt() - Disable Command doorbell interrupt. - * @dev: MHI device structure. - */ -int mhi_dev_mmio_disable_cmdb_interrupt(struct mhi_dev *dev); - -/** - * mhi_dev_mmio_read_cmdb_interrupt() - Read Command doorbell status. - * @dev: MHI device structure. - */ -int mhi_dev_mmio_read_cmdb_status_interrupt(struct mhi_dev *dev); - -/** - * mhi_dev_mmio_enable_chdb_a7() - Enable Channel doorbell for a given - * channel id. - * @dev: MHI device structure. - * @chdb_id: Channel id number. - */ -int mhi_dev_mmio_enable_chdb_a7(struct mhi_dev *dev, uint32_t chdb_id); -/** - * mhi_dev_mmio_disable_chdb_a7() - Disable Channel doorbell for a given - * channel id. - * @dev: MHI device structure. - * @chdb_id: Channel id number. - */ -int mhi_dev_mmio_disable_chdb_a7(struct mhi_dev *dev, uint32_t chdb_id); - -/** - * mhi_dev_mmio_enable_erdb_a7() - Enable Event ring doorbell for a given - * event ring id. - * @dev: MHI device structure. - * @erdb_id: Event ring id number. - */ -int mhi_dev_mmio_enable_erdb_a7(struct mhi_dev *dev, uint32_t erdb_id); - -/** - * mhi_dev_mmio_disable_erdb_a7() - Disable Event ring doorbell for a given - * event ring id. - * @dev: MHI device structure. - * @erdb_id: Event ring id number. - */ -int mhi_dev_mmio_disable_erdb_a7(struct mhi_dev *dev, uint32_t erdb_id); - -/** - * mhi_dev_mmio_enable_chdb_interrupts() - Enable all Channel doorbell - * interrupts. - * @dev: MHI device structure. - */ -int mhi_dev_mmio_enable_chdb_interrupts(struct mhi_dev *dev); - -/** - * mhi_dev_mmio_mask_chdb_interrupts() - Mask all Channel doorbell - * interrupts. - * @dev: MHI device structure. - */ -int mhi_dev_mmio_mask_chdb_interrupts(struct mhi_dev *dev); - -/** - * mhi_dev_mmio_read_chdb_interrupts() - Read all Channel doorbell - * interrupts. - * @dev: MHI device structure. - */ -int mhi_dev_mmio_read_chdb_status_interrupts(struct mhi_dev *dev); - -/** - * mhi_dev_mmio_enable_erdb_interrupts() - Enable all Event doorbell - * interrupts. - * @dev: MHI device structure. - */ -int mhi_dev_mmio_enable_erdb_interrupts(struct mhi_dev *dev); - -/** - * mhi_dev_mmio_mask_erdb_interrupts() - Mask all Event doorbell - * interrupts. - * @dev: MHI device structure. - */ -int mhi_dev_mmio_mask_erdb_interrupts(struct mhi_dev *dev); - -/** - * mhi_dev_mmio_read_erdb_interrupts() - Read all Event doorbell - * interrupts. - * @dev: MHI device structure. - */ -int mhi_dev_mmio_read_erdb_status_interrupts(struct mhi_dev *dev); - -/** - * mhi_dev_mmio_clear_interrupts() - Clear all doorbell interrupts. - * @dev: MHI device structure. - */ -int mhi_dev_mmio_clear_interrupts(struct mhi_dev *dev); - -/** - * mhi_dev_mmio_get_chc_base() - Fetch the Channel ring context base address. - @dev: MHI device structure. - */ -int mhi_dev_mmio_get_chc_base(struct mhi_dev *dev); - -/** - * mhi_dev_mmio_get_erc_base() - Fetch the Event ring context base address. - * @dev: MHI device structure. - */ -int mhi_dev_mmio_get_erc_base(struct mhi_dev *dev); - -/** - * mhi_dev_get_crc_base() - Fetch the Command ring context base address. - * @dev: MHI device structure. - */ -int mhi_dev_mmio_get_crc_base(struct mhi_dev *dev); - -/** - * mhi_dev_mmio_get_ch_db() - Fetch the Write offset of the Channel ring ID. - * @dev: MHI device structure. - * @wr_offset: Pointer of the write offset to be written to. - */ -int mhi_dev_mmio_get_ch_db(struct mhi_dev_ring *ring, uint64_t *wr_offset); - -/** - * mhi_dev_get_erc_base() - Fetch the Write offset of the Event ring ID. - * @dev: MHI device structure. - * @wr_offset: Pointer of the write offset to be written to. - */ -int mhi_dev_mmio_get_erc_db(struct mhi_dev_ring *ring, uint64_t *wr_offset); - -/** - * mhi_dev_get_cmd_base() - Fetch the Write offset of the Command ring ID. - * @dev: MHI device structure. - * @wr_offset: Pointer of the write offset to be written to. - */ -int mhi_dev_mmio_get_cmd_db(struct mhi_dev_ring *ring, uint64_t *wr_offset); - -/** - * mhi_dev_mmio_set_env() - Write the Execution Enviornment. - * @dev: MHI device structure. - * @value: Value of the EXEC EVN. - */ -int mhi_dev_mmio_set_env(struct mhi_dev *dev, uint32_t value); - -/** - * mhi_dev_mmio_reset() - Reset the MMIO done as part of initialization. - * @dev: MHI device structure. - */ -int mhi_dev_mmio_reset(struct mhi_dev *dev); - -/** - * mhi_dev_get_mhi_addr() - Fetches the Data and Control region from the Host. - * @dev: MHI device structure. - */ -int mhi_dev_get_mhi_addr(struct mhi_dev *dev); - -/** - * mhi_dev_get_mhi_state() - Fetches the MHI state such as M0/M1/M2/M3. - * @dev: MHI device structure. - * @state: Pointer of type mhi_dev_state - * @mhi_reset: MHI device reset from host. - */ -int mhi_dev_mmio_get_mhi_state(struct mhi_dev *dev, enum mhi_dev_state *state, - bool *mhi_reset); - -/** - * mhi_dev_mmio_init() - Initializes the MMIO and reads the Number of event - * rings, support number of channels, and offsets to the Channel - * and Event doorbell from the host. - * @dev: MHI device structure. - */ -int mhi_dev_mmio_init(struct mhi_dev *dev); - -/** - * mhi_dev_update_ner() - Update the number of event rings (NER) programmed by - * the host. - * @dev: MHI device structure. - */ -int mhi_dev_update_ner(struct mhi_dev *dev); - -/** - * mhi_dev_restore_mmio() - Restores the MMIO when MHI device comes out of M3. - * @dev: MHI device structure. - */ -int mhi_dev_restore_mmio(struct mhi_dev *dev); - -/** - * mhi_dev_backup_mmio() - Backup MMIO before a MHI transition to M3. - * @dev: MHI device structure. - */ -int mhi_dev_backup_mmio(struct mhi_dev *dev); - -/** - * mhi_dev_dump_mmio() - Memory dump of the MMIO region for debug. - * @dev: MHI device structure. - */ -int mhi_dev_dump_mmio(struct mhi_dev *dev); - -/** - * mhi_dev_config_outbound_iatu() - Configure Outbound Address translation - * unit between device and host to map the Data and Control - * information. - * @dev: MHI device structure. - */ -int mhi_dev_config_outbound_iatu(struct mhi_dev *mhi); - -/** - * mhi_dev_send_state_change_event() - Send state change event to the host - * such as M0/M1/M2/M3. - * @dev: MHI device structure. - * @state: MHI state of type mhi_dev_state - */ -int mhi_dev_send_state_change_event(struct mhi_dev *mhi, - enum mhi_dev_state state); -/** - * mhi_dev_send_ee_event() - Send Execution enviornment state change - * event to the host. - * @dev: MHI device structure. - * @state: MHI state of type mhi_dev_execenv - */ -int mhi_dev_send_ee_event(struct mhi_dev *mhi, - enum mhi_dev_execenv exec_env); -/** - * mhi_dev_syserr() - System error when unexpected events are received. - * @dev: MHI device structure. - */ -int mhi_dev_syserr(struct mhi_dev *mhi); - -/** - * mhi_dev_suspend() - MHI device suspend to stop channel processing at the - * Transfer ring boundary, update the channel state to suspended. - * @dev: MHI device structure. - */ -int mhi_dev_suspend(struct mhi_dev *mhi); - -/** - * mhi_dev_resume() - MHI device resume to update the channel state to running. - * @dev: MHI device structure. - */ -int mhi_dev_resume(struct mhi_dev *mhi); - -/** - * mhi_dev_trigger_hw_acc_wakeup() - Notify State machine there is HW - * accelerated data to be send and prevent MHI suspend. - * @dev: MHI device structure. - */ -int mhi_dev_trigger_hw_acc_wakeup(struct mhi_dev *mhi); - -/** - * mhi_pcie_config_db_routing() - Configure Doorbell for Event and Channel - * context with IPA when performing a MHI resume. - * @dev: MHI device structure. - */ -int mhi_pcie_config_db_routing(struct mhi_dev *mhi); - -/** - * mhi_uci_init() - Initializes the User control interface (UCI) which - * exposes device nodes for the supported MHI software - * channels. - */ -int mhi_uci_init(void); - -/** - * mhi_dev_net_interface_init() - Initializes the mhi device network interface - * which exposes the virtual network interface (mhi_dev_net0). - * data packets will transfer between MHI host interface (mhi_swip) - * and mhi_dev_net interface using software path - */ -int mhi_dev_net_interface_init(void); - -/** - * mhi_dev_net_exit() - Clean up and close MHI Network interface module. - */ -void mhi_dev_net_exit(void); - -/** - * mhi_dev_notify_a7_event() - Used by PCIe driver to notify A7 MHI device - * interrupt after doorbell is received. Used by PCIe driver when MHI - * A7 interrupts are routed to PCIe instead of MHI device. - */ -void mhi_dev_notify_a7_event(struct mhi_dev *mhi); - /** * mhi_ctrl_state_info() - Provide MHI state info * @idx: Channel number idx. Look at channel_state_info and @@ -1282,12 +207,6 @@ void mhi_dev_notify_a7_event(struct mhi_dev *mhi); */ int mhi_ctrl_state_info(uint32_t idx, uint32_t *info); -/** - * uci_ctrl_update() - Update UCI once TRE's are available for clients to - * consume. - */ -void uci_ctrl_update(struct mhi_dev_client_cb_reason *reason); - /** * mhi_register_state_cb() - Clients can register and receive callback after * MHI channel is connected or disconnected. @@ -1295,4 +214,46 @@ void uci_ctrl_update(struct mhi_dev_client_cb_reason *reason); int mhi_register_state_cb(void (*mhi_state_cb) (struct mhi_dev_client_cb_data *cb_data), void *data, enum mhi_client_channel channel); -#endif /* _MHI_H_ */ + +#else +static inline int mhi_dev_open_channel(uint32_t chan_id, + struct mhi_dev_client **handle_client, + void (*event_trigger)(struct mhi_dev_client_cb_reason *cb)) +{ + return -EINVAL; +}; + +static inline int mhi_dev_close_channel(struct mhi_dev_client *handle_client) +{ + return -EINVAL; +}; + +static inline int mhi_dev_read_channel(struct mhi_req *mreq) +{ + return -EINVAL; +}; + +static inline int mhi_dev_write_channel(struct mhi_req *wreq) +{ + return -EINVAL; +}; + +static inline int mhi_dev_channel_isempty(struct mhi_dev_client *handle) +{ + return -EINVAL; +}; + +static inline int mhi_ctrl_state_info(uint32_t idx, uint32_t *info) +{ + return -EINVAL; +}; + +static inline int mhi_register_state_cb(void (*mhi_state_cb) + (struct mhi_dev_client_cb_data *cb_data), void *data, + enum mhi_client_channel channel) +{ + return -EINVAL; +}; +#endif + +#endif /* _MSM_MHI_DEV_H*/ -- GitLab From 27ab58b34f80629aa826ea041c4233be94a989fd Mon Sep 17 00:00:00 2001 From: Zhenhua Huang Date: Mon, 6 Aug 2018 16:58:39 +0800 Subject: [PATCH 603/604] ANDROID: binder: make 32bit of IPC driver configureable Make 32bit of IPC driver configurable so that we can change the behaviour in defconfig. Change-Id: If82c1316ad6f7732a782149e26a2524146237913 Signed-off-by: Zhenhua Huang --- drivers/android/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig index 01de42c8b74b..bb2a5b581622 100644 --- a/drivers/android/Kconfig +++ b/drivers/android/Kconfig @@ -32,9 +32,9 @@ config ANDROID_BINDER_DEVICES therefore logically separated from the other devices. config ANDROID_BINDER_IPC_32BIT - bool + bool "Android Binder IPC 32BIT Driver" depends on !64BIT && ANDROID_BINDER_IPC - default y + default n ---help--- The Binder API has been changed to support both 32 and 64bit applications in a mixed environment. -- GitLab From c1b695b22cb3aedbb75a334f1957f9266cdfc0e4 Mon Sep 17 00:00:00 2001 From: Yogesh Lal Date: Sat, 11 Aug 2018 13:48:56 +0530 Subject: [PATCH 604/604] defconfig: Enable 32bit of IPC driver for msm8909w Enabling ANDROID_BINDER_IPC_32BIT as now its disable by default. Change-Id: I824f9c0b82630e462aee5624c3672cae63e04f06 Signed-off-by: Yogesh Lal --- arch/arm/configs/msm8909w-perf_defconfig | 1 + arch/arm/configs/msm8909w_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig index 3094af9b708a..0e56f7ff9a94 100644 --- a/arch/arm/configs/msm8909w-perf_defconfig +++ b/arch/arm/configs/msm8909w-perf_defconfig @@ -448,6 +448,7 @@ CONFIG_PWM=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDER_IPC_32BIT=y CONFIG_STM=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig index 2e545d8d18cf..1a89fb980d98 100644 --- a/arch/arm/configs/msm8909w_defconfig +++ b/arch/arm/configs/msm8909w_defconfig @@ -440,6 +440,7 @@ CONFIG_PWM=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDER_IPC_32BIT=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y -- GitLab