From 91a4d732d1c13202991567b0eeb4105149230cae Mon Sep 17 00:00:00 2001 From: Jim Wang Date: Wed, 22 Apr 2020 13:32:00 -0400 Subject: [PATCH 001/192] dt-bindings: Add BGR color re-order option for DSI Add the missing DSI RGB color re-order "rgb_swap_bgr" option. Change-Id: I0772e50ce0555b60bf1ed2b09351b71aad43b00c Signed-off-by: Jim Wang --- Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt index 9f57f0cfa636..72e89915f793 100644 --- a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt @@ -253,6 +253,7 @@ Optional properties: - qcom,mdss-dsi-color-order: Specifies the R, G and B channel ordering. "rgb_swap_rgb" = DSI_RGB_SWAP_RGB (default value) "rgb_swap_rbg" = DSI_RGB_SWAP_RBG + "rgb_swap_bgr" = DSI_RGB_SWAP_BGR "rgb_swap_brg" = DSI_RGB_SWAP_BRG "rgb_swap_grb" = DSI_RGB_SWAP_GRB "rgb_swap_gbr" = DSI_RGB_SWAP_GBR From 3a93c5e54b9e3ddd804955060699193a61c1fc35 Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Thu, 23 Jan 2020 18:58:22 +0530 Subject: [PATCH 002/192] drm/msm/dp: avoid sink message processing when hdcp is off Skip processing the sink message in sde_hdcp_2x_main thread when hdcp TA is unloaded. If there is any error generated during the authentication sequence, then the hdcp authentication is aborted and the source will restart authentication procedure. When authentication is aborted, the qseecom handle is lost and memory it referenced becomes protected. When a subsequent command execution in the sde_hdcp_2x_main thread tries to dereference that particular memory from the qseecom handle, there is a page fault crash observed. This change will skip accessing the memory referenced by the qseecom handle when hdcp authentication session is tearing down. Change-Id: I71ed44042897f17cc8817a1b1c54a43e42cf5f73 Signed-off-by: Rajat Gupta --- drivers/gpu/drm/msm/sde_hdcp_2x.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/sde_hdcp_2x.c b/drivers/gpu/drm/msm/sde_hdcp_2x.c index 01e5e2c9e516..c346d26aa1fb 100644 --- a/drivers/gpu/drm/msm/sde_hdcp_2x.c +++ b/drivers/gpu/drm/msm/sde_hdcp_2x.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -563,6 +563,11 @@ static void sde_hdcp_2x_msg_sent(struct sde_hdcp_2x_ctrl *hdcp) HDCP_TRANSPORT_CMD_INVALID }; cdata.context = hdcp->client_data; + if (atomic_read(&hdcp->hdcp_off)) { + pr_debug("invalid state, hdcp off\n"); + return; + } + switch (hdcp->app_data.response.data[0]) { case SKE_SEND_TYPE_ID: sde_hdcp_2x_set_hw_key(hdcp); From 4d1a6badaee5515e4d6cbb1b0e7e55e8cfc35ee8 Mon Sep 17 00:00:00 2001 From: Jim Wang Date: Wed, 22 Apr 2020 13:23:58 -0400 Subject: [PATCH 003/192] dt-bindings: Add property to force DSI TX simulate CSI signal Add new property "qcom,csi-proxy-enable". When enabled, it will force DSI transmitter changes the packet DataTypes to simulate the CSI-2 compatible signal. Change-Id: I9e77845c67cd7b1a9118261488ce411fd233858f Signed-off-by: Jim Wang --- Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt index 9f57f0cfa636..224bc3f9c7c3 100644 --- a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt @@ -553,6 +553,7 @@ Optional properties: frequencies in Hz for the given panel. - qcom,dsi-dyn-clk-skip-timing-update: Boolean to specify whether to skip phy timing parameter update during dynamic clock switch. +- qcom,csi-proxy-enable: Boolean to config DSI transmission packet DataTypes to simulate the CSI-2 compatible signal Required properties for sub-nodes: None Optional properties: From 6651def3497b1375813246f79d14f51167f3b878 Mon Sep 17 00:00:00 2001 From: Yuchao Ma Date: Wed, 6 May 2020 15:20:53 +0800 Subject: [PATCH 004/192] ARM: dts: msm: fix dither configuration on trinket target This change modified incorrect number configuration regarding dither. Change-Id: Ied68fc9d2e0a74e5bef94d92f369fafd0b2b093f Signed-off-by: Yuchao Ma --- arch/arm64/boot/dts/qcom/trinket-sde.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/trinket-sde.dtsi b/arch/arm64/boot/dts/qcom/trinket-sde.dtsi index 77ffa86c0d72..1d06c5eb9ec7 100644 --- a/arch/arm64/boot/dts/qcom/trinket-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/trinket-sde.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -99,7 +99,7 @@ qcom,sde-cdm-off = <0x7a200>; qcom,sde-cdm-size = <0x224>; - qcom,sde-dither-off = <0x30e0 0x30e0 0x30e0 0x30e0>; + qcom,sde-dither-off = <0x30e0 0x30e0>; qcom,sde-dither-version = <0x00010000>; qcom,sde-dither-size = <0x20>; From b4763667ce6f70a2d8c4868a1a80f3c786f3f30f Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Fri, 5 Jun 2020 11:41:20 -0700 Subject: [PATCH 005/192] mhi: core: Use high priority workqueue for all MHI work Boot-up and shutdown require faster scheduling of the PM state worker. Use the high priority workqueue for processing any of the PM state transitions to ensure faster boot-up or shutdown handling on MHI host. Change-Id: Ie311426344d9561d490aa2bf6616aa30b4333e9a Signed-off-by: Bhaumik Bhatt --- drivers/bus/mhi/core/mhi_init.c | 6 +++--- drivers/bus/mhi/core/mhi_main.c | 2 +- drivers/bus/mhi/core/mhi_pm.c | 7 +++---- include/linux/mhi.h | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index dc07a43afcc8..b66b5de5bc28 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -1534,9 +1534,9 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl) INIT_WORK(&mhi_cntrl->st_worker, mhi_pm_st_worker); init_waitqueue_head(&mhi_cntrl->state_event); - mhi_cntrl->special_wq = alloc_ordered_workqueue("mhi_special_w", + mhi_cntrl->wq = alloc_ordered_workqueue("mhi_w", WQ_MEM_RECLAIM | WQ_HIGHPRI); - if (!mhi_cntrl->special_wq) + if (!mhi_cntrl->wq) goto error_alloc_cmd; INIT_WORK(&mhi_cntrl->special_work, mhi_special_purpose_work); @@ -1662,7 +1662,7 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl) error_alloc_dev: kfree(mhi_cntrl->mhi_cmd); - destroy_workqueue(mhi_cntrl->special_wq); + destroy_workqueue(mhi_cntrl->wq); error_alloc_cmd: vfree(mhi_cntrl->mhi_chan); diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index 36737a3bb5b9..dd8d4d8c9074 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -1698,7 +1698,7 @@ irqreturn_t mhi_intvec_handlr(int irq_number, void *dev) MHI_VERB("Exit\n"); if (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) - queue_work(mhi_cntrl->special_wq, &mhi_cntrl->special_work); + queue_work(mhi_cntrl->wq, &mhi_cntrl->special_work); return IRQ_WAKE_THREAD; } diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c index acbdd1d76b54..4a9f1952f965 100644 --- a/drivers/bus/mhi/core/mhi_pm.c +++ b/drivers/bus/mhi/core/mhi_pm.c @@ -777,7 +777,7 @@ static int mhi_queue_disable_transition(struct mhi_controller *mhi_cntrl, list_add_tail(&item->node, &mhi_cntrl->transition_list); spin_unlock_irqrestore(&mhi_cntrl->transition_lock, flags); - schedule_work(&mhi_cntrl->st_worker); + queue_work(mhi_cntrl->wq, &mhi_cntrl->st_worker); return 0; } @@ -797,7 +797,7 @@ int mhi_queue_state_transition(struct mhi_controller *mhi_cntrl, list_add_tail(&item->node, &mhi_cntrl->transition_list); spin_unlock_irqrestore(&mhi_cntrl->transition_lock, flags); - schedule_work(&mhi_cntrl->st_worker); + queue_work(mhi_cntrl->wq, &mhi_cntrl->st_worker); return 0; } @@ -813,8 +813,7 @@ static void mhi_special_events_pending(struct mhi_controller *mhi_cntrl) spin_lock_bh(&mhi_event->lock); if (ev_ring->rp != mhi_to_virtual(ev_ring, er_ctxt->rp)) { - queue_work(mhi_cntrl->special_wq, - &mhi_cntrl->special_work); + queue_work(mhi_cntrl->wq, &mhi_cntrl->special_work); spin_unlock_bh(&mhi_event->lock); break; } diff --git a/include/linux/mhi.h b/include/linux/mhi.h index 5460fc206d7e..8e27a2e4d269 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -357,7 +357,7 @@ struct mhi_controller { /* worker for different state transitions */ struct work_struct st_worker; struct work_struct special_work; - struct workqueue_struct *special_wq; + struct workqueue_struct *wq; wait_queue_head_t state_event; From be889b071ca9f89e2d5d71c84c7fc61940e2d3ab Mon Sep 17 00:00:00 2001 From: Rama Krishna Phani A Date: Thu, 18 Jun 2020 20:54:20 +0530 Subject: [PATCH 006/192] msm: mhi_dev: Wait for host to set BHI_INTVEC value BHI_INTVEC will be reset to 0xFFFFFFFF when the link gets initialized in PBL. This might happen if the device gets rebooted when the link is in D3 cold. This will prevent EP PCIE HLOS driver from sending an MSI to host to request for a reset, which is required in the device reboot case. This change is the device-side part of the fix, which is to wait for the host to re-init the BHI_INTVEC value after link resumes from D3 cold. Change-Id: I286804d597b24d521b291119077e1ec81af32a27 Signed-off-by: Rama Krishna Phani A --- drivers/platform/msm/mhi_dev/mhi.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 859cf76116b8..53c3f3195ac5 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -40,6 +40,9 @@ /* Wait time before suspend/resume is complete */ #define MHI_SUSPEND_MIN 100 #define MHI_SUSPEND_TIMEOUT 600 +/* Wait time on the device for Host to set BHI_INTVEC */ +#define MHI_BHI_INTVEC_MAX_CNT 200 +#define MHI_BHI_INTVEC_WAIT_MS 50 #define MHI_WAKEUP_TIMEOUT_CNT 20 #define MHI_MASK_CH_EV_LEN 32 #define MHI_RING_CMD_ID 0 @@ -3180,7 +3183,7 @@ EXPORT_SYMBOL(mhi_dev_write_channel); static int mhi_dev_recover(struct mhi_dev *mhi) { int rc = 0; - uint32_t syserr, max_cnt = 0, bhi_intvec = 0; + uint32_t syserr, max_cnt = 0, bhi_intvec = 0, bhi_max_cnt = 0; u32 mhi_reset; enum mhi_dev_state state; @@ -3205,6 +3208,26 @@ static int mhi_dev_recover(struct mhi_dev *mhi) if (rc) return rc; + while (bhi_intvec == 0xffffffff && + bhi_max_cnt < MHI_BHI_INTVEC_MAX_CNT) { + /* Wait for Host to set the bhi_intvec */ + msleep(MHI_BHI_INTVEC_WAIT_MS); + mhi_log(MHI_MSG_VERBOSE, + "Wait for Host to set BHI_INTVEC\n"); + rc = mhi_dev_mmio_read(mhi, BHI_INTVEC, &bhi_intvec); + if (rc) { + pr_err("%s: Get BHI_INTVEC failed\n", __func__); + return rc; + } + bhi_max_cnt++; + } + + if (bhi_max_cnt == MHI_BHI_INTVEC_MAX_CNT) { + mhi_log(MHI_MSG_ERROR, + "Host failed to set BHI_INTVEC\n"); + return -EINVAL; + } + if (bhi_intvec != 0xffffffff) { /* Indicate the host that the device is ready */ rc = ep_pcie_trigger_msi(mhi->phandle, bhi_intvec); From 1d8b0ba0d06a1784a4b8bfc3dee1707645df10e6 Mon Sep 17 00:00:00 2001 From: Yashwanth Date: Mon, 22 Jun 2020 15:58:52 +0530 Subject: [PATCH 007/192] msm/sde/rotator: update rotator max clk rate based on target This change updates max clock rate for rotator based on target check instead of pre-defined maximum clk rate. Change-Id: I3523262a7dbe652156c7832dcfc9b5a1e216288e Signed-off-by: Yashwanth --- .../msm/sde/rotator/sde_rotator_core.c | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) 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 43ff8a4a14ff..97540869159d 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c @@ -3173,16 +3173,19 @@ int sde_rotator_core_init(struct sde_rot_mgr **pmgr, mgr->ops_hw_init = sde_rotator_r3_init; mgr->min_rot_clk = ROT_MIN_ROT_CLK; - /* - * on platforms where the maxlinewidth is greater than - * default we need to have a max clock rate check to - * ensure we do not cross the max allowed clock for rotator - */ - if (IS_SDE_MAJOR_SAME(mdata->mdss_version, - SDE_MDP_HW_REV_500) || + if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_500) || + IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_620)) + mgr->max_rot_clk = 460000000UL; + else if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_520)) + mgr->max_rot_clk = 430000000UL; + else if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_530) || IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, - SDE_MDP_HW_REV_620)) - mgr->max_rot_clk = ROT_R3_MAX_ROT_CLK; + SDE_MDP_HW_REV_540)) + mgr->max_rot_clk = 307200000UL; if (!(IS_SDE_MAJOR_SAME(mdata->mdss_version, SDE_MDP_HW_REV_500) || From 7a513099c3e97d7da720c922159ab3d13c43809b Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Fri, 3 Jul 2020 03:42:00 +0530 Subject: [PATCH 008/192] ARM: dts: msm: Correct EP PCIE phy sequence Some registers were programmed incorrectly for the EP phy. Update phy sequence as per HPG. Change-Id: Icdffcb30e1c15e1381459fb7c86e17eb1c82f390 Signed-off-by: Siva Kumar Akkireddi --- arch/arm64/boot/dts/qcom/sdxprairie-v2.dtsi | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-v2.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-v2.dtsi index 96b51654dba5..9c60766e6cc3 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-v2.dtsi @@ -155,7 +155,7 @@ }; &pcie_ep { - qcom,pcie-phy-ver = <2102>; + qcom,pcie-phy-ver = <2103>; qcom,phy-init = <0x1240 0x001 0x0 0x1 0x100c 0x02 0x0 0x1 0x1044 0x18 0x0 0x1 @@ -177,6 +177,8 @@ 0x10bc 0x4b 0x0 0x1 0x10c4 0x50 0x0 0x1 0x10d4 0x00 0x0 0x1 + 0x10ec 0xfb 0x0 0x1 + 0x10f0 0x01 0x0 0x1 0x10f4 0xfb 0x0 0x1 0x10f8 0x01 0x0 0x1 0x110c 0x02 0x0 0x1 @@ -223,7 +225,7 @@ 0x0350 0x08 0x0 0x1 0x0400 0xa0 0x0 0x1 0x043c 0x12 0x0 0x1 - 0x040c 0x12 0x0 0x1 + 0x040c 0x38 0x0 0x1 0x0888 0x05 0x0 0x1 0x088c 0xf6 0x0 0x1 0x0890 0x13 0x0 0x1 @@ -264,6 +266,7 @@ 0x16f4 0x13 0x0 0x1 0x1e24 0x00 0x0 0x1 0x1e28 0x00 0x0 0x1 + 0x1388 0x77 0x0 0x1 0x1200 0x000 0x0 0x1 0x1244 0x003 0x0 0x1>; }; From b8bdc6c460034ac47f2b7f34d6233e8c02ef6a6a Mon Sep 17 00:00:00 2001 From: Puranam V G Tejaswi Date: Mon, 12 Aug 2019 16:08:22 +0530 Subject: [PATCH 009/192] msm: kgsl: remove redundant check for usermem type The check for usermem type, while updating the stat for memory mapped to userspace is not required. Memory with usermem type KGSL_MEM_ENTRY_ION is not mapped to user by kgsl and the mapsize would always be zero. So remove the unnecessary check for usermem type. Change-Id: Iaa0b86d1c7160657de1d802f2cc10c3bdbdf84b3 Signed-off-by: Puranam V G Tejaswi --- drivers/gpu/msm/kgsl.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index e2b00c6d60c4..f82d7f854894 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -516,8 +516,6 @@ static int kgsl_mem_entry_attach_process(struct kgsl_device *device, /* Detach a memory entry from a process and unmap it from the MMU */ static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry) { - unsigned int type; - if (entry == NULL) return; @@ -530,10 +528,7 @@ static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry) idr_remove(&entry->priv->mem_idr, entry->id); entry->id = 0; - type = kgsl_memdesc_usermem_type(&entry->memdesc); - - if (type != KGSL_MEM_ENTRY_ION) - entry->priv->gpumem_mapped -= entry->memdesc.mapsize; + entry->priv->gpumem_mapped -= entry->memdesc.mapsize; spin_unlock(&entry->priv->mem_lock); From 54a03229d449f3eb2bb9077dafa0359bf5ac5888 Mon Sep 17 00:00:00 2001 From: Puranam V G Tejaswi Date: Wed, 7 Aug 2019 23:20:14 +0530 Subject: [PATCH 010/192] msm: kgsl: fix accounting of memory mapped to userspace The mapsize of kgsl_memdesc and gpumem_mapped of process are incremented only in vmfault handler. But for cache modes write through and write back, pages are inserted in kgsl_mmap. So account for those mappings also in gpumem_mapped. Change-Id: I98e29b28fa6fd2915b03bdcb9c655015a926d0eb Signed-off-by: Puranam V G Tejaswi --- drivers/gpu/msm/kgsl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index f82d7f854894..99313e7285cb 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -4768,6 +4768,8 @@ static int kgsl_mmap(struct file *file, struct vm_area_struct *vma) vm_insert_page(vma, addr, page); addr += PAGE_SIZE; } + m->mapsize = m->size; + entry->priv->gpumem_mapped += m->mapsize; } vma->vm_file = file; From 4daead56f20ff2ab60c958cbbc97312b2cf085e8 Mon Sep 17 00:00:00 2001 From: Nirav Khatri Date: Thu, 30 Apr 2020 11:40:55 +0530 Subject: [PATCH 011/192] ARM64: dts: qcs405: Add SPDIF pinctrl nodes Add SPDIF pinctrl nodes to add coaxial and optical spdif out support. Change-Id: I9934ba87ce52ce5b65d31aac82d19e82115c7d1b Signed-off-by: Nirav Khatri --- .../bindings/sound/qcom-audio-dev.txt | 2 + .../dts/qcom/qcs405-csra8-audio-overlay.dtsi | 18 ++++++ .../qcom/qcs405-csra8plus2-audio-overlay.dtsi | 18 ++++++ arch/arm64/boot/dts/qcom/qcs405-lpi.dtsi | 61 ++++++++++++++++++- 4 files changed, 98 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index f3d930fe0573..47fa30fe20bd 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -1417,6 +1417,8 @@ Optional properties: - qcom,afe-rxtx-lb: AFE RX to TX loopback. - qcom,ext-mclk-gpio: pinctrl referring to external mclk - qcom,ext-mclk-src: Device tree node referring to external mclk clock +- qcom,pri-spdiftx-gpios: Pinctrl referring to primary spdif output gpios +- qcom,sec-spdiftx-gpios: Pinctrl referring to secondary spdif output gpios - #ext-mclk-1-cfg-cells: Number of cells in ext-mclk-1-cfg-* nodes. Must be 6. - ext-mclk-1 cfg-11p2896: Frequnency table for 11.2896MHz mclk frequnecy. Fields are clock rate, div2x, m, n, d and clock root. diff --git a/arch/arm64/boot/dts/qcom/qcs405-csra8-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/qcs405-csra8-audio-overlay.dtsi index 5f847f00e5c8..fae8015e8a9e 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-csra8-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-csra8-audio-overlay.dtsi @@ -76,6 +76,22 @@ pinctrl-0 = <&ext_mclk_1_sck_active>; pinctrl-1 = <&ext_mclk_1_sck_sleep>; }; + + pri_spdiftx_gpios: pri_spdiftx_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&pri_spdiftx_active>; + pinctrl-1 = <&pri_spdiftx_sleep>; + qcom,lpi-gpios; + }; + + sec_spdiftx_gpios: sec_spdiftx_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&sec_spdiftx_active>; + pinctrl-1 = <&sec_spdiftx_sleep>; + qcom,lpi-gpios; + }; }; &q6core { @@ -109,6 +125,8 @@ qcom,cdc-dmic67-gpios = <&cdc_dmic67_gpios>; qcom,pri-mi2s-gpios = <&pri_mi2s_gpios>; qcom,sec-mi2s-gpios = <&sec_mi2s_gpios>; + qcom,pri-spdiftx-gpios = <&pri_spdiftx_gpios>; + qcom,sec-spdiftx-gpios = <&sec_spdiftx_gpios>; qcom,audio-routing = "RX_BIAS", "MCLK", "lineout booster", "LINEOUT1", diff --git a/arch/arm64/boot/dts/qcom/qcs405-csra8plus2-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/qcs405-csra8plus2-audio-overlay.dtsi index f5c1dad1a2a9..983889f0fbe2 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-csra8plus2-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-csra8plus2-audio-overlay.dtsi @@ -97,6 +97,22 @@ pinctrl-0 = <&ext_mclk_1_sck_active>; pinctrl-1 = <&ext_mclk_1_sck_sleep>; }; + + pri_spdiftx_gpios: pri_spdiftx_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&pri_spdiftx_active>; + pinctrl-1 = <&pri_spdiftx_sleep>; + qcom,lpi-gpios; + }; + + sec_spdiftx_gpios: sec_spdiftx_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&sec_spdiftx_active>; + pinctrl-1 = <&sec_spdiftx_sleep>; + qcom,lpi-gpios; + }; }; &q6core { @@ -136,6 +152,8 @@ qcom,pri-mi2s-gpios = <&pri_mi2s_gpios>; qcom,sec-mi2s-gpios = <&sec_mi2s_gpios>; qcom,quat-mi2s-gpios = <&quat_mi2s_gpios>; + qcom,pri-spdiftx-gpios = <&pri_spdiftx_gpios>; + qcom,sec-spdiftx-gpios = <&sec_spdiftx_gpios>; qcom,msm-mi2s-master = <1>, <0>, <1>, <0>, <1>, <1>; qcom,audio-routing = "RX_BIAS", "MCLK", diff --git a/arch/arm64/boot/dts/qcom/qcs405-lpi.dtsi b/arch/arm64/boot/dts/qcom/qcs405-lpi.dtsi index ef7a3c487e9b..68e3a6db08d4 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-lpi.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-lpi.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -453,6 +453,65 @@ }; }; + pri_spdiftx_pin { + pri_spdiftx_sleep: pri_spdiftx_sleep { + mux { + pins = "gpio6"; + function = "func1"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + + pri_spdiftx_active: pri_spdiftx_active { + mux { + pins = "gpio6"; + function = "func1"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; + bias-pull-down; + output-low; + }; + }; + }; + + sec_spdiftx_pin { + sec_spdiftx_sleep: sec_spdiftx_sleep { + mux { + pins = "gpio7"; + function = "func1"; + }; + + config { + pins = "gpio7"; + drive-strenght = <2>; + bias-bus-hold; + output-high; + }; + }; + + sec_spdiftx_active: sec_spdiftx_active { + mux { + pins = "gpio7"; + function = "func1"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; + output-low; + }; + }; + }; + wsa_swr_data_pin { wsa_swr_data_sleep: wsa_swr_data_sleep { mux { From 5307b1326ddbce478eadcc453b6f9e69065bbd2c Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 21 Dec 2017 14:30:59 +0530 Subject: [PATCH 012/192] UPSTREAM: ath10k: Add support for 64 bit ce descriptor WCN3990 CE descriptor uses 64bit address for src/dst ring buffer. It has extended field for toeplitz hash result, which is being used for HW assisted hash results. To accommodate WCN3990 descriptor, define new CE descriptor for extended addressing mode and related methods to handle the descriptor data. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: 2a1e1ad3fd37a632b61f50e73dafddb4b0fa57f1 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: Iabd86d2279309e7694f7801be9eee9b89848f438 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/ce.c | 630 ++++++++++++++++++++++---- drivers/net/wireless/ath/ath10k/ce.h | 48 +- drivers/net/wireless/ath/ath10k/pci.c | 6 +- 3 files changed, 587 insertions(+), 97 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 9aa214b1eb48..48314b8fc2c3 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -327,12 +327,12 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar, * Guts of ath10k_ce_send. * The caller takes responsibility for any needed locking. */ -int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, - void *per_transfer_context, - dma_addr_t buffer, - unsigned int nbytes, - unsigned int transfer_id, - unsigned int flags) +static int _ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, + void *per_transfer_context, + dma_addr_t buffer, + unsigned int nbytes, + unsigned int transfer_id, + unsigned int flags) { struct ath10k *ar = ce_state->ar; struct ath10k_ce_ring *src_ring = ce_state->src_ring; @@ -384,6 +384,87 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, return ret; } +static int _ath10k_ce_send_nolock_64(struct ath10k_ce_pipe *ce_state, + void *per_transfer_context, + dma_addr_t buffer, + unsigned int nbytes, + unsigned int transfer_id, + unsigned int flags) +{ + struct ath10k *ar = ce_state->ar; + struct ath10k_ce_ring *src_ring = ce_state->src_ring; + struct ce_desc_64 *desc, sdesc; + unsigned int nentries_mask = src_ring->nentries_mask; + unsigned int sw_index = src_ring->sw_index; + unsigned int write_index = src_ring->write_index; + u32 ctrl_addr = ce_state->ctrl_addr; + __le32 *addr; + u32 desc_flags = 0; + int ret = 0; + + if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) + return -ESHUTDOWN; + + if (nbytes > ce_state->src_sz_max) + ath10k_warn(ar, "%s: send more we can (nbytes: %d, max: %d)\n", + __func__, nbytes, ce_state->src_sz_max); + + if (unlikely(CE_RING_DELTA(nentries_mask, + write_index, sw_index - 1) <= 0)) { + ret = -ENOSR; + goto exit; + } + + desc = CE_SRC_RING_TO_DESC_64(src_ring->base_addr_owner_space, + write_index); + + desc_flags |= SM(transfer_id, CE_DESC_FLAGS_META_DATA); + + if (flags & CE_SEND_FLAG_GATHER) + desc_flags |= CE_DESC_FLAGS_GATHER; + + if (flags & CE_SEND_FLAG_BYTE_SWAP) + desc_flags |= CE_DESC_FLAGS_BYTE_SWAP; + + addr = (__le32 *)&sdesc.addr; + + flags |= upper_32_bits(buffer) & CE_DESC_FLAGS_GET_MASK; + addr[0] = __cpu_to_le32(buffer); + addr[1] = __cpu_to_le32(flags); + if (flags & CE_SEND_FLAG_GATHER) + addr[1] |= __cpu_to_le32(CE_WCN3990_DESC_FLAGS_GATHER); + else + addr[1] &= ~(__cpu_to_le32(CE_WCN3990_DESC_FLAGS_GATHER)); + + sdesc.nbytes = __cpu_to_le16(nbytes); + sdesc.flags = __cpu_to_le16(desc_flags); + + *desc = sdesc; + + src_ring->per_transfer_context[write_index] = per_transfer_context; + + /* Update Source Ring Write Index */ + write_index = CE_RING_IDX_INCR(nentries_mask, write_index); + + if (!(flags & CE_SEND_FLAG_GATHER)) + ath10k_ce_src_ring_write_index_set(ar, ctrl_addr, write_index); + + src_ring->write_index = write_index; +exit: + return ret; +} + +int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, + void *per_transfer_context, + dma_addr_t buffer, + unsigned int nbytes, + unsigned int transfer_id, + unsigned int flags) +{ + return ce_state->ops->ce_send_nolock(ce_state, per_transfer_context, + buffer, nbytes, transfer_id, flags); +} + void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe) { struct ath10k *ar = pipe->ar; @@ -413,7 +494,7 @@ void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe) int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, void *per_transfer_context, - dma_addr_t buffer, + dma_addr_t buffer, unsigned int nbytes, unsigned int transfer_id, unsigned int flags) @@ -459,8 +540,8 @@ int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe) return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1); } -int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, - dma_addr_t paddr) +static int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, + dma_addr_t paddr) { struct ath10k *ar = pipe->ar; struct ath10k_ce *ce = ath10k_ce_priv(ar); @@ -489,6 +570,39 @@ int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, return 0; } +static int __ath10k_ce_rx_post_buf_64(struct ath10k_ce_pipe *pipe, + void *ctx, + dma_addr_t paddr) +{ + struct ath10k *ar = pipe->ar; + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_ce_ring *dest_ring = pipe->dest_ring; + unsigned int nentries_mask = dest_ring->nentries_mask; + unsigned int write_index = dest_ring->write_index; + unsigned int sw_index = dest_ring->sw_index; + struct ce_desc_64 *base = dest_ring->base_addr_owner_space; + struct ce_desc_64 *desc = + CE_DEST_RING_TO_DESC_64(base, write_index); + u32 ctrl_addr = pipe->ctrl_addr; + + lockdep_assert_held(&ce->ce_lock); + + if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) == 0) + return -ENOSPC; + + desc->addr = __cpu_to_le64(paddr); + desc->addr &= __cpu_to_le64(CE_DESC_37BIT_ADDR_MASK); + + desc->nbytes = 0; + + dest_ring->per_transfer_context[write_index] = ctx; + write_index = CE_RING_IDX_INCR(nentries_mask, write_index); + ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index); + dest_ring->write_index = write_index; + + return 0; +} + void ath10k_ce_rx_update_write_idx(struct ath10k_ce_pipe *pipe, u32 nentries) { struct ath10k *ar = pipe->ar; @@ -517,7 +631,7 @@ int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, int ret; spin_lock_bh(&ce->ce_lock); - ret = __ath10k_ce_rx_post_buf(pipe, ctx, paddr); + ret = pipe->ops->ce_rx_post_buf(pipe, ctx, paddr); spin_unlock_bh(&ce->ce_lock); return ret; @@ -527,9 +641,10 @@ int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, * Guts of ath10k_ce_completed_recv_next. * The caller takes responsibility for any necessary locking. */ -int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state, - void **per_transfer_contextp, - unsigned int *nbytesp) +static int + _ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state, + void **per_transfer_contextp, + unsigned int *nbytesp) { struct ath10k_ce_ring *dest_ring = ce_state->dest_ring; unsigned int nentries_mask = dest_ring->nentries_mask; @@ -576,6 +691,64 @@ int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state, return 0; } +static int +_ath10k_ce_completed_recv_next_nolock_64(struct ath10k_ce_pipe *ce_state, + void **per_transfer_contextp, + unsigned int *nbytesp) +{ + struct ath10k_ce_ring *dest_ring = ce_state->dest_ring; + unsigned int nentries_mask = dest_ring->nentries_mask; + unsigned int sw_index = dest_ring->sw_index; + struct ce_desc_64 *base = dest_ring->base_addr_owner_space; + struct ce_desc_64 *desc = + CE_DEST_RING_TO_DESC_64(base, sw_index); + struct ce_desc_64 sdesc; + u16 nbytes; + + /* Copy in one go for performance reasons */ + sdesc = *desc; + + nbytes = __le16_to_cpu(sdesc.nbytes); + if (nbytes == 0) { + /* This closes a relatively unusual race where the Host + * sees the updated DRRI before the update to the + * corresponding descriptor has completed. We treat this + * as a descriptor that is not yet done. + */ + return -EIO; + } + + desc->nbytes = 0; + + /* Return data from completed destination descriptor */ + *nbytesp = nbytes; + + if (per_transfer_contextp) + *per_transfer_contextp = + dest_ring->per_transfer_context[sw_index]; + + /* Copy engine 5 (HTT Rx) will reuse the same transfer context. + * So update transfer context all CEs except CE5. + */ + if (ce_state->id != 5) + dest_ring->per_transfer_context[sw_index] = NULL; + + /* Update sw_index */ + sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); + dest_ring->sw_index = sw_index; + + return 0; +} + +int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state, + void **per_transfer_ctx, + unsigned int *nbytesp) +{ + return ce_state->ops->ce_completed_recv_next_nolock(ce_state, + per_transfer_ctx, + nbytesp); +} + int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state, void **per_transfer_contextp, unsigned int *nbytesp) @@ -585,17 +758,18 @@ int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state, int ret; spin_lock_bh(&ce->ce_lock); - ret = ath10k_ce_completed_recv_next_nolock(ce_state, + ret = ce_state->ops->ce_completed_recv_next_nolock(ce_state, per_transfer_contextp, nbytesp); + spin_unlock_bh(&ce->ce_lock); return ret; } -int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, - void **per_transfer_contextp, - dma_addr_t *bufferp) +static int _ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, + void **per_transfer_contextp, + dma_addr_t *bufferp) { struct ath10k_ce_ring *dest_ring; unsigned int nentries_mask; @@ -646,6 +820,69 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, return ret; } +static int _ath10k_ce_revoke_recv_next_64(struct ath10k_ce_pipe *ce_state, + void **per_transfer_contextp, + dma_addr_t *bufferp) +{ + struct ath10k_ce_ring *dest_ring; + unsigned int nentries_mask; + unsigned int sw_index; + unsigned int write_index; + int ret; + struct ath10k *ar; + struct ath10k_ce *ce; + + dest_ring = ce_state->dest_ring; + + if (!dest_ring) + return -EIO; + + ar = ce_state->ar; + ce = ath10k_ce_priv(ar); + + spin_lock_bh(&ce->ce_lock); + + nentries_mask = dest_ring->nentries_mask; + sw_index = dest_ring->sw_index; + write_index = dest_ring->write_index; + if (write_index != sw_index) { + struct ce_desc_64 *base = dest_ring->base_addr_owner_space; + struct ce_desc_64 *desc = + CE_DEST_RING_TO_DESC_64(base, sw_index); + + /* Return data from completed destination descriptor */ + *bufferp = __le64_to_cpu(desc->addr); + + if (per_transfer_contextp) + *per_transfer_contextp = + dest_ring->per_transfer_context[sw_index]; + + /* sanity */ + dest_ring->per_transfer_context[sw_index] = NULL; + desc->nbytes = 0; + + /* Update sw_index */ + sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); + dest_ring->sw_index = sw_index; + ret = 0; + } else { + ret = -EIO; + } + + spin_unlock_bh(&ce->ce_lock); + + return ret; +} + +int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, + void **per_transfer_contextp, + dma_addr_t *bufferp) +{ + return ce_state->ops->ce_revoke_recv_next(ce_state, + per_transfer_contextp, + bufferp); +} + /* * Guts of ath10k_ce_completed_send_next. * The caller takes responsibility for any necessary locking. @@ -700,6 +937,41 @@ int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, return 0; } +static void ath10k_ce_extract_desc_data(struct ath10k *ar, + struct ath10k_ce_ring *src_ring, + u32 sw_index, + dma_addr_t *bufferp, + u32 *nbytesp, + u32 *transfer_idp) +{ + struct ce_desc *base = src_ring->base_addr_owner_space; + struct ce_desc *desc = CE_SRC_RING_TO_DESC(base, sw_index); + + /* Return data from completed source descriptor */ + *bufferp = __le32_to_cpu(desc->addr); + *nbytesp = __le16_to_cpu(desc->nbytes); + *transfer_idp = MS(__le16_to_cpu(desc->flags), + CE_DESC_FLAGS_META_DATA); +} + +static void ath10k_ce_extract_desc_data_64(struct ath10k *ar, + struct ath10k_ce_ring *src_ring, + u32 sw_index, + dma_addr_t *bufferp, + u32 *nbytesp, + u32 *transfer_idp) +{ + struct ce_desc_64 *base = src_ring->base_addr_owner_space; + struct ce_desc_64 *desc = + CE_SRC_RING_TO_DESC_64(base, sw_index); + + /* Return data from completed source descriptor */ + *bufferp = __le64_to_cpu(desc->addr); + *nbytesp = __le16_to_cpu(desc->nbytes); + *transfer_idp = MS(__le16_to_cpu(desc->flags), + CE_DESC_FLAGS_META_DATA); +} + /* NB: Modeled after ath10k_ce_completed_send_next */ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state, void **per_transfer_contextp, @@ -730,14 +1002,9 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state, write_index = src_ring->write_index; if (write_index != sw_index) { - struct ce_desc *base = src_ring->base_addr_owner_space; - struct ce_desc *desc = CE_SRC_RING_TO_DESC(base, sw_index); - - /* Return data from completed source descriptor */ - *bufferp = __le32_to_cpu(desc->addr); - *nbytesp = __le16_to_cpu(desc->nbytes); - *transfer_idp = MS(__le16_to_cpu(desc->flags), - CE_DESC_FLAGS_META_DATA); + ce_state->ops->ce_extract_desc_data(ar, src_ring, sw_index, + bufferp, nbytesp, + transfer_idp); if (per_transfer_contextp) *per_transfer_contextp = @@ -899,8 +1166,12 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar, nentries = roundup_pow_of_two(attr->src_nentries); - memset(src_ring->base_addr_owner_space, 0, - nentries * sizeof(struct ce_desc)); + if (ar->hw_params.target_64bit) + memset(src_ring->base_addr_owner_space, 0, + nentries * sizeof(struct ce_desc_64)); + else + memset(src_ring->base_addr_owner_space, 0, + nentries * sizeof(struct ce_desc)); src_ring->sw_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); src_ring->sw_index &= src_ring->nentries_mask; @@ -936,8 +1207,12 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar, nentries = roundup_pow_of_two(attr->dest_nentries); - memset(dest_ring->base_addr_owner_space, 0, - nentries * sizeof(struct ce_desc)); + if (ar->hw_params.target_64bit) + memset(dest_ring->base_addr_owner_space, 0, + nentries * sizeof(struct ce_desc_64)); + else + memset(dest_ring->base_addr_owner_space, 0, + nentries * sizeof(struct ce_desc)); dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr); dest_ring->sw_index &= dest_ring->nentries_mask; @@ -995,12 +1270,57 @@ ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id, src_ring->base_addr_ce_space_unaligned = base_addr; - src_ring->base_addr_owner_space = PTR_ALIGN( - src_ring->base_addr_owner_space_unaligned, - CE_DESC_RING_ALIGN); - src_ring->base_addr_ce_space = ALIGN( - src_ring->base_addr_ce_space_unaligned, - CE_DESC_RING_ALIGN); + src_ring->base_addr_owner_space = + PTR_ALIGN(src_ring->base_addr_owner_space_unaligned, + CE_DESC_RING_ALIGN); + src_ring->base_addr_ce_space = + ALIGN(src_ring->base_addr_ce_space_unaligned, + CE_DESC_RING_ALIGN); + + return src_ring; +} + +static struct ath10k_ce_ring * +ath10k_ce_alloc_src_ring_64(struct ath10k *ar, unsigned int ce_id, + const struct ce_attr *attr) +{ + struct ath10k_ce_ring *src_ring; + u32 nentries = attr->src_nentries; + dma_addr_t base_addr; + + nentries = roundup_pow_of_two(nentries); + + src_ring = kzalloc(sizeof(*src_ring) + + (nentries * + sizeof(*src_ring->per_transfer_context)), + GFP_KERNEL); + if (!src_ring) + return ERR_PTR(-ENOMEM); + + src_ring->nentries = nentries; + src_ring->nentries_mask = nentries - 1; + + /* Legacy platforms that do not support cache + * coherent DMA are unsupported + */ + src_ring->base_addr_owner_space_unaligned = + dma_alloc_coherent(ar->dev, + (nentries * sizeof(struct ce_desc_64) + + CE_DESC_RING_ALIGN), + &base_addr, GFP_KERNEL); + if (!src_ring->base_addr_owner_space_unaligned) { + kfree(src_ring); + return ERR_PTR(-ENOMEM); + } + + src_ring->base_addr_ce_space_unaligned = base_addr; + + src_ring->base_addr_owner_space = + PTR_ALIGN(src_ring->base_addr_owner_space_unaligned, + CE_DESC_RING_ALIGN); + src_ring->base_addr_ce_space = + ALIGN(src_ring->base_addr_ce_space_unaligned, + CE_DESC_RING_ALIGN); return src_ring; } @@ -1041,12 +1361,63 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id, dest_ring->base_addr_ce_space_unaligned = base_addr; - dest_ring->base_addr_owner_space = PTR_ALIGN( - dest_ring->base_addr_owner_space_unaligned, - CE_DESC_RING_ALIGN); - dest_ring->base_addr_ce_space = ALIGN( - dest_ring->base_addr_ce_space_unaligned, - CE_DESC_RING_ALIGN); + dest_ring->base_addr_owner_space = + PTR_ALIGN(dest_ring->base_addr_owner_space_unaligned, + CE_DESC_RING_ALIGN); + dest_ring->base_addr_ce_space = + ALIGN(dest_ring->base_addr_ce_space_unaligned, + CE_DESC_RING_ALIGN); + + return dest_ring; +} + +static struct ath10k_ce_ring * +ath10k_ce_alloc_dest_ring_64(struct ath10k *ar, unsigned int ce_id, + const struct ce_attr *attr) +{ + struct ath10k_ce_ring *dest_ring; + u32 nentries; + dma_addr_t base_addr; + + nentries = roundup_pow_of_two(attr->dest_nentries); + + dest_ring = kzalloc(sizeof(*dest_ring) + + (nentries * + sizeof(*dest_ring->per_transfer_context)), + GFP_KERNEL); + if (!dest_ring) + return ERR_PTR(-ENOMEM); + + dest_ring->nentries = nentries; + dest_ring->nentries_mask = nentries - 1; + + /* Legacy platforms that do not support cache + * coherent DMA are unsupported + */ + dest_ring->base_addr_owner_space_unaligned = + dma_alloc_coherent(ar->dev, + (nentries * sizeof(struct ce_desc_64) + + CE_DESC_RING_ALIGN), + &base_addr, GFP_KERNEL); + if (!dest_ring->base_addr_owner_space_unaligned) { + kfree(dest_ring); + return ERR_PTR(-ENOMEM); + } + + dest_ring->base_addr_ce_space_unaligned = base_addr; + + /* Correctly initialize memory to 0 to prevent garbage + * data crashing system when download firmware + */ + memset(dest_ring->base_addr_owner_space_unaligned, 0, + nentries * sizeof(struct ce_desc_64) + CE_DESC_RING_ALIGN); + + dest_ring->base_addr_owner_space = + PTR_ALIGN(dest_ring->base_addr_owner_space_unaligned, + CE_DESC_RING_ALIGN); + dest_ring->base_addr_ce_space = + ALIGN(dest_ring->base_addr_ce_space_unaligned, + CE_DESC_RING_ALIGN); return dest_ring; } @@ -1109,65 +1480,36 @@ void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id) ath10k_ce_deinit_dest_ring(ar, ce_id); } -int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, - const struct ce_attr *attr) +static void _ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) { struct ath10k_ce *ce = ath10k_ce_priv(ar); struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; - int ret; - - /* - * Make sure there's enough CE ringbuffer entries for HTT TX to avoid - * additional TX locking checks. - * - * For the lack of a better place do the check here. - */ - BUILD_BUG_ON(2 * TARGET_NUM_MSDU_DESC > - (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); - BUILD_BUG_ON(2 * TARGET_10_4_NUM_MSDU_DESC_PFC > - (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); - BUILD_BUG_ON(2 * TARGET_TLV_NUM_MSDU_DESC > - (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); - ce_state->ar = ar; - ce_state->id = ce_id; - ce_state->ctrl_addr = ath10k_ce_base_address(ar, ce_id); - ce_state->attr_flags = attr->flags; - ce_state->src_sz_max = attr->src_sz_max; - - if (attr->src_nentries) - ce_state->send_cb = attr->send_cb; - - if (attr->dest_nentries) - ce_state->recv_cb = attr->recv_cb; - - if (attr->src_nentries) { - ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr); - if (IS_ERR(ce_state->src_ring)) { - ret = PTR_ERR(ce_state->src_ring); - ath10k_err(ar, "failed to allocate copy engine source ring %d: %d\n", - ce_id, ret); - ce_state->src_ring = NULL; - return ret; - } + if (ce_state->src_ring) { + dma_free_coherent(ar->dev, + (ce_state->src_ring->nentries * + sizeof(struct ce_desc) + + CE_DESC_RING_ALIGN), + ce_state->src_ring->base_addr_owner_space, + ce_state->src_ring->base_addr_ce_space); + kfree(ce_state->src_ring); } - if (attr->dest_nentries) { - ce_state->dest_ring = ath10k_ce_alloc_dest_ring(ar, ce_id, - attr); - if (IS_ERR(ce_state->dest_ring)) { - ret = PTR_ERR(ce_state->dest_ring); - ath10k_err(ar, "failed to allocate copy engine destination ring %d: %d\n", - ce_id, ret); - ce_state->dest_ring = NULL; - return ret; - } + if (ce_state->dest_ring) { + dma_free_coherent(ar->dev, + (ce_state->dest_ring->nentries * + sizeof(struct ce_desc) + + CE_DESC_RING_ALIGN), + ce_state->dest_ring->base_addr_owner_space, + ce_state->dest_ring->base_addr_ce_space); + kfree(ce_state->dest_ring); } - return 0; + ce_state->src_ring = NULL; + ce_state->dest_ring = NULL; } -void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) +static void _ath10k_ce_free_pipe_64(struct ath10k *ar, int ce_id) { struct ath10k_ce *ce = ath10k_ce_priv(ar); struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; @@ -1175,7 +1517,7 @@ void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) if (ce_state->src_ring) { dma_free_coherent(ar->dev, (ce_state->src_ring->nentries * - sizeof(struct ce_desc) + + sizeof(struct ce_desc_64) + CE_DESC_RING_ALIGN), ce_state->src_ring->base_addr_owner_space, ce_state->src_ring->base_addr_ce_space); @@ -1185,7 +1527,7 @@ void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) if (ce_state->dest_ring) { dma_free_coherent(ar->dev, (ce_state->dest_ring->nentries * - sizeof(struct ce_desc) + + sizeof(struct ce_desc_64) + CE_DESC_RING_ALIGN), ce_state->dest_ring->base_addr_owner_space, ce_state->dest_ring->base_addr_ce_space); @@ -1196,6 +1538,14 @@ void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) ce_state->dest_ring = NULL; } +void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) +{ + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; + + ce_state->ops->ce_free_pipe(ar, ce_id); +} + void ath10k_ce_dump_registers(struct ath10k *ar, struct ath10k_fw_crash_data *crash_data) { @@ -1234,3 +1584,99 @@ void ath10k_ce_dump_registers(struct ath10k *ar, spin_unlock_bh(&ce->ce_lock); } + +static const struct ath10k_ce_ops ce_ops = { + .ce_alloc_src_ring = ath10k_ce_alloc_src_ring, + .ce_alloc_dst_ring = ath10k_ce_alloc_dest_ring, + .ce_rx_post_buf = __ath10k_ce_rx_post_buf, + .ce_completed_recv_next_nolock = _ath10k_ce_completed_recv_next_nolock, + .ce_revoke_recv_next = _ath10k_ce_revoke_recv_next, + .ce_extract_desc_data = ath10k_ce_extract_desc_data, + .ce_free_pipe = _ath10k_ce_free_pipe, + .ce_send_nolock = _ath10k_ce_send_nolock, +}; + +static const struct ath10k_ce_ops ce_64_ops = { + .ce_alloc_src_ring = ath10k_ce_alloc_src_ring_64, + .ce_alloc_dst_ring = ath10k_ce_alloc_dest_ring_64, + .ce_rx_post_buf = __ath10k_ce_rx_post_buf_64, + .ce_completed_recv_next_nolock = + _ath10k_ce_completed_recv_next_nolock_64, + .ce_revoke_recv_next = _ath10k_ce_revoke_recv_next_64, + .ce_extract_desc_data = ath10k_ce_extract_desc_data_64, + .ce_free_pipe = _ath10k_ce_free_pipe_64, + .ce_send_nolock = _ath10k_ce_send_nolock_64, +}; + +static void ath10k_ce_set_ops(struct ath10k *ar, + struct ath10k_ce_pipe *ce_state) +{ + switch (ar->hw_rev) { + case ATH10K_HW_WCN3990: + ce_state->ops = &ce_64_ops; + break; + default: + ce_state->ops = &ce_ops; + break; + } +} + +int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, + const struct ce_attr *attr) +{ + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; + int ret; + + ath10k_ce_set_ops(ar, ce_state); + /* Make sure there's enough CE ringbuffer entries for HTT TX to avoid + * additional TX locking checks. + * + * For the lack of a better place do the check here. + */ + BUILD_BUG_ON(2 * TARGET_NUM_MSDU_DESC > + (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); + BUILD_BUG_ON(2 * TARGET_10_4_NUM_MSDU_DESC_PFC > + (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); + BUILD_BUG_ON(2 * TARGET_TLV_NUM_MSDU_DESC > + (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); + + ce_state->ar = ar; + ce_state->id = ce_id; + ce_state->ctrl_addr = ath10k_ce_base_address(ar, ce_id); + ce_state->attr_flags = attr->flags; + ce_state->src_sz_max = attr->src_sz_max; + + if (attr->src_nentries) + ce_state->send_cb = attr->send_cb; + + if (attr->dest_nentries) + ce_state->recv_cb = attr->recv_cb; + + if (attr->src_nentries) { + ce_state->src_ring = + ce_state->ops->ce_alloc_src_ring(ar, ce_id, attr); + if (IS_ERR(ce_state->src_ring)) { + ret = PTR_ERR(ce_state->src_ring); + ath10k_err(ar, "failed to alloc CE src ring %d: %d\n", + ce_id, ret); + ce_state->src_ring = NULL; + return ret; + } + } + + if (attr->dest_nentries) { + ce_state->dest_ring = ce_state->ops->ce_alloc_dst_ring(ar, + ce_id, + attr); + if (IS_ERR(ce_state->dest_ring)) { + ret = PTR_ERR(ce_state->dest_ring); + ath10k_err(ar, "failed to alloc CE dest ring %d: %d\n", + ce_id, ret); + ce_state->dest_ring = NULL; + return ret; + } + } + + return 0; +} diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index f36ad51e2b52..be1d218c6540 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -36,6 +36,10 @@ struct ath10k_ce_pipe; #define CE_DESC_FLAGS_GATHER (1 << 0) #define CE_DESC_FLAGS_BYTE_SWAP (1 << 1) +#define CE_WCN3990_DESC_FLAGS_GATHER BIT(31) + +#define CE_DESC_FLAGS_GET_MASK GENMASK(4, 0) +#define CE_DESC_37BIT_ADDR_MASK GENMASK_ULL(37, 0) /* Following desc flags are used in QCA99X0 */ #define CE_DESC_FLAGS_HOST_INT_DIS (1 << 2) @@ -50,6 +54,16 @@ struct ce_desc { __le16 flags; /* %CE_DESC_FLAGS_ */ }; +struct ce_desc_64 { + __le64 addr; + __le16 nbytes; /* length in register map */ + __le16 flags; /* fw_metadata_high */ + __le32 toeplitz_hash_result; +}; + +#define CE_DESC_SIZE sizeof(struct ce_desc) +#define CE_DESC_SIZE_64 sizeof(struct ce_desc_64) + struct ath10k_ce_ring { /* Number of entries in this ring; must be power of 2 */ unsigned int nentries; @@ -117,6 +131,7 @@ struct ath10k_ce_pipe { unsigned int src_sz_max; struct ath10k_ce_ring *src_ring; struct ath10k_ce_ring *dest_ring; + const struct ath10k_ce_ops *ops; }; /* Copy Engine settable attributes */ @@ -180,8 +195,6 @@ int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe); /*==================Recv=======================*/ int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe); -int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, - dma_addr_t paddr); int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, dma_addr_t paddr); void ath10k_ce_rx_update_write_idx(struct ath10k_ce_pipe *pipe, u32 nentries); @@ -283,6 +296,31 @@ struct ce_attr { void (*recv_cb)(struct ath10k_ce_pipe *); }; +struct ath10k_ce_ops { + struct ath10k_ce_ring *(*ce_alloc_src_ring)(struct ath10k *ar, + u32 ce_id, + const struct ce_attr *attr); + struct ath10k_ce_ring *(*ce_alloc_dst_ring)(struct ath10k *ar, + u32 ce_id, + const struct ce_attr *attr); + int (*ce_rx_post_buf)(struct ath10k_ce_pipe *pipe, void *ctx, + dma_addr_t paddr); + int (*ce_completed_recv_next_nolock)(struct ath10k_ce_pipe *ce_state, + void **per_transfer_contextp, + u32 *nbytesp); + int (*ce_revoke_recv_next)(struct ath10k_ce_pipe *ce_state, + void **per_transfer_contextp, + dma_addr_t *nbytesp); + void (*ce_extract_desc_data)(struct ath10k *ar, + struct ath10k_ce_ring *src_ring, + u32 sw_index, dma_addr_t *bufferp, + u32 *nbytesp, u32 *transfer_idp); + void (*ce_free_pipe)(struct ath10k *ar, int ce_id); + int (*ce_send_nolock)(struct ath10k_ce_pipe *pipe, + void *per_transfer_context, + dma_addr_t buffer, u32 nbytes, + u32 transfer_id, u32 flags); +}; static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) { return CE0_BASE_ADDRESS + (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS) * ce_id; @@ -294,6 +332,12 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) #define CE_DEST_RING_TO_DESC(baddr, idx) \ (&(((struct ce_desc *)baddr)[idx])) +#define CE_SRC_RING_TO_DESC_64(baddr, idx) \ + (&(((struct ce_desc_64 *)baddr)[idx])) + +#define CE_DEST_RING_TO_DESC_64(baddr, idx) \ + (&(((struct ce_desc_64 *)baddr)[idx])) + /* Ring arithmetic (modulus number of entries in ring, which is a pwr of 2). */ #define CE_RING_DELTA(nentries_mask, fromidx, toidx) \ (((int)(toidx) - (int)(fromidx)) & (nentries_mask)) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index de289681686b..9809eba10fc2 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -785,7 +785,7 @@ static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe) ATH10K_SKB_RXCB(skb)->paddr = paddr; spin_lock_bh(&ce->ce_lock); - ret = __ath10k_ce_rx_post_buf(ce_pipe, skb, paddr); + ret = ce_pipe->ops->ce_rx_post_buf(ce_pipe, skb, paddr); spin_unlock_bh(&ce->ce_lock); if (ret) { dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb), @@ -922,7 +922,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, nbytes = min_t(unsigned int, remaining_bytes, DIAG_TRANSFER_LIMIT); - ret = __ath10k_ce_rx_post_buf(ce_diag, &ce_data, ce_data); + ret = ce_diag->ops->ce_rx_post_buf(ce_diag, &ce_data, ce_data); if (ret != 0) goto done; @@ -1088,7 +1088,7 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, nbytes = min_t(int, remaining_bytes, DIAG_TRANSFER_LIMIT); /* Set up to receive directly into Target(!) address */ - ret = __ath10k_ce_rx_post_buf(ce_diag, &address, address); + ret = ce_diag->ops->ce_rx_post_buf(ce_diag, &address, address); if (ret != 0) goto done; From 2b403853b124526c168016d5a879c2f7ce4fc662 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 21 Dec 2017 21:35:20 +0530 Subject: [PATCH 013/192] UPSTREAM: ath10k: Add SNOC bus type for WCN3990 target WCN3990 is integrated chipset which uses system NOC. Add SNOC bus type and related definitions. Signed-off-by: Govind Singh Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo Git-commit: 63855e3d6e7a4c3f210526e2788c043d32832168 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I2845deaba952ba6979534ab767778d028cb6fcb2 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/core.c | 1 + drivers/net/wireless/ath/ath10k/core.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index c96b23923d83..3c530d9ae9c7 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1577,6 +1577,7 @@ static void ath10k_core_get_fw_name(struct ath10k *ar, char *fw_name, break; case ATH10K_BUS_PCI: case ATH10K_BUS_AHB: + case ATH10K_BUS_SNOC: scnprintf(fw_name, fw_name_len, "%s-%d.bin", ATH10K_FW_FILE_BASE, fw_api); break; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 631df2137e25..86d8f44237a6 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -92,6 +92,7 @@ enum ath10k_bus { ATH10K_BUS_AHB, ATH10K_BUS_SDIO, ATH10K_BUS_USB, + ATH10K_BUS_SNOC, }; static inline const char *ath10k_bus_str(enum ath10k_bus bus) @@ -105,6 +106,8 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus) return "sdio"; case ATH10K_BUS_USB: return "usb"; + case ATH10K_BUS_SNOC: + return "snoc"; } return "unknown"; From 6b28b234da1e9e135a4e138699bc04313ae3f7c8 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 21 Dec 2017 21:35:21 +0530 Subject: [PATCH 014/192] UPSTREAM: ath10k: Add debug mask for SNOC bus type WCN3990 target uses SNOC bus. Add debug mask for SNOC bus type. Signed-off-by: Govind Singh Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo Git-commit: b796240409b3f576ae8ebbad9b5679ff2fb5a39c Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: Ifa65586f20eaddcf98e7b0f81c30f5a9088a6823 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/debug.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 5e662994c49a..134fb68ae546 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -42,6 +42,7 @@ enum ath10k_debug_mask { ATH10K_DBG_SDIO_DUMP = 0x00020000, ATH10K_DBG_USB = 0x00040000, ATH10K_DBG_USB_BULK = 0x00080000, + ATH10K_DBG_SNOC = 0x00100000, ATH10K_DBG_ANY = 0xffffffff, }; From 669593e5106a16ff847e585cfc57bf585ba4426c Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Thu, 21 Dec 2017 21:46:49 +0530 Subject: [PATCH 015/192] UPSTREAM: ath10k: Add fw feature flag for non-bmi firmware load HL1.0 firmware is not loaded via bmi. The bmi specific code should not be executed for HL1.0 Add fw feature flag for non bmi targets and skip the bmi specific code for non bmi targets. Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo Git-commit: 71e9c29fbd28ec14bb8f920c7afd515a75c00234 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: Ibd6892feb0d12c04badd6d19e8bc51017f9537c6 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/core.c | 180 ++++++++++++++----------- drivers/net/wireless/ath/ath10k/core.h | 3 + 2 files changed, 108 insertions(+), 75 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 3c530d9ae9c7..e5e78a4cacde 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -471,6 +471,7 @@ static const char *const ath10k_core_fw_feature_str[] = { [ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST] = "allows-mesh-bcast", [ATH10K_FW_FEATURE_NO_PS] = "no-ps", [ATH10K_FW_FEATURE_MGMT_TX_BY_REF] = "mgmt-tx-by-reference", + [ATH10K_FW_FEATURE_NON_BMI] = "non-bmi", }; static unsigned int ath10k_core_get_fw_feature_str(char *buf, @@ -1550,8 +1551,8 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name, data += ie_len; } - if (!fw_file->firmware_data || - !fw_file->firmware_len) { + if (!test_bit(ATH10K_FW_FEATURE_NON_BMI, fw_file->fw_features) && + (!fw_file->firmware_data || !fw_file->firmware_len)) { ath10k_warn(ar, "No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n", ar->hw_params.fw.dir, name); ret = -ENOMEDIUM; @@ -2105,43 +2106,47 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, ar->running_fw = fw; - ath10k_bmi_start(ar); + if (!test_bit(ATH10K_FW_FEATURE_NON_BMI, + ar->running_fw->fw_file.fw_features)) { + ath10k_bmi_start(ar); - if (ath10k_init_configure_target(ar)) { - status = -EINVAL; - goto err; - } - - status = ath10k_download_cal_data(ar); - if (status) - goto err; + if (ath10k_init_configure_target(ar)) { + status = -EINVAL; + goto err; + } - /* Some of of qca988x solutions are having global reset issue - * during target initialization. Bypassing PLL setting before - * downloading firmware and letting the SoC run on REF_CLK is - * fixing the problem. Corresponding firmware change is also needed - * to set the clock source once the target is initialized. - */ - if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT, - ar->running_fw->fw_file.fw_features)) { - status = ath10k_bmi_write32(ar, hi_skip_clock_init, 1); - if (status) { - ath10k_err(ar, "could not write to skip_clock_init: %d\n", - status); + status = ath10k_download_cal_data(ar); + if (status) goto err; + + /* Some of of qca988x solutions are having global reset issue + * during target initialization. Bypassing PLL setting before + * downloading firmware and letting the SoC run on REF_CLK is + * fixing the problem. Corresponding firmware change is also + * needed to set the clock source once the target is + * initialized. + */ + if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT, + ar->running_fw->fw_file.fw_features)) { + status = ath10k_bmi_write32(ar, hi_skip_clock_init, 1); + if (status) { + ath10k_err(ar, "could not write to skip_clock_init: %d\n", + status); + goto err; + } } - } - status = ath10k_download_fw(ar); - if (status) - goto err; + status = ath10k_download_fw(ar); + if (status) + goto err; - status = ath10k_init_uart(ar); - if (status) - goto err; + status = ath10k_init_uart(ar); + if (status) + goto err; - if (ar->hif.bus == ATH10K_BUS_SDIO) - ath10k_init_sdio(ar); + if (ar->hif.bus == ATH10K_BUS_SDIO) + ath10k_init_sdio(ar); + } ar->htc.htc_ops.target_send_suspend_complete = ath10k_send_suspend_complete; @@ -2152,9 +2157,12 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, goto err; } - status = ath10k_bmi_done(ar); - if (status) - goto err; + if (!test_bit(ATH10K_FW_FEATURE_NON_BMI, + ar->running_fw->fw_file.fw_features)) { + status = ath10k_bmi_done(ar); + if (status) + goto err; + } status = ath10k_wmi_attach(ar); if (status) { @@ -2397,19 +2405,34 @@ static int ath10k_core_probe_fw(struct ath10k *ar) return ret; } - memset(&target_info, 0, sizeof(target_info)); - if (ar->hif.bus == ATH10K_BUS_SDIO) + switch (ar->hif.bus) { + case ATH10K_BUS_SDIO: + memset(&target_info, 0, sizeof(target_info)); ret = ath10k_bmi_get_target_info_sdio(ar, &target_info); - else + if (ret) { + ath10k_err(ar, "could not get target info (%d)\n", ret); + goto err_power_down; + } + ar->target_version = target_info.version; + ar->hw->wiphy->hw_version = target_info.version; + break; + case ATH10K_BUS_PCI: + case ATH10K_BUS_AHB: + memset(&target_info, 0, sizeof(target_info)); ret = ath10k_bmi_get_target_info(ar, &target_info); - if (ret) { - ath10k_err(ar, "could not get target info (%d)\n", ret); - goto err_power_down; + if (ret) { + ath10k_err(ar, "could not get target info (%d)\n", ret); + goto err_power_down; + } + ar->target_version = target_info.version; + ar->hw->wiphy->hw_version = target_info.version; + break; + case ATH10K_BUS_SNOC: + break; + default: + ath10k_err(ar, "incorrect hif bus type: %d\n", ar->hif.bus); } - ar->target_version = target_info.version; - ar->hw->wiphy->hw_version = target_info.version; - ret = ath10k_init_hw_params(ar); if (ret) { ath10k_err(ar, "could not get hw params (%d)\n", ret); @@ -2429,37 +2452,40 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ath10k_debug_print_hwfw_info(ar); - ret = ath10k_core_pre_cal_download(ar); - if (ret) { - /* pre calibration data download is not necessary - * for all the chipsets. Ignore failures and continue. - */ - ath10k_dbg(ar, ATH10K_DBG_BOOT, - "could not load pre cal data: %d\n", ret); - } + if (!test_bit(ATH10K_FW_FEATURE_NON_BMI, + ar->normal_mode_fw.fw_file.fw_features)) { + ret = ath10k_core_pre_cal_download(ar); + if (ret) { + /* pre calibration data download is not necessary + * for all the chipsets. Ignore failures and continue. + */ + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "could not load pre cal data: %d\n", ret); + } - ret = ath10k_core_get_board_id_from_otp(ar); - if (ret && ret != -EOPNOTSUPP) { - ath10k_err(ar, "failed to get board id from otp: %d\n", - ret); - goto err_free_firmware_files; - } + ret = ath10k_core_get_board_id_from_otp(ar); + if (ret && ret != -EOPNOTSUPP) { + ath10k_err(ar, "failed to get board id from otp: %d\n", + ret); + goto err_free_firmware_files; + } - ret = ath10k_core_check_smbios(ar); - if (ret) - ath10k_dbg(ar, ATH10K_DBG_BOOT, "SMBIOS bdf variant name not set.\n"); + ret = ath10k_core_check_smbios(ar); + if (ret) + ath10k_dbg(ar, ATH10K_DBG_BOOT, "SMBIOS bdf variant name not set.\n"); - ret = ath10k_core_check_dt(ar); - if (ret) - ath10k_dbg(ar, ATH10K_DBG_BOOT, "DT bdf variant name not set.\n"); + ret = ath10k_core_check_dt(ar); + if (ret) + ath10k_dbg(ar, ATH10K_DBG_BOOT, "DT bdf variant name not set.\n"); - ret = ath10k_core_fetch_board_file(ar); - if (ret) { - ath10k_err(ar, "failed to fetch board file: %d\n", ret); - goto err_free_firmware_files; - } + ret = ath10k_core_fetch_board_file(ar); + if (ret) { + ath10k_err(ar, "failed to fetch board file: %d\n", ret); + goto err_free_firmware_files; + } - ath10k_debug_print_board_info(ar); + ath10k_debug_print_board_info(ar); + } ret = ath10k_core_init_firmware_features(ar); if (ret) { @@ -2468,11 +2494,15 @@ static int ath10k_core_probe_fw(struct ath10k *ar) goto err_free_firmware_files; } - ret = ath10k_swap_code_seg_init(ar, &ar->normal_mode_fw.fw_file); - if (ret) { - ath10k_err(ar, "failed to initialize code swap segment: %d\n", - ret); - goto err_free_firmware_files; + if (!test_bit(ATH10K_FW_FEATURE_NON_BMI, + ar->normal_mode_fw.fw_file.fw_features)) { + ret = ath10k_swap_code_seg_init(ar, + &ar->normal_mode_fw.fw_file); + if (ret) { + ath10k_err(ar, "failed to initialize code swap segment: %d\n", + ret); + goto err_free_firmware_files; + } } mutex_lock(&ar->conf_mutex); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 86d8f44237a6..6ed40f341461 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -619,6 +619,9 @@ enum ath10k_fw_features { /* Firmware allows management tx by reference instead of by value. */ ATH10K_FW_FEATURE_MGMT_TX_BY_REF = 18, + /* Firmware load is done externally, not by bmi */ + ATH10K_FW_FEATURE_NON_BMI = 19, + /* keep last */ ATH10K_FW_FEATURE_COUNT, }; From 690a9509e4e286fd40f754f0a97336904425fcae Mon Sep 17 00:00:00 2001 From: Balaji Pothunoori Date: Thu, 21 Dec 2017 20:00:42 +0530 Subject: [PATCH 016/192] UPSTREAM: ath10k: advertise TDLS wider bandwidth support for 5GHz Enable TDLS wider bandwidth support for 5GHz based on firmware wmi capabilities. This patch is required for chipset QCA9888. Tested with firmware version 10.4-3.5.1-00018. Signed-off-by: Balaji Pothunoori Signed-off-by: Kalle Valo Git-commit: 14d65775687cb3a6f76a52f48f4be27a522bb396 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I907d25323cf1b87fd0726ceec39c6cec20ed2b49 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/mac.c | 3 ++- drivers/net/wireless/ath/ath10k/wmi.h | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 8b62e85ad3ab..2ba5d058de7c 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -8315,7 +8315,8 @@ int ath10k_mac_register(struct ath10k *ar) if (test_bit(WMI_SERVICE_TDLS, ar->wmi.svc_map) || test_bit(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, ar->wmi.svc_map)) { ar->hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; - ieee80211_hw_set(ar->hw, TDLS_WIDER_BW); + if (test_bit(WMI_SERVICE_TDLS_WIDER_BANDWIDTH, ar->wmi.svc_map)) + ieee80211_hw_set(ar->hw, TDLS_WIDER_BW); } ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 1905a83c9a7c..2718bbc5cef7 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -196,6 +196,7 @@ enum wmi_service { WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE, WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, WMI_SERVICE_MGMT_TX_WMI, + WMI_SERVICE_TDLS_WIDER_BANDWIDTH, /* keep last */ WMI_SERVICE_MAX, @@ -337,6 +338,7 @@ enum wmi_10_4_service { WMI_10_4_SERVICE_TDLS_UAPSD_SLEEP_STA, WMI_10_4_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE, WMI_10_4_SERVICE_TDLS_EXPLICIT_MODE_ONLY, + WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH, }; static inline char *wmi_service_name(int service_id) @@ -445,6 +447,7 @@ static inline char *wmi_service_name(int service_id) SVCSTR(WMI_SERVICE_SMART_LOGGING_SUPPORT); SVCSTR(WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE); SVCSTR(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY); + SVCSTR(WMI_SERVICE_TDLS_WIDER_BANDWIDTH); default: return NULL; } @@ -741,6 +744,8 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out, WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE, len); SVCMAP(WMI_10_4_SERVICE_TDLS_EXPLICIT_MODE_ONLY, WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, len); + SVCMAP(WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH, + WMI_SERVICE_TDLS_WIDER_BANDWIDTH, len); } #undef SVCMAP From 5695552c13af342bb685a4f5f765f87f4c9dba61 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 22 Dec 2017 15:38:29 +0200 Subject: [PATCH 017/192] UPSTREAM: ath10k: remove deprecated fw_crash_dump debugfs file The fw_crash_dump file was deprecated by commmit 727000e6af34 ("ath10k: support dev_coredump for crash dump") in v4.11 in favor of dev_coredump interface, remove it now for good. Everyone should use dev_coredump now. Signed-off-by: Kalle Valo Git-commit: d333bdd9b0653b525494cd7f9f9d3b9350e4bbd3 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: Ide8573611573dcce1d47f1c2c21f6de13ef790b0 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/debug.c | 46 ------------------------- 1 file changed, 46 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index a6184582a933..fbd9ea4042b6 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -859,49 +859,6 @@ int ath10k_debug_fw_devcoredump(struct ath10k *ar) return 0; } -static int ath10k_fw_crash_dump_open(struct inode *inode, struct file *file) -{ - struct ath10k *ar = inode->i_private; - struct ath10k_dump_file_data *dump; - - ath10k_warn(ar, "fw_crash_dump debugfs file is deprecated, please use /sys/class/devcoredump instead."); - - dump = ath10k_build_dump_file(ar, true); - if (!dump) - return -ENODATA; - - file->private_data = dump; - - return 0; -} - -static ssize_t ath10k_fw_crash_dump_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath10k_dump_file_data *dump_file = file->private_data; - - return simple_read_from_buffer(user_buf, count, ppos, - dump_file, - le32_to_cpu(dump_file->len)); -} - -static int ath10k_fw_crash_dump_release(struct inode *inode, - struct file *file) -{ - vfree(file->private_data); - - return 0; -} - -static const struct file_operations fops_fw_crash_dump = { - .open = ath10k_fw_crash_dump_open, - .read = ath10k_fw_crash_dump_read, - .release = ath10k_fw_crash_dump_release, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - static ssize_t ath10k_reg_addr_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -2468,9 +2425,6 @@ int ath10k_debug_register(struct ath10k *ar) debugfs_create_file("simulate_fw_crash", 0600, ar->debug.debugfs_phy, ar, &fops_simulate_fw_crash); - debugfs_create_file("fw_crash_dump", 0400, ar->debug.debugfs_phy, ar, - &fops_fw_crash_dump); - debugfs_create_file("reg_addr", 0600, ar->debug.debugfs_phy, ar, &fops_reg_addr); From 35c6422da11949ab3f0250c9117da5aee2e28d8a Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 22 Dec 2017 15:38:43 +0200 Subject: [PATCH 018/192] UPSTREAM: ath10k: refactor firmware crashdump code to coredump.c In preparation to add RAM dump support. No functional changes, only moving code and renaming function names. Signed-off-by: Kalle Valo Git-commit: f25b9f285a0eff7ae5d987acfb1d2407769b67af Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: Ia4dee32d535cd6b08e1b28ab93f0ef9c81442bf9 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/Makefile | 1 + drivers/net/wireless/ath/ath10k/core.c | 3 +- drivers/net/wireless/ath/ath10k/coredump.c | 165 +++++++++++++++ drivers/net/wireless/ath/ath10k/coredump.h | 121 +++++++++++ drivers/net/wireless/ath/ath10k/debug.c | 222 --------------------- drivers/net/wireless/ath/ath10k/debug.h | 16 -- drivers/net/wireless/ath/ath10k/pci.c | 3 +- 7 files changed, 291 insertions(+), 240 deletions(-) create mode 100644 drivers/net/wireless/ath/ath10k/coredump.c create mode 100644 drivers/net/wireless/ath/ath10k/coredump.h diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 8d9a59b7144e..4e6a396827ee 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -21,6 +21,7 @@ ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o ath10k_core-$(CONFIG_THERMAL) += thermal.o ath10k_core-$(CONFIG_MAC80211_DEBUGFS) += debugfs_sta.o ath10k_core-$(CONFIG_PM) += wow.o +ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += coredump.o obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o ath10k_pci-y += pci.o \ diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index e5e78a4cacde..fe47516999f6 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -32,6 +32,7 @@ #include "htt.h" #include "testmode.h" #include "wmi-ops.h" +#include "coredump.h" unsigned int ath10k_debug_mask; static unsigned int ath10k_cryptmode_param; @@ -1864,7 +1865,7 @@ static void ath10k_core_restart(struct work_struct *work) mutex_unlock(&ar->conf_mutex); - ret = ath10k_debug_fw_devcoredump(ar); + ret = ath10k_coredump_submit(ar); if (ret) ath10k_warn(ar, "failed to send firmware crash dump via devcoredump: %d", ret); diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c new file mode 100644 index 000000000000..51b86878e733 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "coredump.h" + +#include +#include + +#include "debug.h" + +#ifdef CONFIG_DEV_COREDUMP + +struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar) +{ + struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data; + + lockdep_assert_held(&ar->data_lock); + + crash_data->crashed_since_read = true; + guid_gen(&crash_data->guid); + ktime_get_real_ts64(&crash_data->timestamp); + + return crash_data; +} +EXPORT_SYMBOL(ath10k_coredump_new); + +static struct ath10k_dump_file_data *ath10k_coredump_build(struct ath10k *ar, + bool mark_read) +{ + struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data; + struct ath10k_ce_crash_hdr *ce_hdr; + struct ath10k_dump_file_data *dump_data; + struct ath10k_tlv_dump_data *dump_tlv; + size_t hdr_len = sizeof(*dump_data); + size_t len, sofar = 0; + unsigned char *buf; + + len = hdr_len; + len += sizeof(*dump_tlv) + sizeof(crash_data->registers); + len += sizeof(*dump_tlv) + sizeof(*ce_hdr) + + CE_COUNT * sizeof(ce_hdr->entries[0]); + + sofar += hdr_len; + + /* This is going to get big when we start dumping FW RAM and such, + * so go ahead and use vmalloc. + */ + buf = vzalloc(len); + if (!buf) + return NULL; + + spin_lock_bh(&ar->data_lock); + + if (!crash_data->crashed_since_read) { + spin_unlock_bh(&ar->data_lock); + vfree(buf); + return NULL; + } + + dump_data = (struct ath10k_dump_file_data *)(buf); + strlcpy(dump_data->df_magic, "ATH10K-FW-DUMP", + sizeof(dump_data->df_magic)); + dump_data->len = cpu_to_le32(len); + + dump_data->version = cpu_to_le32(ATH10K_FW_CRASH_DUMP_VERSION); + + guid_copy(&dump_data->guid, &crash_data->guid); + dump_data->chip_id = cpu_to_le32(ar->chip_id); + dump_data->bus_type = cpu_to_le32(0); + dump_data->target_version = cpu_to_le32(ar->target_version); + dump_data->fw_version_major = cpu_to_le32(ar->fw_version_major); + dump_data->fw_version_minor = cpu_to_le32(ar->fw_version_minor); + dump_data->fw_version_release = cpu_to_le32(ar->fw_version_release); + dump_data->fw_version_build = cpu_to_le32(ar->fw_version_build); + dump_data->phy_capability = cpu_to_le32(ar->phy_capability); + dump_data->hw_min_tx_power = cpu_to_le32(ar->hw_min_tx_power); + dump_data->hw_max_tx_power = cpu_to_le32(ar->hw_max_tx_power); + dump_data->ht_cap_info = cpu_to_le32(ar->ht_cap_info); + dump_data->vht_cap_info = cpu_to_le32(ar->vht_cap_info); + dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains); + + strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version, + sizeof(dump_data->fw_ver)); + + dump_data->kernel_ver_code = 0; + strlcpy(dump_data->kernel_ver, init_utsname()->release, + sizeof(dump_data->kernel_ver)); + + dump_data->tv_sec = cpu_to_le64(crash_data->timestamp.tv_sec); + dump_data->tv_nsec = cpu_to_le64(crash_data->timestamp.tv_nsec); + + /* Gather crash-dump */ + dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar); + dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_REGISTERS); + dump_tlv->tlv_len = cpu_to_le32(sizeof(crash_data->registers)); + memcpy(dump_tlv->tlv_data, &crash_data->registers, + sizeof(crash_data->registers)); + sofar += sizeof(*dump_tlv) + sizeof(crash_data->registers); + + dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar); + dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_CE_DATA); + dump_tlv->tlv_len = cpu_to_le32(sizeof(*ce_hdr) + + CE_COUNT * sizeof(ce_hdr->entries[0])); + ce_hdr = (struct ath10k_ce_crash_hdr *)(dump_tlv->tlv_data); + ce_hdr->ce_count = cpu_to_le32(CE_COUNT); + memset(ce_hdr->reserved, 0, sizeof(ce_hdr->reserved)); + memcpy(ce_hdr->entries, crash_data->ce_crash_data, + CE_COUNT * sizeof(ce_hdr->entries[0])); + sofar += sizeof(*dump_tlv) + sizeof(*ce_hdr) + + CE_COUNT * sizeof(ce_hdr->entries[0]); + + ar->debug.fw_crash_data->crashed_since_read = !mark_read; + + spin_unlock_bh(&ar->data_lock); + + return dump_data; +} + +int ath10k_coredump_submit(struct ath10k *ar) +{ + struct ath10k_dump_file_data *dump; + void *dump_ptr; + u32 dump_len; + + /* To keep the dump file available also for debugfs don't mark the + * file read, only debugfs should do that. + */ + dump = ath10k_coredump_build(ar, false); + if (!dump) { + ath10k_warn(ar, "no crash dump data found for devcoredump"); + return -ENODATA; + } + + /* Make a copy of the dump file for dev_coredumpv() as during the + * transition period we need to own the original file. Once + * fw_crash_dump debugfs file is removed no need to have a copy + * anymore. + */ + dump_len = le32_to_cpu(dump->len); + dump_ptr = vzalloc(dump_len); + + if (!dump_ptr) + return -ENOMEM; + + memcpy(dump_ptr, dump, dump_len); + + dev_coredumpv(ar->dev, dump_ptr, dump_len, GFP_KERNEL); + + return 0; +} + +#endif /* CONFIG_DEV_COREDUMP */ diff --git a/drivers/net/wireless/ath/ath10k/coredump.h b/drivers/net/wireless/ath/ath10k/coredump.h new file mode 100644 index 000000000000..2d2f45b5aa37 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/coredump.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _COREDUMP_H_ +#define _COREDUMP_H_ + +#include "core.h" + +#define ATH10K_FW_CRASH_DUMP_VERSION 1 + +/** + * enum ath10k_fw_crash_dump_type - types of data in the dump file + * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format + */ +enum ath10k_fw_crash_dump_type { + ATH10K_FW_CRASH_DUMP_REGISTERS = 0, + ATH10K_FW_CRASH_DUMP_CE_DATA = 1, + + ATH10K_FW_CRASH_DUMP_MAX, +}; + +struct ath10k_tlv_dump_data { + /* see ath10k_fw_crash_dump_type above */ + __le32 type; + + /* in bytes */ + __le32 tlv_len; + + /* pad to 32-bit boundaries as needed */ + u8 tlv_data[]; +} __packed; + +struct ath10k_dump_file_data { + /* dump file information */ + + /* "ATH10K-FW-DUMP" */ + char df_magic[16]; + + __le32 len; + + /* file dump version */ + __le32 version; + + /* some info we can get from ath10k struct that might help */ + + guid_t guid; + + __le32 chip_id; + + /* 0 for now, in place for later hardware */ + __le32 bus_type; + + __le32 target_version; + __le32 fw_version_major; + __le32 fw_version_minor; + __le32 fw_version_release; + __le32 fw_version_build; + __le32 phy_capability; + __le32 hw_min_tx_power; + __le32 hw_max_tx_power; + __le32 ht_cap_info; + __le32 vht_cap_info; + __le32 num_rf_chains; + + /* firmware version string */ + char fw_ver[ETHTOOL_FWVERS_LEN]; + + /* Kernel related information */ + + /* time-of-day stamp */ + __le64 tv_sec; + + /* time-of-day stamp, nano-seconds */ + __le64 tv_nsec; + + /* LINUX_VERSION_CODE */ + __le32 kernel_ver_code; + + /* VERMAGIC_STRING */ + char kernel_ver[64]; + + /* room for growth w/out changing binary format */ + u8 unused[128]; + + /* struct ath10k_tlv_dump_data + more */ + u8 data[0]; +} __packed; + +#ifdef CONFIG_DEV_COREDUMP + +int ath10k_coredump_submit(struct ath10k *ar); +struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar); + +#else /* CONFIG_DEV_COREDUMP */ + +static inline int ath10k_coredump_submit(struct ath10k *ar) +{ + return 0; +} + +static inline struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar) +{ + return NULL; +} + +#endif /* CONFIG_DEV_COREDUMP */ + +#endif /* _COREDUMP_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index fbd9ea4042b6..71805ad32d3d 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -19,10 +19,8 @@ #include #include #include -#include #include #include -#include #include "core.h" #include "debug.h" @@ -34,86 +32,6 @@ #define ATH10K_DEBUG_CAL_DATA_LEN 12064 -#define ATH10K_FW_CRASH_DUMP_VERSION 1 - -/** - * enum ath10k_fw_crash_dump_type - types of data in the dump file - * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format - */ -enum ath10k_fw_crash_dump_type { - ATH10K_FW_CRASH_DUMP_REGISTERS = 0, - ATH10K_FW_CRASH_DUMP_CE_DATA = 1, - - ATH10K_FW_CRASH_DUMP_MAX, -}; - -struct ath10k_tlv_dump_data { - /* see ath10k_fw_crash_dump_type above */ - __le32 type; - - /* in bytes */ - __le32 tlv_len; - - /* pad to 32-bit boundaries as needed */ - u8 tlv_data[]; -} __packed; - -struct ath10k_dump_file_data { - /* dump file information */ - - /* "ATH10K-FW-DUMP" */ - char df_magic[16]; - - __le32 len; - - /* file dump version */ - __le32 version; - - /* some info we can get from ath10k struct that might help */ - - guid_t guid; - - __le32 chip_id; - - /* 0 for now, in place for later hardware */ - __le32 bus_type; - - __le32 target_version; - __le32 fw_version_major; - __le32 fw_version_minor; - __le32 fw_version_release; - __le32 fw_version_build; - __le32 phy_capability; - __le32 hw_min_tx_power; - __le32 hw_max_tx_power; - __le32 ht_cap_info; - __le32 vht_cap_info; - __le32 num_rf_chains; - - /* firmware version string */ - char fw_ver[ETHTOOL_FWVERS_LEN]; - - /* Kernel related information */ - - /* time-of-day stamp */ - __le64 tv_sec; - - /* time-of-day stamp, nano-seconds */ - __le64 tv_nsec; - - /* LINUX_VERSION_CODE */ - __le32 kernel_ver_code; - - /* VERMAGIC_STRING */ - char kernel_ver[64]; - - /* room for growth w/out changing binary format */ - u8 unused[128]; - - /* struct ath10k_tlv_dump_data + more */ - u8 data[0]; -} __packed; - void ath10k_info(struct ath10k *ar, const char *fmt, ...) { struct va_format vaf = { @@ -719,146 +637,6 @@ static const struct file_operations fops_chip_id = { .llseek = default_llseek, }; -struct ath10k_fw_crash_data * -ath10k_debug_get_new_fw_crash_data(struct ath10k *ar) -{ - struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data; - - lockdep_assert_held(&ar->data_lock); - - crash_data->crashed_since_read = true; - guid_gen(&crash_data->guid); - ktime_get_real_ts64(&crash_data->timestamp); - - return crash_data; -} -EXPORT_SYMBOL(ath10k_debug_get_new_fw_crash_data); - -static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar, - bool mark_read) -{ - struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data; - struct ath10k_ce_crash_hdr *ce_hdr; - struct ath10k_dump_file_data *dump_data; - struct ath10k_tlv_dump_data *dump_tlv; - size_t hdr_len = sizeof(*dump_data); - size_t len, sofar = 0; - unsigned char *buf; - - len = hdr_len; - len += sizeof(*dump_tlv) + sizeof(crash_data->registers); - len += sizeof(*dump_tlv) + sizeof(*ce_hdr) + - CE_COUNT * sizeof(ce_hdr->entries[0]); - - sofar += hdr_len; - - /* This is going to get big when we start dumping FW RAM and such, - * so go ahead and use vmalloc. - */ - buf = vzalloc(len); - if (!buf) - return NULL; - - spin_lock_bh(&ar->data_lock); - - if (!crash_data->crashed_since_read) { - spin_unlock_bh(&ar->data_lock); - vfree(buf); - return NULL; - } - - dump_data = (struct ath10k_dump_file_data *)(buf); - strlcpy(dump_data->df_magic, "ATH10K-FW-DUMP", - sizeof(dump_data->df_magic)); - dump_data->len = cpu_to_le32(len); - - dump_data->version = cpu_to_le32(ATH10K_FW_CRASH_DUMP_VERSION); - - guid_copy(&dump_data->guid, &crash_data->guid); - dump_data->chip_id = cpu_to_le32(ar->chip_id); - dump_data->bus_type = cpu_to_le32(0); - dump_data->target_version = cpu_to_le32(ar->target_version); - dump_data->fw_version_major = cpu_to_le32(ar->fw_version_major); - dump_data->fw_version_minor = cpu_to_le32(ar->fw_version_minor); - dump_data->fw_version_release = cpu_to_le32(ar->fw_version_release); - dump_data->fw_version_build = cpu_to_le32(ar->fw_version_build); - dump_data->phy_capability = cpu_to_le32(ar->phy_capability); - dump_data->hw_min_tx_power = cpu_to_le32(ar->hw_min_tx_power); - dump_data->hw_max_tx_power = cpu_to_le32(ar->hw_max_tx_power); - dump_data->ht_cap_info = cpu_to_le32(ar->ht_cap_info); - dump_data->vht_cap_info = cpu_to_le32(ar->vht_cap_info); - dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains); - - strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version, - sizeof(dump_data->fw_ver)); - - dump_data->kernel_ver_code = 0; - strlcpy(dump_data->kernel_ver, init_utsname()->release, - sizeof(dump_data->kernel_ver)); - - dump_data->tv_sec = cpu_to_le64(crash_data->timestamp.tv_sec); - dump_data->tv_nsec = cpu_to_le64(crash_data->timestamp.tv_nsec); - - /* Gather crash-dump */ - dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar); - dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_REGISTERS); - dump_tlv->tlv_len = cpu_to_le32(sizeof(crash_data->registers)); - memcpy(dump_tlv->tlv_data, &crash_data->registers, - sizeof(crash_data->registers)); - sofar += sizeof(*dump_tlv) + sizeof(crash_data->registers); - - dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar); - dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_CE_DATA); - dump_tlv->tlv_len = cpu_to_le32(sizeof(*ce_hdr) + - CE_COUNT * sizeof(ce_hdr->entries[0])); - ce_hdr = (struct ath10k_ce_crash_hdr *)(dump_tlv->tlv_data); - ce_hdr->ce_count = cpu_to_le32(CE_COUNT); - memset(ce_hdr->reserved, 0, sizeof(ce_hdr->reserved)); - memcpy(ce_hdr->entries, crash_data->ce_crash_data, - CE_COUNT * sizeof(ce_hdr->entries[0])); - sofar += sizeof(*dump_tlv) + sizeof(*ce_hdr) + - CE_COUNT * sizeof(ce_hdr->entries[0]); - - ar->debug.fw_crash_data->crashed_since_read = !mark_read; - - spin_unlock_bh(&ar->data_lock); - - return dump_data; -} - -int ath10k_debug_fw_devcoredump(struct ath10k *ar) -{ - struct ath10k_dump_file_data *dump; - void *dump_ptr; - u32 dump_len; - - /* To keep the dump file available also for debugfs don't mark the - * file read, only debugfs should do that. - */ - dump = ath10k_build_dump_file(ar, false); - if (!dump) { - ath10k_warn(ar, "no crash dump data found for devcoredump"); - return -ENODATA; - } - - /* Make a copy of the dump file for dev_coredumpv() as during the - * transition period we need to own the original file. Once - * fw_crash_dump debugfs file is removed no need to have a copy - * anymore. - */ - dump_len = le32_to_cpu(dump->len); - dump_ptr = vzalloc(dump_len); - - if (!dump_ptr) - return -ENOMEM; - - memcpy(dump_ptr, dump, dump_len); - - dev_coredumpv(ar->dev, dump_ptr, dump_len, GFP_KERNEL); - - return 0; -} - static ssize_t ath10k_reg_addr_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 134fb68ae546..58046f89dc52 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -101,13 +101,8 @@ void ath10k_debug_unregister(struct ath10k *ar); void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb); void ath10k_debug_tpc_stats_process(struct ath10k *ar, struct ath10k_tpc_stats *tpc_stats); -struct ath10k_fw_crash_data * -ath10k_debug_get_new_fw_crash_data(struct ath10k *ar); - void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len); -int ath10k_debug_fw_devcoredump(struct ath10k *ar); - #define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++) void ath10k_debug_get_et_strings(struct ieee80211_hw *hw, @@ -174,12 +169,6 @@ static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, { } -static inline struct ath10k_fw_crash_data * -ath10k_debug_get_new_fw_crash_data(struct ath10k *ar) -{ - return NULL; -} - static inline u64 ath10k_debug_get_fw_dbglog_mask(struct ath10k *ar) { return 0; @@ -190,11 +179,6 @@ static inline u32 ath10k_debug_get_fw_dbglog_level(struct ath10k *ar) return 0; } -static inline int ath10k_debug_fw_devcoredump(struct ath10k *ar) -{ - return 0; -} - #define ATH10K_DFS_STAT_INC(ar, c) do { } while (0) #define ath10k_debug_get_et_strings NULL diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 9809eba10fc2..57e6253a913c 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -23,6 +23,7 @@ #include "core.h" #include "debug.h" +#include "coredump.h" #include "targaddrs.h" #include "bmi.h" @@ -1469,7 +1470,7 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar) ar->stats.fw_crash_counter++; - crash_data = ath10k_debug_get_new_fw_crash_data(ar); + crash_data = ath10k_coredump_new(ar); if (crash_data) scnprintf(guid, sizeof(guid), "%pUl", &crash_data->guid); From de07afc267e968e9c0de66d600f291dcf427bebe Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 22 Dec 2017 15:38:59 +0200 Subject: [PATCH 019/192] UPSTREAM: ath10k: detach coredump.c from debug.c Now coredump is totally separate from debug.c and doesn't depend on CONFIG_ATH10K_DEBUGFS anymore, only on CONFIG_DEV_COREDUMP. Also remove leftovers from the removed debugfs file support. Signed-off-by: Kalle Valo Git-commit: e2fcf60c6fe84f9540b7420a790cdc3eb3ae47d5 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I9f244937bae84a6e13640e28df444fd252585aa6 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/Makefile | 2 +- drivers/net/wireless/ath/ath10k/core.c | 10 ++++- drivers/net/wireless/ath/ath10k/core.h | 11 +++-- drivers/net/wireless/ath/ath10k/coredump.c | 51 ++++++++-------------- drivers/net/wireless/ath/ath10k/coredump.h | 11 +++++ drivers/net/wireless/ath/ath10k/debug.c | 7 --- 6 files changed, 45 insertions(+), 47 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 4e6a396827ee..6739ac26fd29 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -21,7 +21,7 @@ ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o ath10k_core-$(CONFIG_THERMAL) += thermal.o ath10k_core-$(CONFIG_MAC80211_DEBUGFS) += debugfs_sta.o ath10k_core-$(CONFIG_PM) += wow.o -ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += coredump.o +ath10k_core-$(CONFIG_DEV_COREDUMP) += coredump.o obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o ath10k_pci-y += pci.o \ diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index fe47516999f6..a771746cb421 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2735,12 +2735,19 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, init_dummy_netdev(&ar->napi_dev); - ret = ath10k_debug_create(ar); + ret = ath10k_coredump_create(ar); if (ret) goto err_free_aux_wq; + ret = ath10k_debug_create(ar); + if (ret) + goto err_free_coredump; + return ar; +err_free_coredump: + ath10k_coredump_destroy(ar); + err_free_aux_wq: destroy_workqueue(ar->workqueue_aux); err_free_wq: @@ -2762,6 +2769,7 @@ void ath10k_core_destroy(struct ath10k *ar) destroy_workqueue(ar->workqueue_aux); ath10k_debug_destroy(ar); + ath10k_coredump_destroy(ar); ath10k_htt_tx_destroy(&ar->htt); ath10k_wmi_free_host_mem(ar); ath10k_mac_destroy(ar); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 6ed40f341461..7839e83d4104 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -462,8 +462,6 @@ struct ath10k_ce_crash_hdr { /* used for crash-dump storage, protected by data-lock */ struct ath10k_fw_crash_data { - bool crashed_since_read; - guid_t guid; struct timespec64 timestamp; __le32 registers[REG_DUMP_COUNT_QCA988X]; @@ -493,8 +491,6 @@ struct ath10k_debug { u32 reg_addr; u32 nf_cal_period; void *cal_data; - - struct ath10k_fw_crash_data *fw_crash_data; }; enum ath10k_state { @@ -971,6 +967,13 @@ struct ath10k { #endif u32 pktlog_filter; + +#ifdef CONFIG_DEV_COREDUMP + struct { + struct ath10k_fw_crash_data *fw_crash_data; + } coredump; +#endif + struct { /* protected by conf_mutex */ struct ath10k_fw_components utf_mode_fw; diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c index 51b86878e733..968ab2f74d83 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.c +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -21,15 +21,12 @@ #include "debug.h" -#ifdef CONFIG_DEV_COREDUMP - struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar) { - struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data; + struct ath10k_fw_crash_data *crash_data = ar->coredump.fw_crash_data; lockdep_assert_held(&ar->data_lock); - crash_data->crashed_since_read = true; guid_gen(&crash_data->guid); ktime_get_real_ts64(&crash_data->timestamp); @@ -37,10 +34,9 @@ struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar) } EXPORT_SYMBOL(ath10k_coredump_new); -static struct ath10k_dump_file_data *ath10k_coredump_build(struct ath10k *ar, - bool mark_read) +static struct ath10k_dump_file_data *ath10k_coredump_build(struct ath10k *ar) { - struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data; + struct ath10k_fw_crash_data *crash_data = ar->coredump.fw_crash_data; struct ath10k_ce_crash_hdr *ce_hdr; struct ath10k_dump_file_data *dump_data; struct ath10k_tlv_dump_data *dump_tlv; @@ -64,12 +60,6 @@ static struct ath10k_dump_file_data *ath10k_coredump_build(struct ath10k *ar, spin_lock_bh(&ar->data_lock); - if (!crash_data->crashed_since_read) { - spin_unlock_bh(&ar->data_lock); - vfree(buf); - return NULL; - } - dump_data = (struct ath10k_dump_file_data *)(buf); strlcpy(dump_data->df_magic, "ATH10K-FW-DUMP", sizeof(dump_data->df_magic)); @@ -122,8 +112,6 @@ static struct ath10k_dump_file_data *ath10k_coredump_build(struct ath10k *ar, sofar += sizeof(*dump_tlv) + sizeof(*ce_hdr) + CE_COUNT * sizeof(ce_hdr->entries[0]); - ar->debug.fw_crash_data->crashed_since_read = !mark_read; - spin_unlock_bh(&ar->data_lock); return dump_data; @@ -132,34 +120,29 @@ static struct ath10k_dump_file_data *ath10k_coredump_build(struct ath10k *ar, int ath10k_coredump_submit(struct ath10k *ar) { struct ath10k_dump_file_data *dump; - void *dump_ptr; - u32 dump_len; - /* To keep the dump file available also for debugfs don't mark the - * file read, only debugfs should do that. - */ - dump = ath10k_coredump_build(ar, false); + dump = ath10k_coredump_build(ar); if (!dump) { ath10k_warn(ar, "no crash dump data found for devcoredump"); return -ENODATA; } - /* Make a copy of the dump file for dev_coredumpv() as during the - * transition period we need to own the original file. Once - * fw_crash_dump debugfs file is removed no need to have a copy - * anymore. - */ - dump_len = le32_to_cpu(dump->len); - dump_ptr = vzalloc(dump_len); + dev_coredumpv(ar->dev, dump, le32_to_cpu(dump->len), GFP_KERNEL); - if (!dump_ptr) - return -ENOMEM; - - memcpy(dump_ptr, dump, dump_len); + return 0; +} - dev_coredumpv(ar->dev, dump_ptr, dump_len, GFP_KERNEL); +int ath10k_coredump_create(struct ath10k *ar) +{ + ar->coredump.fw_crash_data = vzalloc(sizeof(*ar->coredump.fw_crash_data)); + if (!ar->coredump.fw_crash_data) + return -ENOMEM; return 0; } -#endif /* CONFIG_DEV_COREDUMP */ +void ath10k_coredump_destroy(struct ath10k *ar) +{ + vfree(ar->coredump.fw_crash_data); + ar->coredump.fw_crash_data = NULL; +} diff --git a/drivers/net/wireless/ath/ath10k/coredump.h b/drivers/net/wireless/ath/ath10k/coredump.h index 2d2f45b5aa37..2d33075f081a 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.h +++ b/drivers/net/wireless/ath/ath10k/coredump.h @@ -103,6 +103,8 @@ struct ath10k_dump_file_data { int ath10k_coredump_submit(struct ath10k *ar); struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar); +int ath10k_coredump_create(struct ath10k *ar); +void ath10k_coredump_destroy(struct ath10k *ar); #else /* CONFIG_DEV_COREDUMP */ @@ -116,6 +118,15 @@ static inline struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar return NULL; } +static inline int ath10k_coredump_create(struct ath10k *ar) +{ + return 0; +} + +static inline void ath10k_coredump_destroy(struct ath10k *ar) +{ +} + #endif /* CONFIG_DEV_COREDUMP */ #endif /* _COREDUMP_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 71805ad32d3d..2ab3c751e6ba 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -2145,10 +2145,6 @@ static const struct file_operations fops_fw_checksums = { int ath10k_debug_create(struct ath10k *ar) { - ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data)); - if (!ar->debug.fw_crash_data) - return -ENOMEM; - ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN); if (!ar->debug.cal_data) return -ENOMEM; @@ -2163,9 +2159,6 @@ int ath10k_debug_create(struct ath10k *ar) void ath10k_debug_destroy(struct ath10k *ar) { - vfree(ar->debug.fw_crash_data); - ar->debug.fw_crash_data = NULL; - vfree(ar->debug.cal_data); ar->debug.cal_data = NULL; From a82868632954a8ab7a5ecf82c8b9f486a9a4e49b Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 22 Dec 2017 15:39:15 +0200 Subject: [PATCH 020/192] UPSTREAM: ath10k: add coredump_mask module parameter For memory dump support (it consumes quite a lot of memory) we need to control what is exactly stored to the crash dump. Add a module parameter call coredump_mask to do that. It's a bit mask of these values: enum ath10k_fw_crash_dump_type { ATH10K_FW_CRASH_DUMP_REGISTERS = 0, ATH10K_FW_CRASH_DUMP_CE_DATA = 1, ATH10K_FW_CRASH_DUMP_MAX, }; For example, if we only want to store CE_DATA we would enable bit 2: modprobe ath10k_core coredump_mask=0x2 Signed-off-by: Kalle Valo Git-commit: 5c9d0a20202beb22a3583c5408157608f400c2d0 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I99e298e9bdd6012072a68a6c695adaf4c48e8ce6 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/core.c | 8 +++ drivers/net/wireless/ath/ath10k/core.h | 2 + drivers/net/wireless/ath/ath10k/coredump.c | 63 ++++++++++++++-------- 3 files changed, 51 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index a771746cb421..025f365e8177 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -40,17 +40,25 @@ static bool uart_print; static bool skip_otp; static bool rawmode; +/* Enable ATH10K_FW_CRASH_DUMP_REGISTERS and ATH10K_FW_CRASH_DUMP_CE_DATA + * by default. + */ +unsigned long ath10k_coredump_mask = 0x3; + +/* FIXME: most of these should be readonly */ module_param_named(debug_mask, ath10k_debug_mask, uint, 0644); module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644); module_param(uart_print, bool, 0644); module_param(skip_otp, bool, 0644); module_param(rawmode, bool, 0644); +module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); MODULE_PARM_DESC(debug_mask, "Debugging mask"); MODULE_PARM_DESC(uart_print, "Uart target debugging"); MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software"); MODULE_PARM_DESC(rawmode, "Use raw 802.11 frame datapath"); +MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); static const struct ath10k_hw_params ath10k_hw_params_list[] = { { diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 7839e83d4104..50bdaa67106d 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -1027,6 +1027,8 @@ static inline bool ath10k_peer_stats_enabled(struct ath10k *ar) return false; } +extern unsigned long ath10k_coredump_mask; + struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, enum ath10k_bus bus, enum ath10k_hw_rev hw_rev, diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c index 968ab2f74d83..5e32a11184d2 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.c +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -27,6 +27,10 @@ struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar) lockdep_assert_held(&ar->data_lock); + if (ath10k_coredump_mask == 0) + /* coredump disabled */ + return NULL; + guid_gen(&crash_data->guid); ktime_get_real_ts64(&crash_data->timestamp); @@ -45,9 +49,13 @@ static struct ath10k_dump_file_data *ath10k_coredump_build(struct ath10k *ar) unsigned char *buf; len = hdr_len; - len += sizeof(*dump_tlv) + sizeof(crash_data->registers); - len += sizeof(*dump_tlv) + sizeof(*ce_hdr) + - CE_COUNT * sizeof(ce_hdr->entries[0]); + + if (test_bit(ATH10K_FW_CRASH_DUMP_REGISTERS, &ath10k_coredump_mask)) + len += sizeof(*dump_tlv) + sizeof(crash_data->registers); + + if (test_bit(ATH10K_FW_CRASH_DUMP_CE_DATA, &ath10k_coredump_mask)) + len += sizeof(*dump_tlv) + sizeof(*ce_hdr) + + CE_COUNT * sizeof(ce_hdr->entries[0]); sofar += hdr_len; @@ -92,25 +100,28 @@ static struct ath10k_dump_file_data *ath10k_coredump_build(struct ath10k *ar) dump_data->tv_sec = cpu_to_le64(crash_data->timestamp.tv_sec); dump_data->tv_nsec = cpu_to_le64(crash_data->timestamp.tv_nsec); - /* Gather crash-dump */ - dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar); - dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_REGISTERS); - dump_tlv->tlv_len = cpu_to_le32(sizeof(crash_data->registers)); - memcpy(dump_tlv->tlv_data, &crash_data->registers, - sizeof(crash_data->registers)); - sofar += sizeof(*dump_tlv) + sizeof(crash_data->registers); - - dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar); - dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_CE_DATA); - dump_tlv->tlv_len = cpu_to_le32(sizeof(*ce_hdr) + - CE_COUNT * sizeof(ce_hdr->entries[0])); - ce_hdr = (struct ath10k_ce_crash_hdr *)(dump_tlv->tlv_data); - ce_hdr->ce_count = cpu_to_le32(CE_COUNT); - memset(ce_hdr->reserved, 0, sizeof(ce_hdr->reserved)); - memcpy(ce_hdr->entries, crash_data->ce_crash_data, - CE_COUNT * sizeof(ce_hdr->entries[0])); - sofar += sizeof(*dump_tlv) + sizeof(*ce_hdr) + - CE_COUNT * sizeof(ce_hdr->entries[0]); + if (test_bit(ATH10K_FW_CRASH_DUMP_REGISTERS, &ath10k_coredump_mask)) { + dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar); + dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_REGISTERS); + dump_tlv->tlv_len = cpu_to_le32(sizeof(crash_data->registers)); + memcpy(dump_tlv->tlv_data, &crash_data->registers, + sizeof(crash_data->registers)); + sofar += sizeof(*dump_tlv) + sizeof(crash_data->registers); + } + + if (test_bit(ATH10K_FW_CRASH_DUMP_CE_DATA, &ath10k_coredump_mask)) { + dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar); + dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_CE_DATA); + dump_tlv->tlv_len = cpu_to_le32(sizeof(*ce_hdr) + + CE_COUNT * sizeof(ce_hdr->entries[0])); + ce_hdr = (struct ath10k_ce_crash_hdr *)(dump_tlv->tlv_data); + ce_hdr->ce_count = cpu_to_le32(CE_COUNT); + memset(ce_hdr->reserved, 0, sizeof(ce_hdr->reserved)); + memcpy(ce_hdr->entries, crash_data->ce_crash_data, + CE_COUNT * sizeof(ce_hdr->entries[0])); + sofar += sizeof(*dump_tlv) + sizeof(*ce_hdr) + + CE_COUNT * sizeof(ce_hdr->entries[0]); + } spin_unlock_bh(&ar->data_lock); @@ -121,6 +132,10 @@ int ath10k_coredump_submit(struct ath10k *ar) { struct ath10k_dump_file_data *dump; + if (ath10k_coredump_mask == 0) + /* coredump disabled */ + return 0; + dump = ath10k_coredump_build(ar); if (!dump) { ath10k_warn(ar, "no crash dump data found for devcoredump"); @@ -134,6 +149,10 @@ int ath10k_coredump_submit(struct ath10k *ar) int ath10k_coredump_create(struct ath10k *ar) { + if (ath10k_coredump_mask == 0) + /* coredump disabled */ + return 0; + ar->coredump.fw_crash_data = vzalloc(sizeof(*ar->coredump.fw_crash_data)); if (!ar->coredump.fw_crash_data) return -ENOMEM; From 3eba12074d8c4c5e527ab35ba632209fb07da58d Mon Sep 17 00:00:00 2001 From: Alan Liu Date: Fri, 22 Dec 2017 15:39:32 +0200 Subject: [PATCH 021/192] UPSTREAM: ath10k: add memory dump support for QCA6174/QCA9377 Add memory dump to the firmware crash data file which is provided to user space via devcoredump interface. This makes it easier for firmware engineers to debug firmware crashes. Due to increased memory consumption the memory dump is disabled by default. To enable it make sure that bit 3 is set in coredump_mask module parameter: modprobe ath10k_core coredump_mask=0xffffffff When RAMDUMP is enabled a buffer for the dump is allocated with vmalloc during device probe. The actual memory layout is different in hardware versions and the layouts are defined in coredump.c. The memory is split to regions and, to get even finegrained control of what to copy, the region can split to smaller sections as not all registers are readable (which could cause the whole system to stall). Signed-off-by: Alan Liu Signed-off-by: Kalle Valo Git-commit: 703f261dd77f3afb8058a927ca2f4651691f0495 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I17f0b4c445ee56842b961ded6d77e5343aba4bdb Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/core.c | 10 +- drivers/net/wireless/ath/ath10k/core.h | 5 + drivers/net/wireless/ath/ath10k/coredump.c | 786 +++++++++++++++++++++ drivers/net/wireless/ath/ath10k/coredump.h | 93 +++ drivers/net/wireless/ath/ath10k/hw.h | 1 + drivers/net/wireless/ath/ath10k/pci.c | 218 ++++++ 6 files changed, 1112 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 025f365e8177..ea432f10cb38 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2563,10 +2563,16 @@ static void ath10k_core_register_work(struct work_struct *work) goto err_release_fw; } + status = ath10k_coredump_register(ar); + if (status) { + ath10k_err(ar, "unable to register coredump\n"); + goto err_unregister_mac; + } + status = ath10k_debug_register(ar); if (status) { ath10k_err(ar, "unable to initialize debugfs\n"); - goto err_unregister_mac; + goto err_unregister_coredump; } status = ath10k_spectral_create(ar); @@ -2589,6 +2595,8 @@ static void ath10k_core_register_work(struct work_struct *work) ath10k_spectral_destroy(ar); err_debug_destroy: ath10k_debug_destroy(ar); +err_unregister_coredump: + ath10k_coredump_unregister(ar); err_unregister_mac: ath10k_mac_unregister(ar); err_release_fw: diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 50bdaa67106d..163cbc746f62 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -460,12 +460,17 @@ struct ath10k_ce_crash_hdr { struct ath10k_ce_crash_data entries[]; }; +#define MAX_MEM_DUMP_TYPE 5 + /* used for crash-dump storage, protected by data-lock */ struct ath10k_fw_crash_data { guid_t guid; struct timespec64 timestamp; __le32 registers[REG_DUMP_COUNT_QCA988X]; struct ath10k_ce_crash_data ce_crash_data[CE_COUNT_MAX]; + + u8 *ramdump_buf; + size_t ramdump_buf_len; }; struct ath10k_debug { diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c index 5e32a11184d2..2f4cb6c473f5 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.c +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -17,9 +17,754 @@ #include "coredump.h" #include +#include +#include #include #include "debug.h" +#include "hw.h" + +static const struct ath10k_mem_section qca6174_hw21_register_sections[] = { + {0x800, 0x810}, + {0x820, 0x82C}, + {0x830, 0x8F4}, + {0x90C, 0x91C}, + {0xA14, 0xA18}, + {0xA84, 0xA94}, + {0xAA8, 0xAD4}, + {0xADC, 0xB40}, + {0x1000, 0x10A4}, + {0x10BC, 0x111C}, + {0x1134, 0x1138}, + {0x1144, 0x114C}, + {0x1150, 0x115C}, + {0x1160, 0x1178}, + {0x1240, 0x1260}, + {0x2000, 0x207C}, + {0x3000, 0x3014}, + {0x4000, 0x4014}, + {0x5000, 0x5124}, + {0x6000, 0x6040}, + {0x6080, 0x60CC}, + {0x6100, 0x611C}, + {0x6140, 0x61D8}, + {0x6200, 0x6238}, + {0x6240, 0x628C}, + {0x62C0, 0x62EC}, + {0x6380, 0x63E8}, + {0x6400, 0x6440}, + {0x6480, 0x64CC}, + {0x6500, 0x651C}, + {0x6540, 0x6580}, + {0x6600, 0x6638}, + {0x6640, 0x668C}, + {0x66C0, 0x66EC}, + {0x6780, 0x67E8}, + {0x7080, 0x708C}, + {0x70C0, 0x70C8}, + {0x7400, 0x741C}, + {0x7440, 0x7454}, + {0x7800, 0x7818}, + {0x8000, 0x8004}, + {0x8010, 0x8064}, + {0x8080, 0x8084}, + {0x80A0, 0x80A4}, + {0x80C0, 0x80C4}, + {0x80E0, 0x80F4}, + {0x8100, 0x8104}, + {0x8110, 0x812C}, + {0x9000, 0x9004}, + {0x9800, 0x982C}, + {0x9830, 0x9838}, + {0x9840, 0x986C}, + {0x9870, 0x9898}, + {0x9A00, 0x9C00}, + {0xD580, 0xD59C}, + {0xF000, 0xF0E0}, + {0xF140, 0xF190}, + {0xF250, 0xF25C}, + {0xF260, 0xF268}, + {0xF26C, 0xF2A8}, + {0x10008, 0x1000C}, + {0x10014, 0x10018}, + {0x1001C, 0x10020}, + {0x10024, 0x10028}, + {0x10030, 0x10034}, + {0x10040, 0x10054}, + {0x10058, 0x1007C}, + {0x10080, 0x100C4}, + {0x100C8, 0x10114}, + {0x1012C, 0x10130}, + {0x10138, 0x10144}, + {0x10200, 0x10220}, + {0x10230, 0x10250}, + {0x10260, 0x10280}, + {0x10290, 0x102B0}, + {0x102C0, 0x102DC}, + {0x102E0, 0x102F4}, + {0x102FC, 0x1037C}, + {0x10380, 0x10390}, + {0x10800, 0x10828}, + {0x10840, 0x10844}, + {0x10880, 0x10884}, + {0x108C0, 0x108E8}, + {0x10900, 0x10928}, + {0x10940, 0x10944}, + {0x10980, 0x10984}, + {0x109C0, 0x109E8}, + {0x10A00, 0x10A28}, + {0x10A40, 0x10A50}, + {0x11000, 0x11028}, + {0x11030, 0x11034}, + {0x11038, 0x11068}, + {0x11070, 0x11074}, + {0x11078, 0x110A8}, + {0x110B0, 0x110B4}, + {0x110B8, 0x110E8}, + {0x110F0, 0x110F4}, + {0x110F8, 0x11128}, + {0x11138, 0x11144}, + {0x11178, 0x11180}, + {0x111B8, 0x111C0}, + {0x111F8, 0x11200}, + {0x11238, 0x1123C}, + {0x11270, 0x11274}, + {0x11278, 0x1127C}, + {0x112B0, 0x112B4}, + {0x112B8, 0x112BC}, + {0x112F0, 0x112F4}, + {0x112F8, 0x112FC}, + {0x11338, 0x1133C}, + {0x11378, 0x1137C}, + {0x113B8, 0x113BC}, + {0x113F8, 0x113FC}, + {0x11438, 0x11440}, + {0x11478, 0x11480}, + {0x114B8, 0x114BC}, + {0x114F8, 0x114FC}, + {0x11538, 0x1153C}, + {0x11578, 0x1157C}, + {0x115B8, 0x115BC}, + {0x115F8, 0x115FC}, + {0x11638, 0x1163C}, + {0x11678, 0x1167C}, + {0x116B8, 0x116BC}, + {0x116F8, 0x116FC}, + {0x11738, 0x1173C}, + {0x11778, 0x1177C}, + {0x117B8, 0x117BC}, + {0x117F8, 0x117FC}, + {0x17000, 0x1701C}, + {0x17020, 0x170AC}, + {0x18000, 0x18050}, + {0x18054, 0x18074}, + {0x18080, 0x180D4}, + {0x180DC, 0x18104}, + {0x18108, 0x1813C}, + {0x18144, 0x18148}, + {0x18168, 0x18174}, + {0x18178, 0x18180}, + {0x181C8, 0x181E0}, + {0x181E4, 0x181E8}, + {0x181EC, 0x1820C}, + {0x1825C, 0x18280}, + {0x18284, 0x18290}, + {0x18294, 0x182A0}, + {0x18300, 0x18304}, + {0x18314, 0x18320}, + {0x18328, 0x18350}, + {0x1835C, 0x1836C}, + {0x18370, 0x18390}, + {0x18398, 0x183AC}, + {0x183BC, 0x183D8}, + {0x183DC, 0x183F4}, + {0x18400, 0x186F4}, + {0x186F8, 0x1871C}, + {0x18720, 0x18790}, + {0x19800, 0x19830}, + {0x19834, 0x19840}, + {0x19880, 0x1989C}, + {0x198A4, 0x198B0}, + {0x198BC, 0x19900}, + {0x19C00, 0x19C88}, + {0x19D00, 0x19D20}, + {0x19E00, 0x19E7C}, + {0x19E80, 0x19E94}, + {0x19E98, 0x19EAC}, + {0x19EB0, 0x19EBC}, + {0x19F70, 0x19F74}, + {0x19F80, 0x19F8C}, + {0x19FA0, 0x19FB4}, + {0x19FC0, 0x19FD8}, + {0x1A000, 0x1A200}, + {0x1A204, 0x1A210}, + {0x1A228, 0x1A22C}, + {0x1A230, 0x1A248}, + {0x1A250, 0x1A270}, + {0x1A280, 0x1A290}, + {0x1A2A0, 0x1A2A4}, + {0x1A2C0, 0x1A2EC}, + {0x1A300, 0x1A3BC}, + {0x1A3F0, 0x1A3F4}, + {0x1A3F8, 0x1A434}, + {0x1A438, 0x1A444}, + {0x1A448, 0x1A468}, + {0x1A580, 0x1A58C}, + {0x1A644, 0x1A654}, + {0x1A670, 0x1A698}, + {0x1A6AC, 0x1A6B0}, + {0x1A6D0, 0x1A6D4}, + {0x1A6EC, 0x1A70C}, + {0x1A710, 0x1A738}, + {0x1A7C0, 0x1A7D0}, + {0x1A7D4, 0x1A7D8}, + {0x1A7DC, 0x1A7E4}, + {0x1A7F0, 0x1A7F8}, + {0x1A888, 0x1A89C}, + {0x1A8A8, 0x1A8AC}, + {0x1A8C0, 0x1A8DC}, + {0x1A8F0, 0x1A8FC}, + {0x1AE04, 0x1AE08}, + {0x1AE18, 0x1AE24}, + {0x1AF80, 0x1AF8C}, + {0x1AFA0, 0x1AFB4}, + {0x1B000, 0x1B200}, + {0x1B284, 0x1B288}, + {0x1B2D0, 0x1B2D8}, + {0x1B2DC, 0x1B2EC}, + {0x1B300, 0x1B340}, + {0x1B374, 0x1B378}, + {0x1B380, 0x1B384}, + {0x1B388, 0x1B38C}, + {0x1B404, 0x1B408}, + {0x1B420, 0x1B428}, + {0x1B440, 0x1B444}, + {0x1B448, 0x1B44C}, + {0x1B450, 0x1B458}, + {0x1B45C, 0x1B468}, + {0x1B584, 0x1B58C}, + {0x1B68C, 0x1B690}, + {0x1B6AC, 0x1B6B0}, + {0x1B7F0, 0x1B7F8}, + {0x1C800, 0x1CC00}, + {0x1CE00, 0x1CE04}, + {0x1CF80, 0x1CF84}, + {0x1D200, 0x1D800}, + {0x1E000, 0x20014}, + {0x20100, 0x20124}, + {0x21400, 0x217A8}, + {0x21800, 0x21BA8}, + {0x21C00, 0x21FA8}, + {0x22000, 0x223A8}, + {0x22400, 0x227A8}, + {0x22800, 0x22BA8}, + {0x22C00, 0x22FA8}, + {0x23000, 0x233A8}, + {0x24000, 0x24034}, + {0x26000, 0x26064}, + {0x27000, 0x27024}, + {0x34000, 0x3400C}, + {0x34400, 0x3445C}, + {0x34800, 0x3485C}, + {0x34C00, 0x34C5C}, + {0x35000, 0x3505C}, + {0x35400, 0x3545C}, + {0x35800, 0x3585C}, + {0x35C00, 0x35C5C}, + {0x36000, 0x3605C}, + {0x38000, 0x38064}, + {0x38070, 0x380E0}, + {0x3A000, 0x3A064}, + {0x40000, 0x400A4}, + {0x80000, 0x8000C}, + {0x80010, 0x80020}, +}; + +static const struct ath10k_mem_section qca6174_hw30_register_sections[] = { + {0x800, 0x810}, + {0x820, 0x82C}, + {0x830, 0x8F4}, + {0x90C, 0x91C}, + {0xA14, 0xA18}, + {0xA84, 0xA94}, + {0xAA8, 0xAD4}, + {0xADC, 0xB40}, + {0x1000, 0x10A4}, + {0x10BC, 0x111C}, + {0x1134, 0x1138}, + {0x1144, 0x114C}, + {0x1150, 0x115C}, + {0x1160, 0x1178}, + {0x1240, 0x1260}, + {0x2000, 0x207C}, + {0x3000, 0x3014}, + {0x4000, 0x4014}, + {0x5000, 0x5124}, + {0x6000, 0x6040}, + {0x6080, 0x60CC}, + {0x6100, 0x611C}, + {0x6140, 0x61D8}, + {0x6200, 0x6238}, + {0x6240, 0x628C}, + {0x62C0, 0x62EC}, + {0x6380, 0x63E8}, + {0x6400, 0x6440}, + {0x6480, 0x64CC}, + {0x6500, 0x651C}, + {0x6540, 0x6580}, + {0x6600, 0x6638}, + {0x6640, 0x668C}, + {0x66C0, 0x66EC}, + {0x6780, 0x67E8}, + {0x7080, 0x708C}, + {0x70C0, 0x70C8}, + {0x7400, 0x741C}, + {0x7440, 0x7454}, + {0x7800, 0x7818}, + {0x8000, 0x8004}, + {0x8010, 0x8064}, + {0x8080, 0x8084}, + {0x80A0, 0x80A4}, + {0x80C0, 0x80C4}, + {0x80E0, 0x80F4}, + {0x8100, 0x8104}, + {0x8110, 0x812C}, + {0x9000, 0x9004}, + {0x9800, 0x982C}, + {0x9830, 0x9838}, + {0x9840, 0x986C}, + {0x9870, 0x9898}, + {0x9A00, 0x9C00}, + {0xD580, 0xD59C}, + {0xF000, 0xF0E0}, + {0xF140, 0xF190}, + {0xF250, 0xF25C}, + {0xF260, 0xF268}, + {0xF26C, 0xF2A8}, + {0x10008, 0x1000C}, + {0x10014, 0x10018}, + {0x1001C, 0x10020}, + {0x10024, 0x10028}, + {0x10030, 0x10034}, + {0x10040, 0x10054}, + {0x10058, 0x1007C}, + {0x10080, 0x100C4}, + {0x100C8, 0x10114}, + {0x1012C, 0x10130}, + {0x10138, 0x10144}, + {0x10200, 0x10220}, + {0x10230, 0x10250}, + {0x10260, 0x10280}, + {0x10290, 0x102B0}, + {0x102C0, 0x102DC}, + {0x102E0, 0x102F4}, + {0x102FC, 0x1037C}, + {0x10380, 0x10390}, + {0x10800, 0x10828}, + {0x10840, 0x10844}, + {0x10880, 0x10884}, + {0x108C0, 0x108E8}, + {0x10900, 0x10928}, + {0x10940, 0x10944}, + {0x10980, 0x10984}, + {0x109C0, 0x109E8}, + {0x10A00, 0x10A28}, + {0x10A40, 0x10A50}, + {0x11000, 0x11028}, + {0x11030, 0x11034}, + {0x11038, 0x11068}, + {0x11070, 0x11074}, + {0x11078, 0x110A8}, + {0x110B0, 0x110B4}, + {0x110B8, 0x110E8}, + {0x110F0, 0x110F4}, + {0x110F8, 0x11128}, + {0x11138, 0x11144}, + {0x11178, 0x11180}, + {0x111B8, 0x111C0}, + {0x111F8, 0x11200}, + {0x11238, 0x1123C}, + {0x11270, 0x11274}, + {0x11278, 0x1127C}, + {0x112B0, 0x112B4}, + {0x112B8, 0x112BC}, + {0x112F0, 0x112F4}, + {0x112F8, 0x112FC}, + {0x11338, 0x1133C}, + {0x11378, 0x1137C}, + {0x113B8, 0x113BC}, + {0x113F8, 0x113FC}, + {0x11438, 0x11440}, + {0x11478, 0x11480}, + {0x114B8, 0x114BC}, + {0x114F8, 0x114FC}, + {0x11538, 0x1153C}, + {0x11578, 0x1157C}, + {0x115B8, 0x115BC}, + {0x115F8, 0x115FC}, + {0x11638, 0x1163C}, + {0x11678, 0x1167C}, + {0x116B8, 0x116BC}, + {0x116F8, 0x116FC}, + {0x11738, 0x1173C}, + {0x11778, 0x1177C}, + {0x117B8, 0x117BC}, + {0x117F8, 0x117FC}, + {0x17000, 0x1701C}, + {0x17020, 0x170AC}, + {0x18000, 0x18050}, + {0x18054, 0x18074}, + {0x18080, 0x180D4}, + {0x180DC, 0x18104}, + {0x18108, 0x1813C}, + {0x18144, 0x18148}, + {0x18168, 0x18174}, + {0x18178, 0x18180}, + {0x181C8, 0x181E0}, + {0x181E4, 0x181E8}, + {0x181EC, 0x1820C}, + {0x1825C, 0x18280}, + {0x18284, 0x18290}, + {0x18294, 0x182A0}, + {0x18300, 0x18304}, + {0x18314, 0x18320}, + {0x18328, 0x18350}, + {0x1835C, 0x1836C}, + {0x18370, 0x18390}, + {0x18398, 0x183AC}, + {0x183BC, 0x183D8}, + {0x183DC, 0x183F4}, + {0x18400, 0x186F4}, + {0x186F8, 0x1871C}, + {0x18720, 0x18790}, + {0x19800, 0x19830}, + {0x19834, 0x19840}, + {0x19880, 0x1989C}, + {0x198A4, 0x198B0}, + {0x198BC, 0x19900}, + {0x19C00, 0x19C88}, + {0x19D00, 0x19D20}, + {0x19E00, 0x19E7C}, + {0x19E80, 0x19E94}, + {0x19E98, 0x19EAC}, + {0x19EB0, 0x19EBC}, + {0x19F70, 0x19F74}, + {0x19F80, 0x19F8C}, + {0x19FA0, 0x19FB4}, + {0x19FC0, 0x19FD8}, + {0x1A000, 0x1A200}, + {0x1A204, 0x1A210}, + {0x1A228, 0x1A22C}, + {0x1A230, 0x1A248}, + {0x1A250, 0x1A270}, + {0x1A280, 0x1A290}, + {0x1A2A0, 0x1A2A4}, + {0x1A2C0, 0x1A2EC}, + {0x1A300, 0x1A3BC}, + {0x1A3F0, 0x1A3F4}, + {0x1A3F8, 0x1A434}, + {0x1A438, 0x1A444}, + {0x1A448, 0x1A468}, + {0x1A580, 0x1A58C}, + {0x1A644, 0x1A654}, + {0x1A670, 0x1A698}, + {0x1A6AC, 0x1A6B0}, + {0x1A6D0, 0x1A6D4}, + {0x1A6EC, 0x1A70C}, + {0x1A710, 0x1A738}, + {0x1A7C0, 0x1A7D0}, + {0x1A7D4, 0x1A7D8}, + {0x1A7DC, 0x1A7E4}, + {0x1A7F0, 0x1A7F8}, + {0x1A888, 0x1A89C}, + {0x1A8A8, 0x1A8AC}, + {0x1A8C0, 0x1A8DC}, + {0x1A8F0, 0x1A8FC}, + {0x1AE04, 0x1AE08}, + {0x1AE18, 0x1AE24}, + {0x1AF80, 0x1AF8C}, + {0x1AFA0, 0x1AFB4}, + {0x1B000, 0x1B200}, + {0x1B284, 0x1B288}, + {0x1B2D0, 0x1B2D8}, + {0x1B2DC, 0x1B2EC}, + {0x1B300, 0x1B340}, + {0x1B374, 0x1B378}, + {0x1B380, 0x1B384}, + {0x1B388, 0x1B38C}, + {0x1B404, 0x1B408}, + {0x1B420, 0x1B428}, + {0x1B440, 0x1B444}, + {0x1B448, 0x1B44C}, + {0x1B450, 0x1B458}, + {0x1B45C, 0x1B468}, + {0x1B584, 0x1B58C}, + {0x1B68C, 0x1B690}, + {0x1B6AC, 0x1B6B0}, + {0x1B7F0, 0x1B7F8}, + {0x1C800, 0x1CC00}, + {0x1CE00, 0x1CE04}, + {0x1CF80, 0x1CF84}, + {0x1D200, 0x1D800}, + {0x1E000, 0x20014}, + {0x20100, 0x20124}, + {0x21400, 0x217A8}, + {0x21800, 0x21BA8}, + {0x21C00, 0x21FA8}, + {0x22000, 0x223A8}, + {0x22400, 0x227A8}, + {0x22800, 0x22BA8}, + {0x22C00, 0x22FA8}, + {0x23000, 0x233A8}, + {0x24000, 0x24034}, + {0x26000, 0x26064}, + {0x27000, 0x27024}, + {0x34000, 0x3400C}, + {0x34400, 0x3445C}, + {0x34800, 0x3485C}, + {0x34C00, 0x34C5C}, + {0x35000, 0x3505C}, + {0x35400, 0x3545C}, + {0x35800, 0x3585C}, + {0x35C00, 0x35C5C}, + {0x36000, 0x3605C}, + {0x38000, 0x38064}, + {0x38070, 0x380E0}, + {0x3A000, 0x3A074}, + {0x40000, 0x400A4}, + {0x80000, 0x8000C}, + {0x80010, 0x80020}, +}; + +static const struct ath10k_mem_region qca6174_hw10_mem_regions[] = { + { + .type = ATH10K_MEM_REGION_TYPE_DRAM, + .start = 0x400000, + .len = 0x70000, + .name = "DRAM", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_REG, + + /* RTC_SOC_BASE_ADDRESS */ + .start = 0x0, + + /* WLAN_MBOX_BASE_ADDRESS - RTC_SOC_BASE_ADDRESS */ + .len = 0x800 - 0x0, + + .name = "REG_PART1", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_REG, + + /* STEREO_BASE_ADDRESS */ + .start = 0x27000, + + /* USB_BASE_ADDRESS - STEREO_BASE_ADDRESS */ + .len = 0x60000 - 0x27000, + + .name = "REG_PART2", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, +}; + +static const struct ath10k_mem_region qca6174_hw21_mem_regions[] = { + { + .type = ATH10K_MEM_REGION_TYPE_DRAM, + .start = 0x400000, + .len = 0x70000, + .name = "DRAM", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_AXI, + .start = 0xa0000, + .len = 0x18000, + .name = "AXI", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_REG, + .start = 0x800, + .len = 0x80020 - 0x800, + .name = "REG_TOTAL", + .section_table = { + .sections = qca6174_hw21_register_sections, + .size = ARRAY_SIZE(qca6174_hw21_register_sections), + }, + }, +}; + +static const struct ath10k_mem_region qca6174_hw30_mem_regions[] = { + { + .type = ATH10K_MEM_REGION_TYPE_DRAM, + .start = 0x400000, + .len = 0x90000, + .name = "DRAM", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_AXI, + .start = 0xa0000, + .len = 0x18000, + .name = "AXI", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_REG, + .start = 0x800, + .len = 0x80020 - 0x800, + .name = "REG_TOTAL", + .section_table = { + .sections = qca6174_hw30_register_sections, + .size = ARRAY_SIZE(qca6174_hw30_register_sections), + }, + }, + + /* IRAM dump must be put last */ + { + .type = ATH10K_MEM_REGION_TYPE_IRAM1, + .start = 0x00980000, + .len = 0x00080000, + .name = "IRAM1", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IRAM2, + .start = 0x00a00000, + .len = 0x00040000, + .name = "IRAM2", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, +}; + +static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { + { + .hw_id = QCA6174_HW_1_0_VERSION, + .region_table = { + .regions = qca6174_hw10_mem_regions, + .size = ARRAY_SIZE(qca6174_hw10_mem_regions), + }, + }, + { + .hw_id = QCA6174_HW_1_1_VERSION, + .region_table = { + .regions = qca6174_hw10_mem_regions, + .size = ARRAY_SIZE(qca6174_hw10_mem_regions), + }, + }, + { + .hw_id = QCA6174_HW_1_3_VERSION, + .region_table = { + .regions = qca6174_hw10_mem_regions, + .size = ARRAY_SIZE(qca6174_hw10_mem_regions), + }, + }, + { + .hw_id = QCA6174_HW_2_1_VERSION, + .region_table = { + .regions = qca6174_hw21_mem_regions, + .size = ARRAY_SIZE(qca6174_hw21_mem_regions), + }, + }, + { + .hw_id = QCA6174_HW_3_0_VERSION, + .region_table = { + .regions = qca6174_hw30_mem_regions, + .size = ARRAY_SIZE(qca6174_hw30_mem_regions), + }, + }, + { + .hw_id = QCA6174_HW_3_2_VERSION, + .region_table = { + .regions = qca6174_hw30_mem_regions, + .size = ARRAY_SIZE(qca6174_hw30_mem_regions), + }, + }, + { + .hw_id = QCA9377_HW_1_1_DEV_VERSION, + .region_table = { + .regions = qca6174_hw30_mem_regions, + .size = ARRAY_SIZE(qca6174_hw30_mem_regions), + }, + }, +}; + +static u32 ath10k_coredump_get_ramdump_size(struct ath10k *ar) +{ + const struct ath10k_hw_mem_layout *hw; + const struct ath10k_mem_region *mem_region; + size_t size = 0; + int i; + + hw = ath10k_coredump_get_mem_layout(ar); + + if (!hw) + return 0; + + mem_region = &hw->region_table.regions[0]; + + for (i = 0; i < hw->region_table.size; i++) { + size += mem_region->len; + mem_region++; + } + + /* reserve space for the headers */ + size += hw->region_table.size * sizeof(struct ath10k_dump_ram_data_hdr); + + /* make sure it is aligned 16 bytes for debug message print out */ + size = ALIGN(size, 16); + + return size; +} + +const struct ath10k_hw_mem_layout *ath10k_coredump_get_mem_layout(struct ath10k *ar) +{ + int i; + + if (!test_bit(ATH10K_FW_CRASH_DUMP_RAM_DATA, &ath10k_coredump_mask)) + return NULL; + + if (WARN_ON(ar->target_version == 0)) + return NULL; + + for (i = 0; i < ARRAY_SIZE(hw_mem_layouts); i++) { + if (ar->target_version == hw_mem_layouts[i].hw_id) + return &hw_mem_layouts[i]; + } + + return NULL; +} +EXPORT_SYMBOL(ath10k_coredump_get_mem_layout); struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar) { @@ -57,6 +802,9 @@ static struct ath10k_dump_file_data *ath10k_coredump_build(struct ath10k *ar) len += sizeof(*dump_tlv) + sizeof(*ce_hdr) + CE_COUNT * sizeof(ce_hdr->entries[0]); + if (test_bit(ATH10K_FW_CRASH_DUMP_RAM_DATA, &ath10k_coredump_mask)) + len += sizeof(*dump_tlv) + crash_data->ramdump_buf_len; + sofar += hdr_len; /* This is going to get big when we start dumping FW RAM and such, @@ -123,6 +871,16 @@ static struct ath10k_dump_file_data *ath10k_coredump_build(struct ath10k *ar) CE_COUNT * sizeof(ce_hdr->entries[0]); } + /* Gather ram dump */ + if (test_bit(ATH10K_FW_CRASH_DUMP_RAM_DATA, &ath10k_coredump_mask)) { + dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar); + dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_RAM_DATA); + dump_tlv->tlv_len = cpu_to_le32(crash_data->ramdump_buf_len); + memcpy(dump_tlv->tlv_data, crash_data->ramdump_buf, + crash_data->ramdump_buf_len); + sofar += sizeof(*dump_tlv) + crash_data->ramdump_buf_len; + } + spin_unlock_bh(&ar->data_lock); return dump_data; @@ -160,8 +918,36 @@ int ath10k_coredump_create(struct ath10k *ar) return 0; } +int ath10k_coredump_register(struct ath10k *ar) +{ + struct ath10k_fw_crash_data *crash_data = ar->coredump.fw_crash_data; + + if (test_bit(ATH10K_FW_CRASH_DUMP_RAM_DATA, &ath10k_coredump_mask)) { + crash_data->ramdump_buf_len = ath10k_coredump_get_ramdump_size(ar); + + crash_data->ramdump_buf = vzalloc(crash_data->ramdump_buf_len); + if (!crash_data->ramdump_buf) + return -ENOMEM; + } + + return 0; +} + +void ath10k_coredump_unregister(struct ath10k *ar) +{ + struct ath10k_fw_crash_data *crash_data = ar->coredump.fw_crash_data; + + vfree(crash_data->ramdump_buf); +} + void ath10k_coredump_destroy(struct ath10k *ar) { + if (ar->coredump.fw_crash_data->ramdump_buf) { + vfree(ar->coredump.fw_crash_data->ramdump_buf); + ar->coredump.fw_crash_data->ramdump_buf = NULL; + ar->coredump.fw_crash_data->ramdump_buf_len = 0; + } + vfree(ar->coredump.fw_crash_data); ar->coredump.fw_crash_data = NULL; } diff --git a/drivers/net/wireless/ath/ath10k/coredump.h b/drivers/net/wireless/ath/ath10k/coredump.h index 2d33075f081a..bfee13038e59 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.h +++ b/drivers/net/wireless/ath/ath10k/coredump.h @@ -29,6 +29,9 @@ enum ath10k_fw_crash_dump_type { ATH10K_FW_CRASH_DUMP_REGISTERS = 0, ATH10K_FW_CRASH_DUMP_CE_DATA = 1, + /* contains multiple struct ath10k_dump_ram_data_hdr */ + ATH10K_FW_CRASH_DUMP_RAM_DATA = 2, + ATH10K_FW_CRASH_DUMP_MAX, }; @@ -99,13 +102,88 @@ struct ath10k_dump_file_data { u8 data[0]; } __packed; +struct ath10k_dump_ram_data_hdr { + /* enum ath10k_mem_region_type */ + __le32 region_type; + + __le32 start; + + /* length of payload data, not including this header */ + __le32 length; + + u8 data[0]; +}; + +/* magic number to fill the holes not copied due to sections in regions */ +#define ATH10K_MAGIC_NOT_COPIED 0xAA + +/* part of user space ABI */ +enum ath10k_mem_region_type { + ATH10K_MEM_REGION_TYPE_REG = 1, + ATH10K_MEM_REGION_TYPE_DRAM = 2, + ATH10K_MEM_REGION_TYPE_AXI = 3, + ATH10K_MEM_REGION_TYPE_IRAM1 = 4, + ATH10K_MEM_REGION_TYPE_IRAM2 = 5, +}; + +/* Define a section of the region which should be copied. As not all parts + * of the memory is possible to copy, for example some of the registers can + * be like that, sections can be used to define what is safe to copy. + * + * To minimize the size of the array, the list must obey the format: + * '{start0,stop0},{start1,stop1},{start2,stop2}....' The values below must + * also obey to 'start0 < stop0 < start1 < stop1 < start2 < ...', otherwise + * we may encouter error in the dump processing. + */ +struct ath10k_mem_section { + u32 start; + u32 end; +}; + +/* One region of a memory layout. If the sections field is null entire + * region is copied. If sections is non-null only the areas specified in + * sections are copied and rest of the areas are filled with + * ATH10K_MAGIC_NOT_COPIED. + */ +struct ath10k_mem_region { + enum ath10k_mem_region_type type; + u32 start; + u32 len; + + const char *name; + + struct { + const struct ath10k_mem_section *sections; + u32 size; + } section_table; +}; + +/* Contains the memory layout of a hardware version identified with the + * hardware id, split into regions. + */ +struct ath10k_hw_mem_layout { + u32 hw_id; + + struct { + const struct ath10k_mem_region *regions; + int size; + } region_table; +}; + +/* FIXME: where to put this? */ +extern unsigned long ath10k_coredump_mask; + #ifdef CONFIG_DEV_COREDUMP int ath10k_coredump_submit(struct ath10k *ar); struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar); int ath10k_coredump_create(struct ath10k *ar); +int ath10k_coredump_register(struct ath10k *ar); +void ath10k_coredump_unregister(struct ath10k *ar); void ath10k_coredump_destroy(struct ath10k *ar); +const struct ath10k_hw_mem_layout *ath10k_coredump_get_mem_layout(struct ath10k *ar); + #else /* CONFIG_DEV_COREDUMP */ static inline int ath10k_coredump_submit(struct ath10k *ar) @@ -123,10 +201,25 @@ static inline int ath10k_coredump_create(struct ath10k *ar) return 0; } +static inline int ath10k_coredump_register(struct ath10k *ar) +{ + return 0; +} + +static inline void ath10k_coredump_unregister(struct ath10k *ar) +{ +} + static inline void ath10k_coredump_destroy(struct ath10k *ar) { } +static inline const struct ath10k_hw_mem_layout * +ath10k_coredump_get_mem_layout(struct ath10k *ar) +{ + return NULL; +} + #endif /* CONFIG_DEV_COREDUMP */ #endif /* _COREDUMP_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index ef370525b8f3..ab0cc2de6f68 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -888,6 +888,7 @@ ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw, #define PCIE_INTR_CLR_ADDRESS ar->regs->pcie_intr_clr_address #define SCRATCH_3_ADDRESS ar->regs->scratch_3_address #define CPU_INTR_ADDRESS 0x0010 +#define FW_RAM_CONFIG_ADDRESS 0x0018 #define CCNT_TO_MSEC(ar, x) ((x) / ar->hw_params.channel_counters_freq_hz) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 57e6253a913c..b0db754cfe81 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -52,6 +52,11 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); #define ATH10K_PCI_TARGET_WAIT 3000 #define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3 +/* Maximum number of bytes that can be handled atomically by + * diag read and write. + */ +#define ATH10K_DIAG_TRANSFER_LIMIT 0x5000 + static const struct pci_device_id ath10k_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */ { PCI_VDEVICE(ATHEROS, QCA6164_2_1_DEVICE_ID) }, /* PCI-E QCA6164 V2.1 */ @@ -1461,6 +1466,218 @@ static void ath10k_pci_dump_registers(struct ath10k *ar, crash_data->registers[i] = reg_dump_values[i]; } +static int ath10k_pci_dump_memory_section(struct ath10k *ar, + const struct ath10k_mem_region *mem_region, + u8 *buf, size_t buf_len) +{ + const struct ath10k_mem_section *cur_section, *next_section; + unsigned int count, section_size, skip_size; + int ret, i, j; + + if (!mem_region || !buf) + return 0; + + if (mem_region->section_table.size < 0) + return 0; + + cur_section = &mem_region->section_table.sections[0]; + + if (mem_region->start > cur_section->start) { + ath10k_warn(ar, "incorrect memdump region 0x%x with section start addrress 0x%x.\n", + mem_region->start, cur_section->start); + return 0; + } + + skip_size = cur_section->start - mem_region->start; + + /* fill the gap between the first register section and register + * start address + */ + for (i = 0; i < skip_size; i++) { + *buf = ATH10K_MAGIC_NOT_COPIED; + buf++; + } + + count = 0; + + for (i = 0; cur_section != NULL; i++) { + section_size = cur_section->end - cur_section->start; + + if (section_size <= 0) { + ath10k_warn(ar, "incorrect ramdump format with start address 0x%x and stop address 0x%x\n", + cur_section->start, + cur_section->end); + break; + } + + if ((i + 1) == mem_region->section_table.size) { + /* last section */ + next_section = NULL; + skip_size = 0; + } else { + next_section = cur_section + 1; + + if (cur_section->end > next_section->start) { + ath10k_warn(ar, "next ramdump section 0x%x is smaller than current end address 0x%x\n", + next_section->start, + cur_section->end); + break; + } + + skip_size = next_section->start - cur_section->end; + } + + if (buf_len < (skip_size + section_size)) { + ath10k_warn(ar, "ramdump buffer is too small: %zu\n", buf_len); + break; + } + + buf_len -= skip_size + section_size; + + /* read section to dest memory */ + ret = ath10k_pci_diag_read_mem(ar, cur_section->start, + buf, section_size); + if (ret) { + ath10k_warn(ar, "failed to read ramdump from section 0x%x: %d\n", + cur_section->start, ret); + break; + } + + buf += section_size; + count += section_size; + + /* fill in the gap between this section and the next */ + for (j = 0; j < skip_size; j++) { + *buf = ATH10K_MAGIC_NOT_COPIED; + buf++; + } + + count += skip_size; + + if (!next_section) + /* this was the last section */ + break; + + cur_section = next_section; + } + + return count; +} + +static int ath10k_pci_set_ram_config(struct ath10k *ar, u32 config) +{ + u32 val; + + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + + FW_RAM_CONFIG_ADDRESS, config); + + val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + FW_RAM_CONFIG_ADDRESS); + if (val != config) { + ath10k_warn(ar, "failed to set RAM config from 0x%x to 0x%x\n", + val, config); + return -EIO; + } + + return 0; +} + +static void ath10k_pci_dump_memory(struct ath10k *ar, + struct ath10k_fw_crash_data *crash_data) +{ + const struct ath10k_hw_mem_layout *mem_layout; + const struct ath10k_mem_region *current_region; + struct ath10k_dump_ram_data_hdr *hdr; + u32 count, shift; + size_t buf_len; + int ret, i; + u8 *buf; + + lockdep_assert_held(&ar->data_lock); + + if (!crash_data) + return; + + mem_layout = ath10k_coredump_get_mem_layout(ar); + if (!mem_layout) + return; + + current_region = &mem_layout->region_table.regions[0]; + + buf = crash_data->ramdump_buf; + buf_len = crash_data->ramdump_buf_len; + + memset(buf, 0, buf_len); + + for (i = 0; i < mem_layout->region_table.size; i++) { + count = 0; + + if (current_region->len > buf_len) { + ath10k_warn(ar, "memory region %s size %d is larger that remaining ramdump buffer size %zu\n", + current_region->name, + current_region->len, + buf_len); + break; + } + + /* To get IRAM dump, the host driver needs to switch target + * ram config from DRAM to IRAM. + */ + if (current_region->type == ATH10K_MEM_REGION_TYPE_IRAM1 || + current_region->type == ATH10K_MEM_REGION_TYPE_IRAM2) { + shift = current_region->start >> 20; + + ret = ath10k_pci_set_ram_config(ar, shift); + if (ret) { + ath10k_warn(ar, "failed to switch ram config to IRAM for section %s: %d\n", + current_region->name, ret); + break; + } + } + + /* Reserve space for the header. */ + hdr = (void *)buf; + buf += sizeof(*hdr); + buf_len -= sizeof(*hdr); + + if (current_region->section_table.size > 0) { + /* Copy each section individually. */ + count = ath10k_pci_dump_memory_section(ar, + current_region, + buf, + current_region->len); + } else { + /* No individiual memory sections defined so we can + * copy the entire memory region. + */ + ret = ath10k_pci_diag_read_mem(ar, + current_region->start, + buf, + current_region->len); + if (ret) { + ath10k_warn(ar, "failed to copy ramdump region %s: %d\n", + current_region->name, ret); + break; + } + + count = current_region->len; + } + + hdr->region_type = cpu_to_le32(current_region->type); + hdr->start = cpu_to_le32(current_region->start); + hdr->length = cpu_to_le32(count); + + if (count == 0) + /* Note: the header remains, just with zero length. */ + break; + + buf += count; + buf_len -= count; + + current_region++; + } +} + static void ath10k_pci_fw_crashed_dump(struct ath10k *ar) { struct ath10k_fw_crash_data *crash_data; @@ -1481,6 +1698,7 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar) ath10k_print_driver_info(ar); ath10k_pci_dump_registers(ar, crash_data); ath10k_ce_dump_registers(ar, crash_data); + ath10k_pci_dump_memory(ar, crash_data); spin_unlock_bh(&ar->data_lock); From 6b8ddfde6cacf941947d1d933ea03649e5c157b7 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 22 Dec 2017 15:39:58 +0200 Subject: [PATCH 022/192] UPSTREAM: ath10k: add memory dump support QCA988X Copy two regions of registers and bigger DRAM region to the dump file. Signed-off-by: Kalle Valo Git-commit: 1a8e5c618bfa66baea195df0e20b0e40cf9825a1 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I81bfa77097814211b62f8f056fd5a7931dfef01c Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/coredump.c | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c index 2f4cb6c473f5..4dde126dab17 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.c +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -667,6 +667,39 @@ static const struct ath10k_mem_region qca6174_hw30_mem_regions[] = { }, }; +static const struct ath10k_mem_region qca988x_hw20_mem_regions[] = { + { + .type = ATH10K_MEM_REGION_TYPE_DRAM, + .start = 0x400000, + .len = 0x50000, + .name = "DRAM", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_REG, + .start = 0x4000, + .len = 0x2000, + .name = "REG_PART1", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_REG, + .start = 0x8000, + .len = 0x58000, + .name = "REG_PART2", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, +}; + static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { { .hw_id = QCA6174_HW_1_0_VERSION, @@ -717,6 +750,13 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { .size = ARRAY_SIZE(qca6174_hw30_mem_regions), }, }, + { + .hw_id = QCA988X_HW_2_0_VERSION, + .region_table = { + .regions = qca988x_hw20_mem_regions, + .size = ARRAY_SIZE(qca988x_hw20_mem_regions), + }, + }, }; static u32 ath10k_coredump_get_ramdump_size(struct ath10k *ar) From 6b8b5b039b9aba2a99d8230d4ad7cc87bccacaba Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 22 Dec 2017 18:31:13 +0200 Subject: [PATCH 023/192] BACKPORT: UPSTREAM: ath10k: update copyright year Update year for Qualcomm Atheros, Inc. copyrights. Signed-off-by: Kalle Valo [dundi@codeaurora.org: dropped drivers/net/wireless/ath/ath10k/debug.c as it has updated copyright year] Git-commit: 8b1083d6188222c5efceb120b3334f0d8527c215 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I5bb016eba98428bceea28766178241251984d236 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/ahb.c | 2 +- drivers/net/wireless/ath/ath10k/bmi.c | 2 +- drivers/net/wireless/ath/ath10k/bmi.h | 2 +- drivers/net/wireless/ath/ath10k/ce.c | 2 +- drivers/net/wireless/ath/ath10k/ce.h | 2 +- drivers/net/wireless/ath/ath10k/core.c | 2 +- drivers/net/wireless/ath/ath10k/core.h | 2 +- drivers/net/wireless/ath/ath10k/debug.h | 2 +- drivers/net/wireless/ath/ath10k/debugfs_sta.c | 2 +- drivers/net/wireless/ath/ath10k/hif.h | 2 +- drivers/net/wireless/ath/ath10k/htc.c | 2 +- drivers/net/wireless/ath/ath10k/htc.h | 2 +- drivers/net/wireless/ath/ath10k/htt.c | 2 +- drivers/net/wireless/ath/ath10k/htt.h | 2 +- drivers/net/wireless/ath/ath10k/htt_rx.c | 2 +- drivers/net/wireless/ath/ath10k/htt_tx.c | 2 +- drivers/net/wireless/ath/ath10k/hw.c | 2 +- drivers/net/wireless/ath/ath10k/hw.h | 2 +- drivers/net/wireless/ath/ath10k/mac.c | 2 +- drivers/net/wireless/ath/ath10k/mac.h | 2 +- drivers/net/wireless/ath/ath10k/pci.c | 2 +- drivers/net/wireless/ath/ath10k/pci.h | 2 +- drivers/net/wireless/ath/ath10k/rx_desc.h | 2 +- drivers/net/wireless/ath/ath10k/spectral.c | 2 +- drivers/net/wireless/ath/ath10k/spectral.h | 2 +- drivers/net/wireless/ath/ath10k/swap.c | 2 +- drivers/net/wireless/ath/ath10k/swap.h | 2 +- drivers/net/wireless/ath/ath10k/targaddrs.h | 2 +- drivers/net/wireless/ath/ath10k/testmode.c | 2 +- drivers/net/wireless/ath/ath10k/testmode_i.h | 2 +- drivers/net/wireless/ath/ath10k/thermal.c | 2 +- drivers/net/wireless/ath/ath10k/thermal.h | 2 +- drivers/net/wireless/ath/ath10k/trace.h | 2 +- drivers/net/wireless/ath/ath10k/txrx.c | 2 +- drivers/net/wireless/ath/ath10k/txrx.h | 2 +- drivers/net/wireless/ath/ath10k/wmi-ops.h | 2 +- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2 +- drivers/net/wireless/ath/ath10k/wmi-tlv.h | 2 +- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- drivers/net/wireless/ath/ath10k/wmi.h | 2 +- drivers/net/wireless/ath/ath10k/wow.c | 2 +- drivers/net/wireless/ath/ath10k/wow.h | 2 +- 42 files changed, 42 insertions(+), 42 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index ff6815e95684..35d10490f6c3 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Qualcomm Atheros, Inc. All rights reserved. + * Copyright (c) 2016-2017 Qualcomm Atheros, Inc. All rights reserved. * Copyright (c) 2015 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c index 2d3a2f31123d..af4978d6a14b 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.c +++ b/drivers/net/wireless/ath/ath10k/bmi.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2014,2016-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index 9c0839b2ca8f..9a396817aa55 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2015,2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 48314b8fc2c3..b9def7bace2f 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index be1d218c6540..06ac2eb70bf5 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index ea432f10cb38..51444d34a06c 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 163cbc746f62..fe6b30356d3b 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 58046f89dc52..e54308889e59 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index ff96f70d2282..b260b09dd4d3 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index 6679dd9cfd12..6da4e3369c5a 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2015,2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index e5c80f582ff5..492dc5b4bbf2 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index 24663b07eeac..a2f8814b3e53 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 764fb2620ad7..625198dea18b 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 3d493d7578ca..783640032216 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 81a236a20acd..717110481b88 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 80df91b5ae11..b204d1ebfd63 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index e0e75471e04c..d8a199448386 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index ab0cc2de6f68..a8be98f1eb41 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 2ba5d058de7c..b7ebe21b7f5d 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h index 553747bc19ed..81f8d6c0af35 100644 --- a/drivers/net/wireless/ath/ath10k/mac.h +++ b/drivers/net/wireless/ath/ath10k/mac.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index b0db754cfe81..3231abebce2b 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 424ff323b2dc..652bb0502680 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index 210e4b1659e7..545deb6d7af1 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c index dd9cc0939ea8..62edb1c686fc 100644 --- a/drivers/net/wireless/ath/ath10k/spectral.c +++ b/drivers/net/wireless/ath/ath10k/spectral.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Qualcomm Atheros, Inc. + * Copyright (c) 2013-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/spectral.h b/drivers/net/wireless/ath/ath10k/spectral.h index b2a2e8ae04b8..13276f4dc12c 100644 --- a/drivers/net/wireless/ath/ath10k/spectral.h +++ b/drivers/net/wireless/ath/ath10k/spectral.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Qualcomm Atheros, Inc. + * Copyright (c) 2013-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/swap.c b/drivers/net/wireless/ath/ath10k/swap.c index adf4592374b4..e7f57efadae1 100644 --- a/drivers/net/wireless/ath/ath10k/swap.c +++ b/drivers/net/wireless/ath/ath10k/swap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Qualcomm Atheros, Inc. + * Copyright (c) 2015-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/swap.h b/drivers/net/wireless/ath/ath10k/swap.h index f5dc0476493e..fa602f15fa93 100644 --- a/drivers/net/wireless/ath/ath10k/swap.h +++ b/drivers/net/wireless/ath/ath10k/swap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Qualcomm Atheros, Inc. + * Copyright (c) 2015-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h index 8bded5da9d0d..c2b5bad0459b 100644 --- a/drivers/net/wireless/ath/ath10k/targaddrs.h +++ b/drivers/net/wireless/ath/ath10k/targaddrs.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/testmode.c b/drivers/net/wireless/ath/ath10k/testmode.c index 9d3eb258ac2f..568810b41657 100644 --- a/drivers/net/wireless/ath/ath10k/testmode.c +++ b/drivers/net/wireless/ath/ath10k/testmode.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/testmode_i.h b/drivers/net/wireless/ath/ath10k/testmode_i.h index 191a8f34c8ea..6514d1a14242 100644 --- a/drivers/net/wireless/ath/ath10k/testmode_i.h +++ b/drivers/net/wireless/ath/ath10k/testmode_i.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. + * Copyright (c) 2014,2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c index ef717b631ff8..aa8978a8d751 100644 --- a/drivers/net/wireless/ath/ath10k/thermal.c +++ b/drivers/net/wireless/ath/ath10k/thermal.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/thermal.h b/drivers/net/wireless/ath/ath10k/thermal.h index 3abb97f63b1e..65e2419543f9 100644 --- a/drivers/net/wireless/ath/ath10k/thermal.h +++ b/drivers/net/wireless/ath/ath10k/thermal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h index 5b974bb76e6c..7d2fac342150 100644 --- a/drivers/net/wireless/ath/ath10k/trace.h +++ b/drivers/net/wireless/ath/ath10k/trace.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index d4986f626c35..5b3b021526ab 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/txrx.h b/drivers/net/wireless/ath/ath10k/txrx.h index e7ea1ae1c438..2bf401e436d3 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.h +++ b/drivers/net/wireless/ath/ath10k/txrx.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2014,2016 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 41eef942ab2c..14093cfdc505 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index b3098ee01bcb..9d21454631c4 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 90524b779a5d..e956574afbac 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index ab8eb9cdfda0..4d73f3664878 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 2718bbc5cef7..bda6e7c786cf 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. - * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c index 0d46d6dc7578..c4cbccb29b31 100644 --- a/drivers/net/wireless/ath/ath10k/wow.c +++ b/drivers/net/wireless/ath/ath10k/wow.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Qualcomm Atheros, Inc. + * Copyright (c) 2015-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath10k/wow.h b/drivers/net/wireless/ath/ath10k/wow.h index 9745b9ddc7f5..6e810105b775 100644 --- a/drivers/net/wireless/ath/ath10k/wow.h +++ b/drivers/net/wireless/ath/ath10k/wow.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Qualcomm Atheros, Inc. + * Copyright (c) 2015,2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above From 873d4fc2da0ac2e21d9d6f5d6c7f3f739b535975 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:11 +0300 Subject: [PATCH 024/192] UPSTREAM: ath10k: build ce layer in ath10k core module CE layer is shared between pci and snoc target and results in duplicate object inclusion if both modules are compiled together statically and undefined KBUILD_MODNAME if compiled as module. Fix this by building ce layer in ath10k core module by adding ce object inclusion with ATH10K_CE boolean CONFIG. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: a0aedd6e0b5755a4c1cf288744a0fbef667f9f8f Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: Ica1cbb9b966de7b1dc47d47958388559020b999f Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/Kconfig | 4 ++++ drivers/net/wireless/ath/ath10k/Makefile | 4 ++-- drivers/net/wireless/ath/ath10k/ce.c | 22 ++++++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index deb5ae21a559..d266f2792dae 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -4,12 +4,16 @@ config ATH10K select ATH_COMMON select CRC32 select WANT_DEV_COREDUMP + select ATH10K_CE ---help--- This module adds support for wireless adapters based on Atheros IEEE 802.11ac family of chipsets. If you choose to build a module, it'll be called ath10k. +config ATH10K_CE + bool + config ATH10K_PCI tristate "Atheros ath10k PCI support" depends on ATH10K && PCI diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 6739ac26fd29..536f3dfb9364 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -22,10 +22,10 @@ ath10k_core-$(CONFIG_THERMAL) += thermal.o ath10k_core-$(CONFIG_MAC80211_DEBUGFS) += debugfs_sta.o ath10k_core-$(CONFIG_PM) += wow.o ath10k_core-$(CONFIG_DEV_COREDUMP) += coredump.o +ath10k_core-$(CONFIG_ATH10K_CE) += ce.o obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o -ath10k_pci-y += pci.o \ - ce.o +ath10k_pci-y += pci.o ath10k_pci-$(CONFIG_ATH10K_AHB) += ahb.o diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index b9def7bace2f..e7e7b342e5b8 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -464,6 +464,7 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, return ce_state->ops->ce_send_nolock(ce_state, per_transfer_context, buffer, nbytes, transfer_id, flags); } +EXPORT_SYMBOL(ath10k_ce_send_nolock); void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe) { @@ -491,6 +492,7 @@ void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe) src_ring->per_transfer_context[src_ring->write_index] = NULL; } +EXPORT_SYMBOL(__ath10k_ce_send_revert); int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, void *per_transfer_context, @@ -510,6 +512,7 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, return ret; } +EXPORT_SYMBOL(ath10k_ce_send); int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe) { @@ -525,6 +528,7 @@ int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe) return delta; } +EXPORT_SYMBOL(ath10k_ce_num_free_src_entries); int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe) { @@ -539,6 +543,7 @@ int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe) return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1); } +EXPORT_SYMBOL(__ath10k_ce_rx_num_free_bufs); static int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, dma_addr_t paddr) @@ -622,6 +627,7 @@ void ath10k_ce_rx_update_write_idx(struct ath10k_ce_pipe *pipe, u32 nentries) ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index); dest_ring->write_index = write_index; } +EXPORT_SYMBOL(ath10k_ce_rx_update_write_idx); int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, dma_addr_t paddr) @@ -636,6 +642,7 @@ int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, return ret; } +EXPORT_SYMBOL(ath10k_ce_rx_post_buf); /* * Guts of ath10k_ce_completed_recv_next. @@ -748,6 +755,7 @@ int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state, per_transfer_ctx, nbytesp); } +EXPORT_SYMBOL(ath10k_ce_completed_recv_next_nolock); int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state, void **per_transfer_contextp, @@ -766,6 +774,7 @@ int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state, return ret; } +EXPORT_SYMBOL(ath10k_ce_completed_recv_next); static int _ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, void **per_transfer_contextp, @@ -882,6 +891,7 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, per_transfer_contextp, bufferp); } +EXPORT_SYMBOL(ath10k_ce_revoke_recv_next); /* * Guts of ath10k_ce_completed_send_next. @@ -936,6 +946,7 @@ int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, return 0; } +EXPORT_SYMBOL(ath10k_ce_completed_send_next_nolock); static void ath10k_ce_extract_desc_data(struct ath10k *ar, struct ath10k_ce_ring *src_ring, @@ -1025,6 +1036,7 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state, return ret; } +EXPORT_SYMBOL(ath10k_ce_cancel_send_next); int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state, void **per_transfer_contextp) @@ -1040,6 +1052,7 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state, return ret; } +EXPORT_SYMBOL(ath10k_ce_completed_send_next); /* * Guts of interrupt handler for per-engine interrupts on a particular CE. @@ -1078,6 +1091,7 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) spin_unlock_bh(&ce->ce_lock); } +EXPORT_SYMBOL(ath10k_ce_per_engine_service); /* * Handler for per-engine interrupts on ALL active CEs. @@ -1102,6 +1116,7 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar) ath10k_ce_per_engine_service(ar, ce_id); } } +EXPORT_SYMBOL(ath10k_ce_per_engine_service_any); /* * Adjust interrupts for the copy complete handler. @@ -1139,6 +1154,7 @@ int ath10k_ce_disable_interrupts(struct ath10k *ar) return 0; } +EXPORT_SYMBOL(ath10k_ce_disable_interrupts); void ath10k_ce_enable_interrupts(struct ath10k *ar) { @@ -1154,6 +1170,7 @@ void ath10k_ce_enable_interrupts(struct ath10k *ar) ath10k_ce_per_engine_handler_adjust(ce_state); } } +EXPORT_SYMBOL(ath10k_ce_enable_interrupts); static int ath10k_ce_init_src_ring(struct ath10k *ar, unsigned int ce_id, @@ -1454,6 +1471,7 @@ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, return 0; } +EXPORT_SYMBOL(ath10k_ce_init_pipe); static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id) { @@ -1479,6 +1497,7 @@ void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id) ath10k_ce_deinit_src_ring(ar, ce_id); ath10k_ce_deinit_dest_ring(ar, ce_id); } +EXPORT_SYMBOL(ath10k_ce_deinit_pipe); static void _ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) { @@ -1545,6 +1564,7 @@ void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) ce_state->ops->ce_free_pipe(ar, ce_id); } +EXPORT_SYMBOL(ath10k_ce_free_pipe); void ath10k_ce_dump_registers(struct ath10k *ar, struct ath10k_fw_crash_data *crash_data) @@ -1584,6 +1604,7 @@ void ath10k_ce_dump_registers(struct ath10k *ar, spin_unlock_bh(&ce->ce_lock); } +EXPORT_SYMBOL(ath10k_ce_dump_registers); static const struct ath10k_ce_ops ce_ops = { .ce_alloc_src_ring = ath10k_ce_alloc_src_ring, @@ -1680,3 +1701,4 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, return 0; } +EXPORT_SYMBOL(ath10k_ce_alloc_pipe); From a2154a703d82c9e0c52853f505d3cdb9462084a2 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:14 +0300 Subject: [PATCH 025/192] UPSTREAM: ath10k: platform driver for WCN3990 SNOC WLAN module WCN3990 is integrated 802.11ac chipset with SNOC bus interface. Add snoc layer driver registration and associated ops. WCN3990 support is not yet complete as cold-boot handshake is done using qmi(Qualcomm-MSM-Interface) and qmi client support will be added once qmi framework is available. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: 17f5559e0da51a8780cd93206689f05feca46615 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I5cded8dcb525e155957299ef803c23de7348a37d Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/Kconfig | 8 ++ drivers/net/wireless/ath/ath10k/Makefile | 3 + drivers/net/wireless/ath/ath10k/snoc.c | 153 +++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/snoc.h | 76 +++++++++++ 4 files changed, 240 insertions(+) create mode 100644 drivers/net/wireless/ath/ath10k/snoc.c create mode 100644 drivers/net/wireless/ath/ath10k/snoc.h diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index d266f2792dae..84f071ac0d84 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -40,6 +40,14 @@ config ATH10K_USB This module adds experimental support for USB bus. Currently work in progress and will not fully work. +config ATH10K_SNOC + tristate "Qualcomm ath10k SNOC support (EXPERIMENTAL)" + depends on ATH10K && ARCH_QCOM + ---help--- + This module adds support for integrated WCN3990 chip connected + to system NOC(SNOC). Currently work in progress and will not + fully work. + config ATH10K_DEBUG bool "Atheros ath10k debugging" depends on ATH10K diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 536f3dfb9364..44d60a61b242 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -35,5 +35,8 @@ ath10k_sdio-y += sdio.o obj-$(CONFIG_ATH10K_USB) += ath10k_usb.o ath10k_usb-y += usb.o +obj-$(CONFIG_ATH10K_SNOC) += ath10k_snoc.o +ath10k_snoc-y += snoc.o + # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c new file mode 100644 index 000000000000..30354a653b62 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include "debug.h" +#include "hif.h" +#include "htc.h" +#include "ce.h" +#include "snoc.h" +#include +#include +#include + +static const struct ath10k_snoc_drv_priv drv_priv = { + .hw_rev = ATH10K_HW_WCN3990, + .dma_mask = DMA_BIT_MASK(37), +}; + +void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + + iowrite32(value, ar_snoc->mem + offset); +} + +u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + u32 val; + + val = ioread32(ar_snoc->mem + offset); + + return val; +} + +static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { + .read32 = ath10k_snoc_read32, + .write32 = ath10k_snoc_write32, +}; + +static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { + .read32 = ath10k_snoc_read32, + .write32 = ath10k_snoc_write32, +}; + +static const struct of_device_id ath10k_snoc_dt_match[] = { + { .compatible = "qcom,wcn3990-wifi", + .data = &drv_priv, + }, + { } +}; +MODULE_DEVICE_TABLE(of, ath10k_snoc_dt_match); + +static int ath10k_snoc_probe(struct platform_device *pdev) +{ + const struct ath10k_snoc_drv_priv *drv_data; + const struct of_device_id *of_id; + struct ath10k_snoc *ar_snoc; + struct device *dev; + struct ath10k *ar; + int ret; + + of_id = of_match_device(ath10k_snoc_dt_match, &pdev->dev); + if (!of_id) { + dev_err(&pdev->dev, "failed to find matching device tree id\n"); + return -EINVAL; + } + + drv_data = of_id->data; + dev = &pdev->dev; + + ret = dma_set_mask_and_coherent(dev, drv_data->dma_mask); + if (ret) { + dev_err(dev, "failed to set dma mask: %d", ret); + return ret; + } + + ar = ath10k_core_create(sizeof(*ar_snoc), dev, ATH10K_BUS_SNOC, + drv_data->hw_rev, &ath10k_snoc_hif_ops); + if (!ar) { + dev_err(dev, "failed to allocate core\n"); + return -ENOMEM; + } + + ar_snoc = ath10k_snoc_priv(ar); + ar_snoc->dev = pdev; + platform_set_drvdata(pdev, ar); + ar_snoc->ar = ar; + ar_snoc->ce.bus_ops = &ath10k_snoc_bus_ops; + ar->ce_priv = &ar_snoc->ce; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n"); + ath10k_warn(ar, "Warning: SNOC support is still work-in-progress, it will not work properly!"); + + return ret; +} + +static int ath10k_snoc_remove(struct platform_device *pdev) +{ + struct ath10k *ar = platform_get_drvdata(pdev); + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc remove\n"); + ath10k_core_destroy(ar); + + return 0; +} + +static struct platform_driver ath10k_snoc_driver = { + .probe = ath10k_snoc_probe, + .remove = ath10k_snoc_remove, + .driver = { + .name = "ath10k_snoc", + .owner = THIS_MODULE, + .of_match_table = ath10k_snoc_dt_match, + }, +}; + +static int __init ath10k_snoc_init(void) +{ + int ret; + + ret = platform_driver_register(&ath10k_snoc_driver); + if (ret) + pr_err("failed to register ath10k snoc driver: %d\n", + ret); + + return ret; +} +module_init(ath10k_snoc_init); + +static void __exit ath10k_snoc_exit(void) +{ + platform_driver_unregister(&ath10k_snoc_driver); +} +module_exit(ath10k_snoc_exit); + +MODULE_AUTHOR("Qualcomm"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("Driver support for Atheros WCN3990 SNOC devices"); diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h new file mode 100644 index 000000000000..cf65b01e0085 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SNOC_H_ +#define _SNOC_H_ + +#include "hw.h" +#include "ce.h" +#include "pci.h" + +struct ath10k_snoc_drv_priv { + enum ath10k_hw_rev hw_rev; + u64 dma_mask; +}; + +struct snoc_state { + u32 pipe_cfg_addr; + u32 svc_to_pipe_map; +}; + +struct ath10k_snoc_pipe { + struct ath10k_ce_pipe *ce_hdl; + u8 pipe_num; + struct ath10k *hif_ce_state; + size_t buf_sz; + /* protect ce info */ + spinlock_t pipe_lock; + struct ath10k_snoc *ar_snoc; +}; + +struct ath10k_snoc_target_info { + u32 target_version; + u32 target_type; + u32 target_revision; + u32 soc_version; +}; + +struct ath10k_snoc_ce_irq { + u32 irq_line; +}; + +struct ath10k_snoc { + struct platform_device *dev; + struct ath10k *ar; + void __iomem *mem; + dma_addr_t mem_pa; + struct ath10k_snoc_target_info target_info; + size_t mem_len; + struct ath10k_snoc_pipe pipe_info[CE_COUNT_MAX]; + struct ath10k_snoc_ce_irq ce_irqs[CE_COUNT_MAX]; + struct ath10k_ce ce; + struct timer_list rx_post_retry; +}; + +static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) +{ + return (struct ath10k_snoc *)ar->drv_priv; +} + +void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value); +u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset); + +#endif /* _SNOC_H_ */ From fd7667adbbad537b979329c17e28b214df9d7c84 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:15 +0300 Subject: [PATCH 026/192] UPSTREAM: ath10k: add resource init and deinit for WCN3990 Add methods for resource(memory, irq, HOST CE config) initialization and de-initialization for WCN3990 target. WCN3990 target uses 12 copy engine and following CE config. [CE0] :host->target control and raw streams [CE1] :target->host HTT [CE2] :target->host WMI [CE3] :host->target WMI [CE4] :host->target HTT [CE5] :reserved [CE6] :Target autonomous HIF_memcpy [CE7] :reserved [CE8] :reserved [CE9] :target->host HTT [CE10] :target->host HTT [CE11] :target -> host PKTLOG Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: c963a683e70151dc458e9a85ed4b366b09f65e57 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: Ie7fa743f00cf7ff66b62cff81ea53e199531dff9 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/snoc.c | 271 +++++++++++++++++++++++++ 1 file changed, 271 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 30354a653b62..575355ce675f 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -24,12 +24,135 @@ #include #include #include +#define WCN3990_CE_ATTR_FLAGS 0 + +static char *const ce_name[] = { + "WLAN_CE_0", + "WLAN_CE_1", + "WLAN_CE_2", + "WLAN_CE_3", + "WLAN_CE_4", + "WLAN_CE_5", + "WLAN_CE_6", + "WLAN_CE_7", + "WLAN_CE_8", + "WLAN_CE_9", + "WLAN_CE_10", + "WLAN_CE_11", +}; static const struct ath10k_snoc_drv_priv drv_priv = { .hw_rev = ATH10K_HW_WCN3990, .dma_mask = DMA_BIT_MASK(37), }; +static struct ce_attr host_ce_config_wlan[] = { + /* CE0: host->target HTC control streams */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 16, + .src_sz_max = 2048, + .dest_nentries = 0, + .send_cb = NULL, + }, + + /* CE1: target->host HTT + HTC control */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 512, + .recv_cb = NULL, + }, + + /* CE2: target->host WMI */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 64, + .recv_cb = NULL, + }, + + /* CE3: host->target WMI */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 32, + .src_sz_max = 2048, + .dest_nentries = 0, + .send_cb = NULL, + }, + + /* CE4: host->target HTT */ + { + .flags = WCN3990_CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, + .src_nentries = 256, + .src_sz_max = 256, + .dest_nentries = 0, + .send_cb = NULL, + }, + + /* CE5: target->host HTT (ipa_uc->target ) */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 512, + .dest_nentries = 512, + .recv_cb = NULL, + }, + + /* CE6: target autonomous hif_memcpy */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 0, + .dest_nentries = 0, + }, + + /* CE7: ce_diag, the Diagnostic Window */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 2, + .src_sz_max = 2048, + .dest_nentries = 2, + }, + + /* CE8: Target to uMC */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 128, + }, + + /* CE9 target->host HTT */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 512, + .recv_cb = NULL, + }, + + /* CE10: target->host HTT */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 512, + .recv_cb = NULL, + }, + + /* CE11: target -> host PKTLOG */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 512, + .recv_cb = NULL, + }, +}; + void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); @@ -57,6 +180,119 @@ static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { .write32 = ath10k_snoc_write32, }; +static irqreturn_t ath10k_snoc_per_engine_handler(int irq, void *arg) +{ + return IRQ_HANDLED; +} + +static int ath10k_snoc_request_irq(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + int irqflags = IRQF_TRIGGER_RISING; + int ret, id; + + for (id = 0; id < CE_COUNT_MAX; id++) { + ret = request_irq(ar_snoc->ce_irqs[id].irq_line, + ath10k_snoc_per_engine_handler, + irqflags, ce_name[id], ar); + if (ret) { + ath10k_err(ar, + "failed to register IRQ handler for CE %d: %d", + id, ret); + goto err_irq; + } + } + + return 0; + +err_irq: + for (id -= 1; id >= 0; id--) + free_irq(ar_snoc->ce_irqs[id].irq_line, ar); + + return ret; +} + +static void ath10k_snoc_free_irq(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + int id; + + for (id = 0; id < CE_COUNT_MAX; id++) + free_irq(ar_snoc->ce_irqs[id].irq_line, ar); +} + +static int ath10k_snoc_resource_init(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct platform_device *pdev; + struct resource *res; + int i, ret = 0; + + pdev = ar_snoc->dev; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "membase"); + if (!res) { + ath10k_err(ar, "Memory base not found in DT\n"); + return -EINVAL; + } + + ar_snoc->mem_pa = res->start; + ar_snoc->mem = devm_ioremap(&pdev->dev, ar_snoc->mem_pa, + resource_size(res)); + if (!ar_snoc->mem) { + ath10k_err(ar, "Memory base ioremap failed with physical address %pa\n", + &ar_snoc->mem_pa); + return -EINVAL; + } + + for (i = 0; i < CE_COUNT; i++) { + res = platform_get_resource(ar_snoc->dev, IORESOURCE_IRQ, i); + if (!res) { + ath10k_err(ar, "failed to get IRQ%d\n", i); + ret = -ENODEV; + goto out; + } + ar_snoc->ce_irqs[i].irq_line = res->start; + } + +out: + return ret; +} + +static int ath10k_snoc_setup_resource(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_snoc_pipe *pipe; + int i, ret; + + spin_lock_init(&ce->ce_lock); + for (i = 0; i < CE_COUNT; i++) { + pipe = &ar_snoc->pipe_info[i]; + pipe->ce_hdl = &ce->ce_states[i]; + pipe->pipe_num = i; + pipe->hif_ce_state = ar; + + ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]); + if (ret) { + ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n", + i, ret); + return ret; + } + + pipe->buf_sz = host_ce_config_wlan[i].src_sz_max; + } + + return 0; +} + +static void ath10k_snoc_release_resource(struct ath10k *ar) +{ + int i; + + for (i = 0; i < CE_COUNT; i++) + ath10k_ce_free_pipe(ar, i); +} + static const struct of_device_id ath10k_snoc_dt_match[] = { { .compatible = "qcom,wcn3990-wifi", .data = &drv_priv, @@ -103,9 +339,41 @@ static int ath10k_snoc_probe(struct platform_device *pdev) ar_snoc->ce.bus_ops = &ath10k_snoc_bus_ops; ar->ce_priv = &ar_snoc->ce; + ath10k_snoc_resource_init(ar); + if (ret) { + ath10k_warn(ar, "failed to initialize resource: %d\n", ret); + goto err_core_destroy; + } + + ath10k_snoc_setup_resource(ar); + if (ret) { + ath10k_warn(ar, "failed to setup resource: %d\n", ret); + goto err_core_destroy; + } + ret = ath10k_snoc_request_irq(ar); + if (ret) { + ath10k_warn(ar, "failed to request irqs: %d\n", ret); + goto err_release_resource; + } + ret = ath10k_core_register(ar, drv_data->hw_rev); + if (ret) { + ath10k_err(ar, "failed to register driver core: %d\n", ret); + goto err_free_irq; + } ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n"); ath10k_warn(ar, "Warning: SNOC support is still work-in-progress, it will not work properly!"); + return 0; + +err_free_irq: + ath10k_snoc_free_irq(ar); + +err_release_resource: + ath10k_snoc_release_resource(ar); + +err_core_destroy: + ath10k_core_destroy(ar); + return ret; } @@ -114,6 +382,9 @@ static int ath10k_snoc_remove(struct platform_device *pdev) struct ath10k *ar = platform_get_drvdata(pdev); ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc remove\n"); + ath10k_core_unregister(ar); + ath10k_snoc_free_irq(ar); + ath10k_snoc_release_resource(ar); ath10k_core_destroy(ar); return 0; From 12ed04dd1432eb985b653b766440326704efad3a Mon Sep 17 00:00:00 2001 From: Gopala Krishna Nuthaki Date: Fri, 26 Jun 2020 12:15:24 +0530 Subject: [PATCH 027/192] drivers: thermal: Re-initialize TSENS controller interrupt configuration If TSENS controller goes to bad state while reading temperature, it invokes TSENS controller re-init code.After controller re-init,it disable all interrupts and reset TSENS critical interrupt related settings. It causes no threshold interrupt or critical interrupt on post controller re-init and it might lead to thermal run away issues. Re-initialize TSENS controller interrupt configuration to enable threshold interrupts and critical interrupt as part of TSENS controller re-init routine. Change-Id: I84b1218ce90ce8e4ae530f93db7c2b4277469781 Signed-off-by: Gopala Krishna Nuthaki --- drivers/thermal/tsens2xxx.c | 122 +++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 52 deletions(-) diff --git a/drivers/thermal/tsens2xxx.c b/drivers/thermal/tsens2xxx.c index 29aca6f3d2d8..209ba04bcc8c 100644 --- a/drivers/thermal/tsens2xxx.c +++ b/drivers/thermal/tsens2xxx.c @@ -83,12 +83,70 @@ static void msm_tsens_convert_temp(int last_temp, int *temp) *temp = last_temp * TSENS_TM_SCALE_DECI_MILLIDEG; } +static int __tsens2xxx_hw_init(struct tsens_device *tmdev) +{ + void __iomem *srot_addr; + void __iomem *sensor_int_mask_addr; + unsigned int srot_val, crit_mask, crit_val; + void __iomem *int_mask_addr; + + srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4); + srot_val = readl_relaxed(srot_addr); + if (!(srot_val & TSENS_EN)) { + pr_err("TSENS device is not enabled\n"); + return -ENODEV; + } + + if (tmdev->ctrl_data->cycle_monitor) { + sensor_int_mask_addr = + TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_tm_addr); + crit_mask = readl_relaxed(sensor_int_mask_addr); + crit_val = TSENS_TM_CRITICAL_CYCLE_MONITOR; + if (tmdev->ctrl_data->cycle_compltn_monitor_mask) + writel_relaxed((crit_mask | crit_val), + (TSENS_TM_CRITICAL_INT_MASK + (tmdev->tsens_tm_addr))); + else + writel_relaxed((crit_mask & ~crit_val), + (TSENS_TM_CRITICAL_INT_MASK + (tmdev->tsens_tm_addr))); + /*Update critical cycle monitoring*/ + mb(); + } + + if (tmdev->ctrl_data->wd_bark) { + sensor_int_mask_addr = + TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_tm_addr); + crit_mask = readl_relaxed(sensor_int_mask_addr); + crit_val = TSENS_TM_CRITICAL_WD_BARK; + if (tmdev->ctrl_data->wd_bark_mask) + writel_relaxed((crit_mask | crit_val), + (TSENS_TM_CRITICAL_INT_MASK + (tmdev->tsens_tm_addr))); + else + writel_relaxed((crit_mask & ~crit_val), + (TSENS_TM_CRITICAL_INT_MASK + (tmdev->tsens_tm_addr))); + /*Update watchdog monitoring*/ + mb(); + } + + int_mask_addr = TSENS_TM_UPPER_LOWER_INT_MASK(tmdev->tsens_tm_addr); + writel_relaxed(TSENS_TM_UPPER_LOWER_INT_DISABLE, int_mask_addr); + + writel_relaxed(TSENS_TM_CRITICAL_INT_EN | + TSENS_TM_UPPER_INT_EN | TSENS_TM_LOWER_INT_EN, + TSENS_TM_INT_EN(tmdev->tsens_tm_addr)); + + return 0; +} + static int tsens2xxx_get_temp(struct tsens_sensor *sensor, int *temp) { struct tsens_device *tmdev = NULL, *tmdev_itr; unsigned int code, ret, tsens_ret; void __iomem *sensor_addr, *trdy; - int last_temp = 0, last_temp2 = 0, last_temp3 = 0, count = 0; + int rc = 0, last_temp = 0, last_temp2 = 0, last_temp3 = 0, count = 0; static atomic_t in_tsens_reinit; if (!sensor) @@ -173,6 +231,13 @@ static int tsens2xxx_get_temp(struct tsens_sensor *sensor, int *temp) /* Notify thermal fwk */ list_for_each_entry(tmdev_itr, &tsens_device_list, list) { + rc = __tsens2xxx_hw_init(tmdev_itr); + if (rc) { + pr_err( + "%s: Failed to re-initialize TSENS controller\n", + __func__); + BUG(); + } queue_work(tmdev_itr->tsens_reinit_work, &tmdev_itr->therm_fwk_notify); } @@ -620,58 +685,11 @@ static int tsens2xxx_hw_sensor_en(struct tsens_device *tmdev, static int tsens2xxx_hw_init(struct tsens_device *tmdev) { - void __iomem *srot_addr; - void __iomem *sensor_int_mask_addr; - unsigned int srot_val, crit_mask, crit_val; - void __iomem *int_mask_addr; - - srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4); - srot_val = readl_relaxed(srot_addr); - if (!(srot_val & TSENS_EN)) { - pr_err("TSENS device is not enabled\n"); - return -ENODEV; - } - - if (tmdev->ctrl_data->cycle_monitor) { - sensor_int_mask_addr = - TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_tm_addr); - crit_mask = readl_relaxed(sensor_int_mask_addr); - crit_val = TSENS_TM_CRITICAL_CYCLE_MONITOR; - if (tmdev->ctrl_data->cycle_compltn_monitor_mask) - writel_relaxed((crit_mask | crit_val), - (TSENS_TM_CRITICAL_INT_MASK - (tmdev->tsens_tm_addr))); - else - writel_relaxed((crit_mask & ~crit_val), - (TSENS_TM_CRITICAL_INT_MASK - (tmdev->tsens_tm_addr))); - /*Update critical cycle monitoring*/ - mb(); - } - - if (tmdev->ctrl_data->wd_bark) { - sensor_int_mask_addr = - TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_tm_addr); - crit_mask = readl_relaxed(sensor_int_mask_addr); - crit_val = TSENS_TM_CRITICAL_WD_BARK; - if (tmdev->ctrl_data->wd_bark_mask) - writel_relaxed((crit_mask | crit_val), - (TSENS_TM_CRITICAL_INT_MASK - (tmdev->tsens_tm_addr))); - else - writel_relaxed((crit_mask & ~crit_val), - (TSENS_TM_CRITICAL_INT_MASK - (tmdev->tsens_tm_addr))); - /*Update watchdog monitoring*/ - mb(); - } - - int_mask_addr = TSENS_TM_UPPER_LOWER_INT_MASK(tmdev->tsens_tm_addr); - writel_relaxed(TSENS_TM_UPPER_LOWER_INT_DISABLE, int_mask_addr); + int rc = 0; - writel_relaxed(TSENS_TM_CRITICAL_INT_EN | - TSENS_TM_UPPER_INT_EN | TSENS_TM_LOWER_INT_EN, - TSENS_TM_INT_EN(tmdev->tsens_tm_addr)); + rc = __tsens2xxx_hw_init(tmdev); + if (rc) + return rc; spin_lock_init(&tmdev->tsens_crit_lock); spin_lock_init(&tmdev->tsens_upp_low_lock); From 31c8b88fa6664fc4793163101a45f06e6ed4742f Mon Sep 17 00:00:00 2001 From: Gopala Krishna Nuthaki Date: Fri, 26 Jun 2020 12:02:03 +0530 Subject: [PATCH 028/192] drivers: thermal: Force notify thermal to re-evaluate TSENS sensors If TSENS controller went to bad state while reading temperature of a sensor, TSENS invokes controller re-init code for all controller and then notifies the thermal framework to re-evaluate thermal for each sensor.But there is a chance that current notification API can bail out without re-evaluating the thermal zone if none of the trips are violated. Notify the thermal framework with proper notification API to force re-evaluate thermal zone and make sure that all sensors are re-enabled next active trips. Change-Id: I0686fabba1ee17de1e859e6fcd3b0af7f40c8e73 Signed-off-by: Gopala Krishna Nuthaki --- drivers/thermal/msm-tsens.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c index c1a52b104991..6f3738a1c2fb 100644 --- a/drivers/thermal/msm-tsens.c +++ b/drivers/thermal/msm-tsens.c @@ -250,7 +250,7 @@ static void tsens_therm_fwk_notify(struct work_struct *work) } TSENS_DBG(tmdev, "Calling trip_temp for sensor %d\n", i); - of_thermal_handle_trip_temp(tmdev->sensor[i].tzd, temp); + of_thermal_handle_trip(tmdev->sensor[i].tzd); } } } From 5c2374b107ab8c580b1a06f35cf7dc5dbba73723 Mon Sep 17 00:00:00 2001 From: Puranam V G Tejaswi Date: Mon, 9 Dec 2019 15:50:54 +0530 Subject: [PATCH 029/192] msm: kgsl: make stats updation atomic There is a chance of messing up per process stats if something like a free and allocation happen at the same time for memory belonging to the same process. Similarly mapsize of memdesc can also go bad because of concurrent access. So make per process stats and mapsize of memdesc atomic. Change-Id: I5da1cf368d523768d0b267b314394612934a620d Signed-off-by: Puranam V G Tejaswi --- drivers/gpu/msm/kgsl.c | 9 +++++---- drivers/gpu/msm/kgsl.h | 4 ++-- drivers/gpu/msm/kgsl_debugfs.c | 7 ++++--- drivers/gpu/msm/kgsl_device.h | 15 ++++++++------- drivers/gpu/msm/kgsl_sharedmem.c | 20 ++++++++++++-------- 5 files changed, 31 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 99313e7285cb..37c54102c5e2 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -528,7 +528,8 @@ static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry) idr_remove(&entry->priv->mem_idr, entry->id); entry->id = 0; - entry->priv->gpumem_mapped -= entry->memdesc.mapsize; + atomic_long_sub(atomic_long_read(&entry->memdesc.mapsize), + &entry->priv->gpumem_mapped); spin_unlock(&entry->priv->mem_lock); @@ -4388,7 +4389,7 @@ kgsl_gpumem_vm_fault(struct vm_fault *vmf) ret = entry->memdesc.ops->vmfault(&entry->memdesc, vmf->vma, vmf); if ((ret == 0) || (ret == VM_FAULT_NOPAGE)) - entry->priv->gpumem_mapped += PAGE_SIZE; + atomic_long_add(PAGE_SIZE, &entry->priv->gpumem_mapped); return ret; } @@ -4768,8 +4769,8 @@ static int kgsl_mmap(struct file *file, struct vm_area_struct *vma) vm_insert_page(vma, addr, page); addr += PAGE_SIZE; } - m->mapsize = m->size; - entry->priv->gpumem_mapped += m->mapsize; + atomic_long_add(m->size, &m->mapsize); + atomic_long_add(m->size, &entry->priv->gpumem_mapped); } vma->vm_file = file; diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 68b761960558..0155f8b8db31 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -233,7 +233,7 @@ struct kgsl_memdesc { uint64_t gpuaddr; phys_addr_t physaddr; uint64_t size; - uint64_t mapsize; + atomic_long_t mapsize; uint64_t pad_to; unsigned int priv; struct sg_table *sgt; diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c index 834706a973d2..47dba924ffdf 100644 --- a/drivers/gpu/msm/kgsl_debugfs.c +++ b/drivers/gpu/msm/kgsl_debugfs.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2008-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2008-2017,2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -163,12 +163,13 @@ static int print_mem_entry(void *data, void *ptr) kgsl_get_egl_counts(entry, &egl_surface_count, &egl_image_count); - seq_printf(s, "%pK %pK %16llu %5d %9s %10s %16s %5d %16llu %6d %6d", + seq_printf(s, "%pK %pK %16llu %5d %9s %10s %16s %5d %16ld %6d %6d", (uint64_t *)(uintptr_t) m->gpuaddr, (unsigned long *) m->useraddr, m->size, entry->id, flags, memtype_str(usermem_type), - usage, (m->sgt ? m->sgt->nents : 0), m->mapsize, + usage, (m->sgt ? m->sgt->nents : 0), + atomic_long_read(&m->mapsize), egl_surface_count, egl_image_count); if (entry->metadata[0] != 0) diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 01bc3ffe7271..99ebd4e3113a 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -474,10 +474,10 @@ struct kgsl_process_private { struct kobject kobj; struct dentry *debug_root; struct { - uint64_t cur; + atomic_long_t cur; uint64_t max; } stats[KGSL_MEM_ENTRY_MAX]; - uint64_t gpumem_mapped; + atomic_long_t gpumem_mapped; struct idr syncsource_idr; spinlock_t syncsource_lock; int fd_count; @@ -571,9 +571,10 @@ struct kgsl_device *kgsl_get_device(int dev_idx); static inline void kgsl_process_add_stats(struct kgsl_process_private *priv, unsigned int type, uint64_t size) { - priv->stats[type].cur += size; - if (priv->stats[type].max < priv->stats[type].cur) - priv->stats[type].max = priv->stats[type].cur; + u64 ret = atomic_long_add_return(size, &priv->stats[type].cur); + + if (ret > priv->stats[type].max) + priv->stats[type].max = ret; add_mm_counter(current->mm, MM_UNRECLAIMABLE, (size >> PAGE_SHIFT)); } @@ -584,7 +585,7 @@ static inline void kgsl_process_sub_stats(struct kgsl_process_private *priv, struct task_struct *task; struct mm_struct *mm; - priv->stats[type].cur -= size; + atomic_long_sub(size, &priv->stats[type].cur); pid_struct = find_get_pid(priv->pid); if (pid_struct) { task = get_pid_task(pid_struct, PIDTYPE_PID); diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index af3fe3e67022..996d79d789f0 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -145,18 +145,21 @@ static ssize_t gpumem_mapped_show(struct kgsl_process_private *priv, int type, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%llu\n", - priv->gpumem_mapped); + return scnprintf(buf, PAGE_SIZE, "%ld\n", + atomic_long_read(&priv->gpumem_mapped)); } static ssize_t gpumem_unmapped_show(struct kgsl_process_private *priv, int type, char *buf) { - if (priv->gpumem_mapped > priv->stats[type].cur) + u64 gpumem_total = atomic_long_read(&priv->stats[type].cur); + u64 gpumem_mapped = atomic_long_read(&priv->gpumem_mapped); + + if (gpumem_mapped > gpumem_total) return -EIO; return scnprintf(buf, PAGE_SIZE, "%llu\n", - priv->stats[type].cur - priv->gpumem_mapped); + gpumem_total - gpumem_mapped); } static struct kgsl_mem_entry_attribute debug_memstats[] = { @@ -173,7 +176,8 @@ static struct kgsl_mem_entry_attribute debug_memstats[] = { static ssize_t mem_entry_show(struct kgsl_process_private *priv, int type, char *buf) { - return snprintf(buf, PAGE_SIZE, "%llu\n", priv->stats[type].cur); + return scnprintf(buf, PAGE_SIZE, "%ld\n", + atomic_long_read(&priv->stats[type].cur)); } /** @@ -448,7 +452,7 @@ static int kgsl_page_alloc_vmfault(struct kgsl_memdesc *memdesc, get_page(page); vmf->page = page; - memdesc->mapsize += PAGE_SIZE; + atomic_long_add(PAGE_SIZE, &memdesc->mapsize); return 0; } @@ -619,7 +623,7 @@ static int kgsl_contiguous_vmfault(struct kgsl_memdesc *memdesc, else if (ret == -EFAULT) return VM_FAULT_SIGBUS; - memdesc->mapsize += PAGE_SIZE; + atomic_long_add(PAGE_SIZE, &memdesc->mapsize); return VM_FAULT_NOPAGE; } From c1239639059977cb345c79d3e3e8791ebe18384a Mon Sep 17 00:00:00 2001 From: Sunil Paidimarri Date: Mon, 8 Jun 2020 22:50:35 -0700 Subject: [PATCH 030/192] msm: ethernet : smmu: enable qcom smmu Providing client API to attach smmu Change-Id: I97708a58686a1446651d59bb049e300fac3c52c5 Signed-off-by: Sunil Paidimarri --- .../configs/vendor/sdxprairie-perf_defconfig | 1 + arch/arm/configs/vendor/sdxprairie_defconfig | 1 + drivers/platform/msm/Kconfig | 7 + drivers/platform/msm/Makefile | 1 + drivers/platform/msm/ethernet/Makefile | 1 + drivers/platform/msm/ethernet/qcom_eth_smmu.c | 243 ++++++++++++++++++ include/linux/qcom_eth_smmu.h | 24 ++ 7 files changed, 278 insertions(+) create mode 100644 drivers/platform/msm/ethernet/Makefile create mode 100644 drivers/platform/msm/ethernet/qcom_eth_smmu.c create mode 100644 include/linux/qcom_eth_smmu.h diff --git a/arch/arm/configs/vendor/sdxprairie-perf_defconfig b/arch/arm/configs/vendor/sdxprairie-perf_defconfig index bedcaa4164e9..8258950d193c 100644 --- a/arch/arm/configs/vendor/sdxprairie-perf_defconfig +++ b/arch/arm/configs/vendor/sdxprairie-perf_defconfig @@ -365,6 +365,7 @@ CONFIG_RMNET_IPA3=y CONFIG_ECM_IPA=y CONFIG_RNDIS_IPA=y CONFIG_IPA_UT=y +CONFIG_QCOM_ETHERNET_UTIL=y CONFIG_SPMI_PMIC_CLKDIV=y CONFIG_MSM_CLK_AOP_QMP=y CONFIG_MSM_CLK_RPMH=y diff --git a/arch/arm/configs/vendor/sdxprairie_defconfig b/arch/arm/configs/vendor/sdxprairie_defconfig index 03fa3501ed40..59a0c67acc29 100644 --- a/arch/arm/configs/vendor/sdxprairie_defconfig +++ b/arch/arm/configs/vendor/sdxprairie_defconfig @@ -376,6 +376,7 @@ CONFIG_RMNET_IPA3=y CONFIG_ECM_IPA=y CONFIG_RNDIS_IPA=y CONFIG_IPA_UT=y +CONFIG_QCOM_ETHERNET_UTIL=y CONFIG_SPMI_PMIC_CLKDIV=y CONFIG_MSM_CLK_AOP_QMP=y CONFIG_MSM_CLK_RPMH=y diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig index 5f0d8594a42c..9db918e26173 100644 --- a/drivers/platform/msm/Kconfig +++ b/drivers/platform/msm/Kconfig @@ -268,6 +268,13 @@ config IPA3_REGDUMP This option is to be used when the saving of IPA/GSI register state is desired upon system crash. +config QCOM_ETHERNET_UTIL + bool "ethernet utilities" + depends on PCI + help + This module will provide API's for clients to attach smmu & + other functionalities + choice prompt "Platform whose registers are to be dumped/collected" depends on IPA3_REGDUMP diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile index a62616609422..12c59dc9324e 100644 --- a/drivers/platform/msm/Makefile +++ b/drivers/platform/msm/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_EP_PCIE) += ep_pcie/ obj-$(CONFIG_MSM_MHI_DEV) += mhi_dev/ obj-$(CONFIG_MSM_11AD) += msm_11ad/ obj-$(CONFIG_SEEMP_CORE) += seemp_core/ +obj-$(CONFIG_QCOM_ETHERNET_UTIL) += ethernet/ diff --git a/drivers/platform/msm/ethernet/Makefile b/drivers/platform/msm/ethernet/Makefile new file mode 100644 index 000000000000..bda2e6f994c3 --- /dev/null +++ b/drivers/platform/msm/ethernet/Makefile @@ -0,0 +1 @@ +obj-y += qcom_eth_smmu.o diff --git a/drivers/platform/msm/ethernet/qcom_eth_smmu.c b/drivers/platform/msm/ethernet/qcom_eth_smmu.c new file mode 100644 index 000000000000..e42332609cd7 --- /dev/null +++ b/drivers/platform/msm/ethernet/qcom_eth_smmu.c @@ -0,0 +1,243 @@ +/* Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +#include +#include +#include + +#include + +static int (*vendor_probe_real)(struct pci_dev *, const struct pci_device_id *); +static void (*vendor_remove_real)(struct pci_dev *); + +static int qcom_parse_smmu_attr(struct device *dev, + struct iommu_domain *domain, + const char *key, + enum iommu_attr attr) +{ + int rc = 0; + unsigned int data = 1; + + if (of_find_property(dev->of_node, key, NULL)) { + rc = iommu_domain_set_attr(domain, attr, &data); + if (!rc) + dev_dbg(dev, "enabled SMMU attribute %u\n", attr); + else + dev_err(dev, "failed to set SMMU attribute %u\n", attr); + } + + return rc; +} + +static int qcom_parse_smmu_attrs(struct device *dev, + struct iommu_domain *domain) +{ + int rc = 0; + + rc |= qcom_parse_smmu_attr(dev, domain, + "qcom,smmu-attr-s1-bypass", DOMAIN_ATTR_S1_BYPASS); + + rc |= qcom_parse_smmu_attr(dev, domain, + "qcom,smmu-attr-fastmap", DOMAIN_ATTR_FAST); + + rc |= qcom_parse_smmu_attr(dev, domain, + "qcom,smmu-attr-atomic", DOMAIN_ATTR_ATOMIC); + + rc |= qcom_parse_smmu_attr(dev, domain, + "qcom,smmu-attr-pt-coherent", + DOMAIN_ATTR_PAGE_TABLE_IS_COHERENT); + + rc |= qcom_parse_smmu_attr(dev, domain, + "qcom,smmu-attr-pt-coherent-force", + DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT); + + return rc; +} + +static int __qcom_attach_smmu(struct device *dev) +{ + int rc; + const char *key; + u64 val64; + + dma_addr_t iova_base = 0; + u64 iova_size = 0; + + struct dma_iommu_mapping *mapping = NULL; + + key = "qcom,smmu-iova-base"; + rc = of_property_read_u64(dev->of_node, key, &val64); + if (rc) { + dev_err(dev, "error parsing DT prop %s: %d\n", key, rc); + return rc; + } + + iova_base = (dma_addr_t)val64; + + key = "qcom,smmu-iova-size"; + rc = of_property_read_u64(dev->of_node, key, &val64); + if (rc) { + dev_err(dev, "error parsing DT prop %s: %d\n", key, rc); + return rc; + } + + iova_size = val64; + + dev_dbg(dev, "creating SMMU mapping with base=0x%llx, size=0x%llx\n", + iova_base, iova_size); + + mapping = arm_iommu_create_mapping(dev->bus, iova_base, iova_size); + if (IS_ERR(mapping)) { + dev_err(dev, "failed to create SMMU mapping\n"); + return PTR_ERR(mapping); + } + + rc = qcom_parse_smmu_attrs(dev, mapping->domain); + if (rc) { + dev_err(dev, "error parsing SMMU DT attributes\n"); + goto err_release_mapping; + } + + rc = arm_iommu_attach_device(dev, mapping); + if (rc) { + dev_err(dev, "failed to attach device to smmu\n"); + goto err_release_mapping; + } + + return 0; + +err_release_mapping: + arm_iommu_release_mapping(mapping); + return rc; +} + +static int qcom_attach_smmu(struct device *dev) +{ + bool dt_present = !!of_find_property(dev->of_node, "qcom,smmu", NULL); + bool smmu_attached = !!iommu_get_domain_for_dev(dev); + + if (smmu_attached) { + /* On platforms where IOMMU is attached automatically, we do + * not expect qcom,smmu property to be present in devicetree. + */ + if (dt_present) { + dev_err(dev, "SMMU DT node is not expected\n"); + return -EEXIST; + } + + return 0; + } + + if (!dt_present) { + dev_err(dev, "SMMU DT is required for the device\n"); + return -EFAULT; + } + + return __qcom_attach_smmu(dev); +} + +static void qcom_detach_smmu(struct device *dev) +{ + bool dt_present = !!of_find_property(dev->of_node, "qcom,smmu", NULL); + bool smmu_attached = !!iommu_get_domain_for_dev(dev); + + /* Perform a manual deattach only if we were tasked with doing the + * attach originally. + */ + if (dt_present && smmu_attached) { + struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); + + if (!mapping) { + dev_err(dev, "Failed to retrieve IOMMU mapping\n"); + return; + } + + arm_iommu_detach_device(dev); + arm_iommu_release_mapping(mapping); + } +} + +static int vendor_qcom_probe( + struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int rc; + + rc = qcom_attach_smmu(&pdev->dev); + if (rc) + return rc; + + rc = vendor_probe_real(pdev, id); + if (rc) { + qcom_detach_smmu(&pdev->dev); + return rc; + } + + return 0; +} + +static void vendor_qcom_remove(struct pci_dev *pdev) +{ + vendor_remove_real(pdev); + qcom_detach_smmu(&pdev->dev); +} + +static int __vendor_qcom_register(struct pci_driver *pdrv) +{ + if (vendor_probe_real || vendor_remove_real) { + pr_warn("%s: Driver already registered\n", __func__); + return -EEXIST; + } + + vendor_probe_real = pdrv->probe; + pdrv->probe = vendor_qcom_probe; + + vendor_remove_real = pdrv->remove; + pdrv->remove = vendor_qcom_remove; + + return 0; +} + +static void __vendor_qcom_unregister(struct pci_driver *pdrv) +{ + if (vendor_probe_real) { + pdrv->probe = vendor_probe_real; + vendor_probe_real = NULL; + } + + if (vendor_remove_real) { + pdrv->remove = vendor_remove_real; + vendor_remove_real = NULL; + } +} + +int qcom_smmu_register(struct pci_driver *pdrv) +{ + int rc; + + rc = __vendor_qcom_register(pdrv); + if (rc) + return rc; + + + return 0; +} +EXPORT_SYMBOL(qcom_smmu_register); + +void qcom_smmu_unregister(struct pci_driver *pdrv) +{ + __vendor_qcom_unregister(pdrv); +} +EXPORT_SYMBOL(qcom_smmu_unregister); + diff --git a/include/linux/qcom_eth_smmu.h b/include/linux/qcom_eth_smmu.h new file mode 100644 index 000000000000..53f0a83c648a --- /dev/null +++ b/include/linux/qcom_eth_smmu.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _QCOM_ETH_SMMU_H_ +#define _QCOM_ETH_SMMU_H_ + +#include + + +int qcom_smmu_register(struct pci_driver *pdrv); +void qcom_smmu_unregister(struct pci_driver *pdrv); + + +#endif // _QCOM_ETH_SMMU_H_ + From 49fb2568e33f5f6b6e9a99bfed077515d7dfc6fa Mon Sep 17 00:00:00 2001 From: Ajay Prathi Date: Fri, 3 Jul 2020 15:12:22 +0530 Subject: [PATCH 031/192] msm: sps: Assign proper BAM destination values Fix NOC error caused due to incorrect BAM destination value. Assign correct destination and destination pipe index values to peer BAM. Change-Id: Ifc8f0c308cc388924dce3e32709dad47fc69bf70 Signed-off-by: Ajay Prathi --- drivers/platform/msm/sps/sps_bam.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c index 68f4e3e91c90..3a8ccbdea296 100644 --- a/drivers/platform/msm/sps/sps_bam.c +++ b/drivers/platform/msm/sps/sps_bam.c @@ -899,14 +899,12 @@ int sps_bam_pipe_connect(struct sps_pipe *bam_pipe, peer_bam->props.phys_addr; } if (!(bam_pipe->connect.options & SPS_O_DUMMY_PEER)) { - hw_params.peer_phys_addr = - bam_pipe->connect.destination; - hw_params.peer_pipe = - bam_pipe->connect.dest_pipe_index; + hw_params.peer_pipe = other_pipe->pipe_index; } else { hw_params.peer_phys_addr = bam_pipe->connect.destination; - hw_params.peer_pipe = other_pipe->pipe_index; + hw_params.peer_pipe = + bam_pipe->connect.dest_pipe_index; hw_params.dummy_peer = true; } /* Verify FIFO buffers are allocated for BAM-to-BAM pipes */ From de3dd6296c14aeb40c398312881fe9d0e804d5ca Mon Sep 17 00:00:00 2001 From: Sunil Paidimarri Date: Wed, 17 Jun 2020 12:15:40 -0700 Subject: [PATCH 032/192] ARM : dts : support realtek r8125 ethernet driver Adding PCI ID's for realtek r8125B hardware Change-Id: I74634e907ea25e74cf56e4f628f83ec7de4b77d1 Signed-off-by: Sunil Paidimarri --- Documentation/devicetree/bindings/net/r8125 | 33 ++++++++++++++++ .../boot/dts/qcom/sdxprairie-qcom-smmu.dtsi | 38 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sdxprairie.dtsi | 1 + 3 files changed, 72 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/r8125 create mode 100644 arch/arm64/boot/dts/qcom/sdxprairie-qcom-smmu.dtsi diff --git a/Documentation/devicetree/bindings/net/r8125 b/Documentation/devicetree/bindings/net/r8125 new file mode 100644 index 000000000000..d302869dbb4b --- /dev/null +++ b/Documentation/devicetree/bindings/net/r8125 @@ -0,0 +1,33 @@ +Realtek r8125B Ethernet Controller + +Required properties: + +- compatible : should be "realtek,rtl-8125" + +If SMMU is present, also use: + +- qcom,smmu : if present, SMMU attach is performed +- qcom,smmu-iova-base : SMMU IOVA start address the device can access +- qcom,smmu-iova-size : SMMU IOVA size the device can access + +Optional Properties: + +- qcom,smmu-attr-fastmap : Enables SMMU fastmap +- qcom,smmu-attr-atomic : Enables DMA alloc using GFP_ATOMIC + +Example: + +&pcie_rc0 { + + r8125_x1: qcom,r8125@0 { + compatible = realtek,rtl-8125"; + + qcom,smmu; + qcom,smmu-iova-base = /bits/ 64 <0x0>; + qcom,smmu-iova-size = /bits/ 64 <0x100000000>; + + qcom,smmu-attr-atomic; + qcom,smmu-attr-fastmap; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-qcom-smmu.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-qcom-smmu.dtsi new file mode 100644 index 000000000000..931dc712da90 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdxprairie-qcom-smmu.dtsi @@ -0,0 +1,38 @@ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +&pcie0_rp { + realtek,rtl8125@pcie0_rp { + reg = <0 0 0 0 0>; + + compatible = "realtek,rtl-8125"; + + pci-ids = + "10ec:8125", + "10ec:3000"; + + qcom,smmu; + + /* IOVA range is restricted to avoid conflicts with PCI BAR + * space, Q6 SMEM and IOVA spaces used by peripherals that are + * currently attached to IPA. + */ + qcom,smmu-iova-base = /bits/ 64 <0x80000000>; + qcom,smmu-iova-size = /bits/ 64 <0x0FE40000>; + + qcom,smmu-attr-atomic; + qcom,smmu-attr-fastmap; + + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi index 64e691e37ddc..fba2298fdd93 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi @@ -1544,6 +1544,7 @@ #include "sdxprairie-coresight.dtsi" #include "sdxprairie-aqc.dtsi" #include "sdxprairie-thermal.dtsi" +#include "sdxprairie-qcom-smmu.dtsi" &gdsc_usb30 { status = "ok"; From f4e371ccb1e64d82d0203f7a0f6a4990e4276c1b Mon Sep 17 00:00:00 2001 From: Ajay Prathi Date: Wed, 13 May 2020 16:47:12 +0530 Subject: [PATCH 033/192] mhi: netdev: free memory allocated in read/write Delete the memory while closing channels to avoid memory leak, which is allocated in mhi dev net read and write request. Change-Id: I5605ef5bd498ac934185ce88a3d21e410e0b61b7 Signed-off-by: Ajay Prathi --- drivers/platform/msm/mhi_dev/mhi_dev_net.c | 25 ++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi_dev_net.c b/drivers/platform/msm/mhi_dev/mhi_dev_net.c index d01e15711e18..c61bec66eaf6 100644 --- a/drivers/platform/msm/mhi_dev/mhi_dev_net.c +++ b/drivers/platform/msm/mhi_dev/mhi_dev_net.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "mhi.h" @@ -526,8 +527,6 @@ static int mhi_dev_net_open_chan_create_netif(struct mhi_dev_net_client *client) mhi_dev_net_log(MHI_DBG, "opening OUT %d IN %d channels\n", client->out_chan, client->in_chan); - mutex_lock(&client->out_chan_lock); - mutex_lock(&client->in_chan_lock); mhi_dev_net_log(MHI_DBG, "Initializing inbound chan %d.\n", client->in_chan); @@ -552,8 +551,6 @@ static int mhi_dev_net_open_chan_create_netif(struct mhi_dev_net_client *client) } else atomic_set(&client->tx_enabled, 1); - mutex_unlock(&client->in_chan_lock); - mutex_unlock(&client->out_chan_lock); mhi_dev_net_log(MHI_INFO, "IN %d, OUT %d channels are opened", client->in_chan, client->out_chan); @@ -601,8 +598,8 @@ static int mhi_dev_net_close(void) "mhi_dev_net module is removed\n"); client = mhi_net_ctxt.client_handle; mhi_dev_close_channel(client->out_handle); - mhi_dev_close_channel(client->in_handle); atomic_set(&client->tx_enabled, 0); + mhi_dev_close_channel(client->in_handle); atomic_set(&client->rx_enabled, 0); if (client->dev != NULL) { netif_stop_queue(client->dev); @@ -638,6 +635,18 @@ static int mhi_dev_net_dergstr_client return 0; } +static void mhi_dev_net_free_reqs(struct list_head *buff) +{ + struct list_head *node, *next; + struct mhi_req *mreq; + + list_for_each_safe(node, next, buff) { + mreq = list_entry(node, struct mhi_req, list); + list_del(&mreq->list); + kfree(mreq); + } +} + static void mhi_dev_net_state_cb(struct mhi_dev_client_cb_data *cb_data) { struct mhi_dev_net_client *mhi_client; @@ -686,11 +695,15 @@ static void mhi_dev_net_state_cb(struct mhi_dev_client_cb_data *cb_data) netif_stop_queue(mhi_client->dev); unregister_netdev(mhi_client->dev); mhi_dev_close_channel(mhi_client->out_handle); - mhi_dev_close_channel(mhi_client->in_handle); atomic_set(&mhi_client->tx_enabled, 0); + mhi_dev_close_channel(mhi_client->in_handle); atomic_set(&mhi_client->rx_enabled, 0); + mhi_dev_net_free_reqs(&mhi_client->rx_buffers); + mhi_dev_net_free_reqs(&mhi_client->wr_req_buffers); free_netdev(mhi_client->dev); mhi_client->dev = NULL; + kfree(mhi_client); + kfree(mhi_net_ipc_log); } } } From 13ecbdfa27a88bae4cf05c473a0797f98a1957ed Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Tue, 14 Jul 2020 16:06:57 -0700 Subject: [PATCH 034/192] mhi: core: Prevent extra votes for multiple timesync requests An extra vote is held and not released during cases of multiple or back to back time synchronization requests where the response is still pending and the doorbell is not rung. As only one response is expected, we can safely remove the latest vote placed. Change-Id: I551ac2721af79162959ca301a61657cdf17cf135 Signed-off-by: Bhaumik Bhatt --- drivers/bus/mhi/core/mhi_main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index dd8d4d8c9074..1a783ee59bb2 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -2676,8 +2676,11 @@ int mhi_get_remote_time(struct mhi_device *mhi_dev, tsync_node->cb_func = cb_func; tsync_node->mhi_dev = mhi_dev; - if (mhi_tsync->db_response_pending) + if (mhi_tsync->db_response_pending) { + mhi_device_put(mhi_cntrl->mhi_dev, + MHI_VOTE_DEVICE | MHI_VOTE_BUS); goto skip_tsync_db; + } mhi_tsync->int_sequence++; if (mhi_tsync->int_sequence == 0xFFFFFFFF) From 7d5279ab6acb1457feac493c407ed01715d04eef Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 8 May 2020 12:25:45 -0700 Subject: [PATCH 035/192] f2fs: remove blk_plugging in block_operations blk_plugging doesn't seem to give any benefit. Change-Id: Ia187efe2617823492dabc4b1f77e0fae43c68fab Signed-off-by: Jaegeuk Kim Git-commit: 1f5f11a3c41e2b23288b2769435a00f74e02496b Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git/ Signed-off-by: Sahitya Tummala --- fs/f2fs/checkpoint.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 88e9c3f135b1..047d8c6ce8b1 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -1104,11 +1104,8 @@ static int block_operations(struct f2fs_sb_info *sbi) .nr_to_write = LONG_MAX, .for_reclaim = 0, }; - struct blk_plug plug; int err = 0, cnt = 0; - blk_start_plug(&plug); - retry_flush_quotas: if (__need_flush_quota(sbi)) { int locked; @@ -1140,7 +1137,7 @@ static int block_operations(struct f2fs_sb_info *sbi) f2fs_unlock_all(sbi); err = f2fs_sync_dirty_inodes(sbi, DIR_INODE); if (err) - goto out; + return err; cond_resched(); goto retry_flush_quotas; } @@ -1162,7 +1159,7 @@ static int block_operations(struct f2fs_sb_info *sbi) f2fs_unlock_all(sbi); err = f2fs_sync_inode_meta(sbi); if (err) - goto out; + return err; cond_resched(); goto retry_flush_quotas; } @@ -1178,7 +1175,7 @@ static int block_operations(struct f2fs_sb_info *sbi) if (err) { up_write(&sbi->node_change); f2fs_unlock_all(sbi); - goto out; + return err; } cond_resched(); goto retry_flush_nodes; @@ -1190,8 +1187,6 @@ static int block_operations(struct f2fs_sb_info *sbi) */ __prepare_cp_block(sbi); up_write(&sbi->node_change); -out: - blk_finish_plug(&plug); return err; } From 84f8ac02df56009e0c7bb439d93e8d606967f147 Mon Sep 17 00:00:00 2001 From: Pradeep P V K Date: Thu, 19 Mar 2020 19:18:13 +0800 Subject: [PATCH 036/192] block, bfq: fix use-after-free in bfq_idle_slice_timer_body In bfq_idle_slice_timer func, bfqq = bfqd->in_service_queue is not in bfqd-lock critical section. The bfqq, which is not equal to NULL in bfq_idle_slice_timer, may be freed after passing to bfq_idle_slice_timer_body. So we will access the freed memory. In addition, considering the bfqq may be in race, we should firstly check whether bfqq is in service before doing something on it in bfq_idle_slice_timer_body func. If the bfqq in race is not in service, it means the bfqq has been expired through __bfq_bfqq_expire func, and wait_request flags has been cleared in __bfq_bfqd_reset_in_service func. So we do not need to re-clear the wait_request of bfqq which is not in service. KASAN log is given as follows: [13058.354613] ============================================================== [13058.354640] BUG: KASAN: use-after-free in bfq_idle_slice_timer+0xac/0x290 [13058.354644] Read of size 8 at addr ffffa02cf3e63f78 by task fork13/19767 [13058.354646] [13058.354655] CPU: 96 PID: 19767 Comm: fork13 [13058.354661] Call trace: [13058.354667] dump_backtrace+0x0/0x310 [13058.354672] show_stack+0x28/0x38 [13058.354681] dump_stack+0xd8/0x108 [13058.354687] print_address_description+0x68/0x2d0 [13058.354690] kasan_report+0x124/0x2e0 [13058.354697] __asan_load8+0x88/0xb0 [13058.354702] bfq_idle_slice_timer+0xac/0x290 [13058.354707] __hrtimer_run_queues+0x298/0x8b8 [13058.354710] hrtimer_interrupt+0x1b8/0x678 [13058.354716] arch_timer_handler_phys+0x4c/0x78 [13058.354722] handle_percpu_devid_irq+0xf0/0x558 [13058.354731] generic_handle_irq+0x50/0x70 [13058.354735] __handle_domain_irq+0x94/0x110 [13058.354739] gic_handle_irq+0x8c/0x1b0 [13058.354742] el1_irq+0xb8/0x140 [13058.354748] do_wp_page+0x260/0xe28 [13058.354752] __handle_mm_fault+0x8ec/0x9b0 [13058.354756] handle_mm_fault+0x280/0x460 [13058.354762] do_page_fault+0x3ec/0x890 [13058.354765] do_mem_abort+0xc0/0x1b0 [13058.354768] el0_da+0x24/0x28 [13058.354770] [13058.354773] Allocated by task 19731: [13058.354780] kasan_kmalloc+0xe0/0x190 [13058.354784] kasan_slab_alloc+0x14/0x20 [13058.354788] kmem_cache_alloc_node+0x130/0x440 [13058.354793] bfq_get_queue+0x138/0x858 [13058.354797] bfq_get_bfqq_handle_split+0xd4/0x328 [13058.354801] bfq_init_rq+0x1f4/0x1180 [13058.354806] bfq_insert_requests+0x264/0x1c98 [13058.354811] blk_mq_sched_insert_requests+0x1c4/0x488 [13058.354818] blk_mq_flush_plug_list+0x2d4/0x6e0 [13058.354826] blk_flush_plug_list+0x230/0x548 [13058.354830] blk_finish_plug+0x60/0x80 [13058.354838] read_pages+0xec/0x2c0 [13058.354842] __do_page_cache_readahead+0x374/0x438 [13058.354846] ondemand_readahead+0x24c/0x6b0 [13058.354851] page_cache_sync_readahead+0x17c/0x2f8 [13058.354858] generic_file_buffered_read+0x588/0xc58 [13058.354862] generic_file_read_iter+0x1b4/0x278 [13058.354965] ext4_file_read_iter+0xa8/0x1d8 [ext4] [13058.354972] __vfs_read+0x238/0x320 [13058.354976] vfs_read+0xbc/0x1c0 [13058.354980] ksys_read+0xdc/0x1b8 [13058.354984] __arm64_sys_read+0x50/0x60 [13058.354990] el0_svc_common+0xb4/0x1d8 [13058.354994] el0_svc_handler+0x50/0xa8 [13058.354998] el0_svc+0x8/0xc [13058.354999] [13058.355001] Freed by task 19731: [13058.355007] __kasan_slab_free+0x120/0x228 [13058.355010] kasan_slab_free+0x10/0x18 [13058.355014] kmem_cache_free+0x288/0x3f0 [13058.355018] bfq_put_queue+0x134/0x208 [13058.355022] bfq_exit_icq_bfqq+0x164/0x348 [13058.355026] bfq_exit_icq+0x28/0x40 [13058.355030] ioc_exit_icq+0xa0/0x150 [13058.355035] put_io_context_active+0x250/0x438 [13058.355038] exit_io_context+0xd0/0x138 [13058.355045] do_exit+0x734/0xc58 [13058.355050] do_group_exit+0x78/0x220 [13058.355054] __wake_up_parent+0x0/0x50 [13058.355058] el0_svc_common+0xb4/0x1d8 [13058.355062] el0_svc_handler+0x50/0xa8 [13058.355066] el0_svc+0x8/0xc. Change-Id: I510c704a6f2324741d70db33f0350e14642fe92f Acked-by: Paolo Valente Reported-by: Wang Wang Signed-off-by: Zhiqiang Liu Signed-off-by: Feilong Lin Signed-off-by: Jens Axboe Git-commit: 2f95fa5c955d0a9987ffdc3a095e2f4e62c5f2a9 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block Signed-off-by: Pradeep P V K --- block/bfq-iosched.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index 3b44bd28fc45..0a1f7bb6e5f2 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c @@ -4532,20 +4532,28 @@ static void bfq_prepare_request(struct request *rq, struct bio *bio) spin_unlock_irq(&bfqd->lock); } -static void bfq_idle_slice_timer_body(struct bfq_queue *bfqq) +static void +bfq_idle_slice_timer_body(struct bfq_data *bfqd, struct bfq_queue *bfqq) { - struct bfq_data *bfqd = bfqq->bfqd; enum bfqq_expiration reason; unsigned long flags; spin_lock_irqsave(&bfqd->lock, flags); - bfq_clear_bfqq_wait_request(bfqq); + /* + * Considering that bfqq may be in race, we should firstly check + * whether bfqq is in service before doing something on it. If + * the bfqq in race is not in service, it has already been expired + * through __bfq_bfqq_expire func and its wait_request flags has + * been cleared in __bfq_bfqd_reset_in_service func. + */ if (bfqq != bfqd->in_service_queue) { spin_unlock_irqrestore(&bfqd->lock, flags); return; } + bfq_clear_bfqq_wait_request(bfqq); + if (bfq_bfqq_budget_timeout(bfqq)) /* * Also here the queue can be safely expired @@ -4590,7 +4598,7 @@ static enum hrtimer_restart bfq_idle_slice_timer(struct hrtimer *timer) * early. */ if (bfqq) - bfq_idle_slice_timer_body(bfqq); + bfq_idle_slice_timer_body(bfqd, bfqq); return HRTIMER_NORESTART; } From c2170665736129c3e3bfe16484052b2b2199c2ab Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Tue, 7 Apr 2020 11:20:39 -0700 Subject: [PATCH 037/192] ion: Improve ION allocation paths Clean up some of the ION heap interfaces so that they are more inline/uniform with respect to each other. Change-Id: I4edabc2c8ccb533898540ceda1fd6aacc2e2e56a Signed-off-by: Isaac J. Manjarres Signed-off-by: Srinivasarao P --- drivers/staging/android/ion/ion_cma_heap.c | 18 +++++++++++++++--- drivers/staging/android/ion/ion_secure_util.c | 7 ++++++- drivers/staging/android/ion/ion_secure_util.h | 4 +++- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index 7782183b993b..9fea27bb4513 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -4,7 +4,7 @@ * Copyright (C) Linaro 2012 * Author: for ST-Ericsson. * - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -55,6 +55,11 @@ static bool ion_cma_has_kernel_mapping(struct ion_heap *heap) } /* ION CMA heap operations functions */ +static bool ion_heap_is_cma_heap_type(enum ion_heap_type type) +{ + return type == ION_HEAP_TYPE_DMA; +} + static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, unsigned long len, unsigned long flags) @@ -73,6 +78,13 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, if (!info) return -ENOMEM; + if (ion_heap_is_cma_heap_type(buffer->heap->type) && + is_secure_allocation(buffer->flags)) { + pr_err("%s: CMA heap doesn't support secure allocations\n", + __func__); + return -EINVAL; + } + if (align > CONFIG_CMA_ALIGNMENT) align = CONFIG_CMA_ALIGNMENT; @@ -94,7 +106,7 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, if (!pages) goto free_info; - if (!(flags & ION_FLAG_SECURE)) { + if (hlos_accessible_buffer(buffer)) { if (PageHighMem(pages)) { unsigned long nr_clear_pages = nr_pages; struct page *page = pages; @@ -113,7 +125,7 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, } if (MAKE_ION_ALLOC_DMA_READY || - (flags & ION_FLAG_SECURE) || + (!hlos_accessible_buffer(buffer)) || !ion_buffer_cached(buffer)) ion_pages_sync_for_device(dev, pages, size, DMA_BIDIRECTIONAL); diff --git a/drivers/staging/android/ion/ion_secure_util.c b/drivers/staging/android/ion/ion_secure_util.c index 05c2168738c3..19df97b80b26 100644 --- a/drivers/staging/android/ion/ion_secure_util.c +++ b/drivers/staging/android/ion/ion_secure_util.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -35,6 +35,11 @@ bool is_secure_vmid_valid(int vmid) vmid == VMID_CP_DSP_EXT); } +bool is_secure_allocation(unsigned long flags) +{ + return !!(flags & (ION_FLAGS_CP_MASK | ION_FLAG_SECURE)); +} + int get_secure_vmid(unsigned long flags) { if (flags & ION_FLAG_CP_TOUCH) diff --git a/drivers/staging/android/ion/ion_secure_util.h b/drivers/staging/android/ion/ion_secure_util.h index f6d00d9d9b70..3e60b7d7bf3e 100644 --- a/drivers/staging/android/ion/ion_secure_util.h +++ b/drivers/staging/android/ion/ion_secure_util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018,2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -30,4 +30,6 @@ int ion_hyp_assign_from_flags(u64 base, u64 size, unsigned long flags); bool hlos_accessible_buffer(struct ion_buffer *buffer); +bool is_secure_allocation(unsigned long flags); + #endif /* _ION_SECURE_UTIL_H */ From ab49090323b4b9d5e0be17561b371a6670f9d160 Mon Sep 17 00:00:00 2001 From: Da Hoon Pyun Date: Tue, 14 Jul 2020 15:33:12 -0400 Subject: [PATCH 038/192] msm: npu: Allow user code to query if NPUDSP SID is mapped Add a new interface to allow user code to query if NPUDSP SID is mapped by IOMMU or not. Change-Id: I59ae9a683b9135938927a1180d4ec7e721c21543 Signed-off-by: Da Hoon Pyun --- drivers/media/platform/msm/npu_v2/npu_common.h | 1 + drivers/media/platform/msm/npu_v2/npu_dev.c | 6 ++++++ include/uapi/linux/msm_npu.h | 1 + 3 files changed, 8 insertions(+) diff --git a/drivers/media/platform/msm/npu_v2/npu_common.h b/drivers/media/platform/msm/npu_v2/npu_common.h index 6dda6133c1fe..5bfc0a571777 100644 --- a/drivers/media/platform/msm/npu_v2/npu_common.h +++ b/drivers/media/platform/msm/npu_v2/npu_common.h @@ -291,6 +291,7 @@ struct npu_device { struct llcc_slice_desc *sys_cache; uint32_t execute_v2_flag; bool cxlimit_registered; + bool npu_dsp_sid_mapped; uint32_t hw_version; }; diff --git a/drivers/media/platform/msm/npu_v2/npu_dev.c b/drivers/media/platform/msm/npu_v2/npu_dev.c index 211a52a97127..e83bf0a9e7e2 100644 --- a/drivers/media/platform/msm/npu_v2/npu_dev.c +++ b/drivers/media/platform/msm/npu_v2/npu_dev.c @@ -1447,6 +1447,8 @@ static int npu_get_property(struct npu_client *client, case MSM_NPU_PROP_ID_DRV_FEATURE: prop.prop_param[0] = MSM_NPU_FEATURE_MULTI_EXECUTE | MSM_NPU_FEATURE_ASYNC_EXECUTE; + if (npu_dev->npu_dsp_sid_mapped) + prop.prop_param[0] |= MSM_NPU_FEATURE_DSP_SID_MAPPED; break; default: ret = npu_host_get_fw_property(client->npu_dev, &prop); @@ -2215,6 +2217,10 @@ static int npu_hw_info_init(struct npu_device *npu_dev) NPU_DBG("NPU_HW_VERSION 0x%x\n", npu_dev->hw_version); npu_disable_core_power(npu_dev); + npu_dev->npu_dsp_sid_mapped = + of_property_read_bool(npu_dev->pdev->dev.of_node, + "qcom,npu-dsp-sid-mapped"); + return rc; } diff --git a/include/uapi/linux/msm_npu.h b/include/uapi/linux/msm_npu.h index b6509ec7a7b6..7deb6edbeaf1 100644 --- a/include/uapi/linux/msm_npu.h +++ b/include/uapi/linux/msm_npu.h @@ -87,6 +87,7 @@ /* features supported by driver */ #define MSM_NPU_FEATURE_MULTI_EXECUTE 0x1 #define MSM_NPU_FEATURE_ASYNC_EXECUTE 0x2 +#define MSM_NPU_FEATURE_DSP_SID_MAPPED 0x8 #define PROP_PARAM_MAX_SIZE 8 From 49e159c6d04a1b161c03ce307ecae7f0afb7781d Mon Sep 17 00:00:00 2001 From: Da Hoon Pyun Date: Tue, 14 Jul 2020 15:51:47 -0400 Subject: [PATCH 039/192] ARM: dts: msm: Add new property npu-dsp-sid-mapped for npu Add new property npu-dsp-sid-mapped to declare NPUDSP SID is supported. Change-Id: I0c358c0f5d9bae469466a7e87daa3464e7e9ff75 Signed-off-by: Da Hoon Pyun --- arch/arm64/boot/dts/qcom/atoll-npu.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/atoll-npu.dtsi b/arch/arm64/boot/dts/qcom/atoll-npu.dtsi index 4a236a5f3077..2743496362ce 100644 --- a/arch/arm64/boot/dts/qcom/atoll-npu.dtsi +++ b/arch/arm64/boot/dts/qcom/atoll-npu.dtsi @@ -31,6 +31,7 @@ iommus = <&apps_smmu 0x1441 0x0>, <&apps_smmu 0x1442 0x0>, <&apps_smmu 0x1461 0x0>, <&apps_smmu 0x1462 0x0>, <&apps_smmu 0x1481 0x0>, <&apps_smmu 0x1482 0x0>; + qcom,npu-dsp-sid-mapped; clocks = <&clock_npucc NPU_CC_XO_CLK>, <&clock_npucc NPU_CC_CORE_CLK>, From 2b2761ab7dd79033260f60dd512e39a4c2d12399 Mon Sep 17 00:00:00 2001 From: Da Hoon Pyun Date: Tue, 14 Jul 2020 16:21:24 -0400 Subject: [PATCH 040/192] msm:npu: prevent fmax_pwrlvl to be used uninitialized Initialize variable fmax_pwrlvl to prevent it being used uninitialized. Change-Id: Ie3f00292a74aa9d2ef57583979efa9d88f17b17a Signed-off-by: Da Hoon Pyun --- drivers/media/platform/msm/npu_v2/npu_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/npu_v2/npu_dev.c b/drivers/media/platform/msm/npu_v2/npu_dev.c index 211a52a97127..b2665b73cb0c 100644 --- a/drivers/media/platform/msm/npu_v2/npu_dev.c +++ b/drivers/media/platform/msm/npu_v2/npu_dev.c @@ -1723,7 +1723,7 @@ int npu_set_bw(struct npu_device *npu_dev, int new_ib, int new_ab) static int npu_adjust_max_power_level(struct npu_device *npu_dev) { struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; - uint32_t fmax_reg_value, fmax, fmax_pwrlvl; + uint32_t fmax_reg_value, fmax, fmax_pwrlvl = pwr->max_pwrlevel; struct npu_pwrlevel *level; int i, j; From 993fd956da5fbde5f579b12899f4ebee81cf5d40 Mon Sep 17 00:00:00 2001 From: Mohammed Date: Tue, 20 Nov 2018 01:19:21 +0530 Subject: [PATCH 041/192] msm: ipa4: debug patch gsi interrupt issue Debug patch for GSI interrupt issue Change-Id: I705cd893233e1afcaeed6fedb424830e39621114 Signed-off-by: Bojun Pan Signed-off-by: Praveen Kurapati Signed-off-by: Ashok Vuyyuru --- drivers/platform/msm/gsi/gsi.c | 7 +++++++ drivers/platform/msm/gsi/gsi.h | 4 +++- drivers/platform/msm/ipa/ipa_v3/ipa.c | 25 ++++++++++++++++++++++++- include/linux/msm_gsi.h | 2 ++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index ee190c0b5d69..0a9d871224fd 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -27,6 +27,7 @@ #define GSI_CMD_POLL_CNT 5 #define GSI_STOP_CMD_TIMEOUT_MS 200 #define GSI_MAX_CH_LOW_WEIGHT 15 +#define GSI_IRQ_STORM_THR 5 #define GSI_STOP_CMD_POLL_CNT 4 #define GSI_STOP_IN_PROC_CMD_POLL_CNT 2 @@ -811,8 +812,13 @@ static irqreturn_t gsi_isr(int irq, void *ctxt) gsi_ctx->per.rel_clk_cb(gsi_ctx->per.user_data); } } else if (!gsi_ctx->per.clk_status_cb()) { + if (atomic_read(&gsi_ctx->num_unclock_irq) == + GSI_IRQ_STORM_THR) + gsi_ctx->per.enable_clk_bug_on(); + atomic_inc(&gsi_ctx->num_unclock_irq); return IRQ_HANDLED; } else { + atomic_set(&gsi_ctx->num_unclock_irq, 0); gsi_handle_irq(); } return IRQ_HANDLED; @@ -1303,6 +1309,7 @@ int gsi_register_device(struct gsi_per_props *props, unsigned long *dev_hdl) } } + *dev_hdl = (uintptr_t)gsi_ctx; return GSI_STATUS_SUCCESS; diff --git a/drivers/platform/msm/gsi/gsi.h b/drivers/platform/msm/gsi/gsi.h index c0159b5c522f..8913b4e4ab65 100644 --- a/drivers/platform/msm/gsi/gsi.h +++ b/drivers/platform/msm/gsi/gsi.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -234,6 +234,8 @@ struct gsi_ctx { u32 intcntrlr_mem_size; irq_handler_t intcntrlr_gsi_isr; irq_handler_t intcntrlr_client_isr; + + atomic_t num_unclock_irq; }; enum gsi_re_type { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 39e534b599bf..68778a1d3c0c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -129,6 +129,10 @@ static void ipa_dec_clients_disable_clks_on_wq(struct work_struct *work); static DECLARE_WORK(ipa_dec_clients_disable_clks_on_wq_work, ipa_dec_clients_disable_clks_on_wq); +static void ipa_inc_clients_enable_clks_on_wq(struct work_struct *work); +static DECLARE_WORK(ipa_inc_clients_enable_clks_on_wq_work, + ipa_inc_clients_enable_clks_on_wq); + static struct ipa3_plat_drv_res ipa3_res = {0, }; static struct clk *ipa3_clk; @@ -4717,6 +4721,12 @@ void ipa3_disable_clks(void) IPADBG("disabling IPA clocks and bus voting\n"); + /* + * We see a NoC error on GSI on this flag sequence. + * Need to set this flag first before clock off. + */ + atomic_set(&ipa3_ctx->ipa_clk_vote, 0); + ipa3_ctx->ctrl->ipa3_disable_clks(); if (ipa3_ctx->use_ipa_pm) @@ -4724,7 +4734,6 @@ void ipa3_disable_clks(void) if (msm_bus_scale_client_update_request(ipa3_ctx->ipa_bus_hdl, 0)) WARN(1, "bus scaling failed"); - atomic_set(&ipa3_ctx->ipa_clk_vote, 0); } /** @@ -4906,6 +4915,12 @@ void ipa3_inc_client_enable_clks(struct ipa_active_client_logging_info *id) mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex); } +static void ipa3_handle_gsi_differ_irq(void) +{ + queue_work(ipa3_ctx->power_mgmt_wq, + &ipa_inc_clients_enable_clks_on_wq_work); +} + /** * ipa3_active_clks_status() - update the current msm bus clock vote * status @@ -5002,6 +5017,13 @@ static void ipa_dec_clients_disable_clks_on_wq(struct work_struct *work) __ipa3_dec_client_disable_clks(); } +static void ipa_inc_clients_enable_clks_on_wq(struct work_struct *work) +{ + ipa3_enable_clks(); + IPAERR("unexpected clk access, clock on IPA to save reg"); + ipa_assert(); +} + /** * ipa3_dec_client_disable_clks_no_block() - Decrease active clients counter * if possible without blocking. If this is the last client then the desrease @@ -5839,6 +5861,7 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, gsi_props.req_clk_cb = NULL; gsi_props.rel_clk_cb = NULL; gsi_props.clk_status_cb = ipa3_active_clks_status; + gsi_props.enable_clk_bug_on = ipa3_handle_gsi_differ_irq; if (ipa3_ctx->ipa_config_is_mhi) { gsi_props.mhi_er_id_limits_valid = true; diff --git a/include/linux/msm_gsi.h b/include/linux/msm_gsi.h index d6d834945d9b..8599380c6133 100644 --- a/include/linux/msm_gsi.h +++ b/include/linux/msm_gsi.h @@ -102,6 +102,7 @@ enum gsi_intr_type { * @rel_clk_cb: callback to release peripheral clock * @user_data: cookie used for notifications * @clk_status_cb: callback to update the current msm bus clock vote + * @enable_clk_bug_on: enable IPA clock for dump saving before assert * * All the callbacks are in interrupt context * @@ -123,6 +124,7 @@ struct gsi_per_props { void (*notify_cb)(struct gsi_per_notify *notify); void (*req_clk_cb)(void *user_data, bool *granted); int (*rel_clk_cb)(void *user_data); + void (*enable_clk_bug_on)(void); void *user_data; int (*clk_status_cb)(void); }; From 0d057ca468f7edcd92de9da400f42280c76efa55 Mon Sep 17 00:00:00 2001 From: Bojun Pan Date: Fri, 27 Dec 2019 13:45:00 -0800 Subject: [PATCH 042/192] msm: ipa4: capture the unclock gsi IPA register access Add more protect on the unclock gsi IPA register access. In case this is a valid access, assert before disabling the IPA clock. Change-Id: If2cc5a9942a5e457bbd8badaabde78138f676176 Signed-off-by: Bojun Pan Signed-off-by: Ashok Vuyyuru --- drivers/platform/msm/gsi/gsi.c | 11 +++++++++++ drivers/platform/msm/ipa/ipa_v3/ipa.c | 13 +++++++++++++ include/linux/msm_gsi.h | 15 +++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 0a9d871224fd..702c697649cf 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -760,6 +760,8 @@ static void gsi_handle_irq(void) unsigned long cnt = 0; while (1) { + if (!gsi_ctx->per.clk_status_cb()) + break; type = gsi_readl(gsi_ctx->base + GSI_EE_n_CNTXT_TYPE_IRQ_OFFS(ee)); @@ -2845,6 +2847,15 @@ int gsi_query_channel_db_addr(unsigned long chan_hdl, } EXPORT_SYMBOL(gsi_query_channel_db_addr); +int gsi_pending_irq_type(void) +{ + int ee = gsi_ctx->per.ee; + + return gsi_readl(gsi_ctx->base + + GSI_EE_n_CNTXT_TYPE_IRQ_OFFS(ee)); +} +EXPORT_SYMBOL(gsi_pending_irq_type); + int gsi_start_channel(unsigned long chan_hdl) { enum gsi_ch_cmd_opcode op = GSI_CH_START; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 68778a1d3c0c..1661c5a0ce23 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -4714,6 +4714,8 @@ void _ipa_disable_clks_v3_0(void) */ void ipa3_disable_clks(void) { + int type; + if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_NORMAL) { IPAERR("not supported in this mode\n"); return; @@ -4727,6 +4729,17 @@ void ipa3_disable_clks(void) */ atomic_set(&ipa3_ctx->ipa_clk_vote, 0); + /* + * If there is still pending gsi irq, this indicate + * issue on GSI FW side. We need to capture before + * turn off the ipa clock. + */ + type = gsi_pending_irq_type(); + if (type) { + IPAERR("unexpected gsi irq type: %d\n", type); + ipa_assert(); + } + ipa3_ctx->ctrl->ipa3_disable_clks(); if (ipa3_ctx->use_ipa_pm) diff --git a/include/linux/msm_gsi.h b/include/linux/msm_gsi.h index 8599380c6133..92be8fc80c05 100644 --- a/include/linux/msm_gsi.h +++ b/include/linux/msm_gsi.h @@ -1335,6 +1335,16 @@ int gsi_read_channel_scratch(unsigned long chan_hdl, int gsi_read_wdi3_channel_scratch2_reg(unsigned long chan_hdl, union __packed gsi_wdi3_channel_scratch2_reg *val); +/** + * gsi_pending_irq_type - Peripheral should call this function to + * check if there is any pending irq + * + * This function can sleep + * + * @Return gsi_irq_type + */ +int gsi_pending_irq_type(void); + /** * gsi_update_mhi_channel_scratch - MHI Peripheral should call this * function to update the scratch area of the channel context. Updating @@ -1810,6 +1820,11 @@ static inline int gsi_read_channel_scratch(unsigned long chan_hdl, return -GSI_STATUS_UNSUPPORTED_OP; } +static inline int gsi_pending_irq_type(void) +{ + return -GSI_STATUS_UNSUPPORTED_OP; +} + static inline int gsi_update_mhi_channel_scratch(unsigned long chan_hdl, struct __packed gsi_mhi_channel_scratch mscr) { From 068fb6c27363e01cfdad879c4370999dde96e958 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Thu, 7 May 2020 18:25:18 -0700 Subject: [PATCH 043/192] ARM: dts: msm: coalesce UL/DL MSIs for IPA HW channels Coalesce MSIs used in event rings dedicated for the IPA HW and RSC channels such that both uplink and downlink traffic uses the same interrupt. Change-Id: Iea49d366d92456d41cfe6a3faf496ae1add7825d Signed-off-by: Bhaumik Bhatt --- arch/arm64/boot/dts/qcom/sm8150-marmot.dtsi | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-marmot.dtsi b/arch/arm64/boot/dts/qcom/sm8150-marmot.dtsi index f6489f20f7f0..f9ceb357c7e0 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-marmot.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-marmot.dtsi @@ -172,7 +172,7 @@ mhi_event@7 { mhi,num-elements = <2048>; mhi,intmod = <5>; - mhi,msi = <6>; + mhi,msi = <5>; mhi,chan = <101>; mhi,priority = <1>; mhi,brstmode = <3>; @@ -183,7 +183,7 @@ mhi_event@8 { mhi,num-elements = <0>; mhi,intmod = <0>; - mhi,msi = <7>; + mhi,msi = <6>; mhi,chan = <102>; mhi,priority = <1>; mhi,brstmode = <3>; @@ -195,7 +195,7 @@ mhi_event@9 { mhi,num-elements = <1024>; mhi,intmod = <5>; - mhi,msi = <8>; + mhi,msi = <7>; mhi,chan = <103>; mhi,priority = <1>; mhi,brstmode = <2>; @@ -205,7 +205,7 @@ mhi_event@10 { mhi,num-elements = <0>; mhi,intmod = <0>; - mhi,msi = <9>; + mhi,msi = <8>; mhi,chan = <105>; mhi,priority = <1>; mhi,brstmode = <3>; @@ -217,7 +217,7 @@ mhi_event@11 { mhi,num-elements = <0>; mhi,intmod = <0>; - mhi,msi = <10>; + mhi,msi = <9>; mhi,chan = <106>; mhi,priority = <1>; mhi,brstmode = <3>; @@ -229,7 +229,7 @@ mhi_event@12 { mhi,num-elements = <0>; mhi,intmod = <0>; - mhi,msi = <11>; + mhi,msi = <10>; mhi,chan = <107>; mhi,priority = <1>; mhi,brstmode = <3>; @@ -241,7 +241,7 @@ mhi_event@13 { mhi,num-elements = <0>; mhi,intmod = <0>; - mhi,msi = <12>; + mhi,msi = <11>; mhi,chan = <108>; mhi,priority = <1>; mhi,brstmode = <3>; @@ -253,7 +253,7 @@ mhi_event@14 { mhi,num-elements = <1024>; mhi,intmod = <1>; - mhi,msi = <13>; + mhi,msi = <12>; mhi,chan = <109>; mhi,priority = <0>; mhi,brstmode = <2>; @@ -263,7 +263,7 @@ mhi_event@15 { mhi,num-elements = <1024>; mhi,intmod = <0>; - mhi,msi = <14>; + mhi,msi = <13>; mhi,chan = <110>; mhi,priority = <0>; mhi,brstmode = <2>; From bb03097ddd04d5bee950da49111f9a586193ce93 Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Wed, 15 Jul 2020 12:45:32 +0530 Subject: [PATCH 044/192] diag: Enable debug logs for pcie operations Add debug logs to track the pcie registrations and enable logging for pcie related operations of read and write. Change-Id: I66852867b09f033ae7f9bc154eb3fc02c0b455ae Signed-off-by: Manoj Prabhu B --- drivers/char/diag/diag_mux.c | 2 ++ drivers/char/diag/diag_pcie.c | 35 +++++++++++++++++++++++-------- drivers/char/diag/diagchar_core.c | 2 +- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/drivers/char/diag/diag_mux.c b/drivers/char/diag/diag_mux.c index 593bc1b6d512..ebc53fcab73c 100644 --- a/drivers/char/diag/diag_mux.c +++ b/drivers/char/diag/diag_mux.c @@ -125,6 +125,8 @@ int diag_pcie_register_ops(int proc, int ctx, struct diag_mux_ops *ops) return 0; pcie_logger.ops[proc] = ops; + DIAG_LOG(DIAG_DEBUG_MUX, + "diag: registering pcie for proc: %d\n", proc); err = diag_pcie_register(proc, ctx, ops); if (err) { pr_err("diag: MUX: unable to register pcie operations for proc: %d, err: %d\n", diff --git a/drivers/char/diag/diag_pcie.c b/drivers/char/diag/diag_pcie.c index f8c424005bc9..3c859a2407ee 100644 --- a/drivers/char/diag/diag_pcie.c +++ b/drivers/char/diag/diag_pcie.c @@ -416,31 +416,39 @@ void diag_pcie_client_cb(struct mhi_dev_client_cb_data *cb_data) { struct diag_pcie_info *pcie_info = NULL; - if (!cb_data) + if (!cb_data) { + pr_err("diag: %s: Invalid cb_data\n", __func__); return; - + } pcie_info = cb_data->user_data; - if (!pcie_info) + if (!pcie_info) { + pr_err("diag: %s: Invalid pcie_info\n", __func__); return; - + } switch (cb_data->ctrl_info) { case MHI_STATE_CONNECTED: if (cb_data->channel == pcie_info->out_chan) { DIAG_LOG(DIAG_DEBUG_MUX, - " Received connect event from MHI for %d", + "diag: Received connect event from MHI for %d\n", pcie_info->out_chan); - if (atomic_read(&pcie_info->enabled)) + if (atomic_read(&pcie_info->enabled)) { + DIAG_LOG(DIAG_DEBUG_MUX, + "diag: pcie channel is already enabled\n"); return; + } queue_work(pcie_info->wq, &pcie_info->open_work); } break; case MHI_STATE_DISCONNECTED: if (cb_data->channel == pcie_info->out_chan) { DIAG_LOG(DIAG_DEBUG_MUX, - " Received disconnect event from MHI for %d", + "diag: Received disconnect event from MHI for %d", pcie_info->out_chan); - if (!atomic_read(&pcie_info->enabled)) + if (!atomic_read(&pcie_info->enabled)) { + DIAG_LOG(DIAG_DEBUG_MUX, + "diag: pcie channel is already disabled\n"); return; + } queue_work(pcie_info->wq, &pcie_info->close_work); } break; @@ -679,6 +687,8 @@ int diag_pcie_register(int id, int ctxt, struct diag_mux_ops *ops) return -EIO; } + pr_info("diag: Pcie registration initiated for id: %d\n", id); + ch = &diag_pcie[id]; ch->ops = ops; ch->ctxt = ctxt; @@ -692,8 +702,12 @@ int diag_pcie_register(int id, int ctxt, struct diag_mux_ops *ops) strlcpy(wq_name, "DIAG_PCIE_", sizeof(wq_name)); strlcat(wq_name, ch->name, sizeof(wq_name)); ch->wq = create_singlethread_workqueue(wq_name); - if (!ch->wq) + if (!ch->wq) { + pr_err("diag: %s: failed creating workqueue for wq_name: %s\n", + __func__, wq_name); return -ENOMEM; + } + DIAG_LOG(DIAG_DEBUG_MUX, "diag: created wq: %s\n", wq_name); diagmem_init(driver, ch->mempool); mutex_init(&ch->in_chan_lock); mutex_init(&ch->out_chan_lock); @@ -702,7 +716,10 @@ int diag_pcie_register(int id, int ctxt, struct diag_mux_ops *ops) if (ch->wq) destroy_workqueue(ch->wq); kfree(ch->in_chan_attr.read_buffer); + pr_err("diag: %s: failed registering pcie channels\n", + __func__); return rc; } + pr_info("diag: pcie channel with id: %d registered successfully\n", id); return 0; } diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 3391a84ca936..276b823b1f2f 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -4292,7 +4292,7 @@ static void diag_debug_init(void) * to be logged to IPC */ diag_debug_mask = DIAG_DEBUG_PERIPHERALS | DIAG_DEBUG_DCI | - DIAG_DEBUG_USERSPACE | DIAG_DEBUG_BRIDGE; + DIAG_DEBUG_USERSPACE | DIAG_DEBUG_BRIDGE | DIAG_DEBUG_MUX; } #else static void diag_debug_init(void) From 16ca66f52f43c8acef59c9a08046358d5badbab4 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:17 +0300 Subject: [PATCH 045/192] UPSTREAM: ath10k: add hif start/stop methods for wcn3990 snoc layer Add hif start/stop callback for allocating/freeing buffers on tx/rx pipe and enabling/disabling the tx/rx pipe interrupts. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: a6e149a9ff03e00b0a4293c0cc70b37db48fdf80 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: Ia2825dbbe59932b5e7e6187368187d856f7be296 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/snoc.c | 189 ++++++++++++++++++++++++- 1 file changed, 187 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 575355ce675f..dcd8bb7b71b4 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -25,6 +25,7 @@ #include #include #define WCN3990_CE_ATTR_FLAGS 0 +#define ATH10K_SNOC_RX_POST_RETRY_MS 50 static char *const ce_name[] = { "WLAN_CE_0", @@ -170,9 +171,193 @@ u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset) return val; } +static int __ath10k_snoc_rx_post_buf(struct ath10k_snoc_pipe *pipe) +{ + struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl; + struct ath10k *ar = pipe->hif_ce_state; + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct sk_buff *skb; + dma_addr_t paddr; + int ret; + + skb = dev_alloc_skb(pipe->buf_sz); + if (!skb) + return -ENOMEM; + + WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb"); + + paddr = dma_map_single(ar->dev, skb->data, + skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(ar->dev, paddr))) { + ath10k_warn(ar, "failed to dma map snoc rx buf\n"); + dev_kfree_skb_any(skb); + return -EIO; + } + + ATH10K_SKB_RXCB(skb)->paddr = paddr; + + spin_lock_bh(&ce->ce_lock); + ret = ce_pipe->ops->ce_rx_post_buf(ce_pipe, skb, paddr); + spin_unlock_bh(&ce->ce_lock); + if (ret) { + dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + return ret; + } + + return 0; +} + +static void ath10k_snoc_rx_post_pipe(struct ath10k_snoc_pipe *pipe) +{ + struct ath10k *ar = pipe->hif_ce_state; + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl; + int ret, num; + + if (pipe->buf_sz == 0) + return; + + if (!ce_pipe->dest_ring) + return; + + spin_lock_bh(&ce->ce_lock); + num = __ath10k_ce_rx_num_free_bufs(ce_pipe); + spin_unlock_bh(&ce->ce_lock); + while (num--) { + ret = __ath10k_snoc_rx_post_buf(pipe); + if (ret) { + if (ret == -ENOSPC) + break; + ath10k_warn(ar, "failed to post rx buf: %d\n", ret); + mod_timer(&ar_snoc->rx_post_retry, jiffies + + ATH10K_SNOC_RX_POST_RETRY_MS); + break; + } + } +} + +static void ath10k_snoc_rx_post(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + int i; + + for (i = 0; i < CE_COUNT; i++) + ath10k_snoc_rx_post_pipe(&ar_snoc->pipe_info[i]); +} + +static inline void ath10k_snoc_irq_disable(struct ath10k *ar) +{ + ath10k_ce_disable_interrupts(ar); +} + +static inline void ath10k_snoc_irq_enable(struct ath10k *ar) +{ + ath10k_ce_enable_interrupts(ar); +} + +static void ath10k_snoc_rx_pipe_cleanup(struct ath10k_snoc_pipe *snoc_pipe) +{ + struct ath10k_ce_pipe *ce_pipe; + struct ath10k_ce_ring *ce_ring; + struct sk_buff *skb; + struct ath10k *ar; + int i; + + ar = snoc_pipe->hif_ce_state; + ce_pipe = snoc_pipe->ce_hdl; + ce_ring = ce_pipe->dest_ring; + + if (!ce_ring) + return; + + if (!snoc_pipe->buf_sz) + return; + + for (i = 0; i < ce_ring->nentries; i++) { + skb = ce_ring->per_transfer_context[i]; + if (!skb) + continue; + + ce_ring->per_transfer_context[i] = NULL; + + dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr, + skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + } +} + +static void ath10k_snoc_tx_pipe_cleanup(struct ath10k_snoc_pipe *snoc_pipe) +{ + struct ath10k_ce_pipe *ce_pipe; + struct ath10k_ce_ring *ce_ring; + struct ath10k_snoc *ar_snoc; + struct sk_buff *skb; + struct ath10k *ar; + int i; + + ar = snoc_pipe->hif_ce_state; + ar_snoc = ath10k_snoc_priv(ar); + ce_pipe = snoc_pipe->ce_hdl; + ce_ring = ce_pipe->src_ring; + + if (!ce_ring) + return; + + if (!snoc_pipe->buf_sz) + return; + + for (i = 0; i < ce_ring->nentries; i++) { + skb = ce_ring->per_transfer_context[i]; + if (!skb) + continue; + + ce_ring->per_transfer_context[i] = NULL; + + ath10k_htc_tx_completion_handler(ar, skb); + } +} + +static void ath10k_snoc_buffer_cleanup(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_snoc_pipe *pipe_info; + int pipe_num; + + del_timer_sync(&ar_snoc->rx_post_retry); + for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { + pipe_info = &ar_snoc->pipe_info[pipe_num]; + ath10k_snoc_rx_pipe_cleanup(pipe_info); + ath10k_snoc_tx_pipe_cleanup(pipe_info); + } +} + +static void ath10k_snoc_hif_stop(struct ath10k *ar) +{ + ath10k_snoc_irq_disable(ar); + ath10k_snoc_buffer_cleanup(ar); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n"); +} + +static int ath10k_snoc_hif_start(struct ath10k *ar) +{ + ath10k_snoc_irq_enable(ar); + ath10k_snoc_rx_post(ar); + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n"); + + return 0; +} + static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { - .read32 = ath10k_snoc_read32, - .write32 = ath10k_snoc_write32, + .read32 = ath10k_snoc_read32, + .write32 = ath10k_snoc_write32, + .start = ath10k_snoc_hif_start, + .stop = ath10k_snoc_hif_stop, }; static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { From 2c4b2dc26a7cbf844b0dbf83298a46506d213af2 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:18 +0300 Subject: [PATCH 046/192] UPSTREAM: ath10k: add HTC services for WCN3990 WCN3990 target uses 3 Copy engine(CE1/CE9/CE10) in RX path and CE 11 for pktlog. Add data path HTC ep services and PKTLOG services for WCN3990. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: b8c27e86211832b06667f11be3c24acc78828ee5 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: Id94c657cdab0257b4e4617acd64201fdb78e7e2d Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/htc.c | 6 ++++++ drivers/net/wireless/ath/ath10k/htc.h | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 492dc5b4bbf2..8902720b4e49 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -542,8 +542,14 @@ static const char *htc_service_name(enum ath10k_htc_svc_id id) return "NMI Data"; case ATH10K_HTC_SVC_ID_HTT_DATA_MSG: return "HTT Data"; + case ATH10K_HTC_SVC_ID_HTT_DATA2_MSG: + return "HTT Data"; + case ATH10K_HTC_SVC_ID_HTT_DATA3_MSG: + return "HTT Data"; case ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS: return "RAW"; + case ATH10K_HTC_SVC_ID_HTT_LOG_MSG: + return "PKTLOG"; } return "Unknown"; diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index a2f8814b3e53..34877597dd6a 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -248,6 +248,7 @@ enum ath10k_htc_svc_gid { ATH10K_HTC_SVC_GRP_WMI = 1, ATH10K_HTC_SVC_GRP_NMI = 2, ATH10K_HTC_SVC_GRP_HTT = 3, + ATH10K_LOG_SERVICE_GROUP = 6, ATH10K_HTC_SVC_GRP_TEST = 254, ATH10K_HTC_SVC_GRP_LAST = 255, @@ -273,6 +274,9 @@ enum ath10k_htc_svc_id { ATH10K_HTC_SVC_ID_HTT_DATA_MSG = SVC(ATH10K_HTC_SVC_GRP_HTT, 0), + ATH10K_HTC_SVC_ID_HTT_DATA2_MSG = SVC(ATH10K_HTC_SVC_GRP_HTT, 1), + ATH10K_HTC_SVC_ID_HTT_DATA3_MSG = SVC(ATH10K_HTC_SVC_GRP_HTT, 2), + ATH10K_HTC_SVC_ID_HTT_LOG_MSG = SVC(ATH10K_LOG_SERVICE_GROUP, 0), /* raw stream service (i.e. flash, tcmd, calibration apps) */ ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS = SVC(ATH10K_HTC_SVC_GRP_TEST, 0), }; From 631075a52f0c0f355fb7d99fddcf2dd40c0d5bdf Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:20 +0300 Subject: [PATCH 047/192] UPSTREAM: ath10k: map HTC services to tx/rx pipes for wcn3990 Add mapping of HTC endpoint services supported by wcn3990 target to tx/rx pipe. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: 84efe7f6ebc56dbeb18c3448a487f2265c647d91 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: Icbc5bf11d0f403aa3d8ee873587a6ce9374fa3ca Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/snoc.c | 168 +++++++++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index dcd8bb7b71b4..a39eee7ed56c 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -154,6 +154,116 @@ static struct ce_attr host_ce_config_wlan[] = { }, }; +static struct service_to_pipe target_service_to_ce_map_wlan[] = { + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(0), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { /* not used */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(0), + }, + { /* not used */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(4), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(1), + }, + { /* not used */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS), + __cpu_to_le32(PIPEDIR_OUT), + __cpu_to_le32(5), + }, + { /* in = DL = target -> host */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA2_MSG), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(9), + }, + { /* in = DL = target -> host */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA3_MSG), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(10), + }, + { /* in = DL = target -> host pktlog */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_LOG_MSG), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(11), + }, + /* (Additions here) */ + + { /* must be last */ + __cpu_to_le32(0), + __cpu_to_le32(0), + __cpu_to_le32(0), + }, +}; + void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); @@ -249,6 +359,62 @@ static void ath10k_snoc_rx_post(struct ath10k *ar) ath10k_snoc_rx_post_pipe(&ar_snoc->pipe_info[i]); } +static int ath10k_snoc_hif_map_service_to_pipe(struct ath10k *ar, + u16 service_id, + u8 *ul_pipe, u8 *dl_pipe) +{ + const struct service_to_pipe *entry; + bool ul_set = false, dl_set = false; + int i; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif map service\n"); + + for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) { + entry = &target_service_to_ce_map_wlan[i]; + + if (__le32_to_cpu(entry->service_id) != service_id) + continue; + + switch (__le32_to_cpu(entry->pipedir)) { + case PIPEDIR_NONE: + break; + case PIPEDIR_IN: + WARN_ON(dl_set); + *dl_pipe = __le32_to_cpu(entry->pipenum); + dl_set = true; + break; + case PIPEDIR_OUT: + WARN_ON(ul_set); + *ul_pipe = __le32_to_cpu(entry->pipenum); + ul_set = true; + break; + case PIPEDIR_INOUT: + WARN_ON(dl_set); + WARN_ON(ul_set); + *dl_pipe = __le32_to_cpu(entry->pipenum); + *ul_pipe = __le32_to_cpu(entry->pipenum); + dl_set = true; + ul_set = true; + break; + } + } + + if (WARN_ON(!ul_set || !dl_set)) + return -ENOENT; + + return 0; +} + +static void ath10k_snoc_hif_get_default_pipe(struct ath10k *ar, + u8 *ul_pipe, u8 *dl_pipe) +{ + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif get default pipe\n"); + + (void)ath10k_snoc_hif_map_service_to_pipe(ar, + ATH10K_HTC_SVC_ID_RSVD_CTRL, + ul_pipe, dl_pipe); +} + static inline void ath10k_snoc_irq_disable(struct ath10k *ar) { ath10k_ce_disable_interrupts(ar); @@ -358,6 +524,8 @@ static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .write32 = ath10k_snoc_write32, .start = ath10k_snoc_hif_start, .stop = ath10k_snoc_hif_stop, + .map_service_to_pipe = ath10k_snoc_hif_map_service_to_pipe, + .get_default_pipe = ath10k_snoc_hif_get_default_pipe, }; static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { From 809fb073d14e1a6be7e927b0e9ac954494e98fc9 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:22 +0300 Subject: [PATCH 048/192] UPSTREAM: ath10k: add hif power-up/power-down methods Add hif power-up/power-down methods for wcn3990 target. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: 0fa4fbe9b8cf7656813382602a6a5d330f01d3ae Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I36434fd36486ed07de3d121b49bd142a1a50256f Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/snoc.c | 61 ++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index a39eee7ed56c..9d402e4afaf9 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -519,6 +519,65 @@ static int ath10k_snoc_hif_start(struct ath10k *ar) return 0; } +static int ath10k_snoc_init_pipes(struct ath10k *ar) +{ + int i, ret; + + for (i = 0; i < CE_COUNT; i++) { + ret = ath10k_ce_init_pipe(ar, i, &host_ce_config_wlan[i]); + if (ret) { + ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n", + i, ret); + return ret; + } + } + + return 0; +} + +static int ath10k_snoc_wlan_enable(struct ath10k *ar) +{ + return 0; +} + +static void ath10k_snoc_wlan_disable(struct ath10k *ar) +{ +} + +static void ath10k_snoc_hif_power_down(struct ath10k *ar) +{ + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n"); + + ath10k_snoc_wlan_disable(ar); +} + +static int ath10k_snoc_hif_power_up(struct ath10k *ar) +{ + int ret; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 driver state = %d\n", + __func__, ar->state); + + ret = ath10k_snoc_wlan_enable(ar); + if (ret) { + ath10k_err(ar, "failed to enable wcn3990: %d\n", ret); + return ret; + } + + ret = ath10k_snoc_init_pipes(ar); + if (ret) { + ath10k_err(ar, "failed to initialize CE: %d\n", ret); + goto err_wlan_enable; + } + + return 0; + +err_wlan_enable: + ath10k_snoc_wlan_disable(ar); + + return ret; +} + static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .read32 = ath10k_snoc_read32, .write32 = ath10k_snoc_write32, @@ -526,6 +585,8 @@ static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .stop = ath10k_snoc_hif_stop, .map_service_to_pipe = ath10k_snoc_hif_map_service_to_pipe, .get_default_pipe = ath10k_snoc_hif_get_default_pipe, + .power_up = ath10k_snoc_hif_power_up, + .power_down = ath10k_snoc_hif_power_down, }; static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { From 894c46604fbb0120c5b2b461dbd3a47936a813dd Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:24 +0300 Subject: [PATCH 049/192] UPSTREAM: ath10k: add hif tx methods for wcn3990 Add hif tx/tx-complete methods for wcn3990 target. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: d390509bdf501c9c8c6e61248e4bc9314c86d854 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I2730d8e4df80181356820d053d314c1a664fb9e5 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/snoc.c | 123 ++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 9d402e4afaf9..899f0a327050 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -42,6 +42,9 @@ static char *const ce_name[] = { "WLAN_CE_11", }; +static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state); +static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state); + static const struct ath10k_snoc_drv_priv drv_priv = { .hw_rev = ATH10K_HW_WCN3990, .dma_mask = DMA_BIT_MASK(37), @@ -54,7 +57,7 @@ static struct ce_attr host_ce_config_wlan[] = { .src_nentries = 16, .src_sz_max = 2048, .dest_nentries = 0, - .send_cb = NULL, + .send_cb = ath10k_snoc_htc_tx_cb, }, /* CE1: target->host HTT + HTC control */ @@ -81,7 +84,7 @@ static struct ce_attr host_ce_config_wlan[] = { .src_nentries = 32, .src_sz_max = 2048, .dest_nentries = 0, - .send_cb = NULL, + .send_cb = ath10k_snoc_htc_tx_cb, }, /* CE4: host->target HTT */ @@ -90,7 +93,7 @@ static struct ce_attr host_ce_config_wlan[] = { .src_nentries = 256, .src_sz_max = 256, .dest_nentries = 0, - .send_cb = NULL, + .send_cb = ath10k_snoc_htt_tx_cb, }, /* CE5: target->host HTT (ipa_uc->target ) */ @@ -359,6 +362,117 @@ static void ath10k_snoc_rx_post(struct ath10k *ar) ath10k_snoc_rx_post_pipe(&ar_snoc->pipe_info[i]); } +static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state) +{ + struct ath10k *ar = ce_state->ar; + struct sk_buff_head list; + struct sk_buff *skb; + + __skb_queue_head_init(&list); + while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) { + if (!skb) + continue; + + __skb_queue_tail(&list, skb); + } + + while ((skb = __skb_dequeue(&list))) + ath10k_htc_tx_completion_handler(ar, skb); +} + +static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state) +{ + struct ath10k *ar = ce_state->ar; + struct sk_buff *skb; + + while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) { + if (!skb) + continue; + + dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, + skb->len, DMA_TO_DEVICE); + ath10k_htt_hif_tx_complete(ar, skb); + } +} + +static int ath10k_snoc_hif_tx_sg(struct ath10k *ar, u8 pipe_id, + struct ath10k_hif_sg_item *items, int n_items) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_snoc_pipe *snoc_pipe; + struct ath10k_ce_pipe *ce_pipe; + int err, i = 0; + + snoc_pipe = &ar_snoc->pipe_info[pipe_id]; + ce_pipe = snoc_pipe->ce_hdl; + spin_lock_bh(&ce->ce_lock); + + for (i = 0; i < n_items - 1; i++) { + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "snoc tx item %d paddr %pad len %d n_items %d\n", + i, &items[i].paddr, items[i].len, n_items); + + err = ath10k_ce_send_nolock(ce_pipe, + items[i].transfer_context, + items[i].paddr, + items[i].len, + items[i].transfer_id, + CE_SEND_FLAG_GATHER); + if (err) + goto err; + } + + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "snoc tx item %d paddr %pad len %d n_items %d\n", + i, &items[i].paddr, items[i].len, n_items); + + err = ath10k_ce_send_nolock(ce_pipe, + items[i].transfer_context, + items[i].paddr, + items[i].len, + items[i].transfer_id, + 0); + if (err) + goto err; + + spin_unlock_bh(&ce->ce_lock); + + return 0; + +err: + for (; i > 0; i--) + __ath10k_ce_send_revert(ce_pipe); + + spin_unlock_bh(&ce->ce_lock); + return err; +} + +static u16 ath10k_snoc_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "hif get free queue number\n"); + + return ath10k_ce_num_free_src_entries(ar_snoc->pipe_info[pipe].ce_hdl); +} + +static void ath10k_snoc_hif_send_complete_check(struct ath10k *ar, u8 pipe, + int force) +{ + int resources; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif send complete check\n"); + + if (!force) { + resources = ath10k_snoc_hif_get_free_queue_number(ar, pipe); + + if (resources > (host_ce_config_wlan[pipe].src_nentries >> 1)) + return; + } + ath10k_ce_per_engine_service(ar, pipe); +} + static int ath10k_snoc_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id, u8 *ul_pipe, u8 *dl_pipe) @@ -587,6 +701,9 @@ static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .get_default_pipe = ath10k_snoc_hif_get_default_pipe, .power_up = ath10k_snoc_hif_power_up, .power_down = ath10k_snoc_hif_power_down, + .tx_sg = ath10k_snoc_hif_tx_sg, + .send_complete_check = ath10k_snoc_hif_send_complete_check, + .get_free_queue_number = ath10k_snoc_hif_get_free_queue_number, }; static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { From 0fc13584f83c86431c0f3ceb2de306513eff584e Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:25 +0300 Subject: [PATCH 050/192] UPSTREAM: ath10k: add hif rx methods for wcn3990 Add hif rx methods in rx path for wcn3990 target. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: d915105231ca0581a9f87e59ed00bc17a54e254f Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I7e8ea5f47f544f450546894fb20c393cda15a102 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/snoc.c | 171 ++++++++++++++++++++++--- 1 file changed, 153 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 899f0a327050..6d9cccee9bbe 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -26,6 +26,7 @@ #include #define WCN3990_CE_ATTR_FLAGS 0 #define ATH10K_SNOC_RX_POST_RETRY_MS 50 +#define CE_POLL_PIPE 4 static char *const ce_name[] = { "WLAN_CE_0", @@ -44,6 +45,9 @@ static char *const ce_name[] = { static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state); static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state); +static void ath10k_snoc_htc_rx_cb(struct ath10k_ce_pipe *ce_state); +static void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state); +static void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state); static const struct ath10k_snoc_drv_priv drv_priv = { .hw_rev = ATH10K_HW_WCN3990, @@ -53,7 +57,7 @@ static const struct ath10k_snoc_drv_priv drv_priv = { static struct ce_attr host_ce_config_wlan[] = { /* CE0: host->target HTC control streams */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 16, .src_sz_max = 2048, .dest_nentries = 0, @@ -62,25 +66,25 @@ static struct ce_attr host_ce_config_wlan[] = { /* CE1: target->host HTT + HTC control */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 0, .src_sz_max = 2048, .dest_nentries = 512, - .recv_cb = NULL, + .recv_cb = ath10k_snoc_htt_htc_rx_cb, }, /* CE2: target->host WMI */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 0, .src_sz_max = 2048, .dest_nentries = 64, - .recv_cb = NULL, + .recv_cb = ath10k_snoc_htc_rx_cb, }, /* CE3: host->target WMI */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 32, .src_sz_max = 2048, .dest_nentries = 0, @@ -89,7 +93,7 @@ static struct ce_attr host_ce_config_wlan[] = { /* CE4: host->target HTT */ { - .flags = WCN3990_CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, + .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, .src_nentries = 256, .src_sz_max = 256, .dest_nentries = 0, @@ -98,16 +102,16 @@ static struct ce_attr host_ce_config_wlan[] = { /* CE5: target->host HTT (ipa_uc->target ) */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 0, .src_sz_max = 512, .dest_nentries = 512, - .recv_cb = NULL, + .recv_cb = ath10k_snoc_htt_rx_cb, }, /* CE6: target autonomous hif_memcpy */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 0, .src_sz_max = 0, .dest_nentries = 0, @@ -115,7 +119,7 @@ static struct ce_attr host_ce_config_wlan[] = { /* CE7: ce_diag, the Diagnostic Window */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 2, .src_sz_max = 2048, .dest_nentries = 2, @@ -123,7 +127,7 @@ static struct ce_attr host_ce_config_wlan[] = { /* CE8: Target to uMC */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 0, .src_sz_max = 2048, .dest_nentries = 128, @@ -131,29 +135,29 @@ static struct ce_attr host_ce_config_wlan[] = { /* CE9 target->host HTT */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 0, .src_sz_max = 2048, .dest_nentries = 512, - .recv_cb = NULL, + .recv_cb = ath10k_snoc_htt_htc_rx_cb, }, /* CE10: target->host HTT */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 0, .src_sz_max = 2048, .dest_nentries = 512, - .recv_cb = NULL, + .recv_cb = ath10k_snoc_htt_htc_rx_cb, }, /* CE11: target -> host PKTLOG */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 0, .src_sz_max = 2048, .dest_nentries = 512, - .recv_cb = NULL, + .recv_cb = ath10k_snoc_htt_htc_rx_cb, }, }; @@ -362,6 +366,82 @@ static void ath10k_snoc_rx_post(struct ath10k *ar) ath10k_snoc_rx_post_pipe(&ar_snoc->pipe_info[i]); } +static void ath10k_snoc_process_rx_cb(struct ath10k_ce_pipe *ce_state, + void (*callback)(struct ath10k *ar, + struct sk_buff *skb)) +{ + struct ath10k *ar = ce_state->ar; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_snoc_pipe *pipe_info = &ar_snoc->pipe_info[ce_state->id]; + struct sk_buff *skb; + struct sk_buff_head list; + void *transfer_context; + unsigned int nbytes, max_nbytes; + + __skb_queue_head_init(&list); + while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, + &nbytes) == 0) { + skb = transfer_context; + max_nbytes = skb->len + skb_tailroom(skb); + dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr, + max_nbytes, DMA_FROM_DEVICE); + + if (unlikely(max_nbytes < nbytes)) { + ath10k_warn(ar, "rxed more than expected (nbytes %d, max %d)", + nbytes, max_nbytes); + dev_kfree_skb_any(skb); + continue; + } + + skb_put(skb, nbytes); + __skb_queue_tail(&list, skb); + } + + while ((skb = __skb_dequeue(&list))) { + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc rx ce pipe %d len %d\n", + ce_state->id, skb->len); + + callback(ar, skb); + } + + ath10k_snoc_rx_post_pipe(pipe_info); +} + +static void ath10k_snoc_htc_rx_cb(struct ath10k_ce_pipe *ce_state) +{ + ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler); +} + +static void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state) +{ + /* CE4 polling needs to be done whenever CE pipe which transports + * HTT Rx (target->host) is processed. + */ + ath10k_ce_per_engine_service(ce_state->ar, CE_POLL_PIPE); + + ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler); +} + +static void ath10k_snoc_htt_rx_deliver(struct ath10k *ar, struct sk_buff *skb) +{ + skb_pull(skb, sizeof(struct ath10k_htc_hdr)); + ath10k_htt_t2h_msg_handler(ar, skb); +} + +static void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state) +{ + ath10k_ce_per_engine_service(ce_state->ar, CE_POLL_PIPE); + ath10k_snoc_process_rx_cb(ce_state, ath10k_snoc_htt_rx_deliver); +} + +static void ath10k_snoc_rx_replenish_retry(struct timer_list *t) +{ + struct ath10k_pci *ar_snoc = from_timer(ar_snoc, t, rx_post_retry); + struct ath10k *ar = ar_snoc->ar; + + ath10k_snoc_rx_post(ar); +} + static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state) { struct ath10k *ar = ce_state->ar; @@ -620,6 +700,8 @@ static void ath10k_snoc_hif_stop(struct ath10k *ar) { ath10k_snoc_irq_disable(ar); ath10k_snoc_buffer_cleanup(ar); + napi_synchronize(&ar->napi); + napi_disable(&ar->napi); ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n"); } @@ -684,6 +766,7 @@ static int ath10k_snoc_hif_power_up(struct ath10k *ar) goto err_wlan_enable; } + napi_enable(&ar->napi); return 0; err_wlan_enable: @@ -711,11 +794,60 @@ static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { .write32 = ath10k_snoc_write32, }; +int ath10k_snoc_get_ce_id_from_irq(struct ath10k *ar, int irq) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + int i; + + for (i = 0; i < CE_COUNT_MAX; i++) { + if (ar_snoc->ce_irqs[i].irq_line == irq) + return i; + } + ath10k_err(ar, "No matching CE id for irq %d\n", irq); + + return -EINVAL; +} + static irqreturn_t ath10k_snoc_per_engine_handler(int irq, void *arg) { + struct ath10k *ar = arg; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + int ce_id = ath10k_snoc_get_ce_id_from_irq(ar, irq); + + if (ce_id < 0 || ce_id >= ARRAY_SIZE(ar_snoc->pipe_info)) { + ath10k_warn(ar, "unexpected/invalid irq %d ce_id %d\n", irq, + ce_id); + return IRQ_HANDLED; + } + + ath10k_snoc_irq_disable(ar); + napi_schedule(&ar->napi); + return IRQ_HANDLED; } +static int ath10k_snoc_napi_poll(struct napi_struct *ctx, int budget) +{ + struct ath10k *ar = container_of(ctx, struct ath10k, napi); + int done = 0; + + ath10k_ce_per_engine_service_any(ar); + done = ath10k_htt_txrx_compl_task(ar, budget); + + if (done < budget) { + napi_complete(ctx); + ath10k_snoc_irq_enable(ar); + } + + return done; +} + +void ath10k_snoc_init_napi(struct ath10k *ar) +{ + netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_snoc_napi_poll, + ATH10K_NAPI_BUDGET); +} + static int ath10k_snoc_request_irq(struct ath10k *ar) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); @@ -796,6 +928,7 @@ static int ath10k_snoc_setup_resource(struct ath10k *ar) struct ath10k_snoc_pipe *pipe; int i, ret; + timer_setup(&ar_snoc->rx_post_retry, ath10k_snoc_rx_replenish_retry, 0); spin_lock_init(&ce->ce_lock); for (i = 0; i < CE_COUNT; i++) { pipe = &ar_snoc->pipe_info[i]; @@ -812,6 +945,7 @@ static int ath10k_snoc_setup_resource(struct ath10k *ar) pipe->buf_sz = host_ce_config_wlan[i].src_sz_max; } + ath10k_snoc_init_napi(ar); return 0; } @@ -820,6 +954,7 @@ static void ath10k_snoc_release_resource(struct ath10k *ar) { int i; + netif_napi_del(&ar->napi); for (i = 0; i < CE_COUNT; i++) ath10k_ce_free_pipe(ar, i); } From d82a7363bb3dbc2d56e191c897fc0f59e05e41f8 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:27 +0300 Subject: [PATCH 051/192] UPSTREAM: ath10k: modify hif tx paddr to dma_addr_t type Change type of hif sg tx paddr to dma_addr_t for supporting target having addressing mode greater than 32 bit. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: 546d407c905bc893886edae52f2323db8eded9b9 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: Ieeaa5519bb5e812a715b274d4b8fa7c82f6af096 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/hif.h | 2 +- drivers/net/wireless/ath/ath10k/pci.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index 6da4e3369c5a..7abb13c1f10b 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -26,7 +26,7 @@ struct ath10k_hif_sg_item { u16 transfer_id; void *transfer_context; /* NULL = tx completion callback not called */ void *vaddr; /* for debugging mostly */ - u32 paddr; + dma_addr_t paddr; u16 len; }; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 3231abebce2b..77fa45a85c7e 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1374,8 +1374,8 @@ int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, for (i = 0; i < n_items - 1; i++) { ath10k_dbg(ar, ATH10K_DBG_PCI, - "pci tx item %d paddr 0x%08x len %d n_items %d\n", - i, items[i].paddr, items[i].len, n_items); + "pci tx item %d paddr %pad len %d n_items %d\n", + i, &items[i].paddr, items[i].len, n_items); ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ", items[i].vaddr, items[i].len); @@ -1392,8 +1392,8 @@ int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, /* `i` is equal to `n_items -1` after for() */ ath10k_dbg(ar, ATH10K_DBG_PCI, - "pci tx item %d paddr 0x%08x len %d n_items %d\n", - i, items[i].paddr, items[i].len, n_items); + "pci tx item %d paddr %pad len %d n_items %d\n", + i, &items[i].paddr, items[i].len, n_items); ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ", items[i].vaddr, items[i].len); From 840a718916544221dc45498fbe2a123a708c4596 Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Tue, 10 Apr 2018 18:01:29 +0300 Subject: [PATCH 052/192] UPSTREAM: ath10k: add support to get target info from hif ops wcn3990 does not use bmi. Add support to get target info from hif ops. Signed-off-by: Rakesh Pillai Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: 140d1214ef555bcb14c7720e91d8a9594e4ab506 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: If948d7d1739406ea04c98c40b6bce0112a74c770 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/core.c | 8 ++++++++ drivers/net/wireless/ath/ath10k/hif.h | 13 +++++++++++++ drivers/net/wireless/ath/ath10k/snoc.c | 10 ++++++++++ 3 files changed, 31 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 51444d34a06c..bcce87591282 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2437,6 +2437,14 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ar->hw->wiphy->hw_version = target_info.version; break; case ATH10K_BUS_SNOC: + memset(&target_info, 0, sizeof(target_info)); + ret = ath10k_hif_get_target_info(ar, &target_info); + if (ret) { + ath10k_err(ar, "could not get target info (%d)\n", ret); + goto err_power_down; + } + ar->target_version = target_info.version; + ar->hw->wiphy->hw_version = target_info.version; break; default: ath10k_err(ar, "incorrect hif bus type: %d\n", ar->hif.bus); diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index 7abb13c1f10b..1a59ea0068c2 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -20,6 +20,7 @@ #include #include "core.h" +#include "bmi.h" #include "debug.h" struct ath10k_hif_sg_item { @@ -93,6 +94,9 @@ struct ath10k_hif_ops { /* fetch calibration data from target eeprom */ int (*fetch_cal_eeprom)(struct ath10k *ar, void **data, size_t *data_len); + + int (*get_target_info)(struct ath10k *ar, + struct bmi_target_info *target_info); }; static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id, @@ -218,4 +222,13 @@ static inline int ath10k_hif_fetch_cal_eeprom(struct ath10k *ar, return ar->hif.ops->fetch_cal_eeprom(ar, data, data_len); } +static inline int ath10k_hif_get_target_info(struct ath10k *ar, + struct bmi_target_info *tgt_info) +{ + if (!ar->hif.ops->get_target_info) + return -EOPNOTSUPP; + + return ar->hif.ops->get_target_info(ar, tgt_info); +} + #endif /* _HIF_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 6d9cccee9bbe..1ef0d3b51b8f 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -528,6 +528,15 @@ static int ath10k_snoc_hif_tx_sg(struct ath10k *ar, u8 pipe_id, return err; } +static int ath10k_snoc_hif_get_target_info(struct ath10k *ar, + struct bmi_target_info *target_info) +{ + target_info->version = ATH10K_HW_WCN3990; + target_info->type = ATH10K_HW_WCN3990; + + return 0; +} + static u16 ath10k_snoc_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); @@ -787,6 +796,7 @@ static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .tx_sg = ath10k_snoc_hif_tx_sg, .send_complete_check = ath10k_snoc_hif_send_complete_check, .get_free_queue_number = ath10k_snoc_hif_get_free_queue_number, + .get_target_info = ath10k_snoc_hif_get_target_info, }; static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { From f56ba0370a9684e689d780ce38f461f0491a5da0 Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Tue, 10 Apr 2018 18:01:32 +0300 Subject: [PATCH 053/192] UPSTREAM: ath10k: check all CE for data if irq summary is not retained WCN3990 has interrupts per CE and the interrupt summary is not retained after the interrupt handler has finished execution. We need to check if we received any ce in rx and tx completion path. Generate a interrupt summary with all CE interrupts if the target does not retain interrupt summary after the execution of interrupt handler. Signed-off-by: Rakesh Pillai Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: ea66b12e63ac62de19685c6900903d22e2680be6 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: Id292fe83ad77621ee275bcc67c3f611770d5b4f0 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/ce.h | 10 +++++++--- drivers/net/wireless/ath/ath10k/core.c | 13 +++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 3 +++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 06ac2eb70bf5..0e70a07230d6 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -354,14 +354,18 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) (((x) & CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) >> \ CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB) #define CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS 0x0000 +#define CE_INTERRUPT_SUMMARY (GENMASK(CE_COUNT_MAX - 1, 0)) static inline u32 ath10k_ce_interrupt_summary(struct ath10k *ar) { struct ath10k_ce *ce = ath10k_ce_priv(ar); - return CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET( - ce->bus_ops->read32((ar), CE_WRAPPER_BASE_ADDRESS + - CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS)); + if (!ar->hw_params.per_ce_irq) + return CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET( + ce->bus_ops->read32((ar), CE_WRAPPER_BASE_ADDRESS + + CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS)); + else + return CE_INTERRUPT_SUMMARY; } #endif /* _CE_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index bcce87591282..8716ea495aea 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -89,6 +89,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA9887_HW_1_0_VERSION, @@ -118,6 +119,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -146,6 +148,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -174,6 +177,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA6174_HW_3_0_VERSION, @@ -202,6 +206,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA6174_HW_3_2_VERSION, @@ -233,6 +238,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA99X0_HW_2_0_DEV_VERSION, @@ -267,6 +273,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA9984_HW_1_0_DEV_VERSION, @@ -306,6 +313,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA9888_HW_2_0_DEV_VERSION, @@ -344,6 +352,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA9377_HW_1_0_DEV_VERSION, @@ -372,6 +381,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA9377_HW_1_1_DEV_VERSION, @@ -402,6 +412,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA4019_HW_1_0_DEV_VERSION, @@ -437,6 +448,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = WCN3990_HW_1_0_DEV_VERSION, @@ -457,6 +469,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = TARGET_HL_10_TLV_NUM_WDS_ENTRIES, .target_64bit = true, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL_DUAL_MAC, + .per_ce_irq = true, }, }; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index a8be98f1eb41..90293200e838 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -567,6 +567,9 @@ struct ath10k_hw_params { /* Target rx ring fill level */ u32 rx_ring_fill_level; + + /* target supporting per ce IRQ */ + bool per_ce_irq; }; struct htt_rx_desc; From 11ebe80796528cb574cafe789e588a5cf28a9ebf Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:34 +0300 Subject: [PATCH 054/192] UPSTREAM: ath10k: vote for hardware resources for WCN3990 Add clock and regulator votes for WCN3990 WLAN chipset. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: a6a793f98786fe146f8926b02b320f0d9b48a61c Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: Ifa8960c0266fa179e0ba2a9484de414a34eb4e71 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/snoc.c | 313 ++++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/snoc.h | 19 ++ 2 files changed, 331 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 1ef0d3b51b8f..2e490ff124f1 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #define WCN3990_CE_ATTR_FLAGS 0 #define ATH10K_SNOC_RX_POST_RETRY_MS 50 #define CE_POLL_PIPE 4 @@ -43,6 +45,17 @@ static char *const ce_name[] = { "WLAN_CE_11", }; +static struct ath10k_wcn3990_vreg_info vreg_cfg[] = { + {NULL, "vdd-0.8-cx-mx", 800000, 800000, 0, 0, false}, + {NULL, "vdd-1.8-xo", 1800000, 1800000, 0, 0, false}, + {NULL, "vdd-1.3-rfa", 1304000, 1304000, 0, 0, false}, + {NULL, "vdd-3.3-ch0", 3312000, 3312000, 0, 0, false}, +}; + +static struct ath10k_wcn3990_clk_info clk_cfg[] = { + {NULL, "cxo_ref_clk_pin", 0, false}, +}; + static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state); static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state); static void ath10k_snoc_htc_rx_cb(struct ath10k_ce_pipe *ce_state); @@ -969,6 +982,277 @@ static void ath10k_snoc_release_resource(struct ath10k *ar) ath10k_ce_free_pipe(ar, i); } +static int ath10k_get_vreg_info(struct ath10k *ar, struct device *dev, + struct ath10k_wcn3990_vreg_info *vreg_info) +{ + struct regulator *reg; + int ret = 0; + + reg = devm_regulator_get_optional(dev, vreg_info->name); + + if (IS_ERR(reg)) { + ret = PTR_ERR(reg); + + if (ret == -EPROBE_DEFER) { + ath10k_err(ar, "EPROBE_DEFER for regulator: %s\n", + vreg_info->name); + return ret; + } + if (vreg_info->required) { + ath10k_err(ar, "Regulator %s doesn't exist: %d\n", + vreg_info->name, ret); + return ret; + } + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "Optional regulator %s doesn't exist: %d\n", + vreg_info->name, ret); + goto done; + } + + vreg_info->reg = reg; + +done: + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "snog vreg %s min_v %u max_v %u load_ua %u settle_delay %lu\n", + vreg_info->name, vreg_info->min_v, vreg_info->max_v, + vreg_info->load_ua, vreg_info->settle_delay); + + return 0; +} + +static int ath10k_get_clk_info(struct ath10k *ar, struct device *dev, + struct ath10k_wcn3990_clk_info *clk_info) +{ + struct clk *handle; + int ret = 0; + + handle = devm_clk_get(dev, clk_info->name); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + if (clk_info->required) { + ath10k_err(ar, "snoc clock %s isn't available: %d\n", + clk_info->name, ret); + return ret; + } + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc ignoring clock %s: %d\n", + clk_info->name, + ret); + return 0; + } + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc clock %s freq %u\n", + clk_info->name, clk_info->freq); + + clk_info->handle = handle; + + return ret; +} + +static int ath10k_wcn3990_vreg_on(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_wcn3990_vreg_info *vreg_info; + int ret = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(vreg_cfg); i++) { + vreg_info = &ar_snoc->vreg[i]; + + if (!vreg_info->reg) + continue; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc regulator %s being enabled\n", + vreg_info->name); + + ret = regulator_set_voltage(vreg_info->reg, vreg_info->min_v, + vreg_info->max_v); + if (ret) { + ath10k_err(ar, + "failed to set regulator %s voltage-min: %d voltage-max: %d\n", + vreg_info->name, vreg_info->min_v, vreg_info->max_v); + goto err_reg_config; + } + + if (vreg_info->load_ua) { + ret = regulator_set_load(vreg_info->reg, + vreg_info->load_ua); + if (ret < 0) { + ath10k_err(ar, + "failed to set regulator %s load: %d\n", + vreg_info->name, + vreg_info->load_ua); + goto err_reg_config; + } + } + + ret = regulator_enable(vreg_info->reg); + if (ret) { + ath10k_err(ar, "failed to enable regulator %s\n", + vreg_info->name); + goto err_reg_config; + } + + if (vreg_info->settle_delay) + udelay(vreg_info->settle_delay); + } + + return 0; + +err_reg_config: + for (; i >= 0; i--) { + vreg_info = &ar_snoc->vreg[i]; + + if (!vreg_info->reg) + continue; + + regulator_disable(vreg_info->reg); + regulator_set_load(vreg_info->reg, 0); + regulator_set_voltage(vreg_info->reg, 0, vreg_info->max_v); + } + + return ret; +} + +static int ath10k_wcn3990_vreg_off(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_wcn3990_vreg_info *vreg_info; + int ret = 0; + int i; + + for (i = ARRAY_SIZE(vreg_cfg) - 1; i >= 0; i--) { + vreg_info = &ar_snoc->vreg[i]; + + if (!vreg_info->reg) + continue; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc regulator %s being disabled\n", + vreg_info->name); + + ret = regulator_disable(vreg_info->reg); + if (ret) + ath10k_err(ar, "failed to disable regulator %s\n", + vreg_info->name); + + ret = regulator_set_load(vreg_info->reg, 0); + if (ret < 0) + ath10k_err(ar, "failed to set load %s\n", + vreg_info->name); + + ret = regulator_set_voltage(vreg_info->reg, 0, + vreg_info->max_v); + if (ret) + ath10k_err(ar, "failed to set voltage %s\n", + vreg_info->name); + } + + return ret; +} + +static int ath10k_wcn3990_clk_init(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_wcn3990_clk_info *clk_info; + int ret = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(clk_cfg); i++) { + clk_info = &ar_snoc->clk[i]; + + if (!clk_info->handle) + continue; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc clock %s being enabled\n", + clk_info->name); + + if (clk_info->freq) { + ret = clk_set_rate(clk_info->handle, clk_info->freq); + + if (ret) { + ath10k_err(ar, "failed to set clock %s freq %u\n", + clk_info->name, clk_info->freq); + goto err_clock_config; + } + } + + ret = clk_prepare_enable(clk_info->handle); + if (ret) { + ath10k_err(ar, "failed to enable clock %s\n", + clk_info->name); + goto err_clock_config; + } + } + + return 0; + +err_clock_config: + for (; i >= 0; i--) { + clk_info = &ar_snoc->clk[i]; + + if (!clk_info->handle) + continue; + + clk_disable_unprepare(clk_info->handle); + } + + return ret; +} + +static int ath10k_wcn3990_clk_deinit(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_wcn3990_clk_info *clk_info; + int i; + + for (i = 0; i < ARRAY_SIZE(clk_cfg); i++) { + clk_info = &ar_snoc->clk[i]; + + if (!clk_info->handle) + continue; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc clock %s being disabled\n", + clk_info->name); + + clk_disable_unprepare(clk_info->handle); + } + + return 0; +} + +static int ath10k_hw_power_on(struct ath10k *ar) +{ + int ret; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power on\n"); + + ret = ath10k_wcn3990_vreg_on(ar); + if (ret) + return ret; + + ret = ath10k_wcn3990_clk_init(ar); + if (ret) + goto vreg_off; + + return ret; + +vreg_off: + ath10k_wcn3990_vreg_off(ar); + return ret; +} + +static int ath10k_hw_power_off(struct ath10k *ar) +{ + int ret; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power off\n"); + + ath10k_wcn3990_clk_deinit(ar); + + ret = ath10k_wcn3990_vreg_off(ar); + + return ret; +} + static const struct of_device_id ath10k_snoc_dt_match[] = { { .compatible = "qcom,wcn3990-wifi", .data = &drv_priv, @@ -985,6 +1269,7 @@ static int ath10k_snoc_probe(struct platform_device *pdev) struct device *dev; struct ath10k *ar; int ret; + u32 i; of_id = of_match_device(ath10k_snoc_dt_match, &pdev->dev); if (!of_id) { @@ -1031,16 +1316,41 @@ static int ath10k_snoc_probe(struct platform_device *pdev) ath10k_warn(ar, "failed to request irqs: %d\n", ret); goto err_release_resource; } + + ar_snoc->vreg = vreg_cfg; + for (i = 0; i < ARRAY_SIZE(vreg_cfg); i++) { + ret = ath10k_get_vreg_info(ar, dev, &ar_snoc->vreg[i]); + if (ret) + goto err_free_irq; + } + + ar_snoc->clk = clk_cfg; + for (i = 0; i < ARRAY_SIZE(clk_cfg); i++) { + ret = ath10k_get_clk_info(ar, dev, &ar_snoc->clk[i]); + if (ret) + goto err_free_irq; + } + + ret = ath10k_hw_power_on(ar); + if (ret) { + ath10k_err(ar, "failed to power on device: %d\n", ret); + goto err_free_irq; + } + ret = ath10k_core_register(ar, drv_data->hw_rev); if (ret) { ath10k_err(ar, "failed to register driver core: %d\n", ret); - goto err_free_irq; + goto err_hw_power_off; } + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n"); ath10k_warn(ar, "Warning: SNOC support is still work-in-progress, it will not work properly!"); return 0; +err_hw_power_off: + ath10k_hw_power_off(ar); + err_free_irq: ath10k_snoc_free_irq(ar); @@ -1059,6 +1369,7 @@ static int ath10k_snoc_remove(struct platform_device *pdev) ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc remove\n"); ath10k_core_unregister(ar); + ath10k_hw_power_off(ar); ath10k_snoc_free_irq(ar); ath10k_snoc_release_resource(ar); ath10k_core_destroy(ar); diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index cf65b01e0085..05dc98f46ccd 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -52,6 +52,23 @@ struct ath10k_snoc_ce_irq { u32 irq_line; }; +struct ath10k_wcn3990_vreg_info { + struct regulator *reg; + const char *name; + u32 min_v; + u32 max_v; + u32 load_ua; + unsigned long settle_delay; + bool required; +}; + +struct ath10k_wcn3990_clk_info { + struct clk *handle; + const char *name; + u32 freq; + bool required; +}; + struct ath10k_snoc { struct platform_device *dev; struct ath10k *ar; @@ -63,6 +80,8 @@ struct ath10k_snoc { struct ath10k_snoc_ce_irq ce_irqs[CE_COUNT_MAX]; struct ath10k_ce ce; struct timer_list rx_post_retry; + struct ath10k_wcn3990_vreg_info *vreg; + struct ath10k_wcn3990_clk_info *clk; }; static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) From 0a1dfc99e5288fe0e43d66c02018b258c9ae3fbe Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Fri, 12 Jun 2020 12:41:55 +0800 Subject: [PATCH 055/192] drm/msm/sde: use atomic counter for pending frame done SDE encoder uses bit mask logic to check the pending pp_done IRQ for dual dsi and trigger release fence when both IRQs are received. It causes issue when encoder triggers two frames back to back without waiting for first frame done. Bitmask clears the frame done prematurely and miss to trigger the release fence for second frame. Atomic counter usages allows to track the number of pending IRQ and release frame_done when both pp_done IRQs are received. Change-Id: I669aea124bae922641afe5d34f8f035dc5de82b3 Signed-off-by: Dhaval Patel Signed-off-by: Bruce Hoo Signed-off-by: Ray Zhang --- drivers/gpu/drm/msm/sde/sde_encoder.c | 90 +++++++++++++-------------- 1 file changed, 44 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index f455f24da622..e83b3063c99a 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -197,9 +197,8 @@ enum sde_enc_rc_states { * @debugfs_root: Debug file system root file node * @enc_lock: Lock around physical encoder create/destroy and access. - * @frame_busy_mask: Bitmask tracking which phys_enc we are still - * busy processing current command. - * Bit0 = phys_encs[0] etc. + * @frame_done_cnt: Atomic counter for tracking which phy_enc is + * done with frame processing. * @crtc_frame_event_cb: callback handler for frame event * @crtc_frame_event_cb_data: callback handler private data * @vsync_event_timer: vsync timer @@ -260,7 +259,7 @@ struct sde_encoder_virt { struct dentry *debugfs_root; struct mutex enc_lock; - DECLARE_BITMAP(frame_busy_mask, MAX_PHYS_ENCODERS_PER_VIRTUAL); + atomic_t frame_done_cnt[MAX_PHYS_ENCODERS_PER_VIRTUAL]; void (*crtc_frame_event_cb)(void *, u32 event); struct sde_crtc_frame_event_cb_data crtc_frame_event_cb_data; @@ -2448,6 +2447,16 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, return -EINVAL; } + /* + * schedule off work item only when there are no + * frames pending + */ + if (sde_crtc_frame_pending(sde_enc->crtc) > 1) { + SDE_DEBUG_ENC(sde_enc, "skip schedule work"); + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_EVTLOG_FUNC_CASE2); + return 0; + } if (sde_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) { SDE_ERROR("invalid crtc index :%u\n", sde_enc->crtc->index); @@ -2469,17 +2478,6 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, return -EINVAL; } - /* - * schedule off work item only when there are no - * frames pending - */ - if (sde_crtc_frame_pending(sde_enc->crtc) > 1) { - SDE_DEBUG_ENC(sde_enc, "skip schedule work"); - SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, - SDE_EVTLOG_FUNC_CASE2); - return 0; - } - /* schedule delayed off work if autorefresh is disabled */ if (sde_enc->cur_master && sde_enc->cur_master->ops.is_autorefresh_enabled) @@ -2692,17 +2690,10 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, SDE_EVTLOG_ERROR); mutex_unlock(&sde_enc->rc_lock); return 0; - } - - /* - * if we are in ON but a frame was just kicked off, - * ignore the IDLE event, it's probably a stale timer event - */ - if (sde_enc->frame_busy_mask[0]) { - SDE_ERROR_ENC(sde_enc, - "sw_event:%d, rc:%d frame pending\n", - sw_event, sde_enc->rc_state); + } else if (sde_crtc_frame_pending(sde_enc->crtc) > 1) { + SDE_DEBUG_ENC(sde_enc, "skip idle entry"); SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + sde_crtc_frame_pending(sde_enc->crtc), SDE_EVTLOG_ERROR); mutex_unlock(&sde_enc->rc_lock); return 0; @@ -3663,6 +3654,8 @@ static void sde_encoder_frame_done_callback( { struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); unsigned int i; + bool trigger = true; + enum sde_rm_topology_name topology = SDE_RM_TOPOLOGY_NONE; if (!drm_enc || !sde_enc->cur_master) { SDE_ERROR("invalid param: drm_enc %lx, cur_master %lx\n", @@ -3677,26 +3670,35 @@ static void sde_encoder_frame_done_callback( if (event & (SDE_ENCODER_FRAME_EVENT_DONE | SDE_ENCODER_FRAME_EVENT_ERROR | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)) { - - if (!sde_enc->frame_busy_mask[0]) { - /** - * suppress frame_done without waiter, - * likely autorefresh - */ - SDE_EVT32(DRMID(drm_enc), event, ready_phys->intf_idx); - return; - } + if (ready_phys->connector) + topology = sde_connector_get_topology_name( + ready_phys->connector); /* One of the physical encoders has become idle */ for (i = 0; i < sde_enc->num_phys_encs; i++) { - if (sde_enc->phys_encs[i] == ready_phys) { - clear_bit(i, sde_enc->frame_busy_mask); + if ((sde_enc->phys_encs[i] == ready_phys) || + (event & SDE_ENCODER_FRAME_EVENT_ERROR)) { SDE_EVT32_VERBOSE(DRMID(drm_enc), i, - sde_enc->frame_busy_mask[0]); + atomic_read( + &sde_enc->frame_done_cnt[i])); + if (!atomic_add_unless( + &sde_enc->frame_done_cnt[i], 1, 1)) { + SDE_EVT32(DRMID(drm_enc), event, + ready_phys->intf_idx, + SDE_EVTLOG_ERROR); + SDE_ERROR_ENC(sde_enc, + "intf idx:%d, event:%d\n", + ready_phys->intf_idx, event); + return; + } } + + if (topology != SDE_RM_TOPOLOGY_PPSPLIT && + atomic_read(&sde_enc->frame_done_cnt[i]) != 1) + trigger = false; } - if (!sde_enc->frame_busy_mask[0]) { + if (trigger) { sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_FRAME_DONE); @@ -3704,6 +3706,8 @@ static void sde_encoder_frame_done_callback( sde_enc->crtc_frame_event_cb( &sde_enc->crtc_frame_event_cb_data, event); + for (i = 0; i < sde_enc->num_phys_encs; i++) + atomic_set(&sde_enc->frame_done_cnt[i], 0); } } else { if (sde_enc->crtc_frame_event_cb) @@ -4015,14 +4019,6 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc) if (phys->connector) topology = sde_connector_get_topology_name( phys->connector); - /* - * don't wait on ppsplit slaves or skipped encoders because - * they dont receive irqs - */ - if (!(topology == SDE_RM_TOPOLOGY_PPSPLIT && - phys->split_role == ENC_ROLE_SLAVE) && - phys->split_role != ENC_ROLE_SKIP) - set_bit(i, sde_enc->frame_busy_mask); if (!phys->ops.needs_single_flush || !phys->ops.needs_single_flush(phys)) { @@ -5487,6 +5483,8 @@ struct drm_encoder *sde_encoder_init_with_ops( sde_enc->cur_master = NULL; spin_lock_init(&sde_enc->enc_spinlock); mutex_init(&sde_enc->vblank_ctl_lock); + for (i = 0; i < MAX_PHYS_ENCODERS_PER_VIRTUAL; i++) + atomic_set(&sde_enc->frame_done_cnt[i], 0); drm_enc = &sde_enc->base; drm_encoder_init(dev, drm_enc, &sde_encoder_funcs, drm_enc_mode, NULL); drm_encoder_helper_add(drm_enc, &sde_encoder_helper_funcs); From 48327dbe33690edce9daa610a32b20f452dc8a63 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Fri, 12 Jun 2020 16:54:36 +0800 Subject: [PATCH 056/192] drm/msm/sde: support posted frame trigger for cmd mode Support posted frame trigger for command mode panel with queue depth 1. It allows panel vsync time for frame transfer duration and reduces the MDP clock and BW requirement. The change also support debugfs entry support to select the cmd mode frame done wait between serialize trigger, posted trigger and default behavior. Change-Id: I84134a6458665c40e94aa29805e528caa2d91a93 Signed-off-by: Dhaval Patel Signed-off-by: Bruce Hoo Signed-off-by: Ray Zhang --- drivers/gpu/drm/msm/sde/sde_encoder.c | 7 ++ drivers/gpu/drm/msm/sde/sde_encoder.h | 3 +- drivers/gpu/drm/msm/sde/sde_encoder_phys.h | 8 +- .../gpu/drm/msm/sde/sde_encoder_phys_cmd.c | 86 +++++++++++-------- drivers/gpu/drm/msm/sde/sde_kms.h | 16 +++- 5 files changed, 79 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index e83b3063c99a..f1d288ef7da8 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -221,6 +221,8 @@ enum sde_enc_rc_states { * @topology: topology of the display * @vblank_enabled: boolean to track userspace vblank vote * @idle_pc_restore: flag to indicate idle_pc_restore happened + * @frame_trigger_mode: frame trigger mode indication for command + * mode display * @rsc_config: rsc configuration for display vtotal, fps, etc. * @cur_conn_roi: current connector roi * @prv_conn_roi: previous connector roi to optimize if unchanged @@ -283,6 +285,7 @@ struct sde_encoder_virt { struct msm_display_topology topology; bool vblank_enabled; bool idle_pc_restore; + enum frame_trigger_mode_type frame_trigger_mode; struct sde_rsc_cmd_config rsc_config; struct sde_rect cur_conn_roi; @@ -3316,6 +3319,7 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) phys->comp_type = comp_info->comp_type; phys->comp_ratio = comp_info->comp_ratio; phys->wide_bus_en = mode_info.wide_bus_en; + phys->frame_trigger_mode = sde_enc->frame_trigger_mode; if (phys->comp_type == MSM_DISPLAY_COMPRESSION_DSC) { phys->dsc_extra_pclk_cycle_cnt = @@ -5152,6 +5156,9 @@ static int _sde_encoder_init_debugfs(struct drm_encoder *drm_enc) debugfs_create_bool("idle_power_collapse", 0600, sde_enc->debugfs_root, &sde_enc->idle_pc_enabled); + debugfs_create_u32("frame_trigger_mode", 0600, sde_enc->debugfs_root, + &sde_enc->frame_trigger_mode); + for (i = 0; i < sde_enc->num_phys_encs; i++) if (sde_enc->phys_encs[i] && sde_enc->phys_encs[i]->ops.late_register) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h index 74639846af3b..7fa700e2910a 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -23,6 +23,7 @@ #include "msm_prop.h" #include "sde_hw_mdss.h" +#include "sde_kms.h" #define SDE_ENCODER_FRAME_EVENT_DONE BIT(0) #define SDE_ENCODER_FRAME_EVENT_ERROR BIT(1) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h index 1fe0075d03d3..841ffb9f7407 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -296,6 +296,8 @@ struct sde_encoder_irq { * @in_clone_mode Indicates if encoder is in clone mode ref@CWB * @vfp_cached: cached vertical front porch to be used for * programming ROT and MDP fetch start + * @frame_trigger_mode: frame trigger mode indication for command + * mode display */ struct sde_encoder_phys { struct drm_encoder *parent; @@ -339,6 +341,7 @@ struct sde_encoder_phys { bool cont_splash_enabled; bool in_clone_mode; int vfp_cached; + enum frame_trigger_mode_type frame_trigger_mode; }; static inline int sde_encoder_phys_inc_pending(struct sde_encoder_phys *phys) @@ -382,8 +385,6 @@ struct sde_encoder_phys_cmd_autorefresh { * @base: Baseclass physical encoder structure * @intf_idx: Intf Block index used by this phys encoder * @stream_sel: Stream selection for multi-stream interfaces - * @serialize_wait4pp: serialize wait4pp feature waits for pp_done interrupt - * after ctl_start instead of before next frame kickoff * @pp_timeout_report_cnt: number of pingpong done irq timeout errors * @autorefresh: autorefresh feature state * @pending_rd_ptr_cnt: atomic counter to indicate if retire fence can be @@ -397,7 +398,6 @@ struct sde_encoder_phys_cmd_autorefresh { struct sde_encoder_phys_cmd { struct sde_encoder_phys base; int stream_sel; - bool serialize_wait4pp; int pp_timeout_report_cnt; struct sde_encoder_phys_cmd_autorefresh autorefresh; atomic_t pending_rd_ptr_cnt; diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index c6f5b15c70b4..8fd37447bb8c 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -199,24 +199,6 @@ static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx) SDE_ATRACE_BEGIN("pp_done_irq"); - /* handle rare cases where the ctl_start_irq is not received */ - if (sde_encoder_phys_cmd_is_master(phys_enc)) { - /* - * Reduce the refcount for the retire fence as well - * as for the ctl_start if the counters are greater - * than zero. If there was a retire fence count pending, - * then signal the RETIRE FENCE here. - */ - if (atomic_add_unless(&phys_enc->pending_retire_fence_cnt, - -1, 0)) - phys_enc->parent_ops.handle_frame_done( - phys_enc->parent, - phys_enc, - SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE); - atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0); - atomic_set(&phys_enc->ctlstart_timeout, 0); - } - /* notify all synchronous clients first, then asynchronous clients */ if (phys_enc->parent_ops.handle_frame_done) phys_enc->parent_ops.handle_frame_done(phys_enc->parent, @@ -229,6 +211,23 @@ static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx) SDE_EVT32_IRQ(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, new_cnt, event); + /* + * Reduce the refcount for the retire fence as well as for the ctl_start + * if the counters are greater than zero. Signal retire fence if there + * was a retire fence count pending and kickoff count is zero. + */ + if (sde_encoder_phys_cmd_is_master(phys_enc) && (new_cnt == 0)) { + while (atomic_add_unless(&phys_enc->pending_retire_fence_cnt, + -1, 0)) { + if (phys_enc->parent_ops.handle_frame_done) + phys_enc->parent_ops.handle_frame_done( + phys_enc->parent, phys_enc, + SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE); + atomic_add_unless(&phys_enc->pending_ctlstart_cnt, + -1, 0); + } + } + /* Signal any waiting atomic commit thread */ wake_up_all(&phys_enc->pending_kickoff_wq); SDE_ATRACE_END("pp_done_irq"); @@ -545,6 +544,10 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout( conn = phys_enc->connector; sde_conn = to_sde_connector(conn); + + if (atomic_read(&phys_enc->pending_kickoff_cnt) == 0) + return 0; + cmd_enc->pp_timeout_report_cnt++; pending_kickoff_cnt = atomic_read(&phys_enc->pending_kickoff_cnt); @@ -744,7 +747,7 @@ static int _sde_encoder_phys_cmd_wait_for_idle( to_sde_encoder_phys_cmd(phys_enc); struct sde_encoder_wait_info wait_info; bool recovery_events; - int ret; + int ret, i, pending_cnt; if (!phys_enc) { SDE_ERROR("invalid encoder\n"); @@ -764,7 +767,9 @@ static int _sde_encoder_phys_cmd_wait_for_idle( ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_PINGPONG, &wait_info); if (ret == -ETIMEDOUT) { - _sde_encoder_phys_cmd_handle_ppdone_timeout(phys_enc, + pending_cnt = atomic_read(&phys_enc->pending_kickoff_cnt); + for (i = 0; i < pending_cnt; i++) + _sde_encoder_phys_cmd_handle_ppdone_timeout(phys_enc, recovery_events); } else if (!ret) { if (cmd_enc->pp_timeout_report_cnt && recovery_events) { @@ -1360,7 +1365,7 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff( struct sde_hw_tear_check tc_cfg = {0}; struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc); - int ret; + int ret = 0; u32 extra_frame_trigger_time; if (!phys_enc || !phys_enc->hw_pp) { @@ -1373,17 +1378,19 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff( atomic_read(&phys_enc->pending_kickoff_cnt), atomic_read(&cmd_enc->autorefresh.kickoff_cnt)); - /* - * Mark kickoff request as outstanding. If there are more than one, - * outstanding, then we have to wait for the previous one to complete - */ - ret = _sde_encoder_phys_cmd_wait_for_idle(phys_enc); - if (ret) { - /* force pending_kickoff_cnt 0 to discard failed kickoff */ - atomic_set(&phys_enc->pending_kickoff_cnt, 0); - SDE_EVT32(DRMID(phys_enc->parent), + if (phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_DEFAULT) { + /* + * Mark kickoff request as outstanding. If there are more than + * one outstanding frame, then we have to wait for the previous + * frame to complete + */ + ret = _sde_encoder_phys_cmd_wait_for_idle(phys_enc); + if (ret) { + atomic_set(&phys_enc->pending_kickoff_cnt, 0); + SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0); - SDE_ERROR("failed wait_for_idle: %d\n", ret); + SDE_ERROR("failed wait_for_idle: %d\n", ret); + } } if (sde_connector_is_qsync_updated(phys_enc->connector)) { @@ -1511,9 +1518,18 @@ static int sde_encoder_phys_cmd_wait_for_commit_done( cmd_enc->autorefresh.cfg.enable) rc = _sde_encoder_phys_cmd_wait_for_autorefresh_done(phys_enc); - /* required for both controllers */ - if (!rc && cmd_enc->serialize_wait4pp) - sde_encoder_phys_cmd_prepare_for_kickoff(phys_enc, NULL); + /* wait for posted start or serialize trigger */ + if ((atomic_read(&phys_enc->pending_kickoff_cnt) > 1) || + (!rc && phys_enc->frame_trigger_mode == + FRAME_DONE_WAIT_SERIALIZE)) { + rc = _sde_encoder_phys_cmd_wait_for_idle(phys_enc); + if (rc) { + atomic_set(&phys_enc->pending_kickoff_cnt, 0); + SDE_EVT32(DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0); + SDE_ERROR("failed wait_for_idle: %d\n", rc); + } + } return rc; } diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h index 1001bc1a48be..d11393fa8890 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.h +++ b/drivers/gpu/drm/msm/sde/sde_kms.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -169,6 +169,20 @@ enum sde_kms_sui_misr_state { SUI_MISR_DISABLE_REQ }; +/* + * @FRAME_DONE_WAIT_DEFAULT: waits for frame N pp_done interrupt before + * triggering frame N+1. + * @FRAME_DONE_WAIT_SERIALIZE: serialize pp_done and ctl_start irq for frame + * N without next frame trigger wait. + * @FRAME_DONE_WAIT_POSTED_START: Do not wait for pp_done interrupt for any + * frame. Wait will trigger only for error case. + */ +enum frame_trigger_mode_type { + FRAME_DONE_WAIT_DEFAULT, + FRAME_DONE_WAIT_SERIALIZE, + FRAME_DONE_WAIT_POSTED_START, +}; + /** * struct sde_kms_smmu_state_data: stores the smmu state and transition type * @state: current state of smmu context banks From 71e67aaa4409b6defcb9f51db4b7eecc729b3d1d Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Fri, 12 Jun 2020 17:23:21 +0800 Subject: [PATCH 057/192] drm/msm/sde: delay reset frame by a frame for posted trigger Posted frame trigger method triggers the frame without checking for frame done for previous frame. However, it waits for current frame trigger. It should iniatiate the recovery sequence only if current frame trigger fails. Change-Id: I3eac35ba722ac01a57504e78c628e82b3dcfb526 Signed-off-by: Dhaval Patel Signed-off-by: Bruce Hoo Signed-off-by: Ray Zhang --- drivers/gpu/drm/msm/sde/sde_crtc.c | 18 ++++++++--------- drivers/gpu/drm/msm/sde/sde_crtc.h | 28 ++++++++++++++++++++++++++- drivers/gpu/drm/msm/sde/sde_encoder.c | 3 +++ drivers/gpu/drm/msm/sde/sde_encoder.h | 2 ++ drivers/gpu/drm/msm/sde/sde_kms.c | 1 + 5 files changed, 42 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index 05737a441df3..e8e6648e28b9 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -4092,14 +4092,13 @@ static void _sde_crtc_remove_pipe_flush(struct drm_crtc *crtc) } /** - * _sde_crtc_reset_hw - attempt hardware reset on errors + * sde_crtc_reset_hw - attempt hardware reset on errors * @crtc: Pointer to DRM crtc instance * @old_state: Pointer to crtc state for previous commit * @recovery_events: Whether or not recovery events are enabled * Returns: Zero if current commit should still be attempted */ -static int _sde_crtc_reset_hw(struct drm_crtc *crtc, - struct drm_crtc_state *old_state, +int sde_crtc_reset_hw(struct drm_crtc *crtc, struct drm_crtc_state *old_state, bool recovery_events) { struct drm_plane *plane_halt[MAX_PLANES]; @@ -4297,9 +4296,10 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, struct msm_drm_private *priv; struct sde_kms *sde_kms; struct sde_crtc_state *cstate; - bool is_error, reset_req, recovery_events; + bool is_error, reset_req; unsigned long flags; enum sde_crtc_idle_pc_state idle_pc_state; + struct sde_encoder_kickoff_params params = { 0 }; if (!crtc) { SDE_ERROR("invalid argument\n"); @@ -4333,7 +4333,6 @@ void sde_crtc_commit_kickoff(struct drm_crtc *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 }; if (encoder->crtc != crtc) continue; @@ -4348,9 +4347,6 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, if (sde_encoder_prepare_for_kickoff(encoder, ¶ms)) reset_req = true; - recovery_events = - sde_encoder_recovery_events_enabled(encoder); - if (idle_pc_state != IDLE_PC_NONE) sde_encoder_control_idle_pc(encoder, (idle_pc_state == IDLE_PC_ENABLE) ? true : false); @@ -4361,7 +4357,11 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, * preparing for the kickoff */ if (reset_req) { - if (_sde_crtc_reset_hw(crtc, old_state, recovery_events)) + sde_crtc->frame_trigger_mode = params.frame_trigger_mode; + if (sde_crtc->frame_trigger_mode + != FRAME_DONE_WAIT_POSTED_START && + sde_crtc_reset_hw(crtc, old_state, + params.recovery_events_enabled)) is_error = true; } diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h index aea5290c0538..d3d875f08492 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.h +++ b/drivers/gpu/drm/msm/sde/sde_crtc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -227,6 +227,7 @@ struct sde_crtc_fps_info { * @rp_lock : serialization lock for resource pool * @rp_head : list of active resource pool * @plane_mask_old: keeps track of the planes used in the previous commit + * @frame_trigger_mode: frame trigger mode */ struct sde_crtc { struct drm_crtc base; @@ -305,6 +306,7 @@ struct sde_crtc { /* blob for histogram data */ struct drm_property_blob *hist_blob; + enum frame_trigger_mode_type frame_trigger_mode; }; #define to_sde_crtc(x) container_of(x, struct sde_crtc, base) @@ -542,6 +544,30 @@ static inline int sde_crtc_frame_pending(struct drm_crtc *crtc) return atomic_read(&sde_crtc->frame_pending); } +/** + * sde_crtc_reset_hw - attempt hardware reset on errors + * @crtc: Pointer to DRM crtc instance + * @old_state: Pointer to crtc state for previous commit + * @recovery_events: Whether or not recovery events are enabled + * Returns: Zero if current commit should still be attempted + */ +int sde_crtc_reset_hw(struct drm_crtc *crtc, struct drm_crtc_state *old_state, + bool recovery_events); + +/** + * sde_crtc_request_frame_reset - requests for next frame reset + * @crtc: Pointer to drm crtc object + */ +static inline int sde_crtc_request_frame_reset(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + + if (sde_crtc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START) + sde_crtc_reset_hw(crtc, crtc->state, false); + + return 0; +} + /** * sde_crtc_vblank - enable or disable vblanks for this crtc * @crtc: Pointer to drm crtc object diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index f1d288ef7da8..402e52e118a8 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -4683,6 +4683,9 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, for (i = 0; i < sde_enc->num_phys_encs; i++) { phys = sde_enc->phys_encs[i]; params->is_primary = sde_enc->disp_info.is_primary; + params->frame_trigger_mode = sde_enc->frame_trigger_mode; + params->recovery_events_enabled = + sde_enc->recovery_events_enabled; if (phys) { if (phys->ops.prepare_for_kickoff) { rc = phys->ops.prepare_for_kickoff( diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h index 7fa700e2910a..69b3ad28bb01 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder.h @@ -60,12 +60,14 @@ struct sde_encoder_hw_resources { * @affected_displays: bitmask, bit set means the ROI of the commit lies within * the bounds of the physical display at the bit index * @recovery_events_enabled: indicates status of client for recoovery events + * @frame_trigger_mode: indicates frame trigger mode */ struct sde_encoder_kickoff_params { u32 inline_rotate_prefill; u32 is_primary; unsigned long affected_displays; bool recovery_events_enabled; + enum frame_trigger_mode_type frame_trigger_mode; }; /** diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index 1c75a5948f59..0dd52d7ac3c1 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -1220,6 +1220,7 @@ static void sde_kms_wait_for_commit_done(struct msm_kms *kms, ret = sde_encoder_wait_for_event(encoder, MSM_ENC_COMMIT_DONE); if (ret && ret != -EWOULDBLOCK) { SDE_ERROR("wait for commit done returned %d\n", ret); + sde_crtc_request_frame_reset(crtc); break; } From 3e588c3b32dc37216bb12951e121c975073448b5 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Fri, 12 Jun 2020 17:38:48 +0800 Subject: [PATCH 058/192] drm/msm/sde: add connector property for frame trigger mode Add connector property for frame trigger mode. Change-Id: I6d193032b49c3a230b3e9a4897a9822540af61a2 Signed-off-by: Dhaval Patel Signed-off-by: Bruce Hoo Signed-off-by: Ray Zhang --- drivers/gpu/drm/msm/msm_drv.h | 3 +- drivers/gpu/drm/msm/sde/sde_connector.c | 243 +++++++++++++----------- drivers/gpu/drm/msm/sde/sde_encoder.c | 54 +++--- 3 files changed, 166 insertions(+), 134 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 4862ba8e5b06..b415efd4ef6b 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -199,6 +199,7 @@ enum msm_mdp_conn_property { CONNECTOR_PROP_LP, CONNECTOR_PROP_FB_TRANSLATION_MODE, CONNECTOR_PROP_QSYNC_MODE, + CONNECTOR_PROP_CMD_FRAME_TRIGGER_MODE, /* total # of properties */ CONNECTOR_PROP_COUNT diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index 49061de5b559..3b8db0bcea4d 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -64,6 +64,12 @@ static const struct drm_prop_enum_list e_qsync_mode[] = { {SDE_RM_QSYNC_ONE_SHOT_MODE, "one_shot"}, }; +static const struct drm_prop_enum_list e_frame_trigger_mode[] = { + {FRAME_DONE_WAIT_DEFAULT, "default"}, + {FRAME_DONE_WAIT_SERIALIZE, "serialize_frame_trigger"}, + {FRAME_DONE_WAIT_POSTED_START, "posted_start"}, +}; + static int sde_backlight_device_update_status(struct backlight_device *bd) { int brightness; @@ -1196,6 +1202,12 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, c_conn->bl_scale_ad = val; c_conn->bl_scale_dirty = true; break; + case CONNECTOR_PROP_HDR_METADATA: + rc = _sde_connector_set_ext_hdr_info(c_conn, + c_state, (void __user *)(uintptr_t)val); + if (rc) + SDE_ERROR_CONN(c_conn, "cannot set hdr info %d\n", rc); + break; case CONNECTOR_PROP_QSYNC_MODE: msm_property_set_dirty(&c_conn->property_info, &c_state->property_state, idx); @@ -1204,13 +1216,6 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, break; } - if (idx == CONNECTOR_PROP_HDR_METADATA) { - rc = _sde_connector_set_ext_hdr_info(c_conn, - c_state, (void *)(uintptr_t)val); - if (rc) - SDE_ERROR_CONN(c_conn, "cannot set hdr info %d\n", rc); - } - /* check for custom property handling */ if (!rc && c_conn->ops.set_property) { rc = c_conn->ops.set_property(connector, @@ -2117,6 +2122,122 @@ int sde_connector_set_blob_data(struct drm_connector *conn, return rc; } +static int _sde_connector_install_properties(struct drm_device *dev, + struct sde_kms *sde_kms, struct sde_connector *c_conn, + int connector_type, void *display, + struct msm_display_info *display_info) +{ + struct dsi_display *dsi_display; + int rc; + + msm_property_install_blob(&c_conn->property_info, "capabilities", + DRM_MODE_PROP_IMMUTABLE, CONNECTOR_PROP_SDE_INFO); + + rc = sde_connector_set_blob_data(&c_conn->base, + NULL, CONNECTOR_PROP_SDE_INFO); + if (rc) { + SDE_ERROR_CONN(c_conn, + "failed to setup connector info, rc = %d\n", rc); + return rc; + } + + msm_property_install_blob(&c_conn->property_info, "mode_properties", + DRM_MODE_PROP_IMMUTABLE, CONNECTOR_PROP_MODE_INFO); + + if (connector_type == DRM_MODE_CONNECTOR_DSI) { + dsi_display = (struct dsi_display *)(display); + if (dsi_display && dsi_display->panel && + dsi_display->panel->hdr_props.hdr_enabled == true) { + msm_property_install_blob(&c_conn->property_info, + "hdr_properties", + DRM_MODE_PROP_IMMUTABLE, + CONNECTOR_PROP_HDR_INFO); + + msm_property_set_blob(&c_conn->property_info, + &c_conn->blob_hdr, + &dsi_display->panel->hdr_props, + sizeof(dsi_display->panel->hdr_props), + CONNECTOR_PROP_HDR_INFO); + } + } + + msm_property_install_volatile_range( + &c_conn->property_info, "sde_drm_roi_v1", 0x0, + 0, ~0, 0, CONNECTOR_PROP_ROI_V1); + + /* install PP_DITHER properties */ + _sde_connector_install_dither_property(dev, sde_kms, c_conn); + + if (connector_type == DRM_MODE_CONNECTOR_DisplayPort) { + struct drm_msm_ext_hdr_properties hdr = {0}; + + msm_property_install_blob(&c_conn->property_info, + "ext_hdr_properties", + DRM_MODE_PROP_IMMUTABLE, + CONNECTOR_PROP_EXT_HDR_INFO); + + /* set default values to avoid reading uninitialized data */ + msm_property_set_blob(&c_conn->property_info, + &c_conn->blob_ext_hdr, + &hdr, + sizeof(hdr), + CONNECTOR_PROP_EXT_HDR_INFO); + } + + msm_property_install_volatile_range(&c_conn->property_info, + "hdr_metadata", 0x0, 0, ~0, 0, CONNECTOR_PROP_HDR_METADATA); + + msm_property_install_volatile_range(&c_conn->property_info, + "RETIRE_FENCE", 0x0, 0, ~0, 0, CONNECTOR_PROP_RETIRE_FENCE); + + msm_property_install_range(&c_conn->property_info, "autorefresh", + 0x0, 0, AUTOREFRESH_MAX_FRAME_CNT, 0, + CONNECTOR_PROP_AUTOREFRESH); + + if (connector_type == DRM_MODE_CONNECTOR_DSI) { + if (sde_kms->catalog->has_qsync && display_info->qsync_min_fps) + msm_property_install_enum(&c_conn->property_info, + "qsync_mode", 0, 0, e_qsync_mode, + ARRAY_SIZE(e_qsync_mode), + CONNECTOR_PROP_QSYNC_MODE); + + if (display_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) + msm_property_install_enum(&c_conn->property_info, + "frame_trigger_mode", 0, 0, + e_frame_trigger_mode, + ARRAY_SIZE(e_frame_trigger_mode), + CONNECTOR_PROP_CMD_FRAME_TRIGGER_MODE); + } + + msm_property_install_range(&c_conn->property_info, "bl_scale", + 0x0, 0, MAX_BL_SCALE_LEVEL, MAX_BL_SCALE_LEVEL, + CONNECTOR_PROP_BL_SCALE); + + msm_property_install_range(&c_conn->property_info, "ad_bl_scale", + 0x0, 0, MAX_AD_BL_SCALE_LEVEL, MAX_AD_BL_SCALE_LEVEL, + CONNECTOR_PROP_AD_BL_SCALE); + + c_conn->bl_scale_dirty = false; + c_conn->bl_scale = MAX_BL_SCALE_LEVEL; + c_conn->bl_scale_ad = MAX_AD_BL_SCALE_LEVEL; + + /* enum/bitmask properties */ + msm_property_install_enum(&c_conn->property_info, "topology_name", + DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name, + ARRAY_SIZE(e_topology_name), + CONNECTOR_PROP_TOPOLOGY_NAME); + msm_property_install_enum(&c_conn->property_info, "topology_control", + 0, 1, e_topology_control, + ARRAY_SIZE(e_topology_control), + CONNECTOR_PROP_TOPOLOGY_CONTROL); + msm_property_install_enum(&c_conn->property_info, "LP", + 0, 0, e_power_mode, + ARRAY_SIZE(e_power_mode), + CONNECTOR_PROP_LP); + + return 0; +} + struct drm_connector *sde_connector_init(struct drm_device *dev, struct drm_encoder *encoder, struct drm_panel *panel, @@ -2128,7 +2249,6 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, struct msm_drm_private *priv; struct sde_kms *sde_kms; struct sde_connector *c_conn = NULL; - struct dsi_display *dsi_display; struct msm_display_info display_info; int rc; @@ -2236,42 +2356,6 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, } } - msm_property_install_blob(&c_conn->property_info, - "capabilities", - DRM_MODE_PROP_IMMUTABLE, - CONNECTOR_PROP_SDE_INFO); - - rc = sde_connector_set_blob_data(&c_conn->base, - NULL, - CONNECTOR_PROP_SDE_INFO); - if (rc) { - SDE_ERROR_CONN(c_conn, - "failed to setup connector info, rc = %d\n", rc); - goto error_cleanup_fence; - } - - msm_property_install_blob(&c_conn->property_info, - "mode_properties", - DRM_MODE_PROP_IMMUTABLE, - CONNECTOR_PROP_MODE_INFO); - - if (connector_type == DRM_MODE_CONNECTOR_DSI) { - dsi_display = (struct dsi_display *)(display); - if (dsi_display && dsi_display->panel && - dsi_display->panel->hdr_props.hdr_enabled == true) { - msm_property_install_blob(&c_conn->property_info, - "hdr_properties", - DRM_MODE_PROP_IMMUTABLE, - CONNECTOR_PROP_HDR_INFO); - - msm_property_set_blob(&c_conn->property_info, - &c_conn->blob_hdr, - &dsi_display->panel->hdr_props, - sizeof(dsi_display->panel->hdr_props), - CONNECTOR_PROP_HDR_INFO); - } - } - rc = sde_connector_get_info(&c_conn->base, &display_info); if (!rc && (connector_type == DRM_MODE_CONNECTOR_DSI) && (display_info.capabilities & MSM_DISPLAY_CAP_VID_MODE)) @@ -2280,73 +2364,10 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, sde_connector_handle_disp_recovery, c_conn); - msm_property_install_volatile_range( - &c_conn->property_info, "sde_drm_roi_v1", 0x0, - 0, ~0, 0, CONNECTOR_PROP_ROI_V1); - - /* install PP_DITHER properties */ - _sde_connector_install_dither_property(dev, sde_kms, c_conn); - - if (connector_type == DRM_MODE_CONNECTOR_DisplayPort) { - struct drm_msm_ext_hdr_properties hdr = {0}; - - c_conn->hdr_capable = true; - - msm_property_install_blob(&c_conn->property_info, - "ext_hdr_properties", - DRM_MODE_PROP_IMMUTABLE, - CONNECTOR_PROP_EXT_HDR_INFO); - - /* set default values to avoid reading uninitialized data */ - msm_property_set_blob(&c_conn->property_info, - &c_conn->blob_ext_hdr, - &hdr, - sizeof(hdr), - CONNECTOR_PROP_EXT_HDR_INFO); - } - - msm_property_install_volatile_range(&c_conn->property_info, - "hdr_metadata", 0x0, 0, ~0, 0, CONNECTOR_PROP_HDR_METADATA); - - msm_property_install_volatile_range(&c_conn->property_info, - "RETIRE_FENCE", 0x0, 0, ~0, 0, CONNECTOR_PROP_RETIRE_FENCE); - - msm_property_install_range(&c_conn->property_info, "autorefresh", - 0x0, 0, AUTOREFRESH_MAX_FRAME_CNT, 0, - CONNECTOR_PROP_AUTOREFRESH); - - if (connector_type == DRM_MODE_CONNECTOR_DSI && - sde_kms->catalog->has_qsync && - display_info.qsync_min_fps) - msm_property_install_enum(&c_conn->property_info, "qsync_mode", - 0, 0, e_qsync_mode, ARRAY_SIZE(e_qsync_mode), - CONNECTOR_PROP_QSYNC_MODE); - - msm_property_install_range(&c_conn->property_info, "bl_scale", - 0x0, 0, MAX_BL_SCALE_LEVEL, MAX_BL_SCALE_LEVEL, - CONNECTOR_PROP_BL_SCALE); - - msm_property_install_range(&c_conn->property_info, "ad_bl_scale", - 0x0, 0, MAX_AD_BL_SCALE_LEVEL, MAX_AD_BL_SCALE_LEVEL, - CONNECTOR_PROP_AD_BL_SCALE); - - c_conn->bl_scale_dirty = false; - c_conn->bl_scale = MAX_BL_SCALE_LEVEL; - c_conn->bl_scale_ad = MAX_AD_BL_SCALE_LEVEL; - - /* enum/bitmask properties */ - msm_property_install_enum(&c_conn->property_info, "topology_name", - DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name, - ARRAY_SIZE(e_topology_name), - CONNECTOR_PROP_TOPOLOGY_NAME); - msm_property_install_enum(&c_conn->property_info, "topology_control", - 0, 1, e_topology_control, - ARRAY_SIZE(e_topology_control), - CONNECTOR_PROP_TOPOLOGY_CONTROL); - msm_property_install_enum(&c_conn->property_info, "LP", - 0, 0, e_power_mode, - ARRAY_SIZE(e_power_mode), - CONNECTOR_PROP_LP); + rc = _sde_connector_install_properties(dev, sde_kms, c_conn, + connector_type, display, &display_info); + if (rc) + goto error_cleanup_fence; rc = msm_property_install_get_status(&c_conn->property_info); if (rc) { diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 402e52e118a8..7b04b6d019d7 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -4643,6 +4643,29 @@ static void _helper_flush_dsc(struct sde_encoder_virt *sde_enc) } } +static void _sde_encoder_needs_hw_reset(struct drm_encoder *drm_enc, + int ln_cnt1) +{ + struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); + struct sde_encoder_phys *phys; + int ln_cnt2, i; + + /* query line count before cur_master is updated */ + if (sde_enc->cur_master && sde_enc->cur_master->ops.get_wr_line_count) + ln_cnt2 = sde_enc->cur_master->ops.get_wr_line_count( + sde_enc->cur_master); + else + ln_cnt2 = -EINVAL; + + SDE_EVT32(DRMID(drm_enc), ln_cnt1, ln_cnt2); + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + phys = sde_enc->phys_encs[i]; + if (phys && phys->ops.hw_reset) + phys->ops.hw_reset(phys); + } +} + int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, struct sde_encoder_kickoff_params *params) { @@ -4652,9 +4675,7 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, struct sde_crtc *sde_crtc; struct msm_drm_private *priv = NULL; bool needs_hw_reset = false; - uint32_t ln_cnt1, ln_cnt2; - unsigned int i; - int rc, ret = 0; + int ln_cnt1 = -EINVAL, i, rc, ret = 0; struct msm_display_info *disp_info; if (!drm_enc || !params || !drm_enc->dev || @@ -4675,8 +4696,12 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, if (sde_enc->cur_master && sde_enc->cur_master->ops.get_wr_line_count) ln_cnt1 = sde_enc->cur_master->ops.get_wr_line_count( sde_enc->cur_master); - else - ln_cnt1 = -EINVAL; + + if (sde_enc->cur_master && sde_enc->cur_master->connector && + disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) + sde_enc->frame_trigger_mode = sde_connector_get_property( + sde_enc->cur_master->connector->state, + CONNECTOR_PROP_CMD_FRAME_TRIGGER_MODE); /* prepare for next kickoff, may include waiting on previous kickoff */ SDE_ATRACE_BEGIN("sde_encoder_prepare_for_kickoff"); @@ -4713,23 +4738,8 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, } /* if any phys needs reset, reset all phys, in-order */ - if (needs_hw_reset) { - /* query line count before cur_master is updated */ - if (sde_enc->cur_master && - sde_enc->cur_master->ops.get_wr_line_count) - ln_cnt2 = sde_enc->cur_master->ops.get_wr_line_count( - sde_enc->cur_master); - else - ln_cnt2 = -EINVAL; - - SDE_EVT32(DRMID(drm_enc), ln_cnt1, ln_cnt2, - SDE_EVTLOG_FUNC_CASE1); - for (i = 0; i < sde_enc->num_phys_encs; i++) { - phys = sde_enc->phys_encs[i]; - if (phys && phys->ops.hw_reset) - phys->ops.hw_reset(phys); - } - } + if (needs_hw_reset) + _sde_encoder_needs_hw_reset(drm_enc, ln_cnt1); _sde_encoder_update_master(drm_enc, params); From d1f2c76f0f4c3f78069609e94242a39eaf4339e2 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Fri, 12 Jun 2020 17:49:13 +0800 Subject: [PATCH 059/192] drm/msm/sde: avoid frame done event during autorefresh Autorefresh enabled configuration updates the pending kickoff count once and receives multiple pp_done interrupts. Avoid frame done event trigger on these multiple interrupts if there is no pending frame. Change-Id: I03e4cd5758c958be27af05bd2ecdbb6fac5e9354 Signed-off-by: Dhaval Patel Signed-off-by: Krishna Manikandan Signed-off-by: Bruce Hoo Signed-off-by: Ray Zhang --- drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index 8fd37447bb8c..d546ee2b34cf 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -200,7 +200,8 @@ static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx) SDE_ATRACE_BEGIN("pp_done_irq"); /* notify all synchronous clients first, then asynchronous clients */ - if (phys_enc->parent_ops.handle_frame_done) + if (phys_enc->parent_ops.handle_frame_done && + atomic_read(&phys_enc->pending_kickoff_cnt)) phys_enc->parent_ops.handle_frame_done(phys_enc->parent, phys_enc, event); From 7fa9ad4fbb7c60d3e357245a16912fa17399a58c Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Fri, 12 Jun 2020 18:06:33 +0800 Subject: [PATCH 060/192] drm/msm/sde: trigger frame done if ctl is idle Command mode display triggers next frame without waiting for current frame transfer complete. In this case, MDP HW transfers two frames and generates done interrupt status for two frames. SW may miss one interrupt if there is a jiffie jump during these two frame done interrupt. This patch checks the controller idle status for posted start triggered frame to avoid invalid pingpong timeout issue. Change-Id: I344357f19e051ebd5ff4d5555d7d27009803f7c2 Signed-off-by: Dhaval Patel Signed-off-by: Ray Zhang Signed-off-by: Bruce Hoo --- drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c | 14 ++++++++++++++ drivers/gpu/drm/msm/sde/sde_hw_ctl.c | 11 ++++++++++- drivers/gpu/drm/msm/sde/sde_hw_ctl.h | 9 ++++++++- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index d546ee2b34cf..a1c1a2afaf93 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -1427,11 +1427,13 @@ static int _sde_encoder_phys_cmd_wait_for_ctl_start( struct sde_encoder_wait_info wait_info; int ret; bool frame_pending = true; + struct sde_hw_ctl *ctl; if (!phys_enc || !phys_enc->hw_ctl) { SDE_ERROR("invalid argument(s)\n"); return -EINVAL; } + ctl = phys_enc->hw_ctl; wait_info.wq = &phys_enc->pending_kickoff_wq; wait_info.atomic_cnt = &phys_enc->pending_ctlstart_cnt; @@ -1474,6 +1476,18 @@ static int _sde_encoder_phys_cmd_wait_for_ctl_start( atomic_inc_return(&phys_enc->ctlstart_timeout); } + } else if ((ret == 0) && + (phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START) && + atomic_read(&phys_enc->pending_kickoff_cnt) && + ctl->ops.get_scheduler_status && + (ctl->ops.get_scheduler_status(ctl) & BIT(0)) && + phys_enc->parent_ops.handle_frame_done) { + atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0); + + phys_enc->parent_ops.handle_frame_done( + phys_enc->parent, phys_enc, + SDE_ENCODER_FRAME_EVENT_DONE | + SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE); } return ret; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c index 53efad2778e1..39a0c620fbfa 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -31,6 +31,7 @@ #define CTL_PREPARE 0x0d0 #define CTL_SW_RESET 0x030 #define CTL_SW_RESET_OVERRIDE 0x060 +#define CTL_STATUS 0x064 #define CTL_LAYER_EXTN_OFFSET 0x40 #define CTL_ROT_TOP 0x0C0 #define CTL_ROT_FLUSH 0x0C4 @@ -709,6 +710,13 @@ static u32 sde_hw_ctl_get_reset_status(struct sde_hw_ctl *ctx) return (u32)SDE_REG_READ(&ctx->hw, CTL_SW_RESET); } +static u32 sde_hw_ctl_get_scheduler_status(struct sde_hw_ctl *ctx) +{ + if (!ctx) + return 0; + return (u32)SDE_REG_READ(&ctx->hw, CTL_STATUS); +} + static int sde_hw_ctl_reset_control(struct sde_hw_ctl *ctx) { struct sde_hw_blk_reg_map *c; @@ -1273,6 +1281,7 @@ static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops, sde_hw_ctl_update_bitmask_periph_v1; ops->get_ctl_intf = sde_hw_ctl_get_intf_v1; ops->reset_post_disable = sde_hw_ctl_reset_post_disable; + ops->get_scheduler_status = sde_hw_ctl_get_scheduler_status; } else { ops->update_pending_flush = sde_hw_ctl_update_pending_flush; ops->trigger_flush = sde_hw_ctl_trigger_flush; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h index e1ee9f89c7e6..1cef1f2ef58f 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -296,6 +296,13 @@ struct sde_hw_ctl_ops { */ u32 (*get_reset)(struct sde_hw_ctl *ctx); + /** + * get_scheduler_reset - check ctl scheduler status bit + * @ctx : ctl path ctx pointer + * Returns: current value of ctl scheduler and idle status + */ + u32 (*get_scheduler_status)(struct sde_hw_ctl *ctx); + /** * hard_reset - force reset on ctl_path * @ctx : ctl path ctx pointer From 0edba2e03b276bca3090307cb7abf8c19bb6fa15 Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Fri, 12 Jun 2020 18:21:17 +0800 Subject: [PATCH 061/192] disp: msm: sde: use wr_ptr interrupt instead of ctl_start SDE driver triggers the frame and waits for the ctl_start interrupt for command mode display. This interrupt provides confirmation that hardware has picked up the frame. Retire fence signaling is associated with this interrupt and it is sent at the rd_ptr interrupt after ctl_start. Due to lut dma delay, ctl_start interrupt may be trigger before rd_ptr or after rd_ptr. SW manages this complexity and handle retire fence for different cases with 500us threshold logic. This change replaces the ctl_start interrupt with wr_ptr interrupt by programming it to trigger at 1st write line count. This is guaranteed to come every time and it is close to rd_ptr interrupt. That allows retire fence trigger at wr_ptr interrupt and simplifies the SW logic. CRTC commit thread would be held slightly longer with this change as the wr_ptr is always close to rd_ptr and after ctl_start. Change-Id: Ic47a8f82c854b4aded0d70c95af853b28a68ffd6 Signed-off-by: Veera Sundaram Sankaran Signed-off-by: Bruce Hoo Signed-off-by: Ray Zhang --- drivers/gpu/drm/msm/sde/sde_crtc.c | 28 +-- drivers/gpu/drm/msm/sde/sde_encoder.c | 17 -- drivers/gpu/drm/msm/sde/sde_encoder.h | 11 +- drivers/gpu/drm/msm/sde/sde_encoder_phys.h | 22 +- .../gpu/drm/msm/sde/sde_encoder_phys_cmd.c | 196 +++++------------- drivers/gpu/drm/msm/sde/sde_hw_intf.c | 3 +- drivers/gpu/drm/msm/sde/sde_hw_mdss.h | 4 +- drivers/gpu/drm/msm/sde/sde_hw_pingpong.c | 1 + 8 files changed, 70 insertions(+), 212 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index e8e6648e28b9..ad4d83d46c42 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -942,26 +942,6 @@ static bool sde_crtc_mode_fixup(struct drm_crtc *crtc, return true; } -static int _sde_crtc_get_ctlstart_timeout(struct drm_crtc *crtc) -{ - struct drm_encoder *encoder; - int rc = 0; - - if (!crtc || !crtc->dev) - return 0; - - list_for_each_entry(encoder, - &crtc->dev->mode_config.encoder_list, head) { - if (encoder->crtc != crtc) - continue; - - if (sde_encoder_get_intf_mode(encoder) == INTF_MODE_CMD) - rc += sde_encoder_get_ctlstart_timeout_state(encoder); - } - - return rc; -} - static void _sde_crtc_setup_blend_cfg(struct sde_crtc_mixer *mixer, struct sde_plane_state *pstate, struct sde_format *format) { @@ -3760,13 +3740,7 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc, if (unlikely(!sde_crtc->num_mixers)) goto end; - if (_sde_crtc_get_ctlstart_timeout(crtc)) { - _sde_crtc_blend_setup(crtc, old_state, false); - SDE_ERROR("border fill only commit after ctlstart timeout\n"); - } else { - _sde_crtc_blend_setup(crtc, old_state, true); - } - + _sde_crtc_blend_setup(crtc, old_state, true); _sde_crtc_dest_scaler_setup(crtc); /* cancel the idle notify delayed work */ diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 7b04b6d019d7..13aadfd4975a 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -3757,23 +3757,6 @@ int sde_encoder_idle_request(struct drm_encoder *drm_enc) return 0; } -int sde_encoder_get_ctlstart_timeout_state(struct drm_encoder *drm_enc) -{ - struct sde_encoder_virt *sde_enc = NULL; - int i, count = 0; - - if (!drm_enc) - return 0; - - sde_enc = to_sde_encoder_virt(drm_enc); - - for (i = 0; i < sde_enc->num_phys_encs; i++) { - count += atomic_read(&sde_enc->phys_encs[i]->ctlstart_timeout); - atomic_set(&sde_enc->phys_encs[i]->ctlstart_timeout, 0); - } - - return count; -} /** * _sde_encoder_trigger_flush - trigger flush for a physical encoder * drm_enc: Pointer to drm encoder structure diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h index 69b3ad28bb01..2f626dfadeb4 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder.h @@ -171,11 +171,11 @@ void sde_encoder_kickoff(struct drm_encoder *encoder, bool is_error); * @encoder: encoder pointer * @event: event to wait for * MSM_ENC_COMMIT_DONE - Wait for hardware to have flushed the current pending - * frames to hardware at a vblank or ctl_start + * frames to hardware at a vblank or wr_ptr_start * Encoders will map this differently depending on the * panel type. * vid mode -> vsync_irq - * cmd mode -> ctl_start + * cmd mode -> wr_ptr_start_irq * MSM_ENC_TX_COMPLETE - Wait for the hardware to transfer all the pixels to * the panel. Encoders will map this differently * depending on the panel type. @@ -345,11 +345,4 @@ void sde_encoder_control_idle_pc(struct drm_encoder *enc, bool enable); */ int sde_encoder_in_cont_splash(struct drm_encoder *enc); -/** - * sde_encoder_get_ctlstart_timeout_state - checks if ctl start timeout happened - * @drm_enc: Pointer to drm encoder structure - * @Return: non zero value if ctl start timeout occurred - */ -int sde_encoder_get_ctlstart_timeout_state(struct drm_encoder *enc); - #endif /* __SDE_ENCODER_H__ */ diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h index 841ffb9f7407..e5f7ea0192d9 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h @@ -197,9 +197,9 @@ struct sde_encoder_phys_ops { /** * enum sde_intr_idx - sde encoder interrupt index * @INTR_IDX_VSYNC: Vsync interrupt for video mode panel - * @INTR_IDX_PINGPONG: Pingpong done unterrupt for cmd mode panel - * @INTR_IDX_UNDERRUN: Underrun unterrupt for video and cmd mode panel - * @INTR_IDX_RDPTR: Readpointer done unterrupt for cmd mode panel + * @INTR_IDX_PINGPONG: Pingpong done interrupt for cmd mode panel + * @INTR_IDX_UNDERRUN: Underrun interrupt for video and cmd mode panel + * @INTR_IDX_RDPTR: Readpointer done interrupt for cmd mode panel * @INTR_IDX_WB_DONE: Writeback done interrupt for WB * @INTR_IDX_PP1_OVFL: Pingpong overflow interrupt on PP1 for Concurrent WB * @INTR_IDX_PP2_OVFL: Pingpong overflow interrupt on PP2 for Concurrent WB @@ -208,6 +208,7 @@ struct sde_encoder_phys_ops { * @INTR_IDX_PP5_OVFL: Pingpong overflow interrupt on PP5 for Concurrent WB * @INTR_IDX_AUTOREFRESH_DONE: Autorefresh done for cmd mode panel meaning * autorefresh has triggered a double buffer flip + * @INTR_IDX_WRPTR: Writepointer start interrupt for cmd mode panel */ enum sde_intr_idx { INTR_IDX_VSYNC, @@ -222,6 +223,7 @@ enum sde_intr_idx { INTR_IDX_PP3_OVFL, INTR_IDX_PP4_OVFL, INTR_IDX_PP5_OVFL, + INTR_IDX_WRPTR, INTR_IDX_MAX, }; @@ -283,12 +285,9 @@ struct sde_encoder_irq { * vs. the number of done/vblank irqs. Should hover * between 0-2 Incremented when a new kickoff is * scheduled. Decremented in irq handler - * @pending_ctlstart_cnt: Atomic counter tracking the number of ctl start - * pending. * @pending_retire_fence_cnt: Atomic counter tracking the pending retire * fences that have to be signalled. * @pending_kickoff_wq: Wait queue for blocking until kickoff completes - * @ctlstart_timeout: Indicates if ctl start timeout occurred * @irq: IRQ tracking structures * @has_intf_te: Interface TE configuration support * @cont_splash_single_flush Variable to check if single flush is enabled. @@ -330,10 +329,8 @@ struct sde_encoder_phys { atomic_t wbirq_refcount; atomic_t vsync_cnt; atomic_t underrun_cnt; - atomic_t pending_ctlstart_cnt; atomic_t pending_kickoff_cnt; atomic_t pending_retire_fence_cnt; - atomic_t ctlstart_timeout; wait_queue_head_t pending_kickoff_wq; struct sde_encoder_irq irq[INTR_IDX_MAX]; bool has_intf_te; @@ -346,7 +343,6 @@ struct sde_encoder_phys { static inline int sde_encoder_phys_inc_pending(struct sde_encoder_phys *phys) { - atomic_inc_return(&phys->pending_ctlstart_cnt); return atomic_inc_return(&phys->pending_kickoff_cnt); } @@ -387,24 +383,16 @@ struct sde_encoder_phys_cmd_autorefresh { * @stream_sel: Stream selection for multi-stream interfaces * @pp_timeout_report_cnt: number of pingpong done irq timeout errors * @autorefresh: autorefresh feature state - * @pending_rd_ptr_cnt: atomic counter to indicate if retire fence can be - * signaled at the next rd_ptr_irq - * @rd_ptr_timestamp: last rd_ptr_irq timestamp * @pending_vblank_cnt: Atomic counter tracking pending wait for VBLANK * @pending_vblank_wq: Wait queue for blocking until VBLANK received - * @ctl_start_threshold: A threshold in microseconds allows command mode - * engine to trigger the retire fence without waiting for rd_ptr. */ struct sde_encoder_phys_cmd { struct sde_encoder_phys base; int stream_sel; int pp_timeout_report_cnt; struct sde_encoder_phys_cmd_autorefresh autorefresh; - atomic_t pending_rd_ptr_cnt; - ktime_t rd_ptr_timestamp; atomic_t pending_vblank_cnt; wait_queue_head_t pending_vblank_wq; - u32 ctl_start_threshold; }; /** diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index a1c1a2afaf93..ffa1d04597e3 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -44,12 +44,6 @@ #define SDE_ENC_WR_PTR_START_TIMEOUT_US 20000 -/* - * Threshold for signalling retire fences in cases where - * CTL_START_IRQ is received just after RD_PTR_IRQ - */ -#define SDE_ENC_CTL_START_THRESHOLD_US 500 - #define SDE_ENC_MAX_POLL_TIMEOUT_US 2000 static inline int _sde_encoder_phys_cmd_get_idle_timeout( @@ -212,23 +206,6 @@ static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx) SDE_EVT32_IRQ(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, new_cnt, event); - /* - * Reduce the refcount for the retire fence as well as for the ctl_start - * if the counters are greater than zero. Signal retire fence if there - * was a retire fence count pending and kickoff count is zero. - */ - if (sde_encoder_phys_cmd_is_master(phys_enc) && (new_cnt == 0)) { - while (atomic_add_unless(&phys_enc->pending_retire_fence_cnt, - -1, 0)) { - if (phys_enc->parent_ops.handle_frame_done) - phys_enc->parent_ops.handle_frame_done( - phys_enc->parent, phys_enc, - SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE); - atomic_add_unless(&phys_enc->pending_ctlstart_cnt, - -1, 0); - } - } - /* Signal any waiting atomic commit thread */ wake_up_all(&phys_enc->pending_kickoff_wq); SDE_ATRACE_END("pp_done_irq"); @@ -263,7 +240,6 @@ static void sde_encoder_phys_cmd_te_rd_ptr_irq(void *arg, int irq_idx) { struct sde_encoder_phys *phys_enc = arg; struct sde_encoder_phys_cmd *cmd_enc; - u32 event = 0; if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) return; @@ -271,94 +247,46 @@ static void sde_encoder_phys_cmd_te_rd_ptr_irq(void *arg, int irq_idx) SDE_ATRACE_BEGIN("rd_ptr_irq"); cmd_enc = to_sde_encoder_phys_cmd(phys_enc); - /** - * signal only for master, when the ctl_start irq is - * done and incremented the pending_rd_ptr_cnt. - */ - if (sde_encoder_phys_cmd_is_master(phys_enc) - && atomic_add_unless(&cmd_enc->pending_rd_ptr_cnt, -1, 0) - && atomic_add_unless( - &phys_enc->pending_retire_fence_cnt, -1, 0)) { - - event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE; - if (phys_enc->parent_ops.handle_frame_done) - phys_enc->parent_ops.handle_frame_done( - phys_enc->parent, phys_enc, event); - } - SDE_EVT32_IRQ(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, - event, 0xfff); + 0xfff); if (phys_enc->parent_ops.handle_vblank_virt) phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent, phys_enc); - cmd_enc->rd_ptr_timestamp = ktime_get(); - atomic_add_unless(&cmd_enc->pending_vblank_cnt, -1, 0); wake_up_all(&cmd_enc->pending_vblank_wq); SDE_ATRACE_END("rd_ptr_irq"); } -static void sde_encoder_phys_cmd_ctl_start_irq(void *arg, int irq_idx) +static void sde_encoder_phys_cmd_wr_ptr_irq(void *arg, int irq_idx) { struct sde_encoder_phys *phys_enc = arg; - struct sde_encoder_phys_cmd *cmd_enc; struct sde_hw_ctl *ctl; u32 event = 0; - s64 time_diff_us; if (!phys_enc || !phys_enc->hw_ctl) return; - SDE_ATRACE_BEGIN("ctl_start_irq"); - cmd_enc = to_sde_encoder_phys_cmd(phys_enc); + SDE_ATRACE_BEGIN("wr_ptr_irq"); ctl = phys_enc->hw_ctl; - atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0); - atomic_set(&phys_enc->ctlstart_timeout, 0); - - time_diff_us = ktime_us_delta(ktime_get(), cmd_enc->rd_ptr_timestamp); - - /* handle retire fence based on only master */ - if (sde_encoder_phys_cmd_is_master(phys_enc) - && atomic_read(&phys_enc->pending_retire_fence_cnt)) { - /** - * Handle rare cases where the ctl_start_irq is received - * after rd_ptr_irq. If it falls within a threshold, it is - * guaranteed the frame would be picked up in the current TE. - * Signal retire fence immediately in such case. The threshold - * timer adds extra line time duration based on lowest panel - * fps for qsync enabled case. - */ - if ((time_diff_us <= cmd_enc->ctl_start_threshold) - && atomic_add_unless( - &phys_enc->pending_retire_fence_cnt, -1, 0)) { - - event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE; - if (phys_enc->parent_ops.handle_frame_done) - phys_enc->parent_ops.handle_frame_done( + if (atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0)) { + event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE; + if (phys_enc->parent_ops.handle_frame_done) + phys_enc->parent_ops.handle_frame_done( phys_enc->parent, phys_enc, event); - - /** - * In ideal cases, ctl_start_irq is received before the - * rd_ptr_irq, so set the atomic flag to indicate the event - * and rd_ptr_irq will handle signalling the retire fence - */ - } else { - atomic_inc(&cmd_enc->pending_rd_ptr_cnt); - } } SDE_EVT32_IRQ(DRMID(phys_enc->parent), ctl->idx - CTL_0, - time_diff_us, event, 0xfff); + event, 0xfff); - /* Signal any waiting ctl start interrupt */ + /* Signal any waiting wr_ptr interrupt */ wake_up_all(&phys_enc->pending_kickoff_wq); - SDE_ATRACE_END("ctl_start_irq"); + SDE_ATRACE_END("wr_ptr_irq"); } static void sde_encoder_phys_cmd_underrun_irq(void *arg, int irq_idx) @@ -432,6 +360,13 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx( else irq->hw_idx = phys_enc->hw_pp->idx; + irq = &phys_enc->irq[INTR_IDX_WRPTR]; + irq->irq_idx = -EINVAL; + if (phys_enc->has_intf_te) + irq->hw_idx = phys_enc->hw_intf->idx; + else + irq->hw_idx = phys_enc->hw_pp->idx; + mutex_unlock(phys_enc->vblank_ctl_lock); } @@ -552,17 +487,6 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout( cmd_enc->pp_timeout_report_cnt++; pending_kickoff_cnt = atomic_read(&phys_enc->pending_kickoff_cnt); - if (sde_encoder_phys_cmd_is_master(phys_enc)) { - /* trigger the retire fence if it was missed */ - if (atomic_add_unless(&phys_enc->pending_retire_fence_cnt, - -1, 0)) - phys_enc->parent_ops.handle_frame_done( - phys_enc->parent, - phys_enc, - SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE); - atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0); - } - SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, cmd_enc->pp_timeout_report_cnt, pending_kickoff_cnt, @@ -904,12 +828,11 @@ void sde_encoder_phys_cmd_irq_control(struct sde_encoder_phys *phys_enc, if (enable) { sde_encoder_helper_register_irq(phys_enc, INTR_IDX_PINGPONG); - sde_encoder_helper_register_irq(phys_enc, INTR_IDX_UNDERRUN); sde_encoder_phys_cmd_control_vblank_irq(phys_enc, true); if (sde_encoder_phys_cmd_is_master(phys_enc)) { sde_encoder_helper_register_irq(phys_enc, - INTR_IDX_CTL_START); + INTR_IDX_WRPTR); sde_encoder_helper_register_irq(phys_enc, INTR_IDX_AUTOREFRESH_DONE); } @@ -917,12 +840,11 @@ void sde_encoder_phys_cmd_irq_control(struct sde_encoder_phys *phys_enc, } else { if (sde_encoder_phys_cmd_is_master(phys_enc)) { sde_encoder_helper_unregister_irq(phys_enc, - INTR_IDX_CTL_START); + INTR_IDX_WRPTR); sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_AUTOREFRESH_DONE); } - sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_UNDERRUN); sde_encoder_phys_cmd_control_vblank_irq(phys_enc, false); sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_PINGPONG); } @@ -1078,9 +1000,7 @@ static void sde_encoder_phys_cmd_tearcheck_config( tc_cfg.sync_threshold_continue = DEFAULT_TEARCHECK_SYNC_THRESH_CONTINUE; tc_cfg.start_pos = mode->vdisplay; tc_cfg.rd_ptr_irq = mode->vdisplay + 1; - - cmd_enc->ctl_start_threshold = (extra_frame_trigger_time / 1000) + - SDE_ENC_CTL_START_THRESHOLD_US; + tc_cfg.wr_ptr_irq = 1; SDE_DEBUG_CMDENC(cmd_enc, "tc %d intf %d vsync_clk_speed_hz %u vtotal %u vrefresh %u\n", @@ -1088,10 +1008,11 @@ static void sde_encoder_phys_cmd_tearcheck_config( phys_enc->hw_intf->idx - INTF_0, vsync_hz, mode->vtotal, mode->vrefresh); SDE_DEBUG_CMDENC(cmd_enc, - "tc %d intf %d enable %u start_pos %u rd_ptr_irq %u\n", + "tc %d intf %d enable %u start_pos %u rd_ptr_irq %u wr_ptr_irq %u\n", phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, - tc_enable, tc_cfg.start_pos, tc_cfg.rd_ptr_irq); + tc_enable, tc_cfg.start_pos, tc_cfg.rd_ptr_irq, + tc_cfg.wr_ptr_irq); SDE_DEBUG_CMDENC(cmd_enc, "tc %d intf %d hw_vsync_mode %u vsync_count %u vsync_init_val %u\n", phys_enc->hw_pp->idx - PINGPONG_0, @@ -1099,12 +1020,11 @@ static void sde_encoder_phys_cmd_tearcheck_config( tc_cfg.hw_vsync_mode, tc_cfg.vsync_count, tc_cfg.vsync_init_val); SDE_DEBUG_CMDENC(cmd_enc, - "tc %d intf %d cfgheight %u thresh_start %u thresh_cont %u ctl_start_threshold:%d\n", + "tc %d intf %d cfgheight %u thresh_start %u thresh_cont %u\n", phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, tc_cfg.sync_cfg_height, - tc_cfg.sync_threshold_start, tc_cfg.sync_threshold_continue, - cmd_enc->ctl_start_threshold); + tc_cfg.sync_threshold_start, tc_cfg.sync_threshold_continue); if (phys_enc->has_intf_te) { phys_enc->hw_intf->ops.setup_tearcheck(phys_enc->hw_intf, @@ -1300,7 +1220,6 @@ static void sde_encoder_phys_cmd_disable(struct sde_encoder_phys *phys_enc) SDE_ERROR("invalid encoder\n"); return; } - atomic_set(&phys_enc->ctlstart_timeout, 0); SDE_DEBUG_CMDENC(cmd_enc, "pp %d intf %d state %d\n", phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_intf->idx - INTF_0, @@ -1378,6 +1297,7 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff( SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, atomic_read(&phys_enc->pending_kickoff_cnt), atomic_read(&cmd_enc->autorefresh.kickoff_cnt)); + phys_enc->frame_trigger_mode = params->frame_trigger_mode; if (phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_DEFAULT) { /* @@ -1406,11 +1326,7 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff( phys_enc->hw_pp->ops.update_tearcheck( phys_enc->hw_pp, &tc_cfg); - cmd_enc->ctl_start_threshold = - (extra_frame_trigger_time / 1000) + - SDE_ENC_CTL_START_THRESHOLD_US; - SDE_EVT32(DRMID(phys_enc->parent), - tc_cfg.sync_threshold_start, cmd_enc->ctl_start_threshold); + SDE_EVT32(DRMID(phys_enc->parent), tc_cfg.sync_threshold_start); } SDE_DEBUG_CMDENC(cmd_enc, "pp:%d pending_cnt %d\n", @@ -1419,7 +1335,7 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff( return ret; } -static int _sde_encoder_phys_cmd_wait_for_ctl_start( +static int _sde_encoder_phys_cmd_wait_for_wr_ptr( struct sde_encoder_phys *phys_enc) { struct sde_encoder_phys_cmd *cmd_enc = @@ -1436,14 +1352,14 @@ static int _sde_encoder_phys_cmd_wait_for_ctl_start( ctl = phys_enc->hw_ctl; wait_info.wq = &phys_enc->pending_kickoff_wq; - wait_info.atomic_cnt = &phys_enc->pending_ctlstart_cnt; + wait_info.atomic_cnt = &phys_enc->pending_retire_fence_cnt; wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; /* slave encoder doesn't enable for ppsplit */ if (_sde_encoder_phys_is_ppsplit_slave(phys_enc)) return 0; - ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_CTL_START, + ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_WRPTR, &wait_info); if (ret == -ETIMEDOUT) { struct sde_hw_ctl *ctl = phys_enc->hw_ctl; @@ -1453,29 +1369,23 @@ static int _sde_encoder_phys_cmd_wait_for_ctl_start( if (frame_pending) SDE_ERROR_CMDENC(cmd_enc, - "ctl start interrupt wait failed\n"); + "wr_ptr interrupt wait failed\n"); else ret = 0; - if (sde_encoder_phys_cmd_is_master(phys_enc)) { - /* - * Signaling the retire fence at ctl start timeout - * to allow the next commit and avoid device freeze. - * As ctl start timeout can occurs due to no read ptr, - * updating pending_rd_ptr_cnt here may not cover all - * cases. Hence signaling the retire fence. - */ - if (atomic_add_unless( - &phys_enc->pending_retire_fence_cnt, -1, 0)) - phys_enc->parent_ops.handle_frame_done( - phys_enc->parent, - phys_enc, - SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE); - atomic_add_unless( - &phys_enc->pending_ctlstart_cnt, -1, 0); - atomic_inc_return(&phys_enc->ctlstart_timeout); - } - + /* + * Signaling the retire fence at wr_ptr timeout + * to allow the next commit and avoid device freeze. + * As wr_ptr timeout can occurs due to no read ptr, + * updating pending_rd_ptr_cnt here may not cover all + * cases. Hence signaling the retire fence. + */ + if (sde_encoder_phys_cmd_is_master(phys_enc) && + atomic_add_unless(&phys_enc->pending_retire_fence_cnt, + -1, 0)) + phys_enc->parent_ops.handle_frame_done( + phys_enc->parent, phys_enc, + SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE); } else if ((ret == 0) && (phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START) && atomic_read(&phys_enc->pending_kickoff_cnt) && @@ -1527,7 +1437,7 @@ static int sde_encoder_phys_cmd_wait_for_commit_done( /* only required for master controller */ if (sde_encoder_phys_cmd_is_master(phys_enc)) - rc = _sde_encoder_phys_cmd_wait_for_ctl_start(phys_enc); + rc = _sde_encoder_phys_cmd_wait_for_wr_ptr(phys_enc); if (!rc && sde_encoder_phys_cmd_is_master(phys_enc) && cmd_enc->autorefresh.cfg.enable) @@ -1760,7 +1670,6 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init( phys_enc->enc_spinlock = p->enc_spinlock; phys_enc->vblank_ctl_lock = p->vblank_ctl_lock; cmd_enc->stream_sel = 0; - cmd_enc->ctl_start_threshold = SDE_ENC_CTL_START_THRESHOLD_US; phys_enc->enable_state = SDE_ENC_DISABLED; sde_encoder_phys_cmd_init_ops(&phys_enc->ops); phys_enc->comp_type = p->comp_type; @@ -1782,7 +1691,7 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init( irq->name = "ctl_start"; irq->intr_type = SDE_IRQ_TYPE_CTL_START; irq->intr_idx = INTR_IDX_CTL_START; - irq->cb.func = sde_encoder_phys_cmd_ctl_start_irq; + irq->cb.func = NULL; irq = &phys_enc->irq[INTR_IDX_PINGPONG]; irq->name = "pp_done"; @@ -1818,13 +1727,20 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init( irq->intr_idx = INTR_IDX_AUTOREFRESH_DONE; irq->cb.func = sde_encoder_phys_cmd_autorefresh_done_irq; + irq = &phys_enc->irq[INTR_IDX_WRPTR]; + irq->intr_idx = INTR_IDX_WRPTR; + irq->name = "wr_ptr"; + + if (phys_enc->has_intf_te) + irq->intr_type = SDE_IRQ_TYPE_INTF_TEAR_WR_PTR; + else + irq->intr_type = SDE_IRQ_TYPE_PING_PONG_WR_PTR; + irq->cb.func = sde_encoder_phys_cmd_wr_ptr_irq; + atomic_set(&phys_enc->vblank_refcount, 0); atomic_set(&phys_enc->pending_kickoff_cnt, 0); - atomic_set(&phys_enc->pending_ctlstart_cnt, 0); atomic_set(&phys_enc->pending_retire_fence_cnt, 0); - atomic_set(&cmd_enc->pending_rd_ptr_cnt, 0); atomic_set(&cmd_enc->pending_vblank_cnt, 0); - atomic_set(&phys_enc->ctlstart_timeout, 0); init_waitqueue_head(&phys_enc->pending_kickoff_wq); init_waitqueue_head(&cmd_enc->pending_vblank_wq); atomic_set(&cmd_enc->autorefresh.kickoff_cnt, 0); diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.c b/drivers/gpu/drm/msm/sde/sde_hw_intf.c index b88d4b525db2..e318395635a9 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_intf.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -497,6 +497,7 @@ static int sde_hw_intf_setup_te_config(struct sde_hw_intf *intf, SDE_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_HEIGHT, te->sync_cfg_height); SDE_REG_WRITE(c, INTF_TEAR_VSYNC_INIT_VAL, te->vsync_init_val); SDE_REG_WRITE(c, INTF_TEAR_RD_PTR_IRQ, te->rd_ptr_irq); + SDE_REG_WRITE(c, INTF_TEAR_WR_PTR_IRQ, te->wr_ptr_irq); SDE_REG_WRITE(c, INTF_TEAR_START_POS, te->start_pos); SDE_REG_WRITE(c, INTF_TEAR_SYNC_THRESH, ((te->sync_threshold_continue << 16) | diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h index 145da74946f2..49be98dd3c2a 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -647,6 +647,7 @@ struct sde_splash_data { * needs to be above the read pointer * @start_pos: The position from which the start_threshold value is added * @rd_ptr_irq: The read pointer line at which interrupt has to be generated + * @wr_ptr_irq: The write pointer line at which interrupt has to be generated * @hw_vsync_mode: Sync with external frame sync input */ struct sde_hw_tear_check { @@ -657,6 +658,7 @@ struct sde_hw_tear_check { u32 sync_threshold_continue; u32 start_pos; u32 rd_ptr_irq; + u32 wr_ptr_irq; u8 hw_vsync_mode; }; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c index 64c1a90f5952..308fd5f6ee46 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c @@ -183,6 +183,7 @@ static int sde_hw_pp_setup_te_config(struct sde_hw_pingpong *pp, SDE_REG_WRITE(c, PP_SYNC_CONFIG_HEIGHT, te->sync_cfg_height); SDE_REG_WRITE(c, PP_VSYNC_INIT_VAL, te->vsync_init_val); SDE_REG_WRITE(c, PP_RD_PTR_IRQ, te->rd_ptr_irq); + SDE_REG_WRITE(c, PP_WR_PTR_IRQ, te->wr_ptr_irq); SDE_REG_WRITE(c, PP_START_POS, te->start_pos); SDE_REG_WRITE(c, PP_SYNC_THRESH, ((te->sync_threshold_continue << 16) | From b7bf59a2e313a0977c893407eee10d0e9c5f128c Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Fri, 12 Jun 2020 18:32:24 +0800 Subject: [PATCH 062/192] disp: msm: sde: reset ctl during wr_ptr_irq timeout wr_ptr_irq timeout signifies that the MDP is stuck on either the current or previous frame. Handle ctl reset and fence signalling as part of this timeout handling. This logic would help to recover the HW faster in case of posted-start. Change-Id: I09b3d21772df431f9fc4a58b2fd9b4fcac4a7de7 Signed-off-by: Veera Sundaram Sankaran Signed-off-by: Ray Zhang Signed-off-by: Bruce Hoo --- drivers/gpu/drm/msm/sde/sde_encoder.c | 23 +++------------ drivers/gpu/drm/msm/sde/sde_encoder_phys.h | 6 ++++ .../gpu/drm/msm/sde/sde_encoder_phys_cmd.c | 29 +++++++++++++------ 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 13aadfd4975a..fe05a401a2fa 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -4626,21 +4626,11 @@ static void _helper_flush_dsc(struct sde_encoder_virt *sde_enc) } } -static void _sde_encoder_needs_hw_reset(struct drm_encoder *drm_enc, - int ln_cnt1) +void sde_encoder_helper_needs_hw_reset(struct drm_encoder *drm_enc) { struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); struct sde_encoder_phys *phys; - int ln_cnt2, i; - - /* query line count before cur_master is updated */ - if (sde_enc->cur_master && sde_enc->cur_master->ops.get_wr_line_count) - ln_cnt2 = sde_enc->cur_master->ops.get_wr_line_count( - sde_enc->cur_master); - else - ln_cnt2 = -EINVAL; - - SDE_EVT32(DRMID(drm_enc), ln_cnt1, ln_cnt2); + int i; for (i = 0; i < sde_enc->num_phys_encs; i++) { phys = sde_enc->phys_encs[i]; @@ -4658,7 +4648,7 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, struct sde_crtc *sde_crtc; struct msm_drm_private *priv = NULL; bool needs_hw_reset = false; - int ln_cnt1 = -EINVAL, i, rc, ret = 0; + int i, rc, ret = 0; struct msm_display_info *disp_info; if (!drm_enc || !params || !drm_enc->dev || @@ -4675,11 +4665,6 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, SDE_DEBUG_ENC(sde_enc, "\n"); SDE_EVT32(DRMID(drm_enc)); - /* save this for later, in case of errors */ - if (sde_enc->cur_master && sde_enc->cur_master->ops.get_wr_line_count) - ln_cnt1 = sde_enc->cur_master->ops.get_wr_line_count( - sde_enc->cur_master); - if (sde_enc->cur_master && sde_enc->cur_master->connector && disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) sde_enc->frame_trigger_mode = sde_connector_get_property( @@ -4722,7 +4707,7 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, /* if any phys needs reset, reset all phys, in-order */ if (needs_hw_reset) - _sde_encoder_needs_hw_reset(drm_enc, ln_cnt1); + sde_encoder_helper_needs_hw_reset(drm_enc); _sde_encoder_update_master(drm_enc, params); diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h index e5f7ea0192d9..53d6cf5fcf3d 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h @@ -516,6 +516,12 @@ void sde_encoder_phys_setup_cdm(struct sde_encoder_phys *phys_enc, struct drm_framebuffer *fb, const struct sde_format *format, struct sde_rect *wb_roi); +/** + * sde_encoder_helper_needs_hw_reset - hw reset helper function + * @drm_enc: Pointer to drm encoder structure + */ +void sde_encoder_helper_needs_hw_reset(struct drm_encoder *drm_enc); + /** * sde_encoder_helper_trigger_flush - control flush helper function * This helper function may be optionally specified by physical diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index ffa1d04597e3..197b34a297c8 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -1436,8 +1436,11 @@ static int sde_encoder_phys_cmd_wait_for_commit_done( cmd_enc = to_sde_encoder_phys_cmd(phys_enc); /* only required for master controller */ - if (sde_encoder_phys_cmd_is_master(phys_enc)) + if (sde_encoder_phys_cmd_is_master(phys_enc)) { rc = _sde_encoder_phys_cmd_wait_for_wr_ptr(phys_enc); + if (rc == -ETIMEDOUT) + goto wait_for_idle; + } if (!rc && sde_encoder_phys_cmd_is_master(phys_enc) && cmd_enc->autorefresh.cfg.enable) @@ -1446,14 +1449,22 @@ static int sde_encoder_phys_cmd_wait_for_commit_done( /* wait for posted start or serialize trigger */ if ((atomic_read(&phys_enc->pending_kickoff_cnt) > 1) || (!rc && phys_enc->frame_trigger_mode == - FRAME_DONE_WAIT_SERIALIZE)) { - rc = _sde_encoder_phys_cmd_wait_for_idle(phys_enc); - if (rc) { - atomic_set(&phys_enc->pending_kickoff_cnt, 0); - SDE_EVT32(DRMID(phys_enc->parent), - phys_enc->hw_pp->idx - PINGPONG_0); - SDE_ERROR("failed wait_for_idle: %d\n", rc); - } + FRAME_DONE_WAIT_SERIALIZE)) + goto wait_for_idle; + +wait_for_idle: + rc = _sde_encoder_phys_cmd_wait_for_idle(phys_enc); + if (rc) { + SDE_EVT32(DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->frame_trigger_mode, + atomic_read(&phys_enc->pending_kickoff_cnt), + phys_enc->enable_state, rc); + atomic_set(&phys_enc->pending_kickoff_cnt, 0); + SDE_ERROR("pp:%d failed wait_for_idle: %d\n", + phys_enc->hw_pp->idx - PINGPONG_0, rc); + if (phys_enc->enable_state == SDE_ENC_ERR_NEEDS_HW_RESET) + sde_encoder_helper_needs_hw_reset(phys_enc->parent); } return rc; From aa8c9096d08914c9838dfaad9dcfb1d9d61f023e Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Fri, 12 Jun 2020 18:45:24 +0800 Subject: [PATCH 063/192] disp: msm: sde: fix release fence signaling in error cases Handle release fence/frame-done error signalling for error case like esd failure, pp_done timeout, interrupt disable on cpu, etc. It fixes the race condition for pending_frame count update and also triggers correct wait function for wr_ptr wait failure. Change-Id: Iad08f20592c97221a1626bb40e607c398a9812b6 Signed-off-by: Veera Sundaram Sankaran Signed-off-by: Dhaval Patel Signed-off-by: Bruce Hoo Signed-off-by: Ray Zhang --- drivers/gpu/drm/msm/sde/sde_encoder.c | 4 +- drivers/gpu/drm/msm/sde/sde_encoder_phys.h | 3 +- .../gpu/drm/msm/sde/sde_encoder_phys_cmd.c | 59 ++++++++++--------- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index fe05a401a2fa..b869a2d01262 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -3455,6 +3455,7 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc) sde_enc->phys_encs[i]->cont_splash_single_flush = 0; sde_enc->phys_encs[i]->connector = NULL; } + atomic_set(&sde_enc->frame_done_cnt[i], 0); } sde_enc->cur_master = NULL; @@ -3680,8 +3681,7 @@ static void sde_encoder_frame_done_callback( /* One of the physical encoders has become idle */ for (i = 0; i < sde_enc->num_phys_encs; i++) { - if ((sde_enc->phys_encs[i] == ready_phys) || - (event & SDE_ENCODER_FRAME_EVENT_ERROR)) { + if (sde_enc->phys_encs[i] == ready_phys) { SDE_EVT32_VERBOSE(DRMID(drm_enc), i, atomic_read( &sde_enc->frame_done_cnt[i])); diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h index 53d6cf5fcf3d..8ffb00f43320 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h @@ -379,12 +379,12 @@ struct sde_encoder_phys_cmd_autorefresh { * struct sde_encoder_phys_cmd - sub-class of sde_encoder_phys to handle command * mode specific operations * @base: Baseclass physical encoder structure - * @intf_idx: Intf Block index used by this phys encoder * @stream_sel: Stream selection for multi-stream interfaces * @pp_timeout_report_cnt: number of pingpong done irq timeout errors * @autorefresh: autorefresh feature state * @pending_vblank_cnt: Atomic counter tracking pending wait for VBLANK * @pending_vblank_wq: Wait queue for blocking until VBLANK received + * @wr_ptr_wait_success: log wr_ptr_wait success for release fence trigger */ struct sde_encoder_phys_cmd { struct sde_encoder_phys base; @@ -393,6 +393,7 @@ struct sde_encoder_phys_cmd { struct sde_encoder_phys_cmd_autorefresh autorefresh; atomic_t pending_vblank_cnt; wait_queue_head_t pending_vblank_wq; + bool wr_ptr_wait_success; }; /** diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index 197b34a297c8..6d127bd06264 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -481,20 +481,18 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout( conn = phys_enc->connector; sde_conn = to_sde_connector(conn); - if (atomic_read(&phys_enc->pending_kickoff_cnt) == 0) + /* decrement the kickoff_cnt before checking for ESD status */ + if (!atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0)) return 0; cmd_enc->pp_timeout_report_cnt++; - pending_kickoff_cnt = atomic_read(&phys_enc->pending_kickoff_cnt); + pending_kickoff_cnt = atomic_read(&phys_enc->pending_kickoff_cnt) + 1; SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, cmd_enc->pp_timeout_report_cnt, pending_kickoff_cnt, frame_event); - /* decrement the kickoff_cnt before checking for ESD status */ - atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0); - /* check if panel is still sending TE signal or not */ if (sde_connector_esd_status(phys_enc->connector) || sde_conn->panel_dead) @@ -672,13 +670,28 @@ static int _sde_encoder_phys_cmd_wait_for_idle( to_sde_encoder_phys_cmd(phys_enc); struct sde_encoder_wait_info wait_info; bool recovery_events; - int ret, i, pending_cnt; + int ret; + struct sde_hw_ctl *ctl; if (!phys_enc) { SDE_ERROR("invalid encoder\n"); return -EINVAL; } + ctl = phys_enc->hw_ctl; + if (cmd_enc->wr_ptr_wait_success && + (phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START) && + ctl->ops.get_scheduler_status && + (ctl->ops.get_scheduler_status(ctl) & BIT(0)) && + atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0) && + phys_enc->parent_ops.handle_frame_done) { + phys_enc->parent_ops.handle_frame_done( + phys_enc->parent, phys_enc, + SDE_ENCODER_FRAME_EVENT_DONE | + SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE); + return 0; + } + wait_info.wq = &phys_enc->pending_kickoff_wq; wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt; wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; @@ -692,9 +705,7 @@ static int _sde_encoder_phys_cmd_wait_for_idle( ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_PINGPONG, &wait_info); if (ret == -ETIMEDOUT) { - pending_cnt = atomic_read(&phys_enc->pending_kickoff_cnt); - for (i = 0; i < pending_cnt; i++) - _sde_encoder_phys_cmd_handle_ppdone_timeout(phys_enc, + _sde_encoder_phys_cmd_handle_ppdone_timeout(phys_enc, recovery_events); } else if (!ret) { if (cmd_enc->pp_timeout_report_cnt && recovery_events) { @@ -1386,20 +1397,10 @@ static int _sde_encoder_phys_cmd_wait_for_wr_ptr( phys_enc->parent_ops.handle_frame_done( phys_enc->parent, phys_enc, SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE); - } else if ((ret == 0) && - (phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START) && - atomic_read(&phys_enc->pending_kickoff_cnt) && - ctl->ops.get_scheduler_status && - (ctl->ops.get_scheduler_status(ctl) & BIT(0)) && - phys_enc->parent_ops.handle_frame_done) { - atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0); - - phys_enc->parent_ops.handle_frame_done( - phys_enc->parent, phys_enc, - SDE_ENCODER_FRAME_EVENT_DONE | - SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE); } + cmd_enc->wr_ptr_wait_success = (ret == 0) ? true : false; + return ret; } @@ -1427,7 +1428,7 @@ static int sde_encoder_phys_cmd_wait_for_tx_complete( static int sde_encoder_phys_cmd_wait_for_commit_done( struct sde_encoder_phys *phys_enc) { - int rc = 0; + int rc = 0, i, pending_cnt; struct sde_encoder_phys_cmd *cmd_enc; if (!phys_enc) @@ -1440,11 +1441,11 @@ static int sde_encoder_phys_cmd_wait_for_commit_done( rc = _sde_encoder_phys_cmd_wait_for_wr_ptr(phys_enc); if (rc == -ETIMEDOUT) goto wait_for_idle; - } - if (!rc && sde_encoder_phys_cmd_is_master(phys_enc) && - cmd_enc->autorefresh.cfg.enable) - rc = _sde_encoder_phys_cmd_wait_for_autorefresh_done(phys_enc); + if (cmd_enc->autorefresh.cfg.enable) + rc = _sde_encoder_phys_cmd_wait_for_autorefresh_done( + phys_enc); + } /* wait for posted start or serialize trigger */ if ((atomic_read(&phys_enc->pending_kickoff_cnt) > 1) || @@ -1453,14 +1454,16 @@ static int sde_encoder_phys_cmd_wait_for_commit_done( goto wait_for_idle; wait_for_idle: - rc = _sde_encoder_phys_cmd_wait_for_idle(phys_enc); + pending_cnt = atomic_read(&phys_enc->pending_kickoff_cnt); + for (i = 0; i < pending_cnt; i++) + rc |= sde_encoder_wait_for_event(phys_enc->parent, + MSM_ENC_TX_COMPLETE); if (rc) { SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->frame_trigger_mode, atomic_read(&phys_enc->pending_kickoff_cnt), phys_enc->enable_state, rc); - atomic_set(&phys_enc->pending_kickoff_cnt, 0); SDE_ERROR("pp:%d failed wait_for_idle: %d\n", phys_enc->hw_pp->idx - PINGPONG_0, rc); if (phys_enc->enable_state == SDE_ENC_ERR_NEEDS_HW_RESET) From 8f0dde931bba48af937213448b309529bfbb3ea4 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Fri, 12 Jun 2020 19:05:14 +0800 Subject: [PATCH 064/192] disp: msm: sde: wait for specific pp_done instead of zero 2 Frames transfer pending is possible with posted start. One ongoing frame and another triggered frame. Current SW waits for pp_done interrupt if pending frame count is greater than 1. It is possible that interrupt may be missed for ongoing frame. In that case, SW should run pp_done wait for one by one frame instead of two frames together. It allows encoder to check the ctl scheduler status and trigger the frame done event on time. Change-Id: I4817842292d96747890ee70da8a5bdf9b56816ed Signed-off-by: Dhaval Patel Signed-off-by: Ray Zhang Signed-off-by: Bruce Hoo --- drivers/gpu/drm/msm/sde/sde_encoder.c | 9 ++++++--- drivers/gpu/drm/msm/sde/sde_encoder_phys.h | 2 ++ drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c | 16 ++++++++++++---- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index b869a2d01262..fee86ae93330 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -444,13 +444,16 @@ static int _sde_encoder_wait_timeout(int32_t drm_id, int32_t hw_id, do { rc = wait_event_timeout(*(info->wq), - atomic_read(info->atomic_cnt) == 0, wait_time_jiffies); + atomic_read(info->atomic_cnt) == info->count_check, + wait_time_jiffies); cur_ktime = ktime_get(); SDE_EVT32(drm_id, hw_id, rc, ktime_to_ms(cur_ktime), - timeout_ms, atomic_read(info->atomic_cnt)); + timeout_ms, atomic_read(info->atomic_cnt), + info->count_check); /* If we timed out, counter is valid and time is less, wait again */ - } while (atomic_read(info->atomic_cnt) && (rc == 0) && + } while ((atomic_read(info->atomic_cnt) != info->count_check) && + (rc == 0) && (ktime_compare_safe(exp_ktime, cur_ktime) > 0)); return rc; diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h index 8ffb00f43320..accab600df16 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h @@ -472,11 +472,13 @@ struct sde_enc_phys_init_params { * sde_encoder_wait_info - container for passing arguments to irq wait functions * @wq: wait queue structure * @atomic_cnt: wait until atomic_cnt equals zero + * @count_check: wait for specific atomic_cnt instead of zero. * @timeout_ms: timeout value in milliseconds */ struct sde_encoder_wait_info { wait_queue_head_t *wq; atomic_t *atomic_cnt; + u32 count_check; s64 timeout_ms; }; diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index 6d127bd06264..1ac7b23bd233 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -672,6 +672,7 @@ static int _sde_encoder_phys_cmd_wait_for_idle( bool recovery_events; int ret; struct sde_hw_ctl *ctl; + bool wr_ptr_wait_success = true; if (!phys_enc) { SDE_ERROR("invalid encoder\n"); @@ -679,7 +680,11 @@ static int _sde_encoder_phys_cmd_wait_for_idle( } ctl = phys_enc->hw_ctl; - if (cmd_enc->wr_ptr_wait_success && + + if (sde_encoder_phys_cmd_is_master(phys_enc)) + wr_ptr_wait_success = cmd_enc->wr_ptr_wait_success; + + if (wr_ptr_wait_success && (phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START) && ctl->ops.get_scheduler_status && (ctl->ops.get_scheduler_status(ctl) & BIT(0)) && @@ -692,6 +697,9 @@ static int _sde_encoder_phys_cmd_wait_for_idle( return 0; } + if (atomic_read(&phys_enc->pending_kickoff_cnt) > 1) + wait_info.count_check = 1; + wait_info.wq = &phys_enc->pending_kickoff_wq; wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt; wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; @@ -727,7 +735,7 @@ static int _sde_encoder_phys_cmd_wait_for_autorefresh_done( { struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc); - struct sde_encoder_wait_info wait_info; + struct sde_encoder_wait_info wait_info = {NULL}; int ret = 0; if (!phys_enc) { @@ -1351,7 +1359,7 @@ static int _sde_encoder_phys_cmd_wait_for_wr_ptr( { struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc); - struct sde_encoder_wait_info wait_info; + struct sde_encoder_wait_info wait_info = {NULL}; int ret; bool frame_pending = true; struct sde_hw_ctl *ctl; @@ -1478,7 +1486,7 @@ static int sde_encoder_phys_cmd_wait_for_vblank( { int rc = 0; struct sde_encoder_phys_cmd *cmd_enc; - struct sde_encoder_wait_info wait_info; + struct sde_encoder_wait_info wait_info = {NULL}; if (!phys_enc) return -EINVAL; From 354291b18d89f23d9e0623129b7d772af14ece24 Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Fri, 12 Jun 2020 19:13:48 +0800 Subject: [PATCH 065/192] disp: msm: sde: fix handling the missing pp-done interrupt cases With posted-start, ctl scheduler status and pending-kickoff count are checked to address the missing pp-done interrupt cases, which can occur if the IRQs are disabled for a long time by some entity. Currently this check is done after the wr-ptr-irq. At this point the scheduler status may or may not be idle, based on the frame-transfer. Move this handling after the timeout, so the scheduler is guaranteed to be in idle state for working use-case. Change-Id: I3fa9ecce8139ff667c1882e286571169c543c797 Signed-off-by: Veera Sundaram Sankaran Signed-off-by: Ray Zhang Signed-off-by: Bruce Hoo --- .../gpu/drm/msm/sde/sde_encoder_phys_cmd.c | 56 ++++++++++++++----- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index 1ac7b23bd233..fd7897d587b8 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -663,38 +663,60 @@ static bool _sde_encoder_phys_cmd_is_ongoing_pptx( return false; } -static int _sde_encoder_phys_cmd_wait_for_idle( +static bool _sde_encoder_phys_cmd_is_scheduler_idle( struct sde_encoder_phys *phys_enc) { + bool wr_ptr_wait_success = true; + unsigned long lock_flags; + bool ret = false; struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc); - struct sde_encoder_wait_info wait_info; - bool recovery_events; - int ret; - struct sde_hw_ctl *ctl; - bool wr_ptr_wait_success = true; - - if (!phys_enc) { - SDE_ERROR("invalid encoder\n"); - return -EINVAL; - } - - ctl = phys_enc->hw_ctl; + struct sde_hw_ctl *ctl = phys_enc->hw_ctl; if (sde_encoder_phys_cmd_is_master(phys_enc)) wr_ptr_wait_success = cmd_enc->wr_ptr_wait_success; + /* + * Handle cases where a pp-done interrupt is missed + * due to irq latency with POSTED start + */ if (wr_ptr_wait_success && (phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START) && ctl->ops.get_scheduler_status && (ctl->ops.get_scheduler_status(ctl) & BIT(0)) && atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0) && phys_enc->parent_ops.handle_frame_done) { + + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); phys_enc->parent_ops.handle_frame_done( phys_enc->parent, phys_enc, SDE_ENCODER_FRAME_EVENT_DONE | SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE); - return 0; + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); + + SDE_EVT32(DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->hw_intf->idx - INTF_0, + atomic_read(&phys_enc->pending_kickoff_cnt)); + + ret = true; + } + + return ret; +} + +static int _sde_encoder_phys_cmd_wait_for_idle( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + struct sde_encoder_wait_info wait_info = {NULL}; + bool recovery_events; + int ret; + + if (!phys_enc) { + SDE_ERROR("invalid encoder\n"); + return -EINVAL; } if (atomic_read(&phys_enc->pending_kickoff_cnt) > 1) @@ -710,9 +732,15 @@ static int _sde_encoder_phys_cmd_wait_for_idle( if (_sde_encoder_phys_is_ppsplit_slave(phys_enc)) return 0; + if (_sde_encoder_phys_cmd_is_scheduler_idle(phys_enc)) + return 0; + ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_PINGPONG, &wait_info); if (ret == -ETIMEDOUT) { + if (_sde_encoder_phys_cmd_is_scheduler_idle(phys_enc)) + return 0; + _sde_encoder_phys_cmd_handle_ppdone_timeout(phys_enc, recovery_events); } else if (!ret) { From 98316bf1125128c1fcbafe9f3a30826f21cfafe9 Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Fri, 12 Jun 2020 19:21:42 +0800 Subject: [PATCH 066/192] disp: msm: sde: avoid encoder power-collapse with pending frames The encoder idle work is scheduled during the frame-done event to be executed after a timeout. During the execution, the check for any on-going/pending frames is invalid as it checks for > 1. Fix it to check for any non-zero frame-pending and avoid power-collapse. Change-Id: If7715ee56cc9bfa63787811458f4fc91de540013 Signed-off-by: Veera Sundaram Sankaran Signed-off-by: Ray Zhang Signed-off-by: Bruce Hoo --- drivers/gpu/drm/msm/sde/sde_encoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index fee86ae93330..1cfa67a88d31 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -2696,7 +2696,7 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, SDE_EVTLOG_ERROR); mutex_unlock(&sde_enc->rc_lock); return 0; - } else if (sde_crtc_frame_pending(sde_enc->crtc) > 1) { + } else if (sde_crtc_frame_pending(sde_enc->crtc)) { SDE_DEBUG_ENC(sde_enc, "skip idle entry"); SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, sde_crtc_frame_pending(sde_enc->crtc), From d8ba1b1072a69b00a54ffe66ffc6b3a428a167bb Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Fri, 12 Jun 2020 19:36:49 +0800 Subject: [PATCH 067/192] disp: msm: sde: handle another case for lost pp-done interrupt Due to interrupt delays, sometimes the pp-done interrupt for an in-between frame is lost, as with posted-start frames are queued to the hardware before the completion of the previous frame. Handle the lost pp-done interrupt in the case where frame-n pp-done interrupt is missed and frame-n+1 pp-done interrupt is processed before frame-n+1 wr-ptr interrupt. Change-Id: I36ec7ac494b2720fc005dab75047d2f4a5a2a699 Signed-off-by: Veera Sundaram Sankaran Signed-off-by: Ray Zhang Signed-off-by: Bruce Hoo --- .../gpu/drm/msm/sde/sde_encoder_phys_cmd.c | 22 ++++++++++++++----- drivers/gpu/drm/msm/sde/sde_hw_ctl.h | 2 ++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index fd7897d587b8..15123d6ee7b1 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -1341,10 +1341,11 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff( } SDE_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0); + phys_enc->frame_trigger_mode = params->frame_trigger_mode; SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, atomic_read(&phys_enc->pending_kickoff_cnt), - atomic_read(&cmd_enc->autorefresh.kickoff_cnt)); - phys_enc->frame_trigger_mode = params->frame_trigger_mode; + atomic_read(&cmd_enc->autorefresh.kickoff_cnt), + phys_enc->frame_trigger_mode); if (phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_DEFAULT) { /* @@ -1466,6 +1467,8 @@ static int sde_encoder_phys_cmd_wait_for_commit_done( { int rc = 0, i, pending_cnt; struct sde_encoder_phys_cmd *cmd_enc; + u32 scheduler_status = INVALID_CTL_STATUS; + struct sde_hw_ctl *ctl; if (!phys_enc) return -EINVAL; @@ -1481,14 +1484,22 @@ static int sde_encoder_phys_cmd_wait_for_commit_done( if (cmd_enc->autorefresh.cfg.enable) rc = _sde_encoder_phys_cmd_wait_for_autorefresh_done( phys_enc); + + ctl = phys_enc->hw_ctl; + if (ctl && ctl->ops.get_scheduler_status) + scheduler_status = ctl->ops.get_scheduler_status(ctl); } /* wait for posted start or serialize trigger */ - if ((atomic_read(&phys_enc->pending_kickoff_cnt) > 1) || + pending_cnt = atomic_read(&phys_enc->pending_kickoff_cnt); + if ((pending_cnt > 1) || + (pending_cnt && (scheduler_status & BIT(0))) || (!rc && phys_enc->frame_trigger_mode == - FRAME_DONE_WAIT_SERIALIZE)) + FRAME_DONE_WAIT_SERIALIZE)) goto wait_for_idle; + return rc; + wait_for_idle: pending_cnt = atomic_read(&phys_enc->pending_kickoff_cnt); for (i = 0; i < pending_cnt; i++) @@ -1499,7 +1510,8 @@ static int sde_encoder_phys_cmd_wait_for_commit_done( phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->frame_trigger_mode, atomic_read(&phys_enc->pending_kickoff_cnt), - phys_enc->enable_state, rc); + phys_enc->enable_state, + cmd_enc->wr_ptr_wait_success, scheduler_status, rc); SDE_ERROR("pp:%d failed wait_for_idle: %d\n", phys_enc->hw_pp->idx - PINGPONG_0, rc); if (phys_enc->enable_state == SDE_ENC_ERR_NEEDS_HW_RESET) diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h index 1cef1f2ef58f..dc1a65c7b058 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h @@ -19,6 +19,8 @@ #include "sde_hw_sspp.h" #include "sde_hw_blk.h" +#define INVALID_CTL_STATUS 0xfffff88e + /** * sde_ctl_mode_sel: Interface mode selection * SDE_CTL_MODE_SEL_VID: Video mode interface From ad18f17b3a1a82a13961796531ba83b1291b28f2 Mon Sep 17 00:00:00 2001 From: Raviteja Tamatam Date: Fri, 12 Jun 2020 19:48:47 +0800 Subject: [PATCH 068/192] disp: msm: sde: signal retire fence in wr_ptr timeout There can be few cases of ESD where CTL_START is cleared but wr_ptr interrupt does not come. Signaling retire fence in these cases to avoid freeze and dangling pending_retire_fence_cnt. Change-Id: I167f69dce5cbe43b4771e5056d8a73bd7587e76e Signed-off-by: Raviteja Tamatam Signed-off-by: Ray Zhang --- .../gpu/drm/msm/sde/sde_encoder_phys_cmd.c | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index 15123d6ee7b1..2e31261902b8 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -1392,6 +1392,7 @@ static int _sde_encoder_phys_cmd_wait_for_wr_ptr( int ret; bool frame_pending = true; struct sde_hw_ctl *ctl; + unsigned long lock_flags; if (!phys_enc || !phys_enc->hw_ctl) { SDE_ERROR("invalid argument(s)\n"); @@ -1422,18 +1423,29 @@ static int _sde_encoder_phys_cmd_wait_for_wr_ptr( ret = 0; /* - * Signaling the retire fence at wr_ptr timeout - * to allow the next commit and avoid device freeze. - * As wr_ptr timeout can occurs due to no read ptr, - * updating pending_rd_ptr_cnt here may not cover all - * cases. Hence signaling the retire fence. + * There can be few cases of ESD where CTL_START is cleared but + * wr_ptr irq doesn't come. Signaling retire fence in these + * cases to avoid freeze and dangling pending_retire_fence_cnt */ - if (sde_encoder_phys_cmd_is_master(phys_enc) && - atomic_add_unless(&phys_enc->pending_retire_fence_cnt, - -1, 0)) - phys_enc->parent_ops.handle_frame_done( - phys_enc->parent, phys_enc, - SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE); + if (!ret) { + u32 signal_retire_event = + SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE; + + SDE_EVT32(DRMID(phys_enc->parent), + SDE_EVTLOG_FUNC_CASE1); + + if (sde_encoder_phys_cmd_is_master(phys_enc) && + atomic_add_unless( + &phys_enc->pending_retire_fence_cnt, -1, 0)) { + spin_lock_irqsave(phys_enc->enc_spinlock, + lock_flags); + phys_enc->parent_ops.handle_frame_done( + phys_enc->parent, phys_enc, + signal_retire_event); + spin_unlock_irqrestore(phys_enc->enc_spinlock, + lock_flags); + } + } } cmd_enc->wr_ptr_wait_success = (ret == 0) ? true : false; From 135b653de9a11fba44c130f664af1def746672f6 Mon Sep 17 00:00:00 2001 From: Ray Zhang Date: Wed, 24 Jun 2020 13:21:37 +0800 Subject: [PATCH 069/192] disp: msm: sde: avoid multiple frame-done encoder events Currently there is a race condition in checking the pending_kickoff_cnt in wr_ptr_irq wait from display-thread and pp_done_irq from interrupt context. In both places, pending_kickoff_cnt is read first and modified later. In partial update cases where the frame-transfer is short, such a race condition might happen and would lead to both triggering the frame-done/release fence for the same frame. Fix it by combining read/modify to one statement in both places. Change-Id: I9162e7dc3f12af3590514f1ebfd68023aa920181 Signed-off-by: Veera Sundaram Sankaran Signed-off-by: Ray Zhang --- drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index 2e31261902b8..ef0f55041a9f 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -183,10 +183,7 @@ static void _sde_encoder_phys_cmd_update_intf_cfg( static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx) { struct sde_encoder_phys *phys_enc = arg; - unsigned long lock_flags; - int new_cnt; - u32 event = SDE_ENCODER_FRAME_EVENT_DONE | - SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE; + u32 event = 0; if (!phys_enc || !phys_enc->hw_pp) return; @@ -195,16 +192,17 @@ static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx) /* notify all synchronous clients first, then asynchronous clients */ if (phys_enc->parent_ops.handle_frame_done && - atomic_read(&phys_enc->pending_kickoff_cnt)) + atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0)) { + event = SDE_ENCODER_FRAME_EVENT_DONE | + SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE; + spin_lock(phys_enc->enc_spinlock); phys_enc->parent_ops.handle_frame_done(phys_enc->parent, phys_enc, event); - - spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); - new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0); - spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); + spin_unlock(phys_enc->enc_spinlock); + } SDE_EVT32_IRQ(DRMID(phys_enc->parent), - phys_enc->hw_pp->idx - PINGPONG_0, new_cnt, event); + phys_enc->hw_pp->idx - PINGPONG_0, event); /* Signal any waiting atomic commit thread */ wake_up_all(&phys_enc->pending_kickoff_wq); From a4816cf8db7cfdba7e8242fea4393facd2137e78 Mon Sep 17 00:00:00 2001 From: Vara Reddy Date: Fri, 12 Jun 2020 21:02:54 +0800 Subject: [PATCH 070/192] dt-bindings: Add frame threshold property for dsi controller Change adds frame threshold time property in microseconds to the controller. This specifies the idle time of controller in command mode operation and is used to calculate the dsi clocks if there is no preferred clock for the panel. Change-Id: I24519602c48bffa8b13fcb49f7d3648b09733708 Signed-off-by: Vara Reddy Signed-off-by: Ray Zhang Signed-off-by: Bruce Hoo --- Documentation/devicetree/bindings/display/msm/dsi.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/display/msm/dsi.txt b/Documentation/devicetree/bindings/display/msm/dsi.txt index 17f9d7516ffb..d9e3421c34ca 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi.txt +++ b/Documentation/devicetree/bindings/display/msm/dsi.txt @@ -127,6 +127,13 @@ Optional properties: turns off PHY pmic power supply, phy ldo and DSI Lane ldo during idle screen (footswitch control off) when this property is enabled. - qcom,dsi-phy-regulator-min-datarate-bps: Minimum per lane data rate (bps) to turn on PHY regulator. +- frame-threshold-time-us: For command mode panel, this specifies the idle + time for dsi controller where no active data is + sent to the panel, as controller is done sending + active pixels. If there is no desired DSI clocks + specified, then clocks will be derived from this + threshold time, which has a default value in chipset + based on the CPU processing power. [1] Documentation/devicetree/bindings/clock/clock-bindings.txt [2] Documentation/devicetree/bindings/graph.txt @@ -178,6 +185,7 @@ Example: qcom,sync-dual-dsi; qcom,mdss-mdp-transfer-time-us = <12000>; + frame-threshold-time-us = <800>; pinctrl-names = "default", "sleep"; pinctrl-0 = <&dsi_active>; From b849d49ad9a4059b5b4cddc79713966de496b950 Mon Sep 17 00:00:00 2001 From: Bruce Hoo Date: Fri, 12 Jun 2020 20:47:52 +0800 Subject: [PATCH 071/192] ARM: dts: msm: update frame threshold time for atoll Change adds 800 microseconds as frame threshold time for atoll as posted start feature enables us to have lower threshold time. Change-Id: I67cbc612270f866ec40a99aba200d03abe48c7cd Signed-off-by: Bruce Hoo Signed-off-by: Ray Zhang --- arch/arm64/boot/dts/qcom/atoll-sde.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/atoll-sde.dtsi b/arch/arm64/boot/dts/qcom/atoll-sde.dtsi index af9ccda50f6f..5455b376e056 100644 --- a/arch/arm64/boot/dts/qcom/atoll-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/atoll-sde.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -419,6 +419,7 @@ compatible = "qcom,dsi-ctrl-hw-v2.4"; label = "dsi-ctrl-0"; cell-index = <0>; + frame-threshold-time-us = <800>; reg = <0xae94000 0x400>, <0xaf08000 0x4>; reg-names = "dsi_ctrl", "disp_cc_base"; From ed484418246f031f00111ec370ac82d81de652cf Mon Sep 17 00:00:00 2001 From: Manikanta Pubbisetty Date: Thu, 12 Apr 2018 17:46:50 +0530 Subject: [PATCH 072/192] UPSTREAM: ath10k: correct target assert problem due to CE5 stuck Correct a minor bug in the commit 0628467f97b5 ("ath10k: fix copy engine 5 destination ring stuck") which introduced a change to fix firmware assert that happens when ring indices of copy engine 5 are stuck for a specific duration, problem with this fix is that it did not use ring arithmatic. As a result,firmware asserts did not go away entirely athough the frequency of occurrence has reduced. Using ring arithmatic to fix the issue. Tested on QCA9984(fw version-10.4-3.4-00082). Fixes: 0628467f97b5 ("ath10k: fix copy engine 5 destination ring stuck) Signed-off-by: Manikanta Pubbisetty Signed-off-by: Kalle Valo Git-commit: 1e8f77502341035f079039c9aa9a647ebc9d881a Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I84b8b4c8feaea2472606601d49ac321a32153b71 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/ce.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index e7e7b342e5b8..3a15923bdd26 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -620,7 +620,7 @@ void ath10k_ce_rx_update_write_idx(struct ath10k_ce_pipe *pipe, u32 nentries) /* Prevent CE ring stuck issue that will occur when ring is full. * Make sure that write index is 1 less than read index. */ - if ((cur_write_idx + nentries) == dest_ring->sw_index) + if (((cur_write_idx + nentries) & nentries_mask) == dest_ring->sw_index) nentries -= 1; write_index = CE_RING_IDX_ADD(nentries_mask, write_index, nentries); From c17ad6175295f2f9f82002f46f51661ab43a5096 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Mon, 16 Apr 2018 09:56:45 +0530 Subject: [PATCH 073/192] UPSTREAM: ath10k: fix fw path name for WCN3990 target FW path is mapped incorrectly for the WCN3990 hw version. Fix fw path with correct hw1.0 name. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: 6da2b2d46ff937edc3ecea0a36d92252981d033a Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I034c3af8e8dbb0c0505a4eb1763f9bbfe65f6a8a Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/hw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 90293200e838..685ba71aeeb9 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -130,7 +130,7 @@ enum qca9377_chip_id_rev { /* WCN3990 1.0 definitions */ #define WCN3990_HW_1_0_DEV_VERSION ATH10K_HW_WCN3990 -#define WCN3990_HW_1_0_FW_DIR ATH10K_FW_DIR "/WCN3990/hw3.0" +#define WCN3990_HW_1_0_FW_DIR ATH10K_FW_DIR "/WCN3990/hw1.0" #define ATH10K_FW_FILE_BASE "firmware" #define ATH10K_FW_API_MAX 6 From bf43957ad4b7fa0a49dbaace65b812313bb82077 Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Tue, 17 Apr 2018 14:54:26 +0530 Subject: [PATCH 074/192] BACKPORT: UPSTREAM: ath10k: enable hw checksum for wcn3990 By default ath10k driver enables the support for HW_CHECKSUM (NETIF_F_HW_CSUM). Since the TCP/UDP checksum calculation is not enabled in the wcn3990 firmware the checksum is incorrect in the TCP/UDP packets and all patckets are dropped. But due note that wcn3990 support in ath10k is still incomplete so this isn't a critical fix (yet). Enable hw checksum calculations in wcn3990 hardware by setting the proper flags in msdu descriptor tso flags. Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo [dundi@codeaurora.org: resolve trivial merge conflicts in drivers/net/wireless/ath/ath10k/htt_tx.c] Git-commit: 20529b33aa12224e4399b4486e5ab617cf8f3e5e Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I2934a6d695826c604007c550159811ee2e9943e8 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/htt.h | 13 +++++++++++++ drivers/net/wireless/ath/ath10k/htt_tx.c | 7 +++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 783640032216..5de693845d31 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -127,6 +127,19 @@ struct htt_msdu_ext_desc_64 { | HTT_MSDU_EXT_DESC_FLAG_TCP_IPV4_CSUM_ENABLE \ | HTT_MSDU_EXT_DESC_FLAG_TCP_IPV6_CSUM_ENABLE) +#define HTT_MSDU_EXT_DESC_FLAG_IPV4_CSUM_ENABLE_64 BIT(16) +#define HTT_MSDU_EXT_DESC_FLAG_UDP_IPV4_CSUM_ENABLE_64 BIT(17) +#define HTT_MSDU_EXT_DESC_FLAG_UDP_IPV6_CSUM_ENABLE_64 BIT(18) +#define HTT_MSDU_EXT_DESC_FLAG_TCP_IPV4_CSUM_ENABLE_64 BIT(19) +#define HTT_MSDU_EXT_DESC_FLAG_TCP_IPV6_CSUM_ENABLE_64 BIT(20) +#define HTT_MSDU_EXT_DESC_FLAG_PARTIAL_CSUM_ENABLE_64 BIT(21) + +#define HTT_MSDU_CHECKSUM_ENABLE_64 (HTT_MSDU_EXT_DESC_FLAG_IPV4_CSUM_ENABLE_64 \ + | HTT_MSDU_EXT_DESC_FLAG_UDP_IPV4_CSUM_ENABLE_64 \ + | HTT_MSDU_EXT_DESC_FLAG_UDP_IPV6_CSUM_ENABLE_64 \ + | HTT_MSDU_EXT_DESC_FLAG_TCP_IPV4_CSUM_ENABLE_64 \ + | HTT_MSDU_EXT_DESC_FLAG_TCP_IPV6_CSUM_ENABLE_64) + enum htt_data_tx_desc_flags0 { HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT = 1 << 0, HTT_DATA_TX_DESC_FLAGS0_NO_AGGR = 1 << 1, diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index b204d1ebfd63..62f3bfab405f 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -1475,8 +1475,11 @@ static int ath10k_htt_tx_64(struct ath10k_htt *htt, !test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; - if (ar->hw_params.continuous_frag_desc && ext_desc) - ext_desc->flags |= HTT_MSDU_CHECKSUM_ENABLE; + if (ar->hw_params.continuous_frag_desc && ext_desc) { + memset(ext_desc->tso_flag, 0, sizeof(ext_desc->tso_flag)); + ext_desc->tso_flag[3] |= + __cpu_to_le32(HTT_MSDU_CHECKSUM_ENABLE_64); + } } /* Prevent firmware from sending up tx inspection requests. There's From da2503e897cb9e94e8fb3268cd269d6e2d990618 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Thu, 19 Apr 2018 19:39:38 +0300 Subject: [PATCH 075/192] BACKPORT: UPSTREAM: ath10k: add WMI_SERVICE_AVAILABLE_EVENT support Add WMI_SERVICE_AVAILABLE_EVENT to extend WMI_SERVICE_READY_EVENT, the 128bit service map in WMI_SERVICE_READY_EVENT is not enough for firmware to notice new WLAN service to host driver. Hereby, for thoese new WLAN service, firmware will notice host driver by WMI_SERVICE_AVAILABLE_EVENT. Signed-off-by: Alan Liu Signed-off-by: Carl Huang Signed-off-by: Kalle Valo [dundi@codeaurora.org: Upstream code has some additional WMI_SERVICE_XXX definitions. To keep WMI_SERVICE_SPOOF_MAC_SUPPORT as same as upstream, backport these definitions too] Git-commit: cea19a6ce8bf0518d156beea419d822021cc3705 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: If6435324f0f716b7146d7f5697adcecfde30c26a Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/wmi-ops.h | 24 ++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 38 +++ drivers/net/wireless/ath/ath10k/wmi-tlv.h | 346 +++++++++++++++++++++- drivers/net/wireless/ath/ath10k/wmi.c | 21 +- drivers/net/wireless/ath/ath10k/wmi.h | 12 + 5 files changed, 435 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 14093cfdc505..86d083de63fc 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -24,6 +24,7 @@ struct sk_buff; struct wmi_ops { void (*rx)(struct ath10k *ar, struct sk_buff *skb); void (*map_svc)(const __le32 *in, unsigned long *out, size_t len); + void (*map_svc_ext)(const __le32 *in, unsigned long *out, size_t len); int (*pull_scan)(struct ath10k *ar, struct sk_buff *skb, struct wmi_scan_ev_arg *arg); @@ -53,6 +54,9 @@ struct wmi_ops { struct wmi_wow_ev_arg *arg); int (*pull_echo_ev)(struct ath10k *ar, struct sk_buff *skb, struct wmi_echo_ev_arg *arg); + int (*pull_svc_avail)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_svc_avail_ev_arg *arg); + enum wmi_txbf_conf (*get_txbf_conf_scheme)(struct ath10k *ar); struct sk_buff *(*gen_pdev_suspend)(struct ath10k *ar, u32 suspend_opt); @@ -222,6 +226,17 @@ ath10k_wmi_map_svc(struct ath10k *ar, const __le32 *in, unsigned long *out, return 0; } +static inline int +ath10k_wmi_map_svc_ext(struct ath10k *ar, const __le32 *in, unsigned long *out, + size_t len) +{ + if (!ar->wmi.ops->map_svc_ext) + return -EOPNOTSUPP; + + ar->wmi.ops->map_svc_ext(in, out, len); + return 0; +} + static inline int ath10k_wmi_pull_scan(struct ath10k *ar, struct sk_buff *skb, struct wmi_scan_ev_arg *arg) @@ -322,6 +337,15 @@ ath10k_wmi_pull_rdy(struct ath10k *ar, struct sk_buff *skb, return ar->wmi.ops->pull_rdy(ar, skb, arg); } +static inline int +ath10k_wmi_pull_svc_avail(struct ath10k *ar, struct sk_buff *skb, + struct wmi_svc_avail_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_svc_avail) + return -EOPNOTSUPP; + return ar->wmi.ops->pull_svc_avail(ar, skb, arg); +} + static inline int ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb, struct ath10k_fw_stats *stats) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 9d21454631c4..f53cdb893e91 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -537,6 +537,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_TLV_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; + case WMI_TLV_SERVICE_AVAILABLE_EVENTID: + ath10k_wmi_event_service_available(ar, skb); + break; case WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID: ath10k_wmi_tlv_event_bcn_tx_status(ar, skb); break; @@ -1054,6 +1057,39 @@ static int ath10k_wmi_tlv_op_pull_rdy_ev(struct ath10k *ar, return 0; } +static int ath10k_wmi_tlv_svc_avail_parse(struct ath10k *ar, u16 tag, u16 len, + const void *ptr, void *data) +{ + struct wmi_svc_avail_ev_arg *arg = data; + + switch (tag) { + case WMI_TLV_TAG_STRUCT_SERVICE_AVAILABLE_EVENT: + arg->service_map_ext_len = *(__le32 *)ptr; + arg->service_map_ext = ptr + sizeof(__le32); + return 0; + default: + break; + } + return -EPROTO; +} + +static int ath10k_wmi_tlv_op_pull_svc_avail(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_svc_avail_ev_arg *arg) +{ + int ret; + + ret = ath10k_wmi_tlv_iter(ar, skb->data, skb->len, + ath10k_wmi_tlv_svc_avail_parse, arg); + + if (ret) { + ath10k_warn(ar, "failed to parse svc_avail tlv: %d\n", ret); + return ret; + } + + return 0; +} + static void ath10k_wmi_tlv_pull_vdev_stats(const struct wmi_tlv_vdev_stats *src, struct ath10k_fw_stats_vdev *dst) { @@ -3659,6 +3695,7 @@ static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = { static const struct wmi_ops wmi_tlv_ops = { .rx = ath10k_wmi_tlv_op_rx, .map_svc = wmi_tlv_svc_map, + .map_svc_ext = wmi_tlv_svc_map_ext, .pull_scan = ath10k_wmi_tlv_op_pull_scan_ev, .pull_mgmt_rx = ath10k_wmi_tlv_op_pull_mgmt_rx_ev, @@ -3670,6 +3707,7 @@ static const struct wmi_ops wmi_tlv_ops = { .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, .pull_svc_rdy = ath10k_wmi_tlv_op_pull_svc_rdy_ev, .pull_rdy = ath10k_wmi_tlv_op_pull_rdy_ev, + .pull_svc_avail = ath10k_wmi_tlv_op_pull_svc_avail, .pull_fw_stats = ath10k_wmi_tlv_op_pull_fw_stats, .pull_roam_ev = ath10k_wmi_tlv_op_pull_roam_ev, .pull_wow_event = ath10k_wmi_tlv_op_pull_wow_ev, diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index e956574afbac..299c32e2dd14 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -295,6 +295,7 @@ enum wmi_tlv_cmd_id { enum wmi_tlv_event_id { WMI_TLV_SERVICE_READY_EVENTID = 0x1, WMI_TLV_READY_EVENTID, + WMI_TLV_SERVICE_AVAILABLE_EVENTID, WMI_TLV_SCAN_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SCAN), WMI_TLV_PDEV_TPC_CONFIG_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PDEV), WMI_TLV_CHAN_INFO_EVENTID, @@ -949,6 +950,275 @@ enum wmi_tlv_tag { WMI_TLV_TAG_STRUCT_PACKET_FILTER_ENABLE, WMI_TLV_TAG_STRUCT_SAP_SET_BLACKLIST_PARAM_CMD, WMI_TLV_TAG_STRUCT_MGMT_TX_CMD, + WMI_TLV_TAG_STRUCT_MGMT_TX_COMPL_EVENT, + WMI_TLV_TAG_STRUCT_SOC_SET_ANTENNA_MODE_CMD, + WMI_TLV_TAG_STRUCT_WOW_UDP_SVC_OFLD_CMD, + WMI_TLV_TAG_STRUCT_LRO_INFO_CMD, + WMI_TLV_TAG_STRUCT_ROAM_EARLYSTOP_RSSI_THRES_PARAM, + WMI_TLV_TAG_STRUCT_SERVICE_READY_EXT_EVENT, + WMI_TLV_TAG_STRUCT_MAWC_SENSOR_REPORT_IND_CMD, + WMI_TLV_TAG_STRUCT_MAWC_ENABLE_SENSOR_EVENT, + WMI_TLV_TAG_STRUCT_ROAM_CONFIGURE_MAWC_CMD, + WMI_TLV_TAG_STRUCT_NLO_CONFIGURE_MAWC_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_CONFIGURE_MAWC_CMD, + WMI_TLV_TAG_STRUCT_PEER_ASSOC_CONF_EVENT, + WMI_TLV_TAG_STRUCT_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_AP_PS_EGAP_PARAM_CMD, + WMI_TLV_TAG_STRUCT_AP_PS_EGAP_INFO_EVENT, + WMI_TLV_TAG_STRUCT_PMF_OFFLOAD_SET_SA_QUERY_CMD, + WMI_TLV_TAG_STRUCT_TRANSFER_DATA_TO_FLASH_CMD, + WMI_TLV_TAG_STRUCT_TRANSFER_DATA_TO_FLASH_COMPLETE_EVENT, + WMI_TLV_TAG_STRUCT_SCPC_EVENT, + WMI_TLV_TAG_STRUCT_AP_PS_EGAP_INFO_CHAINMASK_LIST, + WMI_TLV_TAG_STRUCT_STA_SMPS_FORCE_MODE_COMPLETE_EVENT, + WMI_TLV_TAG_STRUCT_BPF_GET_CAPABILITY_CMD, + WMI_TLV_TAG_STRUCT_BPF_CAPABILITY_INFO_EVT, + WMI_TLV_TAG_STRUCT_BPF_GET_VDEV_STATS_CMD, + WMI_TLV_TAG_STRUCT_BPF_VDEV_STATS_INFO_EVT, + WMI_TLV_TAG_STRUCT_BPF_SET_VDEV_INSTRUCTIONS_CMD, + WMI_TLV_TAG_STRUCT_BPF_DEL_VDEV_INSTRUCTIONS_CMD, + WMI_TLV_TAG_STRUCT_VDEV_DELETE_RESP_EVENT, + WMI_TLV_TAG_STRUCT_PEER_DELETE_RESP_EVENT, + WMI_TLV_TAG_STRUCT_ROAM_DENSE_THRES_PARAM, + WMI_TLV_TAG_STRUCT_ENLO_CANDIDATE_SCORE_PARAM, + WMI_TLV_TAG_STRUCT_PEER_UPDATE_WDS_ENTRY_CMD, + WMI_TLV_TAG_STRUCT_VDEV_CONFIG_RATEMASK, + WMI_TLV_TAG_STRUCT_PDEV_FIPS_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SMART_ANT_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SMART_ANT_SET_RX_ANTENNA_CMD, + WMI_TLV_TAG_STRUCT_PEER_SMART_ANT_SET_TX_ANTENNA_CMD, + WMI_TLV_TAG_STRUCT_PEER_SMART_ANT_SET_TRAIN_ANTENNA_CMD, + WMI_TLV_TAG_STRUCT_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_ANT_SWITCH_TBL_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_CTL_TABLE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_MIMOGAIN_TABLE_CMD, + WMI_TLV_TAG_STRUCT_FWTEST_SET_PARAM_CMD, + WMI_TLV_TAG_STRUCT_PEER_ATF_REQUEST, + WMI_TLV_TAG_STRUCT_VDEV_ATF_REQUEST, + WMI_TLV_TAG_STRUCT_PDEV_GET_ANI_CCK_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_PDEV_GET_ANI_OFDM_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_INST_RSSI_STATS_RESP, + WMI_TLV_TAG_STRUCT_MED_UTIL_REPORT_EVENT, + WMI_TLV_TAG_STRUCT_PEER_STA_PS_STATECHANGE_EVENT, + WMI_TLV_TAG_STRUCT_WDS_ADDR_EVENT, + WMI_TLV_TAG_STRUCT_PEER_RATECODE_LIST_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_NFCAL_POWER_ALL_CHANNELS_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_TPC_EVENT, + WMI_TLV_TAG_STRUCT_ANI_OFDM_EVENT, + WMI_TLV_TAG_STRUCT_ANI_CCK_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_CHANNEL_HOPPING_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_FIPS_EVENT, + WMI_TLV_TAG_STRUCT_ATF_PEER_INFO, + WMI_TLV_TAG_STRUCT_PDEV_GET_TPC_CMD, + WMI_TLV_TAG_STRUCT_VDEV_FILTER_NRP_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_QBOOST_CFG_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SMART_ANT_GPIO_HANDLE, + WMI_TLV_TAG_STRUCT_PEER_SMART_ANT_SET_TX_ANTENNA_SERIES, + WMI_TLV_TAG_STRUCT_PEER_SMART_ANT_SET_TRAIN_ANTENNA_PARAM, + WMI_TLV_TAG_STRUCT_PDEV_SET_ANT_CTRL_CHAIN, + WMI_TLV_TAG_STRUCT_PEER_CCK_OFDM_RATE_INFO, + WMI_TLV_TAG_STRUCT_PEER_MCS_RATE_INFO, + WMI_TLV_TAG_STRUCT_PDEV_NFCAL_POWER_ALL_CHANNELS_NFDBR, + WMI_TLV_TAG_STRUCT_PDEV_NFCAL_POWER_ALL_CHANNELS_NFDBM, + WMI_TLV_TAG_STRUCT_PDEV_NFCAL_POWER_ALL_CHANNELS_FREQNUM, + WMI_TLV_TAG_STRUCT_MU_REPORT_TOTAL_MU, + WMI_TLV_TAG_STRUCT_VDEV_SET_DSCP_TID_MAP_CMD, + WMI_TLV_TAG_STRUCT_ROAM_SET_MBO, + WMI_TLV_TAG_STRUCT_MIB_STATS_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_NAN_DISC_IFACE_CREATED_EVENT, + WMI_TLV_TAG_STRUCT_NAN_DISC_IFACE_DELETED_EVENT, + WMI_TLV_TAG_STRUCT_NAN_STARTED_CLUSTER_EVENT, + WMI_TLV_TAG_STRUCT_NAN_JOINED_CLUSTER_EVENT, + WMI_TLV_TAG_STRUCT_NDI_GET_CAP_REQ, + WMI_TLV_TAG_STRUCT_NDP_INITIATOR_REQ, + WMI_TLV_TAG_STRUCT_NDP_RESPONDER_REQ, + WMI_TLV_TAG_STRUCT_NDP_END_REQ, + WMI_TLV_TAG_STRUCT_NDI_CAP_RSP_EVENT, + WMI_TLV_TAG_STRUCT_NDP_INITIATOR_RSP_EVENT, + WMI_TLV_TAG_STRUCT_NDP_RESPONDER_RSP_EVENT, + WMI_TLV_TAG_STRUCT_NDP_END_RSP_EVENT, + WMI_TLV_TAG_STRUCT_NDP_INDICATION_EVENT, + WMI_TLV_TAG_STRUCT_NDP_CONFIRM_EVENT, + WMI_TLV_TAG_STRUCT_NDP_END_INDICATION_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_SET_QUIET_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_PCL_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_HW_MODE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_MAC_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_ANTENNA_MODE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_HW_MODE_RESPONSE_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_HW_MODE_TRANSITION_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_SET_HW_MODE_RESPONSE_VDEV_MAC_ENTRY, + WMI_TLV_TAG_STRUCT_PDEV_SET_MAC_CONFIG_RESPONSE_EVENT, + WMI_TLV_TAG_STRUCT_COEX_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_CONFIG_ENHANCED_MCAST_FILTER, + WMI_TLV_TAG_STRUCT_CHAN_AVOID_RPT_ALLOW_CMD, + WMI_TLV_TAG_STRUCT_SET_PERIODIC_CHANNEL_STATS_CONFIG, + WMI_TLV_TAG_STRUCT_VDEV_SET_CUSTOM_AGGR_SIZE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_WAL_POWER_DEBUG_CMD, + WMI_TLV_TAG_STRUCT_MAC_PHY_CAPABILITIES, + WMI_TLV_TAG_STRUCT_HW_MODE_CAPABILITIES, + WMI_TLV_TAG_STRUCT_SOC_MAC_PHY_HW_MODE_CAPS, + WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES_EXT, + WMI_TLV_TAG_STRUCT_SOC_HAL_REG_CAPABILITIES, + WMI_TLV_TAG_STRUCT_VDEV_WISA_CMD, + WMI_TLV_TAG_STRUCT_TX_POWER_LEVEL_STATS_EVT, + WMI_TLV_TAG_STRUCT_SCAN_ADAPTIVE_DWELL_PARAMETERS_TLV, + WMI_TLV_TAG_STRUCT_SCAN_ADAPTIVE_DWELL_CONFIG, + WMI_TLV_TAG_STRUCT_WOW_SET_ACTION_WAKE_UP_CMD, + WMI_TLV_TAG_STRUCT_NDP_END_RSP_PER_NDI, + WMI_TLV_TAG_STRUCT_PEER_BWF_REQUEST, + WMI_TLV_TAG_STRUCT_BWF_PEER_INFO, + WMI_TLV_TAG_STRUCT_DBGLOG_TIME_STAMP_SYNC_CMD, + WMI_TLV_TAG_STRUCT_RMC_SET_LEADER_CMD, + WMI_TLV_TAG_STRUCT_RMC_MANUAL_LEADER_EVENT, + WMI_TLV_TAG_STRUCT_PER_CHAIN_RSSI_STATS, + WMI_TLV_TAG_STRUCT_RSSI_STATS, + WMI_TLV_TAG_STRUCT_P2P_LO_START_CMD, + WMI_TLV_TAG_STRUCT_P2P_LO_STOP_CMD, + WMI_TLV_TAG_STRUCT_P2P_LO_STOPPED_EVENT, + WMI_TLV_TAG_STRUCT_PEER_REORDER_QUEUE_SETUP_CMD, + WMI_TLV_TAG_STRUCT_PEER_REORDER_QUEUE_REMOVE_CMD, + WMI_TLV_TAG_STRUCT_SET_MULTIPLE_MCAST_FILTER_CMD, + WMI_TLV_TAG_STRUCT_MGMT_TX_COMPL_BUNDLE_EVENT, + WMI_TLV_TAG_STRUCT_READ_DATA_FROM_FLASH_CMD, + WMI_TLV_TAG_STRUCT_READ_DATA_FROM_FLASH_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_SET_REORDER_TIMEOUT_VAL_CMD, + WMI_TLV_TAG_STRUCT_PEER_SET_RX_BLOCKSIZE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_WAKEUP_CONFIG_CMDID, + WMI_TLV_TAG_STRUCT_TLV_BUF_LEN_PARAM, + WMI_TLV_TAG_STRUCT_SERVICE_AVAILABLE_EVENT, + WMI_TLV_TAG_STRUCT_PEER_ANTDIV_INFO_REQ_CMD, + WMI_TLV_TAG_STRUCT_PEER_ANTDIV_INFO_EVENT, + WMI_TLV_TAG_STRUCT_PEER_ANTDIV_INFO, + WMI_TLV_TAG_STRUCT_PDEV_GET_ANTDIV_STATUS_CMD, + WMI_TLV_TAG_STRUCT_PDEV_ANTDIV_STATUS_EVENT, + WMI_TLV_TAG_STRUCT_MNT_FILTER_CMD, + WMI_TLV_TAG_STRUCT_GET_CHIP_POWER_STATS_CMD, + WMI_TLV_TAG_STRUCT_PDEV_CHIP_POWER_STATS_EVENT, + WMI_TLV_TAG_STRUCT_COEX_GET_ANTENNA_ISOLATION_CMD, + WMI_TLV_TAG_STRUCT_COEX_REPORT_ISOLATION_EVENT, + WMI_TLV_TAG_STRUCT_CHAN_CCA_STATS, + WMI_TLV_TAG_STRUCT_PEER_SIGNAL_STATS, + WMI_TLV_TAG_STRUCT_TX_STATS, + WMI_TLV_TAG_STRUCT_PEER_AC_TX_STATS, + WMI_TLV_TAG_STRUCT_RX_STATS, + WMI_TLV_TAG_STRUCT_PEER_AC_RX_STATS, + WMI_TLV_TAG_STRUCT_REPORT_STATS_EVENT, + WMI_TLV_TAG_STRUCT_CHAN_CCA_STATS_THRESH, + WMI_TLV_TAG_STRUCT_PEER_SIGNAL_STATS_THRESH, + WMI_TLV_TAG_STRUCT_TX_STATS_THRESH, + WMI_TLV_TAG_STRUCT_RX_STATS_THRESH, + WMI_TLV_TAG_STRUCT_PDEV_SET_STATS_THRESHOLD_CMD, + WMI_TLV_TAG_STRUCT_REQUEST_WLAN_STATS_CMD, + WMI_TLV_TAG_STRUCT_RX_AGGR_FAILURE_EVENT, + WMI_TLV_TAG_STRUCT_RX_AGGR_FAILURE_INFO, + WMI_TLV_TAG_STRUCT_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMD, + WMI_TLV_TAG_STRUCT_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_BAND_TO_MAC, + WMI_TLV_TAG_STRUCT_TBTT_OFFSET_INFO, + WMI_TLV_TAG_STRUCT_TBTT_OFFSET_EXT_EVENT, + WMI_TLV_TAG_STRUCT_SAR_LIMITS_CMD, + WMI_TLV_TAG_STRUCT_SAR_LIMIT_CMD_ROW, + WMI_TLV_TAG_STRUCT_PDEV_DFS_PHYERR_OFFLOAD_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_DFS_PHYERR_OFFLOAD_DISABLE_CMD, + WMI_TLV_TAG_STRUCT_VDEV_ADFS_CH_CFG_CMD, + WMI_TLV_TAG_STRUCT_VDEV_ADFS_OCAC_ABORT_CMD, + WMI_TLV_TAG_STRUCT_PDEV_DFS_RADAR_DETECTION_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_ADFS_OCAC_COMPLETE_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_DFS_CAC_COMPLETE_EVENT, + WMI_TLV_TAG_STRUCT_VENDOR_OUI, + WMI_TLV_TAG_STRUCT_REQUEST_RCPI_CMD, + WMI_TLV_TAG_STRUCT_UPDATE_RCPI_EVENT, + WMI_TLV_TAG_STRUCT_REQUEST_PEER_STATS_INFO_CMD, + WMI_TLV_TAG_STRUCT_PEER_STATS_INFO, + WMI_TLV_TAG_STRUCT_PEER_STATS_INFO_EVENT, + WMI_TLV_TAG_STRUCT_PKGID_EVENT, + WMI_TLV_TAG_STRUCT_CONNECTED_NLO_RSSI_PARAMS, + WMI_TLV_TAG_STRUCT_SET_CURRENT_COUNTRY_CMD, + WMI_TLV_TAG_STRUCT_REGULATORY_RULE_STRUCT, + WMI_TLV_TAG_STRUCT_REG_CHAN_LIST_CC_EVENT, + WMI_TLV_TAG_STRUCT_11D_SCAN_START_CMD, + WMI_TLV_TAG_STRUCT_11D_SCAN_STOP_CMD, + WMI_TLV_TAG_STRUCT_11D_NEW_COUNTRY_EVENT, + WMI_TLV_TAG_STRUCT_REQUEST_RADIO_CHAN_STATS_CMD, + WMI_TLV_TAG_STRUCT_RADIO_CHAN_STATS, + WMI_TLV_TAG_STRUCT_RADIO_CHAN_STATS_EVENT, + WMI_TLV_TAG_STRUCT_ROAM_PER_CONFIG, + WMI_TLV_TAG_STRUCT_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMD, + WMI_TLV_TAG_STRUCT_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_STATUS_EVENT, + WMI_TLV_TAG_STRUCT_BPF_SET_VDEV_ACTIVE_MODE_CMD, + WMI_TLV_TAG_STRUCT_HW_DATA_FILTER_CMD, + WMI_TLV_TAG_STRUCT_CONNECTED_NLO_BSS_BAND_RSSI_PREF, + WMI_TLV_TAG_STRUCT_PEER_OPER_MODE_CHANGE_EVENT, + WMI_TLV_TAG_STRUCT_CHIP_POWER_SAVE_FAILURE_DETECTED, + WMI_TLV_TAG_STRUCT_PDEV_MULTIPLE_VDEV_RESTART_REQUEST_CMD, + WMI_TLV_TAG_STRUCT_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_UPDATE_PKT_ROUTING_CMD, + WMI_TLV_TAG_STRUCT_PDEV_CHECK_CAL_VERSION_CMD, + WMI_TLV_TAG_STRUCT_PDEV_CHECK_CAL_VERSION_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_SET_DIVERSITY_GAIN_CMD, + WMI_TLV_TAG_STRUCT_MAC_PHY_CHAINMASK_COMBO, + WMI_TLV_TAG_STRUCT_MAC_PHY_CHAINMASK_CAPABILITY, + WMI_TLV_TAG_STRUCT_VDEV_SET_ARP_STATS_CMD, + WMI_TLV_TAG_STRUCT_VDEV_GET_ARP_STATS_CMD, + WMI_TLV_TAG_STRUCT_VDEV_GET_ARP_STATS_EVENT, + WMI_TLV_TAG_STRUCT_IFACE_OFFLOAD_STATS, + WMI_TLV_TAG_STRUCT_REQUEST_STATS_CMD_SUB_STRUCT_PARAM, + WMI_TLV_TAG_STRUCT_RSSI_CTL_EXT, + WMI_TLV_TAG_STRUCT_SINGLE_PHYERR_EXT_RX_HDR, + WMI_TLV_TAG_STRUCT_COEX_BT_ACTIVITY_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_GET_TX_POWER_CMD, + WMI_TLV_TAG_STRUCT_VDEV_TX_POWER_EVENT, + WMI_TLV_TAG_STRUCT_OFFCHAN_DATA_TX_COMPL_EVENT, + WMI_TLV_TAG_STRUCT_OFFCHAN_DATA_TX_SEND_CMD, + WMI_TLV_TAG_STRUCT_TX_SEND_PARAMS, + WMI_TLV_TAG_STRUCT_HE_RATE_SET, + WMI_TLV_TAG_STRUCT_CONGESTION_STATS, + WMI_TLV_TAG_STRUCT_SET_INIT_COUNTRY_CMD, + WMI_TLV_TAG_STRUCT_SCAN_DBS_DUTY_CYCLE, + WMI_TLV_TAG_STRUCT_SCAN_DBS_DUTY_CYCLE_PARAM_TLV, + WMI_TLV_TAG_STRUCT_PDEV_DIV_GET_RSSI_ANTID, + WMI_TLV_TAG_STRUCT_THERM_THROT_CONFIG_REQUEST, + WMI_TLV_TAG_STRUCT_THERM_THROT_LEVEL_CONFIG_INFO, + WMI_TLV_TAG_STRUCT_THERM_THROT_STATS_EVENT, + WMI_TLV_TAG_STRUCT_THERM_THROT_LEVEL_STATS_INFO, + WMI_TLV_TAG_STRUCT_PDEV_DIV_RSSI_ANTID_EVENT, + WMI_TLV_TAG_STRUCT_OEM_DMA_RING_CAPABILITIES, + WMI_TLV_TAG_STRUCT_OEM_DMA_RING_CFG_REQ, + WMI_TLV_TAG_STRUCT_OEM_DMA_RING_CFG_RSP, + WMI_TLV_TAG_STRUCT_OEM_INDIRECT_DATA, + WMI_TLV_TAG_STRUCT_OEM_DMA_BUF_RELEASE, + WMI_TLV_TAG_STRUCT_OEM_DMA_BUF_RELEASE_ENTRY, + WMI_TLV_TAG_STRUCT_PDEV_BSS_CHAN_INFO_REQUEST, + WMI_TLV_TAG_STRUCT_PDEV_BSS_CHAN_INFO_EVENT, + WMI_TLV_TAG_STRUCT_ROAM_LCA_DISALLOW_CONFIG_TLV_PARAM, + WMI_TLV_TAG_STRUCT_VDEV_LIMIT_OFFCHAN_CMD, + WMI_TLV_TAG_STRUCT_ROAM_RSSI_REJECTION_OCE_CONFIG_PARAM, + WMI_TLV_TAG_STRUCT_UNIT_TEST_EVENT, + WMI_TLV_TAG_STRUCT_ROAM_FILS_OFFLOAD_TLV_PARAM, + WMI_TLV_TAG_STRUCT_PDEV_UPDATE_PMK_CACHE_CMD, + WMI_TLV_TAG_STRUCT_PMK_CACHE, + WMI_TLV_TAG_STRUCT_PDEV_UPDATE_FILS_HLP_PKT_CMD, + WMI_TLV_TAG_STRUCT_ROAM_FILS_SYNCH_TLV_PARAM, + WMI_TLV_TAG_STRUCT_GTK_OFFLOAD_EXTENDED_TLV_PARAM, + WMI_TLV_TAG_STRUCT_ROAM_BG_SCAN_ROAMING_PARAM, + WMI_TLV_TAG_STRUCT_OIC_PING_OFFLOAD_PARAMS_CMD, + WMI_TLV_TAG_STRUCT_OIC_PING_OFFLOAD_SET_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_OIC_PING_HANDOFF_EVENT, + WMI_TLV_TAG_STRUCT_DHCP_LEASE_RENEW_OFFLOAD_CMD, + WMI_TLV_TAG_STRUCT_DHCP_LEASE_RENEW_EVENT, + WMI_TLV_TAG_STRUCT_BTM_CONFIG, + WMI_TLV_TAG_STRUCT_DEBUG_MESG_FW_DATA_STALL_PARAM, + WMI_TLV_TAG_STRUCT_WLM_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_PDEV_UPDATE_CTLTABLE_REQUEST, + WMI_TLV_TAG_STRUCT_PDEV_UPDATE_CTLTABLE_EVENT, + WMI_TLV_TAG_STRUCT_ROAM_CND_SCORING_PARAM, + WMI_TLV_TAG_STRUCT_PDEV_CONFIG_VENDOR_OUI_ACTION, + WMI_TLV_TAG_STRUCT_VENDOR_OUI_EXT, + WMI_TLV_TAG_STRUCT_ROAM_SYNCH_FRAME_EVENT, + WMI_TLV_TAG_STRUCT_FD_SEND_FROM_HOST_CMD, + WMI_TLV_TAG_STRUCT_ENABLE_FILS_CMD, + WMI_TLV_TAG_STRUCT_HOST_SWFDA_EVENT, WMI_TLV_TAG_MAX }; @@ -1068,16 +1338,74 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_WLAN_STATS_REPORT, WMI_TLV_SERVICE_TX_MSDU_ID_NEW_PARTITION_SUPPORT, WMI_TLV_SERVICE_DFS_PHYERR_OFFLOAD, + WMI_TLV_SERVICE_RCPI_SUPPORT, + WMI_TLV_SERVICE_FW_MEM_DUMP_SUPPORT, + WMI_TLV_SERVICE_PEER_STATS_INFO, + WMI_TLV_SERVICE_REGULATORY_DB, + WMI_TLV_SERVICE_11D_OFFLOAD, + WMI_TLV_SERVICE_HW_DATA_FILTERING, + WMI_TLV_SERVICE_MULTIPLE_VDEV_RESTART, + WMI_TLV_SERVICE_PKT_ROUTING, + WMI_TLV_SERVICE_CHECK_CAL_VERSION, + WMI_TLV_SERVICE_OFFCHAN_TX_WMI, + WMI_TLV_SERVICE_8SS_TX_BFEE, + WMI_TLV_SERVICE_EXTENDED_NSS_SUPPORT, + WMI_TLV_SERVICE_ACK_TIMEOUT, + WMI_TLV_SERVICE_PDEV_BSS_CHANNEL_INFO_64, + WMI_TLV_MAX_SERVICE = 128, + +/* NOTE: + * The above service flags are delivered in the wmi_service_bitmap field + * of the WMI_TLV_SERVICE_READY_EVENT message. + * The below service flags are delivered in a WMI_TLV_SERVICE_AVAILABLE_EVENT + * message rather than in the WMI_TLV_SERVICE_READY_EVENT message's + * wmi_service_bitmap field. + * The WMI_TLV_SERVICE_AVAILABLE_EVENT message immediately precedes the + * WMI_TLV_SERVICE_READY_EVENT message. + */ + + WMI_TLV_SERVICE_CHAN_LOAD_INFO = 128, + WMI_TLV_SERVICE_TX_PPDU_INFO_STATS_SUPPORT, + WMI_TLV_SERVICE_VDEV_LIMIT_OFFCHAN_SUPPORT, + WMI_TLV_SERVICE_FILS_SUPPORT, + WMI_TLV_SERVICE_WLAN_OIC_PING_OFFLOAD, + WMI_TLV_SERVICE_WLAN_DHCP_RENEW, + WMI_TLV_SERVICE_MAWC_SUPPORT, + WMI_TLV_SERVICE_VDEV_LATENCY_CONFIG, + WMI_TLV_SERVICE_PDEV_UPDATE_CTLTABLE_SUPPORT, + WMI_TLV_SERVICE_PKTLOG_SUPPORT_OVER_HTT, + WMI_TLV_SERVICE_VDEV_MULTI_GROUP_KEY_SUPPORT, + WMI_TLV_SERVICE_SCAN_PHYMODE_SUPPORT, + WMI_TLV_SERVICE_THERM_THROT, + WMI_TLV_SERVICE_BCN_OFFLOAD_START_STOP_SUPPORT, + WMI_TLV_SERVICE_WOW_WAKEUP_BY_TIMER_PATTERN, + WMI_TLV_SERVICE_PEER_MAP_UNMAP_V2_SUPPORT = 143, + WMI_TLV_SERVICE_OFFCHAN_DATA_TID_SUPPORT = 144, + WMI_TLV_SERVICE_RX_PROMISC_ENABLE_SUPPORT = 145, + WMI_TLV_SERVICE_SUPPORT_DIRECT_DMA = 146, + WMI_TLV_SERVICE_AP_OBSS_DETECTION_OFFLOAD = 147, + WMI_TLV_SERVICE_11K_NEIGHBOUR_REPORT_SUPPORT = 148, + WMI_TLV_SERVICE_LISTEN_INTERVAL_OFFLOAD_SUPPORT = 149, + WMI_TLV_SERVICE_BSS_COLOR_OFFLOAD = 150, + WMI_TLV_SERVICE_RUNTIME_DPD_RECAL = 151, + WMI_TLV_SERVICE_STA_TWT = 152, + WMI_TLV_SERVICE_AP_TWT = 153, + WMI_TLV_SERVICE_GMAC_OFFLOAD_SUPPORT = 154, + WMI_TLV_SERVICE_SPOOF_MAC_SUPPORT = 155, + + WMI_TLV_MAX_EXT_SERVICE = 256, }; -#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \ - ((svc_id) < (len) && \ - __le32_to_cpu((wmi_svc_bmap)[(svc_id) / (sizeof(u32))]) & \ - BIT((svc_id) % (sizeof(u32)))) +#define WMI_TLV_EXT_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \ + ((svc_id) < (WMI_TLV_MAX_EXT_SERVICE) && \ + (svc_id) >= (len) && \ + __le32_to_cpu((wmi_svc_bmap)[((svc_id) - (len)) / 32]) & \ + BIT(((((svc_id) - (len)) % 32) & 0x1f))) #define SVCMAP(x, y, len) \ do { \ - if (WMI_SERVICE_IS_ENABLED((in), (x), (len))) \ + if ((WMI_SERVICE_IS_ENABLED((in), (x), (len))) || \ + (WMI_TLV_EXT_SERVICE_IS_ENABLED((in), (x), (len)))) \ __set_bit(y, out); \ } while (0) @@ -1228,6 +1556,14 @@ wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len) WMI_SERVICE_MGMT_TX_WMI, len); } +static inline void +wmi_tlv_svc_map_ext(const __le32 *in, unsigned long *out, size_t len) +{ + SVCMAP(WMI_TLV_SERVICE_SPOOF_MAC_SUPPORT, + WMI_SERVICE_SPOOF_MAC_SUPPORT, + WMI_TLV_MAX_SERVICE); +} + #undef SVCMAP struct wmi_tlv { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 4d73f3664878..d56c00aaa631 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4693,7 +4693,6 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work) return; } - memset(&ar->wmi.svc_map, 0, sizeof(ar->wmi.svc_map)); ath10k_wmi_map_svc(ar, arg.service_map, ar->wmi.svc_map, arg.service_map_len); @@ -4903,6 +4902,21 @@ int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb) return 0; } +void ath10k_wmi_event_service_available(struct ath10k *ar, struct sk_buff *skb) +{ + int ret; + struct wmi_svc_avail_ev_arg arg = {}; + + ret = ath10k_wmi_pull_svc_avail(ar, skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse servive available event: %d\n", + ret); + } + + ath10k_wmi_map_svc_ext(ar, arg.service_map_ext, ar->wmi.svc_map, + __le32_to_cpu(arg.service_map_ext_len)); +} + static int ath10k_wmi_event_temperature(struct ath10k *ar, struct sk_buff *skb) { const struct wmi_pdev_temperature_event *ev; @@ -5099,6 +5113,9 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_event_ready(ar, skb); ath10k_wmi_queue_set_coverage_class_work(ar); break; + case WMI_SERVICE_AVAILABLE_EVENTID: + ath10k_wmi_event_service_available(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; @@ -5507,6 +5524,8 @@ int ath10k_wmi_connect(struct ath10k *ar) struct ath10k_htc_svc_conn_req conn_req; struct ath10k_htc_svc_conn_resp conn_resp; + memset(&ar->wmi.svc_map, 0, sizeof(ar->wmi.svc_map)); + memset(&conn_req, 0, sizeof(conn_req)); memset(&conn_resp, 0, sizeof(conn_resp)); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index bda6e7c786cf..e3872efc37f0 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -197,6 +197,11 @@ enum wmi_service { WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, WMI_SERVICE_MGMT_TX_WMI, WMI_SERVICE_TDLS_WIDER_BANDWIDTH, + WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, + WMI_SERVICE_HOST_DFS_CHECK_SUPPORT, + WMI_SERVICE_TPC_STATS_FINAL, + WMI_SERVICE_RESET_CHIP, + WMI_SERVICE_SPOOF_MAC_SUPPORT, /* keep last */ WMI_SERVICE_MAX, @@ -1167,6 +1172,7 @@ enum wmi_cmd_id { enum wmi_event_id { WMI_SERVICE_READY_EVENTID = 0x1, WMI_READY_EVENTID, + WMI_SERVICE_AVAILABLE_EVENTID, /* Scan specific events */ WMI_SCAN_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_SCAN), @@ -6545,6 +6551,11 @@ struct wmi_svc_rdy_ev_arg { const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS]; }; +struct wmi_svc_avail_ev_arg { + __le32 service_map_ext_len; + const __le32 *service_map_ext; +}; + struct wmi_rdy_ev_arg { __le32 sw_version; __le32 abi_version; @@ -6964,6 +6975,7 @@ void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb); int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_service_available(struct ath10k *ar, struct sk_buff *skb); int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, const void *phyerr_buf, int left_len, struct wmi_phyerr_ev_arg *arg); void ath10k_wmi_main_op_fw_stats_fill(struct ath10k *ar, From 9f457a6c2890dd2b4357df7adc1813940115b5b3 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Wed, 20 Jun 2018 18:53:23 +0800 Subject: [PATCH 076/192] UPSTREAM: ath10k: support MAC address randomization in scan The ath10k reports the random_mac_addr capability to upper layer based on the service bit firmware reported. Driver sets the spoofed flag in scan_ctrl_flag to firmware if upper layer has enabled this feature in scan request. Test with QCA6174 hw3.0 and firmware-6.bin_WLAN.RM.4.4.1-00102-QCARMSWP-1, but QCA9377 is also affected. Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Git-commit: 60e1d0fb290197fe505dff6e4e3b7e4d258dbf60 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I8825f706045821d4e1533afa34bd319abcff49f6 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/mac.c | 17 +++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-ops.h | 22 ++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 25 +++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.h | 11 ++++++++++ drivers/net/wireless/ath/ath10k/wmi.c | 5 +++++ drivers/net/wireless/ath/ath10k/wmi.h | 9 ++++++++ 6 files changed, 89 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b7ebe21b7f5d..a9d90bc910f6 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -5649,6 +5649,12 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, arg.scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; } + if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + arg.scan_ctrl_flags |= WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ; + ether_addr_copy(arg.mac_addr.addr, req->mac_addr); + ether_addr_copy(arg.mac_mask.addr, req->mac_addr_mask); + } + if (req->n_channels) { arg.n_channels = req->n_channels; for (i = 0; i < arg.n_channels; i++) @@ -8418,6 +8424,17 @@ int ath10k_mac_register(struct ath10k *ar) goto err_dfs_detector_exit; } + if (test_bit(WMI_SERVICE_SPOOF_MAC_SUPPORT, ar->wmi.svc_map)) { + ret = ath10k_wmi_scan_prob_req_oui(ar, ar->mac_addr); + if (ret) { + ath10k_err(ar, "failed to set prob req oui: %i\n", ret); + goto err_dfs_detector_exit; + } + + ar->hw->wiphy->features |= + NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + } + ar->hw->wiphy->cipher_suites = cipher_suites; /* QCA988x and QCA6174 family chips do not support CCMP-256, GCMP-128 diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 86d083de63fc..45d9affb635e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -118,6 +118,8 @@ struct wmi_ops { u32 value); struct sk_buff *(*gen_scan_chan_list)(struct ath10k *ar, const struct wmi_scan_chan_list_arg *arg); + struct sk_buff *(*gen_scan_prob_req_oui)(struct ath10k *ar, + u32 prob_req_oui); struct sk_buff *(*gen_beacon_dma)(struct ath10k *ar, u32 vdev_id, const void *bcn, size_t bcn_len, u32 bcn_paddr, bool dtim_zero, @@ -891,6 +893,26 @@ ath10k_wmi_scan_chan_list(struct ath10k *ar, return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid); } +static inline int +ath10k_wmi_scan_prob_req_oui(struct ath10k *ar, const u8 mac_addr[ETH_ALEN]) +{ + struct sk_buff *skb; + u32 prob_req_oui; + + prob_req_oui = (((u32)mac_addr[0]) << 16) | + (((u32)mac_addr[1]) << 8) | mac_addr[2]; + + if (!ar->wmi.ops->gen_scan_prob_req_oui) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_scan_prob_req_oui(ar, prob_req_oui); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->scan_prob_req_oui_cmdid); +} + static inline int ath10k_wmi_peer_assoc(struct ath10k *ar, const struct wmi_peer_assoc_complete_arg *arg) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index f53cdb893e91..378054d3f3d7 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1578,6 +1578,8 @@ ath10k_wmi_tlv_op_gen_start_scan(struct ath10k *ar, cmd->num_bssids = __cpu_to_le32(arg->n_bssids); cmd->ie_len = __cpu_to_le32(arg->ie_len); cmd->num_probes = __cpu_to_le32(3); + ether_addr_copy(cmd->mac_addr.addr, arg->mac_addr.addr); + ether_addr_copy(cmd->mac_mask.addr, arg->mac_mask.addr); /* FIXME: There are some scan flag inconsistencies across firmwares, * e.g. WMI-TLV inverts the logic behind the following flag. @@ -2424,6 +2426,27 @@ ath10k_wmi_tlv_op_gen_scan_chan_list(struct ath10k *ar, return skb; } +static struct sk_buff * +ath10k_wmi_tlv_op_gen_scan_prob_req_oui(struct ath10k *ar, u32 prob_req_oui) +{ + struct wmi_scan_prob_req_oui_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_SCAN_PROB_REQ_OUI_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->prob_req_oui = __cpu_to_le32(prob_req_oui); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv scan prob req oui\n"); + return skb; +} + static struct sk_buff * ath10k_wmi_tlv_op_gen_beacon_dma(struct ath10k *ar, u32 vdev_id, const void *bcn, size_t bcn_len, @@ -3371,6 +3394,7 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = { .stop_scan_cmdid = WMI_TLV_STOP_SCAN_CMDID, .scan_chan_list_cmdid = WMI_TLV_SCAN_CHAN_LIST_CMDID, .scan_sch_prio_tbl_cmdid = WMI_TLV_SCAN_SCH_PRIO_TBL_CMDID, + .scan_prob_req_oui_cmdid = WMI_TLV_SCAN_PROB_REQ_OUI_CMDID, .pdev_set_regdomain_cmdid = WMI_TLV_PDEV_SET_REGDOMAIN_CMDID, .pdev_set_channel_cmdid = WMI_TLV_PDEV_SET_CHANNEL_CMDID, .pdev_set_param_cmdid = WMI_TLV_PDEV_SET_PARAM_CMDID, @@ -3739,6 +3763,7 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_set_sta_ps = ath10k_wmi_tlv_op_gen_set_sta_ps, .gen_set_ap_ps = ath10k_wmi_tlv_op_gen_set_ap_ps, .gen_scan_chan_list = ath10k_wmi_tlv_op_gen_scan_chan_list, + .gen_scan_prob_req_oui = ath10k_wmi_tlv_op_gen_scan_prob_req_oui, .gen_beacon_dma = ath10k_wmi_tlv_op_gen_beacon_dma, .gen_pdev_set_wmm = ath10k_wmi_tlv_op_gen_pdev_set_wmm, .gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats, diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 299c32e2dd14..eac0a5364a57 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1700,6 +1700,15 @@ struct wmi_tlv_scan_chan_list_cmd { __le32 num_scan_chans; } __packed; +struct wmi_scan_prob_req_oui_cmd { +/* OUI to be used in Probe Request frame when random MAC address is + * requested part of scan parameters. This is applied to both FW internal + * scans and host initiated scans. Host can request for random MAC address + * with WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ flag. + */ + __le32 prob_req_oui; +} __packed; + struct wmi_tlv_start_scan_cmd { struct wmi_start_scan_common common; __le32 burst_duration_ms; @@ -1708,6 +1717,8 @@ struct wmi_tlv_start_scan_cmd { __le32 num_ssids; __le32 ie_len; __le32 num_probes; + struct wmi_mac_addr mac_addr; + struct wmi_mac_addr mac_mask; } __packed; struct wmi_tlv_vdev_start_cmd { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index d56c00aaa631..2674f3a89c24 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -40,6 +40,7 @@ static struct wmi_cmd_map wmi_cmd_map = { .stop_scan_cmdid = WMI_STOP_SCAN_CMDID, .scan_chan_list_cmdid = WMI_SCAN_CHAN_LIST_CMDID, .scan_sch_prio_tbl_cmdid = WMI_SCAN_SCH_PRIO_TBL_CMDID, + .scan_prob_req_oui_cmdid = WMI_CMD_UNSUPPORTED, .pdev_set_regdomain_cmdid = WMI_PDEV_SET_REGDOMAIN_CMDID, .pdev_set_channel_cmdid = WMI_PDEV_SET_CHANNEL_CMDID, .pdev_set_param_cmdid = WMI_PDEV_SET_PARAM_CMDID, @@ -204,6 +205,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = { .stop_scan_cmdid = WMI_10X_STOP_SCAN_CMDID, .scan_chan_list_cmdid = WMI_10X_SCAN_CHAN_LIST_CMDID, .scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED, + .scan_prob_req_oui_cmdid = WMI_CMD_UNSUPPORTED, .pdev_set_regdomain_cmdid = WMI_10X_PDEV_SET_REGDOMAIN_CMDID, .pdev_set_channel_cmdid = WMI_10X_PDEV_SET_CHANNEL_CMDID, .pdev_set_param_cmdid = WMI_10X_PDEV_SET_PARAM_CMDID, @@ -370,6 +372,7 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = { .stop_scan_cmdid = WMI_10_2_STOP_SCAN_CMDID, .scan_chan_list_cmdid = WMI_10_2_SCAN_CHAN_LIST_CMDID, .scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED, + .scan_prob_req_oui_cmdid = WMI_CMD_UNSUPPORTED, .pdev_set_regdomain_cmdid = WMI_10_2_PDEV_SET_REGDOMAIN_CMDID, .pdev_set_channel_cmdid = WMI_10_2_PDEV_SET_CHANNEL_CMDID, .pdev_set_param_cmdid = WMI_10_2_PDEV_SET_PARAM_CMDID, @@ -536,6 +539,7 @@ static struct wmi_cmd_map wmi_10_4_cmd_map = { .stop_scan_cmdid = WMI_10_4_STOP_SCAN_CMDID, .scan_chan_list_cmdid = WMI_10_4_SCAN_CHAN_LIST_CMDID, .scan_sch_prio_tbl_cmdid = WMI_10_4_SCAN_SCH_PRIO_TBL_CMDID, + .scan_prob_req_oui_cmdid = WMI_CMD_UNSUPPORTED, .pdev_set_regdomain_cmdid = WMI_10_4_PDEV_SET_REGDOMAIN_CMDID, .pdev_set_channel_cmdid = WMI_10_4_PDEV_SET_CHANNEL_CMDID, .pdev_set_param_cmdid = WMI_10_4_PDEV_SET_PARAM_CMDID, @@ -1333,6 +1337,7 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = { .stop_scan_cmdid = WMI_10_2_STOP_SCAN_CMDID, .scan_chan_list_cmdid = WMI_10_2_SCAN_CHAN_LIST_CMDID, .scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED, + .scan_prob_req_oui_cmdid = WMI_CMD_UNSUPPORTED, .pdev_set_regdomain_cmdid = WMI_10_2_PDEV_SET_REGDOMAIN_CMDID, .pdev_set_channel_cmdid = WMI_10_2_PDEV_SET_CHANNEL_CMDID, .pdev_set_param_cmdid = WMI_10_2_PDEV_SET_PARAM_CMDID, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index e3872efc37f0..62d1898cdcff 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -772,6 +772,7 @@ struct wmi_cmd_map { u32 stop_scan_cmdid; u32 scan_chan_list_cmdid; u32 scan_sch_prio_tbl_cmdid; + u32 scan_prob_req_oui_cmdid; u32 pdev_set_regdomain_cmdid; u32 pdev_set_channel_cmdid; u32 pdev_set_param_cmdid; @@ -3149,6 +3150,8 @@ struct wmi_start_scan_arg { u16 channels[64]; struct wmi_ssid_arg ssids[WLAN_SCAN_PARAMS_MAX_SSID]; struct wmi_bssid_arg bssids[WLAN_SCAN_PARAMS_MAX_BSSID]; + struct wmi_mac_addr mac_addr; + struct wmi_mac_addr mac_mask; }; /* scan control flags */ @@ -3172,6 +3175,12 @@ struct wmi_start_scan_arg { */ #define WMI_SCAN_CONTINUE_ON_ERROR 0x80 +/* Use random MAC address for TA for Probe Request frame and add + * OUI specified by WMI_SCAN_PROB_REQ_OUI_CMDID to the Probe Request frame. + * if OUI is not set by WMI_SCAN_PROB_REQ_OUI_CMDID then the flag is ignored. + */ +#define WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ 0x1000 + /* WMI_SCAN_CLASS_MASK must be the same value as IEEE80211_SCAN_CLASS_MASK */ #define WMI_SCAN_CLASS_MASK 0xFF000000 From 1e1e0efe8d30b0e04ed0f36081d79656f690c806 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 31 May 2018 02:33:14 +0000 Subject: [PATCH 077/192] UPSTREAM: ath10k: make some functions static Fixes the following sparse warnings: drivers/net/wireless/ath/ath10k/snoc.c:823:5: warning: symbol 'ath10k_snoc_get_ce_id_from_irq' was not declared. Should it be static? drivers/net/wireless/ath/ath10k/snoc.c:871:6: warning: symbol 'ath10k_snoc_init_napi' was not declared. Should it be static? Signed-off-by: Wei Yongjun Signed-off-by: Kalle Valo Git-commit: 6ee0e175a33deea08354bc8a91b743f0ec8c8a0a Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: Ib4fa6c5c55b979b83b3ade40cd5c318e3bb5f96c Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/snoc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 2e490ff124f1..b34506cce43e 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -817,7 +817,7 @@ static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { .write32 = ath10k_snoc_write32, }; -int ath10k_snoc_get_ce_id_from_irq(struct ath10k *ar, int irq) +static int ath10k_snoc_get_ce_id_from_irq(struct ath10k *ar, int irq) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); int i; @@ -865,7 +865,7 @@ static int ath10k_snoc_napi_poll(struct napi_struct *ctx, int budget) return done; } -void ath10k_snoc_init_napi(struct ath10k *ar) +static void ath10k_snoc_init_napi(struct ath10k *ar) { netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_snoc_napi_poll, ATH10K_NAPI_BUDGET); From 0b7c3b14e99c1c94282d3fe4b2ae92912e4224eb Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 11 Jun 2018 12:35:40 -0700 Subject: [PATCH 078/192] UPSTREAM: ath10k: snoc: use module_platform_driver() macro ath10k_snoc_init()/ath10k_snoc_exit() don't add much value; module_platform_driver() can remove the boilerplate. Signed-off-by: Brian Norris Signed-off-by: Kalle Valo Git-commit: 0644fef97451908ef1048043b0a60d1324d8a522 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: If21c61b26ae6a2029ce7cac9ad5b6cb42b373351 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/snoc.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index b34506cce43e..72039a34ecaa 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -1386,25 +1386,7 @@ static struct platform_driver ath10k_snoc_driver = { .of_match_table = ath10k_snoc_dt_match, }, }; - -static int __init ath10k_snoc_init(void) -{ - int ret; - - ret = platform_driver_register(&ath10k_snoc_driver); - if (ret) - pr_err("failed to register ath10k snoc driver: %d\n", - ret); - - return ret; -} -module_init(ath10k_snoc_init); - -static void __exit ath10k_snoc_exit(void) -{ - platform_driver_unregister(&ath10k_snoc_driver); -} -module_exit(ath10k_snoc_exit); +module_platform_driver(ath10k_snoc_driver); MODULE_AUTHOR("Qualcomm"); MODULE_LICENSE("Dual BSD/GPL"); From 516ecfd50d7c5d9ba3e8e50c764c9a7b7299a2eb Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 11 Jun 2018 14:09:43 -0700 Subject: [PATCH 079/192] UPSTREAM: ath10k: snoc: use correct bus-specific pointer in RX retry We're 'ath10k_snoc', not 'ath10k_pci'. This probably means we're accessing junk data in ath10k_snoc_rx_replenish_retry(), unless 'ath10k_snoc' and 'ath10k_pci' happen to have very similar struct layouts. Noticed by inspection. Fixes: d915105231ca ("ath10k: add hif rx methods for wcn3990") Signed-off-by: Brian Norris Signed-off-by: Kalle Valo Git-commit: 426a0f0b5a2fe1df3496ba299ee3521159dba302 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I7358366b2c8442dfb02c6d8851842cd51d2558e3 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/snoc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 72039a34ecaa..aa800aed3f63 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -449,7 +449,7 @@ static void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state) static void ath10k_snoc_rx_replenish_retry(struct timer_list *t) { - struct ath10k_pci *ar_snoc = from_timer(ar_snoc, t, rx_post_retry); + struct ath10k_snoc *ar_snoc = from_timer(ar_snoc, t, rx_post_retry); struct ath10k *ar = ar_snoc->ar; ath10k_snoc_rx_post(ar); From 66d57517f493c7e1c0f773e787600de38d07f555 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 11 Jun 2018 14:09:44 -0700 Subject: [PATCH 080/192] UPSTREAM: ath10k: snoc: stop including pci.h It's easier to violate abstractions and introduce bugs when snoc.h is including pci.h. Let's not do that. I'm not extremely familiar with this driver yet, but several of the shared PCI/SNOC bits seem to be related to the Copy Engine, so move them to ce.h. Signed-off-by: Brian Norris Signed-off-by: Kalle Valo Git-commit: 8ac5fe8e3d110eaff47dd2becf98b08762c84c75 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I48729facdb84f0c194da37c70c5810004e88ee80 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/ce.h | 42 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/pci.h | 42 -------------------------- drivers/net/wireless/ath/ath10k/snoc.h | 1 - 3 files changed, 42 insertions(+), 43 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 0e70a07230d6..ed96dbfe8894 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -368,4 +368,46 @@ static inline u32 ath10k_ce_interrupt_summary(struct ath10k *ar) return CE_INTERRUPT_SUMMARY; } +/* Host software's Copy Engine configuration. */ +#define CE_ATTR_FLAGS 0 + +/* + * Configuration information for a Copy Engine pipe. + * Passed from Host to Target during startup (one per CE). + * + * NOTE: Structure is shared between Host software and Target firmware! + */ +struct ce_pipe_config { + __le32 pipenum; + __le32 pipedir; + __le32 nentries; + __le32 nbytes_max; + __le32 flags; + __le32 reserved; +}; + +/* + * Directions for interconnect pipe configuration. + * These definitions may be used during configuration and are shared + * between Host and Target. + * + * Pipe Directions are relative to the Host, so PIPEDIR_IN means + * "coming IN over air through Target to Host" as with a WiFi Rx operation. + * Conversely, PIPEDIR_OUT means "going OUT from Host through Target over air" + * as with a WiFi Tx operation. This is somewhat awkward for the "middle-man" + * Target since things that are "PIPEDIR_OUT" are coming IN to the Target + * over the interconnect. + */ +#define PIPEDIR_NONE 0 +#define PIPEDIR_IN 1 /* Target-->Host, WiFi Rx direction */ +#define PIPEDIR_OUT 2 /* Host->Target, WiFi Tx direction */ +#define PIPEDIR_INOUT 3 /* bidirectional */ + +/* Establish a mapping between a service/direction and a pipe. */ +struct service_to_pipe { + __le32 service_id; + __le32 pipedir; + __le32 pipenum; +}; + #endif /* _CE_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 652bb0502680..7597d792b564 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -86,48 +86,6 @@ struct pcie_state { /* PCIE_CONFIG_FLAG definitions */ #define PCIE_CONFIG_FLAG_ENABLE_L1 0x0000001 -/* Host software's Copy Engine configuration. */ -#define CE_ATTR_FLAGS 0 - -/* - * Configuration information for a Copy Engine pipe. - * Passed from Host to Target during startup (one per CE). - * - * NOTE: Structure is shared between Host software and Target firmware! - */ -struct ce_pipe_config { - __le32 pipenum; - __le32 pipedir; - __le32 nentries; - __le32 nbytes_max; - __le32 flags; - __le32 reserved; -}; - -/* - * Directions for interconnect pipe configuration. - * These definitions may be used during configuration and are shared - * between Host and Target. - * - * Pipe Directions are relative to the Host, so PIPEDIR_IN means - * "coming IN over air through Target to Host" as with a WiFi Rx operation. - * Conversely, PIPEDIR_OUT means "going OUT from Host through Target over air" - * as with a WiFi Tx operation. This is somewhat awkward for the "middle-man" - * Target since things that are "PIPEDIR_OUT" are coming IN to the Target - * over the interconnect. - */ -#define PIPEDIR_NONE 0 -#define PIPEDIR_IN 1 /* Target-->Host, WiFi Rx direction */ -#define PIPEDIR_OUT 2 /* Host->Target, WiFi Tx direction */ -#define PIPEDIR_INOUT 3 /* bidirectional */ - -/* Establish a mapping between a service/direction and a pipe. */ -struct service_to_pipe { - __le32 service_id; - __le32 pipedir; - __le32 pipenum; -}; - /* Per-pipe state. */ struct ath10k_pci_pipe { /* Handle of underlying Copy Engine */ diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index 05dc98f46ccd..f9e530189d48 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -19,7 +19,6 @@ #include "hw.h" #include "ce.h" -#include "pci.h" struct ath10k_snoc_drv_priv { enum ath10k_hw_rev hw_rev; From b7dd47413bc1424c9dab5663e9305208dbf2acd8 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 11 Jun 2018 14:09:45 -0700 Subject: [PATCH 081/192] UPSTREAM: ath10k: snoc: drop unused WCN3990_CE_ATTR_FLAGS We started using a common CE_ATTR_FLAGS definition, so drop this one. Signed-off-by: Brian Norris Signed-off-by: Kalle Valo Git-commit: 13e6cc0bd4effa9fc4b03fb9b1baf0e26e2e217d Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I4dda82e7420244193e6a646d5475fcc226939e22 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/snoc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index aa800aed3f63..8e036cc16537 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -26,7 +26,7 @@ #include #include #include -#define WCN3990_CE_ATTR_FLAGS 0 + #define ATH10K_SNOC_RX_POST_RETRY_MS 50 #define CE_POLL_PIPE 4 From 3258712639fa22d088c29151cca2c87a4ca3a15f Mon Sep 17 00:00:00 2001 From: Vasantha Balla Date: Thu, 2 Jul 2020 15:56:00 +0530 Subject: [PATCH 082/192] msm: vidc: fix deadlock between queue and flush buffer handling qbuf ioctl acquired bufq[port].lock in one thread and flush call acquired registeredbufs.lock in another thread. So thread-1 is waiting for registeredbufs.lock & thread-2 is waiting for bufq[port].lock i.e leading to deadlock. So added change to avoid above mentioned deadlock. Change-Id: Ie21984fdb562ca7a09f801f036f3a78429ceab94 Signed-off-by: Govindaraj Rajagopal Signed-off-by: Vasantha Balla --- drivers/media/platform/msm/vidc/msm_vidc.c | 24 ++++----- .../media/platform/msm/vidc/msm_vidc_common.c | 53 +++++++++++++------ .../platform/msm/vidc/msm_vidc_internal.h | 4 +- .../media/platform/msm/vidc/vidc_hfi_api.h | 7 ++- 4 files changed, 52 insertions(+), 36 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 199bca664eb6..bc2d87d6ae4b 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -521,6 +521,15 @@ int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b) return -EINVAL; } + q = msm_comm_get_vb2q(inst, b->type); + if (!q) { + dprintk(VIDC_ERR, + "Failed to find buffer queue for type = %d\n", b->type); + return -EINVAL; + } + mutex_lock(&q->lock); + + for (i = 0; i < b->length; i++) { b->m.planes[i].m.fd = b->m.planes[i].reserved[0]; b->m.planes[i].data_offset = b->m.planes[i].reserved[1]; @@ -545,19 +554,11 @@ int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b) tag_data.output_tag = b->m.planes[0].reserved[6]; msm_comm_store_tags(inst, &tag_data); - q = msm_comm_get_vb2q(inst, b->type); - if (!q) { - dprintk(VIDC_ERR, - "Failed to find buffer queue for type = %d\n", b->type); - return -EINVAL; - } - - mutex_lock(&q->lock); rc = vb2_qbuf(&q->vb2_bufq, b); - mutex_unlock(&q->lock); if (rc) dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc); + mutex_unlock(&q->lock); return rc; } EXPORT_SYMBOL(msm_vidc_qbuf); @@ -1873,7 +1874,6 @@ void *msm_vidc_open(int core_id, int session_type) mutex_init(&inst->bufq[CAPTURE_PORT].lock); mutex_init(&inst->bufq[OUTPUT_PORT].lock); mutex_init(&inst->lock); - mutex_init(&inst->flush_lock); INIT_MSM_VIDC_LIST(&inst->scratchbufs); INIT_MSM_VIDC_LIST(&inst->freqs); @@ -1998,7 +1998,6 @@ void *msm_vidc_open(int core_id, int session_type) mutex_destroy(&inst->bufq[CAPTURE_PORT].lock); mutex_destroy(&inst->bufq[OUTPUT_PORT].lock); mutex_destroy(&inst->lock); - mutex_destroy(&inst->flush_lock); DEINIT_MSM_VIDC_LIST(&inst->scratchbufs); DEINIT_MSM_VIDC_LIST(&inst->persistbufs); @@ -2152,7 +2151,6 @@ int msm_vidc_destroy(struct msm_vidc_inst *inst) mutex_destroy(&inst->bufq[CAPTURE_PORT].lock); mutex_destroy(&inst->bufq[OUTPUT_PORT].lock); mutex_destroy(&inst->lock); - mutex_destroy(&inst->flush_lock); msm_vidc_debugfs_deinit_inst(inst); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 96e0442aa26e..15f65e998eda 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2079,7 +2079,11 @@ static void handle_session_flush(enum hal_command_response cmd, void *data) return; } - mutex_lock(&inst->flush_lock); + if (response->data.flush_type & HAL_FLUSH_INPUT) + mutex_lock(&inst->bufq[OUTPUT_PORT].lock); + if (response->data.flush_type & HAL_FLUSH_OUTPUT) + mutex_lock(&inst->bufq[CAPTURE_PORT].lock); + if (msm_comm_get_stream_output_mode(inst) == HAL_VIDEO_DECODER_SECONDARY) { @@ -2122,7 +2126,11 @@ static void handle_session_flush(enum hal_command_response cmd, void *data) v4l2_event_queue_fh(&inst->event_handler, &flush_event); exit: - mutex_unlock(&inst->flush_lock); + if (response->data.flush_type & HAL_FLUSH_OUTPUT) + mutex_unlock(&inst->bufq[CAPTURE_PORT].lock); + if (response->data.flush_type & HAL_FLUSH_INPUT) + mutex_unlock(&inst->bufq[OUTPUT_PORT].lock); + put_inst(inst); } @@ -2331,7 +2339,7 @@ struct vb2_buffer *msm_comm_get_vb_using_vidc_buffer( return NULL; } - mutex_lock(&inst->bufq[port].lock); + WARN_ON(!mutex_is_locked(&inst->bufq[port].lock)); found = false; q = &inst->bufq[port].vb2_bufq; if (!q->streaming) { @@ -2347,7 +2355,6 @@ struct vb2_buffer *msm_comm_get_vb_using_vidc_buffer( } } unlock: - mutex_unlock(&inst->bufq[port].lock); if (!found) { print_vidc_buffer(VIDC_ERR, "vb2 not found for", inst, mbuf); return NULL; @@ -2362,6 +2369,7 @@ int msm_comm_vb2_buffer_done(struct msm_vidc_inst *inst, struct vb2_buffer *vb2; struct vb2_v4l2_buffer *vbuf; u32 i, port; + int rc = 0; if (!inst || !mbuf) { dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n", @@ -2378,16 +2386,20 @@ int msm_comm_vb2_buffer_done(struct msm_vidc_inst *inst, else return -EINVAL; - vb2 = msm_comm_get_vb_using_vidc_buffer(inst, mbuf); - if (!vb2) - return -EINVAL; - /* * access vb2 buffer under q->lock and if streaming only to * ensure the buffer was not free'd by vb2 framework while * we are accessing it here. */ mutex_lock(&inst->bufq[port].lock); + vb2 = msm_comm_get_vb_using_vidc_buffer(inst, mbuf); + if (!vb2) { + rc = -EINVAL; + dprintk(VIDC_ERR, "%s:port %d buffer not found\n", + __func__, port); + goto unlock; + } + if (inst->bufq[port].vb2_bufq.streaming) { vbuf = to_vb2_v4l2_buffer(vb2); vbuf->flags = mbuf->vvb.flags; @@ -2403,9 +2415,9 @@ int msm_comm_vb2_buffer_done(struct msm_vidc_inst *inst, dprintk(VIDC_ERR, "%s: port %d is not streaming\n", __func__, port); } +unlock: mutex_unlock(&inst->bufq[port].lock); - - return 0; + return rc; } bool heic_encode_session_supported(struct msm_vidc_inst *inst) @@ -5316,7 +5328,11 @@ int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags) return 0; } - mutex_lock(&inst->flush_lock); + if (ip_flush) + mutex_lock(&inst->bufq[OUTPUT_PORT].lock); + if (op_flush) + mutex_lock(&inst->bufq[CAPTURE_PORT].lock); + /* enable in flush */ inst->in_flush = true; @@ -5370,7 +5386,12 @@ int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags) rc = call_hfi_op(hdev, session_flush, inst->session, HAL_FLUSH_OUTPUT); } - mutex_unlock(&inst->flush_lock); + + if (op_flush) + mutex_unlock(&inst->bufq[CAPTURE_PORT].lock); + if (ip_flush) + mutex_unlock(&inst->bufq[OUTPUT_PORT].lock); + if (rc) { dprintk(VIDC_ERR, "Sending flush to firmware failed, flush out all buffers\n"); @@ -6462,7 +6483,6 @@ int msm_comm_flush_vidc_buffer(struct msm_vidc_inst *inst, else return -EINVAL; - mutex_lock(&inst->bufq[port].lock); if (inst->bufq[port].vb2_bufq.streaming) { vb->planes[0].bytesused = 0; vb2_buffer_done(vb, VB2_BUF_STATE_DONE); @@ -6470,7 +6490,6 @@ int msm_comm_flush_vidc_buffer(struct msm_vidc_inst *inst, dprintk(VIDC_ERR, "%s: port %d is not streaming\n", __func__, port); } - mutex_unlock(&inst->bufq[port].lock); return 0; } @@ -6824,7 +6843,7 @@ void handle_release_buffer_reference(struct msm_vidc_inst *inst, int i = 0; u32 planes[VIDEO_MAX_PLANES] = {0}; - mutex_lock(&inst->flush_lock); + mutex_lock(&inst->bufq[CAPTURE_PORT].lock); mutex_lock(&inst->registeredbufs.lock); found = false; /* check if mbuf was not removed by any chance */ @@ -6913,7 +6932,7 @@ void handle_release_buffer_reference(struct msm_vidc_inst *inst, print_vidc_buffer(VIDC_ERR, "rbr qbuf failed", inst, mbuf); } - mutex_unlock(&inst->flush_lock); + mutex_unlock(&inst->bufq[CAPTURE_PORT].lock); } int msm_comm_unmap_vidc_buffer(struct msm_vidc_inst *inst, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h index 21453f6a6c8a..b89bb08b3ae5 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -442,7 +442,7 @@ struct msm_vidc_core { struct msm_vidc_inst { struct list_head list; - struct mutex sync_lock, lock, flush_lock; + struct mutex sync_lock, lock; struct msm_vidc_core *core; enum session_type session_type; void *session; diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h index 8fe9afeaf625..fa533afa842b 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h @@ -996,10 +996,9 @@ struct hal_fw_info { }; enum hal_flush { - HAL_FLUSH_INPUT, - HAL_FLUSH_OUTPUT, - HAL_FLUSH_ALL, - HAL_UNUSED_FLUSH = 0x10000000, + HAL_FLUSH_INPUT = BIT(0), + HAL_FLUSH_OUTPUT = BIT(1), + HAL_FLUSH_ALL = HAL_FLUSH_INPUT | HAL_FLUSH_OUTPUT, }; enum hal_event_type { From 27225a9bdd4288bb288798741f18e82214341a1f Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Thu, 16 Jul 2020 14:28:24 -0700 Subject: [PATCH 083/192] mhi: cntrl: qcom: Update the fw image name for new devices Newer devices need to load xbl.elf over BHI instead of the older filename sbl1.mbn. Make the appropriate filename change in the firmware info table. Change-Id: If5a455469c38a9134f610bcd39e5028cc9dbb6b4 Signed-off-by: Bhaumik Bhatt --- drivers/bus/mhi/controllers/mhi_qcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bus/mhi/controllers/mhi_qcom.c b/drivers/bus/mhi/controllers/mhi_qcom.c index 26811368e6c3..e0154b549b4f 100644 --- a/drivers/bus/mhi/controllers/mhi_qcom.c +++ b/drivers/bus/mhi/controllers/mhi_qcom.c @@ -33,7 +33,7 @@ struct firmware_info { }; static const struct firmware_info firmware_table[] = { - {.dev_id = 0x308, .fw_image = "sdx65m/sbl1.mbn", + {.dev_id = 0x308, .fw_image = "sdx65m/xbl.elf", .edl_image = "sdx65m/edl.mbn"}, {.dev_id = 0x307, .fw_image = "sdx60m/sbl1.mbn", .edl_image = "sdx60m/edl.mbn"}, From 9c6317b23ea35825883bdb44612403311837b8e0 Mon Sep 17 00:00:00 2001 From: Vara Reddy Date: Fri, 12 Jun 2020 19:58:53 +0800 Subject: [PATCH 084/192] drm/msm/dsi-staging: update dsi clock calculations Change updates dsi clock calculations for command mode as per recommendation. Now dsi clocks are tied to frame transer time. Propagate correct frame transfer time to hal to update mdp clocks and bandwidth needed accordingly. Change-Id: I46f9038622ddd47cc53c5f3d54229f69a7008c8a Signed-off-by: Vara Reddy Signed-off-by: Ray Zhang --- drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c | 47 +++++++------- drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h | 4 +- drivers/gpu/drm/msm/dsi-staging/dsi_defs.h | 12 ++++ drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 28 +++++++- drivers/gpu/drm/msm/dsi-staging/dsi_panel.c | 65 +++++++++++++++++++ drivers/gpu/drm/msm/dsi-staging/dsi_panel.h | 3 + 6 files changed, 133 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c index 9ad0d88ae427..13fb158125dd 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -823,21 +823,24 @@ int dsi_ctrl_pixel_format_to_bpp(enum dsi_pixel_format dst_format) } static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl, - struct dsi_host_config *config, void *clk_handle) + struct dsi_host_config *config, void *clk_handle, + struct dsi_display_mode *mode) { int rc = 0; u32 num_of_lanes = 0; - u32 bpp; - u64 refresh_rate = TICKS_IN_MICRO_SECOND; + u32 bpp, frame_time_us; u64 h_period, v_period, bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate, byte_intf_clk_rate; struct dsi_host_common_cfg *host_cfg = &config->common_config; struct dsi_split_link_config *split_link = &host_cfg->split_link; struct dsi_mode_info *timing = &config->video_timing; u32 bits_per_symbol = 16, num_of_symbols = 7; /* For Cphy */ + u64 dsi_transfer_time_us = mode->priv_info->dsi_transfer_time_us; + u64 min_dsi_clk_hz = mode->priv_info->min_dsi_clk_hz; - /* Get bits per pxl in desitnation format */ + /* Get bits per pxl in desitination format */ bpp = dsi_ctrl_pixel_format_to_bpp(host_cfg->dst_format); + frame_time_us = mult_frac(1000, 1000, (timing->refresh_rate)); if (host_cfg->data_lanes & DSI_DATA_LANE_0) num_of_lanes++; @@ -851,25 +854,20 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl, if (split_link->split_link_enabled) num_of_lanes = split_link->lanes_per_sublink; - if (config->bit_clk_rate_hz_override == 0) { - if (config->panel_mode == DSI_OP_CMD_MODE) { - h_period = DSI_H_ACTIVE_DSC(timing); - h_period += timing->overlap_pixels; - v_period = timing->v_active; + config->common_config.num_data_lanes = num_of_lanes; + config->common_config.bpp = bpp; - do_div(refresh_rate, timing->mdp_transfer_time_us); - } else { - h_period = DSI_H_TOTAL_DSC(timing); - v_period = DSI_V_TOTAL(timing); - refresh_rate = timing->refresh_rate; - } - bit_rate = h_period * v_period * refresh_rate * bpp; - } else { + if (config->bit_clk_rate_hz_override != 0) { bit_rate = config->bit_clk_rate_hz_override * num_of_lanes; - if (host_cfg->phy_type == DSI_PHY_TYPE_CPHY) { - bit_rate *= bits_per_symbol; - do_div(bit_rate, num_of_symbols); - } + } else if (config->panel_mode == DSI_OP_CMD_MODE) { + /* Calculate the bit rate needed to match dsi transfer time */ + bit_rate = min_dsi_clk_hz * frame_time_us; + do_div(bit_rate, dsi_transfer_time_us); + bit_rate = bit_rate * num_of_lanes; + } else { + h_period = DSI_H_TOTAL_DSC(timing); + v_period = DSI_V_TOTAL(timing); + bit_rate = h_period * v_period * timing->refresh_rate * bpp; } pclk_rate = bit_rate; @@ -2918,6 +2916,7 @@ int dsi_ctrl_host_deinit(struct dsi_ctrl *dsi_ctrl) * dsi_ctrl_update_host_config() - update dsi host configuration * @dsi_ctrl: DSI controller handle. * @config: DSI host configuration. + * @mode: DSI host mode selected. * @flags: dsi_mode_flags modifying the behavior * * Updates driver with new Host configuration to use for host initialization. @@ -2928,6 +2927,7 @@ int dsi_ctrl_host_deinit(struct dsi_ctrl *dsi_ctrl) */ int dsi_ctrl_update_host_config(struct dsi_ctrl *ctrl, struct dsi_host_config *config, + struct dsi_display_mode *mode, int flags, void *clk_handle) { int rc = 0; @@ -2951,7 +2951,8 @@ int dsi_ctrl_update_host_config(struct dsi_ctrl *ctrl, * for dynamic clk switch case link frequence would * be updated dsi_display_dynamic_clk_switch(). */ - rc = dsi_ctrl_update_link_freqs(ctrl, config, clk_handle); + rc = dsi_ctrl_update_link_freqs(ctrl, config, clk_handle, + mode); if (rc) { pr_err("[%s] failed to update link frequencies, rc=%d\n", ctrl->name, rc); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h index b839f23ce582..f99693265990 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -352,6 +352,7 @@ int dsi_ctrl_validate_timing(struct dsi_ctrl *dsi_ctrl, * dsi_ctrl_update_host_config() - update dsi host configuration * @dsi_ctrl: DSI controller handle. * @config: DSI host configuration. + * @mode: DSI host mode selected. * @flags: dsi_mode_flags modifying the behavior * @clk_handle: Clock handle for DSI clocks * @@ -363,6 +364,7 @@ int dsi_ctrl_validate_timing(struct dsi_ctrl *dsi_ctrl, */ int dsi_ctrl_update_host_config(struct dsi_ctrl *dsi_ctrl, struct dsi_host_config *config, + struct dsi_display_mode *mode, int flags, void *clk_handle); /** diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h index e479fa8e0b69..4cc58112f8f8 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h @@ -410,8 +410,10 @@ struct dsi_panel_cmd_set { * @v_sync_polarity: Polarity of VSYNC (false is active low). * @refresh_rate: Refresh rate in Hz. * @clk_rate_hz: DSI bit clock rate per lane in Hz. + * @min_dsi_clk_hz: Min DSI bit clock to transfer in vsync time. * @mdp_transfer_time_us: Specifies the mdp transfer time for command mode * panels in microseconds. + * @dsi_transfer_time_us: Specifies dsi transfer time for command mode. * @overlap_pixels: overlap pixels for certain panels. * @dsc_enabled: DSC compression enabled. * @dsc: DSC compression configuration. @@ -433,7 +435,9 @@ struct dsi_mode_info { u32 refresh_rate; u64 clk_rate_hz; + u64 min_dsi_clk_hz; u32 mdp_transfer_time_us; + u32 dsi_transfer_time_us; u32 overlap_pixels; bool dsc_enabled; struct msm_display_dsc_info *dsc; @@ -456,6 +460,8 @@ struct dsi_split_link_config { * struct dsi_host_common_cfg - Host configuration common to video and cmd mode * @dst_format: Destination pixel format. * @data_lanes: Physical data lanes to be enabled. + * @num_data_lanes: Number of physical data lanes. + * @bpp: Number of bits per pixel. * @en_crc_check: Enable CRC checks. * @en_ecc_check: Enable ECC checks. * @te_mode: Source for TE signalling. @@ -485,6 +491,8 @@ struct dsi_split_link_config { struct dsi_host_common_cfg { enum dsi_pixel_format dst_format; enum dsi_data_lanes data_lanes; + u8 num_data_lanes; + u8 bpp; bool en_crc_check; bool en_ecc_check; enum dsi_te_mode te_mode; @@ -589,7 +597,9 @@ struct dsi_host_config { * @panel_prefill_lines: Panel prefill lines for RSC * @mdp_transfer_time_us: Specifies the mdp transfer time for command mode * panels in microseconds. + * @dsi_transfer_time_us: Specifies the dsi transfer time for cmd panels. * @clk_rate_hz: DSI bit clock per lane in hz. + * @min_dsi_clk_hz: Min dsi clk per lane to transfer frame in vsync time. * @overlap_pixels: overlap pixels for certain panels. * @topology: Topology selected for the panel * @dsc: DSC compression info @@ -606,7 +616,9 @@ struct dsi_display_mode_priv_info { u32 panel_jitter_denom; u32 panel_prefill_lines; u32 mdp_transfer_time_us; + u32 dsi_transfer_time_us; u64 clk_rate_hz; + u64 min_dsi_clk_hz; u32 overlap_pixels; struct msm_display_topology topology; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index bb94f56e7818..f0b9f08a3196 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -4557,7 +4557,7 @@ static int dsi_display_set_mode_sub(struct dsi_display *display, display_for_each_ctrl(i, display) { ctrl = &display->ctrl[i]; rc = dsi_ctrl_update_host_config(ctrl->ctrl, - &display->config, mode->dsi_mode_flags, + &display->config, mode, mode->dsi_mode_flags, display->dsi_clk_handle); if (rc) { pr_err("failed to update ctrl config\n"); @@ -4605,7 +4605,8 @@ static int dsi_display_set_mode_sub(struct dsi_display *display, display_for_each_ctrl(i, display) { ctrl = &display->ctrl[i]; rc = dsi_ctrl_update_host_config(ctrl->ctrl, &display->config, - mode->dsi_mode_flags, display->dsi_clk_handle); + mode, mode->dsi_mode_flags, + display->dsi_clk_handle); if (rc) { pr_err("[%s] failed to update ctrl config, rc=%d\n", display->name, rc); @@ -6306,6 +6307,22 @@ int dsi_display_get_modes(struct dsi_display *display, is_cmd_mode = (display_mode.panel_mode == DSI_OP_CMD_MODE); + /* Calculate dsi frame transfer time */ + if (is_cmd_mode) { + dsi_panel_calc_dsi_transfer_time( + &display->panel->host_config, + &display_mode.timing); + display_mode.priv_info->dsi_transfer_time_us = + display_mode.timing.dsi_transfer_time_us; + display_mode.priv_info->min_dsi_clk_hz = + display_mode.timing.min_dsi_clk_hz; + + display_mode.priv_info->mdp_transfer_time_us = + display_mode.priv_info->dsi_transfer_time_us; + display_mode.timing.mdp_transfer_time_us = + display_mode.timing.dsi_transfer_time_us; + } + is_split_link = host->split_link.split_link_enabled; sublinks_count = host->split_link.num_sublinks; if (is_split_link && sublinks_count > 1) { @@ -6627,6 +6644,7 @@ int dsi_display_set_mode(struct dsi_display *display, { int rc = 0; struct dsi_display_mode adj_mode; + struct dsi_mode_info timing; if (!display || !mode || !display->panel) { pr_err("Invalid params\n"); @@ -6636,6 +6654,7 @@ int dsi_display_set_mode(struct dsi_display *display, mutex_lock(&display->display_lock); adj_mode = *mode; + timing = adj_mode.timing; adjust_timing_by_ctrl_count(display, &adj_mode); /*For dynamic DSI setting, use specified clock rate */ @@ -6663,6 +6682,11 @@ int dsi_display_set_mode(struct dsi_display *display, } } + pr_info("mdp_transfer_time_us=%d us\n", + adj_mode.priv_info->mdp_transfer_time_us); + pr_info("hactive= %d, vactive= %d, fps=%d", timing.h_active, + timing.v_active, timing.refresh_rate); + memcpy(display->panel->cur_mode, &adj_mode, sizeof(adj_mode)); error: mutex_unlock(&display->display_lock); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index fe3013a6edcd..a0ffa9d57e3a 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -967,6 +967,8 @@ static int dsi_panel_parse_pixel_format(struct dsi_host_common_cfg *host, return rc; } + host->bpp = bpp; + switch (bpp) { case 3: fmt = DSI_PIXEL_FORMAT_RGB111; @@ -1007,6 +1009,7 @@ static int dsi_panel_parse_lane_states(struct dsi_host_common_cfg *host, { int rc = 0; bool lane_enabled; + u32 num_of_lanes = 0; lane_enabled = utils->read_bool(utils->data, "qcom,mdss-dsi-lane-0-state"); @@ -1024,6 +1027,17 @@ static int dsi_panel_parse_lane_states(struct dsi_host_common_cfg *host, "qcom,mdss-dsi-lane-3-state"); host->data_lanes |= (lane_enabled ? DSI_DATA_LANE_3 : 0); + if (host->data_lanes & DSI_DATA_LANE_0) + num_of_lanes++; + if (host->data_lanes & DSI_DATA_LANE_1) + num_of_lanes++; + if (host->data_lanes & DSI_DATA_LANE_2) + num_of_lanes++; + if (host->data_lanes & DSI_DATA_LANE_3) + num_of_lanes++; + + host->num_data_lanes = num_of_lanes; + if (host->data_lanes == 0) { pr_err("[%s] No data lanes are enabled, rc=%d\n", name, rc); rc = -EINVAL; @@ -3606,6 +3620,57 @@ void dsi_panel_put_mode(struct dsi_display_mode *mode) kfree(mode->priv_info); } +void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config, + struct dsi_mode_info *timing) +{ + u32 frame_time_us, nslices; + u64 min_bitclk, total_active_pixels, bits_per_line, + dsi_transfer_time_us; + struct msm_display_dsc_info *dsc = timing->dsc; + + /* Packet overlead in bits,2 bytes header + 2 bytes checksum + * + 1 byte dcs data command. + */ + const u32 packet_overhead = 56; + + /* Default time between pingpong done to TE in microsecs */ + const u32 max_tx_threshold_time = 2166; + + frame_time_us = mult_frac(1000, 1000, (timing->refresh_rate)); + + if (timing->dsc_enabled) { + nslices = (timing->h_active)/(dsc->slice_width); + /* (slice width x bit-per-pixel + packet overhead) x + * number of slices x height x fps / lane + */ + bits_per_line = ((dsc->slice_width * dsc->bpp) + + packet_overhead) * nslices; + bits_per_line = bits_per_line / (config->num_data_lanes); + + min_bitclk = (bits_per_line * timing->v_active * + timing->refresh_rate); + } else { + total_active_pixels = ((DSI_H_ACTIVE_DSC(timing) + * timing->v_active)); + /* calculate the actual bitclk needed to transfer the frame */ + min_bitclk = (total_active_pixels * (timing->refresh_rate) * + (config->bpp)); + do_div(min_bitclk, config->num_data_lanes); + } + + timing->min_dsi_clk_hz = min_bitclk; + + if (timing->clk_rate_hz) { + /* adjust the transfer time proportionately for bit clk*/ + dsi_transfer_time_us = frame_time_us * min_bitclk; + do_div(dsi_transfer_time_us, timing->clk_rate_hz); + timing->dsi_transfer_time_us = dsi_transfer_time_us; + } else { + timing->dsi_transfer_time_us = frame_time_us - + max_tx_threshold_time; + } +} + int dsi_panel_get_mode(struct dsi_panel *panel, u32 index, struct dsi_display_mode *mode, int topology_override) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h index 4dcaf16020e5..59d99b0510cc 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h @@ -337,4 +337,7 @@ int dsi_panel_parse_esd_reg_read_configs(struct dsi_panel *panel); void dsi_panel_ext_bridge_put(struct dsi_panel *panel); +void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config, + struct dsi_mode_info *timing); + #endif /* _DSI_PANEL_H_ */ From b693f3694b5f004060fcadc3614b8612695b1f2b Mon Sep 17 00:00:00 2001 From: Vara Reddy Date: Fri, 12 Jun 2020 20:19:12 +0800 Subject: [PATCH 085/192] drm/msm/dsi-staging: update frame transfer time calculations Change updates frame transfer time calculations. Frame threshold is provided as input to decide on the final transfer time. Panel dsi clock node followed by mdp transfer time node will take priority in selecting final transfer time than frame threshold time. Change-Id: I40c3abfc635cd9b338b705535612ac32e047ce6e Signed-off-by: Vara Reddy Signed-off-by: Ray Zhang Signed-off-by: Bruce Hoo --- drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c | 11 ++++++++++- drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h | 5 +++++ drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 5 ++++- drivers/gpu/drm/msm/dsi-staging/dsi_panel.c | 17 ++++++++--------- drivers/gpu/drm/msm/dsi-staging/dsi_panel.h | 2 +- 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c index 13fb158125dd..5efcc39b07d2 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c @@ -1729,7 +1729,7 @@ static int dsi_enable_io_clamp(struct dsi_ctrl *dsi_ctrl, static int dsi_ctrl_dts_parse(struct dsi_ctrl *dsi_ctrl, struct device_node *of_node) { - u32 index = 0; + u32 index = 0, frame_threshold_time_us = 0; int rc = 0; if (!dsi_ctrl || !of_node) { @@ -1758,6 +1758,15 @@ static int dsi_ctrl_dts_parse(struct dsi_ctrl *dsi_ctrl, dsi_ctrl->split_link_supported = of_property_read_bool(of_node, "qcom,split-link-supported"); + rc = of_property_read_u32(of_node, "frame-threshold-time-us", + &frame_threshold_time_us); + if (rc) { + pr_debug("frame-threshold-time not specified, defaulting\n"); + frame_threshold_time_us = 2666; + } + + dsi_ctrl->frame_threshold_time_us = frame_threshold_time_us; + return 0; } diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h index f99693265990..9198e28475bb 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h @@ -230,6 +230,9 @@ struct dsi_ctrl_interrupts { * @debugfs_root: Root for debugfs entries. * @misr_enable: Frame MISR enable/disable * @misr_cache: Cached Frame MISR value + * @frame_threshold_time_us: Frame threshold time in microseconds, where + * dsi data lane will be idle i.e from pingpong done to + * next TE for command mode. * @phy_isolation_enabled: A boolean property allows to isolate the phy from * dsi controller and run only dsi controller. * @null_insertion_enabled: A boolean property to allow dsi controller to @@ -282,6 +285,8 @@ struct dsi_ctrl { bool misr_enable; u32 misr_cache; + u32 frame_threshold_time_us; + /* Check for spurious interrupts */ unsigned long jiffies_start; unsigned int error_interrupt_count; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index f0b9f08a3196..b4be10b40282 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -6246,6 +6246,7 @@ int dsi_display_get_modes(struct dsi_display *display, struct dsi_display_mode **out_modes) { struct dsi_dfps_capabilities dfps_caps; + struct dsi_display_ctrl *ctrl; struct dsi_host_common_cfg *host = &display->panel->host_config; bool is_split_link, is_cmd_mode; u32 num_dfps_rates, timing_mode_count, display_mode_count; @@ -6259,6 +6260,7 @@ int dsi_display_get_modes(struct dsi_display *display, } *out_modes = NULL; + ctrl = &display->ctrl[0]; mutex_lock(&display->display_lock); @@ -6290,6 +6292,7 @@ int dsi_display_get_modes(struct dsi_display *display, for (mode_idx = 0; mode_idx < timing_mode_count; mode_idx++) { struct dsi_display_mode display_mode; int topology_override = NO_OVERRIDE; + u32 frame_threshold_us = ctrl->ctrl->frame_threshold_time_us; if (display->cmdline_timing == mode_idx) topology_override = display->cmdline_topology; @@ -6311,7 +6314,7 @@ int dsi_display_get_modes(struct dsi_display *display, if (is_cmd_mode) { dsi_panel_calc_dsi_transfer_time( &display->panel->host_config, - &display_mode.timing); + &display_mode, frame_threshold_us); display_mode.priv_info->dsi_transfer_time_us = display_mode.timing.dsi_transfer_time_us; display_mode.priv_info->min_dsi_clk_hz = diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index a0ffa9d57e3a..b64192bdf62f 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -35,8 +35,6 @@ #define DSI_PANEL_DEFAULT_LABEL "Default dsi panel" -#define DEFAULT_MDP_TRANSFER_TIME 14000 - #define DEFAULT_PANEL_JITTER_NUMERATOR 2 #define DEFAULT_PANEL_JITTER_DENOMINATOR 1 #define DEFAULT_PANEL_JITTER_ARRAY_SIZE 2 @@ -851,7 +849,7 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode, &mode->mdp_transfer_time_us); if (rc) { pr_debug("fallback to default mdp-transfer-time-us\n"); - mode->mdp_transfer_time_us = DEFAULT_MDP_TRANSFER_TIME; + mode->mdp_transfer_time_us = 0; } display_mode->priv_info->mdp_transfer_time_us = mode->mdp_transfer_time_us; @@ -3621,21 +3619,19 @@ void dsi_panel_put_mode(struct dsi_display_mode *mode) } void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config, - struct dsi_mode_info *timing) + struct dsi_display_mode *mode, u32 frame_threshold_us) { u32 frame_time_us, nslices; u64 min_bitclk, total_active_pixels, bits_per_line, dsi_transfer_time_us; - struct msm_display_dsc_info *dsc = timing->dsc; + struct msm_display_dsc_info *dsc = mode->timing.dsc; + struct dsi_mode_info *timing = &mode->timing; /* Packet overlead in bits,2 bytes header + 2 bytes checksum * + 1 byte dcs data command. */ const u32 packet_overhead = 56; - /* Default time between pingpong done to TE in microsecs */ - const u32 max_tx_threshold_time = 2166; - frame_time_us = mult_frac(1000, 1000, (timing->refresh_rate)); if (timing->dsc_enabled) { @@ -3665,9 +3661,12 @@ void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config, dsi_transfer_time_us = frame_time_us * min_bitclk; do_div(dsi_transfer_time_us, timing->clk_rate_hz); timing->dsi_transfer_time_us = dsi_transfer_time_us; + } else if (mode->priv_info->mdp_transfer_time_us) { + timing->dsi_transfer_time_us = + mode->priv_info->mdp_transfer_time_us; } else { timing->dsi_transfer_time_us = frame_time_us - - max_tx_threshold_time; + frame_threshold_us; } } diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h index 59d99b0510cc..7d5a7e8c4715 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h @@ -338,6 +338,6 @@ int dsi_panel_parse_esd_reg_read_configs(struct dsi_panel *panel); void dsi_panel_ext_bridge_put(struct dsi_panel *panel); void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config, - struct dsi_mode_info *timing); + struct dsi_display_mode *mode, u32 frame_threshold_us); #endif /* _DSI_PANEL_H_ */ From 738b8add680d9fe421d287ae08f8237a71491a45 Mon Sep 17 00:00:00 2001 From: Vara Reddy Date: Fri, 12 Jun 2020 20:52:08 +0800 Subject: [PATCH 086/192] disp: msm: dsi: update dsi pclk in panel mode settings Change calculates and updates correct pclk that is being used to drm modes in kilo hertz. Change-Id: I7aab10c08689697120d4d7c152f30993defd36d3 Signed-off-by: Vara Reddy Signed-off-by: Ray Zhang Signed-off-by: Bruce Hoo --- drivers/gpu/drm/msm/dsi-staging/dsi_panel.c | 55 ++++++++++++--------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index b64192bdf62f..160a1ab73685 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -2555,9 +2555,6 @@ static int dsi_panel_parse_phy_timing(struct dsi_display_mode *mode, u32 len, i; int rc = 0; struct dsi_display_mode_priv_info *priv_info; - u64 h_period, v_period; - u64 refresh_rate = TICKS_IN_MICRO_SECOND; - struct dsi_mode_info *timing = NULL; u64 pixel_clk_khz; if (!mode || !mode->priv_info) @@ -2581,22 +2578,19 @@ static int dsi_panel_parse_phy_timing(struct dsi_display_mode *mode, priv_info->phy_timing_len = len; }; - timing = &mode->timing; - - if (panel_mode == DSI_OP_CMD_MODE) { - h_period = DSI_H_ACTIVE_DSC(timing); - v_period = timing->v_active; - do_div(refresh_rate, priv_info->mdp_transfer_time_us); - } else { - h_period = DSI_H_TOTAL_DSC(timing); - v_period = DSI_V_TOTAL(timing); - refresh_rate = timing->refresh_rate; + if (panel_mode == DSI_OP_VIDEO_MODE) { + /* + * For command mode we update the pclk as part of + * function dsi_panel_calc_dsi_transfer_time( ) + * as we set it based on dsi clock or mdp transfer time. + */ + pixel_clk_khz = (DSI_H_TOTAL_DSC(&mode->timing) * + DSI_V_TOTAL(&mode->timing) * + mode->timing.refresh_rate); + do_div(pixel_clk_khz, 1000); + mode->pixel_clk_khz = pixel_clk_khz; } - pixel_clk_khz = h_period * v_period * refresh_rate; - do_div(pixel_clk_khz, 1000); - mode->pixel_clk_khz = pixel_clk_khz; - return rc; } @@ -3622,16 +3616,19 @@ void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config, struct dsi_display_mode *mode, u32 frame_threshold_us) { u32 frame_time_us, nslices; - u64 min_bitclk, total_active_pixels, bits_per_line, - dsi_transfer_time_us; + u64 min_bitclk_hz, total_active_pixels, bits_per_line, pclk_rate_hz, + dsi_transfer_time_us, pixel_clk_khz; struct msm_display_dsc_info *dsc = mode->timing.dsc; struct dsi_mode_info *timing = &mode->timing; + struct dsi_display_mode *display_mode; /* Packet overlead in bits,2 bytes header + 2 bytes checksum * + 1 byte dcs data command. */ const u32 packet_overhead = 56; + display_mode = container_of(timing, struct dsi_display_mode, timing); + frame_time_us = mult_frac(1000, 1000, (timing->refresh_rate)); if (timing->dsc_enabled) { @@ -3643,22 +3640,22 @@ void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config, packet_overhead) * nslices; bits_per_line = bits_per_line / (config->num_data_lanes); - min_bitclk = (bits_per_line * timing->v_active * + min_bitclk_hz = (bits_per_line * timing->v_active * timing->refresh_rate); } else { total_active_pixels = ((DSI_H_ACTIVE_DSC(timing) * timing->v_active)); /* calculate the actual bitclk needed to transfer the frame */ - min_bitclk = (total_active_pixels * (timing->refresh_rate) * + min_bitclk_hz = (total_active_pixels * (timing->refresh_rate) * (config->bpp)); - do_div(min_bitclk, config->num_data_lanes); + do_div(min_bitclk_hz, config->num_data_lanes); } - timing->min_dsi_clk_hz = min_bitclk; + timing->min_dsi_clk_hz = min_bitclk_hz; if (timing->clk_rate_hz) { /* adjust the transfer time proportionately for bit clk*/ - dsi_transfer_time_us = frame_time_us * min_bitclk; + dsi_transfer_time_us = frame_time_us * min_bitclk_hz; do_div(dsi_transfer_time_us, timing->clk_rate_hz); timing->dsi_transfer_time_us = dsi_transfer_time_us; } else if (mode->priv_info->mdp_transfer_time_us) { @@ -3668,6 +3665,16 @@ void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config, timing->dsi_transfer_time_us = frame_time_us - frame_threshold_us; } + + /* Calculate pclk_khz to update modeinfo */ + pclk_rate_hz = min_bitclk_hz * frame_time_us; + do_div(pclk_rate_hz, timing->dsi_transfer_time_us); + + pixel_clk_khz = pclk_rate_hz * config->num_data_lanes; + do_div(pixel_clk_khz, config->bpp); + display_mode->pixel_clk_khz = pixel_clk_khz; + + display_mode->pixel_clk_khz = display_mode->pixel_clk_khz / 1000; } int dsi_panel_get_mode(struct dsi_panel *panel, From 35fd2e492b49e76cebb0a7a95429a6dd1561f3ae Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 11 Jun 2018 14:09:46 -0700 Subject: [PATCH 087/192] UPSTREAM: ath10k: snoc: sort include files Sort these alphabetically, with local includes in a separate section. Signed-off-by: Brian Norris Signed-off-by: Kalle Valo Git-commit: c9f3e7fa8bcb63a52531bf7e02bf53e0d177f3dc Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I2f35e9a24a5d3e81773a1fc01be5ccc5e750d67b Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/snoc.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 8e036cc16537..ca8b18314342 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -14,18 +14,19 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include #include -#include "debug.h" -#include "hif.h" -#include "htc.h" -#include "ce.h" -#include "snoc.h" +#include #include #include #include #include -#include + +#include "ce.h" +#include "debug.h" +#include "hif.h" +#include "htc.h" +#include "snoc.h" #define ATH10K_SNOC_RX_POST_RETRY_MS 50 #define CE_POLL_PIPE 4 From fc005795f1c13322b7c1886fbf36a987aa35a8f0 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 12 Jun 2018 13:39:05 +0200 Subject: [PATCH 088/192] UPSTREAM: ath10k: do not mix spaces and tabs in Kconfig Do not mix spaces and tabs in Kconfig. Signed-off-by: Niklas Cassel Signed-off-by: Kalle Valo Git-commit: 50c51f394e685c450276e1ae5b91405ad55d8570 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: Id6a91d3469a942dfbb61fdb292c97040ac1178ea Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/Kconfig | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index 84f071ac0d84..54ff5930126c 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -1,15 +1,15 @@ config ATH10K - tristate "Atheros 802.11ac wireless cards support" - depends on MAC80211 && HAS_DMA + tristate "Atheros 802.11ac wireless cards support" + depends on MAC80211 && HAS_DMA select ATH_COMMON select CRC32 select WANT_DEV_COREDUMP select ATH10K_CE - ---help--- - This module adds support for wireless adapters based on - Atheros IEEE 802.11ac family of chipsets. + ---help--- + This module adds support for wireless adapters based on + Atheros IEEE 802.11ac family of chipsets. - If you choose to build a module, it'll be called ath10k. + If you choose to build a module, it'll be called ath10k. config ATH10K_CE bool @@ -41,12 +41,12 @@ config ATH10K_USB work in progress and will not fully work. config ATH10K_SNOC - tristate "Qualcomm ath10k SNOC support (EXPERIMENTAL)" - depends on ATH10K && ARCH_QCOM - ---help--- - This module adds support for integrated WCN3990 chip connected - to system NOC(SNOC). Currently work in progress and will not - fully work. + tristate "Qualcomm ath10k SNOC support (EXPERIMENTAL)" + depends on ATH10K && ARCH_QCOM + ---help--- + This module adds support for integrated WCN3990 chip connected + to system NOC(SNOC). Currently work in progress and will not + fully work. config ATH10K_DEBUG bool "Atheros ath10k debugging" From e924f4c1599a5e796d09be9e482df31cb628918b Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Wed, 13 Jun 2018 12:18:06 +0530 Subject: [PATCH 089/192] UPSTREAM: ath10k: handle resource init failure case Return type of resource init method is not assigned. Handle resource init failures for graceful exit. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: d16a7ab20ac9861979c83d7fce8f5edc48daada6 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: Iea5367f7664399c178b5749f7f9f46d7730ec6d3 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/snoc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index ca8b18314342..293f5116b172 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -1301,13 +1301,13 @@ static int ath10k_snoc_probe(struct platform_device *pdev) ar_snoc->ce.bus_ops = &ath10k_snoc_bus_ops; ar->ce_priv = &ar_snoc->ce; - ath10k_snoc_resource_init(ar); + ret = ath10k_snoc_resource_init(ar); if (ret) { ath10k_warn(ar, "failed to initialize resource: %d\n", ret); goto err_core_destroy; } - ath10k_snoc_setup_resource(ar); + ret = ath10k_snoc_setup_resource(ar); if (ret) { ath10k_warn(ar, "failed to setup resource: %d\n", ret); goto err_core_destroy; From 57567c64765e08c6d58835d7fc06e844d2c77ff4 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 11 Oct 2018 13:11:32 +0300 Subject: [PATCH 090/192] UPSTREAM: ath10k: add qmi service helpers for wcn3990 qmi client WLAN qmi server running in Q6 exposes host to target cold boot qmi handshakes. Add WLAN QMI service helpers for ath10k wcn3990 qmi client. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: bc17d4b90cdd3e557d195937c0003260dfce67d6 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I1a0f39fa2f5b9de731b4e3b0202ea29faf4ecfeb Signed-off-by: Dundi Raviteja --- .../net/wireless/ath/ath10k/qmi_wlfw_v01.c | 2072 +++++++++++++++++ .../net/wireless/ath/ath10k/qmi_wlfw_v01.h | 677 ++++++ 2 files changed, 2749 insertions(+) create mode 100644 drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c create mode 100644 drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c new file mode 100644 index 000000000000..ba79c2e4aed6 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c @@ -0,0 +1,2072 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include "qmi_wlfw_v01.h" + +static struct qmi_elem_info wlfw_ce_tgt_pipe_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, + pipe_num), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_pipedir_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, + pipe_dir), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, + nentries), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, + nbytes_max), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, + flags), + }, + {} +}; + +static struct qmi_elem_info wlfw_ce_svc_pipe_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01, + service_id), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_pipedir_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01, + pipe_dir), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01, + pipe_num), + }, + {} +}; + +static struct qmi_elem_info wlfw_shadow_reg_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_shadow_reg_cfg_s_v01, + id), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_shadow_reg_cfg_s_v01, + offset), + }, + {} +}; + +static struct qmi_elem_info wlfw_shadow_reg_v2_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_shadow_reg_v2_cfg_s_v01, + addr), + }, + {} +}; + +static struct qmi_elem_info wlfw_memory_region_info_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_memory_region_info_s_v01, + region_addr), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_memory_region_info_s_v01, + size), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_memory_region_info_s_v01, + secure_flag), + }, + {} +}; + +static struct qmi_elem_info wlfw_mem_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_cfg_s_v01, + offset), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_cfg_s_v01, + size), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_cfg_s_v01, + secure_flag), + }, + {} +}; + +static struct qmi_elem_info wlfw_mem_seg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_s_v01, + size), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_mem_type_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_s_v01, + type), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_s_v01, + mem_cfg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_MEM_CFG_V01, + .elem_size = sizeof(struct wlfw_mem_cfg_s_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_s_v01, + mem_cfg), + .ei_array = wlfw_mem_cfg_s_v01_ei, + }, + {} +}; + +static struct qmi_elem_info wlfw_mem_seg_resp_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_resp_s_v01, + addr), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_resp_s_v01, + size), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_mem_type_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_resp_s_v01, + type), + }, + {} +}; + +static struct qmi_elem_info wlfw_rf_chip_info_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_rf_chip_info_s_v01, + chip_id), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_rf_chip_info_s_v01, + chip_family), + }, + {} +}; + +static struct qmi_elem_info wlfw_rf_board_info_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_rf_board_info_s_v01, + board_id), + }, + {} +}; + +static struct qmi_elem_info wlfw_soc_info_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_soc_info_s_v01, + soc_id), + }, + {} +}; + +static struct qmi_elem_info wlfw_fw_version_info_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_fw_version_info_s_v01, + fw_version), + }, + { + .data_type = QMI_STRING, + .elem_len = QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1, + .elem_size = sizeof(char), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_fw_version_info_s_v01, + fw_build_timestamp), + }, + {} +}; + +struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + fw_ready_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + fw_ready_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + initiate_cal_download_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + initiate_cal_download_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + initiate_cal_update_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + initiate_cal_update_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + msa_ready_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + msa_ready_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + pin_connect_result_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + pin_connect_result_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + client_id_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + client_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + request_mem_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + request_mem_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x17, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + mem_ready_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x17, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + mem_ready_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x18, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + fw_init_done_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x18, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + fw_init_done_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x19, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + rejuvenate_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x19, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + rejuvenate_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x1A, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + xo_cal_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x1A, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + xo_cal_enable), + }, + {} +}; + +struct qmi_elem_info wlfw_ind_register_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_ind_register_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_ind_register_resp_msg_v01, + fw_status_valid), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_ind_register_resp_msg_v01, + fw_status), + }, + {} +}; + +struct qmi_elem_info wlfw_fw_ready_ind_msg_v01_ei[] = { + {} +}; + +struct qmi_elem_info wlfw_msa_ready_ind_msg_v01_ei[] = { + {} +}; + +struct qmi_elem_info wlfw_pin_connect_result_ind_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01, + pwr_pin_result_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01, + pwr_pin_result), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01, + phy_io_pin_result_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01, + phy_io_pin_result), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01, + rf_pin_result_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01, + rf_pin_result), + }, + {} +}; + +struct qmi_elem_info wlfw_wlan_mode_req_msg_v01_ei[] = { + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_driver_mode_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01, + mode), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01, + hw_debug_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01, + hw_debug), + }, + {} +}; + +struct qmi_elem_info wlfw_wlan_mode_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_wlan_mode_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + host_version_valid), + }, + { + .data_type = QMI_STRING, + .elem_len = QMI_WLFW_MAX_STR_LEN_V01 + 1, + .elem_size = sizeof(char), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + host_version), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + tgt_cfg_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + tgt_cfg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_CE_V01, + .elem_size = sizeof(struct wlfw_ce_tgt_pipe_cfg_s_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + tgt_cfg), + .ei_array = wlfw_ce_tgt_pipe_cfg_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + svc_cfg_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + svc_cfg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_SVC_V01, + .elem_size = sizeof(struct wlfw_ce_svc_pipe_cfg_s_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + svc_cfg), + .ei_array = wlfw_ce_svc_pipe_cfg_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + shadow_reg_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + shadow_reg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01, + .elem_size = sizeof(struct wlfw_shadow_reg_cfg_s_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + shadow_reg), + .ei_array = wlfw_shadow_reg_cfg_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + shadow_reg_v2_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + shadow_reg_v2_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_SHADOW_REG_V2, + .elem_size = sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + shadow_reg_v2), + .ei_array = wlfw_shadow_reg_v2_cfg_s_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_wlan_cfg_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_wlan_cfg_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_cap_req_msg_v01_ei[] = { + {} +}; + +struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + chip_info_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct wlfw_rf_chip_info_s_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + chip_info), + .ei_array = wlfw_rf_chip_info_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + board_info_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct wlfw_rf_board_info_s_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + board_info), + .ei_array = wlfw_rf_board_info_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + soc_info_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct wlfw_soc_info_s_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + soc_info), + .ei_array = wlfw_soc_info_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + fw_version_info_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct wlfw_fw_version_info_s_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + fw_version_info), + .ei_array = wlfw_fw_version_info_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + fw_build_id_valid), + }, + { + .data_type = QMI_STRING, + .elem_len = QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1, + .elem_size = sizeof(char), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + fw_build_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + num_macs_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_cap_resp_msg_v01, + num_macs), + }, + {} +}; + +struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + valid), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + file_id_valid), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + file_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + total_size_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + total_size), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + seg_id_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + seg_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + data_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + data_len), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01, + .elem_size = sizeof(u8), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + data), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + end_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + end), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + bdf_type_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, + bdf_type), + }, + {} +}; + +struct qmi_elem_info wlfw_bdf_download_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_bdf_download_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_cal_report_req_msg_v01_ei[] = { + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_cal_report_req_msg_v01, + meta_data_len), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = QMI_WLFW_MAX_NUM_CAL_V01, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_cal_report_req_msg_v01, + meta_data), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cal_report_req_msg_v01, + xo_cal_data_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cal_report_req_msg_v01, + xo_cal_data), + }, + {} +}; + +struct qmi_elem_info wlfw_cal_report_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_cal_report_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[] = { + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_initiate_cal_download_ind_msg_v01, + cal_id), + }, + {} +}; + +struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + valid), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + file_id_valid), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + file_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + total_size_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + total_size), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + seg_id_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + seg_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + data_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + data_len), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01, + .elem_size = sizeof(u8), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + data), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + end_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_cal_download_req_msg_v01, + end), + }, + {} +}; + +struct qmi_elem_info wlfw_cal_download_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_cal_download_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[] = { + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_initiate_cal_update_ind_msg_v01, + cal_id), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_initiate_cal_update_ind_msg_v01, + total_size), + }, + {} +}; + +struct qmi_elem_info wlfw_cal_update_req_msg_v01_ei[] = { + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_cal_update_req_msg_v01, + cal_id), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_cal_update_req_msg_v01, + seg_id), + }, + {} +}; + +struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + file_id_valid), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + file_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + total_size_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + total_size), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + seg_id_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + seg_id), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + data_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + data_len), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01, + .elem_size = sizeof(u8), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + data), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + end_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, + end), + }, + {} +}; + +struct qmi_elem_info wlfw_msa_info_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_msa_info_req_msg_v01, + msa_addr), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_msa_info_req_msg_v01, + size), + }, + {} +}; + +struct qmi_elem_info wlfw_msa_info_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_msa_info_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct wlfw_msa_info_resp_msg_v01, + mem_region_info_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_MEM_REG_V01, + .elem_size = sizeof(struct wlfw_memory_region_info_s_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct wlfw_msa_info_resp_msg_v01, + mem_region_info), + .ei_array = wlfw_memory_region_info_s_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_msa_ready_req_msg_v01_ei[] = { + {} +}; + +struct qmi_elem_info wlfw_msa_ready_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_msa_ready_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_ini_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_ini_req_msg_v01, + enablefwlog_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_ini_req_msg_v01, + enablefwlog), + }, + {} +}; + +struct qmi_elem_info wlfw_ini_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_ini_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_athdiag_read_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01, + offset), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01, + mem_type), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01, + data_len), + }, + {} +}; + +struct qmi_elem_info wlfw_athdiag_read_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_athdiag_read_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_athdiag_read_resp_msg_v01, + data_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_athdiag_read_resp_msg_v01, + data_len), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01, + .elem_size = sizeof(u8), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_athdiag_read_resp_msg_v01, + data), + }, + {} +}; + +struct qmi_elem_info wlfw_athdiag_write_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_athdiag_write_req_msg_v01, + offset), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_athdiag_write_req_msg_v01, + mem_type), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct wlfw_athdiag_write_req_msg_v01, + data_len), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01, + .elem_size = sizeof(u8), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct wlfw_athdiag_write_req_msg_v01, + data), + }, + {} +}; + +struct qmi_elem_info wlfw_athdiag_write_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_athdiag_write_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_vbatt_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_vbatt_req_msg_v01, + voltage_uv), + }, + {} +}; + +struct qmi_elem_info wlfw_vbatt_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_vbatt_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_mac_addr_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_mac_addr_req_msg_v01, + mac_addr_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = QMI_WLFW_MAC_ADDR_SIZE_V01, + .elem_size = sizeof(u8), + .array_type = STATIC_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_mac_addr_req_msg_v01, + mac_addr), + }, + {} +}; + +struct qmi_elem_info wlfw_mac_addr_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_mac_addr_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + daemon_support_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + daemon_support), + }, + {} +}; + +struct qmi_elem_info wlfw_host_cap_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_host_cap_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_request_mem_ind_msg_v01_ei[] = { + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_request_mem_ind_msg_v01, + mem_seg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_MEM_SEG_V01, + .elem_size = sizeof(struct wlfw_mem_seg_s_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_request_mem_ind_msg_v01, + mem_seg), + .ei_array = wlfw_mem_seg_s_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_respond_mem_req_msg_v01_ei[] = { + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_respond_mem_req_msg_v01, + mem_seg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_MEM_SEG_V01, + .elem_size = sizeof(struct wlfw_mem_seg_resp_s_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_respond_mem_req_msg_v01, + mem_seg), + .ei_array = wlfw_mem_seg_resp_s_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_respond_mem_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_respond_mem_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_mem_ready_ind_msg_v01_ei[] = { + {} +}; + +struct qmi_elem_info wlfw_fw_init_done_ind_msg_v01_ei[] = { + {} +}; + +struct qmi_elem_info wlfw_rejuvenate_ind_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + cause_for_rejuvenation_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + cause_for_rejuvenation), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + requesting_sub_system_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + requesting_sub_system), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + line_number_valid), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + line_number), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + function_name_valid), + }, + { + .data_type = QMI_STRING, + .elem_len = QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1, + .elem_size = sizeof(char), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, + function_name), + }, + {} +}; + +struct qmi_elem_info wlfw_rejuvenate_ack_req_msg_v01_ei[] = { + {} +}; + +struct qmi_elem_info wlfw_rejuvenate_ack_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_rejuvenate_ack_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_dynamic_feature_mask_req_msg_v01, + mask_valid), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_dynamic_feature_mask_req_msg_v01, + mask), + }, + {} +}; + +struct qmi_elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01, + prev_mask_valid), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01, + prev_mask), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01, + curr_mask_valid), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01, + curr_mask), + }, + {} +}; + +struct qmi_elem_info wlfw_m3_info_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_m3_info_req_msg_v01, + addr), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_m3_info_req_msg_v01, + size), + }, + {} +}; + +struct qmi_elem_info wlfw_m3_info_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wlfw_m3_info_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; + +struct qmi_elem_info wlfw_xo_cal_ind_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_xo_cal_ind_msg_v01, + xo_cal_data), + }, + {} +}; diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h new file mode 100644 index 000000000000..c5e3870b8871 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h @@ -0,0 +1,677 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WCN3990_QMI_SVC_V01_H +#define WCN3990_QMI_SVC_V01_H + +#define WLFW_SERVICE_ID_V01 0x45 +#define WLFW_SERVICE_VERS_V01 0x01 + +#define QMI_WLFW_BDF_DOWNLOAD_REQ_V01 0x0025 +#define QMI_WLFW_MEM_READY_IND_V01 0x0037 +#define QMI_WLFW_DYNAMIC_FEATURE_MASK_RESP_V01 0x003B +#define QMI_WLFW_INITIATE_CAL_UPDATE_IND_V01 0x002A +#define QMI_WLFW_HOST_CAP_REQ_V01 0x0034 +#define QMI_WLFW_M3_INFO_REQ_V01 0x003C +#define QMI_WLFW_CAP_REQ_V01 0x0024 +#define QMI_WLFW_FW_INIT_DONE_IND_V01 0x0038 +#define QMI_WLFW_CAL_REPORT_REQ_V01 0x0026 +#define QMI_WLFW_M3_INFO_RESP_V01 0x003C +#define QMI_WLFW_CAL_UPDATE_RESP_V01 0x0029 +#define QMI_WLFW_CAL_DOWNLOAD_RESP_V01 0x0027 +#define QMI_WLFW_XO_CAL_IND_V01 0x003D +#define QMI_WLFW_INI_RESP_V01 0x002F +#define QMI_WLFW_CAL_REPORT_RESP_V01 0x0026 +#define QMI_WLFW_MAC_ADDR_RESP_V01 0x0033 +#define QMI_WLFW_INITIATE_CAL_DOWNLOAD_IND_V01 0x0028 +#define QMI_WLFW_HOST_CAP_RESP_V01 0x0034 +#define QMI_WLFW_MSA_READY_IND_V01 0x002B +#define QMI_WLFW_ATHDIAG_WRITE_RESP_V01 0x0031 +#define QMI_WLFW_WLAN_MODE_REQ_V01 0x0022 +#define QMI_WLFW_IND_REGISTER_REQ_V01 0x0020 +#define QMI_WLFW_WLAN_CFG_RESP_V01 0x0023 +#define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035 +#define QMI_WLFW_REJUVENATE_IND_V01 0x0039 +#define QMI_WLFW_DYNAMIC_FEATURE_MASK_REQ_V01 0x003B +#define QMI_WLFW_ATHDIAG_WRITE_REQ_V01 0x0031 +#define QMI_WLFW_WLAN_MODE_RESP_V01 0x0022 +#define QMI_WLFW_RESPOND_MEM_REQ_V01 0x0036 +#define QMI_WLFW_PIN_CONNECT_RESULT_IND_V01 0x002C +#define QMI_WLFW_FW_READY_IND_V01 0x0021 +#define QMI_WLFW_MSA_READY_RESP_V01 0x002E +#define QMI_WLFW_CAL_UPDATE_REQ_V01 0x0029 +#define QMI_WLFW_INI_REQ_V01 0x002F +#define QMI_WLFW_BDF_DOWNLOAD_RESP_V01 0x0025 +#define QMI_WLFW_REJUVENATE_ACK_RESP_V01 0x003A +#define QMI_WLFW_MSA_INFO_RESP_V01 0x002D +#define QMI_WLFW_MSA_READY_REQ_V01 0x002E +#define QMI_WLFW_CAP_RESP_V01 0x0024 +#define QMI_WLFW_REJUVENATE_ACK_REQ_V01 0x003A +#define QMI_WLFW_ATHDIAG_READ_RESP_V01 0x0030 +#define QMI_WLFW_VBATT_REQ_V01 0x0032 +#define QMI_WLFW_MAC_ADDR_REQ_V01 0x0033 +#define QMI_WLFW_RESPOND_MEM_RESP_V01 0x0036 +#define QMI_WLFW_VBATT_RESP_V01 0x0032 +#define QMI_WLFW_MSA_INFO_REQ_V01 0x002D +#define QMI_WLFW_CAL_DOWNLOAD_REQ_V01 0x0027 +#define QMI_WLFW_ATHDIAG_READ_REQ_V01 0x0030 +#define QMI_WLFW_WLAN_CFG_REQ_V01 0x0023 +#define QMI_WLFW_IND_REGISTER_RESP_V01 0x0020 + +#define QMI_WLFW_MAX_MEM_REG_V01 2 +#define QMI_WLFW_MAX_NUM_MEM_SEG_V01 16 +#define QMI_WLFW_MAX_NUM_CAL_V01 5 +#define QMI_WLFW_MAX_DATA_SIZE_V01 6144 +#define QMI_WLFW_FUNCTION_NAME_LEN_V01 128 +#define QMI_WLFW_MAX_NUM_CE_V01 12 +#define QMI_WLFW_MAX_TIMESTAMP_LEN_V01 32 +#define QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01 6144 +#define QMI_WLFW_MAX_NUM_GPIO_V01 32 +#define QMI_WLFW_MAX_BUILD_ID_LEN_V01 128 +#define QMI_WLFW_MAX_NUM_MEM_CFG_V01 2 +#define QMI_WLFW_MAX_STR_LEN_V01 16 +#define QMI_WLFW_MAX_NUM_SHADOW_REG_V01 24 +#define QMI_WLFW_MAC_ADDR_SIZE_V01 6 +#define QMI_WLFW_MAX_SHADOW_REG_V2 36 +#define QMI_WLFW_MAX_NUM_SVC_V01 24 + +enum wlfw_driver_mode_enum_v01 { + QMI_WLFW_MISSION_V01 = 0, + QMI_WLFW_FTM_V01 = 1, + QMI_WLFW_EPPING_V01 = 2, + QMI_WLFW_WALTEST_V01 = 3, + QMI_WLFW_OFF_V01 = 4, + QMI_WLFW_CCPM_V01 = 5, + QMI_WLFW_QVIT_V01 = 6, + QMI_WLFW_CALIBRATION_V01 = 7, +}; + +enum wlfw_cal_temp_id_enum_v01 { + QMI_WLFW_CAL_TEMP_IDX_0_V01 = 0, + QMI_WLFW_CAL_TEMP_IDX_1_V01 = 1, + QMI_WLFW_CAL_TEMP_IDX_2_V01 = 2, + QMI_WLFW_CAL_TEMP_IDX_3_V01 = 3, + QMI_WLFW_CAL_TEMP_IDX_4_V01 = 4, +}; + +enum wlfw_pipedir_enum_v01 { + QMI_WLFW_PIPEDIR_NONE_V01 = 0, + QMI_WLFW_PIPEDIR_IN_V01 = 1, + QMI_WLFW_PIPEDIR_OUT_V01 = 2, + QMI_WLFW_PIPEDIR_INOUT_V01 = 3, +}; + +enum wlfw_mem_type_enum_v01 { + QMI_WLFW_MEM_TYPE_MSA_V01 = 0, + QMI_WLFW_MEM_TYPE_DDR_V01 = 1, +}; + +#define QMI_WLFW_CE_ATTR_FLAGS_V01 ((u32)0x00) +#define QMI_WLFW_CE_ATTR_NO_SNOOP_V01 ((u32)0x01) +#define QMI_WLFW_CE_ATTR_BYTE_SWAP_DATA_V01 ((u32)0x02) +#define QMI_WLFW_CE_ATTR_SWIZZLE_DESCRIPTORS_V01 ((u32)0x04) +#define QMI_WLFW_CE_ATTR_DISABLE_INTR_V01 ((u32)0x08) +#define QMI_WLFW_CE_ATTR_ENABLE_POLL_V01 ((u32)0x10) + +#define QMI_WLFW_ALREADY_REGISTERED_V01 ((u64)0x01ULL) +#define QMI_WLFW_FW_READY_V01 ((u64)0x02ULL) +#define QMI_WLFW_MSA_READY_V01 ((u64)0x04ULL) +#define QMI_WLFW_MEM_READY_V01 ((u64)0x08ULL) +#define QMI_WLFW_FW_INIT_DONE_V01 ((u64)0x10ULL) + +#define QMI_WLFW_FW_REJUVENATE_V01 ((u64)0x01ULL) + +struct wlfw_ce_tgt_pipe_cfg_s_v01 { + __le32 pipe_num; + __le32 pipe_dir; + __le32 nentries; + __le32 nbytes_max; + __le32 flags; +}; + +struct wlfw_ce_svc_pipe_cfg_s_v01 { + __le32 service_id; + __le32 pipe_dir; + __le32 pipe_num; +}; + +struct wlfw_shadow_reg_cfg_s_v01 { + u16 id; + u16 offset; +}; + +struct wlfw_shadow_reg_v2_cfg_s_v01 { + u32 addr; +}; + +struct wlfw_memory_region_info_s_v01 { + u64 region_addr; + u32 size; + u8 secure_flag; +}; + +struct wlfw_mem_cfg_s_v01 { + u64 offset; + u32 size; + u8 secure_flag; +}; + +struct wlfw_mem_seg_s_v01 { + u32 size; + enum wlfw_mem_type_enum_v01 type; + u32 mem_cfg_len; + struct wlfw_mem_cfg_s_v01 mem_cfg[QMI_WLFW_MAX_NUM_MEM_CFG_V01]; +}; + +struct wlfw_mem_seg_resp_s_v01 { + u64 addr; + u32 size; + enum wlfw_mem_type_enum_v01 type; +}; + +struct wlfw_rf_chip_info_s_v01 { + u32 chip_id; + u32 chip_family; +}; + +struct wlfw_rf_board_info_s_v01 { + u32 board_id; +}; + +struct wlfw_soc_info_s_v01 { + u32 soc_id; +}; + +struct wlfw_fw_version_info_s_v01 { + u32 fw_version; + char fw_build_timestamp[QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1]; +}; + +struct wlfw_ind_register_req_msg_v01 { + u8 fw_ready_enable_valid; + u8 fw_ready_enable; + u8 initiate_cal_download_enable_valid; + u8 initiate_cal_download_enable; + u8 initiate_cal_update_enable_valid; + u8 initiate_cal_update_enable; + u8 msa_ready_enable_valid; + u8 msa_ready_enable; + u8 pin_connect_result_enable_valid; + u8 pin_connect_result_enable; + u8 client_id_valid; + u32 client_id; + u8 request_mem_enable_valid; + u8 request_mem_enable; + u8 mem_ready_enable_valid; + u8 mem_ready_enable; + u8 fw_init_done_enable_valid; + u8 fw_init_done_enable; + u8 rejuvenate_enable_valid; + u32 rejuvenate_enable; + u8 xo_cal_enable_valid; + u8 xo_cal_enable; +}; + +#define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 50 +extern struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[]; + +struct wlfw_ind_register_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u8 fw_status_valid; + u64 fw_status; +}; + +#define WLFW_IND_REGISTER_RESP_MSG_V01_MAX_MSG_LEN 18 +extern struct qmi_elem_info wlfw_ind_register_resp_msg_v01_ei[]; + +struct wlfw_fw_ready_ind_msg_v01 { + char placeholder; +}; + +#define WLFW_FW_READY_IND_MSG_V01_MAX_MSG_LEN 0 +extern struct qmi_elem_info wlfw_fw_ready_ind_msg_v01_ei[]; + +struct wlfw_msa_ready_ind_msg_v01 { + char placeholder; +}; + +#define WLFW_MSA_READY_IND_MSG_V01_MAX_MSG_LEN 0 +extern struct qmi_elem_info wlfw_msa_ready_ind_msg_v01_ei[]; + +struct wlfw_pin_connect_result_ind_msg_v01 { + u8 pwr_pin_result_valid; + u32 pwr_pin_result; + u8 phy_io_pin_result_valid; + u32 phy_io_pin_result; + u8 rf_pin_result_valid; + u32 rf_pin_result; +}; + +#define WLFW_PIN_CONNECT_RESULT_IND_MSG_V01_MAX_MSG_LEN 21 +extern struct qmi_elem_info wlfw_pin_connect_result_ind_msg_v01_ei[]; + +struct wlfw_wlan_mode_req_msg_v01 { + enum wlfw_driver_mode_enum_v01 mode; + u8 hw_debug_valid; + u8 hw_debug; +}; + +#define WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN 11 +extern struct qmi_elem_info wlfw_wlan_mode_req_msg_v01_ei[]; + +struct wlfw_wlan_mode_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_WLAN_MODE_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_wlan_mode_resp_msg_v01_ei[]; + +struct wlfw_wlan_cfg_req_msg_v01 { + u8 host_version_valid; + char host_version[QMI_WLFW_MAX_STR_LEN_V01 + 1]; + u8 tgt_cfg_valid; + u32 tgt_cfg_len; + struct wlfw_ce_tgt_pipe_cfg_s_v01 tgt_cfg[QMI_WLFW_MAX_NUM_CE_V01]; + u8 svc_cfg_valid; + u32 svc_cfg_len; + struct wlfw_ce_svc_pipe_cfg_s_v01 svc_cfg[QMI_WLFW_MAX_NUM_SVC_V01]; + u8 shadow_reg_valid; + u32 shadow_reg_len; + struct wlfw_shadow_reg_cfg_s_v01 shadow_reg[QMI_WLFW_MAX_NUM_SHADOW_REG_V01]; + u8 shadow_reg_v2_valid; + u32 shadow_reg_v2_len; + struct wlfw_shadow_reg_v2_cfg_s_v01 shadow_reg_v2[QMI_WLFW_MAX_SHADOW_REG_V2]; +}; + +#define WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN 803 +extern struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[]; + +struct wlfw_wlan_cfg_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_WLAN_CFG_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_wlan_cfg_resp_msg_v01_ei[]; + +struct wlfw_cap_req_msg_v01 { + char placeholder; +}; + +#define WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN 0 +extern struct qmi_elem_info wlfw_cap_req_msg_v01_ei[]; + +struct wlfw_cap_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u8 chip_info_valid; + struct wlfw_rf_chip_info_s_v01 chip_info; + u8 board_info_valid; + struct wlfw_rf_board_info_s_v01 board_info; + u8 soc_info_valid; + struct wlfw_soc_info_s_v01 soc_info; + u8 fw_version_info_valid; + struct wlfw_fw_version_info_s_v01 fw_version_info; + u8 fw_build_id_valid; + char fw_build_id[QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1]; + u8 num_macs_valid; + u8 num_macs; +}; + +#define WLFW_CAP_RESP_MSG_V01_MAX_MSG_LEN 207 +extern struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[]; + +struct wlfw_bdf_download_req_msg_v01 { + u8 valid; + u8 file_id_valid; + enum wlfw_cal_temp_id_enum_v01 file_id; + u8 total_size_valid; + u32 total_size; + u8 seg_id_valid; + u32 seg_id; + u8 data_valid; + u32 data_len; + u8 data[QMI_WLFW_MAX_DATA_SIZE_V01]; + u8 end_valid; + u8 end; + u8 bdf_type_valid; + u8 bdf_type; +}; + +#define WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6182 +extern struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[]; + +struct wlfw_bdf_download_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_BDF_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_bdf_download_resp_msg_v01_ei[]; + +struct wlfw_cal_report_req_msg_v01 { + u32 meta_data_len; + enum wlfw_cal_temp_id_enum_v01 meta_data[QMI_WLFW_MAX_NUM_CAL_V01]; + u8 xo_cal_data_valid; + u8 xo_cal_data; +}; + +#define WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN 28 +extern struct qmi_elem_info wlfw_cal_report_req_msg_v01_ei[]; + +struct wlfw_cal_report_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_CAL_REPORT_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_cal_report_resp_msg_v01_ei[]; + +struct wlfw_initiate_cal_download_ind_msg_v01 { + enum wlfw_cal_temp_id_enum_v01 cal_id; +}; + +#define WLFW_INITIATE_CAL_DOWNLOAD_IND_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[]; + +struct wlfw_cal_download_req_msg_v01 { + u8 valid; + u8 file_id_valid; + enum wlfw_cal_temp_id_enum_v01 file_id; + u8 total_size_valid; + u32 total_size; + u8 seg_id_valid; + u32 seg_id; + u8 data_valid; + u32 data_len; + u8 data[QMI_WLFW_MAX_DATA_SIZE_V01]; + u8 end_valid; + u8 end; +}; + +#define WLFW_CAL_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6178 +extern struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[]; + +struct wlfw_cal_download_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_CAL_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_cal_download_resp_msg_v01_ei[]; + +struct wlfw_initiate_cal_update_ind_msg_v01 { + enum wlfw_cal_temp_id_enum_v01 cal_id; + u32 total_size; +}; + +#define WLFW_INITIATE_CAL_UPDATE_IND_MSG_V01_MAX_MSG_LEN 14 +extern struct qmi_elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[]; + +struct wlfw_cal_update_req_msg_v01 { + enum wlfw_cal_temp_id_enum_v01 cal_id; + u32 seg_id; +}; + +#define WLFW_CAL_UPDATE_REQ_MSG_V01_MAX_MSG_LEN 14 +extern struct qmi_elem_info wlfw_cal_update_req_msg_v01_ei[]; + +struct wlfw_cal_update_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u8 file_id_valid; + enum wlfw_cal_temp_id_enum_v01 file_id; + u8 total_size_valid; + u32 total_size; + u8 seg_id_valid; + u32 seg_id; + u8 data_valid; + u32 data_len; + u8 data[QMI_WLFW_MAX_DATA_SIZE_V01]; + u8 end_valid; + u8 end; +}; + +#define WLFW_CAL_UPDATE_RESP_MSG_V01_MAX_MSG_LEN 6181 +extern struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[]; + +struct wlfw_msa_info_req_msg_v01 { + u64 msa_addr; + u32 size; +}; + +#define WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN 18 +extern struct qmi_elem_info wlfw_msa_info_req_msg_v01_ei[]; + +struct wlfw_msa_info_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u32 mem_region_info_len; + struct wlfw_memory_region_info_s_v01 mem_region_info[QMI_WLFW_MAX_MEM_REG_V01]; +}; + +#define WLFW_MSA_INFO_RESP_MSG_V01_MAX_MSG_LEN 37 +extern struct qmi_elem_info wlfw_msa_info_resp_msg_v01_ei[]; + +struct wlfw_msa_ready_req_msg_v01 { + char placeholder; +}; + +#define WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN 0 +extern struct qmi_elem_info wlfw_msa_ready_req_msg_v01_ei[]; + +struct wlfw_msa_ready_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_MSA_READY_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_msa_ready_resp_msg_v01_ei[]; + +struct wlfw_ini_req_msg_v01 { + u8 enablefwlog_valid; + u8 enablefwlog; +}; + +#define WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN 4 +extern struct qmi_elem_info wlfw_ini_req_msg_v01_ei[]; + +struct wlfw_ini_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_INI_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_ini_resp_msg_v01_ei[]; + +struct wlfw_athdiag_read_req_msg_v01 { + u32 offset; + u32 mem_type; + u32 data_len; +}; + +#define WLFW_ATHDIAG_READ_REQ_MSG_V01_MAX_MSG_LEN 21 +extern struct qmi_elem_info wlfw_athdiag_read_req_msg_v01_ei[]; + +struct wlfw_athdiag_read_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u8 data_valid; + u32 data_len; + u8 data[QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01]; +}; + +#define WLFW_ATHDIAG_READ_RESP_MSG_V01_MAX_MSG_LEN 6156 +extern struct qmi_elem_info wlfw_athdiag_read_resp_msg_v01_ei[]; + +struct wlfw_athdiag_write_req_msg_v01 { + u32 offset; + u32 mem_type; + u32 data_len; + u8 data[QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01]; +}; + +#define WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN 6163 +extern struct qmi_elem_info wlfw_athdiag_write_req_msg_v01_ei[]; + +struct wlfw_athdiag_write_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_ATHDIAG_WRITE_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_athdiag_write_resp_msg_v01_ei[]; + +struct wlfw_vbatt_req_msg_v01 { + u64 voltage_uv; +}; + +#define WLFW_VBATT_REQ_MSG_V01_MAX_MSG_LEN 11 +extern struct qmi_elem_info wlfw_vbatt_req_msg_v01_ei[]; + +struct wlfw_vbatt_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_VBATT_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_vbatt_resp_msg_v01_ei[]; + +struct wlfw_mac_addr_req_msg_v01 { + u8 mac_addr_valid; + u8 mac_addr[QMI_WLFW_MAC_ADDR_SIZE_V01]; +}; + +#define WLFW_MAC_ADDR_REQ_MSG_V01_MAX_MSG_LEN 9 +extern struct qmi_elem_info wlfw_mac_addr_req_msg_v01_ei[]; + +struct wlfw_mac_addr_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_MAC_ADDR_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_mac_addr_resp_msg_v01_ei[]; + +struct wlfw_host_cap_req_msg_v01 { + u8 daemon_support_valid; + u8 daemon_support; +}; + +#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 4 +extern struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[]; + +struct wlfw_host_cap_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_HOST_CAP_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_host_cap_resp_msg_v01_ei[]; + +struct wlfw_request_mem_ind_msg_v01 { + u32 mem_seg_len; + struct wlfw_mem_seg_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01]; +}; + +#define WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN 564 +extern struct qmi_elem_info wlfw_request_mem_ind_msg_v01_ei[]; + +struct wlfw_respond_mem_req_msg_v01 { + u32 mem_seg_len; + struct wlfw_mem_seg_resp_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01]; +}; + +#define WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN 260 +extern struct qmi_elem_info wlfw_respond_mem_req_msg_v01_ei[]; + +struct wlfw_respond_mem_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_RESPOND_MEM_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_respond_mem_resp_msg_v01_ei[]; + +struct wlfw_mem_ready_ind_msg_v01 { + char placeholder; +}; + +#define WLFW_MEM_READY_IND_MSG_V01_MAX_MSG_LEN 0 +extern struct qmi_elem_info wlfw_mem_ready_ind_msg_v01_ei[]; + +struct wlfw_fw_init_done_ind_msg_v01 { + char placeholder; +}; + +#define WLFW_FW_INIT_DONE_IND_MSG_V01_MAX_MSG_LEN 0 +extern struct qmi_elem_info wlfw_fw_init_done_ind_msg_v01_ei[]; + +struct wlfw_rejuvenate_ind_msg_v01 { + u8 cause_for_rejuvenation_valid; + u8 cause_for_rejuvenation; + u8 requesting_sub_system_valid; + u8 requesting_sub_system; + u8 line_number_valid; + u16 line_number; + u8 function_name_valid; + char function_name[QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1]; +}; + +#define WLFW_REJUVENATE_IND_MSG_V01_MAX_MSG_LEN 144 +extern struct qmi_elem_info wlfw_rejuvenate_ind_msg_v01_ei[]; + +struct wlfw_rejuvenate_ack_req_msg_v01 { + char placeholder; +}; + +#define WLFW_REJUVENATE_ACK_REQ_MSG_V01_MAX_MSG_LEN 0 +extern struct qmi_elem_info wlfw_rejuvenate_ack_req_msg_v01_ei[]; + +struct wlfw_rejuvenate_ack_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_REJUVENATE_ACK_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_rejuvenate_ack_resp_msg_v01_ei[]; + +struct wlfw_dynamic_feature_mask_req_msg_v01 { + u8 mask_valid; + u64 mask; +}; + +#define WLFW_DYNAMIC_FEATURE_MASK_REQ_MSG_V01_MAX_MSG_LEN 11 +extern struct qmi_elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[]; + +struct wlfw_dynamic_feature_mask_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u8 prev_mask_valid; + u64 prev_mask; + u8 curr_mask_valid; + u64 curr_mask; +}; + +#define WLFW_DYNAMIC_FEATURE_MASK_RESP_MSG_V01_MAX_MSG_LEN 29 +extern struct qmi_elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[]; + +struct wlfw_m3_info_req_msg_v01 { + u64 addr; + u32 size; +}; + +#define WLFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN 18 +extern struct qmi_elem_info wlfw_m3_info_req_msg_v01_ei[]; + +struct wlfw_m3_info_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WLFW_M3_INFO_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wlfw_m3_info_resp_msg_v01_ei[]; + +struct wlfw_xo_cal_ind_msg_v01 { + u8 xo_cal_data; +}; + +#define WLFW_XO_CAL_IND_MSG_V01_MAX_MSG_LEN 4 +extern struct qmi_elem_info wlfw_xo_cal_ind_msg_v01_ei[]; + +#endif From c639c35e50a8e0e8413646635085b2854c6688e9 Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Thu, 11 Oct 2018 13:11:45 +0300 Subject: [PATCH 091/192] UPSTREAM: ath10k: add support to create boardname for non-bmi target Add support to create the boardname for non-bmi targets like WCN3990, which uses qmi for bdf download. This boardname is used to parse the board data from board-2.bin. Signed-off-by: Rakesh Pillai Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: 22e8a46027387b4e8db75f73ede9bbf337115e9c Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I7973771be15b01fd89ec15d6880307ea18dd9372 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/core.c | 8 ++++++++ drivers/net/wireless/ath/ath10k/core.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 8716ea495aea..c0719a68a102 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1370,6 +1370,14 @@ static int ath10k_core_create_board_name(struct ath10k *ar, char *name, goto out; } + if (ar->id.qmi_ids_valid) { + scnprintf(name, name_len, + "bus=%s,qmi-board-id=%x", + ath10k_bus_str(ar->hif.bus), + ar->id.qmi_board_id); + goto out; + } + scnprintf(name, name_len, "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x%s", ath10k_bus_str(ar->hif.bus), diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index fe6b30356d3b..ee7d1e0035d4 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -835,6 +835,8 @@ struct ath10k { u32 subsystem_device; bool bmi_ids_valid; + bool qmi_ids_valid; + u32 qmi_board_id; u8 bmi_board_id; u8 bmi_chip_id; From 8800d923ef329b072ff5ea8b869838d55b53df53 Mon Sep 17 00:00:00 2001 From: Sivakanth vaka Date: Fri, 10 Jul 2020 14:30:44 +0530 Subject: [PATCH 092/192] MDM:IPA3: Fixes issue with RNDIS and ECM suspend path PM resources are released even when there are outstanding packets leading to data stall hence resources are released only when there are no outstanding packets. Change-Id: I630737edfc9cadea1d8a99bdb6bb6fcbe76615d8 Signed-off-by: sivakanth vaka --- drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c | 8 ++++++-- drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c | 9 +++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c index 02253135bbf2..b8d4bc4adece 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c +++ b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -668,7 +668,8 @@ static netdev_tx_t ecm_ipa_start_xmit fail_tx_packet: out: - resource_release(ecm_ipa_ctx); + if (atomic_read(&ecm_ipa_ctx->outstanding_pkts) == 0) + resource_release(ecm_ipa_ctx); resource_busy: return status; } @@ -1340,6 +1341,9 @@ static void ecm_ipa_tx_complete_notify netif_wake_queue(ecm_ipa_ctx->net); } + if (atomic_read(&ecm_ipa_ctx->outstanding_pkts) == 0) + resource_release(ecm_ipa_ctx); + out: dev_kfree_skb_any(skb); } diff --git a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c index 7aa28cad3242..0612e97e3813 100644 --- a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c +++ b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -996,7 +996,8 @@ static netdev_tx_t rndis_ipa_start_xmit(struct sk_buff *skb, fail_tx_packet: rndis_ipa_xmit_error(skb); out: - resource_release(rndis_ipa_ctx); + if (atomic_read(&rndis_ipa_ctx->outstanding_pkts) == 0) + resource_release(rndis_ipa_ctx); resource_busy: RNDIS_IPA_DEBUG ("packet Tx done - %s\n", @@ -1069,6 +1070,10 @@ static void rndis_ipa_tx_complete_notify( RNDIS_IPA_DEBUG("send queue was awaken\n"); } + /*Release resource only when outstanding packets are zero*/ + if (atomic_read(&rndis_ipa_ctx->outstanding_pkts) == 0) + resource_release(rndis_ipa_ctx); + out: dev_kfree_skb_any(skb); } From b601ea1cfdcf2895ab80889bdefb011585946ff5 Mon Sep 17 00:00:00 2001 From: Sivakanth vaka Date: Thu, 16 Jul 2020 19:19:16 +0530 Subject: [PATCH 093/192] msm: ipa3: Enable holb as part of usb suspend When USB is suspended there are DL packets on consumer channel leading to stall. to avoid the stall enabling the holb as part of suspend and removing it in resume. Change-Id: I08e2fe248ee675698da16b6df6aec8f109c73608 Signed-off-by: sivakanth vaka --- drivers/platform/msm/ipa/ipa_v3/ipa_client.c | 28 ++++++++++++++++++++ drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 1 + 2 files changed, 29 insertions(+) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index 9eb1be2db085..59773b27782a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -1521,6 +1521,7 @@ int ipa3_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, struct gsi_chan_info ul_gsi_chan_info, dl_gsi_chan_info; int aggr_active_bitmap = 0; struct ipa_ep_cfg_ctrl ep_cfg_ctrl; + struct ipa_ep_cfg_holb holb_cfg; /* In case of DPL, dl is the DPL channel/client */ @@ -1606,6 +1607,15 @@ int ipa3_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, goto unsuspend_dl_and_exit; } + /*enable holb to discard the packets*/ + if (ipa3_ctx->ipa_hw_type == IPA_HW_v4_5 && + IPA_CLIENT_IS_CONS(dl_ep->client) && !is_dpl) { + memset(&holb_cfg, 0, sizeof(holb_cfg)); + holb_cfg.en = IPA_HOLB_TMR_EN; + holb_cfg.tmr_val = IPA_HOLB_TMR_VAL_4_5; + result = ipa3_cfg_ep_holb(dl_clnt_hdl, &holb_cfg); + } + /* Stop DL channel */ result = ipa3_stop_gsi_channel(dl_clnt_hdl); if (result) { @@ -1635,6 +1645,14 @@ int ipa3_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, start_dl_and_exit: gsi_start_channel(dl_ep->gsi_chan_hdl); ipa3_start_gsi_debug_monitor(dl_clnt_hdl); + /*disable holb to allow packets*/ + if (ipa3_ctx->ipa_hw_type == IPA_HW_v4_5 && + IPA_CLIENT_IS_CONS(dl_ep->client) && !is_dpl) { + memset(&holb_cfg, 0, sizeof(holb_cfg)); + holb_cfg.en = IPA_HOLB_TMR_DIS; + holb_cfg.tmr_val = 0; + ipa3_cfg_ep_holb(dl_clnt_hdl, &holb_cfg); + } unsuspend_dl_and_exit: if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) { /* Unsuspend the DL EP */ @@ -1691,6 +1709,7 @@ int ipa3_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, bool is_dpl) struct ipa3_ep_context *dl_ep = NULL; enum gsi_status gsi_res; struct ipa_ep_cfg_ctrl ep_cfg_ctrl; + struct ipa_ep_cfg_holb holb_cfg; /* In case of DPL, dl is the DPL channel/client */ @@ -1721,6 +1740,15 @@ int ipa3_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, bool is_dpl) IPAERR("Error starting DL channel: %d\n", gsi_res); ipa3_start_gsi_debug_monitor(dl_clnt_hdl); + /*disable holb to allow packets*/ + if (ipa3_ctx->ipa_hw_type == IPA_HW_v4_5 && + IPA_CLIENT_IS_CONS(dl_ep->client) && !is_dpl) { + memset(&holb_cfg, 0, sizeof(holb_cfg)); + holb_cfg.en = IPA_HOLB_TMR_DIS; + holb_cfg.tmr_val = 0; + ipa3_cfg_ep_holb(dl_clnt_hdl, &holb_cfg); + } + /* Start UL channel */ if (!is_dpl) { gsi_res = gsi_start_channel(ul_ep->gsi_chan_hdl); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index c66078049ac0..306106272800 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -71,6 +71,7 @@ #define IPA_HOLB_TMR_DIS 0x0 #define IPA_HOLB_TMR_EN 0x1 #define IPA_HOLB_TMR_VAL 65535 +#define IPA_HOLB_TMR_VAL_4_5 31 /* * The transport descriptor size was changed to GSI_CHAN_RE_SIZE_16B, but * IPA users still use sps_iovec size as FIFO element size. From 96d9afe6452947c8b1cff9f825335998d119023b Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 12 Jun 2018 13:39:06 +0200 Subject: [PATCH 094/192] UPSTREAM: ath10k: allow ATH10K_SNOC with COMPILE_TEST ATH10K_SNOC builds just fine with COMPILE_TEST, so make that possible. Change-Id: Ia49d16f5c1a8e448ff3a9aa79ce935bfbd02d39c Signed-off-by: Niklas Cassel Signed-off-by: Kalle Valo Git-commit: f1908735f141f662fbf04436e6efc1560418b5a0 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index 54ff5930126c..6572a43590a8 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -42,7 +42,8 @@ config ATH10K_USB config ATH10K_SNOC tristate "Qualcomm ath10k SNOC support (EXPERIMENTAL)" - depends on ATH10K && ARCH_QCOM + depends on ATH10K + depends on ARCH_QCOM || COMPILE_TEST ---help--- This module adds support for integrated WCN3990 chip connected to system NOC(SNOC). Currently work in progress and will not From b9d72806b322a44ba84fdc0a0866868a5dd88258 Mon Sep 17 00:00:00 2001 From: Sathishkumar Muruganandam Date: Mon, 3 Sep 2018 20:07:50 +0300 Subject: [PATCH 095/192] UPSTREAM: ath10k: refactoring needed for extended board data download Just moving functions down in the file, no functional changes. Change-Id: Iab310aa2761f3e7d1e38d9433ca79171c82d5e12 Signed-off-by: Sathishkumar Muruganandam Signed-off-by: Kalle Valo Git-commit: 5849ed48d226523fd53863104d6aff5052674c1b Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/core.c | 402 ++++++++++++------------- 1 file changed, 201 insertions(+), 201 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index c0719a68a102..e3894f252a18 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -693,149 +693,6 @@ static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data, return 0; } -static int ath10k_download_board_data(struct ath10k *ar, const void *data, - size_t data_len) -{ - u32 board_data_size = ar->hw_params.fw.board_size; - u32 address; - int ret; - - ret = ath10k_push_board_ext_data(ar, data, data_len); - if (ret) { - ath10k_err(ar, "could not push board ext data (%d)\n", ret); - goto exit; - } - - ret = ath10k_bmi_read32(ar, hi_board_data, &address); - if (ret) { - ath10k_err(ar, "could not read board data addr (%d)\n", ret); - goto exit; - } - - ret = ath10k_bmi_write_memory(ar, address, data, - min_t(u32, board_data_size, - data_len)); - if (ret) { - ath10k_err(ar, "could not write board data (%d)\n", ret); - goto exit; - } - - ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1); - if (ret) { - ath10k_err(ar, "could not write board data bit (%d)\n", ret); - goto exit; - } - -exit: - return ret; -} - -static int ath10k_download_cal_file(struct ath10k *ar, - const struct firmware *file) -{ - int ret; - - if (!file) - return -ENOENT; - - if (IS_ERR(file)) - return PTR_ERR(file); - - ret = ath10k_download_board_data(ar, file->data, file->size); - if (ret) { - ath10k_err(ar, "failed to download cal_file data: %d\n", ret); - return ret; - } - - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cal file downloaded\n"); - - return 0; -} - -static int ath10k_download_cal_dt(struct ath10k *ar, const char *dt_name) -{ - struct device_node *node; - int data_len; - void *data; - int ret; - - node = ar->dev->of_node; - if (!node) - /* Device Tree is optional, don't print any warnings if - * there's no node for ath10k. - */ - return -ENOENT; - - if (!of_get_property(node, dt_name, &data_len)) { - /* The calibration data node is optional */ - return -ENOENT; - } - - if (data_len != ar->hw_params.cal_data_len) { - ath10k_warn(ar, "invalid calibration data length in DT: %d\n", - data_len); - ret = -EMSGSIZE; - goto out; - } - - data = kmalloc(data_len, GFP_KERNEL); - if (!data) { - ret = -ENOMEM; - goto out; - } - - ret = of_property_read_u8_array(node, dt_name, data, data_len); - if (ret) { - ath10k_warn(ar, "failed to read calibration data from DT: %d\n", - ret); - goto out_free; - } - - ret = ath10k_download_board_data(ar, data, data_len); - if (ret) { - ath10k_warn(ar, "failed to download calibration data from Device Tree: %d\n", - ret); - goto out_free; - } - - ret = 0; - -out_free: - kfree(data); - -out: - return ret; -} - -static int ath10k_download_cal_eeprom(struct ath10k *ar) -{ - size_t data_len; - void *data = NULL; - int ret; - - ret = ath10k_hif_fetch_cal_eeprom(ar, &data, &data_len); - if (ret) { - if (ret != -EOPNOTSUPP) - ath10k_warn(ar, "failed to read calibration data from EEPROM: %d\n", - ret); - goto out_free; - } - - ret = ath10k_download_board_data(ar, data, data_len); - if (ret) { - ath10k_warn(ar, "failed to download calibration data from EEPROM: %d\n", - ret); - goto out_free; - } - - ret = 0; - -out_free: - kfree(data); - - return ret; -} - static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) { u32 result, address; @@ -986,64 +843,6 @@ static int ath10k_core_check_dt(struct ath10k *ar) return 0; } -static int ath10k_download_and_run_otp(struct ath10k *ar) -{ - u32 result, address = ar->hw_params.patch_load_addr; - u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param; - int ret; - - ret = ath10k_download_board_data(ar, - ar->running_fw->board_data, - ar->running_fw->board_len); - if (ret) { - ath10k_err(ar, "failed to download board data: %d\n", ret); - return ret; - } - - /* OTP is optional */ - - if (!ar->running_fw->fw_file.otp_data || - !ar->running_fw->fw_file.otp_len) { - ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %pK otp_len %zd)!\n", - ar->running_fw->fw_file.otp_data, - ar->running_fw->fw_file.otp_len); - return 0; - } - - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n", - address, ar->running_fw->fw_file.otp_len); - - ret = ath10k_bmi_fast_download(ar, address, - ar->running_fw->fw_file.otp_data, - ar->running_fw->fw_file.otp_len); - if (ret) { - ath10k_err(ar, "could not write otp (%d)\n", ret); - return ret; - } - - /* As of now pre-cal is valid for 10_4 variants */ - if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT || - ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE) - bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL; - - ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result); - if (ret) { - ath10k_err(ar, "could not execute otp (%d)\n", ret); - return ret; - } - - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); - - if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT, - ar->running_fw->fw_file.fw_features)) && - result != 0) { - ath10k_err(ar, "otp calibration failed: %d", result); - return -EINVAL; - } - - return 0; -} - static int ath10k_download_fw(struct ath10k *ar) { u32 address, data_len; @@ -1419,6 +1218,207 @@ static int ath10k_core_fetch_board_file(struct ath10k *ar) return 0; } +static int ath10k_download_board_data(struct ath10k *ar, const void *data, + size_t data_len) +{ + u32 board_data_size = ar->hw_params.fw.board_size; + u32 address; + int ret; + + ret = ath10k_push_board_ext_data(ar, data, data_len); + if (ret) { + ath10k_err(ar, "could not push board ext data (%d)\n", ret); + goto exit; + } + + ret = ath10k_bmi_read32(ar, hi_board_data, &address); + if (ret) { + ath10k_err(ar, "could not read board data addr (%d)\n", ret); + goto exit; + } + + ret = ath10k_bmi_write_memory(ar, address, data, + min_t(u32, board_data_size, + data_len)); + if (ret) { + ath10k_err(ar, "could not write board data (%d)\n", ret); + goto exit; + } + + ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1); + if (ret) { + ath10k_err(ar, "could not write board data bit (%d)\n", ret); + goto exit; + } + +exit: + return ret; +} + +static int ath10k_download_and_run_otp(struct ath10k *ar) +{ + u32 result, address = ar->hw_params.patch_load_addr; + u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param; + int ret; + + ret = ath10k_download_board_data(ar, + ar->running_fw->board_data, + ar->running_fw->board_len); + if (ret) { + ath10k_err(ar, "failed to download board data: %d\n", ret); + return ret; + } + + /* OTP is optional */ + + if (!ar->running_fw->fw_file.otp_data || + !ar->running_fw->fw_file.otp_len) { + ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %pK otp_len %zd)!\n", + ar->running_fw->fw_file.otp_data, + ar->running_fw->fw_file.otp_len); + return 0; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n", + address, ar->running_fw->fw_file.otp_len); + + ret = ath10k_bmi_fast_download(ar, address, + ar->running_fw->fw_file.otp_data, + ar->running_fw->fw_file.otp_len); + if (ret) { + ath10k_err(ar, "could not write otp (%d)\n", ret); + return ret; + } + + /* As of now pre-cal is valid for 10_4 variants */ + if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT || + ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE) + bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL; + + ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result); + if (ret) { + ath10k_err(ar, "could not execute otp (%d)\n", ret); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); + + if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT, + ar->running_fw->fw_file.fw_features)) && + result != 0) { + ath10k_err(ar, "otp calibration failed: %d", result); + return -EINVAL; + } + + return 0; +} + +static int ath10k_download_cal_file(struct ath10k *ar, + const struct firmware *file) +{ + int ret; + + if (!file) + return -ENOENT; + + if (IS_ERR(file)) + return PTR_ERR(file); + + ret = ath10k_download_board_data(ar, file->data, file->size); + if (ret) { + ath10k_err(ar, "failed to download cal_file data: %d\n", ret); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cal file downloaded\n"); + + return 0; +} + +static int ath10k_download_cal_dt(struct ath10k *ar, const char *dt_name) +{ + struct device_node *node; + int data_len; + void *data; + int ret; + + node = ar->dev->of_node; + if (!node) + /* Device Tree is optional, don't print any warnings if + * there's no node for ath10k. + */ + return -ENOENT; + + if (!of_get_property(node, dt_name, &data_len)) { + /* The calibration data node is optional */ + return -ENOENT; + } + + if (data_len != ar->hw_params.cal_data_len) { + ath10k_warn(ar, "invalid calibration data length in DT: %d\n", + data_len); + ret = -EMSGSIZE; + goto out; + } + + data = kmalloc(data_len, GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto out; + } + + ret = of_property_read_u8_array(node, dt_name, data, data_len); + if (ret) { + ath10k_warn(ar, "failed to read calibration data from DT: %d\n", + ret); + goto out_free; + } + + ret = ath10k_download_board_data(ar, data, data_len); + if (ret) { + ath10k_warn(ar, "failed to download calibration data from Device Tree: %d\n", + ret); + goto out_free; + } + + ret = 0; + +out_free: + kfree(data); + +out: + return ret; +} + +static int ath10k_download_cal_eeprom(struct ath10k *ar) +{ + size_t data_len; + void *data = NULL; + int ret; + + ret = ath10k_hif_fetch_cal_eeprom(ar, &data, &data_len); + if (ret) { + if (ret != -EOPNOTSUPP) + ath10k_warn(ar, "failed to read calibration data from EEPROM: %d\n", + ret); + goto out_free; + } + + ret = ath10k_download_board_data(ar, data, data_len); + if (ret) { + ath10k_warn(ar, "failed to download calibration data from EEPROM: %d\n", + ret); + goto out_free; + } + + ret = 0; + +out_free: + kfree(data); + + return ret; +} + int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name, struct ath10k_fw_file *fw_file) { From d81ceda3501623bc23a76f4d8bf3261a9bba926a Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Tue, 4 Sep 2018 15:03:19 +0300 Subject: [PATCH 096/192] UPSTREAM: ath10k: add struct ath10k_bus_params This struct is used as argument to ath10k_core_register in order to make it easier to add more bus parameters in the future. Change-Id: I9b77f6d54759242adfac4f82580342788044ae81 Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo Git-commit: c0d8d565787c5d8f7d4b0ae319dc1d44d69a51d9 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/ahb.c | 8 ++++---- drivers/net/wireless/ath/ath10k/core.c | 5 +++-- drivers/net/wireless/ath/ath10k/core.h | 7 ++++++- drivers/net/wireless/ath/ath10k/pci.c | 12 ++++++------ drivers/net/wireless/ath/ath10k/sdio.c | 7 ++++--- drivers/net/wireless/ath/ath10k/snoc.c | 4 +++- drivers/net/wireless/ath/ath10k/usb.c | 6 +++--- 7 files changed, 29 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index 35d10490f6c3..6f902f355fca 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -758,7 +758,7 @@ static int ath10k_ahb_probe(struct platform_device *pdev) enum ath10k_hw_rev hw_rev; size_t size; int ret; - u32 chip_id; + struct ath10k_bus_params bus_params; of_id = of_match_device(ath10k_ahb_of_match, &pdev->dev); if (!of_id) { @@ -814,14 +814,14 @@ static int ath10k_ahb_probe(struct platform_device *pdev) ath10k_pci_ce_deinit(ar); - chip_id = ath10k_ahb_soc_read32(ar, SOC_CHIP_ID_ADDRESS); - if (chip_id == 0xffffffff) { + bus_params.chip_id = ath10k_ahb_soc_read32(ar, SOC_CHIP_ID_ADDRESS); + if (bus_params.chip_id == 0xffffffff) { ath10k_err(ar, "failed to get chip id\n"); ret = -ENODEV; goto err_halt_device; } - ret = ath10k_core_register(ar, chip_id); + ret = ath10k_core_register(ar, &bus_params); if (ret) { ath10k_err(ar, "failed to register driver core: %d\n", ret); goto err_halt_device; diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index e3894f252a18..28d42a298371 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2637,9 +2637,10 @@ static void ath10k_core_register_work(struct work_struct *work) return; } -int ath10k_core_register(struct ath10k *ar, u32 chip_id) +int ath10k_core_register(struct ath10k *ar, + const struct ath10k_bus_params *bus_params) { - ar->chip_id = chip_id; + ar->chip_id = bus_params->chip_id; queue_work(ar->workqueue, &ar->register_work); return 0; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index ee7d1e0035d4..13bc3afde651 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -769,6 +769,10 @@ struct ath10k_per_peer_tx_stats { u32 reserved2; }; +struct ath10k_bus_params { + u32 chip_id; +}; + struct ath10k { struct ath_common ath_common; struct ieee80211_hw *hw; @@ -1051,7 +1055,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, const struct ath10k_fw_components *fw_components); int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt); void ath10k_core_stop(struct ath10k *ar); -int ath10k_core_register(struct ath10k *ar, u32 chip_id); +int ath10k_core_register(struct ath10k *ar, + const struct ath10k_bus_params *bus_params); void ath10k_core_unregister(struct ath10k *ar); #endif /* _CORE_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 77fa45a85c7e..5c58b5ae312a 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -3420,7 +3420,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, struct ath10k *ar; struct ath10k_pci *ar_pci; enum ath10k_hw_rev hw_rev; - u32 chip_id; + struct ath10k_bus_params bus_params; bool pci_ps; int (*pci_soft_reset)(struct ath10k *ar); int (*pci_hard_reset)(struct ath10k *ar); @@ -3556,19 +3556,19 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_free_irq; } - chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); - if (chip_id == 0xffffffff) { + bus_params.chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); + if (bus_params.chip_id == 0xffffffff) { ath10k_err(ar, "failed to get chip id\n"); goto err_free_irq; } - if (!ath10k_pci_chip_is_supported(pdev->device, chip_id)) { + if (!ath10k_pci_chip_is_supported(pdev->device, bus_params.chip_id)) { ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n", - pdev->device, chip_id); + pdev->device, bus_params.chip_id); goto err_free_irq; } - ret = ath10k_core_register(ar, chip_id); + ret = ath10k_core_register(ar, &bus_params); if (ret) { ath10k_err(ar, "failed to register driver core: %d\n", ret); goto err_free_irq; diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index da9dbf3ddaa5..7e20f198b0b7 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -1938,7 +1938,8 @@ static int ath10k_sdio_probe(struct sdio_func *func, struct ath10k_sdio *ar_sdio; struct ath10k *ar; enum ath10k_hw_rev hw_rev; - u32 chip_id, dev_id_base; + u32 dev_id_base; + struct ath10k_bus_params bus_params; int ret, i; /* Assumption: All SDIO based chipsets (so far) are QCA6174 based. @@ -2033,8 +2034,8 @@ static int ath10k_sdio_probe(struct sdio_func *func, } /* TODO: don't know yet how to get chip_id with SDIO */ - chip_id = 0; - ret = ath10k_core_register(ar, chip_id); + bus_params.chip_id = 0; + ret = ath10k_core_register(ar, &bus_params); if (ret) { ath10k_err(ar, "failed to register driver core: %d\n", ret); goto err_free_wq; diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 293f5116b172..dd15057691b0 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -1271,6 +1271,7 @@ static int ath10k_snoc_probe(struct platform_device *pdev) struct ath10k *ar; int ret; u32 i; + struct ath10k_bus_params bus_params; of_id = of_match_device(ath10k_snoc_dt_match, &pdev->dev); if (!of_id) { @@ -1338,7 +1339,8 @@ static int ath10k_snoc_probe(struct platform_device *pdev) goto err_free_irq; } - ret = ath10k_core_register(ar, drv_data->hw_rev); + bus_params.chip_id = drv_data->hw_rev; + ret = ath10k_core_register(ar, &bus_params); if (ret) { ath10k_err(ar, "failed to register driver core: %d\n", ret); goto err_hw_power_off; diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c index d4803ff5a78a..275e00bafcb1 100644 --- a/drivers/net/wireless/ath/ath10k/usb.c +++ b/drivers/net/wireless/ath/ath10k/usb.c @@ -983,7 +983,7 @@ static int ath10k_usb_probe(struct usb_interface *interface, struct usb_device *dev = interface_to_usbdev(interface); int ret, vendor_id, product_id; enum ath10k_hw_rev hw_rev; - u32 chip_id; + struct ath10k_bus_params bus_params; /* Assumption: All USB based chipsets (so far) are QCA9377 based. * If there will be newer chipsets that does not use the hw reg @@ -1017,8 +1017,8 @@ static int ath10k_usb_probe(struct usb_interface *interface, ar->id.device = product_id; /* TODO: don't know yet how to get chip_id with USB */ - chip_id = 0; - ret = ath10k_core_register(ar, chip_id); + bus_params.chip_id = 0; + ret = ath10k_core_register(ar, &bus_params); if (ret) { ath10k_warn(ar, "failed to register driver core: %d\n", ret); goto err; From 419c7ea77f491f97a5a84daf73bae95fbb91becf Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Tue, 4 Sep 2018 15:03:44 +0300 Subject: [PATCH 097/192] UPSTREAM: ath10k: add device type enum to ath10k_bus_params Add dev_type parameter to struct ath10k_bus_params. The dev type specifies if the device is a high latency device (usb and sdio) or low latency device (pci, ahb and snoc) The setup of high latency chips is sometimes different than for chips using low latency interfaces. Change-Id: I64820fa08d42414b7ebaed44d3c10bd116581710 Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo Signed-off-by: Govind Singh Git-commit: 7c2dd6154fc22e2aec1fcb384beb0a6372f2b439 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/ahb.c | 1 + drivers/net/wireless/ath/ath10k/core.c | 1 + drivers/net/wireless/ath/ath10k/core.h | 7 +++++++ drivers/net/wireless/ath/ath10k/pci.c | 1 + drivers/net/wireless/ath/ath10k/sdio.c | 1 + drivers/net/wireless/ath/ath10k/snoc.c | 1 + drivers/net/wireless/ath/ath10k/usb.c | 1 + 7 files changed, 13 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index 6f902f355fca..de7450d472da 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -814,6 +814,7 @@ static int ath10k_ahb_probe(struct platform_device *pdev) ath10k_pci_ce_deinit(ar); + bus_params.dev_type = ATH10K_DEV_TYPE_LL; bus_params.chip_id = ath10k_ahb_soc_read32(ar, SOC_CHIP_ID_ADDRESS); if (bus_params.chip_id == 0xffffffff) { ath10k_err(ar, "failed to get chip id\n"); diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 28d42a298371..3c8df6a2c643 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2641,6 +2641,7 @@ int ath10k_core_register(struct ath10k *ar, const struct ath10k_bus_params *bus_params) { ar->chip_id = bus_params->chip_id; + ar->dev_type = bus_params->dev_type; queue_work(ar->workqueue, &ar->register_work); return 0; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 13bc3afde651..98c1f2ac969d 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -769,8 +769,14 @@ struct ath10k_per_peer_tx_stats { u32 reserved2; }; +enum ath10k_dev_type { + ATH10K_DEV_TYPE_LL, + ATH10K_DEV_TYPE_HL, +}; + struct ath10k_bus_params { u32 chip_id; + enum ath10k_dev_type dev_type; }; struct ath10k { @@ -783,6 +789,7 @@ struct ath10k { enum ath10k_hw_rev hw_rev; u16 dev_id; u32 chip_id; + enum ath10k_dev_type dev_type; u32 target_version; u8 fw_version_major; u32 fw_version_minor; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 5c58b5ae312a..bf9f94eda4e7 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -3556,6 +3556,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_free_irq; } + bus_params.dev_type = ATH10K_DEV_TYPE_LL; bus_params.chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); if (bus_params.chip_id == 0xffffffff) { ath10k_err(ar, "failed to get chip id\n"); diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 7e20f198b0b7..b577b161418b 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -2033,6 +2033,7 @@ static int ath10k_sdio_probe(struct sdio_func *func, goto err_free_wq; } + bus_params.dev_type = ATH10K_DEV_TYPE_HL; /* TODO: don't know yet how to get chip_id with SDIO */ bus_params.chip_id = 0; ret = ath10k_core_register(ar, &bus_params); diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index dd15057691b0..613349278a25 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -1339,6 +1339,7 @@ static int ath10k_snoc_probe(struct platform_device *pdev) goto err_free_irq; } + bus_params.dev_type = ATH10K_DEV_TYPE_LL; bus_params.chip_id = drv_data->hw_rev; ret = ath10k_core_register(ar, &bus_params); if (ret) { diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c index 275e00bafcb1..f731d35ee76d 100644 --- a/drivers/net/wireless/ath/ath10k/usb.c +++ b/drivers/net/wireless/ath/ath10k/usb.c @@ -1016,6 +1016,7 @@ static int ath10k_usb_probe(struct usb_interface *interface, ar->id.vendor = vendor_id; ar->id.device = product_id; + bus_params.dev_type = ATH10K_DEV_TYPE_HL; /* TODO: don't know yet how to get chip_id with USB */ bus_params.chip_id = 0; ret = ath10k_core_register(ar, &bus_params); From a135845f7f447aece75828d09847055c82595ec1 Mon Sep 17 00:00:00 2001 From: Thomas Hebb Date: Fri, 13 Apr 2018 17:40:26 +0300 Subject: [PATCH 098/192] UPSTREAM: ath10k: search all IEs for variant before falling back commit f2593cb1b291 ("ath10k: Search SMBIOS for OEM board file extension") added a feature to ath10k that allows Board Data File (BDF) conflicts between multiple devices that use the same device IDs but have different calibration requirements to be resolved by allowing a "variant" string to be stored in SMBIOS [and later device tree, added by commit d06f26c5c8a4 ("ath10k: search DT for qcom,ath10k-calibration- variant")] that gets appended to the ID stored in board-2.bin. This original patch had a regression, however. Namely that devices with a variant present in SMBIOS that didn't need custom BDFs could no longer find the default BDF, which has no variant appended. The patch was reverted and re-applied with a fix for this issue in commit 1657b8f84ed9 ("search SMBIOS for OEM board file extension"). But the fix to fall back to a default BDF introduced another issue: the driver currently parses IEs in board-2.bin one by one, and for each one it first checks to see if it matches the ID with the variant appended. If it doesn't, it checks to see if it matches the "fallback" ID with no variant. If a matching BDF is found at any point during this search, the search is terminated and that BDF is used. The issue is that it's very possible (and is currently the case for board-2.bin files present in the ath10k-firmware repository) for the default BDF to occur in an earlier IE than the variant-specific BDF. In this case, the current code will happily choose the default BDF even though a better-matching BDF is present later in the file. This patch fixes the issue by first searching the entire file for the ID with variant, and searching for the fallback ID only if that search fails. It also includes some code cleanup in the area, as ath10k_core_fetch_board_data_api_n() no longer does its own string mangling to remove the variant from an ID, instead leaving that job to a new flag passed to ath10k_core_create_board_name(). I've tested this patch on a QCA4019 and verified that the driver behaves correctly for 1) both fallback and variant BDFs present, 2) only fallback BDF present, and 3) no matching BDFs present. Change-Id: Iffc950515e7f42139190296da31e74194875e799 Fixes: 1657b8f84ed9 ("ath10k: search SMBIOS for OEM board file extension") Signed-off-by: Thomas Hebb Signed-off-by: Kalle Valo Git-commit: c8489668065a283d3027e86e877b103a87f99d22 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/core.c | 134 +++++++++++++------------ 1 file changed, 72 insertions(+), 62 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 3c8df6a2c643..a62de98db432 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1035,14 +1035,61 @@ static int ath10k_core_parse_bd_ie_board(struct ath10k *ar, return ret; } +static int ath10k_core_search_bd(struct ath10k *ar, + const char *boardname, + const u8 *data, + size_t len) +{ + size_t ie_len; + struct ath10k_fw_ie *hdr; + int ret = -ENOENT, ie_id; + + while (len > sizeof(struct ath10k_fw_ie)) { + hdr = (struct ath10k_fw_ie *)data; + ie_id = le32_to_cpu(hdr->id); + ie_len = le32_to_cpu(hdr->len); + + len -= sizeof(*hdr); + data = hdr->data; + + if (len < ALIGN(ie_len, 4)) { + ath10k_err(ar, "invalid length for board ie_id %d ie_len %zu len %zu\n", + ie_id, ie_len, len); + return -EINVAL; + } + + switch (ie_id) { + case ATH10K_BD_IE_BOARD: + ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len, + boardname); + if (ret == -ENOENT) + /* no match found, continue */ + break; + + /* either found or error, so stop searching */ + goto out; + } + + /* jump over the padding */ + ie_len = ALIGN(ie_len, 4); + + len -= ie_len; + data += ie_len; + } + +out: + /* return result of parse_bd_ie_board() or -ENOENT */ + return ret; +} + static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar, const char *boardname, + const char *fallback_boardname, const char *filename) { - size_t len, magic_len, ie_len; - struct ath10k_fw_ie *hdr; + size_t len, magic_len; const u8 *data; - int ret, ie_id; + int ret; ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, @@ -1080,69 +1127,23 @@ static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar, data += magic_len; len -= magic_len; - while (len > sizeof(struct ath10k_fw_ie)) { - hdr = (struct ath10k_fw_ie *)data; - ie_id = le32_to_cpu(hdr->id); - ie_len = le32_to_cpu(hdr->len); - - len -= sizeof(*hdr); - data = hdr->data; - - if (len < ALIGN(ie_len, 4)) { - ath10k_err(ar, "invalid length for board ie_id %d ie_len %zu len %zu\n", - ie_id, ie_len, len); - ret = -EINVAL; - goto err; - } + /* attempt to find boardname in the IE list */ + ret = ath10k_core_search_bd(ar, boardname, data, len); - switch (ie_id) { - case ATH10K_BD_IE_BOARD: - ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len, - boardname); - if (ret == -ENOENT && ar->id.bdf_ext[0] != '\0') { - /* try default bdf if variant was not found */ - char *s, *v = ",variant="; - char boardname2[100]; - - strlcpy(boardname2, boardname, - sizeof(boardname2)); - - s = strstr(boardname2, v); - if (s) - *s = '\0'; /* strip ",variant=%s" */ + /* if we didn't find it and have a fallback name, try that */ + if (ret == -ENOENT && fallback_boardname) + ret = ath10k_core_search_bd(ar, fallback_boardname, data, len); - ret = ath10k_core_parse_bd_ie_board(ar, data, - ie_len, - boardname2); - } - - if (ret == -ENOENT) - /* no match found, continue */ - break; - else if (ret) - /* there was an error, bail out */ - goto err; - - /* board data found */ - goto out; - } - - /* jump over the padding */ - ie_len = ALIGN(ie_len, 4); - - len -= ie_len; - data += ie_len; - } - -out: - if (!ar->normal_mode_fw.board_data || !ar->normal_mode_fw.board_len) { + if (ret == -ENOENT) { ath10k_err(ar, "failed to fetch board data for %s from %s/%s\n", boardname, ar->hw_params.fw.dir, filename); ret = -ENODATA; - goto err; } + if (ret) + goto err; + return 0; err: @@ -1151,12 +1152,12 @@ static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar, } static int ath10k_core_create_board_name(struct ath10k *ar, char *name, - size_t name_len) + size_t name_len, bool with_variant) { /* strlen(',variant=') + strlen(ar->id.bdf_ext) */ char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 }; - if (ar->id.bdf_ext[0] != '\0') + if (with_variant && ar->id.bdf_ext[0] != '\0') scnprintf(variant, sizeof(variant), ",variant=%s", ar->id.bdf_ext); @@ -1190,17 +1191,26 @@ static int ath10k_core_create_board_name(struct ath10k *ar, char *name, static int ath10k_core_fetch_board_file(struct ath10k *ar) { - char boardname[100]; + char boardname[100], fallback_boardname[100]; int ret; - ret = ath10k_core_create_board_name(ar, boardname, sizeof(boardname)); + ret = ath10k_core_create_board_name(ar, boardname, + sizeof(boardname), true); if (ret) { ath10k_err(ar, "failed to create board name: %d", ret); return ret; } + ret = ath10k_core_create_board_name(ar, fallback_boardname, + sizeof(boardname), false); + if (ret) { + ath10k_err(ar, "failed to create fallback board name: %d", ret); + return ret; + } + ar->bd_api = 2; ret = ath10k_core_fetch_board_data_api_n(ar, boardname, + fallback_boardname, ATH10K_BOARD_API2_FILE); if (!ret) goto success; From 9d90193d98a7b71fb447b058bc43f85b9aab0868 Mon Sep 17 00:00:00 2001 From: Sathishkumar Muruganandam Date: Thu, 14 Nov 2019 12:14:36 +0530 Subject: [PATCH 099/192] UPSTREAM: ath10k: support extended board data download for dual-band QCA9984 To support dual-band variant of QCA9984, new extended board data (eBDF) is introduced since existing board data ran out of space. Below is the brief implementation & design detail, ---------------------------------------------------- 1. New OTP changes to inform eBDF support in existing OTP download to fetch board ID and chip ID. This is backward compatible and older card sends 0 by default for eBDF support bit (bit 18 of OTP response) we check in ath10k driver. 2. If eBDF is supported, then we need to fetch eBDF ID which is bundled in downloaded board data. So again OTP is executed for knowing the eBDF ID. This is done once we set 'board_data_initialized' bit. If eBDF ID returned is zero, we continue booting with previous board data downloaded. 3. Based on the eBDF ID fetched, ath10k driver tries to download the extended board data to a new offset ahead of already downloaded board data address. 4. A new BD IE type, ATH10K_BD_IE_BOARD_EXT is added to differentiate in bundling eBDF separately in board-2.bin and also to parse through board bundle for eBDF download in ath10k boot. 5. If eBDF is not present in the board-2.bin bundle or when board ID is zero, we do a fallback boot to "eboard.bin" in the same QCA9984/hw1.0 dir. This is same as done to existing "board.bin" if board ID is not present in board-2.bin bundle. Current design is that eBDF size will be 2KB and eBDF ID will be byte value. Tested the above changes with dual-band variant of QCA9984 card. OTP update needed for the test will be part of next FW release 10.4-3.6-xxxx. Below are the logs with ath10k BOOT debugs enabled. First OTP response : --------------------- .. boot upload otp to 0x1234 len 9478 for board id boot get otp board id result 0x00040400 board_id 1 chip_id 0 ext_bid_support 1 .. Second OTP response : --------------------- .. boot upload otp to 0x1234 len 9478 for ext board id boot get otp ext board id result 0x00000005 ext_board_id 5 boot using eboard name 'bus=pci,bmi-chip-id=0,bmi-eboard-id=5' .. Extended board data download: ------------------------------ .. board name 00000000: 62 75 73 3d 70 63 69 2c 62 6d 69 2d 63 68 69 70 bus=pci,bmi-chip 00000010: 2d 69 64 3d 30 2c 62 6d 69 2d 65 62 6f 61 72 64 -id=0,bmi-eboard 00000020: 2d 69 64 3d 35 -id=5 boot found match for name 'bus=pci,bmi-chip-id=0,bmi-eboard-id=5' boot found eboard data for 'bus=pci,bmi-chip-id=0,bmi-eboard-id=5' using board api 2 boot writing ext board data to addr 0xc3000 .. Fallback Extended board data download from "eboard.bin": --------------------------------------------------------- .. board name 00000000: 62 75 73 3d 70 63 69 2c 62 6d 69 2d 63 68 69 70 bus=pci,bmi-chip 00000010: 2d 69 64 3d 30 2c 62 6d 69 2d 62 6f 61 72 64 2d -id=0,bmi-board- 00000020: 69 64 3d 31 30 id=10 failed to fetch board data for bus=pci,bmi-chip-id=0,bmi-eboard-id=5 from ath10k/QCA9984/hw1.0/board-2.bin boot fw request 'ath10k/QCA9984/hw1.0/eboard.bin': 0 using board api 1 boot writing ext board data to addr 0xc3000 .. Signed-off-by: Sathishkumar Muruganandam Signed-off-by: Kalle Valo Change-Id: I58f05766bf2b755f535f350914eab445b2eec66a Git-commit: 31324d17976ed063839db5de3ce0b37a48dd0439 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Signed-off-by: Govind Singh --- arch/arm64/boot/dts/qcom/msm8916.dtsi | 6 +- drivers/net/wireless/ath/ath10k/bmi.h | 5 + drivers/net/wireless/ath/ath10k/core.c | 246 ++++++++++++++++---- drivers/net/wireless/ath/ath10k/core.h | 5 + drivers/net/wireless/ath/ath10k/hw.h | 4 + drivers/net/wireless/ath/ath10k/targaddrs.h | 4 + 6 files changed, 226 insertions(+), 44 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index 3cc449425a03..ee36196df1d1 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -84,18 +84,18 @@ }; wcnss_mem: wcnss@89300000 { - reg = <0x0 0x89300000 0x0 0x600000>; + reg = <0x0 0x89300000 0x0 0x700000>; no-map; }; venus_mem: venus@89900000 { - reg = <0x0 0x89900000 0x0 0x600000>; + reg = <0x0 0x89A00000 0x0 0x600000>; no-map; }; mba_mem: mba@8ea00000 { no-map; - reg = <0 0x8ea00000 0 0x100000>; + reg = <0 0x8A000000 0 0x100000>; }; }; diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index 9a396817aa55..28f49441ba46 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -86,6 +86,10 @@ enum bmi_cmd_id { #define BMI_PARAM_GET_FLASH_BOARD_ID 0x8000 #define BMI_PARAM_FLASH_SECTION_ALL 0x10000 +/* Dual-band Extended Board ID */ +#define BMI_PARAM_GET_EXT_BOARD_ID 0x40000 +#define ATH10K_BMI_EXT_BOARD_ID_SUPPORT 0x40000 + #define ATH10K_BMI_BOARD_ID_FROM_OTP_MASK 0x7c00 #define ATH10K_BMI_BOARD_ID_FROM_OTP_LSB 10 @@ -93,6 +97,7 @@ enum bmi_cmd_id { #define ATH10K_BMI_CHIP_ID_FROM_OTP_LSB 15 #define ATH10K_BMI_BOARD_ID_STATUS_MASK 0xff +#define ATH10K_BMI_EBOARD_ID_STATUS_MASK 0xff struct bmi_cmd { __le32 id; /* enum bmi_cmd_id */ diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index a62de98db432..bc88dcd7e4fe 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -294,8 +294,10 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .fw = { .dir = QCA9984_HW_1_0_FW_DIR, .board = QCA9984_HW_1_0_BOARD_DATA_FILE, + .eboard = QCA9984_HW_1_0_EBOARD_DATA_FILE, .board_size = QCA99X0_BOARD_DATA_SZ, .board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ, + .ext_board_size = QCA99X0_EXT_BOARD_DATA_SZ, }, .sw_decrypt_mcast_mgmt = true, .hw_ops = &qca99x0_ops, @@ -697,6 +699,7 @@ static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) { u32 result, address; u8 board_id, chip_id; + bool ext_bid_support; int ret, bmi_board_id_param; address = ar->hw_params.patch_load_addr; @@ -736,10 +739,13 @@ static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) board_id = MS(result, ATH10K_BMI_BOARD_ID_FROM_OTP); chip_id = MS(result, ATH10K_BMI_CHIP_ID_FROM_OTP); + ext_bid_support = (result & ATH10K_BMI_EXT_BOARD_ID_SUPPORT); ath10k_dbg(ar, ATH10K_DBG_BOOT, - "boot get otp board id result 0x%08x board_id %d chip_id %d\n", - result, board_id, chip_id); + "boot get otp board id result 0x%08x board_id %d chip_id %d ext_bid_support %d\n", + result, board_id, chip_id, ext_bid_support); + + ar->id.ext_bid_supported = ext_bid_support; if ((result & ATH10K_BMI_BOARD_ID_STATUS_MASK) != 0 || (board_id == 0)) { @@ -880,9 +886,15 @@ static void ath10k_core_free_board_files(struct ath10k *ar) if (!IS_ERR(ar->normal_mode_fw.board)) release_firmware(ar->normal_mode_fw.board); + if (!IS_ERR(ar->normal_mode_fw.ext_board)) + release_firmware(ar->normal_mode_fw.ext_board); + ar->normal_mode_fw.board = NULL; ar->normal_mode_fw.board_data = NULL; ar->normal_mode_fw.board_len = 0; + ar->normal_mode_fw.ext_board = NULL; + ar->normal_mode_fw.ext_board_data = NULL; + ar->normal_mode_fw.ext_board_len = 0; } static void ath10k_core_free_firmware_files(struct ath10k *ar) @@ -936,28 +948,47 @@ static int ath10k_fetch_cal_file(struct ath10k *ar) return 0; } -static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar) +static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar, int bd_ie_type) { - if (!ar->hw_params.fw.board) { - ath10k_err(ar, "failed to find board file fw entry\n"); - return -EINVAL; - } + const struct firmware *fw; - ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar, - ar->hw_params.fw.dir, - ar->hw_params.fw.board); - if (IS_ERR(ar->normal_mode_fw.board)) - return PTR_ERR(ar->normal_mode_fw.board); + if (bd_ie_type == ATH10K_BD_IE_BOARD) { + if (!ar->hw_params.fw.board) { + ath10k_err(ar, "failed to find board file fw entry\n"); + return -EINVAL; + } + + ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar, + ar->hw_params.fw.dir, + ar->hw_params.fw.board); + if (IS_ERR(ar->normal_mode_fw.board)) + return PTR_ERR(ar->normal_mode_fw.board); + + ar->normal_mode_fw.board_data = ar->normal_mode_fw.board->data; + ar->normal_mode_fw.board_len = ar->normal_mode_fw.board->size; + } else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) { + if (!ar->hw_params.fw.eboard) { + ath10k_err(ar, "failed to find eboard file fw entry\n"); + return -EINVAL; + } - ar->normal_mode_fw.board_data = ar->normal_mode_fw.board->data; - ar->normal_mode_fw.board_len = ar->normal_mode_fw.board->size; + fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, + ar->hw_params.fw.eboard); + ar->normal_mode_fw.ext_board = fw; + if (IS_ERR(ar->normal_mode_fw.ext_board)) + return PTR_ERR(ar->normal_mode_fw.ext_board); + + ar->normal_mode_fw.ext_board_data = ar->normal_mode_fw.ext_board->data; + ar->normal_mode_fw.ext_board_len = ar->normal_mode_fw.ext_board->size; + } return 0; } static int ath10k_core_parse_bd_ie_board(struct ath10k *ar, const void *buf, size_t buf_len, - const char *boardname) + const char *boardname, + int bd_ie_type) { const struct ath10k_fw_ie *hdr; bool name_match_found; @@ -1006,12 +1037,21 @@ static int ath10k_core_parse_bd_ie_board(struct ath10k *ar, /* no match found */ break; - ath10k_dbg(ar, ATH10K_DBG_BOOT, - "boot found board data for '%s'", - boardname); + if (bd_ie_type == ATH10K_BD_IE_BOARD) { + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot found board data for '%s'", + boardname); - ar->normal_mode_fw.board_data = board_ie_data; - ar->normal_mode_fw.board_len = board_ie_len; + ar->normal_mode_fw.board_data = board_ie_data; + ar->normal_mode_fw.board_len = board_ie_len; + } else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) { + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot found eboard data for '%s'", + boardname); + + ar->normal_mode_fw.ext_board_data = board_ie_data; + ar->normal_mode_fw.ext_board_len = board_ie_len; + } ret = 0; goto out; @@ -1061,7 +1101,18 @@ static int ath10k_core_search_bd(struct ath10k *ar, switch (ie_id) { case ATH10K_BD_IE_BOARD: ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len, - boardname); + boardname, + ATH10K_BD_IE_BOARD); + if (ret == -ENOENT) + /* no match found, continue */ + break; + + /* either found or error, so stop searching */ + goto out; + case ATH10K_BD_IE_BOARD_EXT: + ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len, + boardname, + ATH10K_BD_IE_BOARD_EXT); if (ret == -ENOENT) /* no match found, continue */ break; @@ -1091,9 +1142,11 @@ static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar, const u8 *data; int ret; - ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar, - ar->hw_params.fw.dir, - filename); + /* Skip if already fetched during board data download */ + if (!ar->normal_mode_fw.board) + ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar, + ar->hw_params.fw.dir, + filename); if (IS_ERR(ar->normal_mode_fw.board)) return PTR_ERR(ar->normal_mode_fw.board); @@ -1189,23 +1242,49 @@ static int ath10k_core_create_board_name(struct ath10k *ar, char *name, return 0; } -static int ath10k_core_fetch_board_file(struct ath10k *ar) +static int ath10k_core_create_eboard_name(struct ath10k *ar, char *name, + size_t name_len) +{ + if (ar->id.bmi_ids_valid) { + scnprintf(name, name_len, + "bus=%s,bmi-chip-id=%d,bmi-eboard-id=%d", + ath10k_bus_str(ar->hif.bus), + ar->id.bmi_chip_id, + ar->id.bmi_eboard_id); + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using eboard name '%s'\n", name); + return 0; + } + /* Fallback if returned board id is zero */ + return -1; +} + +static int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type) { char boardname[100], fallback_boardname[100]; int ret; - ret = ath10k_core_create_board_name(ar, boardname, - sizeof(boardname), true); - if (ret) { - ath10k_err(ar, "failed to create board name: %d", ret); - return ret; - } + if (bd_ie_type == ATH10K_BD_IE_BOARD) { + ret = ath10k_core_create_board_name(ar, boardname, + sizeof(boardname), true); + if (ret) { + ath10k_err(ar, "failed to create board name: %d", ret); + return ret; + } - ret = ath10k_core_create_board_name(ar, fallback_boardname, - sizeof(boardname), false); - if (ret) { - ath10k_err(ar, "failed to create fallback board name: %d", ret); - return ret; + ret = ath10k_core_create_board_name(ar, fallback_boardname, + sizeof(boardname), false); + if (ret) { + ath10k_err(ar, "failed to create fallback board name: %d", ret); + return ret; + } + } else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) { + ret = ath10k_core_create_eboard_name(ar, boardname, + sizeof(boardname)); + if (ret) { + ath10k_err(ar, "fallback to eboard.bin since board id 0"); + goto fallback; + } } ar->bd_api = 2; @@ -1215,8 +1294,9 @@ static int ath10k_core_fetch_board_file(struct ath10k *ar) if (!ret) goto success; +fallback: ar->bd_api = 1; - ret = ath10k_core_fetch_board_data_api_1(ar); + ret = ath10k_core_fetch_board_data_api_1(ar, bd_ie_type); if (ret) { ath10k_err(ar, "failed to fetch board-2.bin or board.bin from %s\n", ar->hw_params.fw.dir); @@ -1228,11 +1308,65 @@ static int ath10k_core_fetch_board_file(struct ath10k *ar) return 0; } +static int ath10k_core_get_ext_board_id_from_otp(struct ath10k *ar) +{ + u32 result, address; + u8 ext_board_id; + int ret; + + address = ar->hw_params.patch_load_addr; + + if (!ar->normal_mode_fw.fw_file.otp_data || + !ar->normal_mode_fw.fw_file.otp_len) { + ath10k_warn(ar, + "failed to retrieve extended board id due to otp binary missing\n"); + return -ENODATA; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot upload otp to 0x%x len %zd for ext board id\n", + address, ar->normal_mode_fw.fw_file.otp_len); + + ret = ath10k_bmi_fast_download(ar, address, + ar->normal_mode_fw.fw_file.otp_data, + ar->normal_mode_fw.fw_file.otp_len); + if (ret) { + ath10k_err(ar, "could not write otp for ext board id check: %d\n", + ret); + return ret; + } + + ret = ath10k_bmi_execute(ar, address, BMI_PARAM_GET_EXT_BOARD_ID, &result); + if (ret) { + ath10k_err(ar, "could not execute otp for ext board id check: %d\n", + ret); + return ret; + } + + if (!result) { + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "ext board id does not exist in otp, ignore it\n"); + return -EOPNOTSUPP; + } + + ext_board_id = result & ATH10K_BMI_EBOARD_ID_STATUS_MASK; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot get otp ext board id result 0x%08x ext_board_id %d\n", + result, ext_board_id); + + ar->id.bmi_eboard_id = ext_board_id; + + return 0; +} + static int ath10k_download_board_data(struct ath10k *ar, const void *data, size_t data_len) { u32 board_data_size = ar->hw_params.fw.board_size; - u32 address; + u32 eboard_data_size = ar->hw_params.fw.ext_board_size; + u32 board_address; + u32 ext_board_address; int ret; ret = ath10k_push_board_ext_data(ar, data, data_len); @@ -1241,13 +1375,13 @@ static int ath10k_download_board_data(struct ath10k *ar, const void *data, goto exit; } - ret = ath10k_bmi_read32(ar, hi_board_data, &address); + ret = ath10k_bmi_read32(ar, hi_board_data, &board_address); if (ret) { ath10k_err(ar, "could not read board data addr (%d)\n", ret); goto exit; } - ret = ath10k_bmi_write_memory(ar, address, data, + ret = ath10k_bmi_write_memory(ar, board_address, data, min_t(u32, board_data_size, data_len)); if (ret) { @@ -1261,6 +1395,36 @@ static int ath10k_download_board_data(struct ath10k *ar, const void *data, goto exit; } + if (!ar->id.ext_bid_supported) + goto exit; + + /* Extended board data download */ + ret = ath10k_core_get_ext_board_id_from_otp(ar); + if (ret == -EOPNOTSUPP) { + /* Not fetching ext_board_data if ext board id is 0 */ + ath10k_dbg(ar, ATH10K_DBG_BOOT, "otp returned ext board id 0\n"); + return 0; + } else if (ret) { + ath10k_err(ar, "failed to get extended board id: %d\n", ret); + goto exit; + } + + ret = ath10k_core_fetch_board_file(ar, ATH10K_BD_IE_BOARD_EXT); + if (ret) + goto exit; + + if (ar->normal_mode_fw.ext_board_data) { + ext_board_address = board_address + EXT_BOARD_ADDRESS_OFFSET; + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot writing ext board data to addr 0x%x", + ext_board_address); + ret = ath10k_bmi_write_memory(ar, ext_board_address, + ar->normal_mode_fw.ext_board_data, + min_t(u32, eboard_data_size, data_len)); + if (ret) + ath10k_err(ar, "failed to write ext board data: %d\n", ret); + } + exit: return ret; } @@ -2526,7 +2690,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar) if (ret) ath10k_dbg(ar, ATH10K_DBG_BOOT, "DT bdf variant name not set.\n"); - ret = ath10k_core_fetch_board_file(ar); + ret = ath10k_core_fetch_board_file(ar, ATH10K_BD_IE_BOARD); if (ret) { ath10k_err(ar, "failed to fetch board file: %d\n", ret); goto err_free_firmware_files; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 98c1f2ac969d..96124c521f9e 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -750,6 +750,9 @@ struct ath10k_fw_components { const struct firmware *board; const void *board_data; size_t board_len; + const struct firmware *ext_board; + const void *ext_board_data; + size_t ext_board_len; struct ath10k_fw_file fw_file; }; @@ -849,7 +852,9 @@ struct ath10k { bool qmi_ids_valid; u32 qmi_board_id; u8 bmi_board_id; + u8 bmi_eboard_id; u8 bmi_chip_id; + bool ext_bid_supported; char bdf_ext[ATH10K_SMBIOS_BDF_EXT_STR_LENGTH]; } id; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 685ba71aeeb9..9815e03a1fe6 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -107,6 +107,7 @@ enum qca9377_chip_id_rev { #define QCA9984_HW_1_0_CHIP_ID_REV 0x0 #define QCA9984_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9984/hw1.0" #define QCA9984_HW_1_0_BOARD_DATA_FILE "board.bin" +#define QCA9984_HW_1_0_EBOARD_DATA_FILE "eboard.bin" #define QCA9984_HW_1_0_PATCH_LOAD_ADDR 0x1234 /* QCA9888 2.0 defines */ @@ -219,6 +220,7 @@ enum ath10k_fw_htt_op_version { enum ath10k_bd_ie_type { /* contains sub IEs of enum ath10k_bd_ie_board_type */ ATH10K_BD_IE_BOARD = 0, + ATH10K_BD_IE_BOARD_EXT = 1, }; enum ath10k_bd_ie_board_type { @@ -529,6 +531,8 @@ struct ath10k_hw_params { const char *dir; const char *board; size_t board_size; + const char *eboard; + size_t ext_board_size; size_t board_ext_size; } fw; diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h index c2b5bad0459b..b11a1c3d87b4 100644 --- a/drivers/net/wireless/ath/ath10k/targaddrs.h +++ b/drivers/net/wireless/ath/ath10k/targaddrs.h @@ -484,6 +484,10 @@ struct host_interest { #define QCA99X0_BOARD_DATA_SZ 12288 #define QCA99X0_BOARD_EXT_DATA_SZ 0 +/* Dual band extended board data */ +#define QCA99X0_EXT_BOARD_DATA_SZ 2048 +#define EXT_BOARD_ADDRESS_OFFSET 0x3000 + #define QCA4019_BOARD_DATA_SZ 12064 #define QCA4019_BOARD_EXT_DATA_SZ 0 From 5b1bc06ac0e32a0a3af426c7a9b9104800f95b87 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 11 Oct 2018 13:16:14 +0300 Subject: [PATCH 100/192] UPSTREAM: ath10k: add debug mask for QMI layer Add debug mask to control debug info of ath10k qmi messaging layer. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Git-commit: 35a6657667375d1564f9e9b75491c9e41b04c51f Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Change-Id: I2d439ef7b441d1b2676b1cc7bc768028d103f021 Signed-off-by: Dundi Raviteja --- drivers/net/wireless/ath/ath10k/debug.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index e54308889e59..9561dbc94b21 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -43,6 +43,7 @@ enum ath10k_debug_mask { ATH10K_DBG_USB = 0x00040000, ATH10K_DBG_USB_BULK = 0x00080000, ATH10K_DBG_SNOC = 0x00100000, + ATH10K_DBG_QMI = 0x00200000, ATH10K_DBG_ANY = 0xffffffff, }; From 949d995070b5ea08ee2513231a6b10d2d320907d Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 14 Nov 2019 12:20:26 +0530 Subject: [PATCH 101/192] UPSTREAM: ath10k: add QMI message handshake for wcn3990 client Add WCN3990 QMI client handshakes for Q6 integrated WLAN connectivity subsystem. This layer is responsible for communicating qmi control messages to wifi fw QMI service using QMI messaging protocol. Qualcomm MSM Interface(QMI) is a messaging format used to communicate between components running between remote processors with underlying transport layer based on integrated chipset(shared memory) or discrete chipset(PCI/USB/SDIO/UART). Change-Id: Ib8f17733ce5012db70a6165ee503bf5f5d1dab82 Signed-off-by: Govind Singh Reviewed-by: Bjorn Andersson Acked-by: Niklas Cassel Reviewed-by: Brian Norris Signed-off-by: Kalle Valo Git-commit: ba94c753ccb471bafe8bd824b744fda6fee0001e Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/Kconfig | 1 + drivers/net/wireless/ath/ath10k/Makefile | 4 +- drivers/net/wireless/ath/ath10k/core.c | 6 +- drivers/net/wireless/ath/ath10k/core.h | 2 + drivers/net/wireless/ath/ath10k/qmi.c | 1019 ++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/qmi.h | 129 +++ drivers/net/wireless/ath/ath10k/snoc.c | 267 +++++- drivers/net/wireless/ath/ath10k/snoc.h | 4 + 8 files changed, 1419 insertions(+), 13 deletions(-) create mode 100644 drivers/net/wireless/ath/ath10k/qmi.c create mode 100644 drivers/net/wireless/ath/ath10k/qmi.h diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index 6572a43590a8..e1ad6b9166a6 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -44,6 +44,7 @@ config ATH10K_SNOC tristate "Qualcomm ath10k SNOC support (EXPERIMENTAL)" depends on ATH10K depends on ARCH_QCOM || COMPILE_TEST + select QCOM_QMI_HELPERS ---help--- This module adds support for integrated WCN3990 chip connected to system NOC(SNOC). Currently work in progress and will not diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 44d60a61b242..66326b949ab1 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -36,7 +36,9 @@ obj-$(CONFIG_ATH10K_USB) += ath10k_usb.o ath10k_usb-y += usb.o obj-$(CONFIG_ATH10K_SNOC) += ath10k_snoc.o -ath10k_snoc-y += snoc.o +ath10k_snoc-y += qmi.o \ + qmi_wlfw_v01.o \ + snoc.o # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index bc88dcd7e4fe..22fb8e6f21c1 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -881,7 +881,7 @@ static int ath10k_download_fw(struct ath10k *ar) return ret; } -static void ath10k_core_free_board_files(struct ath10k *ar) +void ath10k_core_free_board_files(struct ath10k *ar) { if (!IS_ERR(ar->normal_mode_fw.board)) release_firmware(ar->normal_mode_fw.board); @@ -896,6 +896,7 @@ static void ath10k_core_free_board_files(struct ath10k *ar) ar->normal_mode_fw.ext_board_data = NULL; ar->normal_mode_fw.ext_board_len = 0; } +EXPORT_SYMBOL(ath10k_core_free_board_files); static void ath10k_core_free_firmware_files(struct ath10k *ar) { @@ -1259,7 +1260,7 @@ static int ath10k_core_create_eboard_name(struct ath10k *ar, char *name, return -1; } -static int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type) +int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type) { char boardname[100], fallback_boardname[100]; int ret; @@ -1307,6 +1308,7 @@ static int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type) ath10k_dbg(ar, ATH10K_DBG_BOOT, "using board api %d\n", ar->bd_api); return 0; } +EXPORT_SYMBOL(ath10k_core_fetch_board_file); static int ath10k_core_get_ext_board_id_from_otp(struct ath10k *ar) { diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 96124c521f9e..e85ce758f612 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -1070,5 +1070,7 @@ void ath10k_core_stop(struct ath10k *ar); int ath10k_core_register(struct ath10k *ar, const struct ath10k_bus_params *bus_params); void ath10k_core_unregister(struct ath10k *ar); +int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type); +void ath10k_core_free_board_files(struct ath10k *ar); #endif /* _CORE_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c new file mode 100644 index 000000000000..56cb1831dcdf --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -0,0 +1,1019 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "snoc.h" + +#define ATH10K_QMI_CLIENT_ID 0x4b4e454c +#define ATH10K_QMI_TIMEOUT 30 + +static int ath10k_qmi_map_msa_permission(struct ath10k_qmi *qmi, + struct ath10k_msa_mem_info *mem_info) +{ + struct qcom_scm_vmperm dst_perms[3]; + struct ath10k *ar = qmi->ar; + unsigned int src_perms; + u32 perm_count; + int ret; + + src_perms = BIT(QCOM_SCM_VMID_HLOS); + + dst_perms[0].vmid = QCOM_SCM_VMID_MSS_MSA; + dst_perms[0].perm = QCOM_SCM_PERM_RW; + dst_perms[1].vmid = QCOM_SCM_VMID_WLAN; + dst_perms[1].perm = QCOM_SCM_PERM_RW; + + if (mem_info->secure) { + perm_count = 2; + } else { + dst_perms[2].vmid = QCOM_SCM_VMID_WLAN_CE; + dst_perms[2].perm = QCOM_SCM_PERM_RW; + perm_count = 3; + } + + ret = qcom_scm_assign_mem(mem_info->addr, mem_info->size, + &src_perms, dst_perms, perm_count); + if (ret < 0) + ath10k_err(ar, "failed to assign msa map permissions: %d\n", ret); + + return ret; +} + +static int ath10k_qmi_unmap_msa_permission(struct ath10k_qmi *qmi, + struct ath10k_msa_mem_info *mem_info) +{ + struct qcom_scm_vmperm dst_perms; + struct ath10k *ar = qmi->ar; + unsigned int src_perms; + int ret; + + src_perms = BIT(QCOM_SCM_VMID_MSS_MSA) | BIT(QCOM_SCM_VMID_WLAN); + + if (!mem_info->secure) + src_perms |= BIT(QCOM_SCM_VMID_WLAN_CE); + + dst_perms.vmid = QCOM_SCM_VMID_HLOS; + dst_perms.perm = QCOM_SCM_PERM_RW; + + ret = qcom_scm_assign_mem(mem_info->addr, mem_info->size, + &src_perms, &dst_perms, 1); + if (ret < 0) + ath10k_err(ar, "failed to unmap msa permissions: %d\n", ret); + + return ret; +} + +static int ath10k_qmi_setup_msa_permissions(struct ath10k_qmi *qmi) +{ + int ret; + int i; + + for (i = 0; i < qmi->nr_mem_region; i++) { + ret = ath10k_qmi_map_msa_permission(qmi, &qmi->mem_region[i]); + if (ret) + goto err_unmap; + } + + return 0; + +err_unmap: + for (i--; i >= 0; i--) + ath10k_qmi_unmap_msa_permission(qmi, &qmi->mem_region[i]); + return ret; +} + +static void ath10k_qmi_remove_msa_permission(struct ath10k_qmi *qmi) +{ + int i; + + for (i = 0; i < qmi->nr_mem_region; i++) + ath10k_qmi_unmap_msa_permission(qmi, &qmi->mem_region[i]); +} + +static int ath10k_qmi_msa_mem_info_send_sync_msg(struct ath10k_qmi *qmi) +{ + struct wlfw_msa_info_resp_msg_v01 resp = {}; + struct wlfw_msa_info_req_msg_v01 req = {}; + struct ath10k *ar = qmi->ar; + struct qmi_txn txn; + int ret; + int i; + + req.msa_addr = qmi->msa_pa; + req.size = qmi->msa_mem_size; + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, + wlfw_msa_info_resp_msg_v01_ei, &resp); + if (ret < 0) + goto out; + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_MSA_INFO_REQ_V01, + WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_msa_info_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath10k_err(ar, "failed to send msa mem info req: %d\n", ret); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "msa info req rejected: %d\n", resp.resp.error); + ret = -EINVAL; + goto out; + } + + if (resp.mem_region_info_len > QMI_WLFW_MAX_MEM_REG_V01) { + ath10k_err(ar, "invalid memory region length received: %d\n", + resp.mem_region_info_len); + ret = -EINVAL; + goto out; + } + + qmi->nr_mem_region = resp.mem_region_info_len; + for (i = 0; i < resp.mem_region_info_len; i++) { + qmi->mem_region[i].addr = resp.mem_region_info[i].region_addr; + qmi->mem_region[i].size = resp.mem_region_info[i].size; + qmi->mem_region[i].secure = resp.mem_region_info[i].secure_flag; + ath10k_dbg(ar, ATH10K_DBG_QMI, + "qmi msa mem region %d addr 0x%pa size 0x%x flag 0x%08x\n", + i, &qmi->mem_region[i].addr, + qmi->mem_region[i].size, + qmi->mem_region[i].secure); + } + + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa mem info request completed\n"); + return 0; + +out: + return ret; +} + +static int ath10k_qmi_msa_ready_send_sync_msg(struct ath10k_qmi *qmi) +{ + struct wlfw_msa_ready_resp_msg_v01 resp = {}; + struct wlfw_msa_ready_req_msg_v01 req = {}; + struct ath10k *ar = qmi->ar; + struct qmi_txn txn; + int ret; + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, + wlfw_msa_ready_resp_msg_v01_ei, &resp); + if (ret < 0) + goto out; + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_MSA_READY_REQ_V01, + WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_msa_ready_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath10k_err(ar, "failed to send msa mem ready request: %d\n", ret); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "msa ready request rejected: %d\n", resp.resp.error); + ret = -EINVAL; + } + + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa mem ready request completed\n"); + return 0; + +out: + return ret; +} + +static int ath10k_qmi_bdf_dnld_send_sync(struct ath10k_qmi *qmi) +{ + struct wlfw_bdf_download_resp_msg_v01 resp = {}; + struct wlfw_bdf_download_req_msg_v01 *req; + struct ath10k *ar = qmi->ar; + unsigned int remaining; + struct qmi_txn txn; + const u8 *temp; + int ret; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + temp = ar->normal_mode_fw.board_data; + remaining = ar->normal_mode_fw.board_len; + + while (remaining) { + req->valid = 1; + req->file_id_valid = 1; + req->file_id = 0; + req->total_size_valid = 1; + req->total_size = ar->normal_mode_fw.board_len; + req->seg_id_valid = 1; + req->data_valid = 1; + req->end_valid = 1; + + if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) { + req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01; + } else { + req->data_len = remaining; + req->end = 1; + } + + memcpy(req->data, temp, req->data_len); + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, + wlfw_bdf_download_resp_msg_v01_ei, + &resp); + if (ret < 0) + goto out; + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_BDF_DOWNLOAD_REQ_V01, + WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_bdf_download_req_msg_v01_ei, req); + if (ret < 0) { + qmi_txn_cancel(&txn); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "failed to download board data file: %d\n", + resp.resp.error); + ret = -EINVAL; + goto out; + } + + remaining -= req->data_len; + temp += req->data_len; + req->seg_id++; + } + + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi bdf download request completed\n"); + + kfree(req); + return 0; + +out: + kfree(req); + return ret; +} + +static int ath10k_qmi_send_cal_report_req(struct ath10k_qmi *qmi) +{ + struct wlfw_cal_report_resp_msg_v01 resp = {}; + struct wlfw_cal_report_req_msg_v01 req = {}; + struct ath10k *ar = qmi->ar; + struct qmi_txn txn; + int i, j = 0; + int ret; + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_cal_report_resp_msg_v01_ei, + &resp); + if (ret < 0) + goto out; + + for (i = 0; i < QMI_WLFW_MAX_NUM_CAL_V01; i++) { + if (qmi->cal_data[i].total_size && + qmi->cal_data[i].data) { + req.meta_data[j] = qmi->cal_data[i].cal_id; + j++; + } + } + req.meta_data_len = j; + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_CAL_REPORT_REQ_V01, + WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_cal_report_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath10k_err(ar, "failed to send calibration request: %d\n", ret); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "calibration request rejected: %d\n", resp.resp.error); + ret = -EINVAL; + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi cal report request completed\n"); + return 0; + +out: + return ret; +} + +static int +ath10k_qmi_mode_send_sync_msg(struct ath10k *ar, enum wlfw_driver_mode_enum_v01 mode) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_qmi *qmi = ar_snoc->qmi; + struct wlfw_wlan_mode_resp_msg_v01 resp = {}; + struct wlfw_wlan_mode_req_msg_v01 req = {}; + struct qmi_txn txn; + int ret; + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, + wlfw_wlan_mode_resp_msg_v01_ei, + &resp); + if (ret < 0) + goto out; + + req.mode = mode; + req.hw_debug_valid = 1; + req.hw_debug = 0; + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_WLAN_MODE_REQ_V01, + WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_wlan_mode_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath10k_err(ar, "failed to send wlan mode %d request: %d\n", mode, ret); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "more request rejected: %d\n", resp.resp.error); + ret = -EINVAL; + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi wlan mode req completed: %d\n", mode); + return 0; + +out: + return ret; +} + +static int +ath10k_qmi_cfg_send_sync_msg(struct ath10k *ar, + struct ath10k_qmi_wlan_enable_cfg *config, + const char *version) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_qmi *qmi = ar_snoc->qmi; + struct wlfw_wlan_cfg_resp_msg_v01 resp = {}; + struct wlfw_wlan_cfg_req_msg_v01 *req; + struct qmi_txn txn; + int ret; + u32 i; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, + wlfw_wlan_cfg_resp_msg_v01_ei, + &resp); + if (ret < 0) + goto out; + + req->host_version_valid = 0; + + req->tgt_cfg_valid = 1; + if (config->num_ce_tgt_cfg > QMI_WLFW_MAX_NUM_CE_V01) + req->tgt_cfg_len = QMI_WLFW_MAX_NUM_CE_V01; + else + req->tgt_cfg_len = config->num_ce_tgt_cfg; + for (i = 0; i < req->tgt_cfg_len; i++) { + req->tgt_cfg[i].pipe_num = config->ce_tgt_cfg[i].pipe_num; + req->tgt_cfg[i].pipe_dir = config->ce_tgt_cfg[i].pipe_dir; + req->tgt_cfg[i].nentries = config->ce_tgt_cfg[i].nentries; + req->tgt_cfg[i].nbytes_max = config->ce_tgt_cfg[i].nbytes_max; + req->tgt_cfg[i].flags = config->ce_tgt_cfg[i].flags; + } + + req->svc_cfg_valid = 1; + if (config->num_ce_svc_pipe_cfg > QMI_WLFW_MAX_NUM_SVC_V01) + req->svc_cfg_len = QMI_WLFW_MAX_NUM_SVC_V01; + else + req->svc_cfg_len = config->num_ce_svc_pipe_cfg; + for (i = 0; i < req->svc_cfg_len; i++) { + req->svc_cfg[i].service_id = config->ce_svc_cfg[i].service_id; + req->svc_cfg[i].pipe_dir = config->ce_svc_cfg[i].pipe_dir; + req->svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num; + } + + req->shadow_reg_valid = 1; + if (config->num_shadow_reg_cfg > + QMI_WLFW_MAX_NUM_SHADOW_REG_V01) + req->shadow_reg_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01; + else + req->shadow_reg_len = config->num_shadow_reg_cfg; + + memcpy(req->shadow_reg, config->shadow_reg_cfg, + sizeof(struct wlfw_shadow_reg_cfg_s_v01) * req->shadow_reg_len); + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_WLAN_CFG_REQ_V01, + WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_wlan_cfg_req_msg_v01_ei, req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath10k_err(ar, "failed to send config request: %d\n", ret); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "config request rejected: %d\n", resp.resp.error); + ret = -EINVAL; + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi config request completed\n"); + kfree(req); + return 0; + +out: + kfree(req); + return ret; +} + +int ath10k_qmi_wlan_enable(struct ath10k *ar, + struct ath10k_qmi_wlan_enable_cfg *config, + enum wlfw_driver_mode_enum_v01 mode, + const char *version) +{ + int ret; + + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi mode %d config %p\n", + mode, config); + + ret = ath10k_qmi_cfg_send_sync_msg(ar, config, version); + if (ret) { + ath10k_err(ar, "failed to send qmi config: %d\n", ret); + return ret; + } + + ret = ath10k_qmi_mode_send_sync_msg(ar, mode); + if (ret) { + ath10k_err(ar, "failed to send qmi mode: %d\n", ret); + return ret; + } + + return 0; +} + +int ath10k_qmi_wlan_disable(struct ath10k *ar) +{ + return ath10k_qmi_mode_send_sync_msg(ar, QMI_WLFW_OFF_V01); +} + +static int ath10k_qmi_cap_send_sync_msg(struct ath10k_qmi *qmi) +{ + struct wlfw_cap_resp_msg_v01 *resp; + struct wlfw_cap_req_msg_v01 req = {}; + struct ath10k *ar = qmi->ar; + struct qmi_txn txn; + int ret; + + resp = kzalloc(sizeof(*resp), GFP_KERNEL); + if (!resp) + return -ENOMEM; + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_cap_resp_msg_v01_ei, resp); + if (ret < 0) + goto out; + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_CAP_REQ_V01, + WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_cap_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath10k_err(ar, "failed to send capability request: %d\n", ret); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + if (ret < 0) + goto out; + + if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "capablity req rejected: %d\n", resp->resp.error); + ret = -EINVAL; + goto out; + } + + if (resp->chip_info_valid) { + qmi->chip_info.chip_id = resp->chip_info.chip_id; + qmi->chip_info.chip_family = resp->chip_info.chip_family; + } + + if (resp->board_info_valid) + qmi->board_info.board_id = resp->board_info.board_id; + else + qmi->board_info.board_id = 0xFF; + + if (resp->soc_info_valid) + qmi->soc_info.soc_id = resp->soc_info.soc_id; + + if (resp->fw_version_info_valid) { + qmi->fw_version = resp->fw_version_info.fw_version; + strlcpy(qmi->fw_build_timestamp, resp->fw_version_info.fw_build_timestamp, + sizeof(qmi->fw_build_timestamp)); + } + + if (resp->fw_build_id_valid) + strlcpy(qmi->fw_build_id, resp->fw_build_id, + MAX_BUILD_ID_LEN + 1); + + ath10k_dbg(ar, ATH10K_DBG_QMI, + "qmi chip_id 0x%x chip_family 0x%x board_id 0x%x soc_id 0x%x", + qmi->chip_info.chip_id, qmi->chip_info.chip_family, + qmi->board_info.board_id, qmi->soc_info.soc_id); + ath10k_dbg(ar, ATH10K_DBG_QMI, + "qmi fw_version 0x%x fw_build_timestamp %s fw_build_id %s", + qmi->fw_version, qmi->fw_build_timestamp, qmi->fw_build_id); + + kfree(resp); + return 0; + +out: + kfree(resp); + return ret; +} + +static int ath10k_qmi_host_cap_send_sync(struct ath10k_qmi *qmi) +{ + struct wlfw_host_cap_resp_msg_v01 resp = {}; + struct wlfw_host_cap_req_msg_v01 req = {}; + struct ath10k *ar = qmi->ar; + struct qmi_txn txn; + int ret; + + req.daemon_support_valid = 1; + req.daemon_support = 0; + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, + wlfw_host_cap_resp_msg_v01_ei, &resp); + if (ret < 0) + goto out; + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_HOST_CAP_REQ_V01, + WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_host_cap_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath10k_err(ar, "failed to send host capability request: %d\n", ret); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "host capability request rejected: %d\n", resp.resp.error); + ret = -EINVAL; + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi host capablity request completed\n"); + return 0; + +out: + return ret; +} + +static int +ath10k_qmi_ind_register_send_sync_msg(struct ath10k_qmi *qmi) +{ + struct wlfw_ind_register_resp_msg_v01 resp = {}; + struct wlfw_ind_register_req_msg_v01 req = {}; + struct ath10k *ar = qmi->ar; + struct qmi_txn txn; + int ret; + + req.client_id_valid = 1; + req.client_id = ATH10K_QMI_CLIENT_ID; + req.fw_ready_enable_valid = 1; + req.fw_ready_enable = 1; + req.msa_ready_enable_valid = 1; + req.msa_ready_enable = 1; + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, + wlfw_ind_register_resp_msg_v01_ei, &resp); + if (ret < 0) + goto out; + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_IND_REGISTER_REQ_V01, + WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_ind_register_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath10k_err(ar, "failed to send indication registed request: %d\n", ret); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "indication request rejected: %d\n", resp.resp.error); + ret = -EINVAL; + goto out; + } + + if (resp.fw_status_valid) { + if (resp.fw_status & QMI_WLFW_FW_READY_V01) + qmi->fw_ready = true; + } + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi indication register request completed\n"); + return 0; + +out: + return ret; +} + +static void ath10k_qmi_event_server_arrive(struct ath10k_qmi *qmi) +{ + struct ath10k *ar = qmi->ar; + int ret; + + ret = ath10k_qmi_ind_register_send_sync_msg(qmi); + if (ret) + return; + + if (qmi->fw_ready) { + ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_READY_IND); + return; + } + + ret = ath10k_qmi_host_cap_send_sync(qmi); + if (ret) + return; + + ret = ath10k_qmi_msa_mem_info_send_sync_msg(qmi); + if (ret) + return; + + ret = ath10k_qmi_setup_msa_permissions(qmi); + if (ret) + return; + + ret = ath10k_qmi_msa_ready_send_sync_msg(qmi); + if (ret) + goto err_setup_msa; + + ret = ath10k_qmi_cap_send_sync_msg(qmi); + if (ret) + goto err_setup_msa; + + return; + +err_setup_msa: + ath10k_qmi_remove_msa_permission(qmi); +} + +static int ath10k_qmi_fetch_board_file(struct ath10k_qmi *qmi) +{ + struct ath10k *ar = qmi->ar; + + ar->hif.bus = ATH10K_BUS_SNOC; + ar->id.qmi_ids_valid = true; + ar->id.qmi_board_id = qmi->board_info.board_id; + ar->hw_params.fw.dir = WCN3990_HW_1_0_FW_DIR; + + return ath10k_core_fetch_board_file(qmi->ar, ATH10K_BD_IE_BOARD); +} + +static int +ath10k_qmi_driver_event_post(struct ath10k_qmi *qmi, + enum ath10k_qmi_driver_event_type type, + void *data) +{ + struct ath10k_qmi_driver_event *event; + + event = kzalloc(sizeof(*event), GFP_ATOMIC); + if (!event) + return -ENOMEM; + + event->type = type; + event->data = data; + + spin_lock(&qmi->event_lock); + list_add_tail(&event->list, &qmi->event_list); + spin_unlock(&qmi->event_lock); + + queue_work(qmi->event_wq, &qmi->event_work); + + return 0; +} + +static void ath10k_qmi_event_server_exit(struct ath10k_qmi *qmi) +{ + struct ath10k *ar = qmi->ar; + + ath10k_qmi_remove_msa_permission(qmi); + ath10k_core_free_board_files(ar); + ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_DOWN_IND); + ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw qmi service disconnected\n"); +} + +static void ath10k_qmi_event_msa_ready(struct ath10k_qmi *qmi) +{ + int ret; + + ret = ath10k_qmi_fetch_board_file(qmi); + if (ret) + goto out; + + ret = ath10k_qmi_bdf_dnld_send_sync(qmi); + if (ret) + goto out; + + ret = ath10k_qmi_send_cal_report_req(qmi); + +out: + return; +} + +static int ath10k_qmi_event_fw_ready_ind(struct ath10k_qmi *qmi) +{ + struct ath10k *ar = qmi->ar; + + ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw ready event received\n"); + ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_READY_IND); + + return 0; +} + +static void ath10k_qmi_fw_ready_ind(struct qmi_handle *qmi_hdl, + struct sockaddr_qrtr *sq, + struct qmi_txn *txn, const void *data) +{ + struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl); + + ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_FW_READY_IND, NULL); +} + +static void ath10k_qmi_msa_ready_ind(struct qmi_handle *qmi_hdl, + struct sockaddr_qrtr *sq, + struct qmi_txn *txn, const void *data) +{ + struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl); + + ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_MSA_READY_IND, NULL); +} + +static struct qmi_msg_handler qmi_msg_handler[] = { + { + .type = QMI_INDICATION, + .msg_id = QMI_WLFW_FW_READY_IND_V01, + .ei = wlfw_fw_ready_ind_msg_v01_ei, + .decoded_size = sizeof(struct wlfw_fw_ready_ind_msg_v01), + .fn = ath10k_qmi_fw_ready_ind, + }, + { + .type = QMI_INDICATION, + .msg_id = QMI_WLFW_MSA_READY_IND_V01, + .ei = wlfw_msa_ready_ind_msg_v01_ei, + .decoded_size = sizeof(struct wlfw_msa_ready_ind_msg_v01), + .fn = ath10k_qmi_msa_ready_ind, + }, + {} +}; + +static int ath10k_qmi_new_server(struct qmi_handle *qmi_hdl, + struct qmi_service *service) +{ + struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl); + struct sockaddr_qrtr *sq = &qmi->sq; + struct ath10k *ar = qmi->ar; + int ret; + + sq->sq_family = AF_QIPCRTR; + sq->sq_node = service->node; + sq->sq_port = service->port; + + ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw qmi service found\n"); + + ret = kernel_connect(qmi_hdl->sock, (struct sockaddr *)&qmi->sq, + sizeof(qmi->sq), 0); + if (ret) { + ath10k_err(ar, "failed to connect to a remote QMI service port\n"); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi wifi fw qmi service connected\n"); + ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_SERVER_ARRIVE, NULL); + + return ret; +} + +static void ath10k_qmi_del_server(struct qmi_handle *qmi_hdl, + struct qmi_service *service) +{ + struct ath10k_qmi *qmi = + container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl); + + qmi->fw_ready = false; + ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_SERVER_EXIT, NULL); +} + +static struct qmi_ops ath10k_qmi_ops = { + .new_server = ath10k_qmi_new_server, + .del_server = ath10k_qmi_del_server, +}; + +static void ath10k_qmi_driver_event_work(struct work_struct *work) +{ + struct ath10k_qmi *qmi = container_of(work, struct ath10k_qmi, + event_work); + struct ath10k_qmi_driver_event *event; + struct ath10k *ar = qmi->ar; + + spin_lock(&qmi->event_lock); + while (!list_empty(&qmi->event_list)) { + event = list_first_entry(&qmi->event_list, + struct ath10k_qmi_driver_event, list); + list_del(&event->list); + spin_unlock(&qmi->event_lock); + + switch (event->type) { + case ATH10K_QMI_EVENT_SERVER_ARRIVE: + ath10k_qmi_event_server_arrive(qmi); + break; + case ATH10K_QMI_EVENT_SERVER_EXIT: + ath10k_qmi_event_server_exit(qmi); + break; + case ATH10K_QMI_EVENT_FW_READY_IND: + ath10k_qmi_event_fw_ready_ind(qmi); + break; + case ATH10K_QMI_EVENT_MSA_READY_IND: + ath10k_qmi_event_msa_ready(qmi); + break; + default: + ath10k_warn(ar, "invalid event type: %d", event->type); + break; + } + kfree(event); + spin_lock(&qmi->event_lock); + } + spin_unlock(&qmi->event_lock); +} + +static int ath10k_qmi_setup_msa_resources(struct ath10k_qmi *qmi, u32 msa_size) +{ + struct ath10k *ar = qmi->ar; + struct device *dev = ar->dev; + struct device_node *node; + struct resource r; + int ret; + + node = of_parse_phandle(dev->of_node, "memory-region", 0); + if (node) { + ret = of_address_to_resource(node, 0, &r); + if (ret) { + dev_err(dev, "failed to resolve msa fixed region\n"); + return ret; + } + of_node_put(node); + + qmi->msa_pa = r.start; + qmi->msa_mem_size = resource_size(&r); + qmi->msa_va = devm_memremap(dev, qmi->msa_pa, qmi->msa_mem_size, + MEMREMAP_WT); + if (!qmi->msa_pa) { + dev_err(dev, "failed to map memory region: %pa\n", &r.start); + return -EBUSY; + } + } else { + qmi->msa_va = dmam_alloc_coherent(dev, msa_size, + &qmi->msa_pa, GFP_KERNEL); + if (!qmi->msa_va) { + ath10k_err(ar, "failed to allocate dma memory for msa region\n"); + return -ENOMEM; + } + qmi->msa_mem_size = msa_size; + } + + ath10k_dbg(ar, ATH10K_DBG_QMI, "msa pa: %pad , msa va: 0x%p\n", + &qmi->msa_pa, + qmi->msa_va); + + return 0; +} + +int ath10k_qmi_init(struct ath10k *ar, u32 msa_size) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_qmi *qmi; + int ret; + + qmi = kzalloc(sizeof(*qmi), GFP_KERNEL); + if (!qmi) + return -ENOMEM; + + qmi->ar = ar; + ar_snoc->qmi = qmi; + + ret = ath10k_qmi_setup_msa_resources(qmi, msa_size); + if (ret) + goto err; + + ret = qmi_handle_init(&qmi->qmi_hdl, + WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN, + &ath10k_qmi_ops, qmi_msg_handler); + if (ret) + goto err; + + qmi->event_wq = alloc_workqueue("ath10k_qmi_driver_event", + WQ_UNBOUND, 1); + if (!qmi->event_wq) { + ath10k_err(ar, "failed to allocate workqueue\n"); + ret = -EFAULT; + goto err_release_qmi_handle; + } + + INIT_LIST_HEAD(&qmi->event_list); + spin_lock_init(&qmi->event_lock); + INIT_WORK(&qmi->event_work, ath10k_qmi_driver_event_work); + + ret = qmi_add_lookup(&qmi->qmi_hdl, WLFW_SERVICE_ID_V01, + WLFW_SERVICE_VERS_V01, 0); + if (ret) + goto err_qmi_lookup; + + return 0; + +err_qmi_lookup: + destroy_workqueue(qmi->event_wq); + +err_release_qmi_handle: + qmi_handle_release(&qmi->qmi_hdl); + +err: + kfree(qmi); + return ret; +} + +int ath10k_qmi_deinit(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_qmi *qmi = ar_snoc->qmi; + + qmi_handle_release(&qmi->qmi_hdl); + cancel_work_sync(&qmi->event_work); + destroy_workqueue(qmi->event_wq); + ar_snoc->qmi = NULL; + + return 0; +} diff --git a/drivers/net/wireless/ath/ath10k/qmi.h b/drivers/net/wireless/ath/ath10k/qmi.h new file mode 100644 index 000000000000..1efe1d22fc2f --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/qmi.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _ATH10K_QMI_H_ +#define _ATH10K_QMI_H_ + +#include +#include +#include "qmi_wlfw_v01.h" + +#define MAX_NUM_MEMORY_REGIONS 2 +#define MAX_TIMESTAMP_LEN 32 +#define MAX_BUILD_ID_LEN 128 +#define MAX_NUM_CAL_V01 5 + +enum ath10k_qmi_driver_event_type { + ATH10K_QMI_EVENT_SERVER_ARRIVE, + ATH10K_QMI_EVENT_SERVER_EXIT, + ATH10K_QMI_EVENT_FW_READY_IND, + ATH10K_QMI_EVENT_FW_DOWN_IND, + ATH10K_QMI_EVENT_MSA_READY_IND, + ATH10K_QMI_EVENT_MAX, +}; + +struct ath10k_msa_mem_info { + phys_addr_t addr; + u32 size; + bool secure; +}; + +struct ath10k_qmi_chip_info { + u32 chip_id; + u32 chip_family; +}; + +struct ath10k_qmi_board_info { + u32 board_id; +}; + +struct ath10k_qmi_soc_info { + u32 soc_id; +}; + +struct ath10k_qmi_cal_data { + u32 cal_id; + u32 total_size; + u8 *data; +}; + +struct ath10k_tgt_pipe_cfg { + __le32 pipe_num; + __le32 pipe_dir; + __le32 nentries; + __le32 nbytes_max; + __le32 flags; + __le32 reserved; +}; + +struct ath10k_svc_pipe_cfg { + __le32 service_id; + __le32 pipe_dir; + __le32 pipe_num; +}; + +struct ath10k_shadow_reg_cfg { + __le16 ce_id; + __le16 reg_offset; +}; + +struct ath10k_qmi_wlan_enable_cfg { + u32 num_ce_tgt_cfg; + struct ath10k_tgt_pipe_cfg *ce_tgt_cfg; + u32 num_ce_svc_pipe_cfg; + struct ath10k_svc_pipe_cfg *ce_svc_cfg; + u32 num_shadow_reg_cfg; + struct ath10k_shadow_reg_cfg *shadow_reg_cfg; +}; + +struct ath10k_qmi_driver_event { + struct list_head list; + enum ath10k_qmi_driver_event_type type; + void *data; +}; + +struct ath10k_qmi { + struct ath10k *ar; + struct qmi_handle qmi_hdl; + struct sockaddr_qrtr sq; + struct work_struct event_work; + struct workqueue_struct *event_wq; + struct list_head event_list; + spinlock_t event_lock; /* spinlock for qmi event list */ + u32 nr_mem_region; + struct ath10k_msa_mem_info mem_region[MAX_NUM_MEMORY_REGIONS]; + dma_addr_t msa_pa; + u32 msa_mem_size; + void *msa_va; + struct ath10k_qmi_chip_info chip_info; + struct ath10k_qmi_board_info board_info; + struct ath10k_qmi_soc_info soc_info; + char fw_build_id[MAX_BUILD_ID_LEN + 1]; + u32 fw_version; + bool fw_ready; + char fw_build_timestamp[MAX_TIMESTAMP_LEN + 1]; + struct ath10k_qmi_cal_data cal_data[MAX_NUM_CAL_V01]; +}; + +int ath10k_qmi_wlan_enable(struct ath10k *ar, + struct ath10k_qmi_wlan_enable_cfg *config, + enum wlfw_driver_mode_enum_v01 mode, + const char *version); +int ath10k_qmi_wlan_disable(struct ath10k *ar); +int ath10k_qmi_register_service_notifier(struct notifier_block *nb); +int ath10k_qmi_init(struct ath10k *ar, u32 msa_size); +int ath10k_qmi_deinit(struct ath10k *ar); + +#endif /* ATH10K_QMI_H */ diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 613349278a25..7bca714ef4b4 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -66,6 +66,72 @@ static void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state); static const struct ath10k_snoc_drv_priv drv_priv = { .hw_rev = ATH10K_HW_WCN3990, .dma_mask = DMA_BIT_MASK(37), + .msa_size = 0x100000, +}; + +#define WCN3990_SRC_WR_IDX_OFFSET 0x3C +#define WCN3990_DST_WR_IDX_OFFSET 0x40 + +static struct ath10k_shadow_reg_cfg target_shadow_reg_cfg_map[] = { + { + .ce_id = __cpu_to_le16(0), + .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(3), + .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(4), + .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(5), + .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(7), + .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(1), + .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(2), + .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(7), + .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(8), + .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(9), + .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(10), + .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET), + }, + + { + .ce_id = __cpu_to_le16(11), + .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET), + }, }; static struct ce_attr host_ce_config_wlan[] = { @@ -175,6 +241,128 @@ static struct ce_attr host_ce_config_wlan[] = { }, }; +static struct ce_pipe_config target_ce_config_wlan[] = { + /* CE0: host->target HTC control and raw streams */ + { + .pipenum = __cpu_to_le32(0), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE1: target->host HTT + HTC control */ + { + .pipenum = __cpu_to_le32(1), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE2: target->host WMI */ + { + .pipenum = __cpu_to_le32(2), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(64), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE3: host->target WMI */ + { + .pipenum = __cpu_to_le32(3), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE4: host->target HTT */ + { + .pipenum = __cpu_to_le32(4), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(256), + .nbytes_max = __cpu_to_le32(256), + .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), + .reserved = __cpu_to_le32(0), + }, + + /* CE5: target->host HTT (HIF->HTT) */ + { + .pipenum = __cpu_to_le32(5), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(1024), + .nbytes_max = __cpu_to_le32(64), + .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), + .reserved = __cpu_to_le32(0), + }, + + /* CE6: Reserved for target autonomous hif_memcpy */ + { + .pipenum = __cpu_to_le32(6), + .pipedir = __cpu_to_le32(PIPEDIR_INOUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(16384), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE7 used only by Host */ + { + .pipenum = __cpu_to_le32(7), + .pipedir = __cpu_to_le32(4), + .nentries = __cpu_to_le32(0), + .nbytes_max = __cpu_to_le32(0), + .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), + .reserved = __cpu_to_le32(0), + }, + + /* CE8 Target to uMC */ + { + .pipenum = __cpu_to_le32(8), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(0), + .reserved = __cpu_to_le32(0), + }, + + /* CE9 target->host HTT */ + { + .pipenum = __cpu_to_le32(9), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE10 target->host HTT */ + { + .pipenum = __cpu_to_le32(10), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE11 target autonomous qcache memcpy */ + { + .pipenum = __cpu_to_le32(11), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, +}; + static struct service_to_pipe target_service_to_ce_map_wlan[] = { { __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO), @@ -756,11 +944,47 @@ static int ath10k_snoc_init_pipes(struct ath10k *ar) static int ath10k_snoc_wlan_enable(struct ath10k *ar) { - return 0; + struct ath10k_tgt_pipe_cfg tgt_cfg[CE_COUNT_MAX]; + struct ath10k_qmi_wlan_enable_cfg cfg; + enum wlfw_driver_mode_enum_v01 mode; + int pipe_num; + + for (pipe_num = 0; pipe_num < CE_COUNT_MAX; pipe_num++) { + tgt_cfg[pipe_num].pipe_num = + target_ce_config_wlan[pipe_num].pipenum; + tgt_cfg[pipe_num].pipe_dir = + target_ce_config_wlan[pipe_num].pipedir; + tgt_cfg[pipe_num].nentries = + target_ce_config_wlan[pipe_num].nentries; + tgt_cfg[pipe_num].nbytes_max = + target_ce_config_wlan[pipe_num].nbytes_max; + tgt_cfg[pipe_num].flags = + target_ce_config_wlan[pipe_num].flags; + tgt_cfg[pipe_num].reserved = 0; + } + + cfg.num_ce_tgt_cfg = sizeof(target_ce_config_wlan) / + sizeof(struct ath10k_tgt_pipe_cfg); + cfg.ce_tgt_cfg = (struct ath10k_tgt_pipe_cfg *) + &tgt_cfg; + cfg.num_ce_svc_pipe_cfg = sizeof(target_service_to_ce_map_wlan) / + sizeof(struct ath10k_svc_pipe_cfg); + cfg.ce_svc_cfg = (struct ath10k_svc_pipe_cfg *) + &target_service_to_ce_map_wlan; + cfg.num_shadow_reg_cfg = sizeof(target_shadow_reg_cfg_map) / + sizeof(struct ath10k_shadow_reg_cfg); + cfg.shadow_reg_cfg = (struct ath10k_shadow_reg_cfg *) + &target_shadow_reg_cfg_map; + + mode = QMI_WLFW_MISSION_V01; + + return ath10k_qmi_wlan_enable(ar, &cfg, mode, + NULL); } static void ath10k_snoc_wlan_disable(struct ath10k *ar) { + ath10k_qmi_wlan_disable(ar); } static void ath10k_snoc_hif_power_down(struct ath10k *ar) @@ -945,6 +1169,32 @@ static int ath10k_snoc_resource_init(struct ath10k *ar) return ret; } +int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_bus_params bus_params; + int ret; + + switch (type) { + case ATH10K_QMI_EVENT_FW_READY_IND: + bus_params.dev_type = ATH10K_DEV_TYPE_LL; + bus_params.chip_id = ar_snoc->target_info.soc_version; + ret = ath10k_core_register(ar, &bus_params); + if (ret) { + ath10k_err(ar, "failed to register driver core: %d\n", + ret); + } + break; + case ATH10K_QMI_EVENT_FW_DOWN_IND: + break; + default: + ath10k_err(ar, "invalid fw indication: %llx\n", type); + return -EINVAL; + } + + return 0; +} + static int ath10k_snoc_setup_resource(struct ath10k *ar) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); @@ -1269,9 +1519,9 @@ static int ath10k_snoc_probe(struct platform_device *pdev) struct ath10k_snoc *ar_snoc; struct device *dev; struct ath10k *ar; + u32 msa_size; int ret; u32 i; - struct ath10k_bus_params bus_params; of_id = of_match_device(ath10k_snoc_dt_match, &pdev->dev); if (!of_id) { @@ -1301,6 +1551,7 @@ static int ath10k_snoc_probe(struct platform_device *pdev) ar_snoc->ar = ar; ar_snoc->ce.bus_ops = &ath10k_snoc_bus_ops; ar->ce_priv = &ar_snoc->ce; + msa_size = drv_data->msa_size; ret = ath10k_snoc_resource_init(ar); if (ret) { @@ -1339,12 +1590,10 @@ static int ath10k_snoc_probe(struct platform_device *pdev) goto err_free_irq; } - bus_params.dev_type = ATH10K_DEV_TYPE_LL; - bus_params.chip_id = drv_data->hw_rev; - ret = ath10k_core_register(ar, &bus_params); + ret = ath10k_qmi_init(ar, msa_size); if (ret) { - ath10k_err(ar, "failed to register driver core: %d\n", ret); - goto err_hw_power_off; + ath10k_warn(ar, "failed to register wlfw qmi client: %d\n", ret); + goto err_core_destroy; } ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n"); @@ -1352,9 +1601,6 @@ static int ath10k_snoc_probe(struct platform_device *pdev) return 0; -err_hw_power_off: - ath10k_hw_power_off(ar); - err_free_irq: ath10k_snoc_free_irq(ar); @@ -1376,6 +1622,7 @@ static int ath10k_snoc_remove(struct platform_device *pdev) ath10k_hw_power_off(ar); ath10k_snoc_free_irq(ar); ath10k_snoc_release_resource(ar); + ath10k_qmi_deinit(ar); ath10k_core_destroy(ar); return 0; diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index f9e530189d48..e1d2d6675556 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -19,10 +19,12 @@ #include "hw.h" #include "ce.h" +#include "qmi.h" struct ath10k_snoc_drv_priv { enum ath10k_hw_rev hw_rev; u64 dma_mask; + u32 msa_size; }; struct snoc_state { @@ -81,6 +83,7 @@ struct ath10k_snoc { struct timer_list rx_post_retry; struct ath10k_wcn3990_vreg_info *vreg; struct ath10k_wcn3990_clk_info *clk; + struct ath10k_qmi *qmi; }; static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) @@ -90,5 +93,6 @@ static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value); u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset); +int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type); #endif /* _SNOC_H_ */ From 5ae42611fc2bbd2cc10fc6e523861ce320484384 Mon Sep 17 00:00:00 2001 From: Tobias Schramm Date: Tue, 30 Jan 2018 14:06:02 +0200 Subject: [PATCH 102/192] UPSTREAM: PCI: Add Ubiquiti Networks vendor ID Acked-by: Bjorn Helgaas Signed-off-by: Tobias Schramm Signed-off-by: Kalle Valo Change-Id: I44d256ed53b081a4b3a931ca9249dcd334a8b9eb Git-commit: d5cc61119343b6f1b8716cfe591d4989ea0c5c28 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Govind Singh --- include/linux/pci_ids.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 7fa3f1498b34..f93437e82883 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -149,6 +149,8 @@ #define PCI_VENDOR_ID_DYNALINK 0x0675 #define PCI_DEVICE_ID_DYNALINK_IS64PH 0x1702 +#define PCI_VENDOR_ID_UBIQUITI 0x0777 + #define PCI_VENDOR_ID_BERKOM 0x0871 #define PCI_DEVICE_ID_BERKOM_A1T 0xffa1 #define PCI_DEVICE_ID_BERKOM_T_CONCEPT 0xffa2 From 9f8fe9d00c6e2dd9bf67046ea775f0db694b4765 Mon Sep 17 00:00:00 2001 From: Tobias Schramm Date: Wed, 20 Nov 2019 10:58:02 +0530 Subject: [PATCH 103/192] UPSTREAM: ath10k: add support for Ubiquiti rebranded QCA988X v2 Some modern Ubiquiti devices contain a rebranded QCA988X rev2 with a custom Ubiquiti vendor and device id. This patch adds support for those devices, treating them as a QCA988X v2. Signed-off-by: Tobias Schramm [kvalo@codeaurora.org: rebase, add missing fields in hw_params, fix a long line in pci.c:61] Signed-off-by: Kalle Valo Change-Id: Idccf117407c82bcdb654808db8efc389e0709a91 Git-commit: 34f1cb339cae5c0b6b75094e2d5c79d19be424ed Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/core.c | 29 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 1 + drivers/net/wireless/ath/ath10k/pci.c | 6 ++++++ 3 files changed, 36 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index c0719a68a102..f97da38b056f 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -91,6 +91,35 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, }, + { + .id = QCA988X_HW_2_0_VERSION, + .dev_id = QCA988X_2_0_DEVICE_ID_UBNT, + .name = "qca988x hw2.0 ubiquiti", + .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, + .uart_pin = 7, + .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL, + .otp_exe_param = 0, + .channel_counters_freq_hz = 88000, + .max_probe_resp_desc_thres = 0, + .cal_data_len = 2116, + .fw = { + .dir = QCA988X_HW_2_0_FW_DIR, + .board = QCA988X_HW_2_0_BOARD_DATA_FILE, + .board_size = QCA988X_BOARD_DATA_SZ, + .board_ext_size = QCA988X_BOARD_EXT_DATA_SZ, + }, + .hw_ops = &qca988x_ops, + .decap_align_bytes = 4, + .spectral_bin_discard = 0, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, + .n_cipher_suites = 8, + .num_peers = TARGET_TLV_NUM_PEERS, + .ast_skid_limit = 0x10, + .num_wds_entries = 0x20, + .target_64bit = false, + .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + }, { .id = QCA9887_HW_1_0_VERSION, .dev_id = QCA9887_1_0_DEVICE_ID, diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 685ba71aeeb9..59207462b88a 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -22,6 +22,7 @@ #define ATH10K_FW_DIR "ath10k" +#define QCA988X_2_0_DEVICE_ID_UBNT (0x11ac) #define QCA988X_2_0_DEVICE_ID (0x003c) #define QCA6164_2_1_DEVICE_ID (0x0041) #define QCA6174_2_1_DEVICE_ID (0x003e) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 77fa45a85c7e..755b0aedda24 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -58,6 +58,9 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); #define ATH10K_DIAG_TRANSFER_LIMIT 0x5000 static const struct pci_device_id ath10k_pci_id_table[] = { + /* PCI-E QCA988X V2 (Ubiquiti branded) */ + { PCI_VDEVICE(UBIQUITI, QCA988X_2_0_DEVICE_ID_UBNT) }, + { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */ { PCI_VDEVICE(ATHEROS, QCA6164_2_1_DEVICE_ID) }, /* PCI-E QCA6164 V2.1 */ { PCI_VDEVICE(ATHEROS, QCA6174_2_1_DEVICE_ID) }, /* PCI-E QCA6174 V2.1 */ @@ -74,6 +77,7 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { * hacks. ath10k doesn't have them and these devices crash horribly * because of that. */ + { QCA988X_2_0_DEVICE_ID_UBNT, QCA988X_HW_2_0_CHIP_ID_REV }, { QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV }, { QCA6164_2_1_DEVICE_ID, QCA6174_HW_2_1_CHIP_ID_REV }, @@ -2195,6 +2199,7 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); switch (ar_pci->pdev->device) { + case QCA988X_2_0_DEVICE_ID_UBNT: case QCA988X_2_0_DEVICE_ID: case QCA99X0_2_0_DEVICE_ID: case QCA9888_2_0_DEVICE_ID: @@ -3427,6 +3432,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, u32 (*targ_cpu_to_ce_addr)(struct ath10k *ar, u32 addr); switch (pci_dev->device) { + case QCA988X_2_0_DEVICE_ID_UBNT: case QCA988X_2_0_DEVICE_ID: hw_rev = ATH10K_HW_QCA988X; pci_ps = false; From c7fa7fcd3952821f06a2f00e73972f7247c049af Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Wed, 20 Nov 2019 11:01:59 +0530 Subject: [PATCH 104/192] BACKPORT: UPSTREAM: ath10k: add hw params for shadow register support wcn3990 supports shadow register for ce write. Add a hw param for shadow register support. Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo [govinds@codeaurora.org: resolve trivial merge conflicts in drivers/net/wireless/ath/ath10k/core.c] Change-Id: I0797078c50f7531ecaccc7c305db9f2d6c6e1835 Git-commit: b2e40d7ab8e2d36b455113df96dcbab0407e35c0 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/core.c | 14 ++++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index f97da38b056f..c6ad56f38afd 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -90,6 +90,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA988X_HW_2_0_VERSION, @@ -119,6 +120,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .shadow_reg_support = false, }, { .id = QCA9887_HW_1_0_VERSION, @@ -149,6 +151,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -178,6 +181,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -207,6 +211,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA6174_HW_3_0_VERSION, @@ -236,6 +241,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA6174_HW_3_2_VERSION, @@ -268,6 +274,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA99X0_HW_2_0_DEV_VERSION, @@ -303,6 +310,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA9984_HW_1_0_DEV_VERSION, @@ -343,6 +351,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA9888_HW_2_0_DEV_VERSION, @@ -382,6 +391,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA9377_HW_1_0_DEV_VERSION, @@ -411,6 +421,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA9377_HW_1_1_DEV_VERSION, @@ -442,6 +453,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA4019_HW_1_0_DEV_VERSION, @@ -478,6 +490,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = WCN3990_HW_1_0_DEV_VERSION, @@ -499,6 +512,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = true, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL_DUAL_MAC, .per_ce_irq = true, + .shadow_reg_support = true, }, }; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 59207462b88a..e060df59a03c 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -571,6 +572,9 @@ struct ath10k_hw_params { /* target supporting per ce IRQ */ bool per_ce_irq; + + /* target supporting shadow register for ce write */ + bool shadow_reg_support; }; struct htt_rx_desc; From ebedee3d7763150e5bcba919c0d4bcdbcb9e0563 Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Tue, 17 Apr 2018 17:36:59 +0530 Subject: [PATCH 105/192] UPSTREAM: ath10k: add support for shadow register for WNC3990 WCN3990 needs shadow register write operation support for copy engine for regular operation in powersave mode. Add support for copy engine shadow register write in datapath tx for WCN3990 Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo Change-Id: I7877f8bcc425ff3f05b0c5653396276fe33bf21d Git-commit: b7ba83f7c414e583fdf82a1b1b95d2376cdb4b45 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/ce.c | 143 ++++++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/ce.h | 4 + 2 files changed, 145 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 3a15923bdd26..020405b6d408 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -58,6 +59,74 @@ * the buffer is sent/received. */ +static inline u32 shadow_sr_wr_ind_addr(struct ath10k *ar, + struct ath10k_ce_pipe *ce_state) +{ + u32 ce_id = ce_state->id; + u32 addr = 0; + + switch (ce_id) { + case 0: + addr = 0x00032000; + break; + case 3: + addr = 0x0003200C; + break; + case 4: + addr = 0x00032010; + break; + case 5: + addr = 0x00032014; + break; + case 7: + addr = 0x0003201C; + break; + default: + ath10k_warn(ar, "invalid CE id: %d", ce_id); + break; + } + return addr; +} + +static inline u32 shadow_dst_wr_ind_addr(struct ath10k *ar, + struct ath10k_ce_pipe *ce_state) +{ + u32 ce_id = ce_state->id; + u32 addr = 0; + + switch (ce_id) { + case 1: + addr = 0x00032034; + break; + case 2: + addr = 0x00032038; + break; + case 5: + addr = 0x00032044; + break; + case 7: + addr = 0x0003204C; + break; + case 8: + addr = 0x00032050; + break; + case 9: + addr = 0x00032054; + break; + case 10: + addr = 0x00032058; + break; + case 11: + addr = 0x0003205C; + break; + default: + ath10k_warn(ar, "invalid CE id: %d", ce_id); + break; + } + + return addr; +} + static inline unsigned int ath10k_set_ring_byte(unsigned int offset, struct ath10k_hw_ce_regs_addr_map *addr_map) @@ -123,6 +192,22 @@ static inline u32 ath10k_ce_src_ring_read_index_get(struct ath10k *ar, ar->hw_ce_regs->current_srri_addr); } +static inline void +ath10k_ce_shadow_src_ring_write_index_set(struct ath10k *ar, + struct ath10k_ce_pipe *ce_state, + unsigned int value) +{ + ath10k_ce_write32(ar, shadow_sr_wr_ind_addr(ar, ce_state), value); +} + +static inline void +ath10k_ce_shadow_dest_ring_write_index_set(struct ath10k *ar, + struct ath10k_ce_pipe *ce_state, + unsigned int value) +{ + ath10k_ce_write32(ar, shadow_dst_wr_ind_addr(ar, ce_state), value); +} + static inline void ath10k_ce_src_ring_base_addr_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int addr) @@ -376,8 +461,14 @@ static int _ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, write_index = CE_RING_IDX_INCR(nentries_mask, write_index); /* WORKAROUND */ - if (!(flags & CE_SEND_FLAG_GATHER)) - ath10k_ce_src_ring_write_index_set(ar, ctrl_addr, write_index); + if (!(flags & CE_SEND_FLAG_GATHER)) { + if (ar->hw_params.shadow_reg_support) + ath10k_ce_shadow_src_ring_write_index_set(ar, ce_state, + write_index); + else + ath10k_ce_src_ring_write_index_set(ar, ctrl_addr, + write_index); + } src_ring->write_index = write_index; exit: @@ -1251,6 +1342,22 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar, return 0; } +static int ath10k_ce_alloc_shadow_base(struct ath10k *ar, + struct ath10k_ce_ring *src_ring, + u32 nentries) +{ + src_ring->shadow_base_unaligned = kcalloc(nentries, + sizeof(struct ce_desc), + GFP_KERNEL); + if (!src_ring->shadow_base_unaligned) + return -ENOMEM; + + src_ring->shadow_base = (struct ce_desc *) + PTR_ALIGN(src_ring->shadow_base_unaligned, + CE_DESC_RING_ALIGN); + return 0; +} + static struct ath10k_ce_ring * ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id, const struct ce_attr *attr) @@ -1258,6 +1365,7 @@ ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id, struct ath10k_ce_ring *src_ring; u32 nentries = attr->src_nentries; dma_addr_t base_addr; + int ret; nentries = roundup_pow_of_two(nentries); @@ -1294,6 +1402,19 @@ ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id, ALIGN(src_ring->base_addr_ce_space_unaligned, CE_DESC_RING_ALIGN); + if (ar->hw_params.shadow_reg_support) { + ret = ath10k_ce_alloc_shadow_base(ar, src_ring, nentries); + if (ret) { + dma_free_coherent(ar->dev, + (nentries * sizeof(struct ce_desc) + + CE_DESC_RING_ALIGN), + src_ring->base_addr_owner_space_unaligned, + base_addr); + kfree(src_ring); + return ERR_PTR(ret); + } + } + return src_ring; } @@ -1304,6 +1425,7 @@ ath10k_ce_alloc_src_ring_64(struct ath10k *ar, unsigned int ce_id, struct ath10k_ce_ring *src_ring; u32 nentries = attr->src_nentries; dma_addr_t base_addr; + int ret; nentries = roundup_pow_of_two(nentries); @@ -1339,6 +1461,19 @@ ath10k_ce_alloc_src_ring_64(struct ath10k *ar, unsigned int ce_id, ALIGN(src_ring->base_addr_ce_space_unaligned, CE_DESC_RING_ALIGN); + if (ar->hw_params.shadow_reg_support) { + ret = ath10k_ce_alloc_shadow_base(ar, src_ring, nentries); + if (ret) { + dma_free_coherent(ar->dev, + (nentries * sizeof(struct ce_desc) + + CE_DESC_RING_ALIGN), + src_ring->base_addr_owner_space_unaligned, + base_addr); + kfree(src_ring); + return ERR_PTR(ret); + } + } + return src_ring; } @@ -1505,6 +1640,8 @@ static void _ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; if (ce_state->src_ring) { + if (ar->hw_params.shadow_reg_support) + kfree(ce_state->src_ring->shadow_base_unaligned); dma_free_coherent(ar->dev, (ce_state->src_ring->nentries * sizeof(struct ce_desc) + @@ -1534,6 +1671,8 @@ static void _ath10k_ce_free_pipe_64(struct ath10k *ar, int ce_id) struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; if (ce_state->src_ring) { + if (ar->hw_params.shadow_reg_support) + kfree(ce_state->src_ring->shadow_base_unaligned); dma_free_coherent(ar->dev, (ce_state->src_ring->nentries * sizeof(struct ce_desc_64) + diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index ed96dbfe8894..f230f882ca55 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -113,6 +114,9 @@ struct ath10k_ce_ring { /* CE address space */ u32 base_addr_ce_space; + char *shadow_base_unaligned; + struct ce_desc *shadow_base; + /* keep last */ void *per_transfer_context[0]; }; From 066883a86065331ec1503e0b9c13aa4a25d8cee8 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Wed, 20 Nov 2019 11:18:13 +0530 Subject: [PATCH 106/192] BACKPORT: UPSTREAM: ath10k: enable SRRI/DRRI support on ddr for WCN3990 SRRI/DRRI are not mapped in the HW Shadow block and can lead to un-clocked access if common subsystem in the target is powered down due to idle mode. To mitigate this problem SRRI/DRRI can be read from DDR instead of doing an actual hardware read. Host allocates non cached memory on ddr and configures the physical address of this memory to the CE hardware. The hardware updates the RRI on this particular location. Read SRRI/DRRI from DDR location instead of direct target read. Enable retention restore on ddr using hw params to enable in specific targets. Signed-off-by: Govind Singh Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo [govinds@codeaurora.org: resolve trivial merge conflicts in drivers/net/wireless/ath/ath10k/core.c] Change-Id: I23477617dbd3687f51e0db331c069dc6c181b3d6 Git-commit: 4945af5b264fbdbdb5a9021b8a6a179d0c7a33b2 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/ce.c | 102 +++++++++++++++++++++++-- drivers/net/wireless/ath/ath10k/ce.h | 10 +++ drivers/net/wireless/ath/ath10k/core.c | 14 ++++ drivers/net/wireless/ath/ath10k/hw.c | 9 ++- drivers/net/wireless/ath/ath10k/hw.h | 13 +++- drivers/net/wireless/ath/ath10k/snoc.c | 3 + 6 files changed, 142 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 020405b6d408..3b96a43fbda4 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -185,11 +185,30 @@ static inline u32 ath10k_ce_src_ring_write_index_get(struct ath10k *ar, ar->hw_ce_regs->sr_wr_index_addr); } +static inline u32 ath10k_ce_src_ring_read_index_from_ddr(struct ath10k *ar, + u32 ce_id) +{ + struct ath10k_ce *ce = ath10k_ce_priv(ar); + + return ce->vaddr_rri[ce_id] & CE_DDR_RRI_MASK; +} + static inline u32 ath10k_ce_src_ring_read_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_ce_read32(ar, ce_ctrl_addr + - ar->hw_ce_regs->current_srri_addr); + struct ath10k_ce *ce = ath10k_ce_priv(ar); + u32 ce_id = COPY_ENGINE_ID(ce_ctrl_addr); + struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; + u32 index; + + if (ar->hw_params.rri_on_ddr && + (ce_state->attr_flags & CE_ATTR_DIS_INTR)) + index = ath10k_ce_src_ring_read_index_from_ddr(ar, ce_id); + else + index = ath10k_ce_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->current_srri_addr); + + return index; } static inline void @@ -266,11 +285,31 @@ static inline void ath10k_ce_dest_ring_byte_swap_set(struct ath10k *ar, ath10k_set_ring_byte(n, ctrl_regs->dst_ring)); } +static inline + u32 ath10k_ce_dest_ring_read_index_from_ddr(struct ath10k *ar, u32 ce_id) +{ + struct ath10k_ce *ce = ath10k_ce_priv(ar); + + return (ce->vaddr_rri[ce_id] >> CE_DDR_DRRI_SHIFT) & + CE_DDR_RRI_MASK; +} + static inline u32 ath10k_ce_dest_ring_read_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_ce_read32(ar, ce_ctrl_addr + - ar->hw_ce_regs->current_drri_addr); + struct ath10k_ce *ce = ath10k_ce_priv(ar); + u32 ce_id = COPY_ENGINE_ID(ce_ctrl_addr); + struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; + u32 index; + + if (ar->hw_params.rri_on_ddr && + (ce_state->attr_flags & CE_ATTR_DIS_INTR)) + index = ath10k_ce_dest_ring_read_index_from_ddr(ar, ce_id); + else + index = ath10k_ce_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->current_drri_addr); + + return index; } static inline void ath10k_ce_dest_ring_base_addr_set(struct ath10k *ar, @@ -486,7 +525,7 @@ static int _ath10k_ce_send_nolock_64(struct ath10k_ce_pipe *ce_state, struct ath10k_ce_ring *src_ring = ce_state->src_ring; struct ce_desc_64 *desc, sdesc; unsigned int nentries_mask = src_ring->nentries_mask; - unsigned int sw_index = src_ring->sw_index; + unsigned int sw_index; unsigned int write_index = src_ring->write_index; u32 ctrl_addr = ce_state->ctrl_addr; __le32 *addr; @@ -500,6 +539,11 @@ static int _ath10k_ce_send_nolock_64(struct ath10k_ce_pipe *ce_state, ath10k_warn(ar, "%s: send more we can (nbytes: %d, max: %d)\n", __func__, nbytes, ce_state->src_sz_max); + if (ar->hw_params.rri_on_ddr) + sw_index = ath10k_ce_src_ring_read_index_from_ddr(ar, ce_state->id); + else + sw_index = src_ring->sw_index; + if (unlikely(CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) <= 0)) { ret = -ENOSR; @@ -1016,7 +1060,10 @@ int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, src_ring->hw_index = read_index; } - read_index = src_ring->hw_index; + if (ar->hw_params.rri_on_ddr) + read_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); + else + read_index = src_ring->hw_index; if (read_index == sw_index) return -EIO; @@ -1841,3 +1888,46 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, return 0; } EXPORT_SYMBOL(ath10k_ce_alloc_pipe); + +void ath10k_ce_alloc_rri(struct ath10k *ar) +{ + int i; + u32 value; + u32 ctrl1_regs; + u32 ce_base_addr; + struct ath10k_ce *ce = ath10k_ce_priv(ar); + + ce->vaddr_rri = dma_alloc_coherent(ar->dev, + (CE_COUNT * sizeof(u32)), + &ce->paddr_rri, GFP_KERNEL); + + if (!ce->vaddr_rri) + return; + + ath10k_ce_write32(ar, ar->hw_ce_regs->ce_rri_low, + lower_32_bits(ce->paddr_rri)); + ath10k_ce_write32(ar, ar->hw_ce_regs->ce_rri_high, + (upper_32_bits(ce->paddr_rri) & + CE_DESC_FLAGS_GET_MASK)); + + for (i = 0; i < CE_COUNT; i++) { + ctrl1_regs = ar->hw_ce_regs->ctrl1_regs->addr; + ce_base_addr = ath10k_ce_base_address(ar, i); + value = ath10k_ce_read32(ar, ce_base_addr + ctrl1_regs); + value |= ar->hw_ce_regs->upd->mask; + ath10k_ce_write32(ar, ce_base_addr + ctrl1_regs, value); + } + + memset(ce->vaddr_rri, 0, CE_COUNT * sizeof(u32)); +} +EXPORT_SYMBOL(ath10k_ce_alloc_rri); + +void ath10k_ce_free_rri(struct ath10k *ar) +{ + struct ath10k_ce *ce = ath10k_ce_priv(ar); + + dma_free_coherent(ar->dev, (CE_COUNT * sizeof(u32)), + ce->vaddr_rri, + ce->paddr_rri); +} +EXPORT_SYMBOL(ath10k_ce_free_rri); diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index f230f882ca55..0c3a1ad25a9a 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -49,6 +49,9 @@ struct ath10k_ce_pipe; #define CE_DESC_FLAGS_META_DATA_MASK ar->hw_values->ce_desc_meta_data_mask #define CE_DESC_FLAGS_META_DATA_LSB ar->hw_values->ce_desc_meta_data_lsb +#define CE_DDR_RRI_MASK GENMASK(15, 0) +#define CE_DDR_DRRI_SHIFT 16 + struct ce_desc { __le32 addr; __le16 nbytes; @@ -157,6 +160,8 @@ struct ath10k_ce { spinlock_t ce_lock; const struct ath10k_bus_ops *bus_ops; struct ath10k_ce_pipe ce_states[CE_COUNT_MAX]; + u32 *vaddr_rri; + dma_addr_t paddr_rri; }; /*==================Send====================*/ @@ -265,6 +270,8 @@ int ath10k_ce_disable_interrupts(struct ath10k *ar); void ath10k_ce_enable_interrupts(struct ath10k *ar); void ath10k_ce_dump_registers(struct ath10k *ar, struct ath10k_fw_crash_data *crash_data); +void ath10k_ce_alloc_rri(struct ath10k *ar); +void ath10k_ce_free_rri(struct ath10k *ar); /* ce_attr.flags values */ /* Use NonSnooping PCIe accesses? */ @@ -330,6 +337,9 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) return CE0_BASE_ADDRESS + (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS) * ce_id; } +#define COPY_ENGINE_ID(COPY_ENGINE_BASE_ADDRESS) (((COPY_ENGINE_BASE_ADDRESS) \ + - CE0_BASE_ADDRESS) / (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS)) + #define CE_SRC_RING_TO_DESC(baddr, idx) \ (&(((struct ce_desc *)baddr)[idx])) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index c6ad56f38afd..77b22c42bc7b 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -91,6 +91,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA988X_HW_2_0_VERSION, @@ -121,6 +122,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA9887_HW_1_0_VERSION, @@ -152,6 +154,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -182,6 +185,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -212,6 +216,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA6174_HW_3_0_VERSION, @@ -242,6 +247,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA6174_HW_3_2_VERSION, @@ -275,6 +281,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA99X0_HW_2_0_DEV_VERSION, @@ -311,6 +318,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA9984_HW_1_0_DEV_VERSION, @@ -352,6 +360,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA9888_HW_2_0_DEV_VERSION, @@ -392,6 +401,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA9377_HW_1_0_DEV_VERSION, @@ -422,6 +432,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA9377_HW_1_1_DEV_VERSION, @@ -454,6 +465,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA4019_HW_1_0_DEV_VERSION, @@ -491,6 +503,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = WCN3990_HW_1_0_DEV_VERSION, @@ -513,6 +526,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL_DUAL_MAC, .per_ce_irq = true, .shadow_reg_support = true, + .rri_on_ddr = true, }, }; diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index d8a199448386..1ffaeb1dd71d 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -310,6 +310,12 @@ static struct ath10k_hw_ce_dst_src_wm_regs wcn3990_wm_dst_ring = { .wm_high = &wcn3990_dst_wm_high, }; +static struct ath10k_hw_ce_ctrl1_upd wcn3990_ctrl1_upd = { + .shift = 19, + .mask = 0x00080000, + .enable = 0x00000000, +}; + struct ath10k_hw_ce_regs wcn3990_ce_regs = { .sr_base_addr = 0x00000000, .sr_size_addr = 0x00000008, @@ -320,8 +326,6 @@ struct ath10k_hw_ce_regs wcn3990_ce_regs = { .dst_wr_index_addr = 0x00000040, .current_srri_addr = 0x00000044, .current_drri_addr = 0x00000048, - .ddr_addr_for_rri_low = 0x00000004, - .ddr_addr_for_rri_high = 0x00000008, .ce_rri_low = 0x0024C004, .ce_rri_high = 0x0024C008, .host_ie_addr = 0x0000002c, @@ -331,6 +335,7 @@ struct ath10k_hw_ce_regs wcn3990_ce_regs = { .misc_regs = &wcn3990_misc_reg, .wm_srcr = &wcn3990_wm_src_ring, .wm_dstr = &wcn3990_wm_dst_ring, + .upd = &wcn3990_ctrl1_upd, }; const struct ath10k_hw_values wcn3990_values = { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index e060df59a03c..bb68f11d9951 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -336,6 +336,12 @@ struct ath10k_hw_ce_dst_src_wm_regs { struct ath10k_hw_ce_regs_addr_map *wm_low; struct ath10k_hw_ce_regs_addr_map *wm_high; }; +struct ath10k_hw_ce_ctrl1_upd { + u32 shift; + u32 mask; + u32 enable; +}; + struct ath10k_hw_ce_regs { u32 sr_base_addr; u32 sr_size_addr; @@ -358,7 +364,9 @@ struct ath10k_hw_ce_regs { struct ath10k_hw_ce_cmd_halt *cmd_halt; struct ath10k_hw_ce_host_ie *host_ie; struct ath10k_hw_ce_dst_src_wm_regs *wm_srcr; - struct ath10k_hw_ce_dst_src_wm_regs *wm_dstr; }; + struct ath10k_hw_ce_dst_src_wm_regs *wm_dstr; + struct ath10k_hw_ce_ctrl1_upd *upd; +}; struct ath10k_hw_values { u32 rtc_state_val_on; @@ -575,6 +583,9 @@ struct ath10k_hw_params { /* target supporting shadow register for ce write */ bool shadow_reg_support; + + /* target supporting retention restore on ddr */ + bool rri_on_ddr; }; struct htt_rx_desc; diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 293f5116b172..c00107978c99 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -768,6 +768,7 @@ static void ath10k_snoc_hif_power_down(struct ath10k *ar) ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n"); ath10k_snoc_wlan_disable(ar); + ath10k_ce_free_rri(ar); } static int ath10k_snoc_hif_power_up(struct ath10k *ar) @@ -783,6 +784,8 @@ static int ath10k_snoc_hif_power_up(struct ath10k *ar) return ret; } + ath10k_ce_alloc_rri(ar); + ret = ath10k_snoc_init_pipes(ar); if (ret) { ath10k_err(ar, "failed to initialize CE: %d\n", ret); From 0d415741162c8c5a9c8722359586bd39f845d324 Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Wed, 20 Nov 2019 15:34:48 +0530 Subject: [PATCH 107/192] BACKPORT: UPSTREAM: ath10k: skip resetting rx filter for WCN3990 WCN3990 has the MAC_PCU_ADDR1 configured properly and hence it will not send spurious ack frames during boot up. Hence the reset_rx_filter workaround is not needed for WCN3990. Add a hw_param to indicate if hardware rx filter reset is needed and skip the reset_rx_filter for WCN3990. Tested HW: WCN3990 Tested FW: WLAN.HL.2.0-01188-QCAHLSWMTPLZ-1 Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo [govinds@codeaurora.org: resolve trivial merge conflicts in drivers/net/wireless/ath/ath10k/hw.h] Change-Id: I417d4dcd16fe9518b9a48fc8154f764ccf457e2d Git-commit: 58da3b42307061b71f2dcce2bd1185d578a3aa53 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/core.c | 17 ++++++++++++++++- drivers/net/wireless/ath/ath10k/hw.h | 5 +++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 77b22c42bc7b..ebd709bde222 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -92,6 +92,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA988X_HW_2_0_VERSION, @@ -123,6 +124,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA9887_HW_1_0_VERSION, @@ -155,6 +157,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA6174_HW_2_1_VERSION, @@ -186,6 +189,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA6174_HW_2_1_VERSION, @@ -217,6 +221,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA6174_HW_3_0_VERSION, @@ -248,6 +253,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA6174_HW_3_2_VERSION, @@ -282,6 +288,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA99X0_HW_2_0_DEV_VERSION, @@ -319,6 +326,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA9984_HW_1_0_DEV_VERSION, @@ -361,6 +369,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA9888_HW_2_0_DEV_VERSION, @@ -402,6 +411,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA9377_HW_1_0_DEV_VERSION, @@ -433,6 +443,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA9377_HW_1_1_DEV_VERSION, @@ -466,6 +477,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = QCA4019_HW_1_0_DEV_VERSION, @@ -504,6 +516,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, + .hw_filter_reset_required = true, }, { .id = WCN3990_HW_1_0_DEV_VERSION, @@ -527,6 +540,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .per_ce_irq = true, .shadow_reg_support = true, .rri_on_ddr = true, + .hw_filter_reset_required = false, }, }; @@ -2386,7 +2400,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, * possible to implicitly make it correct by creating a dummy vdev and * then deleting it. */ - if (mode == ATH10K_FIRMWARE_MODE_NORMAL) { + if (ar->hw_params.hw_filter_reset_required && + mode == ATH10K_FIRMWARE_MODE_NORMAL) { status = ath10k_core_reset_rx_filter(ar); if (status) { ath10k_err(ar, diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index bb68f11d9951..0cd06de308d4 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -586,6 +586,11 @@ struct ath10k_hw_params { /* target supporting retention restore on ddr */ bool rri_on_ddr; + + /* targets which require hw filter reset during boot up, + * to avoid it sending spurious acks. + */ + bool hw_filter_reset_required; }; struct htt_rx_desc; From a628ebd89b4841d568144e8e5bb60e1ce262146f Mon Sep 17 00:00:00 2001 From: Suraj Jaiswal Date: Wed, 6 May 2020 19:38:39 +0530 Subject: [PATCH 108/192] net: stmmac: Ethtool half duplex not supported Half duplex is not supported by the driver. Return error for Half duplex setting. Change-Id: I16bc99f66d52f236412b1513964e37f266d7c649 Signed-off-by: Suraj Jaiswal --- drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 8c7109008185..7cc9e5ec9909 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -402,9 +402,11 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev, return 0; } - - rc = phy_ethtool_ksettings_set(phy, cmd); - + /* Half duplex is not supported */ + if (cmd->base.duplex != DUPLEX_FULL) + rc = -EINVAL; + else + rc = phy_ethtool_ksettings_set(phy, cmd); return rc; } From ea795d293717bc300d9c5aa6c540e06d73beecff Mon Sep 17 00:00:00 2001 From: Lakshit Tyagi Date: Wed, 15 Jul 2020 16:48:32 +0530 Subject: [PATCH 109/192] net: stmmac: Fixed autoneg disable issue Don't support 1Gbps link speed when autoneg is disabled. Change-Id: Ic40703beab56684689e686fc3e717d99be8d5bb0 Signed-off-by: Lakshit Tyagi --- drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 7cc9e5ec9909..fc89b34b74e8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -376,6 +376,7 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev, struct stmmac_priv *priv = netdev_priv(dev); struct phy_device *phy = dev->phydev; int rc; + u32 cmd_speed = cmd->base.speed; if (priv->hw->pcs & STMMAC_PCS_RGMII || priv->hw->pcs & STMMAC_PCS_SGMII) { @@ -402,11 +403,14 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev, return 0; } + /* Half duplex is not supported */ - if (cmd->base.duplex != DUPLEX_FULL) + if (cmd->base.duplex != DUPLEX_FULL || + (cmd_speed == SPEED_1000 && cmd->base.autoneg == AUTONEG_DISABLE)) rc = -EINVAL; else rc = phy_ethtool_ksettings_set(phy, cmd); + return rc; } From 54ab11cae1568c75e6a8627e0f076a43145223f6 Mon Sep 17 00:00:00 2001 From: Rama Krishna Phani A Date: Tue, 7 Jul 2020 16:02:33 +0530 Subject: [PATCH 110/192] msm: sps: Correct descriptor fifo address to dump contents Few clients of BAM will use SMMU for data transfers. Assign correct descriptor fifo address for SMMU clients of BAM while dumping contents. Change-Id: I21584e6778315f51cac0d202d41f4c81a56fcbf0 Signed-off-by: Rama Krishna Phani A --- drivers/platform/msm/sps/bam.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c index c2b2137185b8..be6e45604f8a 100644 --- a/drivers/platform/msm/sps/bam.c +++ b/drivers/platform/msm/sps/bam.c @@ -2174,13 +2174,16 @@ void print_bam_pipe_desc_fifo(void *virt_addr, u32 pipe_index, u32 option) u32 pipe = pipe_index; u32 desc_fifo_addr; u32 desc_fifo_size; - u32 *desc_fifo; + u32 __iomem *desc_fifo; int i; char desc_info[MAX_MSG_LEN]; + struct sps_bam *dev; if (base == NULL) return; + dev = to_sps_bam_dev(virt_addr); + desc_fifo_addr = bam_read_reg(base, P_DESC_FIFO_ADDR, pipe); desc_fifo_size = bam_read_reg_field(base, P_FIFO_SIZES, pipe, P_DESC_FIFO_SIZE); @@ -2202,7 +2205,14 @@ void print_bam_pipe_desc_fifo(void *virt_addr, u32 pipe_index, u32 option) "BAM_P_DESC_FIFO_SIZE: 0x%x (%d)\n\n", desc_fifo_addr, desc_fifo_size, desc_fifo_size); - desc_fifo = (u32 *) phys_to_virt(desc_fifo_addr); + if (dev->props.options & SPS_BAM_SMMU_EN) { + struct sps_pipe *pipe_indx = dev->pipes[pipe_index]; + + SPS_DUMP("%s", "SMMU is enabled\n"); + desc_fifo = pipe_indx->map->desc.base; + } else { + desc_fifo = (u32 __iomem *) phys_to_virt(desc_fifo_addr); + } if (option == 100) { SPS_DUMP("%s", From 5a682290077d7c6826f61dcfcbcf76ebb2d21a03 Mon Sep 17 00:00:00 2001 From: Wyes Karny Date: Mon, 6 Jul 2020 22:17:22 +0530 Subject: [PATCH 111/192] msm: camera: isp: Dumping state monitor array to debug logs During dumping state monitor array info logs, tasklet is taking more time to print the logs, that is causing delay in processing the next irqs in the tasklet. This is causing the isp state going to bubble state repeatedly. So changing the dump state monitor array logs to debug logs. Change-Id: Id58d6b3aa7e7da4338ef2f69c6b76e4c1477efbc Signed-off-by: Wyes Karny --- drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c index 5ebe3767f87d..3ed714658e44 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 @@ -228,7 +228,7 @@ static void __cam_isp_ctx_dump_state_monitor_array( ctx_monitor = ctx_isp->cam_isp_ctx_state_monitor; if (log_rate_limit) - CAM_INFO_RATE_LIMIT_CUSTOM(CAM_ISP, 5, 20, + CAM_DBG(CAM_ISP, "Dumping state information for preceding requests"); else CAM_INFO(CAM_ISP, @@ -241,7 +241,7 @@ static void __cam_isp_ctx_dump_state_monitor_array( CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES); if (log_rate_limit) { - CAM_INFO_RATE_LIMIT_CUSTOM(CAM_ISP, 5, 20, + CAM_DBG(CAM_ISP, "time[%lld] last reported req_id[%u] frame id[%lld] applied id[%lld] current state[%s] next state[%s] hw_event[%s]", ctx_monitor[index].evt_time_stamp, ctx_monitor[index].last_reported_id, From 1abf1a982a8d07da0a5efc1229772e55d648eef9 Mon Sep 17 00:00:00 2001 From: Ashish Chavan Date: Mon, 6 Apr 2020 23:09:13 +0530 Subject: [PATCH 112/192] power: battery: Add support to enable PPS to work in CV mode Add support to enable PPS to work in CV mode by allowing ICL to be split for PPS adapter where the maximum ILIM for it is been limited to min(qc4_icl_ua, pd_current_max). Change-Id: Iac3b4a4964783eb7f60a93e2237058f687e3de09 Signed-off-by: Ashish Chavan --- drivers/power/supply/qcom/battery.c | 58 ++++++++++++++++++++------- drivers/power/supply/qcom/battery.h | 1 + drivers/power/supply/qcom/qpnp-smb5.c | 7 ++++ 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 1d195ef98a24..fe9055ee8ba2 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -49,6 +49,7 @@ #define FCC_STEPPER_VOTER "FCC_STEPPER_VOTER" #define FCC_VOTER "FCC_VOTER" #define MAIN_FCC_VOTER "MAIN_FCC_VOTER" +#define PD_VOTER "PD_VOTER" struct pl_data { int pl_mode; @@ -198,30 +199,57 @@ static int cp_get_parallel_mode(struct pl_data *chip, int mode) return pval.intval; } -static int get_hvdcp3_icl_limit(struct pl_data *chip) +static int get_adapter_icl_based_ilim(struct pl_data *chip) { - int main_icl, target_icl = -EINVAL; + int main_icl, adapter_icl = -EINVAL, rc = -EINVAL, final_icl = -EINVAL; + union power_supply_propval pval = {0, }; + + rc = power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_PD_ACTIVE, &pval); + if (rc < 0) + pr_err("Failed to read PD_ACTIVE status rc=%d\n", + rc); + /* Check for QC 3, 3.5 and PPS adapters, return if its none of them */ + if (chip->charger_type != POWER_SUPPLY_TYPE_USB_HVDCP_3 && + chip->charger_type != POWER_SUPPLY_TYPE_USB_HVDCP_3P5 && + pval.intval != POWER_SUPPLY_PD_PPS_ACTIVE) + return final_icl; - if ((chip->charger_type != POWER_SUPPLY_TYPE_USB_HVDCP_3) - && (chip->charger_type != POWER_SUPPLY_TYPE_USB_HVDCP_3P5)) - return target_icl; + /* + * For HVDCP3/HVDCP_3P5 adapters, limit max. ILIM as: + * HVDCP3_ICL: Maximum ICL of HVDCP3 adapter(from DT + * configuration). + * + * For PPS adapters, limit max. ILIM to + * MIN(qc4_max_icl, PD_CURRENT_MAX) + */ + if (pval.intval == POWER_SUPPLY_PD_PPS_ACTIVE) { + adapter_icl = min_t(int, chip->chg_param->qc4_max_icl_ua, + get_client_vote_locked(chip->usb_icl_votable, + PD_VOTER)); + if (adapter_icl <= 0) + adapter_icl = chip->chg_param->qc4_max_icl_ua; + } else { + adapter_icl = chip->chg_param->hvdcp3_max_icl_ua; + } /* - * For HVDCP3 adapters, limit max. ILIM as follows: - * HVDCP3_ICL: Maximum ICL of HVDCP3 adapter(from DT configuration) * For Parallel input configurations: - * VBUS: target_icl = HVDCP3_ICL - main_ICL - * VMID: target_icl = HVDCP3_ICL + * VBUS: final_icl = adapter_icl - main_ICL + * VMID: final_icl = adapter_icl */ - target_icl = chip->chg_param->hvdcp3_max_icl_ua; + final_icl = adapter_icl; if (cp_get_parallel_mode(chip, PARALLEL_INPUT_MODE) == POWER_SUPPLY_PL_USBIN_USBIN) { main_icl = get_effective_result_locked(chip->usb_icl_votable); - if ((main_icl >= 0) && (main_icl < target_icl)) - target_icl -= main_icl; + if ((main_icl >= 0) && (main_icl < adapter_icl)) + final_icl = adapter_icl - main_icl; } - return target_icl; + pr_debug("charger_type=%d final_icl=%d adapter_icl=%d main_icl=%d\n", + chip->charger_type, final_icl, adapter_icl, main_icl); + + return final_icl; } /* @@ -252,7 +280,7 @@ static void cp_configure_ilim(struct pl_data *chip, const char *voter, int ilim) == POWER_SUPPLY_PL_OUTPUT_VPH) return; - target_icl = get_hvdcp3_icl_limit(chip); + target_icl = get_adapter_icl_based_ilim(chip); ilim = (target_icl > 0) ? min(ilim, target_icl) : ilim; rc = power_supply_get_property(chip->cp_master_psy, @@ -750,7 +778,7 @@ static void get_fcc_stepper_params(struct pl_data *chip, int main_fcc_ua, if (!chip->cp_ilim_votable) chip->cp_ilim_votable = find_votable("CP_ILIM"); - target_icl = get_hvdcp3_icl_limit(chip) * 2; + target_icl = get_adapter_icl_based_ilim(chip) * 2; total_fcc_ua -= chip->main_fcc_ua; /* diff --git a/drivers/power/supply/qcom/battery.h b/drivers/power/supply/qcom/battery.h index 0ff716a3d97b..5d2e783ead82 100644 --- a/drivers/power/supply/qcom/battery.h +++ b/drivers/power/supply/qcom/battery.h @@ -19,6 +19,7 @@ struct charger_param { u32 smb_version; u32 hvdcp3_max_icl_ua; u32 forced_main_fcc; + u32 qc4_max_icl_ua; }; int qcom_batt_init(struct charger_param *param); diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 09d2995e5bbc..91e575e159f0 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -387,6 +387,7 @@ static int smb5_configure_internal_pull(struct smb_charger *chg, int type, #define MICRO_P1A 100000 #define MICRO_1PA 1000000 #define MICRO_3PA 3000000 +#define MICRO_4PA 4000000 #define OTG_DEFAULT_DEGLITCH_TIME_MS 50 #define DEFAULT_WD_BARK_TIME 64 #define DEFAULT_WD_SNARL_TIME_8S 0x07 @@ -653,6 +654,12 @@ static int smb5_parse_dt(struct smb5 *chip) if (chg->chg_param.hvdcp3_max_icl_ua <= 0) chg->chg_param.hvdcp3_max_icl_ua = MICRO_3PA; + /* Used only in Adapter CV mode of operation */ + of_property_read_u32(node, "qcom,qc4-max-icl-ua", + &chg->chg_param.qc4_max_icl_ua); + if (chg->chg_param.qc4_max_icl_ua <= 0) + chg->chg_param.qc4_max_icl_ua = MICRO_4PA; + chg->wls_icl_ua = DCIN_ICL_MAX_UA; rc = of_property_read_u32(node, "qcom,wls-current-max-ua", &tmp); From ac9f068080fc9123741c8fc97ad2ef06f2d40b50 Mon Sep 17 00:00:00 2001 From: Ashish Chavan Date: Wed, 3 Jun 2020 20:09:40 +0530 Subject: [PATCH 113/192] power: smb1398: Update default cp-min-icl to 1A for HVDCP3 Update default cp-min-icl value to MAX(dt_min_icl, 1A) when charging with HVDCP3. Change-Id: I44c9fd306414ed052f88ccc45cc377a6bce1ae9c Signed-off-by: Ashish Chavan --- drivers/power/supply/qcom/smb1398-charger.c | 34 +++++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/drivers/power/supply/qcom/smb1398-charger.c b/drivers/power/supply/qcom/smb1398-charger.c index 5f834401ab0b..8158883fb666 100644 --- a/drivers/power/supply/qcom/smb1398-charger.c +++ b/drivers/power/supply/qcom/smb1398-charger.c @@ -879,6 +879,24 @@ static int div2_cp_master_get_prop_suspended(struct smb1398_chip *chip, return 0; } +#define DEFAULT_HVDCP3_MIN_ICL_UA 1000000 +static int smb1398_div2_cp_get_min_icl(struct smb1398_chip *chip) +{ + union power_supply_propval pval; + int rc; + + /* Use max(dt_min_icl, 1A) for HVDCP3 */ + if (chip->usb_psy) { + rc = power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_REAL_TYPE, &pval); + if (rc >= 0 && (pval.intval == POWER_SUPPLY_TYPE_USB_HVDCP_3)) + return max(chip->div2_cp_min_ilim_ua, + DEFAULT_HVDCP3_MIN_ICL_UA); + } + + return chip->div2_cp_min_ilim_ua; +} + static int div2_cp_master_get_prop(struct power_supply *psy, enum power_supply_property prop, union power_supply_propval *val) @@ -979,7 +997,7 @@ static int div2_cp_master_get_prop(struct power_supply *psy, val->intval = chip->pl_output_mode; break; case POWER_SUPPLY_PROP_MIN_ICL: - val->intval = chip->div2_cp_min_ilim_ua; + val->intval = smb1398_div2_cp_get_min_icl(chip); break; default: rc = -EINVAL; @@ -1278,7 +1296,7 @@ static int smb1398_div2_cp_ilim_vote_cb(struct votable *votable, { struct smb1398_chip *chip = (struct smb1398_chip *)data; union power_supply_propval pval = {0}; - int rc = 0, max_ilim_ua; + int rc = 0, max_ilim_ua, min_ilim_ua; bool slave_dis, split_ilim = false; if (!is_psy_voter_available(chip) || chip->in_suspend) @@ -1287,19 +1305,21 @@ static int smb1398_div2_cp_ilim_vote_cb(struct votable *votable, if (!client) return -EINVAL; + min_ilim_ua = smb1398_div2_cp_get_min_icl(chip); + ilim_ua = (ilim_ua * DIV2_ILIM_CFG_PCT) / 100; max_ilim_ua = is_cps_available(chip) ? DIV2_MAX_ILIM_DUAL_CP_UA : DIV2_MAX_ILIM_UA; ilim_ua = min(ilim_ua, max_ilim_ua); - if (ilim_ua < chip->div2_cp_min_ilim_ua) { + if (ilim_ua < min_ilim_ua) { dev_dbg(chip->dev, "ilim %duA is too low to config CP charging\n", ilim_ua); vote(chip->div2_cp_disable_votable, ILIM_VOTER, true, 0); } else { if (is_cps_available(chip)) { split_ilim = true; - slave_dis = ilim_ua < (2 * chip->div2_cp_min_ilim_ua); + slave_dis = ilim_ua < (2 * min_ilim_ua); vote(chip->div2_cp_slave_disable_votable, ILIM_VOTER, slave_dis, 0); slave_dis = !!get_effective_result( @@ -1726,7 +1746,7 @@ static void smb1398_taper_work(struct work_struct *work) struct smb1398_chip *chip = container_of(work, struct smb1398_chip, taper_work); union power_supply_propval pval = {0}; - int rc, fcc_ua, fv_uv, stepper_ua, main_fcc_ua = 0; + int rc, fcc_ua, fv_uv, stepper_ua, main_fcc_ua, min_ilim_ua; bool slave_en; if (!is_psy_voter_available(chip)) @@ -1738,6 +1758,8 @@ static void smb1398_taper_work(struct work_struct *work) if (chip->fcc_main_votable) main_fcc_ua = get_effective_result(chip->fcc_main_votable); + min_ilim_ua = smb1398_div2_cp_get_min_icl(chip); + chip->taper_entry_fv = get_effective_result(chip->fv_votable); while (true) { rc = power_supply_get_property(chip->batt_psy, @@ -1773,7 +1795,7 @@ static void smb1398_taper_work(struct work_struct *work) * If total FCC is less than the minimum ILIM to * keep CP master and slave online, disable CP. */ - if (fcc_ua < (chip->div2_cp_min_ilim_ua * 2)) { + if (fcc_ua < (min_ilim_ua * 2)) { vote(chip->div2_cp_disable_votable, TAPER_VOTER, true, 0); /* From 8932a5c2237c5b1cbba02a310b2350b151b9ae7a Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Fri, 5 Jun 2020 15:59:51 +0530 Subject: [PATCH 114/192] power: smb1398-charger: Update the OVP threshold to 14V Update the OVP threshold to 14V for SMB1390 V3. Change-Id: I868002d932647ad64a3ede67f8b7cb1e2e451735 Signed-off-by: Anirudh Ghayal --- drivers/power/supply/qcom/smb1398-charger.c | 66 +++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/drivers/power/supply/qcom/smb1398-charger.c b/drivers/power/supply/qcom/smb1398-charger.c index 8158883fb666..1305317bfb1e 100644 --- a/drivers/power/supply/qcom/smb1398-charger.c +++ b/drivers/power/supply/qcom/smb1398-charger.c @@ -26,6 +26,8 @@ #include /* Status register definition */ +#define PERPH0_REVISION4 0x2603 + #define INPUT_STATUS_REG 0x2609 #define INPUT_USB_IN BIT(1) #define INPUT_WLS_IN BIT(0) @@ -177,6 +179,10 @@ #define PERPH0_CFG_SDCDC_REG 0x267A #define EN_WIN_UV_BIT BIT(7) +#define PERPH0_SSUPPLY_CFG0_REG 0x2682 +#define EN_HV_OV_OPTION2_BIT BIT(7) +#define EN_MV_OV_OPTION2_BIT BIT(5) + #define SSUPLY_TEMP_CTRL_REG 0x2683 #define SEL_OUT_TEMP_MAX_MASK GENMASK(7, 5) #define SEL_OUT_TEMP_MAX_SHFT 5 @@ -191,6 +197,10 @@ #define DIV2_ILIM_STS BIT(5) #define DIV2_CFLY_SS_DONE_STS BIT(1) +#define PERPH1_LOCK_SPARE_REG 0x27C3 +#define CFG_LOCK_SPARE1_MASK GENMASK(7, 6) +#define CFG_LOCK_SPARE1_SHIFT 6 + /* available voters */ #define ILIM_VOTER "ILIM_VOTER" #define TAPER_VOTER "TAPER_VOTER" @@ -232,6 +242,13 @@ enum isns_mode { ISNS_MODE_STANDBY, }; +enum ovp { + OVP_17P7V = 0, + OVP_14V, + OVP_22P2V, + OVP_7P3, +}; + enum { /* Perph0 IRQs */ CFLY_HARD_FAULT_LATCH_IRQ, @@ -1844,10 +1861,53 @@ static void smb1398_taper_work(struct work_struct *work) chip->taper_work_running = false; } +static int smb1398_update_ovp(struct smb1398_chip *chip) +{ + int rc = 0; + u8 reg = 0; + + rc = smb1398_read(chip, PERPH0_REVISION4, ®); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't read PERPH0_REVISION4 rc=%d\n", rc); + return rc; + } + + /* Ignore for REV2 and below */ + if (reg <= 2) + return 0; + + rc = smb1398_masked_write(chip, PERPH0_SSUPPLY_CFG0_REG, + EN_HV_OV_OPTION2_BIT | EN_MV_OV_OPTION2_BIT, + EN_HV_OV_OPTION2_BIT); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't set PERPH0_SSUPPLY_CFG0_REG rc=%d\n", rc); + return rc; + } + + rc = smb1398_masked_write(chip, PERPH1_LOCK_SPARE_REG, + CFG_LOCK_SPARE1_MASK, + OVP_14V << CFG_LOCK_SPARE1_SHIFT); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't set PERPH1_LOCK_SPARE_REG rc=%d\n", rc); + return rc; + } + + return 0; +} + static int smb1398_div2_cp_hw_init(struct smb1398_chip *chip) { int rc = 0; + rc = smb1398_update_ovp(chip); + if (rc < 0) { + dev_err(chip->dev, "Couldn't update OVP threshold rc=%d\n", rc); + return rc; + } + /* Configure window (Vin/2 - Vout) OV level to 500mV */ rc = smb1398_masked_write(chip, DIV2_PROTECTION_REG, DIV2_WIN_OV_SEL_MASK, WIN_OV_500_MV); @@ -2168,6 +2228,12 @@ static int smb1398_div2_cp_slave_probe(struct smb1398_chip *chip) int rc; u8 status; + rc = smb1398_update_ovp(chip); + if (rc < 0) { + dev_err(chip->dev, "Couldn't update OVP threshold rc=%d\n", rc); + return rc; + } + rc = smb1398_read(chip, MODE_STATUS_REG, &status); if (rc < 0) { dev_err(chip->dev, "Couldn't read slave MODE_STATUS_REG, rc=%d\n", From efbb8b6f5b2605ec1b49da6e71ca0c0ac03f5f44 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 9 Jun 2020 14:23:28 +0800 Subject: [PATCH 115/192] power: smb1398-charger: disable sync between master and slave Disable clock sync between master and slave and enable slave clock to make it switching on its own clock. Change-Id: I738b69118f8f7766d4109e551dae310204ffef4b Signed-off-by: Fenglin Wu --- drivers/power/supply/qcom/smb1398-charger.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/power/supply/qcom/smb1398-charger.c b/drivers/power/supply/qcom/smb1398-charger.c index 1305317bfb1e..2c1abcdc471c 100644 --- a/drivers/power/supply/qcom/smb1398-charger.c +++ b/drivers/power/supply/qcom/smb1398-charger.c @@ -115,6 +115,7 @@ #define MISC_CFG2_REG 0x2636 #define NOLOCK_SPARE_REG 0x2637 +#define EN_SLAVE_OWN_FREQ_BIT BIT(5) #define DIV2_WIN_UV_SEL_BIT BIT(4) #define DIV2_WIN_UV_25MV 0 #define COMBO_WIN_LO_EXIT_SEL_MASK GENMASK(3, 2) @@ -1258,16 +1259,6 @@ static int smb1398_div2_cp_slave_disable_vote_cb(struct votable *votable, if (!is_cps_available(chip)) return -ENODEV; - /* Enable/disable SYNC driver before enabling/disabling slave */ - reg = MISC_CFG0_REG; - val = !!disable ? DIS_SYNC_DRV_BIT : 0; - rc = smb1398_masked_write(chip, reg, DIS_SYNC_DRV_BIT, val); - if (rc < 0) { - dev_err(chip->dev, "%s slave SYNC_DRV failed, rc=%d\n", - !!disable ? "disable" : "enable", rc); - return rc; - } - reg = MISC_SL_SWITCH_EN_REG; val = !!disable ? 0 : EN_SLAVE; rc = smb1398_masked_write(chip, reg, EN_SLAVE, val); @@ -2279,6 +2270,15 @@ static int smb1398_div2_cp_slave_probe(struct smb1398_chip *chip) return rc; } + /* Enable slave clock on its own */ + rc = smb1398_masked_write(chip, NOLOCK_SPARE_REG, + EN_SLAVE_OWN_FREQ_BIT, EN_SLAVE_OWN_FREQ_BIT); + if (rc < 0) { + dev_err(chip->dev, "Couldn't enable slave clock, rc=%d\n", + rc); + return rc; + } + rc = smb1398_init_div2_cp_slave_psy(chip); if (rc < 0) { dev_err(chip->dev, "Initial div2_cp_slave_psy failed, rc=%d\n", From ac612524374f7e663e6b7a1115642df5ed832fb1 Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Tue, 30 Jun 2020 15:14:17 +0530 Subject: [PATCH 116/192] power: smb5-lib: Report the CURRENT_MAX as 1A in CC-mode Userspace uses the CURRENT_MAX power-supply property to determine the strength of the charger. In CC-mode of operation the main-charger's ICL is configured low and hence the CURRENT_MAX reported is lower attributing it as a weak-charger. Fix this by reporting a fixed value of 1A during CC-mode. Change-Id: Id8745b54c3909d01df69376a823396ea4c94eeb1 Signed-off-by: Anirudh Ghayal --- drivers/power/supply/qcom/qpnp-smb5.c | 2 +- drivers/power/supply/qcom/smb5-lib.c | 19 +++++++++++++++++++ drivers/power/supply/qcom/smb5-lib.h | 2 ++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 09d2995e5bbc..11b4878662e5 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -780,7 +780,7 @@ static int smb5_usb_get_prop(struct power_supply *psy, val->intval = get_client_vote(chg->usb_icl_votable, PD_VOTER); break; case POWER_SUPPLY_PROP_CURRENT_MAX: - rc = smblib_get_prop_input_current_settled(chg, val); + rc = smblib_get_prop_input_current_max(chg, val); break; case POWER_SUPPLY_PROP_TYPE: val->intval = POWER_SUPPLY_TYPE_USB_PD; diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 5b6c010a39ee..21bf5e9c383c 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -1337,6 +1337,7 @@ static int smblib_get_pulse_cnt(struct smb_charger *chg, int *count) #define USBIN_150MA 150000 #define USBIN_500MA 500000 #define USBIN_900MA 900000 +#define USBIN_1000MA 1000000 static int set_sdp_current(struct smb_charger *chg, int icl_ua) { int rc; @@ -3740,6 +3741,24 @@ int smblib_get_prop_input_current_settled(struct smb_charger *chg, return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval); } +int smblib_get_prop_input_current_max(struct smb_charger *chg, + union power_supply_propval *val) +{ + int icl_ua = 0, rc; + + rc = smblib_get_charge_param(chg, &chg->param.usb_icl, &icl_ua); + if (rc < 0) + return rc; + + if (is_override_vote_enabled_locked(chg->usb_icl_votable) && + icl_ua < USBIN_1000MA) { + val->intval = USBIN_1000MA; + return 0; + } + + return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval); +} + int smblib_get_prop_input_voltage_settled(struct smb_charger *chg, union power_supply_propval *val) { diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 8b5491214e97..8feca0df720c 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -751,6 +751,8 @@ int smblib_get_prop_charger_temp(struct smb_charger *chg, int smblib_get_prop_die_health(struct smb_charger *chg); int smblib_get_prop_smb_health(struct smb_charger *chg); int smblib_get_prop_connector_health(struct smb_charger *chg); +int smblib_get_prop_input_current_max(struct smb_charger *chg, + union power_supply_propval *val); int smblib_set_prop_thermal_overheat(struct smb_charger *chg, int therm_overheat); int smblib_get_skin_temp_status(struct smb_charger *chg); From 27b5d0e8294b769790ffd2c8dc03299fdf845334 Mon Sep 17 00:00:00 2001 From: "Jinesh K. Jayakumar" Date: Mon, 20 Jul 2020 23:41:21 -0400 Subject: [PATCH 117/192] msm: ipa: eth: Prevent suspend for 2 seconds after device resume Hold wake lock for 2 seconds after a device resume for allowing the device to settle and link interrupts to arrive after a resume. Change-Id: I91fd3d689895a9526d66d613a273cb7cc231fb2e Signed-off-by: Jinesh K. Jayakumar --- .../msm/ipa/ipa_v3/ethernet/ipa_eth.c | 7 +++-- .../msm/ipa/ipa_v3/ethernet/ipa_eth_i.h | 30 +++++++++++++++++-- .../msm/ipa/ipa_v3/ethernet/ipa_eth_pci.c | 6 ++-- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth.c b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth.c index 8a64c5a6e7b1..71c7c6ffbad7 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth.c +++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth.c @@ -571,9 +571,10 @@ static int ipa_eth_pm_notifier_event_suspend_prepare( * and reverts the device suspension by aborting the system suspend. */ if (ipa_eth_net_check_active(eth_dev)) { - pr_info("%s: %s is active, preventing suspend for some time", - IPA_ETH_SUBSYS, eth_dev->net_dev->name); - ipa_eth_dev_wakeup_event(eth_dev); + pr_info("%s: %s is active, preventing suspend for %u ms", + IPA_ETH_SUBSYS, eth_dev->net_dev->name, + IPA_ETH_WAKE_TIME_MS); + pm_wakeup_dev_event(eth_dev->dev, IPA_ETH_WAKE_TIME_MS, false); return NOTIFY_BAD; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_i.h b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_i.h index f92da41cd7aa..2ffc31c27da7 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_i.h @@ -35,8 +35,12 @@ #define IPA_ETH_IPC_LOGDBG_DEFAULT false #endif +/* Time to remain awake after a suspend abort due to NIC activity */ #define IPA_ETH_WAKE_TIME_MS 500 +/* Time for NIC HW to settle down (ex. receive link interrupt) after a resume */ +#define IPA_ETH_RESUME_SETTLE_MS 2000 + #define IPA_ETH_PFDEV (ipa3_ctx ? ipa3_ctx->pdev : NULL) #define IPA_ETH_SUBSYS "ipa_eth" @@ -161,9 +165,31 @@ extern bool ipa_eth_ipc_logdbg; bool ipa_eth_is_ready(void); bool ipa_eth_all_ready(void); -static inline void ipa_eth_dev_wakeup_event(struct ipa_eth_device *eth_dev) +static inline void ipa_eth_dev_assume_active_ms( + struct ipa_eth_device *eth_dev, + unsigned int msec) +{ + eth_dev_priv(eth_dev)->assume_active += + DIV_ROUND_UP(msec, IPA_ETH_WAKE_TIME_MS); + pm_system_wakeup(); +} + +static inline void ipa_eth_dev_assume_active_inc( + struct ipa_eth_device *eth_dev, + unsigned int count) +{ + eth_dev_priv(eth_dev)->assume_active += count; + pm_system_wakeup(); +} + +static inline void ipa_eth_dev_assume_active_dec( + struct ipa_eth_device *eth_dev, + unsigned int count) { - pm_wakeup_dev_event(eth_dev->dev, IPA_ETH_WAKE_TIME_MS, false); + if (eth_dev_priv(eth_dev)->assume_active > count) + eth_dev_priv(eth_dev)->assume_active -= count; + else + eth_dev_priv(eth_dev)->assume_active = 0; } struct ipa_eth_device *ipa_eth_alloc_device( diff --git a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_pci.c b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_pci.c index 1095306b009f..80f4a80b7181 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_pci.c +++ b/drivers/platform/msm/ipa/ipa_v3/ethernet/ipa_eth_pci.c @@ -374,7 +374,7 @@ static int ipa_eth_pci_suspend_late_handler(struct device *dev) IPA_ETH_SUBSYS, eth_dev->net_dev->name); /* Have PM_SUSPEND_PREPARE give us one wakeup time quanta */ - eth_dev_priv(eth_dev)->assume_active++; + ipa_eth_dev_assume_active_inc(eth_dev, 1); return -EAGAIN; } @@ -428,8 +428,8 @@ static int ipa_eth_pci_resume_handler(struct device *dev) "Device resume delegated to net driver"); rc = eth_dev_pm_ops(eth_dev)->resume(dev); - /* Give some time after a resume for the device to settle */ - eth_dev_priv(eth_dev)->assume_active++; + /* Give some time for device to settle after a resume */ + ipa_eth_dev_assume_active_ms(eth_dev, IPA_ETH_RESUME_SETTLE_MS); } if (rc) From e0d3f38ad1e4f78a51b706ac048694dff7db8b9e Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Tue, 24 Oct 2017 21:22:24 +0530 Subject: [PATCH 118/192] firmware: scm: Add new SCM call API for switching memory ownership Two different processors on a SOC need to switch memory ownership during load/unload. To enable this, second level memory map table need to be updated, which is done by secure layer. This patch adds the interface for making secure monitor call for memory ownership switching request. Acked-by: Andy Gross Signed-off-by: Avaneesh Kumar Dwivedi [bjorn: Minor style and kerneldoc updates] Signed-off-by: Bjorn Andersson Change-Id: I8e2e27ebd22a77c9130ca8bb570473dc8537b609 Git-commit: d82bd359972a7fe71a778396cf287bc9f9f3b981 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/ath.git Signed-off-by: Govind Singh --- drivers/firmware/qcom_scm-32.c | 9 +++- drivers/firmware/qcom_scm-64.c | 29 +++++++++- drivers/firmware/qcom_scm.c | 97 +++++++++++++++++++++++++++++++++- drivers/firmware/qcom_scm.h | 7 ++- include/linux/qcom_scm.h | 18 ++++++- 5 files changed, 155 insertions(+), 5 deletions(-) diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c index 93e3b96b6dfa..627bdd2b5c29 100644 --- a/drivers/firmware/qcom_scm-32.c +++ b/drivers/firmware/qcom_scm-32.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010,2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010,2015,2020 The Linux Foundation. All rights reserved. * Copyright (C) 2015 Linaro Ltd. * * This program is free software; you can redistribute it and/or modify @@ -579,6 +579,13 @@ int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id) return ret ? : le32_to_cpu(scm_ret); } +int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region, + size_t mem_sz, phys_addr_t src, size_t src_sz, + phys_addr_t dest, size_t dest_sz) +{ + return -ENODEV; +} + int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare) { diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c index 6e6d561708e2..d67cb15a9b95 100644 --- a/drivers/firmware/qcom_scm-64.c +++ b/drivers/firmware/qcom_scm-64.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015,2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -382,6 +382,33 @@ int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id) return ret ? : res.a1; } +int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region, + size_t mem_sz, phys_addr_t src, size_t src_sz, + phys_addr_t dest, size_t dest_sz) +{ + int ret; + struct qcom_scm_desc desc = {0}; + struct arm_smccc_res res; + + desc.args[0] = mem_region; + desc.args[1] = mem_sz; + desc.args[2] = src; + desc.args[3] = src_sz; + desc.args[4] = dest; + desc.args[5] = dest_sz; + desc.args[6] = 0; + + desc.arginfo = QCOM_SCM_ARGS(7, QCOM_SCM_RO, QCOM_SCM_VAL, + QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_RO, + QCOM_SCM_VAL, QCOM_SCM_VAL); + + ret = qcom_scm_call(dev, QCOM_SCM_SVC_MP, + QCOM_MEM_PROT_ASSIGN_ID, + &desc, &res); + + return ret ? : res.a1; +} + int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, u32 spare) { struct qcom_scm_desc desc = {0}; diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index bb16510d75ba..a0fb36aa6ad5 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -1,7 +1,7 @@ /* * Qualcomm SCM driver * - * Copyright (c) 2010,2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2010,2015,2020 The Linux Foundation. All rights reserved. * Copyright (C) 2015 Linaro Ltd. * * This program is free software; you can redistribute it and/or modify @@ -40,6 +40,19 @@ struct qcom_scm { struct reset_controller_dev reset; }; +struct qcom_scm_current_perm_info { + __le32 vmid; + __le32 perm; + __le64 ctx; + __le32 ctx_size; + __le32 unused; +}; + +struct qcom_scm_mem_map_info { + __le64 mem_addr; + __le64 mem_size; +}; + static struct qcom_scm *__scm; static int qcom_scm_clk_enable(void) @@ -348,6 +361,88 @@ int qcom_scm_set_remote_state(u32 state, u32 id) } EXPORT_SYMBOL(qcom_scm_set_remote_state); +/** + * qcom_scm_assign_mem() - Make a secure call to reassign memory ownership + * @mem_addr: mem region whose ownership need to be reassigned + * @mem_sz: size of the region. + * @srcvm: vmid for current set of owners, each set bit in + * flag indicate a unique owner + * @newvm: array having new owners and corrsponding permission + * flags + * @dest_cnt: number of owners in next set. + * + * Return negative errno on failure, 0 on success, with @srcvm updated. + */ +int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, + unsigned int *srcvm, + struct qcom_scm_vmperm *newvm, int dest_cnt) +{ + struct qcom_scm_current_perm_info *destvm; + struct qcom_scm_mem_map_info *mem_to_map; + phys_addr_t mem_to_map_phys; + phys_addr_t dest_phys; + phys_addr_t ptr_phys; + size_t mem_to_map_sz; + size_t dest_sz; + size_t src_sz; + size_t ptr_sz; + int next_vm; + __le32 *src; + void *ptr; + int ret; + int len; + int i; + + src_sz = hweight_long(*srcvm) * sizeof(*src); + mem_to_map_sz = sizeof(*mem_to_map); + dest_sz = dest_cnt * sizeof(*destvm); + ptr_sz = ALIGN(src_sz, SZ_64) + ALIGN(mem_to_map_sz, SZ_64) + + ALIGN(dest_sz, SZ_64); + + ptr = dma_alloc_coherent(__scm->dev, ptr_sz, &ptr_phys, GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + /* Fill source vmid detail */ + src = ptr; + len = hweight_long(*srcvm); + for (i = 0; i < len; i++) { + src[i] = cpu_to_le32(ffs(*srcvm) - 1); + *srcvm ^= 1 << (ffs(*srcvm) - 1); + } + + /* Fill details of mem buff to map */ + mem_to_map = ptr + ALIGN(src_sz, SZ_64); + mem_to_map_phys = ptr_phys + ALIGN(src_sz, SZ_64); + mem_to_map[0].mem_addr = cpu_to_le64(mem_addr); + mem_to_map[0].mem_size = cpu_to_le64(mem_sz); + + next_vm = 0; + /* Fill details of next vmid detail */ + destvm = ptr + ALIGN(mem_to_map_sz, SZ_64) + ALIGN(src_sz, SZ_64); + dest_phys = ptr_phys + ALIGN(mem_to_map_sz, SZ_64) + ALIGN(src_sz, SZ_64); + for (i = 0; i < dest_cnt; i++) { + destvm[i].vmid = cpu_to_le32(newvm[i].vmid); + destvm[i].perm = cpu_to_le32(newvm[i].perm); + destvm[i].ctx = 0; + destvm[i].ctx_size = 0; + next_vm |= BIT(newvm[i].vmid); + } + + ret = __qcom_scm_assign_mem(__scm->dev, mem_to_map_phys, mem_to_map_sz, + ptr_phys, src_sz, dest_phys, dest_sz); + dma_free_coherent(__scm->dev, ALIGN(ptr_sz, SZ_64), ptr, ptr_phys); + if (ret) { + dev_err(__scm->dev, + "Assign memory protection call failed %d.\n", ret); + return -EINVAL; + } + + *srcvm = next_vm; + return 0; +} +EXPORT_SYMBOL(qcom_scm_assign_mem); + static int qcom_scm_probe(struct platform_device *pdev) { struct qcom_scm *scm; diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index 9bea691f30fb..9b9fe30cada6 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2015,2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -95,5 +95,10 @@ extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare, size_t *size); extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, u32 size, u32 spare); +#define QCOM_MEM_PROT_ASSIGN_ID 0x16 +extern int __qcom_scm_assign_mem(struct device *dev, + phys_addr_t mem_region, size_t mem_sz, + phys_addr_t src, size_t src_sz, + phys_addr_t dest, size_t dest_sz); #endif diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index e5380471c2cd..0723b96beb0e 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2015,2020 The Linux Foundation. All rights reserved. * Copyright (C) 2015 Linaro Ltd. * * This program is free software; you can redistribute it and/or modify @@ -23,6 +23,19 @@ struct qcom_scm_hdcp_req { u32 val; }; +struct qcom_scm_vmperm { + int vmid; + int perm; +}; + +#define QCOM_SCM_VMID_HLOS 0x3 +#define QCOM_SCM_VMID_MSS_MSA 0xF +#define QCOM_SCM_PERM_READ 0x4 +#define QCOM_SCM_PERM_WRITE 0x2 +#define QCOM_SCM_PERM_EXEC 0x1 +#define QCOM_SCM_PERM_RW (QCOM_SCM_PERM_READ | QCOM_SCM_PERM_WRITE) +#define QCOM_SCM_PERM_RWX (QCOM_SCM_PERM_RW | QCOM_SCM_PERM_EXEC) + #if IS_ENABLED(CONFIG_QCOM_SCM) extern int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus); extern int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus); @@ -37,6 +50,9 @@ extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size); extern int qcom_scm_pas_auth_and_reset(u32 peripheral); extern int qcom_scm_pas_shutdown(u32 peripheral); +extern int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, + unsigned int *src, struct qcom_scm_vmperm *newvm, + int dest_cnt); extern void qcom_scm_cpu_power_down(u32 flags); extern u32 qcom_scm_get_version(void); extern int qcom_scm_set_remote_state(u32 state, u32 id); From 1f54b65b7c6602ce170aa566ea732c89e92fb77e Mon Sep 17 00:00:00 2001 From: Surabhi Vishnoi Date: Wed, 13 Jun 2018 10:33:35 +0530 Subject: [PATCH 119/192] ath10k: skip data calibration for non-bmi target In non-bmi target ex. WCN3990, data calibration is handled via QMI. Skip data calibration in debug routine to enable ath10k debugfs for non bmi targets. Signed-off-by: Surabhi Vishnoi Signed-off-by: Kalle Valo Change-Id: Ic2970c7954661a3e96ba15879768f195101cb456 Git-commit: 5db98aee93cd1ba5b94b1a9bc9057c98e2a36fd6 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/ath.git Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/debug.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 2ab3c751e6ba..a57f892830c0 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -1708,7 +1708,9 @@ int ath10k_debug_start(struct ath10k *ar) ath10k_warn(ar, "failed to disable pktlog: %d\n", ret); } - if (ar->debug.nf_cal_period) { + if (ar->debug.nf_cal_period && + !test_bit(ATH10K_FW_FEATURE_NON_BMI, + ar->normal_mode_fw.fw_file.fw_features)) { ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->cal_period, ar->debug.nf_cal_period); @@ -1725,7 +1727,9 @@ void ath10k_debug_stop(struct ath10k *ar) { lockdep_assert_held(&ar->conf_mutex); - ath10k_debug_cal_data_fetch(ar); + if (!test_bit(ATH10K_FW_FEATURE_NON_BMI, + ar->normal_mode_fw.fw_file.fw_features)) + ath10k_debug_cal_data_fetch(ar); /* Must not use _sync to avoid deadlock, we do that in * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid @@ -2217,15 +2221,18 @@ int ath10k_debug_register(struct ath10k *ar) debugfs_create_file("fw_dbglog", 0600, ar->debug.debugfs_phy, ar, &fops_fw_dbglog); - debugfs_create_file("cal_data", 0400, ar->debug.debugfs_phy, ar, - &fops_cal_data); + if (!test_bit(ATH10K_FW_FEATURE_NON_BMI, + ar->normal_mode_fw.fw_file.fw_features)) { + debugfs_create_file("cal_data", 0400, ar->debug.debugfs_phy, ar, + &fops_cal_data); + + debugfs_create_file("nf_cal_period", 0600, ar->debug.debugfs_phy, ar, + &fops_nf_cal_period); + } debugfs_create_file("ani_enable", 0600, ar->debug.debugfs_phy, ar, &fops_ani_enable); - debugfs_create_file("nf_cal_period", 0600, ar->debug.debugfs_phy, ar, - &fops_nf_cal_period); - if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED)) { debugfs_create_file("dfs_simulate_radar", 0200, ar->debug.debugfs_phy, ar, &fops_simulate_radar); From 463bb738da6697c6a0f60af5ee77057d05d3fbf1 Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Tue, 5 May 2020 14:15:15 +0530 Subject: [PATCH 120/192] msm: mhi_dev: Redesign UCI transfer request structure management Invalid memory access can happen if a client closes its channels with transfers pending because the mhi transfer request structure gets freed in UCI when channel is closed, but MHI driver accesses the request structure in the transfer completion callback. To avoid the invalid memory access, following changes are done: * Allocate mhi transfer request structures for a client in the first UCI client open call * Do not free mhi transfer request structs when client calls release, to allow for subsequent re-use * Maintain an in-use list to track active transfers * If a client exits with transfers pending, move the request structs corresponding to pending transfers to free list and mark them as stale. * Stale transfers, if completed later, are ignored. Change-Id: I170e06321de9c67b0a1d107b775d75b2ed97febb Signed-off-by: Siva Kumar Akkireddi --- drivers/platform/msm/mhi_dev/mhi.c | 26 ++- drivers/platform/msm/mhi_dev/mhi_uci.c | 286 +++++++++++++++++-------- include/linux/msm_mhi_dev.h | 1 + 3 files changed, 211 insertions(+), 102 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 53c3f3195ac5..612cc531c2a8 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -2154,25 +2154,34 @@ static void mhi_dev_transfer_completion_cb(void *mreq) { int rc = 0; struct mhi_req *req = mreq; - struct mhi_dev_channel *ch = req->client->channel; + struct mhi_dev_channel *ch; u32 snd_cmpl = req->snd_cmpl; + bool inbound = false; - if (mhi_ctx->ch_ctx_cache[ch->ch_id].ch_type == - MHI_DEV_CH_TYPE_INBOUND_CHANNEL) - ch->pend_wr_count--; + ch = &mhi_ctx->ch[req->chan]; dma_unmap_single(&mhi_ctx->pdev->dev, req->dma, - req->len, DMA_FROM_DEVICE); + req->len, DMA_FROM_DEVICE); + + if (mhi_ctx->ch_ctx_cache[ch->ch_id].ch_type == + MHI_DEV_CH_TYPE_INBOUND_CHANNEL) { + inbound = true; + ch->pend_wr_count--; + } /* - * Channel got stopped or closed with transfers pending + * Channel got closed with transfers pending * Do not trigger callback or send cmpl to host */ if (ch->state == MHI_DEV_CH_CLOSED || ch->state == MHI_DEV_CH_STOPPED) { - mhi_log(MHI_MSG_DBG, - "Ch %d not in started state, %d writes pending\n", + if (inbound) + mhi_log(MHI_MSG_DBG, + "Ch %d closed with %d writes pending\n", ch->ch_id, ch->pend_wr_count + 1); + else + mhi_log(MHI_MSG_DBG, + "Ch %d closed with read pending\n", ch->ch_id); return; } @@ -2729,6 +2738,7 @@ int mhi_dev_open_channel(uint32_t chan_id, ch->active_client = (*handle_client); (*handle_client)->channel = ch; (*handle_client)->event_trigger = mhi_dev_client_cb_reason; + ch->pend_wr_count = 0; if (ch->state == MHI_DEV_CH_UNINT) { ch->ring = &mhi_ctx->ring[chan_id + mhi_ctx->ch_ring_start]; diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c index ac8901689fa9..5fd129d96255 100644 --- a/drivers/platform/msm/mhi_dev/mhi_uci.c +++ b/drivers/platform/msm/mhi_dev/mhi_uci.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015,2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015,2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -33,8 +33,8 @@ #define MHI_SOFTWARE_CLIENT_LIMIT (MHI_MAX_SOFTWARE_CHANNELS/2) #define MHI_UCI_IPC_LOG_PAGES (100) -/* Max number of MHI write request structures (used in async writes) */ -#define MHI_UCI_NUM_WR_REQ_DEFAULT 10 +/* Max number of MHI read/write request structs (used in async transfers) */ +#define MHI_UCI_NUM_REQ_DEFAULT 10 #define MAX_NR_TRBS_PER_CHAN 9 #define MHI_QTI_IFACE_ID 4 #define MHI_ADPL_IFACE_ID 5 @@ -50,6 +50,8 @@ #define MHI_UCI_RELEASE_TIMEOUT_MAX 5100 #define MHI_UCI_RELEASE_TIMEOUT_COUNT 30 +#define MHI_UCI_IS_CHAN_DIR_IN(n) ((n % 2) ? true : false) + enum uci_dbg_level { UCI_DBG_VERBOSE = 0x0, UCI_DBG_INFO = 0x1, @@ -92,8 +94,7 @@ struct chan_attr { /* Uevent broadcast of channel state */ bool state_bcast; /* Number of write request structs to allocate */ - u32 num_wr_reqs; - + u32 num_reqs; }; static void mhi_uci_generic_client_cb(struct mhi_dev_client_cb_data *cb_data); @@ -330,15 +331,19 @@ struct uci_client { struct mhi_uci_ctxt_t *uci_ctxt; struct mutex in_chan_lock; struct mutex out_chan_lock; - spinlock_t wr_req_lock; + spinlock_t req_lock; unsigned int f_flags; - struct mhi_req *wreqs; - struct list_head wr_req_list; + /* Pointer to dynamically allocated mhi_req structs */ + struct mhi_req *reqs; + /* Pointer to available (free) reqs */ + struct list_head req_list; + /* Pointer to in-use reqs */ + struct list_head in_use_list; struct completion read_done; struct completion at_ctrl_read_done; struct completion *write_done; int (*send)(struct uci_client*, void*, u32); - int (*read)(struct uci_client*, struct mhi_req*, int*); + int (*read)(struct uci_client*, int*); unsigned int tiocm; unsigned int at_ctrl_mask; }; @@ -478,23 +483,75 @@ static int mhi_init_read_chan(struct uci_client *client_handle, return rc; } +static struct mhi_req *mhi_uci_get_req(struct uci_client *uci_handle) +{ + struct mhi_req *req; + unsigned long flags; + + spin_lock_irqsave(&uci_handle->req_lock, flags); + if (list_empty(&uci_handle->req_list)) { + uci_log(UCI_DBG_ERROR, "Request pool empty for chans %d, %d\n", + uci_handle->in_chan, uci_handle->out_chan); + spin_unlock_irqrestore(&uci_handle->req_lock, flags); + return NULL; + } + /* Remove from free list and add to in-use list */ + req = container_of(uci_handle->req_list.next, + struct mhi_req, list); + list_del_init(&req->list); + /* + * If req is marked stale and if it was used for the write channel + * to host, free the previously allocated input buffer before the + * req is re-used + */ + if (req->is_stale && req->buf && MHI_UCI_IS_CHAN_DIR_IN(req->chan)) { + uci_log(UCI_DBG_VERBOSE, "Freeing write buf for chan %d\n", + req->chan); + kfree(req->buf); + } + req->is_stale = false; + uci_log(UCI_DBG_VERBOSE, "Adding req to in-use list\n"); + list_add_tail(&req->list, &uci_handle->in_use_list); + spin_unlock_irqrestore(&uci_handle->req_lock, flags); + + return req; +} + +static void mhi_uci_put_req(struct uci_client *uci_handle, struct mhi_req *req) +{ + unsigned long flags; + + spin_lock_irqsave(&uci_handle->req_lock, flags); + /* Remove from in-use list and add back to free list */ + list_del_init(&req->list); + list_add_tail(&req->list, &uci_handle->req_list); + spin_unlock_irqrestore(&uci_handle->req_lock, flags); +} + static void mhi_uci_write_completion_cb(void *req) { struct mhi_req *ureq = req; - struct uci_client *uci_handle; - unsigned long flags; + struct uci_client *uci_handle = (struct uci_client *)ureq->context; - uci_handle = (struct uci_client *)ureq->context; kfree(ureq->buf); ureq->buf = NULL; - spin_lock_irqsave(&uci_handle->wr_req_lock, flags); - list_add_tail(&ureq->list, &uci_handle->wr_req_list); - spin_unlock_irqrestore(&uci_handle->wr_req_lock, flags); + /* + * If this is a delayed write completion, just clear + * the stale flag and return. The ureq was added to + * the free list when client called release function. + */ + if (ureq->is_stale) { + uci_log(UCI_DBG_VERBOSE, + "Got stale completion for ch %d\n", ureq->chan); + ureq->is_stale = false; + return; + } if (uci_handle->write_done) complete(uci_handle->write_done); + mhi_uci_put_req(uci_handle, ureq); /* Write queue may be waiting for write request structs */ wake_up(&uci_handle->write_wq); } @@ -504,7 +561,19 @@ static void mhi_uci_read_completion_cb(void *req) struct mhi_req *ureq = req; struct uci_client *uci_handle; + if (ureq->is_stale) { + uci_log(UCI_DBG_VERBOSE, + "Got stale completion for ch %d, ignoring\n", + ureq->chan); + return; + } + uci_handle = (struct uci_client *)ureq->context; + + uci_handle->pkt_loc = (void *)ureq->buf; + uci_handle->pkt_size = ureq->transfer_len; + + mhi_uci_put_req(uci_handle, ureq); complete(&uci_handle->read_done); } @@ -514,6 +583,9 @@ static int mhi_uci_send_sync(struct uci_client *uci_handle, struct mhi_req ureq; int ret_val; + uci_log(UCI_DBG_VERBOSE, + "Sync write for ch %d size %d\n", uci_handle->out_chan, size); + ureq.client = uci_handle->out_handle; ureq.buf = data_loc; ureq.len = size; @@ -534,19 +606,12 @@ static int mhi_uci_send_async(struct uci_client *uci_handle, struct mhi_req *ureq; uci_log(UCI_DBG_VERBOSE, - "Got async write for ch %d of size %d\n", + "Async write for ch %d size %d\n", uci_handle->out_chan, size); - spin_lock_irq(&uci_handle->wr_req_lock); - if (list_empty(&uci_handle->wr_req_list)) { - uci_log(UCI_DBG_ERROR, "Write request pool empty\n"); - spin_unlock_irq(&uci_handle->wr_req_lock); + ureq = mhi_uci_get_req(uci_handle); + if (!ureq) return -EBUSY; - } - ureq = container_of(uci_handle->wr_req_list.next, - struct mhi_req, list); - list_del_init(&ureq->list); - spin_unlock_irq(&uci_handle->wr_req_lock); ureq->client = uci_handle->out_handle; ureq->context = uci_handle; @@ -565,9 +630,7 @@ static int mhi_uci_send_async(struct uci_client *uci_handle, error_async_transfer: ureq->buf = NULL; - spin_lock_irq(&uci_handle->wr_req_lock); - list_add_tail(&ureq->list, &uci_handle->wr_req_list); - spin_unlock_irq(&uci_handle->wr_req_lock); + mhi_uci_put_req(uci_handle, ureq); return bytes_to_write; } @@ -609,7 +672,7 @@ static int mhi_uci_send_packet(struct uci_client *uci_handle, void *data_loc, return -EAGAIN; ret_val = wait_event_interruptible_timeout( uci_handle->write_wq, - !list_empty(&uci_handle->wr_req_list), + !list_empty(&uci_handle->req_list), MHI_UCI_WRITE_REQ_AVAIL_TIMEOUT); if (ret_val > 0) { /* @@ -710,42 +773,62 @@ static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait) return mask; } -static int mhi_uci_alloc_write_reqs(struct uci_client *client) +static int mhi_uci_alloc_reqs(struct uci_client *client) { int i; - u32 num_wr_reqs; + u32 num_reqs; - num_wr_reqs = client->in_chan_attr->num_wr_reqs; - if (!num_wr_reqs) - num_wr_reqs = MHI_UCI_NUM_WR_REQ_DEFAULT; + if (client->reqs) { + uci_log(UCI_DBG_VERBOSE, "Reqs already allocated\n"); + return 0; + } - client->wreqs = kcalloc(num_wr_reqs, + num_reqs = client->in_chan_attr->num_reqs; + if (!num_reqs) + num_reqs = MHI_UCI_NUM_REQ_DEFAULT; + + client->reqs = kcalloc(num_reqs, sizeof(struct mhi_req), GFP_KERNEL); - if (!client->wreqs) { - uci_log(UCI_DBG_ERROR, "Write reqs alloc failed\n"); + if (!client->reqs) { + uci_log(UCI_DBG_ERROR, "Reqs alloc failed\n"); return -ENOMEM; } - INIT_LIST_HEAD(&client->wr_req_list); - for (i = 0; i < num_wr_reqs; ++i) - list_add_tail(&client->wreqs[i].list, &client->wr_req_list); + INIT_LIST_HEAD(&client->req_list); + INIT_LIST_HEAD(&client->in_use_list); + for (i = 0; i < num_reqs; ++i) + list_add_tail(&client->reqs[i].list, &client->req_list); uci_log(UCI_DBG_INFO, "Allocated %d write reqs for chan %d\n", - num_wr_reqs, client->out_chan); + num_reqs, client->out_chan); return 0; } -static int mhi_uci_read_async(struct uci_client *uci_handle, - struct mhi_req *ureq, int *bytes_avail) +static int mhi_uci_read_async(struct uci_client *uci_handle, int *bytes_avail) { int ret_val = 0; unsigned long compl_ret; + struct mhi_req *ureq; + struct mhi_dev_client *client_handle; uci_log(UCI_DBG_ERROR, "Async read for ch %d\n", uci_handle->in_chan); + ureq = mhi_uci_get_req(uci_handle); + if (!ureq) { + uci_log(UCI_DBG_ERROR, + "Out of reqs for chan %d\n", uci_handle->in_chan); + return -EBUSY; + } + + client_handle = uci_handle->in_handle; + ureq->chan = uci_handle->in_chan; + ureq->client = client_handle; + ureq->buf = uci_handle->in_buf_list[0].addr; + ureq->len = uci_handle->in_buf_list[0].buf_size; + ureq->mode = DMA_ASYNC; ureq->client_cb = mhi_uci_read_completion_cb; ureq->snd_cmpl = 1; @@ -754,14 +837,14 @@ static int mhi_uci_read_async(struct uci_client *uci_handle, reinit_completion(&uci_handle->read_done); *bytes_avail = mhi_dev_read_channel(ureq); - uci_log(UCI_DBG_VERBOSE, "buf_size = 0x%lx bytes_read = 0x%x\n", - ureq->len, *bytes_avail); if (*bytes_avail < 0) { uci_log(UCI_DBG_ERROR, "Failed to read channel ret %dlu\n", *bytes_avail); + mhi_uci_put_req(uci_handle, ureq); return -EIO; } - + uci_log(UCI_DBG_VERBOSE, "buf_size = 0x%lx bytes_read = 0x%x\n", + ureq->len, *bytes_avail); if (*bytes_avail > 0) { uci_log(UCI_DBG_VERBOSE, "Waiting for async read completion!\n"); @@ -769,7 +852,6 @@ static int mhi_uci_read_async(struct uci_client *uci_handle, wait_for_completion_interruptible_timeout( &uci_handle->read_done, MHI_UCI_ASYNC_READ_TIMEOUT); - if (compl_ret == -ERESTARTSYS) { uci_log(UCI_DBG_ERROR, "Exit signal caught\n"); return compl_ret; @@ -779,33 +861,41 @@ static int mhi_uci_read_async(struct uci_client *uci_handle, return -EIO; } uci_log(UCI_DBG_VERBOSE, - "wk up Read completed on ch %d\n", ureq->chan); - - uci_handle->pkt_loc = (void *)ureq->buf; - uci_handle->pkt_size = ureq->transfer_len; - + "wk up Read completed on ch %d\n", uci_handle->in_chan); uci_log(UCI_DBG_VERBOSE, "Got pkt of sz 0x%lx at adr %pK, ch %d\n", uci_handle->pkt_size, - ureq->buf, ureq->chan); + uci_handle->pkt_loc, uci_handle->in_chan); } else { uci_handle->pkt_loc = NULL; uci_handle->pkt_size = 0; + uci_log(UCI_DBG_VERBOSE, + "No read data available, return req to free liat\n"); + mhi_uci_put_req(uci_handle, ureq); } return ret_val; } -static int mhi_uci_read_sync(struct uci_client *uci_handle, - struct mhi_req *ureq, int *bytes_avail) +static int mhi_uci_read_sync(struct uci_client *uci_handle, int *bytes_avail) { int ret_val = 0; + struct mhi_req ureq; + struct mhi_dev_client *client_handle; - ureq->mode = DMA_SYNC; - *bytes_avail = mhi_dev_read_channel(ureq); + uci_log(UCI_DBG_ERROR, + "Sync read for ch %d\n", uci_handle->in_chan); + client_handle = uci_handle->in_handle; + ureq.chan = uci_handle->in_chan; + ureq.client = client_handle; + ureq.buf = uci_handle->in_buf_list[0].addr; + ureq.len = uci_handle->in_buf_list[0].buf_size; + ureq.mode = DMA_SYNC; + + *bytes_avail = mhi_dev_read_channel(&ureq); uci_log(UCI_DBG_VERBOSE, "buf_size = 0x%lx bytes_read = 0x%x\n", - ureq->len, *bytes_avail); + ureq.len, *bytes_avail); if (*bytes_avail < 0) { uci_log(UCI_DBG_ERROR, "Failed to read channel ret %d\n", @@ -814,13 +904,13 @@ static int mhi_uci_read_sync(struct uci_client *uci_handle, } if (*bytes_avail > 0) { - uci_handle->pkt_loc = (void *)ureq->buf; - uci_handle->pkt_size = ureq->transfer_len; + uci_handle->pkt_loc = (void *)ureq.buf; + uci_handle->pkt_size = ureq.transfer_len; uci_log(UCI_DBG_VERBOSE, "Got pkt of sz 0x%lx at adr %pK, ch %d\n", uci_handle->pkt_size, - ureq->buf, ureq->chan); + ureq.buf, ureq.chan); } else { uci_handle->pkt_loc = NULL; uci_handle->pkt_size = 0; @@ -845,7 +935,7 @@ static int open_client_mhi_channels(struct uci_client *uci_client) /* Allocate write requests for async operations */ if (!(uci_client->f_flags & O_SYNC)) { - rc = mhi_uci_alloc_write_reqs(uci_client); + rc = mhi_uci_alloc_reqs(uci_client); if (rc) goto handle_not_rdy_err; uci_client->send = mhi_uci_send_async; @@ -965,6 +1055,7 @@ static int mhi_uci_client_release(struct inode *mhi_inode, { struct uci_client *uci_handle = file_handle->private_data; int count = 0; + struct mhi_req *ureq; if (!uci_handle) return -EINVAL; @@ -995,9 +1086,6 @@ static int mhi_uci_client_release(struct inode *mhi_inode, if (atomic_read(&uci_handle->mhi_chans_open)) { atomic_set(&uci_handle->mhi_chans_open, 0); - - if (!(uci_handle->f_flags & O_SYNC)) - kfree(uci_handle->wreqs); mutex_lock(&uci_handle->out_chan_lock); mhi_dev_close_channel(uci_handle->out_handle); wake_up(&uci_handle->write_wq); @@ -1007,6 +1095,27 @@ static int mhi_uci_client_release(struct inode *mhi_inode, mhi_dev_close_channel(uci_handle->in_handle); wake_up(&uci_handle->read_wq); mutex_unlock(&uci_handle->in_chan_lock); + /* + * Add back reqs in in-use list, if any, to free list. + * Mark the ureq stale to avoid returning stale data + * to client if the transfer completes later. + */ + count = 0; + while (!(list_empty(&uci_handle->in_use_list))) { + ureq = container_of(uci_handle->in_use_list.next, + struct mhi_req, list); + list_del_init(&ureq->list); + ureq->is_stale = true; + uci_log(UCI_DBG_VERBOSE, + "Adding back req for chan %d to free list\n", + ureq->chan); + list_add_tail(&ureq->list, &uci_handle->req_list); + count++; + } + if (count) + uci_log(UCI_DBG_DBG, + "Client %d closed with %d transfers pending\n", + iminor(mhi_inode), count); } atomic_set(&uci_handle->read_data_ready, 0); @@ -1123,20 +1232,11 @@ static int __mhi_uci_client_read(struct uci_client *uci_handle, int *bytes_avail) { int ret_val = 0; - struct mhi_dev_client *client_handle; - struct mhi_req ureq; - - client_handle = uci_handle->in_handle; - ureq.chan = uci_handle->in_chan; - ureq.client = client_handle; - ureq.buf = uci_handle->in_buf_list[0].addr; - ureq.len = uci_handle->in_buf_list[0].buf_size; do { if (!uci_handle->pkt_loc && !atomic_read(&uci_ctxt.mhi_disabled)) { - ret_val = uci_handle->read(uci_handle, &ureq, - bytes_avail); + ret_val = uci_handle->read(uci_handle, bytes_avail); if (ret_val) return ret_val; } @@ -1146,12 +1246,13 @@ static int __mhi_uci_client_read(struct uci_client *uci_handle, uci_log(UCI_DBG_VERBOSE, "No data read_data_ready %d, chan %d\n", atomic_read(&uci_handle->read_data_ready), - ureq.chan); + uci_handle->in_chan); if (uci_handle->f_flags & (O_NONBLOCK | O_NDELAY)) return -EAGAIN; ret_val = wait_event_interruptible(uci_handle->read_wq, - (!mhi_dev_channel_isempty(client_handle))); + (!mhi_dev_channel_isempty( + uci_handle->in_handle))); if (ret_val == -ERESTARTSYS) { uci_log(UCI_DBG_ERROR, "Exit signal caught\n"); @@ -1160,27 +1261,16 @@ static int __mhi_uci_client_read(struct uci_client *uci_handle, uci_log(UCI_DBG_VERBOSE, "wk up Got data on ch %d read_data_ready %d\n", - ureq.chan, + uci_handle->in_chan, atomic_read(&uci_handle->read_data_ready)); } else if (*bytes_avail > 0) { /* A valid packet was returned from MHI */ uci_log(UCI_DBG_VERBOSE, "Got packet: avail pkts %d phy_adr %pK, ch %d\n", atomic_read(&uci_handle->read_data_ready), - ureq.buf, - ureq.chan); + uci_handle->pkt_loc, + uci_handle->in_chan); break; - } else { - /* - * MHI did not return a valid packet, but we have one - * which we did not finish returning to user - */ - uci_log(UCI_DBG_CRITICAL, - "chan %d err: avail pkts %d phy_adr %pK", - ureq.chan, - atomic_read(&uci_handle->read_data_ready), - ureq.buf); - return -EIO; } } while (!uci_handle->pkt_loc); @@ -1442,7 +1532,7 @@ static int mhi_register_client(struct uci_client *mhi_client, int index) mutex_init(&mhi_client->in_chan_lock); mutex_init(&mhi_client->out_chan_lock); - spin_lock_init(&mhi_client->wr_req_lock); + spin_lock_init(&mhi_client->req_lock); /* Init the completion event for AT ctrl read */ init_completion(&mhi_client->at_ctrl_read_done); @@ -1787,6 +1877,7 @@ static void mhi_uci_at_ctrl_client_cb(struct mhi_dev_client_cb_data *cb_data) { struct uci_client *client = cb_data->user_data; int rc; + struct mhi_req *ureq; uci_log(UCI_DBG_VERBOSE, " Rcvd MHI cb for channel %d, state %d\n", cb_data->channel, cb_data->ctrl_info); @@ -1813,10 +1904,17 @@ static void mhi_uci_at_ctrl_client_cb(struct mhi_dev_client_cb_data *cb_data) } destroy_workqueue(uci_ctxt.at_ctrl_wq); uci_ctxt.at_ctrl_wq = NULL; - if (!(client->f_flags & O_SYNC)) - kfree(client->wreqs); mhi_dev_close_channel(client->out_handle); mhi_dev_close_channel(client->in_handle); + + /* Add back reqs in in-use list, if any, to free list */ + while (!(list_empty(&client->in_use_list))) { + ureq = container_of(client->in_use_list.next, + struct mhi_req, list); + list_del_init(&ureq->list); + /* Add to in-use list */ + list_add_tail(&ureq->list, &client->req_list); + } } } diff --git a/include/linux/msm_mhi_dev.h b/include/linux/msm_mhi_dev.h index f086e848327f..42eb9fa05405 100644 --- a/include/linux/msm_mhi_dev.h +++ b/include/linux/msm_mhi_dev.h @@ -73,6 +73,7 @@ struct mhi_req { struct list_head list; union mhi_dev_ring_element_type *el; void (*client_cb)(void *req); + bool is_stale; }; /* SW channel client list */ From 2a0a9945d87f22aec55c1468181aa261587631ae Mon Sep 17 00:00:00 2001 From: Naveen Yadav Date: Wed, 29 Apr 2020 22:26:26 +0530 Subject: [PATCH 121/192] clk: qcom: gdsc-regulator: Add support to skip GDSC disable Add check to skip gdsc disable when disable call comes before the gdsc enable. In case if the gdsc is enabled by entity external to HLOS then skip disable call. Change-Id: I14ba8a24fb4403a1805cba23967bb22a82ac6e7f Signed-off-by: Naveen Yadav Signed-off-by: Taniya Das --- .../bindings/regulator/gdsc-regulator.txt | 3 +++ drivers/clk/qcom/gdsc-regulator.c | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt index 9c12fb871cfe..f4f462f6ab7f 100644 --- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt @@ -80,6 +80,9 @@ Optional properties: identifier. If this is specified, then a QMP message should be sent to enable the GDSC instead of setting SW_COLLAPSE=0. + - qcom,skip-disable-before-sw-enable: Presence denotes a hardware requirement + to leave the GDSC on that has been + enabled by an entity external to HLOS. [1]: Documentation/devicetree/bindings/arm/msm/msm_bus.txt diff --git a/drivers/clk/qcom/gdsc-regulator.c b/drivers/clk/qcom/gdsc-regulator.c index 89fc5824c85d..b259859a3e79 100644 --- a/drivers/clk/qcom/gdsc-regulator.c +++ b/drivers/clk/qcom/gdsc-regulator.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -88,6 +88,7 @@ struct gdsc { int reset_count; int root_clk_idx; u32 gds_timeout; + bool skip_disable_before_enable; }; enum gdscr_status { @@ -423,6 +424,8 @@ static int gdsc_enable(struct regulator_dev *rdev) sc->is_bus_enabled = false; } + sc->skip_disable_before_enable = false; + if (ret && sc->parent_regulator) regulator_set_voltage(sc->parent_regulator, 0, INT_MAX); @@ -435,6 +438,16 @@ static int gdsc_disable(struct regulator_dev *rdev) uint32_t regval; int i, ret = 0; + /* + * Protect GDSC against late_init disabling when the GDSC is enabled + * by an entity outside external to HLOS. + */ + if (sc->skip_disable_before_enable) { + dev_dbg(&rdev->dev, "Skip Disabling: %s\n", sc->rdesc.name); + sc->skip_disable_before_enable = false; + return 0; + } + if (sc->force_root_en) clk_prepare_enable(sc->clocks[sc->root_clk_idx]); @@ -994,6 +1007,9 @@ static int gdsc_probe(struct platform_device *pdev) clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH); } + sc->skip_disable_before_enable = of_property_read_bool( + pdev->dev.of_node, "qcom,skip-disable-before-sw-enable"); + reg_config.dev = &pdev->dev; reg_config.init_data = init_data; reg_config.driver_data = sc; From 435684a538426c6807447512a5158043978ad549 Mon Sep 17 00:00:00 2001 From: Naveen Yadav Date: Tue, 12 May 2020 19:32:02 +0530 Subject: [PATCH 122/192] clk: qcom: gdsc-regulator: Update support to skip GDSC disable Update gdsc_is_enable and gdsc_enable to return 0 for the GDSC which needs only GDSC disable support from HLOS. Change-Id: Ie1e9faf806f504fc56419c5c557d3063d031d804 Signed-off-by: Naveen Yadav --- drivers/clk/qcom/gdsc-regulator.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/clk/qcom/gdsc-regulator.c b/drivers/clk/qcom/gdsc-regulator.c index b259859a3e79..f689661cfc3d 100644 --- a/drivers/clk/qcom/gdsc-regulator.c +++ b/drivers/clk/qcom/gdsc-regulator.c @@ -167,6 +167,9 @@ static int gdsc_is_enabled(struct regulator_dev *rdev) if (!sc->toggle_logic) return !sc->resets_asserted; + if (sc->skip_disable_before_enable) + return false; + if (sc->parent_regulator) { /* * The parent regulator for the GDSC is required to be on to @@ -259,6 +262,9 @@ static int gdsc_enable(struct regulator_dev *rdev) uint32_t regval, hw_ctrl_regval = 0x0; int i, ret = 0; + if (sc->skip_disable_before_enable) + return 0; + if (sc->parent_regulator) { ret = regulator_set_voltage(sc->parent_regulator, RPMH_REGULATOR_LEVEL_LOW_SVS, INT_MAX); @@ -438,16 +444,6 @@ static int gdsc_disable(struct regulator_dev *rdev) uint32_t regval; int i, ret = 0; - /* - * Protect GDSC against late_init disabling when the GDSC is enabled - * by an entity outside external to HLOS. - */ - if (sc->skip_disable_before_enable) { - dev_dbg(&rdev->dev, "Skip Disabling: %s\n", sc->rdesc.name); - sc->skip_disable_before_enable = false; - return 0; - } - if (sc->force_root_en) clk_prepare_enable(sc->clocks[sc->root_clk_idx]); From a6e500711a8f71573373950f53a9c194a4b95f70 Mon Sep 17 00:00:00 2001 From: Naveen Yadav Date: Thu, 2 Jul 2020 14:56:44 +0530 Subject: [PATCH 123/192] ARM: dts: msm: Add skip-disable-before-sw-enable flag to gx_gdsc Add flag to avoid GDSC disable when the gdsc is enabled by entity external to HLOS and there is no enable call on the GDSC. Change-Id: I87e4d28369eba7b2ddb8721f6705c30d7dd28b88 Signed-off-by: Naveen Yadav --- arch/arm64/boot/dts/qcom/atoll-gdsc.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/atoll-gdsc.dtsi b/arch/arm64/boot/dts/qcom/atoll-gdsc.dtsi index 0eba4a21ff28..776b1b552f0c 100644 --- a/arch/arm64/boot/dts/qcom/atoll-gdsc.dtsi +++ b/arch/arm64/boot/dts/qcom/atoll-gdsc.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -134,6 +134,7 @@ qcom,poll-cfg-gdscr; domain-addr = <&gpu_gx_domain_addr>; sw-reset = <&gpu_gx_sw_reset>; + qcom,skip-disable-before-sw-enable; status = "disabled"; }; From 1c655b03854cf55b238c58a85962bda7a57a3b7f Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Fri, 20 Sep 2019 17:29:41 +0530 Subject: [PATCH 124/192] BACKPORT: UPSTREAM: ath10k: Add WMI diag fw logging support for WCN3990 Integrated WiFi chipset ex:WCN399x supports fw logging using WMI copy engine and shared mem DIAG based fw logging. By default shared mem DIAG based fw logging is enabled. To support WMI copy engine based fw logging add QMI control message to enable WMI copy engine based fw logging. Enable WMI based fw logging using fw_diag_log module parameter. insmod ath10k_core.ko fw_diag_log=1 DIAG utility(https://github.com/andersson/diag) implements extraction of diagnostics related messages between application processor and various subsystems while shared mem DIAG based fw logging is enabled. Testing: Tested on WCN3990/QCA6174 HW. Tested FW: WLAN.HL.3.1-00959-QCAHLSWMTPLZ-1. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo [govinds@codeaurora.org: fix trivial merge conflicts] Change-Id: I975844da5efc8aad78684298f6a6188934547758 Git-commit: d9e47698965d782dba1d9d9bc04441e668d71008 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/core.c | 9 ++++++ drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/hif.h | 15 +++++++++ drivers/net/wireless/ath/ath10k/qmi.c | 45 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/qmi.h | 1 + drivers/net/wireless/ath/ath10k/snoc.c | 14 ++++++++ 6 files changed, 85 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 21df3e6b0d58..81e9b36c056a 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -39,6 +39,7 @@ static unsigned int ath10k_cryptmode_param; static bool uart_print; static bool skip_otp; static bool rawmode; +static bool fw_diag_log; /* Enable ATH10K_FW_CRASH_DUMP_REGISTERS and ATH10K_FW_CRASH_DUMP_CE_DATA * by default. @@ -51,6 +52,7 @@ module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644); module_param(uart_print, bool, 0644); module_param(skip_otp, bool, 0644); module_param(rawmode, bool, 0644); +module_param(fw_diag_log, bool, 0644); module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); MODULE_PARM_DESC(debug_mask, "Debugging mask"); @@ -59,6 +61,7 @@ MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software"); MODULE_PARM_DESC(rawmode, "Use raw 802.11 frame datapath"); MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); +MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); static const struct ath10k_hw_params ath10k_hw_params_list[] = { { @@ -2612,6 +2615,12 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, if (status) goto err_hif_stop; + status = ath10k_hif_set_target_log_mode(ar, fw_diag_log); + if (status && status != -EOPNOTSUPP) { + ath10k_warn(ar, "set traget log mode faileds: %d\n", status); + goto err_hif_stop; + } + return 0; err_hif_stop: diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index e85ce758f612..35fc24f5d8d4 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -496,6 +496,7 @@ struct ath10k_debug { u32 reg_addr; u32 nf_cal_period; void *cal_data; + u8 fw_dbglog_mode; }; enum ath10k_state { diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index 1a59ea0068c2..ee825a78480d 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -23,6 +23,12 @@ #include "bmi.h" #include "debug.h" +/* Types of fw logging mode */ +enum ath_dbg_mode { + ATH10K_ENABLE_FW_LOG_DIAG, + ATH10K_ENABLE_FW_LOG_CE, +}; + struct ath10k_hif_sg_item { u16 transfer_id; void *transfer_context; /* NULL = tx completion callback not called */ @@ -97,6 +103,7 @@ struct ath10k_hif_ops { int (*get_target_info)(struct ath10k *ar, struct bmi_target_info *target_info); + int (*set_target_log_mode)(struct ath10k *ar, u8 fw_log_mode); }; static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id, @@ -231,4 +238,12 @@ static inline int ath10k_hif_get_target_info(struct ath10k *ar, return ar->hif.ops->get_target_info(ar, tgt_info); } +static inline int ath10k_hif_set_target_log_mode(struct ath10k *ar, + u8 fw_log_mode) +{ + if (!ar->hif.ops->set_target_log_mode) + return -EOPNOTSUPP; + + return ar->hif.ops->set_target_log_mode(ar, fw_log_mode); +} #endif /* _HIF_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index 56cb1831dcdf..73defa565523 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -630,6 +630,51 @@ static int ath10k_qmi_host_cap_send_sync(struct ath10k_qmi *qmi) return ret; } +int ath10k_qmi_set_fw_log_mode(struct ath10k *ar, u8 fw_log_mode) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct wlfw_ini_resp_msg_v01 resp = {}; + struct ath10k_qmi *qmi = ar_snoc->qmi; + struct wlfw_ini_req_msg_v01 req = {}; + struct qmi_txn txn; + int ret; + + req.enablefwlog_valid = 1; + req.enablefwlog = fw_log_mode; + + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_ini_resp_msg_v01_ei, + &resp); + if (ret < 0) + goto out; + + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, + QMI_WLFW_INI_REQ_V01, + WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_ini_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath10k_err(ar, "fail to send fw log reqest: %d\n", ret); + goto out; + } + + ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ); + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath10k_err(ar, "fw log request rejectedr: %d\n", + resp.resp.error); + ret = -EINVAL; + goto out; + } + ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi fw log request completed, mode: %d\n", + fw_log_mode); + return 0; + +out: + return ret; +} + static int ath10k_qmi_ind_register_send_sync_msg(struct ath10k_qmi *qmi) { diff --git a/drivers/net/wireless/ath/ath10k/qmi.h b/drivers/net/wireless/ath/ath10k/qmi.h index 1efe1d22fc2f..4ab21b223aaf 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.h +++ b/drivers/net/wireless/ath/ath10k/qmi.h @@ -125,5 +125,6 @@ int ath10k_qmi_wlan_disable(struct ath10k *ar); int ath10k_qmi_register_service_notifier(struct notifier_block *nb); int ath10k_qmi_init(struct ath10k *ar, u32 msa_size); int ath10k_qmi_deinit(struct ath10k *ar); +int ath10k_qmi_set_fw_log_mode(struct ath10k *ar, u8 fw_log_mode); #endif /* ATH10K_QMI_H */ diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index e40375b8a425..8ab43b3f8002 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -1025,6 +1025,19 @@ static int ath10k_snoc_hif_power_up(struct ath10k *ar) return ret; } +static int ath10k_snoc_hif_set_target_log_mode(struct ath10k *ar, + u8 fw_log_mode) +{ + u8 fw_dbg_mode; + + if (fw_log_mode) + fw_dbg_mode = ATH10K_ENABLE_FW_LOG_CE; + else + fw_dbg_mode = ATH10K_ENABLE_FW_LOG_DIAG; + + return ath10k_qmi_set_fw_log_mode(ar, fw_dbg_mode); +} + static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .read32 = ath10k_snoc_read32, .write32 = ath10k_snoc_write32, @@ -1038,6 +1051,7 @@ static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .send_complete_check = ath10k_snoc_hif_send_complete_check, .get_free_queue_number = ath10k_snoc_hif_get_free_queue_number, .get_target_info = ath10k_snoc_hif_get_target_info, + .set_target_log_mode = ath10k_snoc_hif_set_target_log_mode, }; static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { From af07aee30208f2f74092462e0eb7b2f3424c1c73 Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Tue, 7 Jul 2020 12:42:04 +0530 Subject: [PATCH 125/192] msm: mhi_dev: Fix interrupt storm during Enable/disable mhi_dev_backup_mmio() and mhi_dev_restore_mmio() does backup/restore of INTR registers of MHI device, causing it to restore interrupts that are not valid during PCIE PM_RST_DEAST event. The fix is to skip the INTR register space. Change-Id: I2a8cde174cf4c6acd7acce13ad0195ed6a9a6f0b Signed-off-by: Subramanian Ananthanarayanan --- drivers/platform/msm/mhi_dev/mhi.h | 3 ++- drivers/platform/msm/mhi_dev/mhi_mmio.c | 12 ++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.h b/drivers/platform/msm/mhi_dev/mhi.h index 5d7923a7dc6e..6f5e1fea3cd0 100644 --- a/drivers/platform/msm/mhi_dev/mhi.h +++ b/drivers/platform/msm/mhi_dev/mhi.h @@ -424,7 +424,8 @@ static inline void mhi_dev_ring_inc_index(struct mhi_dev_ring *ring, #define TRACE_DATA_MAX 128 #define MHI_DEV_DATA_MAX 512 -#define MHI_DEV_MMIO_RANGE 0xc80 +#define MHI_DEV_MMIO_RANGE 0xb80 +#define MHI_DEV_MMIO_OFFSET 0x100 struct ring_cache_req { struct completion *done; diff --git a/drivers/platform/msm/mhi_dev/mhi_mmio.c b/drivers/platform/msm/mhi_dev/mhi_mmio.c index 240eff2edf5f..fd43d1152dbf 100644 --- a/drivers/platform/msm/mhi_dev/mhi_mmio.c +++ b/drivers/platform/msm/mhi_dev/mhi_mmio.c @@ -619,7 +619,8 @@ int mhi_dev_restore_mmio(struct mhi_dev *dev) mhi_dev_mmio_mask_interrupts(dev); for (i = 0; i < (MHI_DEV_MMIO_RANGE/4); i++) { - reg_cntl_addr = dev->mmio_base_addr + (i * 4); + reg_cntl_addr = dev->mmio_base_addr + + MHI_DEV_MMIO_OFFSET + (i * 4); reg_cntl_value = dev->mmio_backup[i]; writel_relaxed(reg_cntl_value, reg_cntl_addr); } @@ -640,13 +641,16 @@ EXPORT_SYMBOL(mhi_dev_restore_mmio); int mhi_dev_backup_mmio(struct mhi_dev *dev) { uint32_t i = 0; + void __iomem *reg_cntl_addr; if (WARN_ON(!dev)) return -EINVAL; - for (i = 0; i < MHI_DEV_MMIO_RANGE/4; i++) - dev->mmio_backup[i] = - readl_relaxed(dev->mmio_base_addr + (i * 4)); + for (i = 0; i < MHI_DEV_MMIO_RANGE/4; i++) { + reg_cntl_addr = (void __iomem *) (dev->mmio_base_addr + + MHI_DEV_MMIO_OFFSET + (i * 4)); + dev->mmio_backup[i] = readl_relaxed(reg_cntl_addr); + } return 0; } From fc14d1c505eaf259a1fce6d117ad6a5da0ec9878 Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Sat, 11 Jan 2020 17:50:36 +0800 Subject: [PATCH 126/192] ubifs: Fix deadlock in concurrent bulk-read and writepage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In ubifs, concurrent execution of writepage and bulk read on the same file may cause ABBA deadlock, for example (Reproduce method see Link): Process A(Bulk-read starts from page4) Process B(write page4 back) vfs_read wb_workfn or fsync ... ... generic_file_buffered_read write_cache_pages ubifs_readpage LOCK(page4) ubifs_bulk_read ubifs_writepage LOCK(ui->ui_mutex) ubifs_write_inode ubifs_do_bulk_read LOCK(ui->ui_mutex) find_or_create_page(alloc page4) ↑ LOCK(page4) <-- ABBA deadlock occurs! In order to ensure the serialization execution of bulk read, we can't remove the big lock 'ui->ui_mutex' in ubifs_bulk_read(). Instead, we allow ubifs_do_bulk_read() to lock page failed by replacing find_or_create_page(FGP_LOCK) with pagecache_get_page(FGP_LOCK | FGP_NOWAIT). Change-Id: I49a5b8d22c66bc4e45c1b93de59baff55d69ff43 Signed-off-by: Zhihao Cheng Suggested-by: zhangyi (F) Cc: Fixes: 4793e7c5e1c ("UBIFS: add bulk-read facility") Link: https://bugzilla.kernel.org/show_bug.cgi?id=206153 Signed-off-by: Richard Weinberger Git-commit: f5de5b83303e61b1f3fb09bd77ce3ac2d7a475f2 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/ Signed-off-by: Pradeep P V K --- fs/ubifs/file.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index ff44fd90d51b..76fff889a2f7 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -797,7 +797,9 @@ static int ubifs_do_bulk_read(struct ubifs_info *c, struct bu_info *bu, if (page_offset > end_index) break; - page = find_or_create_page(mapping, page_offset, ra_gfp_mask); + page = pagecache_get_page(mapping, page_offset, + FGP_LOCK|FGP_ACCESSED|FGP_CREAT|FGP_NOWAIT, + ra_gfp_mask); if (!page) break; if (!PageUptodate(page)) From 5e871485ef84541fad64ccbbb52b5bb5dbf123d1 Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Wed, 22 Apr 2020 16:04:21 +0800 Subject: [PATCH 127/192] coresight: tmc-etr: fix etr smmu unmap issue The return value 0 of dma_map_resource() is valid, so should use the dma_mapping_error() to check for errors. Change-Id: I368f480ed66bad0498e38da2fc6baa78b5935d7f Signed-off-by: Yuanfang Zhang --- drivers/hwtracing/coresight/coresight-tmc-etr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 11689f9b10a3..47c4d44e885c 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -604,7 +604,7 @@ static int tmc_etr_fill_usb_bam_data(struct tmc_drvdata *drvdata) data_fifo_iova = dma_map_resource(drvdata->dev, bamdata->data_fifo.phys_base, bamdata->data_fifo.size, DMA_BIDIRECTIONAL, 0); - if (!data_fifo_iova) + if (dma_mapping_error(drvdata->dev, data_fifo_iova)) return -ENOMEM; dev_dbg(drvdata->dev, "%s:data p_addr:%pa,iova:%pad,size:%x\n", __func__, &(bamdata->data_fifo.phys_base), @@ -613,7 +613,7 @@ static int tmc_etr_fill_usb_bam_data(struct tmc_drvdata *drvdata) desc_fifo_iova = dma_map_resource(drvdata->dev, bamdata->desc_fifo.phys_base, bamdata->desc_fifo.size, DMA_BIDIRECTIONAL, 0); - if (!desc_fifo_iova) + if (dma_mapping_error(drvdata->dev, desc_fifo_iova)) return -ENOMEM; dev_dbg(drvdata->dev, "%s:desc p_addr:%pa,iova:%pad,size:%x\n", __func__, &(bamdata->desc_fifo.phys_base), @@ -711,7 +711,7 @@ static int get_usb_bam_iova(struct device *dev, unsigned long usb_bam_handle, return ret; } *iova = dma_map_resource(dev, p_addr, bam_size, DMA_BIDIRECTIONAL, 0); - if (!(*iova)) + if (dma_mapping_error(dev, *iova)) return -ENOMEM; return 0; } From 8aed3617c48320538e4e032009c5b2b3de1bcd36 Mon Sep 17 00:00:00 2001 From: Vivek Pernamitta Date: Fri, 10 Jul 2020 13:11:37 +0530 Subject: [PATCH 128/192] mhi: core: Error handling for pending packets in mission_mode Clearing pending packets global reference count in mhi_controller only when channel is in mission mode in error handling mechanism with command completion timeout in mhi prepeare channel. Change-Id: Ib86b4f2a2ff5f28d27cf6174f65987d4f9ca1aea Signed-off-by: Vivek Pernamitta --- drivers/bus/mhi/core/mhi_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index 1a783ee59bb2..8e78c526dc04 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -1889,7 +1889,8 @@ int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, return 0; error_dec_pendpkt: - atomic_dec(&mhi_cntrl->pending_pkts); + if (in_mission_mode) + atomic_dec(&mhi_cntrl->pending_pkts); error_pm_state: if (!mhi_chan->offload_ch) mhi_deinit_chan_ctxt(mhi_cntrl, mhi_chan); From c082ac770973b871db29dd16e2b69aa4d4496145 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Sun, 24 Nov 2019 12:09:40 +0530 Subject: [PATCH 129/192] BACKPORT: UPSTREAM: ath10k: Set DMA address mask to 35 bit for WCN3990 WCN3990 is a 37-bit target but can address memory range only upto 35 bits. The 36th bit is used to control the smmu/iommu translation and the 37th bit is used by the internal bus masters to access the wifi subsystem internal SRAM. With the DMA mask set to 37i-bit, the host driver can get 37-bit dma address, which leads to incorrect address access in the target. Hence the host driver can used addresses upto 35-bit for WCN3990. Fix the dma mask for wcn3990 to 35-bit, instead of 37-bit. Tested HW: WCN3990 Tested FW: WLAN.HL.2.0-01188-QCAHLSWMTPLZ-1 Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo Git-commit: 5b9030cee1bedba934adb5c7ae708e510dddd0f0 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Change-Id: I798c67099212647c33dc897918ae2219e703de55 [govinds@codeaurora.org: resolve trivial merge conflicts in drivers/net/wireless/ath/ath10k/ce.c, drivers/net/wireless/ath/ath10k/hw.c] Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/ce.c | 75 ++++++++++++++++++++---- drivers/net/wireless/ath/ath10k/ce.h | 14 +++-- drivers/net/wireless/ath/ath10k/htt_tx.c | 2 +- drivers/net/wireless/ath/ath10k/hw.c | 10 ++-- drivers/net/wireless/ath/ath10k/hw.h | 6 +- drivers/net/wireless/ath/ath10k/snoc.c | 2 +- 6 files changed, 84 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 3b96a43fbda4..7c6733b026e5 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -228,11 +228,31 @@ ath10k_ce_shadow_dest_ring_write_index_set(struct ath10k *ar, } static inline void ath10k_ce_src_ring_base_addr_set(struct ath10k *ar, - u32 ce_ctrl_addr, - unsigned int addr) + u32 ce_id, + u64 addr) +{ + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; + u32 ce_ctrl_addr = ath10k_ce_base_address(ar, ce_id); + u32 addr_lo = lower_32_bits(addr); + + ath10k_ce_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->sr_base_addr_lo, addr_lo); + + if (ce_state->ops->ce_set_src_ring_base_addr_hi) { + ce_state->ops->ce_set_src_ring_base_addr_hi(ar, ce_ctrl_addr, + addr); + } +} + +static void ath10k_ce_set_src_ring_base_addr_hi(struct ath10k *ar, + u32 ce_ctrl_addr, + u64 addr) { + u32 addr_hi = upper_32_bits(addr) & CE_DESC_ADDR_HI_MASK; + ath10k_ce_write32(ar, ce_ctrl_addr + - ar->hw_ce_regs->sr_base_addr, addr); + ar->hw_ce_regs->sr_base_addr_hi, addr_hi); } static inline void ath10k_ce_src_ring_size_set(struct ath10k *ar, @@ -313,11 +333,36 @@ static inline u32 ath10k_ce_dest_ring_read_index_get(struct ath10k *ar, } static inline void ath10k_ce_dest_ring_base_addr_set(struct ath10k *ar, - u32 ce_ctrl_addr, - u32 addr) + u32 ce_id, + u64 addr) { + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; + u32 ce_ctrl_addr = ath10k_ce_base_address(ar, ce_id); + u32 addr_lo = lower_32_bits(addr); + + ath10k_ce_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->dr_base_addr_lo, addr_lo); + + if (ce_state->ops->ce_set_dest_ring_base_addr_hi) { + ce_state->ops->ce_set_dest_ring_base_addr_hi(ar, ce_ctrl_addr, + addr); + } +} + +static void ath10k_ce_set_dest_ring_base_addr_hi(struct ath10k *ar, + u32 ce_ctrl_addr, + u64 addr) +{ + u32 addr_hi = upper_32_bits(addr) & CE_DESC_ADDR_HI_MASK; + u32 reg_value; + + reg_value = ath10k_ce_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->dr_base_addr_hi); + reg_value &= ~CE_DESC_ADDR_HI_MASK; + reg_value |= addr_hi; ath10k_ce_write32(ar, ce_ctrl_addr + - ar->hw_ce_regs->dr_base_addr, addr); + ar->hw_ce_regs->dr_base_addr_hi, reg_value); } static inline void ath10k_ce_dest_ring_size_set(struct ath10k *ar, @@ -563,7 +608,7 @@ static int _ath10k_ce_send_nolock_64(struct ath10k_ce_pipe *ce_state, addr = (__le32 *)&sdesc.addr; - flags |= upper_32_bits(buffer) & CE_DESC_FLAGS_GET_MASK; + flags |= upper_32_bits(buffer) & CE_DESC_ADDR_HI_MASK; addr[0] = __cpu_to_le32(buffer); addr[1] = __cpu_to_le32(flags); if (flags & CE_SEND_FLAG_GATHER) @@ -731,7 +776,7 @@ static int __ath10k_ce_rx_post_buf_64(struct ath10k_ce_pipe *pipe, return -ENOSPC; desc->addr = __cpu_to_le64(paddr); - desc->addr &= __cpu_to_le64(CE_DESC_37BIT_ADDR_MASK); + desc->addr &= __cpu_to_le64(CE_DESC_ADDR_MASK); desc->nbytes = 0; @@ -1336,7 +1381,7 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar, ath10k_ce_src_ring_write_index_get(ar, ctrl_addr); src_ring->write_index &= src_ring->nentries_mask; - ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr, + ath10k_ce_src_ring_base_addr_set(ar, ce_id, src_ring->base_addr_ce_space); ath10k_ce_src_ring_size_set(ar, ctrl_addr, nentries); ath10k_ce_src_ring_dmax_set(ar, ctrl_addr, attr->src_sz_max); @@ -1375,7 +1420,7 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar, ath10k_ce_dest_ring_write_index_get(ar, ctrl_addr); dest_ring->write_index &= dest_ring->nentries_mask; - ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr, + ath10k_ce_dest_ring_base_addr_set(ar, ce_id, dest_ring->base_addr_ce_space); ath10k_ce_dest_ring_size_set(ar, ctrl_addr, nentries); ath10k_ce_dest_ring_byte_swap_set(ar, ctrl_addr, 0); @@ -1659,7 +1704,7 @@ static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id) { u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id); - ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr, 0); + ath10k_ce_src_ring_base_addr_set(ar, ce_id, 0); ath10k_ce_src_ring_size_set(ar, ctrl_addr, 0); ath10k_ce_src_ring_dmax_set(ar, ctrl_addr, 0); ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, 0); @@ -1669,7 +1714,7 @@ static void ath10k_ce_deinit_dest_ring(struct ath10k *ar, unsigned int ce_id) { u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id); - ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr, 0); + ath10k_ce_dest_ring_base_addr_set(ar, ce_id, 0); ath10k_ce_dest_ring_size_set(ar, ctrl_addr, 0); ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, 0); } @@ -1801,6 +1846,8 @@ static const struct ath10k_ce_ops ce_ops = { .ce_extract_desc_data = ath10k_ce_extract_desc_data, .ce_free_pipe = _ath10k_ce_free_pipe, .ce_send_nolock = _ath10k_ce_send_nolock, + .ce_set_src_ring_base_addr_hi = NULL, + .ce_set_dest_ring_base_addr_hi = NULL, }; static const struct ath10k_ce_ops ce_64_ops = { @@ -1813,6 +1860,8 @@ static const struct ath10k_ce_ops ce_64_ops = { .ce_extract_desc_data = ath10k_ce_extract_desc_data_64, .ce_free_pipe = _ath10k_ce_free_pipe_64, .ce_send_nolock = _ath10k_ce_send_nolock_64, + .ce_set_src_ring_base_addr_hi = ath10k_ce_set_src_ring_base_addr_hi, + .ce_set_dest_ring_base_addr_hi = ath10k_ce_set_dest_ring_base_addr_hi, }; static void ath10k_ce_set_ops(struct ath10k *ar, @@ -1908,7 +1957,7 @@ void ath10k_ce_alloc_rri(struct ath10k *ar) lower_32_bits(ce->paddr_rri)); ath10k_ce_write32(ar, ar->hw_ce_regs->ce_rri_high, (upper_32_bits(ce->paddr_rri) & - CE_DESC_FLAGS_GET_MASK)); + CE_DESC_ADDR_HI_MASK)); for (i = 0; i < CE_COUNT; i++) { ctrl1_regs = ar->hw_ce_regs->ctrl1_regs->addr; diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 0c3a1ad25a9a..2282aae9557f 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -39,8 +39,8 @@ struct ath10k_ce_pipe; #define CE_DESC_FLAGS_BYTE_SWAP (1 << 1) #define CE_WCN3990_DESC_FLAGS_GATHER BIT(31) -#define CE_DESC_FLAGS_GET_MASK GENMASK(4, 0) -#define CE_DESC_37BIT_ADDR_MASK GENMASK_ULL(37, 0) +#define CE_DESC_ADDR_MASK GENMASK_ULL(34, 0) +#define CE_DESC_ADDR_HI_MASK GENMASK(4, 0) /* Following desc flags are used in QCA99X0 */ #define CE_DESC_FLAGS_HOST_INT_DIS (1 << 2) @@ -104,7 +104,7 @@ struct ath10k_ce_ring { /* Host address space */ void *base_addr_owner_space_unaligned; /* CE address space */ - u32 base_addr_ce_space_unaligned; + dma_addr_t base_addr_ce_space_unaligned; /* * Actual start of descriptors. @@ -115,7 +115,7 @@ struct ath10k_ce_ring { void *base_addr_owner_space; /* CE address space */ - u32 base_addr_ce_space; + dma_addr_t base_addr_ce_space; char *shadow_base_unaligned; struct ce_desc *shadow_base; @@ -331,6 +331,12 @@ struct ath10k_ce_ops { void *per_transfer_context, dma_addr_t buffer, u32 nbytes, u32 transfer_id, u32 flags); + void (*ce_set_src_ring_base_addr_hi)(struct ath10k *ar, + u32 ce_ctrl_addr, + u64 addr); + void (*ce_set_dest_ring_base_addr_hi)(struct ath10k *ar, + u32 ce_ctrl_addr, + u64 addr); }; static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) { diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 62f3bfab405f..4854df133724 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -1359,7 +1359,7 @@ static int ath10k_htt_tx_64(struct ath10k_htt *htt, u16 msdu_id, flags1 = 0; u16 freq = 0; dma_addr_t frags_paddr = 0; - u32 txbuf_paddr; + dma_addr_t txbuf_paddr; struct htt_msdu_ext_desc_64 *ext_desc = NULL; struct htt_msdu_ext_desc_64 *ext_desc_t = NULL; diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 1ffaeb1dd71d..669a0ab927c4 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -317,9 +317,11 @@ static struct ath10k_hw_ce_ctrl1_upd wcn3990_ctrl1_upd = { }; struct ath10k_hw_ce_regs wcn3990_ce_regs = { - .sr_base_addr = 0x00000000, + .sr_base_addr_lo = 0x00000000, + .sr_base_addr_hi = 0x00000004, .sr_size_addr = 0x00000008, - .dr_base_addr = 0x0000000c, + .dr_base_addr_lo = 0x0000000c, + .dr_base_addr_hi = 0x00000010, .dr_size_addr = 0x00000014, .misc_ie_addr = 0x00000034, .sr_wr_index_addr = 0x0000003c, @@ -463,9 +465,9 @@ static struct ath10k_hw_ce_dst_src_wm_regs qcax_wm_dst_ring = { }; struct ath10k_hw_ce_regs qcax_ce_regs = { - .sr_base_addr = 0x00000000, + .sr_base_addr_lo = 0x00000000, .sr_size_addr = 0x00000004, - .dr_base_addr = 0x00000008, + .dr_base_addr_lo = 0x00000008, .dr_size_addr = 0x0000000c, .ce_cmd_addr = 0x00000018, .misc_ie_addr = 0x00000034, diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index fe54746a33ec..e4c5fd756c57 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -345,9 +345,11 @@ struct ath10k_hw_ce_ctrl1_upd { }; struct ath10k_hw_ce_regs { - u32 sr_base_addr; + u32 sr_base_addr_lo; + u32 sr_base_addr_hi; u32 sr_size_addr; - u32 dr_base_addr; + u32 dr_base_addr_lo; + u32 dr_base_addr_hi; u32 dr_size_addr; u32 ce_cmd_addr; u32 misc_ie_addr; diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 8ab43b3f8002..f9f527a96a24 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -65,7 +65,7 @@ static void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state); static const struct ath10k_snoc_drv_priv drv_priv = { .hw_rev = ATH10K_HW_WCN3990, - .dma_mask = DMA_BIT_MASK(37), + .dma_mask = DMA_BIT_MASK(35), .msa_size = 0x100000, }; From 7ff8634ec6a9f2e9250ee7728c1f541453e00893 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Mon, 4 Feb 2019 17:25:55 +0530 Subject: [PATCH 130/192] UPSTREAM: ath10k: update HOST capability qmi message HOST capability interface data structures are updated in HL3.1 fw version.Update the qmi host capability members for compatibility across different firmware versions. Since this change breaks backward compatibility with HL2.0 fw, HL2.0 fw upgrade to WLAN.HL.2.0-01617-QCAHLSWMTPLZ-1 or later version is required. Testing: Tested on QCS404 platform(WCN3990 HW). Tested FW: WLAN.HL.3.1-00784-QCAHLSWMTPLZ-1, WLAN.HL.2.0-01617-QCAHLSWMTPLZ-1 Signed-off-by: Kalle Valo Signed-off-by: Govind Singh Change-Id: I3b2eb17b065d23b44bef57c0be52c723c30d4055 Git-commit: 768ec4c012ac8b32d8062e599f105f57a6f4c01b Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Govind Singh --- .../net/wireless/ath/ath10k/qmi_wlfw_v01.c | 229 +++++++++++++++++- .../net/wireless/ath/ath10k/qmi_wlfw_v01.h | 34 ++- 2 files changed, 257 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c index ba79c2e4aed6..4102f7b0b5c3 100644 --- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c +++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c @@ -1763,14 +1763,239 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { daemon_support_valid), }, { - .data_type = QMI_UNSIGNED_1_BYTE, + .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, - .elem_size = sizeof(u8), + .elem_size = sizeof(u32), .array_type = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, daemon_support), }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + wake_msi_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + wake_msi), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + gpios_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + gpios_len), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = QMI_WLFW_MAX_NUM_GPIO_V01, + .elem_size = sizeof(u32), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + gpios), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + nm_modem_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + nm_modem), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + bdf_support_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + bdf_support), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + bdf_cache_support_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + bdf_cache_support), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + m3_support_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + m3_support), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x17, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + m3_cache_support_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x17, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + m3_cache_support), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x18, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + cal_filesys_support_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x18, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + cal_filesys_support), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x19, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + cal_cache_support_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x19, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + cal_cache_support), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x1A, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + cal_done_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x1A, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + cal_done), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x1B, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + mem_bucket_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x1B, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + mem_bucket), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x1C, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + mem_cfg_mode_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x1C, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + mem_cfg_mode), + }, {} }; diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h index c5e3870b8871..ff668f5d8afd 100644 --- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h +++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h @@ -553,12 +553,38 @@ struct wlfw_mac_addr_resp_msg_v01 { #define WLFW_MAC_ADDR_RESP_MSG_V01_MAX_MSG_LEN 7 extern struct qmi_elem_info wlfw_mac_addr_resp_msg_v01_ei[]; +#define QMI_WLFW_MAX_NUM_GPIO_V01 32 struct wlfw_host_cap_req_msg_v01 { u8 daemon_support_valid; - u8 daemon_support; -}; - -#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 4 + u32 daemon_support; + u8 wake_msi_valid; + u32 wake_msi; + u8 gpios_valid; + u32 gpios_len; + u32 gpios[QMI_WLFW_MAX_NUM_GPIO_V01]; + u8 nm_modem_valid; + u8 nm_modem; + u8 bdf_support_valid; + u8 bdf_support; + u8 bdf_cache_support_valid; + u8 bdf_cache_support; + u8 m3_support_valid; + u8 m3_support; + u8 m3_cache_support_valid; + u8 m3_cache_support; + u8 cal_filesys_support_valid; + u8 cal_filesys_support; + u8 cal_cache_support_valid; + u8 cal_cache_support; + u8 cal_done_valid; + u8 cal_done; + u8 mem_bucket_valid; + u32 mem_bucket; + u8 mem_cfg_mode_valid; + u8 mem_cfg_mode; +}; + +#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 189 extern struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[]; struct wlfw_host_cap_resp_msg_v01 { From f162170cbc71c81955071763f95af4efe6ce516d Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 17 Sep 2019 10:48:59 +0530 Subject: [PATCH 131/192] ath10k: Don't call SCM interface for statically mapped msa region For some targets ex: QCS404, SCM permissions for MSA region is statically configured in TrustZone fw. Add SCM call disable option for such targets to avoid duplicate permissions. Change-Id: Id0d75721bfd31bfbcc146d8251764e4841c22d6c Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/qmi.c | 9 +++++++++ drivers/net/wireless/ath/ath10k/qmi.h | 1 + 2 files changed, 10 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index 73defa565523..664a51831abb 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -95,6 +95,9 @@ static int ath10k_qmi_setup_msa_permissions(struct ath10k_qmi *qmi) int ret; int i; + if (qmi->msa_fixed_perm) + return 0; + for (i = 0; i < qmi->nr_mem_region; i++) { ret = ath10k_qmi_map_msa_permission(qmi, &qmi->mem_region[i]); if (ret) @@ -113,6 +116,9 @@ static void ath10k_qmi_remove_msa_permission(struct ath10k_qmi *qmi) { int i; + if (qmi->msa_fixed_perm) + return; + for (i = 0; i < qmi->nr_mem_region; i++) ath10k_qmi_unmap_msa_permission(qmi, &qmi->mem_region[i]); } @@ -990,6 +996,9 @@ static int ath10k_qmi_setup_msa_resources(struct ath10k_qmi *qmi, u32 msa_size) qmi->msa_mem_size = msa_size; } + if (of_property_read_bool(dev->of_node, "qcom,msa_fixed_perm")) + qmi->msa_fixed_perm = true; + ath10k_dbg(ar, ATH10K_DBG_QMI, "msa pa: %pad , msa va: 0x%p\n", &qmi->msa_pa, qmi->msa_va); diff --git a/drivers/net/wireless/ath/ath10k/qmi.h b/drivers/net/wireless/ath/ath10k/qmi.h index 4ab21b223aaf..3a039e6e29df 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.h +++ b/drivers/net/wireless/ath/ath10k/qmi.h @@ -115,6 +115,7 @@ struct ath10k_qmi { bool fw_ready; char fw_build_timestamp[MAX_TIMESTAMP_LEN + 1]; struct ath10k_qmi_cal_data cal_data[MAX_NUM_CAL_V01]; + bool msa_fixed_perm; }; int ath10k_qmi_wlan_enable(struct ath10k *ar, From 03522f50bb2fb726bea8fc4da45c07ca21f35e5b Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Mon, 30 Jul 2018 15:18:13 +0530 Subject: [PATCH 132/192] ath10k: Fix compilation error due to downstream QMI implementation struct qmi_elem_info members in downstream kernel are not in sync with upstream implementation. Fix this to avoid compilation errors. Change-Id: I57a50377e9333044ed2e302dbb8a7e0cc1167a5f Signed-off-by: Govind Singh --- .../net/wireless/ath/ath10k/qmi_wlfw_v01.c | 392 +++++++++--------- 1 file changed, 196 insertions(+), 196 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c index 4102f7b0b5c3..2f3b13ab9864 100644 --- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c +++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c @@ -23,7 +23,7 @@ static struct qmi_elem_info wlfw_ce_tgt_pipe_cfg_s_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, pipe_num), @@ -32,7 +32,7 @@ static struct qmi_elem_info wlfw_ce_tgt_pipe_cfg_s_v01_ei[] = { .data_type = QMI_SIGNED_4_BYTE_ENUM, .elem_len = 1, .elem_size = sizeof(enum wlfw_pipedir_enum_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, pipe_dir), @@ -41,7 +41,7 @@ static struct qmi_elem_info wlfw_ce_tgt_pipe_cfg_s_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, nentries), @@ -50,7 +50,7 @@ static struct qmi_elem_info wlfw_ce_tgt_pipe_cfg_s_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, nbytes_max), @@ -59,7 +59,7 @@ static struct qmi_elem_info wlfw_ce_tgt_pipe_cfg_s_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01, flags), @@ -72,7 +72,7 @@ static struct qmi_elem_info wlfw_ce_svc_pipe_cfg_s_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01, service_id), @@ -81,7 +81,7 @@ static struct qmi_elem_info wlfw_ce_svc_pipe_cfg_s_v01_ei[] = { .data_type = QMI_SIGNED_4_BYTE_ENUM, .elem_len = 1, .elem_size = sizeof(enum wlfw_pipedir_enum_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01, pipe_dir), @@ -90,7 +90,7 @@ static struct qmi_elem_info wlfw_ce_svc_pipe_cfg_s_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01, pipe_num), @@ -103,7 +103,7 @@ static struct qmi_elem_info wlfw_shadow_reg_cfg_s_v01_ei[] = { .data_type = QMI_UNSIGNED_2_BYTE, .elem_len = 1, .elem_size = sizeof(u16), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_shadow_reg_cfg_s_v01, id), @@ -112,7 +112,7 @@ static struct qmi_elem_info wlfw_shadow_reg_cfg_s_v01_ei[] = { .data_type = QMI_UNSIGNED_2_BYTE, .elem_len = 1, .elem_size = sizeof(u16), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_shadow_reg_cfg_s_v01, offset), @@ -125,7 +125,7 @@ static struct qmi_elem_info wlfw_shadow_reg_v2_cfg_s_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_shadow_reg_v2_cfg_s_v01, addr), @@ -138,7 +138,7 @@ static struct qmi_elem_info wlfw_memory_region_info_s_v01_ei[] = { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, .elem_size = sizeof(u64), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_memory_region_info_s_v01, region_addr), @@ -147,7 +147,7 @@ static struct qmi_elem_info wlfw_memory_region_info_s_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_memory_region_info_s_v01, size), @@ -156,7 +156,7 @@ static struct qmi_elem_info wlfw_memory_region_info_s_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_memory_region_info_s_v01, secure_flag), @@ -169,7 +169,7 @@ static struct qmi_elem_info wlfw_mem_cfg_s_v01_ei[] = { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, .elem_size = sizeof(u64), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_mem_cfg_s_v01, offset), @@ -178,7 +178,7 @@ static struct qmi_elem_info wlfw_mem_cfg_s_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_mem_cfg_s_v01, size), @@ -187,7 +187,7 @@ static struct qmi_elem_info wlfw_mem_cfg_s_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_mem_cfg_s_v01, secure_flag), @@ -200,7 +200,7 @@ static struct qmi_elem_info wlfw_mem_seg_s_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_mem_seg_s_v01, size), @@ -209,7 +209,7 @@ static struct qmi_elem_info wlfw_mem_seg_s_v01_ei[] = { .data_type = QMI_SIGNED_4_BYTE_ENUM, .elem_len = 1, .elem_size = sizeof(enum wlfw_mem_type_enum_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_mem_seg_s_v01, type), @@ -218,7 +218,7 @@ static struct qmi_elem_info wlfw_mem_seg_s_v01_ei[] = { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_mem_seg_s_v01, mem_cfg_len), @@ -227,7 +227,7 @@ static struct qmi_elem_info wlfw_mem_seg_s_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = QMI_WLFW_MAX_NUM_MEM_CFG_V01, .elem_size = sizeof(struct wlfw_mem_cfg_s_v01), - .array_type = VAR_LEN_ARRAY, + .is_array = VAR_LEN_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_mem_seg_s_v01, mem_cfg), @@ -241,7 +241,7 @@ static struct qmi_elem_info wlfw_mem_seg_resp_s_v01_ei[] = { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, .elem_size = sizeof(u64), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_mem_seg_resp_s_v01, addr), @@ -250,7 +250,7 @@ static struct qmi_elem_info wlfw_mem_seg_resp_s_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_mem_seg_resp_s_v01, size), @@ -259,7 +259,7 @@ static struct qmi_elem_info wlfw_mem_seg_resp_s_v01_ei[] = { .data_type = QMI_SIGNED_4_BYTE_ENUM, .elem_len = 1, .elem_size = sizeof(enum wlfw_mem_type_enum_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_mem_seg_resp_s_v01, type), @@ -272,7 +272,7 @@ static struct qmi_elem_info wlfw_rf_chip_info_s_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_rf_chip_info_s_v01, chip_id), @@ -281,7 +281,7 @@ static struct qmi_elem_info wlfw_rf_chip_info_s_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_rf_chip_info_s_v01, chip_family), @@ -294,7 +294,7 @@ static struct qmi_elem_info wlfw_rf_board_info_s_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_rf_board_info_s_v01, board_id), @@ -307,7 +307,7 @@ static struct qmi_elem_info wlfw_soc_info_s_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_soc_info_s_v01, soc_id), @@ -320,7 +320,7 @@ static struct qmi_elem_info wlfw_fw_version_info_s_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_fw_version_info_s_v01, fw_version), @@ -329,7 +329,7 @@ static struct qmi_elem_info wlfw_fw_version_info_s_v01_ei[] = { .data_type = QMI_STRING, .elem_len = QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1, .elem_size = sizeof(char), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0, .offset = offsetof(struct wlfw_fw_version_info_s_v01, fw_build_timestamp), @@ -342,7 +342,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, fw_ready_enable_valid), @@ -351,7 +351,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, fw_ready_enable), @@ -360,7 +360,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, initiate_cal_download_enable_valid), @@ -369,7 +369,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, initiate_cal_download_enable), @@ -378,7 +378,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, initiate_cal_update_enable_valid), @@ -387,7 +387,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, initiate_cal_update_enable), @@ -396,7 +396,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, msa_ready_enable_valid), @@ -405,7 +405,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, msa_ready_enable), @@ -414,7 +414,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x14, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, pin_connect_result_enable_valid), @@ -423,7 +423,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x14, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, pin_connect_result_enable), @@ -432,7 +432,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x15, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, client_id_valid), @@ -441,7 +441,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x15, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, client_id), @@ -450,7 +450,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x16, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, request_mem_enable_valid), @@ -459,7 +459,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x16, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, request_mem_enable), @@ -468,7 +468,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x17, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, mem_ready_enable_valid), @@ -477,7 +477,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x17, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, mem_ready_enable), @@ -486,7 +486,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x18, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, fw_init_done_enable_valid), @@ -495,7 +495,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x18, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, fw_init_done_enable), @@ -504,7 +504,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x19, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, rejuvenate_enable_valid), @@ -513,7 +513,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x19, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, rejuvenate_enable), @@ -522,7 +522,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x1A, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, xo_cal_enable_valid), @@ -531,7 +531,7 @@ struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x1A, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, xo_cal_enable), @@ -544,7 +544,7 @@ struct qmi_elem_info wlfw_ind_register_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_ind_register_resp_msg_v01, resp), @@ -554,7 +554,7 @@ struct qmi_elem_info wlfw_ind_register_resp_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_ind_register_resp_msg_v01, fw_status_valid), @@ -563,7 +563,7 @@ struct qmi_elem_info wlfw_ind_register_resp_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, .elem_size = sizeof(u64), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_ind_register_resp_msg_v01, fw_status), @@ -584,7 +584,7 @@ struct qmi_elem_info wlfw_pin_connect_result_ind_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01, pwr_pin_result_valid), @@ -593,7 +593,7 @@ struct qmi_elem_info wlfw_pin_connect_result_ind_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01, pwr_pin_result), @@ -602,7 +602,7 @@ struct qmi_elem_info wlfw_pin_connect_result_ind_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01, phy_io_pin_result_valid), @@ -611,7 +611,7 @@ struct qmi_elem_info wlfw_pin_connect_result_ind_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01, phy_io_pin_result), @@ -620,7 +620,7 @@ struct qmi_elem_info wlfw_pin_connect_result_ind_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01, rf_pin_result_valid), @@ -629,7 +629,7 @@ struct qmi_elem_info wlfw_pin_connect_result_ind_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_pin_connect_result_ind_msg_v01, rf_pin_result), @@ -642,7 +642,7 @@ struct qmi_elem_info wlfw_wlan_mode_req_msg_v01_ei[] = { .data_type = QMI_SIGNED_4_BYTE_ENUM, .elem_len = 1, .elem_size = sizeof(enum wlfw_driver_mode_enum_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01, mode), @@ -651,7 +651,7 @@ struct qmi_elem_info wlfw_wlan_mode_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01, hw_debug_valid), @@ -660,7 +660,7 @@ struct qmi_elem_info wlfw_wlan_mode_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01, hw_debug), @@ -673,7 +673,7 @@ struct qmi_elem_info wlfw_wlan_mode_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_wlan_mode_resp_msg_v01, resp), @@ -687,7 +687,7 @@ struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, host_version_valid), @@ -696,7 +696,7 @@ struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { .data_type = QMI_STRING, .elem_len = QMI_WLFW_MAX_STR_LEN_V01 + 1, .elem_size = sizeof(char), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, host_version), @@ -705,7 +705,7 @@ struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, tgt_cfg_valid), @@ -714,7 +714,7 @@ struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, tgt_cfg_len), @@ -723,7 +723,7 @@ struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = QMI_WLFW_MAX_NUM_CE_V01, .elem_size = sizeof(struct wlfw_ce_tgt_pipe_cfg_s_v01), - .array_type = VAR_LEN_ARRAY, + .is_array = VAR_LEN_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, tgt_cfg), @@ -733,7 +733,7 @@ struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, svc_cfg_valid), @@ -742,7 +742,7 @@ struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, svc_cfg_len), @@ -751,7 +751,7 @@ struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = QMI_WLFW_MAX_NUM_SVC_V01, .elem_size = sizeof(struct wlfw_ce_svc_pipe_cfg_s_v01), - .array_type = VAR_LEN_ARRAY, + .is_array = VAR_LEN_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, svc_cfg), @@ -761,7 +761,7 @@ struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, shadow_reg_valid), @@ -770,7 +770,7 @@ struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, shadow_reg_len), @@ -779,7 +779,7 @@ struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01, .elem_size = sizeof(struct wlfw_shadow_reg_cfg_s_v01), - .array_type = VAR_LEN_ARRAY, + .is_array = VAR_LEN_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, shadow_reg), @@ -789,7 +789,7 @@ struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x14, .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, shadow_reg_v2_valid), @@ -798,7 +798,7 @@ struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x14, .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, shadow_reg_v2_len), @@ -807,7 +807,7 @@ struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = QMI_WLFW_MAX_SHADOW_REG_V2, .elem_size = sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01), - .array_type = VAR_LEN_ARRAY, + .is_array = VAR_LEN_ARRAY, .tlv_type = 0x14, .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, shadow_reg_v2), @@ -821,7 +821,7 @@ struct qmi_elem_info wlfw_wlan_cfg_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_wlan_cfg_resp_msg_v01, resp), @@ -839,7 +839,7 @@ struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_cap_resp_msg_v01, resp), @@ -849,7 +849,7 @@ struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_cap_resp_msg_v01, chip_info_valid), @@ -858,7 +858,7 @@ struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct wlfw_rf_chip_info_s_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_cap_resp_msg_v01, chip_info), @@ -868,7 +868,7 @@ struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_cap_resp_msg_v01, board_info_valid), @@ -877,7 +877,7 @@ struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct wlfw_rf_board_info_s_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_cap_resp_msg_v01, board_info), @@ -887,7 +887,7 @@ struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_cap_resp_msg_v01, soc_info_valid), @@ -896,7 +896,7 @@ struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct wlfw_soc_info_s_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_cap_resp_msg_v01, soc_info), @@ -906,7 +906,7 @@ struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_cap_resp_msg_v01, fw_version_info_valid), @@ -915,7 +915,7 @@ struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct wlfw_fw_version_info_s_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_cap_resp_msg_v01, fw_version_info), @@ -925,7 +925,7 @@ struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x14, .offset = offsetof(struct wlfw_cap_resp_msg_v01, fw_build_id_valid), @@ -934,7 +934,7 @@ struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[] = { .data_type = QMI_STRING, .elem_len = QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1, .elem_size = sizeof(char), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x14, .offset = offsetof(struct wlfw_cap_resp_msg_v01, fw_build_id), @@ -943,7 +943,7 @@ struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x15, .offset = offsetof(struct wlfw_cap_resp_msg_v01, num_macs_valid), @@ -952,7 +952,7 @@ struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x15, .offset = offsetof(struct wlfw_cap_resp_msg_v01, num_macs), @@ -965,7 +965,7 @@ struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, valid), @@ -974,7 +974,7 @@ struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, file_id_valid), @@ -983,7 +983,7 @@ struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[] = { .data_type = QMI_SIGNED_4_BYTE_ENUM, .elem_len = 1, .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, file_id), @@ -992,7 +992,7 @@ struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, total_size_valid), @@ -1001,7 +1001,7 @@ struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, total_size), @@ -1010,7 +1010,7 @@ struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, seg_id_valid), @@ -1019,7 +1019,7 @@ struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, seg_id), @@ -1028,7 +1028,7 @@ struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, data_valid), @@ -1037,7 +1037,7 @@ struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[] = { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(u16), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, data_len), @@ -1046,7 +1046,7 @@ struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01, .elem_size = sizeof(u8), - .array_type = VAR_LEN_ARRAY, + .is_array = VAR_LEN_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, data), @@ -1055,7 +1055,7 @@ struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x14, .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, end_valid), @@ -1064,7 +1064,7 @@ struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x14, .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, end), @@ -1073,7 +1073,7 @@ struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x15, .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, bdf_type_valid), @@ -1082,7 +1082,7 @@ struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x15, .offset = offsetof(struct wlfw_bdf_download_req_msg_v01, bdf_type), @@ -1095,7 +1095,7 @@ struct qmi_elem_info wlfw_bdf_download_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_bdf_download_resp_msg_v01, resp), @@ -1109,7 +1109,7 @@ struct qmi_elem_info wlfw_cal_report_req_msg_v01_ei[] = { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_cal_report_req_msg_v01, meta_data_len), @@ -1118,7 +1118,7 @@ struct qmi_elem_info wlfw_cal_report_req_msg_v01_ei[] = { .data_type = QMI_SIGNED_4_BYTE_ENUM, .elem_len = QMI_WLFW_MAX_NUM_CAL_V01, .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), - .array_type = VAR_LEN_ARRAY, + .is_array = VAR_LEN_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_cal_report_req_msg_v01, meta_data), @@ -1127,7 +1127,7 @@ struct qmi_elem_info wlfw_cal_report_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_cal_report_req_msg_v01, xo_cal_data_valid), @@ -1136,7 +1136,7 @@ struct qmi_elem_info wlfw_cal_report_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_cal_report_req_msg_v01, xo_cal_data), @@ -1149,7 +1149,7 @@ struct qmi_elem_info wlfw_cal_report_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_cal_report_resp_msg_v01, resp), @@ -1163,7 +1163,7 @@ struct qmi_elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[] = { .data_type = QMI_SIGNED_4_BYTE_ENUM, .elem_len = 1, .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_initiate_cal_download_ind_msg_v01, cal_id), @@ -1176,7 +1176,7 @@ struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_cal_download_req_msg_v01, valid), @@ -1185,7 +1185,7 @@ struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_cal_download_req_msg_v01, file_id_valid), @@ -1194,7 +1194,7 @@ struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[] = { .data_type = QMI_SIGNED_4_BYTE_ENUM, .elem_len = 1, .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_cal_download_req_msg_v01, file_id), @@ -1203,7 +1203,7 @@ struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_cal_download_req_msg_v01, total_size_valid), @@ -1212,7 +1212,7 @@ struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_cal_download_req_msg_v01, total_size), @@ -1221,7 +1221,7 @@ struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_cal_download_req_msg_v01, seg_id_valid), @@ -1230,7 +1230,7 @@ struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_cal_download_req_msg_v01, seg_id), @@ -1239,7 +1239,7 @@ struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_cal_download_req_msg_v01, data_valid), @@ -1248,7 +1248,7 @@ struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[] = { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(u16), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_cal_download_req_msg_v01, data_len), @@ -1257,7 +1257,7 @@ struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01, .elem_size = sizeof(u8), - .array_type = VAR_LEN_ARRAY, + .is_array = VAR_LEN_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_cal_download_req_msg_v01, data), @@ -1266,7 +1266,7 @@ struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x14, .offset = offsetof(struct wlfw_cal_download_req_msg_v01, end_valid), @@ -1275,7 +1275,7 @@ struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x14, .offset = offsetof(struct wlfw_cal_download_req_msg_v01, end), @@ -1288,7 +1288,7 @@ struct qmi_elem_info wlfw_cal_download_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_cal_download_resp_msg_v01, resp), @@ -1302,7 +1302,7 @@ struct qmi_elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[] = { .data_type = QMI_SIGNED_4_BYTE_ENUM, .elem_len = 1, .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_initiate_cal_update_ind_msg_v01, cal_id), @@ -1311,7 +1311,7 @@ struct qmi_elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_initiate_cal_update_ind_msg_v01, total_size), @@ -1324,7 +1324,7 @@ struct qmi_elem_info wlfw_cal_update_req_msg_v01_ei[] = { .data_type = QMI_SIGNED_4_BYTE_ENUM, .elem_len = 1, .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_cal_update_req_msg_v01, cal_id), @@ -1333,7 +1333,7 @@ struct qmi_elem_info wlfw_cal_update_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_cal_update_req_msg_v01, seg_id), @@ -1346,7 +1346,7 @@ struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, resp), @@ -1356,7 +1356,7 @@ struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, file_id_valid), @@ -1365,7 +1365,7 @@ struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[] = { .data_type = QMI_SIGNED_4_BYTE_ENUM, .elem_len = 1, .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, file_id), @@ -1374,7 +1374,7 @@ struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, total_size_valid), @@ -1383,7 +1383,7 @@ struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, total_size), @@ -1392,7 +1392,7 @@ struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, seg_id_valid), @@ -1401,7 +1401,7 @@ struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, seg_id), @@ -1410,7 +1410,7 @@ struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, data_valid), @@ -1419,7 +1419,7 @@ struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[] = { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(u16), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, data_len), @@ -1428,7 +1428,7 @@ struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01, .elem_size = sizeof(u8), - .array_type = VAR_LEN_ARRAY, + .is_array = VAR_LEN_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, data), @@ -1437,7 +1437,7 @@ struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x14, .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, end_valid), @@ -1446,7 +1446,7 @@ struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x14, .offset = offsetof(struct wlfw_cal_update_resp_msg_v01, end), @@ -1459,7 +1459,7 @@ struct qmi_elem_info wlfw_msa_info_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, .elem_size = sizeof(u64), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_msa_info_req_msg_v01, msa_addr), @@ -1468,7 +1468,7 @@ struct qmi_elem_info wlfw_msa_info_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_msa_info_req_msg_v01, size), @@ -1481,7 +1481,7 @@ struct qmi_elem_info wlfw_msa_info_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_msa_info_resp_msg_v01, resp), @@ -1491,7 +1491,7 @@ struct qmi_elem_info wlfw_msa_info_resp_msg_v01_ei[] = { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x03, .offset = offsetof(struct wlfw_msa_info_resp_msg_v01, mem_region_info_len), @@ -1500,7 +1500,7 @@ struct qmi_elem_info wlfw_msa_info_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = QMI_WLFW_MAX_MEM_REG_V01, .elem_size = sizeof(struct wlfw_memory_region_info_s_v01), - .array_type = VAR_LEN_ARRAY, + .is_array = VAR_LEN_ARRAY, .tlv_type = 0x03, .offset = offsetof(struct wlfw_msa_info_resp_msg_v01, mem_region_info), @@ -1518,7 +1518,7 @@ struct qmi_elem_info wlfw_msa_ready_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_msa_ready_resp_msg_v01, resp), @@ -1532,7 +1532,7 @@ struct qmi_elem_info wlfw_ini_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_ini_req_msg_v01, enablefwlog_valid), @@ -1541,7 +1541,7 @@ struct qmi_elem_info wlfw_ini_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_ini_req_msg_v01, enablefwlog), @@ -1554,7 +1554,7 @@ struct qmi_elem_info wlfw_ini_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_ini_resp_msg_v01, resp), @@ -1568,7 +1568,7 @@ struct qmi_elem_info wlfw_athdiag_read_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01, offset), @@ -1577,7 +1577,7 @@ struct qmi_elem_info wlfw_athdiag_read_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01, mem_type), @@ -1586,7 +1586,7 @@ struct qmi_elem_info wlfw_athdiag_read_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x03, .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01, data_len), @@ -1599,7 +1599,7 @@ struct qmi_elem_info wlfw_athdiag_read_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_athdiag_read_resp_msg_v01, resp), @@ -1609,7 +1609,7 @@ struct qmi_elem_info wlfw_athdiag_read_resp_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_athdiag_read_resp_msg_v01, data_valid), @@ -1618,7 +1618,7 @@ struct qmi_elem_info wlfw_athdiag_read_resp_msg_v01_ei[] = { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(u16), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_athdiag_read_resp_msg_v01, data_len), @@ -1627,7 +1627,7 @@ struct qmi_elem_info wlfw_athdiag_read_resp_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01, .elem_size = sizeof(u8), - .array_type = VAR_LEN_ARRAY, + .is_array = VAR_LEN_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_athdiag_read_resp_msg_v01, data), @@ -1640,7 +1640,7 @@ struct qmi_elem_info wlfw_athdiag_write_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_athdiag_write_req_msg_v01, offset), @@ -1649,7 +1649,7 @@ struct qmi_elem_info wlfw_athdiag_write_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_athdiag_write_req_msg_v01, mem_type), @@ -1658,7 +1658,7 @@ struct qmi_elem_info wlfw_athdiag_write_req_msg_v01_ei[] = { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(u16), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x03, .offset = offsetof(struct wlfw_athdiag_write_req_msg_v01, data_len), @@ -1667,7 +1667,7 @@ struct qmi_elem_info wlfw_athdiag_write_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01, .elem_size = sizeof(u8), - .array_type = VAR_LEN_ARRAY, + .is_array = VAR_LEN_ARRAY, .tlv_type = 0x03, .offset = offsetof(struct wlfw_athdiag_write_req_msg_v01, data), @@ -1680,7 +1680,7 @@ struct qmi_elem_info wlfw_athdiag_write_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_athdiag_write_resp_msg_v01, resp), @@ -1694,7 +1694,7 @@ struct qmi_elem_info wlfw_vbatt_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, .elem_size = sizeof(u64), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_vbatt_req_msg_v01, voltage_uv), @@ -1707,7 +1707,7 @@ struct qmi_elem_info wlfw_vbatt_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_vbatt_resp_msg_v01, resp), @@ -1721,7 +1721,7 @@ struct qmi_elem_info wlfw_mac_addr_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_mac_addr_req_msg_v01, mac_addr_valid), @@ -1730,7 +1730,7 @@ struct qmi_elem_info wlfw_mac_addr_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = QMI_WLFW_MAC_ADDR_SIZE_V01, .elem_size = sizeof(u8), - .array_type = STATIC_ARRAY, + .is_array = STATIC_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_mac_addr_req_msg_v01, mac_addr), @@ -1743,7 +1743,7 @@ struct qmi_elem_info wlfw_mac_addr_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_mac_addr_resp_msg_v01, resp), @@ -1757,7 +1757,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, daemon_support_valid), @@ -2004,7 +2004,7 @@ struct qmi_elem_info wlfw_host_cap_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_host_cap_resp_msg_v01, resp), @@ -2018,7 +2018,7 @@ struct qmi_elem_info wlfw_request_mem_ind_msg_v01_ei[] = { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_request_mem_ind_msg_v01, mem_seg_len), @@ -2027,7 +2027,7 @@ struct qmi_elem_info wlfw_request_mem_ind_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = QMI_WLFW_MAX_NUM_MEM_SEG_V01, .elem_size = sizeof(struct wlfw_mem_seg_s_v01), - .array_type = VAR_LEN_ARRAY, + .is_array = VAR_LEN_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_request_mem_ind_msg_v01, mem_seg), @@ -2041,7 +2041,7 @@ struct qmi_elem_info wlfw_respond_mem_req_msg_v01_ei[] = { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_respond_mem_req_msg_v01, mem_seg_len), @@ -2050,7 +2050,7 @@ struct qmi_elem_info wlfw_respond_mem_req_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = QMI_WLFW_MAX_NUM_MEM_SEG_V01, .elem_size = sizeof(struct wlfw_mem_seg_resp_s_v01), - .array_type = VAR_LEN_ARRAY, + .is_array = VAR_LEN_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_respond_mem_req_msg_v01, mem_seg), @@ -2064,7 +2064,7 @@ struct qmi_elem_info wlfw_respond_mem_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_respond_mem_resp_msg_v01, resp), @@ -2086,7 +2086,7 @@ struct qmi_elem_info wlfw_rejuvenate_ind_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, cause_for_rejuvenation_valid), @@ -2095,7 +2095,7 @@ struct qmi_elem_info wlfw_rejuvenate_ind_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, cause_for_rejuvenation), @@ -2104,7 +2104,7 @@ struct qmi_elem_info wlfw_rejuvenate_ind_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, requesting_sub_system_valid), @@ -2113,7 +2113,7 @@ struct qmi_elem_info wlfw_rejuvenate_ind_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, requesting_sub_system), @@ -2122,7 +2122,7 @@ struct qmi_elem_info wlfw_rejuvenate_ind_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, line_number_valid), @@ -2131,7 +2131,7 @@ struct qmi_elem_info wlfw_rejuvenate_ind_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_2_BYTE, .elem_len = 1, .elem_size = sizeof(u16), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, line_number), @@ -2140,7 +2140,7 @@ struct qmi_elem_info wlfw_rejuvenate_ind_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, function_name_valid), @@ -2149,7 +2149,7 @@ struct qmi_elem_info wlfw_rejuvenate_ind_msg_v01_ei[] = { .data_type = QMI_STRING, .elem_len = QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1, .elem_size = sizeof(char), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01, function_name), @@ -2166,7 +2166,7 @@ struct qmi_elem_info wlfw_rejuvenate_ack_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_rejuvenate_ack_resp_msg_v01, resp), @@ -2180,7 +2180,7 @@ struct qmi_elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_dynamic_feature_mask_req_msg_v01, mask_valid), @@ -2189,7 +2189,7 @@ struct qmi_elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, .elem_size = sizeof(u64), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_dynamic_feature_mask_req_msg_v01, mask), @@ -2202,7 +2202,7 @@ struct qmi_elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01, resp), @@ -2212,7 +2212,7 @@ struct qmi_elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01, prev_mask_valid), @@ -2221,7 +2221,7 @@ struct qmi_elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, .elem_size = sizeof(u64), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01, prev_mask), @@ -2230,7 +2230,7 @@ struct qmi_elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01, curr_mask_valid), @@ -2239,7 +2239,7 @@ struct qmi_elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, .elem_size = sizeof(u64), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_dynamic_feature_mask_resp_msg_v01, curr_mask), @@ -2252,7 +2252,7 @@ struct qmi_elem_info wlfw_m3_info_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, .elem_size = sizeof(u64), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_m3_info_req_msg_v01, addr), @@ -2261,7 +2261,7 @@ struct qmi_elem_info wlfw_m3_info_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_m3_info_req_msg_v01, size), @@ -2274,7 +2274,7 @@ struct qmi_elem_info wlfw_m3_info_resp_msg_v01_ei[] = { .data_type = QMI_STRUCT, .elem_len = 1, .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x02, .offset = offsetof(struct wlfw_m3_info_resp_msg_v01, resp), @@ -2288,7 +2288,7 @@ struct qmi_elem_info wlfw_xo_cal_ind_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_xo_cal_ind_msg_v01, xo_cal_data), From 6b8f00393d2a2ccbd34f25905bbd51ff27b3df0a Mon Sep 17 00:00:00 2001 From: Siddartha Mohanadoss Date: Fri, 24 Jul 2020 10:40:21 -0700 Subject: [PATCH 133/192] PCI: Add PCIe quirks for PCIe root port Add the PCIe quirks for sdxprairie root port. Without this change there will be conflicts in the iommu group for the end points across the switch. Adding the quirk resolves each end points that has data traffic to get its own iommu group. Change-Id: I1c495889e76b84b2cef1cceee8fa3721778fc923 Signed-off-by: Siddartha Mohanadoss --- drivers/pci/quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 867056395d48..b931b2d8c6ea 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4530,6 +4530,7 @@ static const struct pci_dev_acs_enabled { /* QCOM QDF2xxx root ports */ { 0x17cb, 0x400, pci_quirk_qcom_rp_acs }, { 0x17cb, 0x401, pci_quirk_qcom_rp_acs }, + { 0x17cb, 0x10c, pci_quirk_qcom_rp_acs }, /* Intel PCH root ports */ { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs }, { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_spt_pch_acs }, From 0985a882bd37be606048b1e2dc55a10a05608c40 Mon Sep 17 00:00:00 2001 From: Ray Zhang Date: Thu, 23 Jul 2020 19:59:15 +0800 Subject: [PATCH 134/192] drm/msm/sde: initialize sde_encoder_wait_info before usage wait_info is not initialized in some cases, so fix it in sde driver. Change-Id: I7224cade5f088410dbfa1d95bbb0b05d3fbfde47 Signed-off-by: Ray Zhang --- drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c | 8 ++++---- drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c | 4 ++-- drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index ef0f55041a9f..3d31c6497f6d 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -708,7 +708,7 @@ static int _sde_encoder_phys_cmd_wait_for_idle( { struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc); - struct sde_encoder_wait_info wait_info = {NULL}; + struct sde_encoder_wait_info wait_info = {0}; bool recovery_events; int ret; @@ -761,7 +761,7 @@ static int _sde_encoder_phys_cmd_wait_for_autorefresh_done( { struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc); - struct sde_encoder_wait_info wait_info = {NULL}; + struct sde_encoder_wait_info wait_info = {0}; int ret = 0; if (!phys_enc) { @@ -1386,7 +1386,7 @@ static int _sde_encoder_phys_cmd_wait_for_wr_ptr( { struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc); - struct sde_encoder_wait_info wait_info = {NULL}; + struct sde_encoder_wait_info wait_info = {0}; int ret; bool frame_pending = true; struct sde_hw_ctl *ctl; @@ -1536,7 +1536,7 @@ static int sde_encoder_phys_cmd_wait_for_vblank( { int rc = 0; struct sde_encoder_phys_cmd *cmd_enc; - struct sde_encoder_wait_info wait_info = {NULL}; + struct sde_encoder_wait_info wait_info = {0}; if (!phys_enc) return -EINVAL; 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 34ebe8d2503d..c6c2c99ef496 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -945,7 +945,7 @@ static void sde_encoder_phys_vid_get_hw_resources( static int _sde_encoder_phys_vid_wait_for_vblank( struct sde_encoder_phys *phys_enc, bool notify) { - struct sde_encoder_wait_info wait_info; + struct sde_encoder_wait_info wait_info = {0}; int ret = 0; u32 event = 0; u32 event_helper = 0; 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 2e81e31288b0..e79450e2b941 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1227,7 +1227,7 @@ static int _sde_encoder_phys_wb_wait_for_commit_done( u32 event = 0; u64 wb_time = 0; int rc = 0; - struct sde_encoder_wait_info wait_info; + struct sde_encoder_wait_info wait_info = {0}; /* Return EWOULDBLOCK since we know the wait isn't necessary */ if (phys_enc->enable_state == SDE_ENC_DISABLED) { From 8215d24c78c694aedc0be766c671be006a9a1160 Mon Sep 17 00:00:00 2001 From: Ray Zhang Date: Thu, 23 Jul 2020 20:08:32 +0800 Subject: [PATCH 135/192] drm/msm/sde: avoid frame_done event trigger for idle scenario Current sde video mode encoder triggers frame done event without checking pending frame count in vblank_wait API call. That may lead to multiple frame_done events for last frame during encoder disable sequence. It can be avoided by managing frame_done event trigger along with retire fence because retire fence trigger always checks the pending frame count. It also avoids the frame_event callback from two different places and reduced event thread workload. Change-Id: I4bf0723f559c8c235bf56d8a676f6b6e8b6d6381 Signed-off-by: Dhaval Patel Signed-off-by: Ray Zhang --- .../gpu/drm/msm/sde/sde_encoder_phys_vid.c | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 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 c6c2c99ef496..426870b57164 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c @@ -597,7 +597,8 @@ static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) if (sde_encoder_phys_vid_is_master(phys_enc)) { if (atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0)) - event |= SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE | + event |= SDE_ENCODER_FRAME_EVENT_DONE | + SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE | SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE; } @@ -616,9 +617,10 @@ static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) phys_enc); SDE_EVT32_IRQ(DRMID(phys_enc->parent), phys_enc->hw_intf->idx - INTF_0, - old_cnt, new_cnt, reset_status ? SDE_EVTLOG_ERROR : 0, + old_cnt, atomic_read(&phys_enc->pending_kickoff_cnt), + reset_status ? SDE_EVTLOG_ERROR : 0, flush_register, event, - pend_ret_fence_cnt); + atomic_read(&phys_enc->pending_retire_fence_cnt)); /* Signal any waiting atomic commit thread */ wake_up_all(&phys_enc->pending_kickoff_wq); @@ -947,27 +949,25 @@ static int _sde_encoder_phys_vid_wait_for_vblank( { struct sde_encoder_wait_info wait_info = {0}; int ret = 0; - u32 event = 0; - u32 event_helper = 0; + u32 event = 0, event_helper = 0; if (!phys_enc) { pr_err("invalid encoder\n"); return -EINVAL; } - wait_info.wq = &phys_enc->pending_kickoff_wq; - wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt; - wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; - if (!sde_encoder_phys_vid_is_master(phys_enc)) { /* signal done for slave video encoder, unless it is pp-split */ if (!_sde_encoder_phys_is_ppsplit(phys_enc) && notify) { event = SDE_ENCODER_FRAME_EVENT_DONE; goto end; } - return 0; } + wait_info.wq = &phys_enc->pending_kickoff_wq; + wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt; + wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; + /* Wait for kickoff to complete */ ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_VSYNC, &wait_info); @@ -975,15 +975,11 @@ static int _sde_encoder_phys_vid_wait_for_vblank( event_helper = SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE | SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE; - if (notify) { - if (ret == -ETIMEDOUT) { - event = SDE_ENCODER_FRAME_EVENT_ERROR; - if (atomic_add_unless( - &phys_enc->pending_retire_fence_cnt, -1, 0)) - event |= event_helper; - } else if (!ret) { - event = SDE_ENCODER_FRAME_EVENT_DONE; - } + if (notify && (ret == -ETIMEDOUT)) { + event = SDE_ENCODER_FRAME_EVENT_ERROR; + if (atomic_add_unless(&phys_enc->pending_retire_fence_cnt, + -1, 0)) + event |= event_helper; } end: From e7fa7a65a4f80c0ff2c2433242ad378baaac413e Mon Sep 17 00:00:00 2001 From: Ray Zhang Date: Thu, 23 Jul 2020 20:19:59 +0800 Subject: [PATCH 136/192] drm/msm/sde: trigger single frame_done evt for vid encoder Commit 5db4349803d6 ("drm/msm/sde: avoid frame_done event trigger for idle scenario") supports frame_done event merging with release and retire fence for video mode. This works for single dsi display but it causes issue for dual dsi display. Dual dsi display needs two frame_done events in current design. The second dummy frame_done event is generated by physical video mode display. This patch simplifies the frame_done event trigger for video mode by generating single event. It aligns the logic with wb display. Command mode display still waits for two pp_done IRQs and triggers the frame_done interrupt when both events are arrived. Change-Id: I8d5a15d1d478001450b3e86a84f19e031f777d8d Signed-off-by: Dhaval Patel Signed-off-by: Ray Zhang --- drivers/gpu/drm/msm/sde/sde_encoder.c | 13 ++++-- .../gpu/drm/msm/sde/sde_encoder_phys_vid.c | 44 ++++++------------- 2 files changed, 23 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 1cfa67a88d31..e598ce85fc9e 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -3662,7 +3662,7 @@ static void sde_encoder_frame_done_callback( { struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); unsigned int i; - bool trigger = true; + bool trigger = true, is_cmd_mode; enum sde_rm_topology_name topology = SDE_RM_TOPOLOGY_NONE; if (!drm_enc || !sde_enc->cur_master) { @@ -3674,10 +3674,12 @@ static void sde_encoder_frame_done_callback( sde_enc->crtc_frame_event_cb_data.connector = sde_enc->cur_master->connector; + is_cmd_mode = sde_enc->disp_info.capabilities & + MSM_DISPLAY_CAP_CMD_MODE; if (event & (SDE_ENCODER_FRAME_EVENT_DONE | SDE_ENCODER_FRAME_EVENT_ERROR - | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)) { + | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD) && is_cmd_mode) { if (ready_phys->connector) topology = sde_connector_get_topology_name( ready_phys->connector); @@ -3717,9 +3719,14 @@ static void sde_encoder_frame_done_callback( atomic_set(&sde_enc->frame_done_cnt[i], 0); } } else { - if (sde_enc->crtc_frame_event_cb) + if (sde_enc->crtc_frame_event_cb) { + if (!is_cmd_mode) + sde_encoder_resource_control(drm_enc, + SDE_ENC_RC_EVENT_FRAME_DONE); + sde_enc->crtc_frame_event_cb( &sde_enc->crtc_frame_event_cb_data, event); + } } } 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 426870b57164..670c405b6605 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c @@ -594,12 +594,11 @@ static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) pend_ret_fence_cnt = atomic_read(&phys_enc->pending_retire_fence_cnt); /* signal only for master, where there is a pending kickoff */ - if (sde_encoder_phys_vid_is_master(phys_enc)) { - if (atomic_add_unless(&phys_enc->pending_retire_fence_cnt, - -1, 0)) - event |= SDE_ENCODER_FRAME_EVENT_DONE | - SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE | - SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE; + if (sde_encoder_phys_vid_is_master(phys_enc) && + atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0)) { + event = SDE_ENCODER_FRAME_EVENT_DONE | + SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE | + SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE; } not_flushed: @@ -949,21 +948,15 @@ static int _sde_encoder_phys_vid_wait_for_vblank( { struct sde_encoder_wait_info wait_info = {0}; int ret = 0; - u32 event = 0, event_helper = 0; + u32 event = SDE_ENCODER_FRAME_EVENT_ERROR | + SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE | + SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE; if (!phys_enc) { pr_err("invalid encoder\n"); return -EINVAL; } - if (!sde_encoder_phys_vid_is_master(phys_enc)) { - /* signal done for slave video encoder, unless it is pp-split */ - if (!_sde_encoder_phys_is_ppsplit(phys_enc) && notify) { - event = SDE_ENCODER_FRAME_EVENT_DONE; - goto end; - } - } - wait_info.wq = &phys_enc->pending_kickoff_wq; wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt; wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; @@ -972,23 +965,12 @@ static int _sde_encoder_phys_vid_wait_for_vblank( ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_VSYNC, &wait_info); - event_helper = SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE - | SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE; - - if (notify && (ret == -ETIMEDOUT)) { - event = SDE_ENCODER_FRAME_EVENT_ERROR; - if (atomic_add_unless(&phys_enc->pending_retire_fence_cnt, - -1, 0)) - event |= event_helper; - } - -end: - SDE_EVT32(DRMID(phys_enc->parent), event, notify, ret, - ret ? SDE_EVTLOG_FATAL : 0); - if (phys_enc->parent_ops.handle_frame_done && event) + if (notify && (ret == -ETIMEDOUT) && + atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0) && + phys_enc->parent_ops.handle_frame_done) phys_enc->parent_ops.handle_frame_done( - phys_enc->parent, phys_enc, - event); + phys_enc->parent, phys_enc, event); + return ret; } From 71dad47bea5154bda411a61e0a2ba36a07b7eeed Mon Sep 17 00:00:00 2001 From: Sean Tranchetti Date: Wed, 22 Jul 2020 16:22:20 -0600 Subject: [PATCH 137/192] net: qualcomm: rmnet: validate ipv6 extension header lengths When calculating the length of the IPv6 header chain, lengths of the IPv6 extension headers are not checked against the overall packet lengths and thus it's possible to parse past the end of the packet when the packet is malformed. This adds the necessary bounds checking to ensure that parsing stops if the end of the packet is reached to avoid the following: Unable to handle kernel paging request at virtual address pc : rmnet_frag_ipv6_skip_exthdr+0xc0/0x108 [rmnet_core] lr : rmnet_frag_ipv6_skip_exthdr+0x68/0x108 [rmnet_core] Call trace: rmnet_frag_ipv6_skip_exthdr+0xc0/0x108 [rmnet_core] DATARMNET29e8d137c4+0x1a0/0x3e0 [rmnet_offload] rmnet_frag_ingress_handler+0x294/0x404 [rmnet_core] rmnet_rx_handler+0x1b4/0x284 [rmnet_core] __netif_receive_skb_core+0x740/0xd2c __netif_receive_skb+0x44/0x158 Change-Id: Ib2e2ebce733bd4d14a3dfc175133638b15015277 Signed-off-by: Sean Tranchetti --- drivers/net/ethernet/qualcomm/rmnet/rmnet_descriptor.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_descriptor.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_descriptor.c index 3ee89fdd8c54..2e658278fa70 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_descriptor.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_descriptor.c @@ -103,6 +103,7 @@ EXPORT_SYMBOL(rmnet_descriptor_add_frag); int rmnet_frag_ipv6_skip_exthdr(struct rmnet_frag_descriptor *frag_desc, int start, u8 *nexthdrp, __be16 *fragp) { + u32 frag_size = skb_frag_size(&frag_desc->frag); u8 nexthdr = *nexthdrp; *fragp = 0; @@ -114,11 +115,17 @@ int rmnet_frag_ipv6_skip_exthdr(struct rmnet_frag_descriptor *frag_desc, if (nexthdr == NEXTHDR_NONE) return -EINVAL; - hp = rmnet_frag_data_ptr(frag_desc) + start; + if (start >= frag_size) + return -EINVAL; + hp = rmnet_frag_data_ptr(frag_desc) + start; if (nexthdr == NEXTHDR_FRAGMENT) { __be16 *fp; + if (start + offsetof(struct frag_hdr, frag_off) >= + frag_size) + return -EINVAL; + fp = rmnet_frag_data_ptr(frag_desc) + start + offsetof(struct frag_hdr, frag_off); *fragp = *fp; From 0e483ff43b033cd842f09374ea26fc43ab22a04e Mon Sep 17 00:00:00 2001 From: Lakshit Tyagi Date: Fri, 17 Jul 2020 14:03:55 +0530 Subject: [PATCH 138/192] ARM: dts: Update AXI bus votes for EMAC in QCS405 Update ab votes for AXI bus to support bi-directional data rates. Change-Id: If50906e88c00d469da7d976904c61e1d790d9749 Signed-off-by: Lakshit Tyagi --- arch/arm64/boot/dts/qcom/qcs405.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index aa38235ab5e4..eb5fb1f2c0dd 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -1571,9 +1571,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>, From cfeb4030e3229091414abe4d9bc16eaefa756342 Mon Sep 17 00:00:00 2001 From: Ashish Chavan Date: Fri, 17 Jul 2020 14:11:37 +0530 Subject: [PATCH 139/192] power: smb1398: Do not disable FP_FET during IREV condition Allow the charger to recover after a momentary IREV condition by using the configuration-bit to not-disable FP-FET in IREV. Change-Id: I22cad3bbc4bde0a143e3ff6e068e750a2c40e34b Signed-off-by: Ashish Chavan --- drivers/power/supply/qcom/smb1398-charger.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/power/supply/qcom/smb1398-charger.c b/drivers/power/supply/qcom/smb1398-charger.c index 2c1abcdc471c..81be751b6591 100644 --- a/drivers/power/supply/qcom/smb1398-charger.c +++ b/drivers/power/supply/qcom/smb1398-charger.c @@ -99,6 +99,7 @@ #define MISC_CFG0_REG 0x2634 #define DIS_SYNC_DRV_BIT BIT(5) #define SW_EN_SWITCHER_BIT BIT(3) +#define CFG_DIS_FPF_IREV_BIT BIT(1) #define MISC_CFG1_REG 0x2635 #define MISC_CFG1_MASK GENMASK(7, 0) @@ -1947,6 +1948,14 @@ static int smb1398_div2_cp_hw_init(struct smb1398_chip *chip) return rc; } + /* Do not disable FP_FET during IREV conditions */ + rc = smb1398_masked_write(chip, MISC_CFG0_REG, CFG_DIS_FPF_IREV_BIT, 0); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set CFG_DIS_FPF_IREV_BIT, rc=%d\n", + rc); + return rc; + } + /* switcher enable controlled by register */ rc = smb1398_masked_write(chip, MISC_CFG0_REG, SW_EN_SWITCHER_BIT, SW_EN_SWITCHER_BIT); From bd84bb75f5b9741a382418ceff39419c41592f92 Mon Sep 17 00:00:00 2001 From: Ashish Chavan Date: Mon, 20 Jul 2020 12:18:59 +0530 Subject: [PATCH 140/192] power: battery: Fix use of uninitialized variable error Fix use of uninitiallized variable error in function get_adapter_icl_based_ilim. Change-Id: I650594d80fda88aca2de399dfa16483f72f88e77 Signed-off-by: Ashish Chavan --- drivers/power/supply/qcom/battery.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index fe9055ee8ba2..918ea62290ad 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -201,7 +201,8 @@ static int cp_get_parallel_mode(struct pl_data *chip, int mode) static int get_adapter_icl_based_ilim(struct pl_data *chip) { - int main_icl, adapter_icl = -EINVAL, rc = -EINVAL, final_icl = -EINVAL; + int main_icl = -EINVAL, adapter_icl = -EINVAL, final_icl = -EINVAL; + int rc = -EINVAL; union power_supply_propval pval = {0, }; rc = power_supply_get_property(chip->usb_psy, From 1c50dd1630ddc78a85957d9327ad16066c596358 Mon Sep 17 00:00:00 2001 From: Ashish Chavan Date: Fri, 17 Jul 2020 14:11:37 +0530 Subject: [PATCH 141/192] power: smb1398: Update win-uv threshold to 10mV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When VIN/2 – VOUT < the threshold with debounce time, WIN_UV protection kicks in. Update this threshold to 10mV. Change-Id: I015528b9fb1e4db86c4e1af186aa0f6a912967f2 Signed-off-by: Ashish Chavan --- drivers/power/supply/qcom/smb1398-charger.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/power/supply/qcom/smb1398-charger.c b/drivers/power/supply/qcom/smb1398-charger.c index 81be751b6591..d52d1410d7eb 100644 --- a/drivers/power/supply/qcom/smb1398-charger.c +++ b/drivers/power/supply/qcom/smb1398-charger.c @@ -1908,6 +1908,14 @@ static int smb1398_div2_cp_hw_init(struct smb1398_chip *chip) return rc; } + /* Configure window (Vin/2 - Vout) UV level to 10mV */ + rc = smb1398_masked_write(chip, NOLOCK_SPARE_REG, + DIV2_WIN_UV_SEL_BIT, 0); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set WIN_UV_10_MV rc=%d\n", rc); + return rc; + } + /* Configure master TEMP pin to output Vtemp signal by default */ rc = smb1398_masked_write(chip, SSUPLY_TEMP_CTRL_REG, SEL_OUT_TEMP_MAX_MASK, SEL_OUT_VTEMP); @@ -2241,6 +2249,14 @@ static int smb1398_div2_cp_slave_probe(struct smb1398_chip *chip) return rc; } + /* Configure window (Vin/2 - Vout) UV level to 10mV */ + rc = smb1398_masked_write(chip, NOLOCK_SPARE_REG, + DIV2_WIN_UV_SEL_BIT, 0); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set WIN_UV_10_MV rc=%d\n", rc); + return rc; + } + /* * Disable slave WIN_UV detection, otherwise slave might not be * enabled due to WIN_UV until master drawing very high current. From 6d12f0bf941085daadab9f4ab38a5f768ee6c0bc Mon Sep 17 00:00:00 2001 From: Sneh Shah Date: Fri, 19 Jun 2020 15:20:05 +0530 Subject: [PATCH 142/192] arm: dts: msm: Add dt entry to enable geometry mapping in EMAC Add dt entry to to enable geometry mapping for fastmap to save memory. Change-Id: I201734811d8161810c82b3b15fcac75d16ae1093 Signed-off-by: Sneh Shah --- arch/arm64/boot/dts/qcom/sdxprairie.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi index fba2298fdd93..e63d05e9698e 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi @@ -1519,6 +1519,7 @@ compatible = "qcom,emac-smmu-embedded"; iommus = <&apps_smmu 0x1c0 0xf>; qcom,iova-mapping = <0x80000000 0x40000000>; + qcom,smmu-geometry; }; }; From be70eb70732126fe33e61731e3c52257031d5fd4 Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Tue, 28 Jul 2020 13:43:33 +0530 Subject: [PATCH 143/192] msm: ep_pcie: Prevent apps suspend in active state PCIE global interrupt and MHI interrupts are not wakeup-capable. Acquire wakelock after PERST de-assertion to avoid delayed processing of these interrupts if apps enters suspend before they fire. Wakelock is released when entering D3 cold. This change also involves a check for PERST de-assertion to bail out before we shut down the link. Change-Id: I53e9c58584f92b91bb17e0a20d3666339bd878b4 Signed-off-by: Subramanian Ananthanarayanan --- drivers/platform/msm/ep_pcie/ep_pcie_com.h | 3 +- drivers/platform/msm/ep_pcie/ep_pcie_core.c | 70 ++++++++++++++++++--- 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h index d4552f5dd4f4..0006f4ba2567 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h +++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h @@ -406,7 +406,6 @@ struct ep_pcie_dev_t { bool config_mmio_init; bool enumerated; enum ep_pcie_link_status link_status; - bool perst_deast; bool power_on; bool suspending; bool l23_ready; @@ -414,6 +413,8 @@ struct ep_pcie_dev_t { struct ep_pcie_msi_config msi_cfg; bool no_notify; bool client_ready; + atomic_t ep_pcie_dev_wake; + atomic_t perst_deast; struct ep_pcie_register_event *event_reg; struct work_struct handle_perst_work; diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c index 09b1ade55292..b926976dc2e0 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c @@ -1804,7 +1804,7 @@ int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt) ret = EP_PCIE_ERROR; goto link_fail; } else { - dev->perst_deast = true; + atomic_set(&dev->perst_deast, 1); if (opt & EP_PCIE_OPT_AST_WAKE) { /* deassert PCIe WAKE# */ EP_PCIE_DBG(dev, @@ -1967,11 +1967,19 @@ int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt) int ep_pcie_core_disable_endpoint(void) { int rc = 0; + u32 val = 0; + unsigned long irqsave_flags; struct ep_pcie_dev_t *dev = &ep_pcie_dev; EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev); mutex_lock(&dev->setup_mtx); + if (atomic_read(&dev->perst_deast)) { + EP_PCIE_DBG(dev, + "PCIe V%d: PERST is de-asserted, exiting disable\n", + dev->rev); + goto out; + } if (!dev->power_on) { EP_PCIE_DBG(dev, @@ -1988,9 +1996,25 @@ int ep_pcie_core_disable_endpoint(void) dev->rev); } + val = readl_relaxed(dev->elbi + PCIE20_ELBI_SYS_STTS); + EP_PCIE_DBG(dev, "PCIe V%d: LTSSM_STATE during disable:0x%x\n", + dev->rev, (val >> 0xC) & 0x3f); ep_pcie_pipe_clk_deinit(dev); ep_pcie_clk_deinit(dev); ep_pcie_vreg_deinit(dev); + + spin_lock_irqsave(&dev->isr_lock, irqsave_flags); + if (atomic_read(&dev->ep_pcie_dev_wake) && + !atomic_read(&dev->perst_deast)) { + EP_PCIE_DBG(dev, "PCIe V%d: Released wakelock\n", dev->rev); + atomic_set(&dev->ep_pcie_dev_wake, 0); + pm_relax(&dev->pdev->dev); + } else { + EP_PCIE_DBG(dev, "PCIe V%d: Bail, Perst-assert:%d wake:%d\n", + dev->rev, atomic_read(&dev->perst_deast), + atomic_read(&dev->ep_pcie_dev_wake)); + } + spin_unlock_irqrestore(&dev->isr_lock, irqsave_flags); out: mutex_unlock(&dev->setup_mtx); return rc; @@ -2247,12 +2271,25 @@ static void handle_d3cold_func(struct work_struct *work) { struct ep_pcie_dev_t *dev = container_of(work, struct ep_pcie_dev_t, handle_d3cold_work); + unsigned long irqsave_flags; EP_PCIE_DBG(dev, "PCIe V%d: shutdown PCIe link due to PERST assertion before BME is set\n", dev->rev); ep_pcie_core_disable_endpoint(); dev->no_notify = false; + spin_lock_irqsave(&dev->isr_lock, irqsave_flags); + if (atomic_read(&dev->ep_pcie_dev_wake) && + !atomic_read(&dev->perst_deast)) { + atomic_set(&dev->ep_pcie_dev_wake, 0); + pm_relax(&dev->pdev->dev); + EP_PCIE_DBG(dev, "PCIe V%d: Released wakelock\n", dev->rev); + } else { + EP_PCIE_DBG(dev, "PCIe V%d: Bail, Perst-assert:%d wake:%d\n", + dev->rev, atomic_read(&dev->perst_deast), + atomic_read(&dev->ep_pcie_dev_wake)); + } + spin_unlock_irqrestore(&dev->isr_lock, irqsave_flags); } static void handle_bme_func(struct work_struct *work) @@ -2290,14 +2327,24 @@ static irqreturn_t ep_pcie_handle_perst_irq(int irq, void *data) } if (perst) { - dev->perst_deast = true; + atomic_set(&dev->perst_deast, 1); dev->perst_deast_counter++; + /* + * Hold a wakelock to avoid missing BME and other + * interrupts if apps goes into suspend before BME is set. + */ + if (!atomic_read(&dev->ep_pcie_dev_wake)) { + pm_stay_awake(&dev->pdev->dev); + atomic_set(&dev->ep_pcie_dev_wake, 1); + EP_PCIE_DBG(dev, "PCIe V%d: Acquired wakelock\n", + dev->rev); + } EP_PCIE_DBG(dev, "PCIe V%d: No. %ld PERST deassertion\n", dev->rev, dev->perst_deast_counter); ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_RST_DEAST); } else { - dev->perst_deast = false; + atomic_set(&dev->perst_deast, 0); dev->perst_ast_counter++; EP_PCIE_DBG(dev, "PCIe V%d: No. %ld PERST assertion\n", @@ -2548,13 +2595,14 @@ int32_t ep_pcie_irq_init(struct ep_pcie_dev_t *dev) * based on the next expected level of the gpio */ if (gpio_get_value(dev->gpio[EP_PCIE_GPIO_PERST].num) == 1) - dev->perst_deast = true; + atomic_set(&dev->perst_deast, 1); /* register handler for PERST interrupt */ perst_irq = gpio_to_irq(dev->gpio[EP_PCIE_GPIO_PERST].num); ret = devm_request_irq(pdev, perst_irq, ep_pcie_handle_perst_irq, - (dev->perst_deast ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH), + (atomic_read(&dev->perst_deast) ? + IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH), "ep_pcie_perst", dev); if (ret) { EP_PCIE_ERR(dev, @@ -2948,7 +2996,7 @@ static int ep_pcie_core_wakeup_host(enum ep_pcie_event event) if (event == EP_PCIE_EVENT_PM_D3_HOT) ep_pcie_core_issue_inband_pme(); - if (dev->perst_deast && !dev->l23_ready) { + if (atomic_read(&dev->perst_deast) && !dev->l23_ready) { EP_PCIE_ERR(dev, "PCIe V%d: request to assert WAKE# when PERST is de-asserted and D3hot is not received\n", dev->rev); @@ -2959,7 +3007,7 @@ static int ep_pcie_core_wakeup_host(enum ep_pcie_event event) EP_PCIE_DBG(dev, "PCIe V%d: No. %ld to assert PCIe WAKE#; perst is %s de-asserted; D3hot is %s received\n", dev->rev, dev->wake_counter, - dev->perst_deast ? "" : "not", + atomic_read(&dev->perst_deast) ? "" : "not", dev->l23_ready ? "" : "not"); /* * Assert WAKE# GPIO until link is back to L0. @@ -3214,6 +3262,14 @@ static int ep_pcie_probe(struct platform_device *pdev) goto irq_failure; } + /* + * Wakelock is needed to avoid missing BME and other + * interrupts if apps goes into suspend before host + * sets them. + */ + device_init_wakeup(&ep_pcie_dev.pdev->dev, true); + atomic_set(&ep_pcie_dev.ep_pcie_dev_wake, 0); + if (ep_pcie_dev.perst_enum && !gpio_get_value(ep_pcie_dev.gpio[EP_PCIE_GPIO_PERST].num)) { EP_PCIE_DBG2(&ep_pcie_dev, From 5c3a37c61e0612bf173e7b66c8d8b4e3ca18b3b9 Mon Sep 17 00:00:00 2001 From: Ashish Chavan Date: Wed, 29 Jul 2020 09:32:06 +0530 Subject: [PATCH 144/192] power: smb1390: Fix taper condition for VPH configuration For VPH configuration fcc and fcc_main are same. Reducing fcc_main from fcc can cause the charger disbale condition to always be false. Fix this by changing the main_ilim_ua type to int and add a check for subtracting the main_fcc_ua from fcc_ua only for VBAT configuration. Change-Id: I63a527a6de981a42d0c879151af1346191dbb4f6 Signed-off-by: Ashish Chavan --- .../power/supply/qcom/smb1390-charger-psy.c | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/qcom/smb1390-charger-psy.c b/drivers/power/supply/qcom/smb1390-charger-psy.c index 65a8b4a45861..bf06af7ba33a 100644 --- a/drivers/power/supply/qcom/smb1390-charger-psy.c +++ b/drivers/power/supply/qcom/smb1390-charger-psy.c @@ -211,10 +211,10 @@ struct smb1390 { int cp_isns_slave; int cp_ilim; int die_temp; + int min_ilim_ua; bool suspended; bool disabled; u32 debug_mask; - u32 min_ilim_ua; u32 max_temp_alarm_degc; u32 max_cutoff_soc; u32 pl_output_mode; @@ -1240,7 +1240,7 @@ static void smb1390_taper_work(struct work_struct *work) { struct smb1390 *chip = container_of(work, struct smb1390, taper_work); union power_supply_propval pval = {0, }; - int rc, fcc_uA, delta_fcc_uA, main_fcc_ua = 0; + int rc, fcc_uA, delta_fcc_uA, main_fcc_ua = 0, fcc_cp_ua; if (!is_psy_voter_available(chip)) goto out; @@ -1290,7 +1290,21 @@ static void smb1390_taper_work(struct work_struct *work) goto out; } - if ((fcc_uA - main_fcc_ua) < (chip->min_ilim_ua * 2)) { + /* + * fcc and fcc_main are the same for VPH config, hence + * reduce fcc_main from fcc only in VBAT (output config) + * where fcc_main is a portion of full-fcc. + */ + fcc_cp_ua = fcc_uA; + if (chip->pl_output_mode == POWER_SUPPLY_PL_OUTPUT_VBAT) + fcc_cp_ua = fcc_uA - main_fcc_ua; + + smb1390_dbg(chip, PR_INFO, + "Taper: fcc_ua=%d fcc_cp_ua=%d fcc_main_ua=%d min_ilim_ua(x2) = %u\n", + fcc_uA, fcc_cp_ua, main_fcc_ua, + (chip->min_ilim_ua*2)); + + if (fcc_cp_ua < (chip->min_ilim_ua * 2)) { vote(chip->disable_votable, TAPER_END_VOTER, true, 0); /* From c78e0de21d60ee6ae2e240d489aa72583b2216f1 Mon Sep 17 00:00:00 2001 From: Madhukar Sandi Date: Wed, 29 Jul 2020 20:42:49 +0530 Subject: [PATCH 145/192] ARM: dts: msm: Enable regulator for geni ir Enable ldo12 regulator for geni ir to get interrupts in suspend mode. Change-Id: I954ad8fb2511a399076e45f2aabe130dd2043a01 Signed-off-by: Madhukar Sandi --- arch/arm64/boot/dts/qcom/qcs405-geni-ir-overlay.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs405-geni-ir-overlay.dtsi b/arch/arm64/boot/dts/qcom/qcs405-geni-ir-overlay.dtsi index 8b202e53646a..0e7efd8cdf11 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-geni-ir-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-geni-ir-overlay.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -26,6 +26,7 @@ <&clock_gcc GCC_GENI_IR_S_CLK>; clock-names = "iface_clk", "serial_clk"; + vdda33-supply = <&pms405_l12>; qcom,geni-ir-wakeup-gpio = <&tlmm 77 IRQ_TYPE_LEVEL_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&ir_in_default>; From 6cba114723bbd49e07f360fc17ffe4442d94b16e Mon Sep 17 00:00:00 2001 From: Naveen Yadav Date: Mon, 13 Jul 2020 17:09:56 +0530 Subject: [PATCH 146/192] clk: qcom: npucc: Update NPU Q6 frequency for ATOLL As per the hardware recommendation update the q6 PLL to use double the frequency and use the RCG pre divider. Change-Id: Ic9ebafa881046d8b0155674fe97ae63a5598e466 Signed-off-by: Naveen Yadav --- drivers/clk/qcom/npucc-atoll.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/clk/qcom/npucc-atoll.c b/drivers/clk/qcom/npucc-atoll.c index b2be104de7f6..a58d96d0c017 100644 --- a/drivers/clk/qcom/npucc-atoll.c +++ b/drivers/clk/qcom/npucc-atoll.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -357,13 +357,13 @@ static struct clk_rcg2 npu_cc_core_clk_src = { }; static const struct freq_tbl ftbl_npu_dsp_core_clk_src[] = { - F(250000000, P_NPU_Q6SS_PLL_OUT_MAIN, 1, 0, 0), - F(300000000, P_NPU_Q6SS_PLL_OUT_MAIN, 1, 0, 0), - F(400000000, P_NPU_Q6SS_PLL_OUT_MAIN, 1, 0, 0), - F(500000000, P_NPU_Q6SS_PLL_OUT_MAIN, 1, 0, 0), - F(600000000, P_NPU_Q6SS_PLL_OUT_MAIN, 1, 0, 0), - F(660000000, P_NPU_Q6SS_PLL_OUT_MAIN, 1, 0, 0), - F(800000000, P_NPU_Q6SS_PLL_OUT_MAIN, 1, 0, 0), + F(250000000, P_NPU_Q6SS_PLL_OUT_MAIN, 2, 0, 0), + F(300000000, P_NPU_Q6SS_PLL_OUT_MAIN, 2, 0, 0), + F(400000000, P_NPU_Q6SS_PLL_OUT_MAIN, 2, 0, 0), + F(500000000, P_NPU_Q6SS_PLL_OUT_MAIN, 2, 0, 0), + F(600000000, P_NPU_Q6SS_PLL_OUT_MAIN, 2, 0, 0), + F(660000000, P_NPU_Q6SS_PLL_OUT_MAIN, 2, 0, 0), + F(800000000, P_NPU_Q6SS_PLL_OUT_MAIN, 2, 0, 0), { } }; From fdb23d75e4b2f73eed5c7dd5ba3bb7b8c13fd75c Mon Sep 17 00:00:00 2001 From: Madhukar Sandi Date: Sat, 1 Aug 2020 20:32:34 +0530 Subject: [PATCH 147/192] media: rc: Enable regulator and rxfifo in suspend Enable regulator and rxfifo in suspend state to get get geni ir interrputs for geni ir to get interrupt in suspend state and keep enable rxfifo as well in suspend mode. Change-Id: I6433d94fb59967d04385274a20a744dd9305f8d8 Signed-off-by: Madhukar Sandi --- drivers/media/rc/msm-geni-ir.c | 124 ++++----------------------------- 1 file changed, 15 insertions(+), 109 deletions(-) diff --git a/drivers/media/rc/msm-geni-ir.c b/drivers/media/rc/msm-geni-ir.c index 8ee451f06f1f..7fae4e04bd30 100644 --- a/drivers/media/rc/msm-geni-ir.c +++ b/drivers/media/rc/msm-geni-ir.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, 2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2014, 2018, 2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -360,7 +361,7 @@ struct msm_geni_ir { void __iomem *base; unsigned int gpio_rx; - + struct regulator *vdda33; struct clk *ahb_clk; struct clk *serial_clk; struct reset_control *reset_core; @@ -494,28 +495,6 @@ static void msm_geni_ir_load_firmware(struct msm_geni_ir *ir) } EXPORT_SYMBOL(msm_geni_ir_load_firmware); -/* sets the RX filter table with wakeup commands */ -static void msm_geni_ir_set_rx_filter(struct msm_geni_ir *ir) -{ - u32 i, irq_enable = 0; - - /* set the IRQ enable bit for non-zero RX wakeup commands */ - for (i = 0; i < ir->num_wakeup_codes; i++) { - irq_enable |= ((ir->wakeup_codes[i]) ? (1 << i) : 0); - - writel_relaxed(ir->wakeup_codes[i], - ir->base + GENI_IR_RX_FILTER_TABLE(i)); - } - - /* set the filter mask */ - writel_relaxed(ir->wakeup_mask, ir->base + IR_RX_FILTER_VAL_MASK); - - /* set the IRQ enable bits */ - writel_relaxed(irq_enable, ir->base + GENI_IR_IRQ_ENABLE); - /*write memory barrier*/ - wmb(); -} - /* stop GENI IR */ static void msm_geni_ir_stop(struct msm_geni_ir *ir) { @@ -543,76 +522,6 @@ static void msm_geni_ir_stop(struct msm_geni_ir *ir) readl_relaxed(ir->base + IR_GENI_RX_FIFO(i)); } -/* configures geni IR to low power mode */ -static void msm_geni_ir_low_power_mode(struct msm_geni_ir *ir) -{ - u32 clk_cfg; - - /* set the RX filter table for wakeup */ - msm_geni_ir_set_rx_filter(ir); - - /* disable interrupts */ - writel_relaxed(0, ir->base + IR_GENI_IRQ_ENABLE); - synchronize_irq(ir->irq); - - /* stop GENI IR */ - msm_geni_ir_stop(ir); - - /* disable TX path, enable RX path */ - clk_cfg = RX_CLK_DIV_VALUE(RX_CLK_DIV_LP) | RX_SER_CLK_EN; - writel_relaxed(clk_cfg, ir->base + IR_GENI_SER_CLK_CFG); - - /* switch clock mux output from hclk to sclk */ - writel_relaxed(0x1, ir->base + GENI_IR_CLK_MUX); - - /* read back clk_mux register to ensure output clk is active */ - readl_relaxed(ir->base + GENI_IR_CLK_MUX); - - /* select low power mode */ - writel_relaxed(GENI_IR_LOW_POWER_MODE, ir->base + GENI_IR_AHB_MUX_SEL); - - /* enable the RX filter */ - writel_relaxed(0x1, ir->base + GENI_IR_RX_FILTER_EN); - /*write memory barrier*/ - wmb(); -} - -/* configures geni IR to normal mode */ -static void msm_geni_ir_normal_mode(struct msm_geni_ir *ir) -{ - u32 clk_cfg; - - /* ensure RX filter is disabled */ - writel_relaxed(0x0, ir->base + GENI_IR_RX_FILTER_EN); - - /* switch clock mux output from sclk to hclk */ - writel_relaxed(0x0, ir->base + GENI_IR_CLK_MUX); - - /* read back clk_mux register to ensure output clk is active */ - readl_relaxed(ir->base + GENI_IR_CLK_MUX); - - /* select normal mode */ - writel_relaxed(GENI_IR_NORMAL_MODE, ir->base + GENI_IR_AHB_MUX_SEL); - - /* stop GENI IR */ - msm_geni_ir_stop(ir); - - /* configure serial clock */ - clk_cfg = RX_CLK_DIV_VALUE(RX_CLK_DIV) | RX_SER_CLK_EN; - writel_relaxed(clk_cfg, ir->base + IR_GENI_SER_CLK_CFG); - - /* set rx polarization to active low */ - writel_relaxed(RX_POL_LOW, ir->base + IR_GENI_GP_OUTPUT_REG); - - /* enable interrupts */ - writel_relaxed(GENI_IR_DEF_IRQ_EN, ir->base + IR_GENI_IRQ_ENABLE); - - /* enable RX */ - writel_relaxed(0, ir->base + IR_GENI_S_CMD0); - /*write memory barrier*/ - wmb(); -} - /* sets the core for the specified protocol */ static int msm_geni_ir_change_protocol(struct rc_dev *dev, u64 *rc_type) { @@ -883,6 +792,13 @@ static int msm_geni_ir_get_res(struct platform_device *pdev, return -ENOMEM; } pr_debug("ir->base: 0x%lx\n", (unsigned long int)ir->base); + + ir->vdda33 = devm_regulator_get(&pdev->dev, "vdda33"); + if (IS_ERR(ir->vdda33)) { + pr_err("unable to get vdda33 supply\n"); + return rc; + } + ir->ahb_clk = clk_get(&pdev->dev, "iface_clk"); ir->serial_clk = clk_get(&pdev->dev, "serial_clk"); if (IS_ERR(ir->ahb_clk)) { @@ -974,6 +890,11 @@ int msm_geni_ir_probe(struct platform_device *pdev) goto rc_register_err; } + rc = regulator_enable(ir->vdda33); + if (rc) { + pr_err("Unable to enable vdda33:%d\n", rc); + return rc; + } #ifdef CONFIG_IR_MSM_GENI_TX ir->misc.minor = MISC_DYNAMIC_MINOR; @@ -1032,11 +953,6 @@ static int msm_geni_ir_suspend(struct device *dev) { struct msm_geni_ir *ir = platform_get_drvdata(to_platform_device(dev)); - if (ir->image_loaded != NULL) { - /* configure low power mode */ - msm_geni_ir_low_power_mode(ir); - clk_disable_unprepare(ir->ahb_clk); - } enable_irq_wake(ir->wakeup_irq); return 0; @@ -1046,27 +962,17 @@ static int msm_geni_ir_resume(struct device *dev) { struct msm_geni_ir *ir = platform_get_drvdata(to_platform_device(dev)); u32 status; - int rc; disable_irq_wake(ir->wakeup_irq); if (ir->image_loaded == NULL) return 0; - rc = clk_prepare_enable(ir->ahb_clk); - if (rc) { - pr_err("ahb clk enable failed %d\n", rc); - return rc; - } - /* clear wakeup irq */ status = readl_relaxed(ir->base + GENI_IR_IRQ_STATUS); writel_relaxed(status, ir->base + GENI_IR_IRQ_CLEAR); /*write memory barrier*/ wmb(); - /* configure normal mode */ - msm_geni_ir_normal_mode(ir); - return 0; } #endif /* CONFIG_PM_SLEEP */ From 1e322e1d6105d9f5fb697203a2d1f2486f2c6084 Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Thu, 16 Jul 2020 00:49:09 +0530 Subject: [PATCH 148/192] msm: kgsl: Mark the scratch buffer as privileged Mark the scratch buffer as privileged so that it can only be accessed by GPU through the ringbuffer. To accomplish this, we need to: 1. Move the preemption data out of the scratch buffer. 2. Disable the shadow rptr feature. 3. Trigger RPTR update from GPU using a WHERE_AM_I packet. 4. Add support for the new ucode. Change-Id: I9b388f55f53b69028b9bbb2306cb43fd1297c52f Signed-off-by: Akhil P Oommen Signed-off-by: Harshitha Sai Neelati --- drivers/gpu/msm/adreno.c | 13 ++++++++ drivers/gpu/msm/adreno.h | 9 +++--- drivers/gpu/msm/adreno_a5xx.c | 13 +++++--- drivers/gpu/msm/adreno_a5xx.h | 4 +-- drivers/gpu/msm/adreno_a5xx_preempt.c | 8 ++--- drivers/gpu/msm/adreno_a6xx.c | 6 ++-- drivers/gpu/msm/adreno_a6xx.h | 4 +-- drivers/gpu/msm/adreno_a6xx_preempt.c | 33 +++++++++---------- drivers/gpu/msm/adreno_ioctl.c | 4 +-- drivers/gpu/msm/adreno_pm4types.h | 4 ++- drivers/gpu/msm/adreno_ringbuffer.c | 46 +++++++++++++++++++++++++-- drivers/gpu/msm/adreno_ringbuffer.h | 5 ++- drivers/gpu/msm/kgsl.h | 11 +------ 13 files changed, 107 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 2b1393152f19..1209b0c6cd1f 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -4143,6 +4143,19 @@ static int adreno_resume_device(struct kgsl_device *device, return 0; } +u32 adreno_get_ucode_version(const u32 *data) +{ + u32 version; + + version = data[1]; + + if ((version & 0xf) != 0xa) + return version; + + version &= ~0xfff; + return version | ((data[3] & 0xfff000) >> 12); +} + static const struct kgsl_functable adreno_functable = { /* Mandatory functions */ .regread = adreno_regread, diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 69f7235decbf..d7cf1e9d8054 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -288,8 +288,8 @@ enum adreno_preempt_states { /** * struct adreno_preemption * @state: The current state of preemption - * @counters: Memory descriptor for the memory where the GPU writes the - * preemption counters on switch + * @scratch: Memory descriptor for the memory where the GPU writes the + * current ctxt record address and preemption counters on switch * @timer: A timer to make sure preemption doesn't stall * @work: A work struct for the preemption worker (for 5XX) * @token_submit: Indicates if a preempt token has been submitted in @@ -301,7 +301,7 @@ enum adreno_preempt_states { */ struct adreno_preemption { atomic_t state; - struct kgsl_memdesc counters; + struct kgsl_memdesc scratch; struct timer_list timer; struct work_struct work; bool token_submit; @@ -1210,6 +1210,7 @@ void adreno_cx_misc_regwrite(struct adreno_device *adreno_dev, void adreno_cx_misc_regrmw(struct adreno_device *adreno_dev, unsigned int offsetwords, unsigned int mask, unsigned int bits); +u32 adreno_get_ucode_version(const u32 *data); #define ADRENO_TARGET(_name, _id) \ diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 671d23691dfa..7ee260585081 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -2151,12 +2151,15 @@ static int a5xx_post_start(struct adreno_device *adreno_dev) *cmds++ = 0xF; } - if (adreno_is_preemption_enabled(adreno_dev)) + if (adreno_is_preemption_enabled(adreno_dev)) { cmds += _preemption_init(adreno_dev, rb, cmds, NULL); + rb->_wptr = rb->_wptr - (42 - (cmds - start)); + ret = adreno_ringbuffer_submit_spin_nosync(rb, NULL, 2000); + } else { + rb->_wptr = rb->_wptr - (42 - (cmds - start)); + ret = adreno_ringbuffer_submit_spin(rb, NULL, 2000); + } - rb->_wptr = rb->_wptr - (42 - (cmds - start)); - - ret = adreno_ringbuffer_submit_spin(rb, NULL, 2000); if (ret) adreno_spin_idle_debug(adreno_dev, "hw initialization failed to idle\n"); @@ -2493,7 +2496,7 @@ static int _load_firmware(struct kgsl_device *device, const char *fwfile, memcpy(firmware->memdesc.hostptr, &fw->data[4], fw->size - 4); firmware->size = (fw->size - 4) / sizeof(uint32_t); - firmware->version = *(unsigned int *)&fw->data[4]; + firmware->version = adreno_get_ucode_version((u32 *)fw->data); done: release_firmware(fw); diff --git a/drivers/gpu/msm/adreno_a5xx.h b/drivers/gpu/msm/adreno_a5xx.h index 08f56d6701f2..71e9e69895f0 100644 --- a/drivers/gpu/msm/adreno_a5xx.h +++ b/drivers/gpu/msm/adreno_a5xx.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017,2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017,2019-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -112,7 +112,7 @@ void a5xx_crashdump_init(struct adreno_device *adreno_dev); void a5xx_hwcg_set(struct adreno_device *adreno_dev, bool on); -#define A5XX_CP_RB_CNTL_DEFAULT (((ilog2(4) << 8) & 0x1F00) | \ +#define A5XX_CP_RB_CNTL_DEFAULT ((1 << 27) | ((ilog2(4) << 8) & 0x1F00) | \ (ilog2(KGSL_RB_DWORDS >> 1) & 0x3F)) /* GPMU interrupt multiplexor */ #define FW_INTR_INFO (0) diff --git a/drivers/gpu/msm/adreno_a5xx_preempt.c b/drivers/gpu/msm/adreno_a5xx_preempt.c index cb7a65f92135..39283db8f100 100644 --- a/drivers/gpu/msm/adreno_a5xx_preempt.c +++ b/drivers/gpu/msm/adreno_a5xx_preempt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017,2019 The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017,2019-2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -575,7 +575,7 @@ static void _preemption_close(struct adreno_device *adreno_dev) unsigned int i; del_timer(&preempt->timer); - kgsl_free_global(device, &preempt->counters); + kgsl_free_global(device, &preempt->scratch); a5xx_preemption_iommu_close(adreno_dev); FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { @@ -611,14 +611,14 @@ int a5xx_preemption_init(struct adreno_device *adreno_dev) (unsigned long) adreno_dev); /* Allocate mem for storing preemption counters */ - ret = kgsl_allocate_global(device, &preempt->counters, + ret = kgsl_allocate_global(device, &preempt->scratch, adreno_dev->num_ringbuffers * A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE, 0, 0, "preemption_counters"); if (ret) goto err; - addr = preempt->counters.gpuaddr; + addr = preempt->scratch.gpuaddr; /* Allocate mem for storing preemption switch record */ FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index c22e8368675c..1c84d0706060 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -1,4 +1,4 @@ -/* Copyright (c)2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c)2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1204,7 +1204,7 @@ static int a6xx_post_start(struct adreno_device *adreno_dev) rb->_wptr = rb->_wptr - (42 - (cmds - start)); - ret = adreno_ringbuffer_submit_spin(rb, NULL, 2000); + ret = adreno_ringbuffer_submit_spin_nosync(rb, NULL, 2000); if (ret) adreno_spin_idle_debug(adreno_dev, "hw preemption initialization failed to idle\n"); @@ -1350,7 +1350,7 @@ static int _load_firmware(struct kgsl_device *device, const char *fwfile, if (!ret) { memcpy(firmware->memdesc.hostptr, &fw->data[4], fw->size - 4); firmware->size = (fw->size - 4) / sizeof(uint32_t); - firmware->version = *(unsigned int *)&fw->data[4]; + firmware->version = adreno_get_ucode_version((u32 *)fw->data); } release_firmware(fw); diff --git a/drivers/gpu/msm/adreno_a6xx.h b/drivers/gpu/msm/adreno_a6xx.h index bc205da4d9f8..890688cedb26 100644 --- a/drivers/gpu/msm/adreno_a6xx.h +++ b/drivers/gpu/msm/adreno_a6xx.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -103,7 +103,7 @@ struct cpu_gpu_lock { /* Size of the performance counter save/restore block (in bytes) */ #define A6XX_CP_PERFCOUNTER_SAVE_RESTORE_SIZE (4 * 1024) -#define A6XX_CP_RB_CNTL_DEFAULT (((ilog2(4) << 8) & 0x1F00) | \ +#define A6XX_CP_RB_CNTL_DEFAULT ((1 << 27) | ((ilog2(4) << 8) & 0x1F00) | \ (ilog2(KGSL_RB_DWORDS >> 1) & 0x3F)) /* diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c index 57e12f58edf9..afc977acf386 100644 --- a/drivers/gpu/msm/adreno_a6xx_preempt.c +++ b/drivers/gpu/msm/adreno_a6xx_preempt.c @@ -304,8 +304,8 @@ void a6xx_preemption_trigger(struct adreno_device *adreno_dev) kgsl_sharedmem_writel(device, &iommu->smmu_info, PREEMPT_SMMU_RECORD(context_idr), contextidr); - kgsl_sharedmem_readq(&device->scratch, &gpuaddr, - SCRATCH_PREEMPTION_CTXT_RESTORE_ADDR_OFFSET(next->id)); + kgsl_sharedmem_readq(&preempt->scratch, &gpuaddr, + next->id * sizeof(u64)); /* * Set a keepalive bit before the first preemption register write. @@ -525,12 +525,10 @@ unsigned int a6xx_preemption_pre_ibsubmit( rb->perfcounter_save_restore_desc.gpuaddr); if (context) { - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_context *drawctxt = ADRENO_CONTEXT(context); struct adreno_ringbuffer *rb = drawctxt->rb; - uint64_t dest = - SCRATCH_PREEMPTION_CTXT_RESTORE_GPU_ADDR(device, - rb->id); + uint64_t dest = adreno_dev->preempt.scratch.gpuaddr + + sizeof(u64) * rb->id; *cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 2); cmds += cp_gpuaddr(adreno_dev, cmds, dest); @@ -548,9 +546,8 @@ unsigned int a6xx_preemption_post_ibsubmit(struct adreno_device *adreno_dev, struct adreno_ringbuffer *rb = adreno_dev->cur_rb; if (rb) { - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - uint64_t dest = SCRATCH_PREEMPTION_CTXT_RESTORE_GPU_ADDR(device, - rb->id); + uint64_t dest = adreno_dev->preempt.scratch.gpuaddr + + sizeof(u64) * rb->id; *cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 2); cmds += cp_gpuaddr(adreno_dev, cmds, dest); @@ -702,7 +699,7 @@ static void _preemption_close(struct adreno_device *adreno_dev) unsigned int i; del_timer(&preempt->timer); - kgsl_free_global(device, &preempt->counters); + kgsl_free_global(device, &preempt->scratch); a6xx_preemption_iommu_close(adreno_dev); FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { @@ -741,15 +738,19 @@ int a6xx_preemption_init(struct adreno_device *adreno_dev) setup_timer(&preempt->timer, _a6xx_preemption_timer, (unsigned long) adreno_dev); - /* Allocate mem for storing preemption counters */ - ret = kgsl_allocate_global(device, &preempt->counters, - adreno_dev->num_ringbuffers * - A6XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE, 0, 0, - "preemption_counters"); + /* + * Allocate a scratch buffer to keep the below table: + * Offset: What + * 0x0: Context Record address + * 0x10: Preemption Counters + */ + ret = kgsl_allocate_global(device, &preempt->scratch, PAGE_SIZE, 0, 0, + "preemption_scratch"); if (ret) goto err; - addr = preempt->counters.gpuaddr; + addr = preempt->scratch.gpuaddr + + KGSL_PRIORITY_MAX_RB_LEVELS * sizeof(u64); /* Allocate mem for storing preemption switch record */ FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { diff --git a/drivers/gpu/msm/adreno_ioctl.c b/drivers/gpu/msm/adreno_ioctl.c index 82629c6fcf23..d18aa19ad563 100644 --- a/drivers/gpu/msm/adreno_ioctl.c +++ b/drivers/gpu/msm/adreno_ioctl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2018,2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -168,7 +168,7 @@ static long adreno_ioctl_preemption_counters_query( levels_to_copy = gpudev->num_prio_levels; if (copy_to_user((void __user *) (uintptr_t) read->counters, - adreno_dev->preempt.counters.hostptr, + adreno_dev->preempt.scratch.hostptr, levels_to_copy * size_level)) return -EFAULT; diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h index 2a330b4474aa..543496399044 100644 --- a/drivers/gpu/msm/adreno_pm4types.h +++ b/drivers/gpu/msm/adreno_pm4types.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2017,2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -103,6 +103,8 @@ /* A5XX Enable yield in RB only */ #define CP_YIELD_ENABLE 0x1C +#define CP_WHERE_AM_I 0x62 + /* Enable/Disable/Defer A5x global preemption model */ #define CP_PREEMPT_ENABLE_GLOBAL 0x69 diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index 12ebc174bf16..2eaf901104ef 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -189,7 +189,7 @@ void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb, adreno_ringbuffer_wptr(adreno_dev, rb); } -int adreno_ringbuffer_submit_spin(struct adreno_ringbuffer *rb, +int adreno_ringbuffer_submit_spin_nosync(struct adreno_ringbuffer *rb, struct adreno_submit_time *time, unsigned int timeout) { struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb); @@ -198,6 +198,38 @@ int adreno_ringbuffer_submit_spin(struct adreno_ringbuffer *rb, return adreno_spin_idle(adreno_dev, timeout); } +/* + * adreno_ringbuffer_submit_spin() - Submit the cmds and wait until GPU is idle + * @rb: Pointer to ringbuffer + * @time: Pointer to adreno_submit_time + * @timeout: timeout value in ms + * + * Add commands to the ringbuffer and wait until GPU goes to idle. This routine + * inserts a WHERE_AM_I packet to trigger a shadow rptr update. So, use + * adreno_ringbuffer_submit_spin_nosync() if the previous cmd in the RB is a + * CSY packet because CSY followed by WHERE_AM_I is not legal. + */ +int adreno_ringbuffer_submit_spin(struct adreno_ringbuffer *rb, + struct adreno_submit_time *time, unsigned int timeout) +{ + struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + unsigned int *cmds; + + if (adreno_is_a3xx(adreno_dev)) + return adreno_ringbuffer_submit_spin_nosync(rb, time, timeout); + + cmds = adreno_ringbuffer_allocspace(rb, 3); + if (IS_ERR(cmds)) + return PTR_ERR(cmds); + + *cmds++ = cp_packet(adreno_dev, CP_WHERE_AM_I, 2); + cmds += cp_gpuaddr(adreno_dev, cmds, + SCRATCH_RPTR_GPU_ADDR(device, rb->id)); + + return adreno_ringbuffer_submit_spin_nosync(rb, time, timeout); +} + unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb, unsigned int dwords) { @@ -322,12 +354,13 @@ int adreno_ringbuffer_probe(struct adreno_device *adreno_dev, bool nopreempt) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); + unsigned int priv = KGSL_MEMDESC_RANDOM | KGSL_MEMDESC_PRIVILEGED; int i, r = 0; int status = -ENOMEM; if (!adreno_is_a3xx(adreno_dev)) { status = kgsl_allocate_global(device, &device->scratch, - PAGE_SIZE, 0, KGSL_MEMDESC_RANDOM, "scratch"); + PAGE_SIZE, 0, priv, "scratch"); if (status != 0) return status; } @@ -549,6 +582,8 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, if (gpudev->preemption_post_ibsubmit && adreno_is_preemption_enabled(adreno_dev)) total_sizedwords += 10; + else if (!adreno_is_a3xx(adreno_dev)) + total_sizedwords += 3; /* * a5xx uses 64 bit memory address. pm4 commands that involve read/write @@ -760,6 +795,11 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, adreno_is_preemption_enabled(adreno_dev)) ringcmds += gpudev->preemption_post_ibsubmit(adreno_dev, ringcmds); + else if (!adreno_is_a3xx(adreno_dev)) { + *ringcmds++ = cp_packet(adreno_dev, CP_WHERE_AM_I, 2); + ringcmds += cp_gpuaddr(adreno_dev, ringcmds, + SCRATCH_RPTR_GPU_ADDR(device, rb->id)); + } /* * If we have more ringbuffer commands than space reserved diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h index 9eb0c92213f3..14b4ecc2e192 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.h +++ b/drivers/gpu/msm/adreno_ringbuffer.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -178,6 +178,9 @@ int adreno_ringbuffer_issue_internal_cmds(struct adreno_ringbuffer *rb, void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb, struct adreno_submit_time *time); +int adreno_ringbuffer_submit_spin_nosync(struct adreno_ringbuffer *rb, + struct adreno_submit_time *time, unsigned int timeout); + int adreno_ringbuffer_submit_spin(struct adreno_ringbuffer *rb, struct adreno_submit_time *time, unsigned int timeout); diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 0155f8b8db31..274349f688ec 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -71,13 +71,11 @@ /* * SCRATCH MEMORY: The scratch memory is one page worth of data that * is mapped into the GPU. This allows for some 'shared' data between - * the GPU and CPU. For example, it will be used by the GPU to write - * each updated RPTR for each RB. + * the GPU and CPU. * * Used Data: * Offset: Length(bytes): What * 0x0: 4 * KGSL_PRIORITY_MAX_RB_LEVELS: RB0 RPTR - * 0x10: 8 * KGSL_PRIORITY_MAX_RB_LEVELS: RB0 CTXT RESTORE ADDR */ /* Shadow global helpers */ @@ -85,13 +83,6 @@ #define SCRATCH_RPTR_GPU_ADDR(dev, id) \ ((dev)->scratch.gpuaddr + SCRATCH_RPTR_OFFSET(id)) -#define SCRATCH_PREEMPTION_CTXT_RESTORE_ADDR_OFFSET(id) \ - (SCRATCH_RPTR_OFFSET(KGSL_PRIORITY_MAX_RB_LEVELS) + \ - ((id) * sizeof(uint64_t))) -#define SCRATCH_PREEMPTION_CTXT_RESTORE_GPU_ADDR(dev, id) \ - ((dev)->scratch.gpuaddr + \ - SCRATCH_PREEMPTION_CTXT_RESTORE_ADDR_OFFSET(id)) - /* Timestamp window used to detect rollovers (half of integer range) */ #define KGSL_TIMESTAMP_WINDOW 0x80000000 From 2542a44cd90a94381baefea22cd45d2ae9110b40 Mon Sep 17 00:00:00 2001 From: Elson Roy Serrao Date: Tue, 15 Oct 2019 13:52:45 -0700 Subject: [PATCH 149/192] usb: gadget: Reset string ids upon unbind String ids for qdss,cdev and gsi based interfaces are re-used even though the device re-enumerates. This is causing string id sequence mismatch and resulting in adb using the string id of qdss interface. Reset the string ids for these functions in their respective unbind calls to fix this issue. Change-Id: Ia9b196734a99ccc2e8c35073ec4e535755774c16 Signed-off-by: Elson Roy Serrao Signed-off-by: Sriharsha Allenki --- drivers/usb/gadget/function/f_cdev.c | 3 +++ drivers/usb/gadget/function/f_gsi.c | 7 +++++++ drivers/usb/gadget/function/f_qdss.c | 6 +++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c index 79cd361fe8db..eebf17556cbc 100644 --- a/drivers/usb/gadget/function/f_cdev.c +++ b/drivers/usb/gadget/function/f_cdev.c @@ -963,6 +963,9 @@ static void usb_cser_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_cdev *port = func_to_port(f); + /* Reset string id */ + cser_string_defs[0].id = 0; + usb_free_all_descriptors(f); usb_cser_free_req(port->port_usb.notify, port->port_usb.notify_req); } diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 614d8ede3e91..d719903f71d0 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -3335,6 +3335,13 @@ static void gsi_unbind(struct usb_configuration *c, struct usb_function *f) drain_workqueue(gsi->d_port.ipa_usb_wq); ipa_usb_deinit_teth_prot((enum ipa_usb_teth_prot)gsi->prot_id); + /* Reset string ids */ + rndis_gsi_string_defs[0].id = 0; + ecm_gsi_string_defs[0].id = 0; + rmnet_gsi_string_defs[0].id = 0; + mbim_gsi_string_defs[0].id = 0; + qdss_gsi_string_defs[0].id = 0; + skip_ipa_dinit: if (gsi->prot_id == USB_PROT_RNDIS_IPA) { gsi->d_port.sm_state = STATE_UNINITIALIZED; diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index afe2569193c7..84880ae3d774 100644 --- a/drivers/usb/gadget/function/f_qdss.c +++ b/drivers/usb/gadget/function/f_qdss.c @@ -1,7 +1,7 @@ /* * f_qdss.c -- QDSS function Driver * - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018, 2020, The Linux Foundation. All rights reserved. * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -526,6 +526,10 @@ static void qdss_unbind(struct usb_configuration *c, struct usb_function *f) flush_workqueue(qdss->wq); + /* Reset string ids */ + qdss_string_defs[QDSS_DATA_IDX].id = 0; + qdss_string_defs[QDSS_CTRL_IDX].id = 0; + qdss->debug_inface_enabled = 0; clear_eps(f); From 4acd0a43e226b9c38c2f0b4b398669ed0e9a8a44 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Tue, 5 Mar 2019 11:41:09 -0800 Subject: [PATCH 150/192] usb: gadget: f_qdss: Allocate one string ID for all instances In case multi instance of driver exist in same composition, id of the string gets overridden due to multiple bind() calls. This results in STALL on GET_DESCRIPTOR (string type) on interface string descriptor index which got overridden. Fix this issue by assigning one string ID to all interface string desc index of the driver. Change-Id: If61455e9786175a1dd435320bfb54f2949e4ffa4 Signed-off-by: Hemant Kumar --- drivers/usb/gadget/function/f_qdss.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index 84880ae3d774..6e54df08ced5 100644 --- a/drivers/usb/gadget/function/f_qdss.c +++ b/drivers/usb/gadget/function/f_qdss.c @@ -2,7 +2,6 @@ * f_qdss.c -- QDSS function Driver * * Copyright (c) 2012-2018, 2020, The Linux Foundation. All rights reserved. - * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. @@ -423,11 +422,13 @@ static int qdss_bind(struct usb_configuration *c, struct usb_function *f) qdss_data_intf_desc.bInterfaceNumber = iface; qdss->data_iface_id = iface; - id = usb_string_id(c->cdev); - if (id < 0) - return id; - qdss_string_defs[QDSS_DATA_IDX].id = id; - qdss_data_intf_desc.iInterface = id; + if (!qdss_string_defs[QDSS_DATA_IDX].id) { + id = usb_string_id(c->cdev); + if (id < 0) + return id; + qdss_string_defs[QDSS_DATA_IDX].id = id; + qdss_data_intf_desc.iInterface = id; + } if (qdss->debug_inface_enabled) { /* Allocate ctrl I/F */ @@ -438,11 +439,14 @@ static int qdss_bind(struct usb_configuration *c, struct usb_function *f) } qdss_ctrl_intf_desc.bInterfaceNumber = iface; qdss->ctrl_iface_id = iface; - id = usb_string_id(c->cdev); - if (id < 0) - return id; - qdss_string_defs[QDSS_CTRL_IDX].id = id; - qdss_ctrl_intf_desc.iInterface = id; + + if (!qdss_string_defs[QDSS_CTRL_IDX].id) { + id = usb_string_id(c->cdev); + if (id < 0) + return id; + qdss_string_defs[QDSS_CTRL_IDX].id = id; + qdss_ctrl_intf_desc.iInterface = id; + } } /* for non-accelerated path keep tx fifo size 1k */ From 2c96059cf60133eceb3a42035cceea9936bb43d4 Mon Sep 17 00:00:00 2001 From: Nitesh Gupta Date: Tue, 28 Jul 2020 20:28:51 +0530 Subject: [PATCH 151/192] msm: mhi_dev: allocate high priority Workqueue for mhi_sm_wq Allocate high priority work queue for mhi_sm_wq such that MHI state change events are handled with priority. Change-Id: I3d95e23b3daafce5a8888e5203caa75f1744351b Signed-off-by: Nitesh Gupta --- drivers/platform/msm/mhi_dev/mhi_sm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.c b/drivers/platform/msm/mhi_dev/mhi_sm.c index 445ff640bf4e..373edaf7555d 100644 --- a/drivers/platform/msm/mhi_dev/mhi_sm.c +++ b/drivers/platform/msm/mhi_dev/mhi_sm.c @@ -930,7 +930,7 @@ int mhi_dev_sm_init(struct mhi_dev *mhi_dev) /*init debugfs*/ mhi_sm_debugfs_init(); - mhi_sm_ctx->mhi_sm_wq = create_singlethread_workqueue("mhi_sm_wq"); + mhi_sm_ctx->mhi_sm_wq = alloc_workqueue("mhi_sm_wq", WQ_HIGHPRI, 0); if (!mhi_sm_ctx->mhi_sm_wq) { MHI_SM_ERR("Failed to create singlethread_workqueue: sm_wq\n"); res = -ENOMEM; From d905496b7820c82474b945fe68b0090330195899 Mon Sep 17 00:00:00 2001 From: Wyes Karny Date: Wed, 6 May 2020 21:15:02 +0530 Subject: [PATCH 152/192] msm: camera: reqmgr: reset slots after deactivating session After Deactivate request comes in link control we are deactivating the link and resetting every slots in the in_q. CRs-Fixed: 2685198 Change-Id: I3f152d6486ccfe81ec44ea27ed992aacf18342bc Signed-off-by: Wyes Karny --- .../msm/camera/cam_req_mgr/cam_req_mgr_core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c index 35790fd06405..3c620519b46e 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 @@ -3444,6 +3444,8 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) struct cam_req_mgr_connected_device *dev = NULL; struct cam_req_mgr_link_evt_data evt_data; + struct cam_req_mgr_req_queue *in_q = NULL; + struct cam_req_mgr_slot *slot = NULL; if (!control) { CAM_ERR(CAM_CRM, "Control command is NULL"); @@ -3507,6 +3509,18 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) if (dev->ops && dev->ops->process_evt) dev->ops->process_evt(&evt_data); } + in_q = link->req.in_q; + /* reset all slots */ + for (j = 0; j < in_q->num_slots; j++) { + slot = &in_q->slot[j]; + slot->req_id = -1; + slot->sync_mode = + CAM_REQ_MGR_SYNC_MODE_NO_SYNC; + slot->skip_idx = 1; + slot->status = CRM_SLOT_STATUS_NO_REQ; + } + in_q->wr_idx = 0; + in_q->rd_idx = 0; } else { CAM_ERR(CAM_CRM, "Invalid link control command"); rc = -EINVAL; From 2a26c912560f2c944d81c50679263a7689f02314 Mon Sep 17 00:00:00 2001 From: Tejas Prajapati Date: Thu, 11 Jun 2020 10:16:57 +0530 Subject: [PATCH 153/192] msm: camera: reqmgr: increase the rd idx if no lower pd device For link with maximum pipeline delay of 1 e.g., TPG use case or sensors with pipeline delay of 1, if the request is not submitted before 2 consecutive triggers we do not get chance to increment rd idx, in the mean time the slot which was last applied will be reset and we will not be able to apply request even if new requests are scheduled. This will cause the camera to not apply any request further, hence increasing the rd idx if no lower pd devices are pending will fix the issue. Change-Id: Ib2eddc9c6a0ce5e73cf19873c6ce54169e29a6e1 Signed-off-by: Tejas Prajapati --- .../media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c | 2 ++ 1 file changed, 2 insertions(+) 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 3c620519b46e..354c8c5e8d9c 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 @@ -2295,6 +2295,8 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) CAM_DBG(CAM_REQ, "No pending req to apply to lower pd devices"); rc = 0; + __cam_req_mgr_inc_idx(&in_q->rd_idx, + 1, in_q->num_slots); goto release_lock; } __cam_req_mgr_inc_idx(&in_q->rd_idx, 1, in_q->num_slots); From c06917c3012add1b3e026fd253e079154567a3f2 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Thu, 9 Apr 2020 02:44:09 +0530 Subject: [PATCH 154/192] msm: camera: reqmgr: Skip apply for initial sync req on slave link This change is to stop slave link to apply initial sync request in the same frame duration in which master apply initial sync request. Slave link should wait for the master link to apply initial sync request first and then slave should apply initial sync request in the next frame. Change-Id: I8f1f54bbf674df1c578e6041eaa08869949728b3 Signed-off-by: Ayush Kumar --- .../msm/camera/cam_req_mgr/cam_req_mgr_core.c | 47 +++++++++++++++++-- 1 file changed, 43 insertions(+), 4 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 3c620519b46e..7c5da3a1b238 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 @@ -696,13 +696,19 @@ static int32_t __cam_req_mgr_find_slot_for_req( */ static int __cam_req_mgr_check_sync_for_mslave( struct cam_req_mgr_core_link *link, - struct cam_req_mgr_slot *slot) + struct cam_req_mgr_slot *slot, + uint64_t request_id) { struct cam_req_mgr_core_link *sync_link = NULL; struct cam_req_mgr_slot *sync_slot = NULL; + struct cam_req_mgr_slot *sync_rd_slot = NULL; int sync_slot_idx = 0, prev_idx, next_idx, rd_idx, sync_rd_idx, rc = 0; int64_t req_id = 0, sync_req_id = 0; int32_t sync_num_slots = 0; + uint64_t sync_frame_duration = 0; + int32_t sync_req_status = 0; + uint64_t sof_timestamp_delta = 0; + int sync_link_idx = 0; if (!link->sync_link) { CAM_ERR(CAM_CRM, "Sync link null"); @@ -713,6 +719,12 @@ static int __cam_req_mgr_check_sync_for_mslave( req_id = slot->req_id; sync_num_slots = sync_link->req.in_q->num_slots; sync_rd_idx = sync_link->req.in_q->rd_idx; + sync_rd_slot = &sync_link->req.in_q->slot[sync_rd_idx]; + + sof_timestamp_delta = + link->sof_timestamp >= sync_link->sof_timestamp + ? link->sof_timestamp - sync_link->sof_timestamp + : sync_link->sof_timestamp - link->sof_timestamp; CAM_DBG(CAM_CRM, "link_hdl %x req %lld frame_skip_flag %d open_req_cnt:%d initial_sync_req [%lld,%lld] is_master:%d", @@ -742,6 +754,10 @@ static int __cam_req_mgr_check_sync_for_mslave( return -EINVAL; } + if (sync_link->prev_sof_timestamp) + sync_frame_duration = sync_link->sof_timestamp - + sync_link->prev_sof_timestamp; + if (link->is_master) { rc = __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); if (rc) { @@ -763,7 +779,6 @@ static int __cam_req_mgr_check_sync_for_mslave( CAM_DBG(CAM_CRM, "Req: %lld [master] not ready on link: %x, rc=%d", req_id, link->link_hdl, rc); - link->sync_link_sof_skip = true; return rc; } @@ -830,10 +845,34 @@ static int __cam_req_mgr_check_sync_for_mslave( CAM_DBG(CAM_CRM, "Req: %lld [slave] not ready on link: %x, rc=%d", req_id, link->link_hdl, rc); - link->sync_link_sof_skip = true; return rc; } + sync_link_idx = __cam_req_mgr_find_slot_for_req( + sync_link->req.in_q, request_id); + if (sync_link_idx != -1) { + sync_req_status = + sync_link->req.in_q->slot[sync_link_idx].status; + if (sync_req_status != CRM_SLOT_STATUS_REQ_APPLIED) { + CAM_DBG(CAM_CRM, + "Skipping initial sync req %lld id %d as master not applied", + request_id, sync_link_idx); + return -EINVAL; + } + } else + sync_req_status = 0; + + if ((sync_link->initial_sync_req == req_id) && + (sync_req_status == CRM_SLOT_STATUS_REQ_APPLIED) && + (sof_timestamp_delta < (sync_frame_duration / 2)) && + (((sync_link_idx - sync_rd_idx + sync_num_slots) % + sync_num_slots) <= 1) && + (sync_rd_slot->status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, "Skipping initial sync req for slave"); + return -EINVAL; + } + next_idx = link->req.in_q->rd_idx; rd_idx = sync_link->req.in_q->rd_idx; __cam_req_mgr_inc_idx(&next_idx, @@ -1215,7 +1254,7 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, } rc = __cam_req_mgr_check_sync_for_mslave( - link, slot); + link, slot, trigger_data->req_id); } else { rc = __cam_req_mgr_check_sync_req_is_ready( link, slot); From 598bf245a7c6c7e75d3eeca7a48c1b9bf171c1ab Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Fri, 5 Jun 2020 00:55:14 +0530 Subject: [PATCH 155/192] msm: camera: core: Change return type Return different error number when new requests and update packets are rejected due to bad request id. This allows userspace to differentiate this specific reason for failure. Change-Id: I0b1e7086351b9438fd72a6d824bc20c8213b5ea8 Signed-off-by: Ayush Kumar --- drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c | 2 +- .../media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c index 3ed714658e44..abb910e71345 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 @@ -3345,7 +3345,7 @@ static int __cam_isp_ctx_config_dev_in_top_state( CAM_INFO(CAM_ISP, "request %lld has been flushed, reject packet", packet->header.request_id); - rc = -EINVAL; + rc = -EBADR; goto free_cpu_buf; } 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 354c8c5e8d9c..eedf8f5a4fcb 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 @@ -3207,7 +3207,7 @@ int cam_req_mgr_schedule_request( CAM_INFO(CAM_CRM, "request %lld is flushed, last_flush_id to flush %u", sched_req->req_id, link->last_flush_id); - rc = -EINVAL; + rc = -EBADR; goto end; } From 3f85b1024a777767e7648248b482101971fb2ded Mon Sep 17 00:00:00 2001 From: Shravan Nevatia Date: Fri, 20 Mar 2020 17:42:05 +0530 Subject: [PATCH 156/192] msm: camera: csiphy: Update phy settings for atoll Update the PHY (CPHY, DPHY, DPHY combo) sequences for csiphy v1.2.2 to align with HPG revision W. Change-Id: Ib25d958cacd1a9b0f51d6b749ba0d59a84def761 Signed-off-by: Shravan Nevatia --- .../include/cam_csiphy_1_2_2_hwreg.h | 166 +++++++++--------- 1 file changed, 79 insertions(+), 87 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h index 51ffc1872af4..0aa91d58767a 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_2_hwreg.h @@ -19,10 +19,10 @@ struct csiphy_reg_parms_t csiphy_v1_2_2 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .csiphy_common_array_size = 7, + .csiphy_common_array_size = 6, .csiphy_reset_array_size = 5, - .csiphy_2ph_config_array_size = 22, - .csiphy_3ph_config_array_size = 38, + .csiphy_2ph_config_array_size = 23, + .csiphy_3ph_config_array_size = 30, .csiphy_2ph_clock_lane = 0x1, .csiphy_2ph_combo_ck_ln = 0x10, }; @@ -30,8 +30,7 @@ struct csiphy_reg_parms_t csiphy_v1_2_2 = { struct csiphy_reg_t csiphy_common_reg_1_2_2[] = { {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x081C, 0x02, 0x00, CSIPHY_2PH_REGS}, - {0x081C, 0x52, 0x00, CSIPHY_3PH_REGS}, + {0x081C, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x03, 0x01, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_2PH_REGS}, {0x0800, 0x0E, 0x00, CSIPHY_3PH_REGS}, @@ -65,34 +64,34 @@ csiphy_reg_t csiphy_2ph_v1_2_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0910, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0900, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0908, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0900, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0908, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x00C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C80, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C88, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C88, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x07C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -108,78 +107,83 @@ csiphy_reg_t csiphy_2ph_v1_2_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A00, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A08, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x02C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B00, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B08, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x04C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0428, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C00, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C08, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x06C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0628, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x065C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, }; @@ -189,34 +193,34 @@ struct csiphy_reg_t {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0910, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0900, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0908, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0900, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0908, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x00C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C80, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C88, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C88, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x07C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -231,40 +235,42 @@ struct csiphy_reg_t {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x075C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A00, 0x0B, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A08, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x02C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B00, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B08, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x04C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -276,19 +282,20 @@ struct csiphy_reg_t {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, - {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, }, { {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C00, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0C08, 0x14, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C00, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C08, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x06C4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -296,14 +303,16 @@ struct csiphy_reg_t {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, {0x060c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x065C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }; @@ -311,9 +320,6 @@ struct csiphy_reg_t csiphy_3ph_v1_2_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { { {0x015C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0990, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0994, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0998, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0990, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0994, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0998, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -339,25 +345,17 @@ csiphy_reg_t csiphy_3ph_v1_2_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09C0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09C4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x09C8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0984, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x09B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x09B4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x035C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A8C, 0xBF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x036C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -379,21 +377,13 @@ csiphy_reg_t csiphy_3ph_v1_2_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0AC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0A84, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0AB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0AB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, }, { {0x055C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -419,12 +409,7 @@ csiphy_reg_t csiphy_3ph_v1_2_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0BC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0B84, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0B80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0BB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0BB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -437,7 +422,7 @@ struct data_rate_settings_t data_rate_delta_table_1_2_2 = { { /* (2.5 * 10**3 * 2.28) rounded value*/ .bandwidth = 5700000000, - .data_rate_reg_array_size = 8, + .data_rate_reg_array_size = 6, .csiphy_data_rate_regs = { {0x144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -445,14 +430,12 @@ struct data_rate_settings_t data_rate_delta_table_1_2_2 = { {0x984, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xA84, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xB84, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A8C, 0xBF, 0x00, CSIPHY_DEFAULT_PARAMS}, } }, { /* (3.5 * 10**3 * 2.28) rounded value */ .bandwidth = 7980000000, - .data_rate_reg_array_size = 8, + .data_rate_reg_array_size = 12, .csiphy_data_rate_regs = { {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -460,14 +443,18 @@ struct data_rate_settings_t data_rate_delta_table_1_2_2 = { {0x984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xA84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xB84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, }, }, { /* (4.5 * 10**3 * 2.28) rounded value */ .bandwidth = 10260000000, - .data_rate_reg_array_size = 8, + .data_rate_reg_array_size = 12, .csiphy_data_rate_regs = { {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, @@ -475,8 +462,13 @@ struct data_rate_settings_t data_rate_delta_table_1_2_2 = { {0x984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xA84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, {0xB84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, - {0x0A8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, } } From 92a05d8c57722134abd448d059ab383211ce8da5 Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Thu, 18 Jun 2020 21:34:25 +0530 Subject: [PATCH 157/192] msm: mhi_dev: Fix memory leak mhi_dev_cache_host_cfg will be called during cold boot and also when processing mhi device reset command from host. Do not re-allocate the command, event and channel context cache memory if they were already allocated. Change-Id: I55826e05b3d83c9fcf3d4b23e26b91253130671e Signed-off-by: Siva Kumar Akkireddi --- drivers/platform/msm/mhi_dev/mhi.c | 73 +++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 612cc531c2a8..548bd573b68b 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -2425,34 +2425,51 @@ static int mhi_dev_cache_host_cfg(struct mhi_dev *mhi) mhi->cfg.event_rings; mhi->ch_ctx_shadow.size = sizeof(struct mhi_dev_ch_ctx) * mhi->cfg.channels; - - mhi->cmd_ctx_cache = dma_alloc_coherent(&pdev->dev, - sizeof(struct mhi_dev_cmd_ctx), - &mhi->cmd_ctx_cache_dma_handle, - GFP_KERNEL); + /* + * This func mhi_dev_cache_host_cfg will be called when + * processing mhi device reset as well, do not allocate + * the command, event and channel context caches if they + * were already allocated during device boot, to avoid + * memory leak. + */ if (!mhi->cmd_ctx_cache) { - pr_err("no memory while allocating cmd ctx\n"); - return -ENOMEM; + mhi->cmd_ctx_cache = dma_alloc_coherent(&pdev->dev, + sizeof(struct mhi_dev_cmd_ctx), + &mhi->cmd_ctx_cache_dma_handle, + GFP_KERNEL); + if (!mhi->cmd_ctx_cache) { + pr_err("no memory while allocating cmd ctx\n"); + rc = -ENOMEM; + goto exit; + } } memset(mhi->cmd_ctx_cache, 0, sizeof(struct mhi_dev_cmd_ctx)); - mhi->ev_ctx_cache = dma_alloc_coherent(&pdev->dev, - sizeof(struct mhi_dev_ev_ctx) * - mhi->cfg.event_rings, - &mhi->ev_ctx_cache_dma_handle, - GFP_KERNEL); - if (!mhi->ev_ctx_cache) - return -ENOMEM; + if (!mhi->ev_ctx_cache) { + mhi->ev_ctx_cache = dma_alloc_coherent(&pdev->dev, + sizeof(struct mhi_dev_ev_ctx) * + mhi->cfg.event_rings, + &mhi->ev_ctx_cache_dma_handle, + GFP_KERNEL); + if (!mhi->ev_ctx_cache) { + rc = -ENOMEM; + goto exit; + } + } memset(mhi->ev_ctx_cache, 0, sizeof(struct mhi_dev_ev_ctx) * mhi->cfg.event_rings); - mhi->ch_ctx_cache = dma_alloc_coherent(&pdev->dev, - sizeof(struct mhi_dev_ch_ctx) * - mhi->cfg.channels, - &mhi->ch_ctx_cache_dma_handle, - GFP_KERNEL); - if (!mhi->ch_ctx_cache) - return -ENOMEM; + if (!mhi->ch_ctx_cache) { + mhi->ch_ctx_cache = dma_alloc_coherent(&pdev->dev, + sizeof(struct mhi_dev_ch_ctx) * + mhi->cfg.channels, + &mhi->ch_ctx_cache_dma_handle, + GFP_KERNEL); + if (!mhi->ch_ctx_cache) { + rc = -ENOMEM; + goto exit; + } + } memset(mhi->ch_ctx_cache, 0, sizeof(struct mhi_dev_ch_ctx) * mhi->cfg.channels); @@ -2488,6 +2505,20 @@ static int mhi_dev_cache_host_cfg(struct mhi_dev *mhi) return mhi_ring_start(&mhi->ring[0], (union mhi_dev_ring_ctx *)mhi->cmd_ctx_cache, mhi); + +exit: + if (mhi->cmd_ctx_cache) + dma_free_coherent(&pdev->dev, + sizeof(struct mhi_dev_cmd_ctx), + mhi->cmd_ctx_cache, + mhi->cmd_ctx_cache_dma_handle); + if (mhi->ev_ctx_cache) + dma_free_coherent(&pdev->dev, + sizeof(struct mhi_dev_ev_ctx) * + mhi->cfg.event_rings, + mhi->ev_ctx_cache, + mhi->ev_ctx_cache_dma_handle); + return rc; } void mhi_dev_pm_relax(void) From 3bea959dad1b5da0e631c138504b89ff60961e4e Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Fri, 19 Jun 2020 13:42:24 +0530 Subject: [PATCH 158/192] msm: mhi_dev: Fix memory leak during channel reset/stop mhi_ring_start() does not check whether we once ever allocated DMA buffer or not , causing it to leak memory if channel reset/stop happens. Also removing the free logic in mhi_deinit() as the check would suffice to prevent reallocation. Change-Id: I569560f9de9facc690131c56f657eadb77a12811 Signed-off-by: Subramanian Ananthanarayanan --- drivers/platform/msm/mhi_dev/mhi.c | 35 +++------------- drivers/platform/msm/mhi_dev/mhi_ring.c | 56 +++++++++++++++---------- 2 files changed, 39 insertions(+), 52 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 548bd573b68b..94fad034dbab 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -3655,35 +3655,9 @@ static int get_device_tree_data(struct platform_device *pdev) static int mhi_deinit(struct mhi_dev *mhi) { - int i = 0, ring_id = 0; - struct mhi_dev_ring *ring; struct platform_device *pdev = mhi->pdev; - ring_id = mhi->cfg.channels + mhi->cfg.event_rings + 1; - - for (i = 0; i < ring_id; i++) { - ring = &mhi->ring[i]; - if (ring->state == RING_STATE_UINT) - continue; - - dma_free_coherent(mhi->dev, ring->ring_size * - sizeof(union mhi_dev_ring_element_type), - ring->ring_cache, - ring->ring_cache_dma_handle); - if (ring->type == RING_TYPE_ER) { - dma_free_coherent(mhi->dev, ring->ring_size * - sizeof(uint64_t), - ring->evt_rp_cache, - ring->evt_rp_cache_dma_handle); - dma_free_coherent(mhi->dev, - sizeof(uint32_t), - ring->msi_buf, - ring->msi_buf_dma_handle); - } - } - devm_kfree(&pdev->dev, mhi->mmio_backup); - devm_kfree(&pdev->dev, mhi->ring); mhi_dev_sm_exit(mhi); @@ -3703,10 +3677,11 @@ static int mhi_init(struct mhi_dev *mhi) return rc; } - mhi->ring = devm_kzalloc(&pdev->dev, - (sizeof(struct mhi_dev_ring) * - (mhi->cfg.channels + mhi->cfg.event_rings + 1)), - GFP_KERNEL); + if (!mhi->ring) + mhi->ring = devm_kzalloc(&pdev->dev, + (sizeof(struct mhi_dev_ring) * + (mhi->cfg.channels + mhi->cfg.event_rings + 1)), + GFP_KERNEL); if (!mhi->ring) return -ENOMEM; diff --git a/drivers/platform/msm/mhi_dev/mhi_ring.c b/drivers/platform/msm/mhi_dev/mhi_ring.c index 7268ca6ff916..6c2b60d230a1 100644 --- a/drivers/platform/msm/mhi_dev/mhi_ring.c +++ b/drivers/platform/msm/mhi_dev/mhi_ring.c @@ -416,33 +416,43 @@ int mhi_ring_start(struct mhi_dev_ring *ring, union mhi_dev_ring_ctx *ctx, wr_offset = mhi_dev_ring_addr2ofst(ring, ring->ring_ctx->generic.wp); - ring->ring_cache = dma_alloc_coherent(mhi->dev, - ring->ring_size * - sizeof(union mhi_dev_ring_element_type), - &ring->ring_cache_dma_handle, - GFP_KERNEL); - if (!ring->ring_cache) - return -ENOMEM; + if (!ring->ring_cache) { + ring->ring_cache = dma_alloc_coherent(mhi->dev, + ring->ring_size * + sizeof(union mhi_dev_ring_element_type), + &ring->ring_cache_dma_handle, + GFP_KERNEL); + if (!ring->ring_cache) { + mhi_log(MHI_MSG_ERROR, + "Failed to allocate ring cache\n"); + return -ENOMEM; + } + } if (ring->type == RING_TYPE_ER) { - ring->evt_rp_cache = dma_alloc_coherent(mhi->dev, - sizeof(uint64_t) * ring->ring_size, - &ring->evt_rp_cache_dma_handle, - GFP_KERNEL); if (!ring->evt_rp_cache) { - mhi_log(MHI_MSG_ERROR, - "Failed to allocate evt rp cache\n"); - rc = -ENOMEM; - goto cleanup; + ring->evt_rp_cache = dma_alloc_coherent(mhi->dev, + sizeof(uint64_t) * ring->ring_size, + &ring->evt_rp_cache_dma_handle, + GFP_KERNEL); + if (!ring->evt_rp_cache) { + mhi_log(MHI_MSG_ERROR, + "Failed to allocate evt rp cache\n"); + rc = -ENOMEM; + goto cleanup; + } } - ring->msi_buf = dma_alloc_coherent(mhi->dev, - sizeof(uint32_t), - &ring->msi_buf_dma_handle, - GFP_KERNEL); if (!ring->msi_buf) { - mhi_log(MHI_MSG_ERROR, "Failed to allocate msi buf\n"); - rc = -ENOMEM; - goto cleanup; + ring->msi_buf = dma_alloc_coherent(mhi->dev, + sizeof(uint32_t), + &ring->msi_buf_dma_handle, + GFP_KERNEL); + if (!ring->msi_buf) { + mhi_log(MHI_MSG_ERROR, + "Failed to allocate msi buf\n"); + rc = -ENOMEM; + goto cleanup; + } } } @@ -488,11 +498,13 @@ int mhi_ring_start(struct mhi_dev_ring *ring, union mhi_dev_ring_ctx *ctx, sizeof(union mhi_dev_ring_element_type), ring->ring_cache, ring->ring_cache_dma_handle); + ring->ring_cache = NULL; if (ring->evt_rp_cache) { dma_free_coherent(mhi->dev, sizeof(uint64_t) * ring->ring_size, ring->evt_rp_cache, ring->evt_rp_cache_dma_handle); + ring->evt_rp_cache = NULL; } return rc; } From 4d3f4cfd14f0cdc74a5f9b9aa74f0d29ddb4940b Mon Sep 17 00:00:00 2001 From: Rishabh Bhatnagar Date: Tue, 16 Jul 2019 14:03:00 -0700 Subject: [PATCH 159/192] esoc: Use BOOT mode indicating mdm2ap status high Put modem in BOOT mode representing the state where mdm2ap status has gone high but the efs pipe is not established. Differenciating boot and run state helps handle errafatal interrupts better. Change-Id: Ifbc24468be67ba6f56a3dd2ca20e404949fb2ceb Signed-off-by: Rishabh Bhatnagar --- drivers/esoc/esoc-mdm-4x.c | 1 + drivers/esoc/esoc-mdm-drv.c | 7 +++++++ include/uapi/linux/esoc_ctrl.h | 1 + 3 files changed, 9 insertions(+) diff --git a/drivers/esoc/esoc-mdm-4x.c b/drivers/esoc/esoc-mdm-4x.c index b9de06cb7bd4..f348d116a9ce 100644 --- a/drivers/esoc/esoc-mdm-4x.c +++ b/drivers/esoc/esoc-mdm-4x.c @@ -563,6 +563,7 @@ static irqreturn_t mdm_status_change(int irq, void *dev_id) cancel_delayed_work(&mdm->mdm2ap_status_check_work); dev_dbg(dev, "status = 1: mdm is now ready\n"); mdm->ready = true; + esoc_clink_evt_notify(ESOC_BOOT_STATE, esoc); mdm_trigger_dbg(mdm); queue_work(mdm->mdm_queue, &mdm->mdm_status_work); if (mdm->get_restart_reason) diff --git a/drivers/esoc/esoc-mdm-drv.c b/drivers/esoc/esoc-mdm-drv.c index b6ea5eaec967..7d031c37c4b9 100644 --- a/drivers/esoc/esoc-mdm-drv.c +++ b/drivers/esoc/esoc-mdm-drv.c @@ -150,6 +150,13 @@ static void mdm_handle_clink_evt(enum esoc_evt evt, mdm_drv->pon_state = PON_FAIL; complete(&mdm_drv->pon_done); break; + case ESOC_BOOT_STATE: + if (mdm_drv->mode == PWR_OFF) { + esoc_mdm_log( + "ESOC_BOOT_STATE: Observed status high from modem.\n"); + mdm_drv->mode = BOOT; + } + break; case ESOC_RUN_STATE: esoc_mdm_log( "ESOC_RUN_STATE: Calling complete with state: PON_SUCCESS\n"); diff --git a/include/uapi/linux/esoc_ctrl.h b/include/uapi/linux/esoc_ctrl.h index 631fa449c386..d1f644ace36a 100644 --- a/include/uapi/linux/esoc_ctrl.h +++ b/include/uapi/linux/esoc_ctrl.h @@ -44,6 +44,7 @@ enum esoc_evt { ESOC_CMD_ENG_OFF, ESOC_INVALID_STATE, ESOC_RETRY_PON_EVT, + ESOC_BOOT_STATE, }; enum esoc_cmd { From 70f2a23fc6e29ee901ec05f1f1a290d7d00bf817 Mon Sep 17 00:00:00 2001 From: Rishabh Bhatnagar Date: Tue, 16 Jul 2019 13:48:53 -0700 Subject: [PATCH 160/192] esoc: Service errfatal interrupt in BOOT and RUN mode Start monitoring the errfatal interrupt after modem status goes high. If we observe errfatal before modem is completely up wait till mdm-helper is done with bootup to trigger SSR. Change-Id: Iecbe7870dd85831189830bf565a24738cfb5e373 Signed-off-by: Rishabh Bhatnagar --- drivers/esoc/esoc-mdm-drv.c | 43 ++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/drivers/esoc/esoc-mdm-drv.c b/drivers/esoc/esoc-mdm-drv.c index 7d031c37c4b9..9ab7d9d87bef 100644 --- a/drivers/esoc/esoc-mdm-drv.c +++ b/drivers/esoc/esoc-mdm-drv.c @@ -35,20 +35,21 @@ enum esoc_pon_state { enum { PWR_OFF = 0x1, - PWR_ON, - BOOT, - RUN, - CRASH, - IN_DEBUG, SHUTDOWN, RESET, PEER_CRASH, + IN_DEBUG, + CRASH, + PWR_ON, + BOOT, + RUN, }; struct mdm_drv { unsigned int mode; struct esoc_eng cmd_eng; struct completion pon_done; + struct completion ssr_ready; struct completion req_eng_wait; struct esoc_clink *esoc_clink; enum esoc_pon_state pon_state; @@ -149,6 +150,7 @@ static void mdm_handle_clink_evt(enum esoc_evt evt, "ESOC_INVALID_STATE: Calling complete with state: PON_FAIL\n"); mdm_drv->pon_state = PON_FAIL; complete(&mdm_drv->pon_done); + complete(&mdm_drv->ssr_ready); break; case ESOC_BOOT_STATE: if (mdm_drv->mode == PWR_OFF) { @@ -163,12 +165,14 @@ static void mdm_handle_clink_evt(enum esoc_evt evt, mdm_drv->pon_state = PON_SUCCESS; mdm_drv->mode = RUN, complete(&mdm_drv->pon_done); + complete(&mdm_drv->ssr_ready); break; case ESOC_RETRY_PON_EVT: esoc_mdm_log( "ESOC_RETRY_PON_EVT: Calling complete with state: PON_RETRY\n"); mdm_drv->pon_state = PON_RETRY; complete(&mdm_drv->pon_done); + complete(&mdm_drv->ssr_ready); break; case ESOC_UNEXPECTED_RESET: esoc_mdm_log("evt_state: ESOC_UNEXPECTED_RESET\n"); @@ -178,19 +182,15 @@ static void mdm_handle_clink_evt(enum esoc_evt evt, esoc_mdm_log("evt_state: ESOC_ERR_FATAL\n"); /* - * Modem can crash while we are waiting for pon_done during - * a subsystem_get(). Setting mode to CRASH will prevent a - * subsequent subsystem_get() from entering poweron ops. Avoid - * this by seting mode to CRASH only if device was up and - * running. + * Ignore all modem errfatals if the status is not up + * or modem in run state. */ - if (mdm_drv->mode == CRASH) + if (mdm_drv->mode <= CRASH) { esoc_mdm_log( - "Modem in crash state already. Ignoring.\n"); - if (mdm_drv->mode != RUN) - esoc_mdm_log("Modem not up. Ignoring.\n"); - if (mdm_drv->mode == CRASH || mdm_drv->mode != RUN) + "Modem in crash state or not booted. Ignoring.\n"); return; + } + esoc_mdm_log("Setting crash flag\n"); mdm_drv->mode = CRASH; queue_work(mdm_drv->mdm_queue, &mdm_drv->ssr_work); break; @@ -209,10 +209,15 @@ static void mdm_ssr_fn(struct work_struct *work) struct mdm_drv *mdm_drv = container_of(work, struct mdm_drv, ssr_work); struct mdm_ctrl *mdm = get_esoc_clink_data(mdm_drv->esoc_clink); - esoc_client_link_mdm_crash(mdm_drv->esoc_clink); + /* Wait for pon to complete. Start SSR only if pon is success */ + wait_for_completion(&mdm_drv->ssr_ready); + if (mdm_drv->pon_state != PON_SUCCESS) { + esoc_mdm_log("Got errfatal but ignoring as boot failed\n"); + return; + } + esoc_client_link_mdm_crash(mdm_drv->esoc_clink); mdm_wait_for_status_low(mdm, false); - esoc_mdm_log("Starting SSR work\n"); /* @@ -376,7 +381,9 @@ static void mdm_subsys_retry_powerup_cleanup(struct esoc_clink *esoc_clink, esoc_client_link_power_off(esoc_clink, poff_flags); mdm_disable_irqs(mdm); mdm_drv->pon_state = PON_INIT; + mdm_drv->mode = PWR_OFF; reinit_completion(&mdm_drv->pon_done); + reinit_completion(&mdm_drv->ssr_ready); reinit_completion(&mdm_drv->req_eng_wait); } @@ -424,6 +431,7 @@ static int mdm_handle_boot_fail(struct esoc_clink *esoc_clink, u8 *pon_trial) break; case BOOT_FAIL_ACTION_NOP: esoc_mdm_log("Leaving the modem in its curent state\n"); + mdm_drv->mode = PWR_OFF; return -EIO; case BOOT_FAIL_ACTION_SHUTDOWN: default: @@ -587,6 +595,7 @@ int esoc_ssr_probe(struct esoc_clink *esoc_clink, struct esoc_drv *drv) } esoc_set_drv_data(esoc_clink, mdm_drv); init_completion(&mdm_drv->pon_done); + init_completion(&mdm_drv->ssr_ready); init_completion(&mdm_drv->req_eng_wait); INIT_WORK(&mdm_drv->ssr_work, mdm_ssr_fn); mdm_drv->esoc_clink = esoc_clink; From 87f883b6a3752004e4fd454999ec33d6b2420348 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Fri, 24 Jan 2020 11:54:24 +0530 Subject: [PATCH 161/192] BACKPORT: ath10k: enable bus layer suspend/resume for WCN3990 Register snoc bus layer suspend/resume PM ops and configure the wakeup source(CE2) for the device. Testing: Tested on WCN3990 HW. Tested FW: WLAN.HL.2.0-01192-QCAHLSWMTPLZ-1. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo [govinds@codeaurora.org: fix trivial merge conflicts] Change-Id: I1116b98f82197a1ee28e094e3b1804aa50227e23 Git-commit: 185be1c66469b2c31bd3a0502b3cdf0e654f95eb Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/ath.git Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/snoc.c | 45 ++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index f9f527a96a24..495d3cb3cde6 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -30,6 +30,7 @@ #define ATH10K_SNOC_RX_POST_RETRY_MS 50 #define CE_POLL_PIPE 4 +#define ATH10K_SNOC_WAKE_IRQ 2 static char *const ce_name[] = { "WLAN_CE_0", @@ -1038,6 +1039,46 @@ static int ath10k_snoc_hif_set_target_log_mode(struct ath10k *ar, return ath10k_qmi_set_fw_log_mode(ar, fw_dbg_mode); } +#ifdef CONFIG_PM +static int ath10k_snoc_hif_suspend(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + int ret; + + if (!device_may_wakeup(ar->dev)) + return -EPERM; + + ret = enable_irq_wake(ar_snoc->ce_irqs[ATH10K_SNOC_WAKE_IRQ].irq_line); + if (ret) { + ath10k_err(ar, "failed to enable wakeup irq :%d\n", ret); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc device suspended\n"); + + return ret; +} + +static int ath10k_snoc_hif_resume(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + int ret; + + if (!device_may_wakeup(ar->dev)) + return -EPERM; + + ret = disable_irq_wake(ar_snoc->ce_irqs[ATH10K_SNOC_WAKE_IRQ].irq_line); + if (ret) { + ath10k_err(ar, "failed to disable wakeup irq: %d\n", ret); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc device resumed\n"); + + return ret; +} +#endif + static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .read32 = ath10k_snoc_read32, .write32 = ath10k_snoc_write32, @@ -1052,6 +1093,10 @@ static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .get_free_queue_number = ath10k_snoc_hif_get_free_queue_number, .get_target_info = ath10k_snoc_hif_get_target_info, .set_target_log_mode = ath10k_snoc_hif_set_target_log_mode, +#ifdef CONFIG_PM + .suspend = ath10k_snoc_hif_suspend, + .resume = ath10k_snoc_hif_resume, +#endif }; static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { From 8eabae5c1832efc03c296f827a119938403f5895 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Fri, 8 Feb 2019 14:55:35 +0200 Subject: [PATCH 162/192] ath10k: request credit report if flow control enabled on ep FW credit flow control is enabled for only WMI ctrl service(CE3) but credit update is requested unconditionally on all HTC services as part of HTC tx in CE3/CE0/CE4. This is causing WOW failure as FW is not expecting credit report request on other end-points(CE0/CE4). Request credit report only on those endpoints where credit flow control is enabled. Testing: Tested on WCN3990 HW. Tested FW: WLAN.HL.2.0-01192-QCAHLSWMTPLZ-1. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Change-Id: I59307aa14cf62f303ab68bb5fd36fd89c081948b Git-commit: c40e448e0bcf1541c0d0c42a197ef4f183a83db0 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/ath.git Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/htc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 8902720b4e49..31f1a316be7c 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -87,7 +87,8 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep, hdr->eid = ep->eid; hdr->len = __cpu_to_le16(skb->len - sizeof(*hdr)); hdr->flags = 0; - hdr->flags |= ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE; + if (ep->tx_credit_flow_enabled) + hdr->flags |= ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE; spin_lock_bh(&ep->htc->tx_lock); hdr->seq_no = ep->seq_no++; From b4c1ff8f74e5d4e7b192f19ce2bec349768f2b23 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Wed, 16 Jan 2019 16:59:42 +0530 Subject: [PATCH 163/192] ath10k: Add support for extended HTT aggr msg support HTT aggr message parameter in HL2.0 fw are different in comparison to legacy fw version. Fill correct HTT aggr msg parameter for targets using HL2.0 firmware. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Change-Id: I7798f480c5cd3ac502a7c3b921b81b8b37ff4706 Git-commit: 5cbb117477501df2f8b3a384b042b08cd7174c92 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/ath.git Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/htt.c | 2 +- drivers/net/wireless/ath/ath10k/htt.h | 11 ++++++ drivers/net/wireless/ath/ath10k/htt_tx.c | 49 ++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 625198dea18b..55743f781d5a 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -268,7 +268,7 @@ int ath10k_htt_setup(struct ath10k_htt *htt) return status; } - status = ath10k_htt_h2t_aggr_cfg_msg(htt, + status = htt->tx_ops->htt_h2t_aggr_cfg_msg(htt, htt->max_num_ampdu, htt->max_num_amsdu); if (status) { diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 5de693845d31..e9f54b37db6f 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -357,6 +357,13 @@ struct htt_aggr_conf { u8 max_num_amsdu_subframes; } __packed; +struct htt_aggr_conf_v2 { + u8 max_num_ampdu_subframes; + /* amsdu_subframes is limited by 0x1F mask */ + u8 max_num_amsdu_subframes; + u8 reserved; +} __packed; + #define HTT_MGMT_FRM_HDR_DOWNLOAD_LEN 32 struct htt_mgmt_tx_desc_qca99x0 { __le32 rate; @@ -1621,6 +1628,7 @@ struct htt_cmd { struct htt_stats_req stats_req; struct htt_oob_sync_req oob_sync_req; struct htt_aggr_conf aggr_conf; + struct htt_aggr_conf_v2 aggr_conf_v2; struct htt_frag_desc_bank_cfg32 frag_desc_bank_cfg32; struct htt_frag_desc_bank_cfg64 frag_desc_bank_cfg64; struct htt_tx_fetch_resp tx_fetch_resp; @@ -1859,6 +1867,9 @@ struct ath10k_htt_tx_ops { struct sk_buff *msdu); int (*htt_alloc_txbuff)(struct ath10k_htt *htt); void (*htt_free_txbuff)(struct ath10k_htt *htt); + int (*htt_h2t_aggr_cfg_msg)(struct ath10k_htt *htt, + u8 max_subfrms_ampdu, + u8 max_subfrms_amsdu); }; struct ath10k_htt_rx_ops { diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 4854df133724..ad0692e2de8e 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -981,6 +981,53 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, return 0; } +static int ath10k_htt_h2t_aggr_cfg_msg_v2(struct ath10k_htt *htt, + u8 max_subfrms_ampdu, + u8 max_subfrms_amsdu) +{ + struct ath10k *ar = htt->ar; + struct htt_aggr_conf_v2 *aggr_conf; + struct sk_buff *skb; + struct htt_cmd *cmd; + int len; + int ret; + + /* Firmware defaults are: amsdu = 3 and ampdu = 64 */ + + if (max_subfrms_ampdu == 0 || max_subfrms_ampdu > 64) + return -EINVAL; + + if (max_subfrms_amsdu == 0 || max_subfrms_amsdu > 31) + return -EINVAL; + + len = sizeof(cmd->hdr); + len += sizeof(cmd->aggr_conf_v2); + + skb = ath10k_htc_alloc_skb(ar, len); + if (!skb) + return -ENOMEM; + + skb_put(skb, len); + cmd = (struct htt_cmd *)skb->data; + cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_AGGR_CFG; + + aggr_conf = &cmd->aggr_conf_v2; + aggr_conf->max_num_ampdu_subframes = max_subfrms_ampdu; + aggr_conf->max_num_amsdu_subframes = max_subfrms_amsdu; + + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt h2t aggr cfg msg amsdu %d ampdu %d", + aggr_conf->max_num_amsdu_subframes, + aggr_conf->max_num_ampdu_subframes); + + ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); + if (ret) { + dev_kfree_skb_any(skb); + return ret; + } + + return 0; +} + int ath10k_htt_tx_fetch_resp(struct ath10k *ar, __le32 token, __le16 fetch_seq_num, @@ -1555,6 +1602,7 @@ static const struct ath10k_htt_tx_ops htt_tx_ops_32 = { .htt_tx = ath10k_htt_tx_32, .htt_alloc_txbuff = ath10k_htt_tx_alloc_cont_txbuf_32, .htt_free_txbuff = ath10k_htt_tx_free_cont_txbuf_32, + .htt_h2t_aggr_cfg_msg = ath10k_htt_h2t_aggr_cfg_msg, }; static const struct ath10k_htt_tx_ops htt_tx_ops_64 = { @@ -1565,6 +1613,7 @@ static const struct ath10k_htt_tx_ops htt_tx_ops_64 = { .htt_tx = ath10k_htt_tx_64, .htt_alloc_txbuff = ath10k_htt_tx_alloc_cont_txbuf_64, .htt_free_txbuff = ath10k_htt_tx_free_cont_txbuf_64, + .htt_h2t_aggr_cfg_msg = ath10k_htt_h2t_aggr_cfg_msg_v2, }; void ath10k_htt_set_tx_ops(struct ath10k_htt *htt) From 34589bbd27163096cb3c9a68785a5c9770da5fbc Mon Sep 17 00:00:00 2001 From: Yu Wang Date: Fri, 15 Feb 2019 15:38:44 +0530 Subject: [PATCH 164/192] ath10k: correct the format of host memory chunks in wmi init command This is a theoretical fix, the issue is found in code review. When adding the host memory chunks into wmi-tlv init command, there is no separate tlv header for each host memory chunk in the struct array, which breaches the convention between host and firmware, will result in mismatch between the two. To fix this issue, add separate tlv headers for the host memory chunks in wmi-tlv init command. Signed-off-by: Yu Wang Signed-off-by: Kalle Valo Signed-off-by: Govind Singh Change-Id: I6d0c3466e108268447b02ac0667b2518ad27075a Git-commit: d961284df24b8566b473d3828fe299677e155ae6 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/ath.git Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 39 +++++++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 378054d3f3d7..6ab44add9f51 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1423,17 +1423,50 @@ ath10k_wmi_tlv_op_gen_pdev_set_param(struct ath10k *ar, u32 param_id, return skb; } +static void +ath10k_wmi_tlv_put_host_mem_chunks(struct ath10k *ar, void *host_mem_chunks) +{ + struct host_memory_chunk *chunk; + struct wmi_tlv *tlv; + int i; + __le16 tlv_len, tlv_tag; + + tlv_tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WLAN_HOST_MEMORY_CHUNK); + tlv_len = __cpu_to_le16(sizeof(*chunk)); + for (i = 0; i < ar->wmi.num_mem_chunks; i++) { + tlv = host_mem_chunks; + tlv->tag = tlv_tag; + tlv->len = tlv_len; + chunk = (void *)tlv->value; + + chunk->ptr = __cpu_to_le32(ar->wmi.mem_chunks[i].paddr); + chunk->size = __cpu_to_le32(ar->wmi.mem_chunks[i].len); + chunk->req_id = __cpu_to_le32(ar->wmi.mem_chunks[i].req_id); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi-tlv chunk %d len %d, addr 0x%llx, id 0x%x\n", + i, + ar->wmi.mem_chunks[i].len, + (unsigned long long)ar->wmi.mem_chunks[i].paddr, + ar->wmi.mem_chunks[i].req_id); + + host_mem_chunks += sizeof(*tlv); + host_mem_chunks += sizeof(*chunk); + } +} + static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) { struct sk_buff *skb; struct wmi_tlv *tlv; struct wmi_tlv_init_cmd *cmd; struct wmi_tlv_resource_config *cfg; - struct wmi_host_mem_chunks *chunks; + void *chunks; size_t len, chunks_len; void *ptr; - chunks_len = ar->wmi.num_mem_chunks * sizeof(struct host_memory_chunk); + chunks_len = ar->wmi.num_mem_chunks * + (sizeof(struct host_memory_chunk) + sizeof(*tlv)); len = (sizeof(*tlv) + sizeof(*cmd)) + (sizeof(*tlv) + sizeof(*cfg)) + (sizeof(*tlv) + chunks_len); @@ -1527,7 +1560,7 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) cfg->num_ocb_schedules = __cpu_to_le32(0); cfg->host_capab = __cpu_to_le32(0); - ath10k_wmi_put_host_mem_chunks(ar, chunks); + ath10k_wmi_tlv_put_host_mem_chunks(ar, chunks); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv init\n"); return skb; From a914560cbc496487bbd63e31d37251484ee4fdde Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Sat, 21 Sep 2019 14:12:54 +0530 Subject: [PATCH 165/192] ath10k: Fix compilation error in host cap due to downstream QMI struct qmi_elem_info members in downstream kernel are not in sync with up streamed implementation. In order to enable compilation with down streamed implementation use downstream qmi_elem_info definition. Change-Id: Ife64900aeb3d963bc763467ab912b0224298080d Signed-off-by: Govind Singh --- .../net/wireless/ath/ath10k/qmi_wlfw_v01.c | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c index 2f3b13ab9864..7ace965e6115 100644 --- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c +++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c @@ -1766,7 +1766,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, daemon_support), @@ -1775,7 +1775,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, wake_msi_valid), @@ -1784,7 +1784,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, wake_msi), @@ -1793,7 +1793,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, gpios_valid), @@ -1802,7 +1802,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, gpios_len), @@ -1811,7 +1811,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = QMI_WLFW_MAX_NUM_GPIO_V01, .elem_size = sizeof(u32), - .array_type = VAR_LEN_ARRAY, + .is_array = VAR_LEN_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, gpios), @@ -1820,7 +1820,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, nm_modem_valid), @@ -1829,7 +1829,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x13, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, nm_modem), @@ -1838,7 +1838,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x14, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, bdf_support_valid), @@ -1847,7 +1847,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x14, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, bdf_support), @@ -1856,7 +1856,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x15, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, bdf_cache_support_valid), @@ -1865,7 +1865,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x15, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, bdf_cache_support), @@ -1874,7 +1874,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x16, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, m3_support_valid), @@ -1883,7 +1883,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x16, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, m3_support), @@ -1892,7 +1892,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x17, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, m3_cache_support_valid), @@ -1901,7 +1901,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x17, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, m3_cache_support), @@ -1910,7 +1910,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x18, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, cal_filesys_support_valid), @@ -1919,7 +1919,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x18, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, cal_filesys_support), @@ -1928,7 +1928,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x19, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, cal_cache_support_valid), @@ -1937,7 +1937,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x19, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, cal_cache_support), @@ -1946,7 +1946,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x1A, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, cal_done_valid), @@ -1955,7 +1955,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x1A, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, cal_done), @@ -1964,7 +1964,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x1B, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, mem_bucket_valid), @@ -1973,7 +1973,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, .elem_size = sizeof(u32), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x1B, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, mem_bucket), @@ -1982,7 +1982,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x1C, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, mem_cfg_mode_valid), @@ -1991,7 +1991,7 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), - .array_type = NO_ARRAY, + .is_array = NO_ARRAY, .tlv_type = 0x1C, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, mem_cfg_mode), From d5cfaf8c86a96df954be5c796ef77a9e50c2cc52 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 11 Oct 2018 13:16:01 +0300 Subject: [PATCH 166/192] firmware: qcom: scm: Add WLAN VMID for Qualcomm SCM interface Add WLAN related VMID's to support wlan driver to set up the remote's permissions call via TrustZone. Signed-off-by: Govind Singh Reviewed-by: Bjorn Andersson Acked-by: Niklas Cassel Reviewed-by: Brian Norris Signed-off-by: Kalle Valo Git-commit: cc53aabcc283c36274d3f3ce9adc4b40c21d4838 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Change-Id: I4b2380db750b57cf945c5718b201b811b13110db Signed-off-by: Dundi Raviteja --- include/linux/qcom_scm.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index 0723b96beb0e..017da1cc1fb2 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -30,6 +30,8 @@ struct qcom_scm_vmperm { #define QCOM_SCM_VMID_HLOS 0x3 #define QCOM_SCM_VMID_MSS_MSA 0xF +#define QCOM_SCM_VMID_WLAN 0x18 +#define QCOM_SCM_VMID_WLAN_CE 0x19 #define QCOM_SCM_PERM_READ 0x4 #define QCOM_SCM_PERM_WRITE 0x2 #define QCOM_SCM_PERM_EXEC 0x1 From 120a2beaa2243b42d061673b8687118bd528e992 Mon Sep 17 00:00:00 2001 From: Dundi Raviteja Date: Tue, 21 Jul 2020 20:19:13 +0530 Subject: [PATCH 167/192] ARM: dts: msm8916: Update reserved-memory for wcnss, venus and mba Reserved memory for wcnss, venus and mba nodes updated mistakenly in earlier commit. Revert them back to original values. Change-Id: I17e11d8ce161b0802fbd8bd81e6e830f7f586024 Fixes: 8c5aade5252c ("UPSTREAM: ath10k: support extended board data download for dual-band QCA9984) Signed-off-by: Dundi Raviteja --- arch/arm64/boot/dts/qcom/msm8916.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index ee36196df1d1..4a8f48564538 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2015, 2020 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -84,18 +84,18 @@ }; wcnss_mem: wcnss@89300000 { - reg = <0x0 0x89300000 0x0 0x700000>; + reg = <0x0 0x89300000 0x0 0x600000>; no-map; }; venus_mem: venus@89900000 { - reg = <0x0 0x89A00000 0x0 0x600000>; + reg = <0x0 0x89900000 0x0 0x600000>; no-map; }; mba_mem: mba@8ea00000 { no-map; - reg = <0 0x8A000000 0 0x100000>; + reg = <0 0x8ea00000 0 0x100000>; }; }; From fe984af7f5f70e72ffb3a0fc42c997e0c1261610 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Wed, 28 Aug 2019 10:16:17 +0530 Subject: [PATCH 168/192] ath10k: Enable IOMMU support for WCN3990 target When an IOMMU device is available on the platform bus, allocate an IOMMU domain and attach the wlan target to it. WCN3990 target can then attach an DMA I/O virtual address space to scan out of bound transactions. Change-Id: I3c741af1614cb5088c8127d9a0092c9f0c53496f Signed-off-by: Govind Singh --- drivers/net/wireless/ath/ath10k/snoc.c | 99 +++++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/snoc.h | 3 + 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index f9f527a96a24..ff9787cdec88 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -21,6 +21,9 @@ #include #include #include +#include +#include +#include #include "ce.h" #include "debug.h" @@ -1521,6 +1524,88 @@ static int ath10k_hw_power_off(struct ath10k *ar) return ret; } +static int ath10k_smmu_attach(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct dma_iommu_mapping *mapping; + struct platform_device *pdev; + int ret = 0; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "Initializing SMMU\n"); + + pdev = ar_snoc->dev; + mapping = arm_iommu_create_mapping(&platform_bus_type, + ar_snoc->smmu_iova_start, + ar_snoc->smmu_iova_len); + if (IS_ERR(mapping)) { + ath10k_err(ar, "create mapping failed, err = %d\n", ret); + ret = PTR_ERR(mapping); + goto map_fail; + } + + ret = arm_iommu_attach_device(&pdev->dev, mapping); + if (ret < 0 && ret != -EEXIST) { + ath10k_err(ar, "iommu attach device failed, err = %d\n", ret); + goto attach_fail; + } else if (ret == -EEXIST) { + ret = 0; + } + + ar_snoc->smmu_mapping = mapping; + + return ret; + +attach_fail: + arm_iommu_release_mapping(mapping); +map_fail: + return ret; +} + +static void ath10k_smmu_deinit(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct platform_device *pdev; + + pdev = ar_snoc->dev; + + if (!ar_snoc->smmu_mapping) + return; + + arm_iommu_detach_device(&pdev->dev); + arm_iommu_release_mapping(ar_snoc->smmu_mapping); + + ar_snoc->smmu_mapping = NULL; +} + +static int ath10k_smmu_init(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct platform_device *pdev; + struct resource *res; + int ret = 0; + + pdev = ar_snoc->dev; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "smmu_iova_base"); + if (!res) { + ath10k_err(ar, "SMMU iova base not found\n"); + } else { + ar_snoc->smmu_iova_start = res->start; + ar_snoc->smmu_iova_len = resource_size(res); + ath10k_dbg(ar, ATH10K_DBG_SNOC, "SMMU iova start: %pa, len: %zu\n", + &ar_snoc->smmu_iova_start, ar_snoc->smmu_iova_len); + + ret = ath10k_smmu_attach(ar); + if (ret < 0) { + ath10k_err(ar, "SMMU init failed, err = %d, start: %pad, len: %zx\n", + ret, &ar_snoc->smmu_iova_start, + ar_snoc->smmu_iova_len); + } + } + + return ret; +} + static const struct of_device_id ath10k_snoc_dt_match[] = { { .compatible = "qcom,wcn3990-wifi", .data = &drv_priv, @@ -1570,16 +1655,22 @@ static int ath10k_snoc_probe(struct platform_device *pdev) ar->ce_priv = &ar_snoc->ce; msa_size = drv_data->msa_size; + ret = ath10k_smmu_init(ar); + if (ret) { + ath10k_warn(ar, "failed to int SMMU: %d\n", ret); + goto err_core_destroy; + } + ret = ath10k_snoc_resource_init(ar); if (ret) { ath10k_warn(ar, "failed to initialize resource: %d\n", ret); - goto err_core_destroy; + goto err_smmu_deinit; } ret = ath10k_snoc_setup_resource(ar); if (ret) { ath10k_warn(ar, "failed to setup resource: %d\n", ret); - goto err_core_destroy; + goto err_smmu_deinit; } ret = ath10k_snoc_request_irq(ar); if (ret) { @@ -1624,6 +1715,9 @@ static int ath10k_snoc_probe(struct platform_device *pdev) err_release_resource: ath10k_snoc_release_resource(ar); +err_smmu_deinit: + ath10k_smmu_deinit(ar); + err_core_destroy: ath10k_core_destroy(ar); @@ -1637,6 +1731,7 @@ static int ath10k_snoc_remove(struct platform_device *pdev) ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc remove\n"); ath10k_core_unregister(ar); ath10k_hw_power_off(ar); + ath10k_smmu_deinit(ar); ath10k_snoc_free_irq(ar); ath10k_snoc_release_resource(ar); ath10k_qmi_deinit(ar); diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index e1d2d6675556..524c2dfa0024 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -84,6 +84,9 @@ struct ath10k_snoc { struct ath10k_wcn3990_vreg_info *vreg; struct ath10k_wcn3990_clk_info *clk; struct ath10k_qmi *qmi; + struct dma_iommu_mapping *smmu_mapping; + dma_addr_t smmu_iova_start; + size_t smmu_iova_len; }; static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) From 8f465455e919085784ea961dd04fdd53b3a025f1 Mon Sep 17 00:00:00 2001 From: Surendar karka Date: Tue, 2 Jun 2020 11:57:11 +0530 Subject: [PATCH 169/192] uapi: sound: add TTP pass through run mode command Add RUN_WITH_TTP_PASS_THROUGH run mode to support split A2Dp source usecase with TTP. Change-Id: I0490464b4620dcde9b777d6d48b1e25ecd3eca7b Signed-off-by: Surendar karka --- include/uapi/sound/compress_offload.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h index 5f0fd5ebb94a..3a50f6ca1619 100644 --- a/include/uapi/sound/compress_offload.h +++ b/include/uapi/sound/compress_offload.h @@ -137,6 +137,7 @@ struct snd_compr_audio_info { #define SNDRV_COMPRESS_RENDER_MODE_AUDIO_MASTER 0 #define SNDRV_COMPRESS_RENDER_MODE_STC_MASTER 1 #define SNDRV_COMPRESS_RENDER_MODE_TTP 2 +#define SNDRV_COMPRESS_RENDER_MODE_TTP_PASS_THROUGH 3 #define SNDRV_COMPRESS_CLK_REC_MODE_NONE 0 #define SNDRV_COMPRESS_CLK_REC_MODE_AUTO 1 From 31aa4a85e2fc8941ec9f10cb32b0b55ba79f56e5 Mon Sep 17 00:00:00 2001 From: Neeraja P Date: Wed, 5 Aug 2020 23:23:19 +0530 Subject: [PATCH 170/192] msm: kgsl: Fix possible use-after-free while adding context to active list Consider a scenario where a context is valid when the check is made in adreno_dispatcher_queue_cmds(), but by the time we reach _track_context(), context has been detached. We would try to delete the entry from the active context list as part of detaching the context though the entry is not added yet. Now in _track_context() the context is actually added. When the context is finally destroyed, we would be left with invalid entry in the list. Next time when a context is added, an attempt would be made to use a freed entry. Fix this by moving the entry deletion part under drawctxt lock. Change-Id: Idab7cbf10987598b3e6395b2d50c20d1990d1f02 Signed-off-by: Puranam V G Tejaswi Signed-off-by: Neeraja P --- drivers/gpu/msm/adreno_drawctxt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c index df8e8acecb4c..aa945a4bd302 100644 --- a/drivers/gpu/msm/adreno_drawctxt.c +++ b/drivers/gpu/msm/adreno_drawctxt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -487,11 +487,12 @@ void adreno_drawctxt_detach(struct kgsl_context *context) drawctxt = ADRENO_CONTEXT(context); rb = drawctxt->rb; + spin_lock(&drawctxt->lock); + spin_lock(&adreno_dev->active_list_lock); list_del_init(&drawctxt->active_node); spin_unlock(&adreno_dev->active_list_lock); - spin_lock(&drawctxt->lock); count = drawctxt_detach_drawobjs(drawctxt, list); spin_unlock(&drawctxt->lock); From bbe08997a9e5604343c0f9aeeec2a04cba710544 Mon Sep 17 00:00:00 2001 From: Rohith Kollalsi Date: Fri, 17 Jul 2020 15:00:44 +0530 Subject: [PATCH 171/192] usb: gadget: Revert increase write buffer size Commit 3fb319966d33 ("usb: gadget: increase write buffer size") brings additional memory requirement and leads to memory allocation failure when trying to allocate buffer to the request in usb_cser_alloc_req. Hence revert it to fix this. Change-Id: Iff5d6a2502d7ff094422fc66c20dff13d5b8d4ca Signed-off-by: Rohith Kollalsi --- drivers/usb/gadget/function/f_cdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c index 79cd361fe8db..e12ab6b67d36 100644 --- a/drivers/usb/gadget/function/f_cdev.c +++ b/drivers/usb/gadget/function/f_cdev.c @@ -57,7 +57,7 @@ #define BRIDGE_RX_QUEUE_SIZE 8 #define BRIDGE_RX_BUF_SIZE 2048 #define BRIDGE_TX_QUEUE_SIZE 8 -#define BRIDGE_TX_BUF_SIZE (50 * 1024) +#define BRIDGE_TX_BUF_SIZE 2048 #define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */ #define GS_NOTIFY_MAXPACKET 10 /* notification + 2 bytes */ From 478fbba9ca984b063796ed00e2e7d4c645fbf8fb Mon Sep 17 00:00:00 2001 From: Vipin Deep Kaur Date: Wed, 8 Jul 2020 13:00:58 +0530 Subject: [PATCH 172/192] spi: spi-geni-qcom: Return error if setup transfer fails setup_fifo_xfer/setup_gsi_xfer api may fail while transfer preparation, return error to the client in such case instead of advancing with the erroneous transfer to prevent unpredictable transfer scenarios. Change-Id: Ic02285df53713c813b56d88ad4d6731ace72d54a Signed-off-by: Vipin Deep Kaur Signed-off-by: Ashish Kori --- drivers/spi/spi-geni-qcom.c | 42 ++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index 5577567eab5b..265ab54b20ac 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1044,10 +1044,11 @@ static int spi_geni_unprepare_transfer_hardware(struct spi_master *spi) return 0; } -static void setup_fifo_xfer(struct spi_transfer *xfer, +static int setup_fifo_xfer(struct spi_transfer *xfer, struct spi_geni_master *mas, u16 mode, struct spi_master *spi) { + int ret = 0; u32 m_cmd = 0; u32 m_param = 0; u32 spi_tx_cfg = geni_read_reg(mas->base, SE_SPI_TRANS_CFG); @@ -1060,7 +1061,6 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, /* Speed and bits per word can be overridden per transfer */ if (xfer->speed_hz != mas->cur_speed_hz) { - int ret = 0; u32 clk_sel = 0; u32 m_clk_cfg = 0; int idx = 0; @@ -1070,7 +1070,7 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, if (ret) { dev_err(mas->dev, "%s:Err setting clks:%d\n", __func__, ret); - return; + return ret; } mas->cur_speed_hz = xfer->speed_hz; clk_sel |= (idx & CLK_SEL_MSK); @@ -1151,13 +1151,14 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, __func__, trans_len, xfer->len, spi_tx_cfg, m_cmd, xfer->cs_change, mas->cur_xfer_mode); if ((m_cmd & SPI_RX_ONLY) && (mas->cur_xfer_mode == SE_DMA)) { - int ret = 0; - ret = geni_se_rx_dma_prep(mas->wrapper_dev, mas->base, xfer->rx_buf, xfer->len, &xfer->rx_dma); - if (ret) + if (ret) { GENI_SE_ERR(mas->ipc, true, mas->dev, "Failed to setup Rx dma %d\n", ret); + xfer->rx_dma = 0; + return ret; + } } if (m_cmd & SPI_TX_ONLY) { if (mas->cur_xfer_mode == FIFO_MODE) { @@ -1169,14 +1170,18 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, ret = geni_se_tx_dma_prep(mas->wrapper_dev, mas->base, (void *)xfer->tx_buf, xfer->len, &xfer->tx_dma); - if (ret) + if (ret) { GENI_SE_ERR(mas->ipc, true, mas->dev, "Failed to setup tx dma %d\n", ret); + xfer->tx_dma = 0; + return ret; + } } } /* Ensure all writes are done before the WM interrupt */ mb(); + return ret; } static void handle_fifo_timeout(struct spi_geni_master *mas, @@ -1204,10 +1209,10 @@ static void handle_fifo_timeout(struct spi_geni_master *mas, "Failed to cancel/abort m_cmd\n"); } if (mas->cur_xfer_mode == SE_DMA) { - if (xfer->tx_buf) + if (xfer->tx_buf && xfer->tx_dma) geni_se_tx_dma_unprep(mas->wrapper_dev, xfer->tx_dma, xfer->len); - if (xfer->rx_buf) + if (xfer->rx_buf && xfer->rx_dma) geni_se_rx_dma_unprep(mas->wrapper_dev, xfer->rx_dma, xfer->len); } @@ -1235,7 +1240,14 @@ static int spi_geni_transfer_one(struct spi_master *spi, if (mas->cur_xfer_mode != GSI_DMA) { reinit_completion(&mas->xfer_done); - setup_fifo_xfer(xfer, mas, slv->mode, spi); + ret = setup_fifo_xfer(xfer, mas, slv->mode, spi); + if (ret) { + GENI_SE_ERR(mas->ipc, true, mas->dev, + "setup_fifo_xfer failed: %d\n", ret); + mas->cur_xfer = NULL; + goto err_fifo_geni_transfer_one; + } + if (spi->slave) spi->slave_state = true; mutex_unlock(&mas->spi_ssr.ssr_lock); @@ -1274,7 +1286,13 @@ static int spi_geni_transfer_one(struct spi_master *spi, reinit_completion(&mas->tx_cb); reinit_completion(&mas->rx_cb); - setup_gsi_xfer(xfer, mas, slv, spi); + ret = setup_gsi_xfer(xfer, mas, slv, spi); + if (ret) { + GENI_SE_ERR(mas->ipc, true, mas->dev, + "setup_gsi_xfer failed: %d\n", ret); + mas->cur_xfer = NULL; + goto err_gsi_geni_transfer_one; + } if ((mas->num_xfers >= NUM_SPI_XFER) || (list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))) { From 1aaf55e06de33fb9597bc4f663859c35ef50d33a Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Fri, 17 Apr 2020 18:48:22 +0530 Subject: [PATCH 173/192] msm: camera: reqmgr: Stop slot reset on buf done This change is to stop slot reset on link in case of buf done. If slot is required for applying either next or previous request on sync link, then stop the slot reset for the link. Change-Id: I296e450de94e273d17b1a9bb0879d879a63414f4 Signed-off-by: Ayush Kumar --- .../msm/camera/cam_req_mgr/cam_req_mgr_core.c | 54 ++++++++++++++++--- 1 file changed, 48 insertions(+), 6 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 a022989aa256..5bdf3f87de0d 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 @@ -2257,6 +2257,42 @@ int cam_req_mgr_process_error(void *priv, void *data) return rc; } +static void cam_req_mgr_process_reset_for_dual_link( + struct cam_req_mgr_core_link *link, + struct cam_req_mgr_trigger_notify *trigger_data) +{ + int32_t idx = -1; + int32_t sync_idx = -1; + struct cam_req_mgr_req_queue *in_q = NULL; + struct cam_req_mgr_req_queue *sync_in_q = NULL; + + in_q = link->req.in_q; + sync_in_q = link->sync_link->req.in_q; + + sync_idx = __cam_req_mgr_find_slot_for_req(sync_in_q, + trigger_data->req_id); + if (link->is_master) + __cam_req_mgr_dec_idx(&sync_idx, + (link->max_delay - link->sync_link->max_delay), + sync_in_q->num_slots); + else + __cam_req_mgr_inc_idx(&sync_idx, + (link->sync_link->max_delay - link->max_delay), + sync_in_q->num_slots); + if (sync_idx != -1 && + (sync_in_q->slot[sync_in_q->rd_idx].status == + CRM_SLOT_STATUS_REQ_APPLIED)) { + idx = __cam_req_mgr_find_slot_for_req(in_q, + trigger_data->req_id); + CAM_DBG(CAM_CRM, "Reset req: %lld idx: %d link_hdl: %x", + trigger_data->req_id, idx, + link->link_hdl); + if (idx == in_q->last_applied_idx) + in_q->last_applied_idx = -1; + __cam_req_mgr_reset_req_slot(link, idx); + } +} + /** * cam_req_mgr_process_trigger() * @@ -2295,12 +2331,18 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) mutex_lock(&link->req.lock); if (trigger_data->trigger == CAM_TRIGGER_POINT_SOF) { - idx = __cam_req_mgr_find_slot_for_req(in_q, - trigger_data->req_id); - if (idx >= 0) { - if (idx == in_q->last_applied_idx) - in_q->last_applied_idx = -1; - __cam_req_mgr_reset_req_slot(link, idx); + if (link->sync_link && + (link->is_master || link->sync_link->is_master)) { + cam_req_mgr_process_reset_for_dual_link(link, + trigger_data); + } else { + idx = __cam_req_mgr_find_slot_for_req(in_q, + trigger_data->req_id); + if (idx >= 0) { + if (idx == in_q->last_applied_idx) + in_q->last_applied_idx = -1; + __cam_req_mgr_reset_req_slot(link, idx); + } } } From 6b3a181fc0879f8c62cabccb6de37e3fe9c29c1c Mon Sep 17 00:00:00 2001 From: Michael Adisumarta Date: Thu, 6 Aug 2020 21:09:39 -0700 Subject: [PATCH 174/192] msm: ipa: Fix deleting the routing entries Make changes to delete the route entry even when the hdr/proc_ctx handles are already freed. Otherwise the entry will be dangling. Change-Id: Icbab6b96fa137c5214b37ea33c6203c5a54273ac Signed-off-by: Michael Adisumarta --- drivers/platform/msm/ipa/ipa_v3/ipa_rt.c | 48 ++++++++++-------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c index d1e0a90f24b7..1b332f15abcb 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c @@ -86,14 +86,16 @@ static int ipa_generate_rt_hw_rule(enum ipa_ip_type ip, if (entry->hdr) { hdr_entry = ipa3_id_find(entry->rule.hdr_hdl); - if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) { + if (!hdr_entry || (hdr_entry->cookie != IPA_HDR_COOKIE) || + ipa3_check_idr_if_freed(entry->hdr)) { IPAERR_RL("Header entry already deleted\n"); return -EPERM; } } else if (entry->proc_ctx) { hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl); if (!hdr_proc_entry || - hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) { + (hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) || + ipa3_check_idr_if_freed(entry->proc_ctx)) { IPAERR_RL("Proc header entry already deleted\n"); return -EPERM; } @@ -1745,18 +1747,19 @@ int __ipa3_del_rt_rule(u32 rule_hdl) hdr_entry = ipa3_id_find(entry->rule.hdr_hdl); if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) { IPAERR_RL("Header entry already deleted\n"); - return -EINVAL; + entry->hdr = NULL; } } else if (entry->proc_ctx) { hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl); if (!hdr_proc_entry || hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) { IPAERR_RL("Proc header entry already deleted\n"); - return -EINVAL; + entry->proc_ctx = NULL; } } - if (entry->hdr) + if (entry->hdr && + (!ipa3_check_idr_if_freed(entry->hdr))) __ipa3_release_hdr(entry->hdr->id); else if (entry->proc_ctx && (!ipa3_check_idr_if_freed(entry->proc_ctx))) @@ -1933,7 +1936,6 @@ int ipa3_reset_rt(enum ipa_ip_type ip, bool user_only) if (!user_only || rule->ipacm_installed) { - list_del(&rule->link); if (rule->hdr) { hdr_entry = ipa3_id_find( rule->rule.hdr_hdl); @@ -1941,8 +1943,7 @@ int ipa3_reset_rt(enum ipa_ip_type ip, bool user_only) hdr_entry->cookie != IPA_HDR_COOKIE) { IPAERR_RL( "Header already deleted\n"); - mutex_unlock(&ipa3_ctx->lock); - return -EINVAL; + rule->hdr = NULL; } } else if (rule->proc_ctx) { hdr_proc_entry = @@ -1953,12 +1954,13 @@ int ipa3_reset_rt(enum ipa_ip_type ip, bool user_only) IPA_PROC_HDR_COOKIE) { IPAERR_RL( "Proc entry already deleted\n"); - mutex_unlock(&ipa3_ctx->lock); - return -EINVAL; + rule->proc_ctx = NULL; } } tbl->rule_cnt--; - if (rule->hdr) + list_del(&rule->link); + if (rule->hdr && + (!ipa3_check_idr_if_freed(rule->hdr))) __ipa3_release_hdr(rule->hdr->id); else if (rule->proc_ctx && (!ipa3_check_idr_if_freed( @@ -2135,20 +2137,8 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy_i *rtrule) struct ipa3_hdr_entry *hdr_entry; struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry; - if (rtrule->rule.hdr_hdl) { - hdr = ipa3_id_find(rtrule->rule.hdr_hdl); - if ((hdr == NULL) || (hdr->cookie != IPA_HDR_COOKIE)) { - IPAERR_RL("rt rule does not point to valid hdr\n"); - goto error; - } - } else if (rtrule->rule.hdr_proc_ctx_hdl) { - proc_ctx = ipa3_id_find(rtrule->rule.hdr_proc_ctx_hdl); - if ((proc_ctx == NULL) || - (proc_ctx->cookie != IPA_PROC_HDR_COOKIE)) { - IPAERR_RL("rt rule does not point to valid proc ctx\n"); - goto error; - } - } + if (__ipa_rt_validate_hndls(&rtrule->rule, &hdr, &proc_ctx)) + goto error; entry = ipa3_id_find(rtrule->rt_rule_hdl); if (entry == NULL) { @@ -2171,14 +2161,16 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy_i *rtrule) if (entry->hdr) { hdr_entry = ipa3_id_find(entry->rule.hdr_hdl); - if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) { + if (!hdr_entry || (hdr_entry->cookie != IPA_HDR_COOKIE) || + ipa3_check_idr_if_freed(entry->hdr)) { IPAERR_RL("Header entry already deleted\n"); return -EPERM; } } else if (entry->proc_ctx) { hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl); if (!hdr_proc_entry || - hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) { + (hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) || + ipa3_check_idr_if_freed(entry->proc_ctx)) { IPAERR_RL("Proc header entry already deleted\n"); return -EPERM; } @@ -2186,7 +2178,7 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy_i *rtrule) if (entry->hdr) entry->hdr->ref_cnt--; - if (entry->proc_ctx) + else if (entry->proc_ctx) entry->proc_ctx->ref_cnt--; entry->rule = rtrule->rule; From dfc7dff8f48ff6e360f3a24ac4c244e1bc6df6ac Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Fri, 7 Aug 2020 10:55:31 +0530 Subject: [PATCH 175/192] mhi: netdev: Avoid free of netdev client,ipc handles Change involves to avoid free of mhi netdev client, ipc handles as part of mhi_dev_net_state_cb(). These are not re-allocated in mhi_dev_net_interface_init() as mhi_net_ctxt.client_handle is already valid which is called during device reset scenario. Change-Id: I6f660c8dccd47a93c115c39d2898f450c5d61635 Signed-off-by: Subramanian Ananthanarayanan --- drivers/platform/msm/mhi_dev/mhi_dev_net.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi_dev_net.c b/drivers/platform/msm/mhi_dev/mhi_dev_net.c index c61bec66eaf6..cf1cc41472c3 100644 --- a/drivers/platform/msm/mhi_dev/mhi_dev_net.c +++ b/drivers/platform/msm/mhi_dev/mhi_dev_net.c @@ -702,8 +702,6 @@ static void mhi_dev_net_state_cb(struct mhi_dev_client_cb_data *cb_data) mhi_dev_net_free_reqs(&mhi_client->wr_req_buffers); free_netdev(mhi_client->dev); mhi_client->dev = NULL; - kfree(mhi_client); - kfree(mhi_net_ipc_log); } } } From 253b3b2528b32c4254d739161060412bf16f39b0 Mon Sep 17 00:00:00 2001 From: Kavya Nunna Date: Wed, 5 Aug 2020 17:26:55 +0530 Subject: [PATCH 176/192] power: smb1398-charger: Fix use of uninitialized variable error Fix use of uninitiallized variable error in function smb1398_taper_work. Change-Id: I5a86fc7b879cbe3c31556645ad4808ac1b8f7ae2 Signed-off-by: Kavya Nunna --- drivers/power/supply/qcom/smb1398-charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/smb1398-charger.c b/drivers/power/supply/qcom/smb1398-charger.c index d52d1410d7eb..62396c59a32e 100644 --- a/drivers/power/supply/qcom/smb1398-charger.c +++ b/drivers/power/supply/qcom/smb1398-charger.c @@ -1755,7 +1755,7 @@ static void smb1398_taper_work(struct work_struct *work) struct smb1398_chip *chip = container_of(work, struct smb1398_chip, taper_work); union power_supply_propval pval = {0}; - int rc, fcc_ua, fv_uv, stepper_ua, main_fcc_ua, min_ilim_ua; + int rc, fcc_ua, fv_uv, stepper_ua, main_fcc_ua = 0, min_ilim_ua; bool slave_en; if (!is_psy_voter_available(chip)) From 6ef6da4278aad9c11d3255d1c9a85b5bfbb4806f Mon Sep 17 00:00:00 2001 From: Michael Adisumarta Date: Thu, 6 Aug 2020 16:07:33 -0700 Subject: [PATCH 177/192] msm: ipa: header file to support wdi 2.4G new pipe Header file changes that includes new 2.4G wdi tx pipe info and it's interface. Change-Id: I0bc77f8359152f8209ec4ef132dc6497d0875c2a Signed-off-by: Michael Adisumarta --- include/linux/ipa_wdi3.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/include/linux/ipa_wdi3.h b/include/linux/ipa_wdi3.h index bdbeb2ffd8e9..965b3d95b8f5 100644 --- a/include/linux/ipa_wdi3.h +++ b/include/linux/ipa_wdi3.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -89,6 +89,7 @@ struct ipa_wdi_hdr_info { * @is_meta_data_valid: if meta data is valid * @meta_data: meta data if any * @meta_data_mask: meta data mask + * @is_tx1_used: to indicate whether 2.4g or 5g iface */ struct ipa_wdi_reg_intf_in_params { const char *netdev_name; @@ -97,6 +98,7 @@ struct ipa_wdi_reg_intf_in_params { u8 is_meta_data_valid; u32 meta_data; u32 meta_data_mask; + u8 is_tx1_used; }; /** @@ -189,6 +191,9 @@ struct ipa_wdi_pipe_setup_info_smmu { * @tx_smmu: smmu parameters to connect TX pipe(from IPA to WLAN) * @rx: parameters to connect RX pipe(from WLAN to IPA) * @rx_smmu: smmu parameters to connect RX pipe(from WLAN to IPA) + * @is_tx1_used: to notify extra pipe required/not + * @tx1: parameters to connect TX1 pipe(from IPA to WLAN second pipe) + * @tx1_smmu: smmu parameters to connect TX1 pipe(from IPA to WLAN second pipe) */ struct ipa_wdi_conn_in_params { ipa_notify_cb notify; @@ -204,6 +209,11 @@ struct ipa_wdi_conn_in_params { struct ipa_wdi_pipe_setup_info rx; struct ipa_wdi_pipe_setup_info_smmu rx_smmu; } u_rx; + bool is_tx1_used; + union { + struct ipa_wdi_pipe_setup_info tx; + struct ipa_wdi_pipe_setup_info_smmu tx_smmu; + } u_tx1; }; /** @@ -211,10 +221,12 @@ struct ipa_wdi_conn_in_params { * to WLAN driver * @tx_uc_db_pa: physical address of IPA uC doorbell for TX * @rx_uc_db_pa: physical address of IPA uC doorbell for RX + * @tx1_uc_db_pa: physical address of IPA uC doorbell for TX1 */ struct ipa_wdi_conn_out_params { phys_addr_t tx_uc_db_pa; phys_addr_t rx_uc_db_pa; + phys_addr_t tx1_uc_db_pa; }; /** From 9af818a04d60e99af70d9d95536af9b3e75ae63f Mon Sep 17 00:00:00 2001 From: Ashok Vuyyuru Date: Wed, 5 Aug 2020 19:17:30 +0530 Subject: [PATCH 178/192] msm: ipa3: Fix to save the ntn buffers in SMMU disabled case Not able to unmap the buffers due not saving data buffers when SMMU disabled on EMAC side. Adding changes to save the data buffer list in EMAC SMMU disabled case also. Change-Id: Ia22110b450477927c35942f2161c2730086da892 Signed-off-by: Ashok Vuyyuru --- .../msm/ipa/ipa_clients/ipa_uc_offload.c | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c index 7090b63f4cc3..67ed1fd76347 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c @@ -540,20 +540,16 @@ int ipa_uc_ntn_conn_pipes(struct ipa_ntn_conn_in_params *inp, goto fail; } - if (ntn_ctx->conn.dl.smmu_enabled) { - result = ipa_uc_ntn_alloc_conn_smmu_info(&ntn_ctx->conn.dl, - &inp->dl); - if (result) { - IPA_UC_OFFLOAD_ERR("alloc failure on TX\n"); - goto fail; - } - result = ipa_uc_ntn_alloc_conn_smmu_info(&ntn_ctx->conn.ul, - &inp->ul); - if (result) { - ipa_uc_ntn_free_conn_smmu_info(&ntn_ctx->conn.dl); - IPA_UC_OFFLOAD_ERR("alloc failure on RX\n"); - goto fail; - } + result = ipa_uc_ntn_alloc_conn_smmu_info(&ntn_ctx->conn.dl, &inp->dl); + if (result) { + IPA_UC_OFFLOAD_ERR("alloc failure on TX\n"); + goto fail; + } + result = ipa_uc_ntn_alloc_conn_smmu_info(&ntn_ctx->conn.ul, &inp->ul); + if (result) { + ipa_uc_ntn_free_conn_smmu_info(&ntn_ctx->conn.dl); + IPA_UC_OFFLOAD_ERR("alloc failure on RX\n"); + goto fail; } fail: From 8eac8b9a077e1d1e0774d1bef28ad62506f5ad56 Mon Sep 17 00:00:00 2001 From: Pradeep P V K Date: Thu, 9 Jul 2020 19:35:17 +0530 Subject: [PATCH 179/192] mtd: msm_qpic_nand: Skip erased page check upon error Skip erased page check upon error. Change-Id: I08ea01fdccd6896f83a42758652e19949e3d1b0e Signed-off-by: Pradeep P V K --- drivers/mtd/devices/msm_qpic_nand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c index ea6c4ed2c1f8..1149a1688414 100644 --- a/drivers/mtd/devices/msm_qpic_nand.c +++ b/drivers/mtd/devices/msm_qpic_nand.c @@ -1984,7 +1984,7 @@ static int msm_nand_is_erased_page_ps(struct mtd_info *mtd, loff_t from, total_ecc_byte_cnt, DMA_FROM_DEVICE); /* check for bit flips in ecc data */ ecc_temp = ecc; - for (n = rw_params->start_sector; n < cwperpage; n++) { + for (n = rw_params->start_sector; !err && n < cwperpage; n++) { int last_pos = 0, next_pos = 0; int ecc_bytes_percw_in_bits = (chip->ecc_parity_bytes * 8); @@ -2624,7 +2624,7 @@ static int msm_nand_is_erased_page(struct mtd_info *mtd, loff_t from, total_ecc_byte_cnt, DMA_FROM_DEVICE); /* check for bit flips in ecc data */ ecc_temp = ecc; - for (n = rw_params->start_sector; n < cwperpage; n++) { + for (n = rw_params->start_sector; !err && n < cwperpage; n++) { int last_pos = 0, next_pos = 0; int ecc_bytes_percw_in_bits = (chip->ecc_parity_bytes * 8); From 3de255f883569c29fd90efbc67108a0460bc30fb Mon Sep 17 00:00:00 2001 From: Anjana Hari Date: Thu, 18 Jun 2020 22:24:24 +0530 Subject: [PATCH 180/192] mtd: msm_qpic_nand: Add support to read one codeword When the read requests received from upper layer are less than 516 bytes, then instead of reading the entire page, we can read only one codeword, thereby improving the read performance. This support is only applicable if the data requested lies in first codeword of the page. Modem KPI markers: All units in seconds | Parameter | With OCW | W/o OCW | Delta | | Modem Image Start Loading | 13.5542 | 14.6176 | 1.0634| | Modem out of reset | 19.8452 | 20.9962 | 1.151 | NAND Perf Stats: Obtained by reading 1GB data. All units in usec | Parameter | With OCW | W/o OCW | Delta | | min_read_time_us | 70 | 340.6 | 270.6 | | total_read_time_us | 17737604 | 18603376| 865772|. Change-Id: I1df9ea7b9193a900b38e3d7a4fe38e2212bbf705 Signed-off-by: Anjana Hari --- drivers/mtd/devices/msm_qpic_nand.c | 86 ++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 19 deletions(-) diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c index ea6c4ed2c1f8..544c66cecfd1 100644 --- a/drivers/mtd/devices/msm_qpic_nand.c +++ b/drivers/mtd/devices/msm_qpic_nand.c @@ -26,6 +26,8 @@ #define MAX_DESC 16 #define SMEM_AARM_PARTITION_TABLE 9 #define SMEM_APPS 0 +#define ONE_CODEWORD_SIZE 516 + static bool enable_euclean; static bool enable_perfstats; @@ -1183,10 +1185,16 @@ static int msm_nand_validate_mtd_params(struct mtd_info *mtd, bool read, err = -EINVAL; goto out; } - args->page_count = ops->len / (mtd->writesize + mtd->oobsize); + if (ops->len <= ONE_CODEWORD_SIZE) + args->page_count = 1; + else + args->page_count = ops->len / + (mtd->writesize + mtd->oobsize); } else if (ops->mode == MTD_OPS_AUTO_OOB) { - if (ops->datbuf && (ops->len % mtd->writesize) != 0) { + if (ops->datbuf && (ops->len % + ((ops->len <= ONE_CODEWORD_SIZE) ? + ONE_CODEWORD_SIZE : mtd->writesize)) != 0) { /* when ops->datbuf is NULL, ops->len can be ooblen */ pr_err("unsupported data len %d for AUTO mode\n", ops->len); @@ -1199,7 +1207,10 @@ static int msm_nand_validate_mtd_params(struct mtd_info *mtd, bool read, if ((args->page_count == 0) && (ops->ooblen)) args->page_count = 1; } else if (ops->datbuf) { - args->page_count = ops->len / mtd->writesize; + if (ops->len <= ONE_CODEWORD_SIZE) + args->page_count = 1; + else + args->page_count = ops->len / mtd->writesize; } } @@ -1245,12 +1256,20 @@ static void msm_nand_update_rw_reg_data(struct msm_nand_chip *chip, struct msm_nand_rw_params *args, struct msm_nand_rw_reg_data *data) { + /* + * While reading one codeword, CW_PER_PAGE bits of QPIC_NAND_DEV0_CFG0 + * should be set to 0, which implies 1 codeword per page. 'n' below, + * is used to configure cfg0 for reading one full page or one single + * codeword. + */ + int n = (ops->len <= ONE_CODEWORD_SIZE) ? args->cwperpage : 1; + if (args->read) { if (ops->mode != MTD_OPS_RAW) { data->cmd = MSM_NAND_CMD_PAGE_READ_ECC; data->cfg0 = (chip->cfg0 & ~(7U << CW_PER_PAGE)) | - (((args->cwperpage-1) - args->start_sector) + (((args->cwperpage-n) - args->start_sector) << CW_PER_PAGE); data->cfg1 = chip->cfg1; data->ecc_bch_cfg = chip->ecc_bch_cfg; @@ -1258,7 +1277,7 @@ static void msm_nand_update_rw_reg_data(struct msm_nand_chip *chip, data->cmd = MSM_NAND_CMD_PAGE_READ_ALL; data->cfg0 = (chip->cfg0_raw & ~(7U << CW_PER_PAGE)) | - (((args->cwperpage-1) - args->start_sector) + (((args->cwperpage-n) - args->start_sector) << CW_PER_PAGE); data->cfg1 = chip->cfg1_raw; data->ecc_bch_cfg = chip->ecc_cfg_raw; @@ -1302,6 +1321,11 @@ static void msm_nand_prep_rw_cmd_desc(struct mtd_oob_ops *ops, uint32_t offset, size, last_read; struct sps_command_element *curr_ce, *start_ce; uint32_t *flags_ptr, *num_ce_ptr; + /* + * Variable to configure read_location register parameters + * while reading one codeword or one full page + */ + int n = (ops->len <= ONE_CODEWORD_SIZE) ? args->cwperpage : 1; if (curr_cw == args->start_sector) { curr_ce = start_ce = &cmd_list->setup_desc.ce[0]; @@ -1394,10 +1418,15 @@ static void msm_nand_prep_rw_cmd_desc(struct mtd_oob_ops *ops, if (ops->mode == MTD_OPS_AUTO_OOB) { if (ops->datbuf) { offset = 0; - size = (curr_cw < (args->cwperpage - 1)) ? 516 : - (512 - ((args->cwperpage - 1) << 2)); - last_read = (curr_cw < (args->cwperpage - 1)) ? 1 : - (ops->oobbuf ? 0 : 1); + if (ops->len <= ONE_CODEWORD_SIZE) { + size = ONE_CODEWORD_SIZE; + last_read = 1; + } else { + size = (curr_cw < (args->cwperpage - 1)) ? 516 : + (512 - ((args->cwperpage - 1) << 2)); + last_read = (curr_cw < (args->cwperpage - 1)) ? + 1 : (ops->oobbuf ? 0 : 1); + } rdata = (offset << 0) | (size << 16) | (last_read << 31); @@ -1413,7 +1442,7 @@ static void msm_nand_prep_rw_cmd_desc(struct mtd_oob_ops *ops, curr_ce++; } } - if (curr_cw == (args->cwperpage - 1) && ops->oobbuf) { + if (curr_cw == (args->cwperpage - n) && ops->oobbuf) { offset = 512 - ((args->cwperpage - 1) << 2); size = (args->cwperpage) << 2; if (size > args->oob_len_cmd) @@ -1471,6 +1500,11 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops, uint32_t sectordatasize, sectoroobsize; uint32_t sps_flags = 0; int err = 0; + /* + * Variable to configure sectordatasize and sectoroobsize + * while reading one codeword or one full page. + */ + int n = (ops->len <= ONE_CODEWORD_SIZE) ? args->cwperpage : 1; if (args->read) data_pipe_handle = info->sps.data_prod.handle; @@ -1479,7 +1513,7 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops, if (ops->mode == MTD_OPS_RAW) { if (ecc_parity_bytes && args->read) { - if (curr_cw == (args->cwperpage - 1)) + if (curr_cw == (args->cwperpage - n)) sps_flags |= SPS_IOVEC_FLAG_INT; /* read only ecc bytes */ @@ -1494,7 +1528,7 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops, sectordatasize = chip->cw_size; if (!args->read) sps_flags = SPS_IOVEC_FLAG_EOT; - if (curr_cw == (args->cwperpage - 1)) + if (curr_cw == (args->cwperpage - n)) sps_flags |= SPS_IOVEC_FLAG_INT; err = sps_transfer_one(data_pipe_handle, @@ -1507,8 +1541,13 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops, } } else if (ops->mode == MTD_OPS_AUTO_OOB) { if (ops->datbuf) { - sectordatasize = (curr_cw < (args->cwperpage - 1)) - ? 516 : (512 - ((args->cwperpage - 1) << 2)); + if (ops->len <= ONE_CODEWORD_SIZE) + sectordatasize = ONE_CODEWORD_SIZE; + else + sectordatasize = + (curr_cw < (args->cwperpage - 1)) + ? 516 : + (512 - ((args->cwperpage - 1) << 2)); if (!args->read) { sps_flags = SPS_IOVEC_FLAG_EOT; @@ -1516,7 +1555,7 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops, ops->oobbuf) sps_flags = 0; } - if ((curr_cw == (args->cwperpage - 1)) && !ops->oobbuf) + if ((curr_cw == (args->cwperpage - n)) && !ops->oobbuf) sps_flags |= SPS_IOVEC_FLAG_INT; err = sps_transfer_one(data_pipe_handle, @@ -1528,7 +1567,7 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops, args->data_dma_addr_curr += sectordatasize; } - if (ops->oobbuf && (curr_cw == (args->cwperpage - 1))) { + if (ops->oobbuf && (curr_cw == (args->cwperpage - n))) { sectoroobsize = args->cwperpage << 2; if (sectoroobsize > args->oob_len_data) sectoroobsize = args->oob_len_data; @@ -2728,6 +2767,9 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, data.addr0 = (rw_params.page << 16) | rw_params.oob_col; data.addr1 = (rw_params.page >> 16) & 0xff; + if (ops->len <= ONE_CODEWORD_SIZE) + cwperpage = 1; + for (n = rw_params.start_sector; n < cwperpage; n++) { struct sps_command_element *curr_ce, *start_ce; @@ -2805,7 +2847,7 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, } else if (ops->mode == MTD_OPS_AUTO_OOB) { if (ops->datbuf) submitted_num_desc = cwperpage - - rw_params.start_sector; + rw_params.start_sector; if (ops->oobbuf) submitted_num_desc++; } @@ -2998,7 +3040,10 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, } validate_mtd_params_failed: if (ops->mode != MTD_OPS_RAW) - ops->retlen = mtd->writesize * pages_read; + if (ops->len <= ONE_CODEWORD_SIZE) + ops->retlen = ONE_CODEWORD_SIZE; + else + ops->retlen = mtd->writesize * pages_read; else ops->retlen = (mtd->writesize + mtd->oobsize) * pages_read; ops->oobretlen = ops->ooblen - rw_params.oob_len_data; @@ -3071,8 +3116,11 @@ static int msm_nand_read_partial_page(struct mtd_info *mtd, ops->datbuf = no_copy ? actual_buf : bounce_buf; if (info->nand_chip.caps & MSM_NAND_CAP_PAGE_SCOPE_READ) err = msm_nand_read_pagescope(mtd, aligned_from, ops); - else + else { + if ((len <= ONE_CODEWORD_SIZE) && (offset == 0)) + ops->len = ONE_CODEWORD_SIZE; err = msm_nand_read_oob(mtd, aligned_from, ops); + } if (err == -EUCLEAN) { is_euclean = 1; err = 0; From 6b4fa3eda2c11dc78e6da323719b986f8920a8f7 Mon Sep 17 00:00:00 2001 From: Pradeep P V K Date: Mon, 10 Aug 2020 21:03:31 +0530 Subject: [PATCH 181/192] mtd: msm_qpic_nand: Use logical unit count in flash density In an ONFI compliant devices, the flash parameters are calculated by reading the onfi parameter page of the device. Existing flash density is calculated based on a single logical unit(LUN). This shows wrong density information on Multi LUN flashes. So, always use number of LUNS value in flash density calculations. Change-Id: Idba4d4e129e7fdcdab1e509bd8c3149f26fc11f2 Signed-off-by: Pradeep P V K --- drivers/mtd/devices/msm_qpic_nand.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c index ea6c4ed2c1f8..c55364232b40 100644 --- a/drivers/mtd/devices/msm_qpic_nand.c +++ b/drivers/mtd/devices/msm_qpic_nand.c @@ -1054,8 +1054,9 @@ static int msm_nand_flash_onfi_probe(struct msm_nand_info *info) flash->blksize = onfi_param_page_ptr->number_of_pages_per_block * flash->pagesize; flash->oobsize = onfi_param_page_ptr->number_of_spare_bytes_per_page; - flash->density = onfi_param_page_ptr->number_of_blocks_per_logical_unit - * flash->blksize; + flash->density = onfi_param_page_ptr->number_of_logical_units * + onfi_param_page_ptr->number_of_blocks_per_logical_unit * + flash->blksize; flash->ecc_correctability = onfi_param_page_ptr->number_of_bits_ecc_correctability; From 816c6d4fd20685a435dddc97e32384488d696433 Mon Sep 17 00:00:00 2001 From: Akshay Pandit Date: Thu, 6 Aug 2020 22:29:16 +0530 Subject: [PATCH 182/192] msm: ipa3: Define ODL DPL cons for sdx55 CPE config Define IPA_CLIENT_ODL_DPL_CONS for sdx55 in CPE config where it boots up with mhi config. Change-Id: Ib42716568193d866662f9074c08aaaa322684f9b Signed-off-by: Akshay Pandit --- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 5e5b5ab39c47..50f052f9d568 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -2617,6 +2617,12 @@ static const struct ipa_ep_configuration ipa3_ep_mapping IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_PCIE, { 22, 2, 5, 5, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY, 0 } }, + [IPA_4_5_MHI][IPA_CLIENT_ODL_DPL_CONS] = { + true, IPA_v4_5_MHI_GROUP_DDR, + false, + IPA_DPS_HPS_SEQ_TYPE_INVALID, + QMB_MASTER_SELECT_DDR, + { 22, 2, 5, 5, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY, 0 } }, [IPA_4_5_MHI][IPA_CLIENT_MHI_LOW_LAT_CONS] = { true, IPA_v4_5_MHI_GROUP_PCIE, false, From 827c2fcadb0569bd94bdff386483fb404145687b Mon Sep 17 00:00:00 2001 From: Jeya R Date: Tue, 11 Aug 2020 12:26:06 +0530 Subject: [PATCH 183/192] msm: adsprpc: Avoid race condition during map find and free Protect remote heap buffer list with spin lock while freeing to avoid UAF in fastrpc_mmap_find() on a buffer that is freed in fastrpc_mmap_free(). Change-Id: I524abf80087a5a53dfdf81c81ef34cd13f6a43cb Acked-by: Maitreyi Gupta Signed-off-by: jeyr --- drivers/char/adsprpc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 7dd63f5aede7..ef2180c98b11 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -730,9 +730,11 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags) } if (map->flags == ADSP_MMAP_HEAP_ADDR || map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { + spin_lock(&me->hlock); map->refs--; if (!map->refs) hlist_del_init(&map->hn); + spin_unlock(&me->hlock); if (map->refs > 0) return; } else { From 91464757b5fd8f5559aacd686405a0b26305fb85 Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Thu, 23 Jul 2020 22:55:44 -0700 Subject: [PATCH 184/192] Revert "coresight: tmc-etr: fix etr smmu unmap issue" This reverts commit 5e871485ef84541fad64ccbbb52b5bb5dbf123d1. Change-Id: I44f7d60f37ee61f6a5fca2a3f90e692c539c8554 Signed-off-by: Yuanfang Zhang --- drivers/hwtracing/coresight/coresight-tmc-etr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 47c4d44e885c..11689f9b10a3 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -604,7 +604,7 @@ static int tmc_etr_fill_usb_bam_data(struct tmc_drvdata *drvdata) data_fifo_iova = dma_map_resource(drvdata->dev, bamdata->data_fifo.phys_base, bamdata->data_fifo.size, DMA_BIDIRECTIONAL, 0); - if (dma_mapping_error(drvdata->dev, data_fifo_iova)) + if (!data_fifo_iova) return -ENOMEM; dev_dbg(drvdata->dev, "%s:data p_addr:%pa,iova:%pad,size:%x\n", __func__, &(bamdata->data_fifo.phys_base), @@ -613,7 +613,7 @@ static int tmc_etr_fill_usb_bam_data(struct tmc_drvdata *drvdata) desc_fifo_iova = dma_map_resource(drvdata->dev, bamdata->desc_fifo.phys_base, bamdata->desc_fifo.size, DMA_BIDIRECTIONAL, 0); - if (dma_mapping_error(drvdata->dev, desc_fifo_iova)) + if (!desc_fifo_iova) return -ENOMEM; dev_dbg(drvdata->dev, "%s:desc p_addr:%pa,iova:%pad,size:%x\n", __func__, &(bamdata->desc_fifo.phys_base), @@ -711,7 +711,7 @@ static int get_usb_bam_iova(struct device *dev, unsigned long usb_bam_handle, return ret; } *iova = dma_map_resource(dev, p_addr, bam_size, DMA_BIDIRECTIONAL, 0); - if (dma_mapping_error(dev, *iova)) + if (!(*iova)) return -ENOMEM; return 0; } From 350f8990a61121f046f40eacfd7c4edac73ccdef Mon Sep 17 00:00:00 2001 From: Ashok Vuyyuru Date: Fri, 17 Jul 2020 11:39:09 +0530 Subject: [PATCH 185/192] msm: ipa3: Configure correct aggeragtion byte limit IPA HW will treat aggeragtion byte limit value 1 consider as 1K. Adding changes to configuring the aggeragtion byte value w.r.t IPA HW requirement. Change-Id: Ibe9353a39971296f7e4b04f30039457c07c63033 Signed-off-by: Ashok Vuyyuru --- drivers/platform/msm/ipa/ipa_v3/ipa_odl.c | 6 ++++-- drivers/platform/msm/ipa/ipa_v3/ipa_odl.h | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c index 01bb8f3fe3e7..3b855589f88e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -623,7 +623,9 @@ static long ipa_adpl_ioctl(struct file *filp, switch (cmd) { case IPA_IOC_ODL_GET_AGG_BYTE_LIMIT: odl_pipe_info.agg_byte_limit = - ipa3_odl_ctx->odl_sys_param.ipa_ep_cfg.aggr.aggr_byte_limit; + /*Modem expecting value in bytes. so passing 15 = 15*1024*/ + (ipa3_odl_ctx->odl_sys_param.ipa_ep_cfg.aggr.aggr_byte_limit * + 1024); if (copy_to_user((void __user *)arg, &odl_pipe_info, sizeof(odl_pipe_info))) { retval = -EFAULT; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.h b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.h index 0a23c49e324c..6effa1b2f18a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -13,7 +13,7 @@ #ifndef _IPA3_ODL_H_ #define _IPA3_ODL_H_ -#define IPA_ODL_AGGR_BYTE_LIMIT (15 * 1024) +#define IPA_ODL_AGGR_BYTE_LIMIT 15 #define IPA_ODL_RX_RING_SIZE 192 #define MAX_QUEUE_TO_ODL 1024 #define CONFIG_SUCCESS 1 From ba4cc3083612203002bf44fa941721a821301655 Mon Sep 17 00:00:00 2001 From: Nitesh Gupta Date: Tue, 28 Jul 2020 18:52:35 +0530 Subject: [PATCH 186/192] msm: ep_pcie: set irq flag to IRQF_EARLY_RESUME for PERST irq All interrupts get disabled during system suspend and enabled during system resume. The enabling/disabling of interrupts happen in sequence of interrupt registration with framework. Set flag for early resume so that PERST interrupt get enabled before parent interrupt. Change-Id: Icccf8d2968832d9dc88e4f7c16b2d8fc6597698e Signed-off-by: Nitesh Gupta --- drivers/platform/msm/ep_pcie/ep_pcie_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c index b926976dc2e0..864c44ad2ff9 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c @@ -2601,8 +2601,9 @@ int32_t ep_pcie_irq_init(struct ep_pcie_dev_t *dev) perst_irq = gpio_to_irq(dev->gpio[EP_PCIE_GPIO_PERST].num); ret = devm_request_irq(pdev, perst_irq, ep_pcie_handle_perst_irq, - (atomic_read(&dev->perst_deast) ? - IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH), + ((atomic_read(&dev->perst_deast) ? + IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH) + | IRQF_EARLY_RESUME), "ep_pcie_perst", dev); if (ret) { EP_PCIE_ERR(dev, From 2e088609d09be4cbc1452fc39facfc3cd86aabe8 Mon Sep 17 00:00:00 2001 From: Jeya R Date: Wed, 22 Jul 2020 16:53:49 +0530 Subject: [PATCH 187/192] msm: ADSPRPC: Size check before allocating memory from DMA For allocating memory from DMA we need to do a size check. This validation is required to avoid any improper paging request. We already have the range in which the size is expected to be. Change-Id: I72919a8807a7e3bacb7f8353a2aabb8cc6c19f0f Acked-by: Ekansh Gupta Signed-off-by: Jeya R --- drivers/char/adsprpc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index ef2180c98b11..d9cd53dcf281 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -653,12 +653,20 @@ static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, static int dma_alloc_memory(dma_addr_t *region_phys, void **vaddr, size_t size, unsigned long dma_attr) { + int err = 0; struct fastrpc_apps *me = &gfa; if (me->dev == NULL) { pr_err("device adsprpc-mem is not initialized\n"); return -ENODEV; } + VERIFY(err, size > 0 && size < MAX_SIZE_LIMIT); + if (err) { + err = -EFAULT; + pr_err("adsprpc: %s: invalid allocation size 0x%zx\n", + __func__, size); + return err; + } *vaddr = dma_alloc_attrs(me->dev, size, region_phys, GFP_KERNEL, dma_attr); if (IS_ERR_OR_NULL(*vaddr)) { From ed76b19cef726440f0f0e8bc5e80b3f4b0887e62 Mon Sep 17 00:00:00 2001 From: Om Parkash Date: Mon, 3 Aug 2020 12:22:38 +0530 Subject: [PATCH 188/192] msm: camera: cci: Fix incorrect use of cci config ioctl The cci configuration will be transitioned to a new API that does not require routing through the v4l layer. This is work-in-progrss so in the mean time prevent the device from being exposed as configurable from userspace. The ioctl will still be exposed to kernel users so fix the arg size as well. We want size of struct not pointer. Change-Id: I1eeb58b8355a81fc36b9845e2096060b03f1debe Signed-off-by: Om Parkash --- .../msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c | 4 ++-- .../msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) 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 69b5af002610..9f8ee883355a 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 @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -404,7 +404,7 @@ static int cam_cci_platform_probe(struct platform_device *pdev) new_cci_dev->v4l2_dev_str.name = new_cci_dev->device_name; new_cci_dev->v4l2_dev_str.sd_flags = - (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); + V4L2_SUBDEV_FL_HAS_EVENTS; new_cci_dev->v4l2_dev_str.ent_function = CAM_CCI_DEVICE_TYPE; new_cci_dev->v4l2_dev_str.token = diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h index 2e4c032cb322..fd93dedd01f1 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -317,6 +317,6 @@ static inline struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index) #endif #define VIDIOC_MSM_CCI_CFG \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct cam_cci_ctrl *) + _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct cam_cci_ctrl) #endif /* _CAM_CCI_DEV_H_ */ From 1838ec3fb99f03d7407e41ae19480cf83bca6262 Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Thu, 6 Aug 2020 13:19:56 +0530 Subject: [PATCH 189/192] msm: mhi_dev: UCI memory leak fix mhi_init_read_chan() allocates max_packet_size*nr_trbs for async client for inbound channel. Multiple open/close of channels can cause memory leak. Adding free operation during channel release to resolve this. Change-Id: I7be4d47d28140a4d04b5070cb7db776a7f909238 Signed-off-by: Subramanian Ananthanarayanan --- drivers/platform/msm/mhi_dev/mhi_uci.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c index 5fd129d96255..2e3db4db59b4 100644 --- a/drivers/platform/msm/mhi_dev/mhi_uci.c +++ b/drivers/platform/msm/mhi_dev/mhi_uci.c @@ -1054,12 +1054,20 @@ static int mhi_uci_client_release(struct inode *mhi_inode, struct file *file_handle) { struct uci_client *uci_handle = file_handle->private_data; - int count = 0; + const struct chan_attr *in_chan_attr; + int count = 0, i; struct mhi_req *ureq; if (!uci_handle) return -EINVAL; + in_chan_attr = uci_handle->in_chan_attr; + if (!in_chan_attr) { + uci_log(UCI_DBG_ERROR, "Null channel attributes for chan %d\n", + uci_handle->in_chan); + return -EINVAL; + } + if (atomic_sub_return(1, &uci_handle->ref_count)) { uci_log(UCI_DBG_DBG, "Client close chan %d, ref count 0x%x\n", iminor(mhi_inode), @@ -1118,6 +1126,12 @@ static int mhi_uci_client_release(struct inode *mhi_inode, iminor(mhi_inode), count); } + for (i = 0; i < (in_chan_attr->nr_trbs); i++) { + kfree(uci_handle->in_buf_list[i].addr); + uci_handle->in_buf_list[i].addr = NULL; + uci_handle->in_buf_list[i].buf_size = 0; + } + atomic_set(&uci_handle->read_data_ready, 0); atomic_set(&uci_handle->write_data_ready, 0); file_handle->private_data = NULL; From d90c8bd2fa3c12fce3162a11f44d820a3b38e2fa Mon Sep 17 00:00:00 2001 From: Tony Truong Date: Mon, 3 Aug 2020 18:44:27 -0700 Subject: [PATCH 190/192] msm: pcie: correct cached PCIe link BW max gen speed PCIe link BW (bandwidth) max GEN speed is incorrectly calculated. Update bw_gen_max to have to the correct value. Change-Id: I5a9c77e326966681bdc0efde84815dcea083d470 Signed-off-by: Tony Truong --- drivers/pci/host/pci-msm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index 2f9ce9f100d2..6c5b2faa7b40 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -3675,7 +3675,7 @@ static int msm_pcie_get_resources(struct msm_pcie_dev_t *dev, of_property_read_u32_array(pdev->dev.of_node, "qcom,bw-scale", (u32 *)dev->bw_scale, size / sizeof(u32)); - dev->bw_gen_max = size / sizeof(u32); + dev->bw_gen_max = size / sizeof(*dev->bw_scale); } else { PCIE_DBG(dev, "RC%d: bandwidth scaling is not supported\n", dev->rc_idx); From 4ffb77e36fa30ae789d49065744634c40974e876 Mon Sep 17 00:00:00 2001 From: Tony Truong Date: Mon, 3 Aug 2020 18:34:22 -0700 Subject: [PATCH 191/192] msm: pcie: validate speed switch request Validate the target link speed request to ensure it does not exceed what PCIe root complex allow. Change-Id: I62f218e227ff446feae292ce4eeb78b02904ea3e Signed-off-by: Tony Truong --- drivers/pci/host/pci-msm.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index 6c5b2faa7b40..1cafc63e2293 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -6374,6 +6374,15 @@ int msm_pcie_set_link_bandwidth(struct pci_dev *pci_dev, u16 target_link_speed, pcie_dev = PCIE_BUS_PRIV_DATA(root_pci_dev->bus); + if (target_link_speed > pcie_dev->bw_gen_max || + (pcie_dev->target_link_speed && + target_link_speed > pcie_dev->target_link_speed)) { + PCIE_DBG(pcie_dev, + "PCIe: RC%d: invalid target link speed: %d\n", + pcie_dev->rc_idx, target_link_speed); + return -EINVAL; + } + pcie_capability_read_word(root_pci_dev, PCI_EXP_LNKSTA, &link_status); current_link_speed = link_status & PCI_EXP_LNKSTA_CLS; From 82c8ac09bb74c9af836088dada1ed7c0a7b94d46 Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Thu, 6 Aug 2020 14:33:13 +0530 Subject: [PATCH 192/192] msm: mhi_dev: Prevent invalid memory access during channel read ring_cache is NULL as channel has not yet been started, read operation accesses ring_cache before checking if channel is in stopped state. Adding a check in UCI layer to perform read/write transfers only if the channel is in valid state. Change-Id: Ic8e6ae19badf43a7f64f92349e9c2427750a98b6 Signed-off-by: Subramanian Ananthanarayanan --- drivers/platform/msm/mhi_dev/mhi.c | 15 ++++++++------- drivers/platform/msm/mhi_dev/mhi_uci.c | 17 ++++++++++++++++- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 94fad034dbab..38195a8afaff 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -2942,6 +2942,14 @@ int mhi_dev_read_channel(struct mhi_req *mreq) mutex_lock(&ch->ch_lock); do { + if (ch->state == MHI_DEV_CH_STOPPED) { + mhi_log(MHI_MSG_VERBOSE, + "channel (%d) already stopped\n", + mreq->chan); + bytes_read = -1; + goto exit; + } + el = &ring->ring_cache[ring->rd_offset]; mhi_log(MHI_MSG_VERBOSE, "evtptr : 0x%llx\n", el->tre.data_buf_ptr); @@ -2963,13 +2971,6 @@ int mhi_dev_read_channel(struct mhi_req *mreq) goto exit; } - if (ch->state == MHI_DEV_CH_STOPPED) { - mhi_log(MHI_MSG_VERBOSE, - "channel (%d) already stopped\n", - mreq->chan); - bytes_read = -1; - goto exit; - } ch->tre_loc = el->tre.data_buf_ptr; ch->tre_size = el->tre.len; diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c index 2e3db4db59b4..a51f95b7bc9f 100644 --- a/drivers/platform/msm/mhi_dev/mhi_uci.c +++ b/drivers/platform/msm/mhi_dev/mhi_uci.c @@ -923,8 +923,11 @@ static int open_client_mhi_channels(struct uci_client *uci_client) { int rc = 0; - if (!mhi_uci_are_channels_connected(uci_client)) + if (!mhi_uci_are_channels_connected(uci_client)) { + uci_log(UCI_DBG_ERROR, "%s:Channels are not connected\n", + __func__); return -ENODEV; + } uci_log(UCI_DBG_DBG, "Starting channels %d %d.\n", @@ -1248,6 +1251,12 @@ static int __mhi_uci_client_read(struct uci_client *uci_handle, int ret_val = 0; do { + if (!mhi_uci_are_channels_connected(uci_handle)) { + uci_log(UCI_DBG_ERROR, + "%s:Channels are not connected\n", __func__); + return -ENODEV; + } + if (!uci_handle->pkt_loc && !atomic_read(&uci_ctxt.mhi_disabled)) { ret_val = uci_handle->read(uci_handle, bytes_avail); @@ -1394,6 +1403,12 @@ static ssize_t mhi_uci_client_write(struct file *file, return -EIO; } + if (!mhi_uci_are_channels_connected(uci_handle)) { + uci_log(UCI_DBG_ERROR, "%s:Channels are not connected\n", + __func__); + return -ENODEV; + } + if (count > TRB_MAX_DATA_SIZE) { uci_log(UCI_DBG_ERROR, "Too big write size: %d, max supported size is %d\n",