From 6b6b8dc6fb2b09331565363b65e0b744f3188d25 Mon Sep 17 00:00:00 2001 From: longzuming Date: Wed, 9 Jun 2021 14:22:27 +0800 Subject: [PATCH 01/90] ANDROID: GKI: Update abi_gki_aarch64_oplus Leaf changes summary: 1 artifacts changed Changed leaf types summary: 0 leaf type changed Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 1 Added functions Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable 1 Added function: [A] 'void spi_set_cs_timing(struct spi_device *spi, u8 setup, u8 hold, u8 inactive_dly)' Bug: 190457773 Signed-off-by: zuming.long Change-Id: Ic8ebbdd8a794ca38982e74ee7d01bbf6b1ba2eb4 --- android/abi_gki_aarch64.xml | 8 ++++++++ android/abi_gki_aarch64_oplus | 1 + 2 files changed, 9 insertions(+) diff --git a/android/abi_gki_aarch64.xml b/android/abi_gki_aarch64.xml index 2e8113c8c557..ff1a17ee7753 100644 --- a/android/abi_gki_aarch64.xml +++ b/android/abi_gki_aarch64.xml @@ -3967,6 +3967,7 @@ + @@ -128457,6 +128458,13 @@ + + + + + + + diff --git a/android/abi_gki_aarch64_oplus b/android/abi_gki_aarch64_oplus index 15ac9a66a517..c2eacbe29161 100644 --- a/android/abi_gki_aarch64_oplus +++ b/android/abi_gki_aarch64_oplus @@ -198,6 +198,7 @@ remove_proc_subtree request_firmware rtc_time64_to_tm + spi_set_cs_timing spi_sync strcat system_wq From 0a5d2ddf235351c8321da5a2df1e8a1e4b80e107 Mon Sep 17 00:00:00 2001 From: wangting11 Date: Tue, 8 Jun 2021 17:55:17 +0800 Subject: [PATCH 02/90] ANDROID: GKI: update symbol list for xiaomi Update the android/abi_gki_aarch64_xiaomi with recent symbol additions. No new symbol addition. Leaf changes summary: 0 artifact changed Changed leaf types summary: 0 leaf type changed Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable Bug: 190458832 Signed-off-by: wangting11 Change-Id: I406585d9b0761bba7ca7bb6ab1ab3d3bb07051fc Signed-off-by: wangting11 --- android/abi_gki_aarch64_xiaomi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/android/abi_gki_aarch64_xiaomi b/android/abi_gki_aarch64_xiaomi index 95acdab2fb70..824b53703ce5 100644 --- a/android/abi_gki_aarch64_xiaomi +++ b/android/abi_gki_aarch64_xiaomi @@ -16,6 +16,13 @@ regcache_drop_region snd_soc_dapm_del_routes +# required by us_prox.ko + iio_device_unregister + iio_device_free + __iio_device_register + __kfifo_to_user + iio_device_alloc + # required by tfa98xx_dlkm.ko device_remove_bin_file snd_pcm_hw_constraint_mask64 @@ -32,15 +39,21 @@ # required by msm_drm.ko kobject_set_name + wakeup_source_destroy + wakeup_source_remove + wakeup_source_add + wakeup_source_create # required by exfat.ko block_write_full_page __blockdev_direct_IO __bread_gfp __brelse + clear_nlink cont_write_begin d_find_alias d_move + d_splice_alias filemap_fdatawait_range filemap_fdatawrite_range full_name_hash @@ -53,6 +66,7 @@ generic_fillattr generic_write_end __getblk_gfp + igrab ilookup in_group_p inc_nlink @@ -76,14 +90,20 @@ sb_min_blocksize sb_set_blocksize setattr_copy + setattr_prepare + set_nlink sync_blockdev sync_dirty_buffer sync_mapping_buffers __remove_inode_hash touch_buffer truncate_pagecache + truncate_setsize unload_nls unlock_buffer utf16s_to_utf8s utf8s_to_utf16s write_inode_now + +# required by incrementalfs.ko + revert_creds From 905e945fabfd97f9ed667c4500cb7f4b7396a5ef Mon Sep 17 00:00:00 2001 From: Tengfei Fan Date: Fri, 13 Dec 2019 15:57:49 +0800 Subject: [PATCH 03/90] soc: qcom: use MODULES_END instead of KIMAGE_VADDR Because of KIMAGE_VADDR is not defined by ARM32, so in order to support minidump function on ARM32, so use MODULES_END instead of KIMAGE_VADDR, because MODULES_END are defined by ARM64 and ARM32. Change-Id: Ie0d990baa17a207ceb7ed56faa9b5256f31a3e17 Signed-off-by: Tengfei Fan --- drivers/soc/qcom/minidump_log.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/minidump_log.c b/drivers/soc/qcom/minidump_log.c index 1313f7e5e135..9c18be966ebe 100644 --- a/drivers/soc/qcom/minidump_log.c +++ b/drivers/soc/qcom/minidump_log.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -264,7 +264,7 @@ void dump_stack_minidump(u64 sp) is_vmap_stack = IS_ENABLED(CONFIG_VMAP_STACK); - if (sp < KIMAGE_VADDR || sp > -256UL) + if (sp < MODULES_END || sp > -256UL) sp = current_stack_pointer; /* From 9f0b6f9c8f9e6c96adc7ceb443e982b18f63f180 Mon Sep 17 00:00:00 2001 From: Deepak Dimri Date: Thu, 5 Nov 2020 14:03:37 +0530 Subject: [PATCH 04/90] minidump: Add support for !CONFIG_SMP kernel __per_cpu variables are only applicable for the systems with multiple cpu Minidump code without any check for same was causing the kernel compilation to fail for the single core cpu where __per_cpu symbols are not applicable so added conditional compilation to the __per_cpu code based on CONFIG_SMP. Change-Id: I626fc3c47fd9600608ea721ef6f8811110e1ee1d Signed-off-by: Deepak Dimri --- drivers/soc/qcom/minidump_log.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/soc/qcom/minidump_log.c b/drivers/soc/qcom/minidump_log.c index 9c18be966ebe..921e2a6ea63b 100644 --- a/drivers/soc/qcom/minidump_log.c +++ b/drivers/soc/qcom/minidump_log.c @@ -191,9 +191,11 @@ static void __init register_kernel_sections(void) struct md_region ksec_entry; char *data_name = "KDATABSS"; char *rodata_name = "KROAIDATA"; +#ifdef CONFIG_SMP const size_t static_size = __per_cpu_end - __per_cpu_start; void __percpu *base = (void __percpu *)__per_cpu_start; unsigned int cpu; +#endif strlcpy(ksec_entry.name, data_name, sizeof(ksec_entry.name)); ksec_entry.virt_addr = (uintptr_t)_sdata; @@ -209,6 +211,7 @@ static void __init register_kernel_sections(void) if (msm_minidump_add_region(&ksec_entry) < 0) pr_err("Failed to add rodata section in Minidump\n"); +#ifdef CONFIG_SMP /* Add percpu static sections */ for_each_possible_cpu(cpu) { void *start = per_cpu_ptr(base, cpu); @@ -222,6 +225,7 @@ static void __init register_kernel_sections(void) if (msm_minidump_add_region(&ksec_entry) < 0) pr_err("Failed to add percpu sections in Minidump\n"); } +#endif } static inline bool in_stack_range( From 9e798cb682559c8d9a2f00b38698c9911398728c Mon Sep 17 00:00:00 2001 From: Melody Olvera Date: Wed, 19 May 2021 14:20:32 -0700 Subject: [PATCH 05/90] defconfig: sdxlemur: Enable configs for minidump Enable defconfigs needed for minidump. Change-Id: I9c2ea879cc6e36915db72b26e1e3da5f9fd3859e Signed-off-by: Melody Olvera --- arch/arm/configs/vendor/sdxlemur.config | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/vendor/sdxlemur.config b/arch/arm/configs/vendor/sdxlemur.config index 5974ea0c7c99..30171ec7eb2b 100644 --- a/arch/arm/configs/vendor/sdxlemur.config +++ b/arch/arm/configs/vendor/sdxlemur.config @@ -342,6 +342,8 @@ CONFIG_QCOM_EUD=y CONFIG_POWER_RESET_QCOM_DOWNLOAD_MODE=y CONFIG_POWER_RESET_QCOM_DOWNLOAD_MODE_DEFAULT=y CONFIG_POWER_RESET_QCOM_REBOOT_REASON=y +CONFIG_POWER_RESET_MSM=y +CONFIG_QCOM_MINIDUMP=y CONFIG_ENABLE_SFE=y # CONFIG_ENABLE_VMALLOC_SAVING is not set # CONFIG_SLUB_DEBUG is not set From e399f16519fac54e5a12125631c41db458e4336e Mon Sep 17 00:00:00 2001 From: Kiwoong Kim Date: Fri, 14 May 2021 16:58:14 +0900 Subject: [PATCH 06/90] ANDROID: GKI: add ufshcd_config_pwr_mode Sometimes, ufs host exits from hibern8 with low speed even if it start with high speed. In the case, a module needs to call ufshcd_config_pwr_mode to sustain IO performance. Bug: 188122907 Signed-off-by: Kiwoong Kim Change-Id: I5e2cdcd5f36b7328f3543ba3225b95733f12bd0d --- android/abi_gki_aarch64_exynos | 1 + 1 file changed, 1 insertion(+) diff --git a/android/abi_gki_aarch64_exynos b/android/abi_gki_aarch64_exynos index 1f795dac9b27..4316e90e289d 100644 --- a/android/abi_gki_aarch64_exynos +++ b/android/abi_gki_aarch64_exynos @@ -1598,6 +1598,7 @@ uart_update_timeout uart_write_wakeup __udelay + ufshcd_config_pwr_mode ufshcd_dme_get_attr ufshcd_dme_set_attr ufshcd_pltfrm_init From 6f8540b7442e0fd7c5c02059f6328f55b0f7d36a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bram=20Bonn=C3=A9?= Date: Fri, 30 Apr 2021 11:50:19 +0200 Subject: [PATCH 07/90] ANDROID: selinux: modify RTM_GETNEIGH{TBL} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Map the permission gating RTM_GETNEIGH/RTM_GETNEIGHTBL messages to a new permission so that it can be distinguished from the other netlink route permissions in selinux policy. The new permission is triggered by a flag set in system images T and up. This change is intended to be backported to all kernels that a T system image can run on top of. Bug: 171572148 Test: atest NetworkInterfaceTest Test: atest CtsSelinuxTargetSdkCurrentTestCases Test: atest bionic-unit-tests-static Test: On Cuttlefish, run combinations of: - Policy bit set or omitted (see https://r.android.com/1701847) - This patch applied or omitted - App having nlmsg_readneigh permission or not Verify that only the combination of this patch + the policy bit being set + the app not having the nlmsg_readneigh permission prevents the app from sending RTM_GETNEIGH messages. Change-Id: I4bcfce4decb34ea9388eeedfc4be67403de8a980 Signed-off-by: Bram Bonné (cherry picked from commit fac07550bdac9adea0dbe3edbdbec7a9a690a178) --- security/selinux/include/classmap.h | 3 ++- security/selinux/include/security.h | 9 +++++++++ security/selinux/nlmsgtab.c | 24 ++++++++++++++++++++---- security/selinux/ss/policydb.c | 4 ++++ security/selinux/ss/policydb.h | 2 ++ security/selinux/ss/services.c | 1 + 6 files changed, 38 insertions(+), 5 deletions(-) diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 562bd1802c99..896ccad73ee8 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -116,7 +116,8 @@ struct security_class_mapping secclass_map[] = { { COMMON_IPC_PERMS, NULL } }, { "netlink_route_socket", { COMMON_SOCK_PERMS, - "nlmsg_read", "nlmsg_write", "nlmsg_readpriv", NULL } }, + "nlmsg_read", "nlmsg_write", "nlmsg_readpriv", "nlmsg_getneigh", + NULL } }, { "netlink_tcpdiag_socket", { COMMON_SOCK_PERMS, "nlmsg_read", "nlmsg_write", NULL } }, diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 6d6068490466..6f5abff4109b 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -106,6 +106,8 @@ struct selinux_state { bool initialized; bool policycap[__POLICYDB_CAPABILITY_MAX]; bool android_netlink_route; + bool android_netlink_getneigh; + struct selinux_avc *avc; struct selinux_ss *ss; }; @@ -185,6 +187,13 @@ static inline bool selinux_android_nlroute_getlink(void) return state->android_netlink_route; } +static inline bool selinux_android_nlroute_getneigh(void) +{ + struct selinux_state *state = &selinux_state; + + return state->android_netlink_getneigh; +} + int security_mls_enabled(struct selinux_state *state); int security_load_policy(struct selinux_state *state, void *data, size_t len); diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index d1bec5a281db..328f5ffc30a9 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -207,12 +207,12 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm) return err; } -static void nlmsg_set_getlink_perm(u32 perm) +static void nlmsg_set_perm_for_type(u32 perm, u16 type) { int i; for (i = 0; i < ARRAY_SIZE(nlmsg_route_perms); i++) { - if (nlmsg_route_perms[i].nlmsg_type == RTM_GETLINK) { + if (nlmsg_route_perms[i].nlmsg_type == type) { nlmsg_route_perms[i].perm = perm; break; } @@ -222,11 +222,27 @@ static void nlmsg_set_getlink_perm(u32 perm) /** * Use nlmsg_readpriv as the permission for RTM_GETLINK messages if the * netlink_route_getlink policy capability is set. Otherwise use nlmsg_read. + * Similarly, use nlmsg_getneigh for RTM_GETNEIGH and RTM_GETNEIGHTBL if the + * netlink_route_getneigh policy capability is set. Otherwise use nlmsg_read. */ void selinux_nlmsg_init(void) { if (selinux_android_nlroute_getlink()) - nlmsg_set_getlink_perm(NETLINK_ROUTE_SOCKET__NLMSG_READPRIV); + nlmsg_set_perm_for_type(NETLINK_ROUTE_SOCKET__NLMSG_READPRIV, + RTM_GETLINK); else - nlmsg_set_getlink_perm(NETLINK_ROUTE_SOCKET__NLMSG_READ); + nlmsg_set_perm_for_type(NETLINK_ROUTE_SOCKET__NLMSG_READ, + RTM_GETLINK); + + if (selinux_android_nlroute_getneigh()) { + nlmsg_set_perm_for_type(NETLINK_ROUTE_SOCKET__NLMSG_GETNEIGH, + RTM_GETNEIGH); + nlmsg_set_perm_for_type(NETLINK_ROUTE_SOCKET__NLMSG_GETNEIGH, + RTM_GETNEIGHTBL); + } else { + nlmsg_set_perm_for_type(NETLINK_ROUTE_SOCKET__NLMSG_READ, + RTM_GETNEIGH); + nlmsg_set_perm_for_type(NETLINK_ROUTE_SOCKET__NLMSG_READ, + RTM_GETNEIGHTBL); + } } diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 99a207784ce9..b2393555d471 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -2353,6 +2353,10 @@ int policydb_read(struct policydb *p, void *fp) p->android_netlink_route = 1; } + if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_ANDROID_NETLINK_GETNEIGH)) { + p->android_netlink_getneigh = 1; + } + if (p->policyvers >= POLICYDB_VERSION_POLCAP) { rc = ebitmap_read(&p->policycaps, fp); if (rc) diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 95fb3607f07c..eefacd40d491 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -235,6 +235,7 @@ struct genfs { struct policydb { int mls_enabled; int android_netlink_route; + int android_netlink_getneigh; /* symbol tables */ struct symtab symtab[SYM_NUM]; @@ -322,6 +323,7 @@ extern int policydb_write(struct policydb *p, void *fp); #define POLICYDB_CONFIG_MLS 1 #define POLICYDB_CONFIG_ANDROID_NETLINK_ROUTE (1 << 31) +#define POLICYDB_CONFIG_ANDROID_NETLINK_GETNEIGH (1 << 30) /* the config flags related to unknown classes/perms are bits 2 and 3 */ #define REJECT_UNKNOWN 0x00000002 diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 5199dd3f3db5..6559767d3444 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -2127,6 +2127,7 @@ static void security_load_policycaps(struct selinux_state *state) } state->android_netlink_route = p->android_netlink_route; + state->android_netlink_getneigh = p->android_netlink_getneigh; selinux_nlmsg_init(); } From 4f659999590962fcc58f9dffff962f0b3cd88771 Mon Sep 17 00:00:00 2001 From: Mukesh Kumar Savaliya Date: Wed, 24 Mar 2021 00:16:54 +0530 Subject: [PATCH 08/90] spi: spi-msm-geni: Store the wrapper dev handle for LE VM also This change uses correct wrapper dev for LE instead of bypassing. If wrapper dev or internal members are NULL, it crashes during register dump time due to some other error. This change fixes a crash happening to due to NULL pointer access while dumping the register using geni_se_dump_dbg_regs. sample dump from I2C driver which is fixed in i2c: [ 278.999159] Call trace: [ 278.999165] geni_se_dump_dbg_regs+0x98/0x2f0 [ 278.999177] geni_i2c_runtime_resume+0x2f4/0x4c8 [ 278.999186] pm_generic_runtime_resume+0x34/0x48 [ 278.999193] __rpm_callback+0x80/0x1a0 [ 278.999198] rpm_resume+0x4ec/0x720 [ 278.999202] __pm_runtime_resume+0x54/0x78 [ 278.999211] fts_trusted_touch_enable_store+0x1dc/0x8e0 [ 278.999217] dev_attr_store+0x40/0x58 [ 278.999226] sysfs_kf_write+0x50/0x68 [ 278.999231] kernfs_fop_write+0x150/0x1f8 [ 278.999240] __vfs_write+0x54/0x190 [ 278.999247] vfs_write+0xe4/0x1a0 [ 278.999254] __arm64_sys_pwrite64+0x80/0xc0 [ 278.999263] el0_svc_common+0x98/0x118 [ 278.999270] el0_svc_handler+0x7c/0x98 [ 278.999277] el0_svc+0x8/0xc [ 278.999286] Code: f94006a8 d0002800 9134b000 aa1603e1 (f9404d15). Change-Id: Iecdb214452fc8232ee5aa3f803180f4c3a92affd Signed-off-by: Mukesh Kumar Savaliya --- drivers/spi/spi-msm-geni.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-msm-geni.c b/drivers/spi/spi-msm-geni.c index 0b71df4757e6..ecbe17055e56 100644 --- a/drivers/spi/spi-msm-geni.c +++ b/drivers/spi/spi-msm-geni.c @@ -2002,6 +2002,7 @@ static int spi_geni_probe(struct platform_device *pdev) dev_info(&pdev->dev, "LA-VM usecase\n"); } + geni_mas->spi_rsc.wrapper_dev = &wrapper_pdev->dev; /* * For LE, clocks, gpio and icb voting will be provided by * by LA. The SPI operates in GSI mode only for LE usecase, @@ -2009,7 +2010,6 @@ static int spi_geni_probe(struct platform_device *pdev) * in SPI LE dt. */ if (!geni_mas->is_le_vm) { - geni_mas->spi_rsc.wrapper_dev = &wrapper_pdev->dev; ret = geni_se_resources_init(rsc, SPI_CORE2X_VOTE, (DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH)); if (ret) { From 770b8d5b45985658f1f7de45bbbd107d22f0607d Mon Sep 17 00:00:00 2001 From: Michael Adisumarta Date: Mon, 21 Jun 2021 12:30:19 -0700 Subject: [PATCH 09/90] msm: ipa: macros to determine the structure mismatch Macros to determine the structure mismatch between ipa_lnx_agent and ipa driver. Also includes new framework APIs to get the IPA client info for the IPA stats module. Change-Id: I15399b6730c7f4b5c6c7a63684c674f8899dc151 Signed-off-by: Michael Adisumarta --- drivers/platform/msm/ipa_fmwk/ipa_fmwk.c | 74 +++++++++++++++++++++++- include/linux/ipa_eth.h | 6 +- include/linux/ipa_fmwk.h | 11 ++++ include/linux/ipa_usb.h | 16 ++++- include/linux/ipa_wdi3.h | 11 ++++ include/uapi/linux/msm_ipa.h | 41 +++++++++++++ 6 files changed, 154 insertions(+), 5 deletions(-) diff --git a/drivers/platform/msm/ipa_fmwk/ipa_fmwk.c b/drivers/platform/msm/ipa_fmwk/ipa_fmwk.c index dc9702ab169d..d0ebb899fde5 100644 --- a/drivers/platform/msm/ipa_fmwk/ipa_fmwk.c +++ b/drivers/platform/msm/ipa_fmwk/ipa_fmwk.c @@ -251,6 +251,9 @@ struct ipa_fmwk_contex { int (*ipa_usb_xdci_resume)(u32 ul_clnt_hdl, u32 dl_clnt_hdl, enum ipa_usb_teth_prot teth_prot); + bool (*ipa_usb_is_teth_prot_connected)( + enum ipa_usb_teth_prot usb_teth_prot); + /* ipa_wdi3 APIs */ int (*ipa_wdi_init)(struct ipa_wdi_init_in_params *in, struct ipa_wdi_init_out_params *out); @@ -309,6 +312,8 @@ struct ipa_fmwk_contex { int (*ipa_dereg_uc_rdyCB)(void); + bool (*ipa_wdi_is_tx1_used)(void); + /* ipa_gsb APIs*/ int (*ipa_bridge_init)(struct ipa_bridge_init_params *params, u32 *hdl); @@ -425,8 +430,15 @@ struct ipa_fmwk_contex { int (*ipa_eth_client_conn_evt)(struct ipa_ecm_msg *msg); int (*ipa_eth_client_disconn_evt)(struct ipa_ecm_msg *msg); + int (*ipa_get_default_aggr_time_limit)(enum ipa_client_type client, u32 *default_aggr_time_limit); + + enum ipa_client_type (*ipa_eth_get_ipa_client_type_from_eth_type)( + enum ipa_eth_client_type eth_client_type, enum ipa_eth_pipe_direction dir); + + bool (*ipa_eth_client_exist)( + enum ipa_eth_client_type eth_client_type, int inst_id); }; static struct ipa_fmwk_contex *ipa_fmwk_ctx; @@ -1056,7 +1068,8 @@ int ipa_fmwk_register_ipa_usb(const struct ipa_usb_data *in) ipa_fmwk_ctx->ipa_usb_xdci_disconnect || ipa_fmwk_ctx->ipa_usb_deinit_teth_prot || ipa_fmwk_ctx->ipa_usb_xdci_suspend || - ipa_fmwk_ctx->ipa_usb_xdci_resume) { + ipa_fmwk_ctx->ipa_usb_xdci_resume || + ipa_fmwk_ctx->ipa_usb_is_teth_prot_connected) { pr_err("ipa_usb APIs were already initialized\n"); return -EPERM; } @@ -1066,6 +1079,8 @@ int ipa_fmwk_register_ipa_usb(const struct ipa_usb_data *in) ipa_fmwk_ctx->ipa_usb_deinit_teth_prot = in->ipa_usb_deinit_teth_prot; ipa_fmwk_ctx->ipa_usb_xdci_suspend = in->ipa_usb_xdci_suspend; ipa_fmwk_ctx->ipa_usb_xdci_resume = in->ipa_usb_xdci_resume; + ipa_fmwk_ctx->ipa_usb_is_teth_prot_connected = + in->ipa_usb_is_teth_prot_connected; pr_info("ipa_usb registered successfully\n"); @@ -1153,6 +1168,17 @@ int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, } EXPORT_SYMBOL(ipa_usb_xdci_resume); +bool ipa_usb_is_teth_prot_connected(enum ipa_usb_teth_prot usb_teth_prot) +{ + int ret; + + IPA_FMWK_DISPATCH_RETURN(ipa_usb_is_teth_prot_connected, + usb_teth_prot); + + return ret; +} +EXPORT_SYMBOL(ipa_usb_is_teth_prot_connected); + /* registration API for IPA wdi3 module */ int ipa_fmwk_register_ipa_wdi3(const struct ipa_wdi3_data *in) { @@ -1175,7 +1201,8 @@ int ipa_fmwk_register_ipa_wdi3(const struct ipa_wdi3_data *in) || ipa_fmwk_ctx->ipa_wdi_release_smmu_mapping || ipa_fmwk_ctx->ipa_wdi_get_stats || ipa_fmwk_ctx->ipa_get_wdi_version - || ipa_fmwk_ctx->ipa_wdi_sw_stats) { + || ipa_fmwk_ctx->ipa_wdi_sw_stats + || ipa_fmwk_ctx->ipa_wdi_is_tx1_used) { pr_err("ipa_wdi3 APIs were already initialized\n"); return -EPERM; } @@ -1197,6 +1224,7 @@ int ipa_fmwk_register_ipa_wdi3(const struct ipa_wdi3_data *in) ipa_fmwk_ctx->ipa_wdi_get_stats = in->ipa_wdi_get_stats; ipa_fmwk_ctx->ipa_wdi_sw_stats = in->ipa_wdi_sw_stats; ipa_fmwk_ctx->ipa_get_wdi_version = in->ipa_get_wdi_version; + ipa_fmwk_ctx->ipa_wdi_is_tx1_used = in->ipa_wdi_is_tx1_used; pr_info("ipa_wdi3 registered successfully\n"); @@ -1217,6 +1245,16 @@ int ipa_wdi_init(struct ipa_wdi_init_in_params *in, } EXPORT_SYMBOL(ipa_wdi_init); +bool ipa_wdi_is_tx1_used(void) +{ + int ret; + + IPA_FMWK_DISPATCH_RETURN(ipa_wdi_is_tx1_used); + + return ret; +} +EXPORT_SYMBOL(ipa_wdi_is_tx1_used); + int ipa_wdi_cleanup(void) { int ret; @@ -2125,7 +2163,9 @@ int ipa_fmwk_register_ipa_eth(const struct ipa_eth_data *in) || ipa_fmwk_ctx->ipa_eth_client_unreg_intf || ipa_fmwk_ctx->ipa_eth_client_set_perf_profile || ipa_fmwk_ctx->ipa_eth_client_conn_evt - || ipa_fmwk_ctx->ipa_eth_client_disconn_evt) { + || ipa_fmwk_ctx->ipa_eth_client_disconn_evt + || ipa_fmwk_ctx->ipa_eth_get_ipa_client_type_from_eth_type + || ipa_fmwk_ctx->ipa_eth_client_exist) { pr_err("ipa_eth APIs were already initialized\n"); return -EPERM; } @@ -2143,6 +2183,10 @@ int ipa_fmwk_register_ipa_eth(const struct ipa_eth_data *in) ipa_fmwk_ctx->ipa_eth_client_conn_evt = in->ipa_eth_client_conn_evt; ipa_fmwk_ctx->ipa_eth_client_disconn_evt = in->ipa_eth_client_disconn_evt; + ipa_fmwk_ctx->ipa_eth_get_ipa_client_type_from_eth_type = + in->ipa_eth_get_ipa_client_type_from_eth_type; + ipa_fmwk_ctx->ipa_eth_client_exist = + in->ipa_eth_client_exist; pr_info("ipa_eth registered successfully\n"); @@ -2275,6 +2319,30 @@ int ipa_get_default_aggr_time_limit(enum ipa_client_type client, } EXPORT_SYMBOL(ipa_get_default_aggr_time_limit); +enum ipa_client_type ipa_eth_get_ipa_client_type_from_eth_type( + enum ipa_eth_client_type eth_client_type, enum ipa_eth_pipe_direction dir) +{ + int ret; + + IPA_FMWK_DISPATCH_RETURN_DP(ipa_eth_get_ipa_client_type_from_eth_type, + eth_client_type, dir); + + return ret; +} +EXPORT_SYMBOL(ipa_eth_get_ipa_client_type_from_eth_type); + +bool ipa_eth_client_exist( + enum ipa_eth_client_type eth_client_type, int inst_id) +{ + int ret; + + IPA_FMWK_DISPATCH_RETURN_DP(ipa_eth_client_exist, + eth_client_type, inst_id); + + return ret; +} +EXPORT_SYMBOL(ipa_eth_client_exist); + /* module functions */ static int __init ipa_fmwk_init(void) { diff --git a/include/linux/ipa_eth.h b/include/linux/ipa_eth.h index a2d013da4a61..ff230cbb466f 100644 --- a/include/linux/ipa_eth.h +++ b/include/linux/ipa_eth.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #ifndef _IPA_ETH_H_ @@ -1094,5 +1094,9 @@ int ipa_eth_client_set_perf_profile(struct ipa_eth_client *client, struct ipa_eth_perf_profile *profile); int ipa_eth_client_conn_evt(struct ipa_ecm_msg *msg); int ipa_eth_client_disconn_evt(struct ipa_ecm_msg *msg); +enum ipa_client_type ipa_eth_get_ipa_client_type_from_eth_type( + enum ipa_eth_client_type eth_client_type, enum ipa_eth_pipe_direction dir); +bool ipa_eth_client_exist( + enum ipa_eth_client_type eth_client_type, int inst_id); #endif // _IPA_ETH_H_ diff --git a/include/linux/ipa_fmwk.h b/include/linux/ipa_fmwk.h index af65e545507d..28077d869691 100644 --- a/include/linux/ipa_fmwk.h +++ b/include/linux/ipa_fmwk.h @@ -162,6 +162,8 @@ struct ipa_usb_data { int (*ipa_usb_xdci_resume)(u32 ul_clnt_hdl, u32 dl_clnt_hdl, enum ipa_usb_teth_prot teth_prot); + + bool (*ipa_usb_is_teth_prot_connected)(enum ipa_usb_teth_prot usb_teth_prot); }; struct ipa_wdi3_data { @@ -199,6 +201,8 @@ struct ipa_wdi3_data { int (*ipa_wdi_sw_stats)(struct ipa_wdi_tx_info *info); int (*ipa_get_wdi_version)(void); + + bool (*ipa_wdi_is_tx1_used)(void); }; struct ipa_qdss_data { @@ -327,6 +331,13 @@ struct ipa_eth_data { int (*ipa_eth_client_conn_evt)(struct ipa_ecm_msg *msg); int (*ipa_eth_client_disconn_evt)(struct ipa_ecm_msg *msg); + + enum ipa_client_type (*ipa_eth_get_ipa_client_type_from_eth_type)( + enum ipa_eth_client_type eth_client_type, + enum ipa_eth_pipe_direction dir); + + bool (*ipa_eth_client_exist)( + enum ipa_eth_client_type eth_client_type, int inst_id); }; #if IS_ENABLED(CONFIG_IPA3) diff --git a/include/linux/ipa_usb.h b/include/linux/ipa_usb.h index c0c250e4709a..3fad1a392896 100644 --- a/include/linux/ipa_usb.h +++ b/include/linux/ipa_usb.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ #ifndef _IPA_USB_H_ @@ -292,6 +292,15 @@ int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, enum ipa_usb_teth_prot teth_prot); +/** + * ipa_usb_is_teth_prot_connected - Internal API for checking USB + * protocol is connected + * + * @usb_teth_prot: USB tethering protocol + * @Return true if connected, false if not + */ +bool ipa_usb_is_teth_prot_connected(enum ipa_usb_teth_prot usb_teth_prot); + #else /* IS_ENABLED(CONFIG_IPA3) */ static inline int ipa_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot, @@ -337,6 +346,11 @@ static inline int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, return -EPERM; } +static inline int ipa_usb_is_teth_prot_connected(enum ipa_usb_teth_prot usb_teth_prot) +{ + return -EPERM; +} + #endif /* IS_ENABLED(CONFIG_IPA3) */ diff --git a/include/linux/ipa_wdi3.h b/include/linux/ipa_wdi3.h index ad31f927adb9..ca07b74877a2 100644 --- a/include/linux/ipa_wdi3.h +++ b/include/linux/ipa_wdi3.h @@ -250,6 +250,12 @@ struct ipa_wdi_perf_profile { int ipa_wdi_init(struct ipa_wdi_init_in_params *in, struct ipa_wdi_init_out_params *out); +/** ipa_wdi_is_tx1_used - return if DBS mode is active + * + * @Return bool + */ +bool ipa_wdi_is_tx1_used(void); + /** * ipa_wdi_cleanup - Client should call this function to * clean up WDI IPA offload data path @@ -399,6 +405,11 @@ static inline int ipa_get_wdi_version(void) return -EPERM; } +static inline int ipa_wdi_is_tx1_used(void) +{ + return -EPERM; +} + static inline int ipa_wdi_cleanup(void) { return -EPERM; diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index f7e9b59cb304..4445d65f9eed 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -256,6 +256,47 @@ #define IPA_MAX_PDN_NUM 16 #define IPA_MAX_PDN_NUM_v4 5 +/** + * Macros duplicated from ipa_lnx_spearhead_stats.h and + * ipa_lnx_stats.h. All three macros should match. + * This needs to be updated whenever the header file structure + * and structure length macros are updated to match exactly + * the same. This is done to overcome backward and forward + * compatibility between userspace and driver spearhead structures. + */ +/* IPA Linux basic stats structure macros */ +#define IPA_LNX_PG_RECYCLE_STATS_STRUCT_LEN 32 +#define IPA_LNX_EXCEPTION_STATS_STRUCT_LEN 40 +#define IPA_LNX_ODL_EP_STATS_STRUCT_LEN 16 +#define IPA_LNX_HOLB_DISCARD_STATS_STRUCT_LEN 16 +#define IPA_LNX_HOLB_MONITOR_STATS_STRUCT_LEN 16 +#define IPA_LNX_HOLB_DROP_AND_MON_STATS_STRUCT_LEN (8 + 16 + 16) +#define IPA_LNX_GENERIC_STATS_STRUCT_LEN (40 + 32 + 40 + 16 + 40) +/* IPA Linux clock stats structures */ +#define IPA_LNX_PM_CLIENT_STATS_STRUCT_LEN 24 +#define IPA_LNX_CLOCK_STATS_STRUCT_LEN (24 + 24) +/* Generic instance structures */ +#define IPA_LNX_GSI_RX_DEBUG_STATS_STRUCT_LEN 48 +#define IPA_LNX_GSI_TX_DEBUG_STATS_STRUCT_LEN 56 +#define IPA_LNX_GSI_DEBUG_STATS_STRUCT_LEN (8 + 48 + 56) +#define IPA_LNX_PIPE_INFO_STATS_STRUCT_LEN 120 +/* IPA Linux wlan instance stats structures */ +#define IPA_LNX_WLAN_INSTANCE_INFO_STRUCT_LEN (32 + 112 + 120) +#define IPA_LNX_WLAN_INST_STATS_STRUCT_LEN (8 + 264) +/* IPA Linux eth instance stats structures */ +#define IPA_LNX_ETH_INSTANCE_INFO_STRUCT_LEN (16 + 112 + 120) +#define IPA_LNX_ETH_INST_STATS_STRUCT_LEN (8 + 248) +/* IPA Linux usb instance stats structures */ +#define IPA_LNX_USB_INSTANCE_INFO_STRUCT_LEN (16 + 112 + 120) +#define IPA_LNX_USB_INST_STATS_STRUCT_LEN (8 + 248) +/* IPA Linux mhip instance stats structures */ +#define IPA_LNX_MHIP_INSTANCE_INFO_STRUCT_LEN (16 + 112 + 120) +#define IPA_LNX_MHIP_INST_STATS_STRUCT_LEN (8 + 248) +/* IPA Linux Instance allocation info structures */ +#define IPA_LNX_EACH_INST_ALLOC_INFO_STRUCT_LEN (24 + 12 + 12 + 16) +#define IPA_LNX_STATS_ALL_INFO_STRUCT_LEN (32 + 128 + 128 + 128) +#define IPA_LNX_STATS_SPEARHEAD_CTX_STRUCT_LEN (8 + 4 + 416) + /** * enum ipa_client_type - names for the various IPA "clients" * these are from the perspective of the clients, for e.g. From d80149a113666b6f3df7600f583f5e7995b88030 Mon Sep 17 00:00:00 2001 From: Sarthak Garg Date: Tue, 9 Mar 2021 13:01:59 +0530 Subject: [PATCH 10/90] mmc: sdhci-msm: Update TLMM_NORTH_SPARE register as per vdd_px2 supply On blair some current leakage is seen wrt to vdd_px2 pads. Pad team recommended to update bit 15 of TLMM_NORTH_SPARE register which is mapped to core_ie bit of SDC2 pads to avoid this leakage. As per blair TLMM HPG, recommendation is to write 0/1 to TLMM_NORTH_SPARE register before turning off/after turning ON vdd_px2. Change-Id: I7aaecd93de86f5d5b9af57656ac85e36b2d519fb Signed-off-by: Sarthak Garg --- drivers/mmc/host/sdhci-msm.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 9b30ce9562b9..8288f6b01d39 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "sdhci-pltfm.h" #include "cqhci.h" @@ -164,6 +165,10 @@ #define CQHCI_VENDOR_DIS_RST_ON_CQ_EN (0x3 << 13) #define RCLK_TOGGLE BIT(2) +/* enum for writing to TLMM_NORTH_SPARE register as defined by pinctrl API */ +#define TLMM_NORTH_SPARE 2 +#define TLMM_NORTH_SPARE_CORE_IE BIT(15) + struct sdhci_msm_offset { u32 core_hc_mode; u32 core_mci_data_cnt; @@ -2226,6 +2231,7 @@ static int sdhci_msm_setup_vreg(struct sdhci_msm_host *msm_host, struct sdhci_msm_vreg_data *curr_slot; struct sdhci_msm_reg_data *vreg_table[2]; struct mmc_host *mmc = msm_host->mmc; + u32 val = 0; curr_slot = msm_host->vreg_data; if (!curr_slot) { @@ -2241,6 +2247,20 @@ static int sdhci_msm_setup_vreg(struct sdhci_msm_host *msm_host, if (!enable && vreg_table[1]->is_always_on && !mmc->card) vreg_table[1]->is_always_on = false; + if (!enable && !(mmc->caps & MMC_CAP_NONREMOVABLE)) { + + /* + * Disable Receiver of the Pad to avoid crowbar currents + * when Pad power supplies are collapsed. Provide SW control + * on the core_ie of SDC2 Pads. SW write 1’b0 + * into the bit 15 of register TLMM_NORTH_SPARE. + */ + + val = msm_spare_read(TLMM_NORTH_SPARE); + val &= ~TLMM_NORTH_SPARE_CORE_IE; + msm_spare_write(TLMM_NORTH_SPARE, val); + } + for (i = 0; i < ARRAY_SIZE(vreg_table); i++) { if (vreg_table[i]) { if (enable) @@ -2251,6 +2271,20 @@ static int sdhci_msm_setup_vreg(struct sdhci_msm_host *msm_host, goto out; } } + + if (enable && !(mmc->caps & MMC_CAP_NONREMOVABLE)) { + + /* + * Disable Receiver of the Pad to avoid crowbar currents + * when Pad power supplies are collapsed. Provide SW control + * on the core_ie of SDC2 Pads. SW write 1’b1 + * into the bit 15 of register TLMM_NORTH_SPARE. + */ + + val = msm_spare_read(TLMM_NORTH_SPARE); + val |= TLMM_NORTH_SPARE_CORE_IE; + msm_spare_write(TLMM_NORTH_SPARE, val); + } out: return ret; } From 24bf1e88dd6fd2e71d0d8601cbbd0fa4d0fe6114 Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Thu, 10 Dec 2020 13:48:35 +0530 Subject: [PATCH 11/90] msm: mhi: Stop sending event completion, during channel reset The change is to prevent sending channel completion events, post a channel stop or reset command. Sending a channel completion post reset can cause the RP to in reset value and hence the completion will be treated as an out of order event. Change-Id: I2cdd7a705a001689609ff8fa1f31fe11d61e5ea8 Signed-off-by: Subramanian Ananthanarayanan Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 0eeef414892c..3bc4d448d8bd 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -476,6 +476,22 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring, if (!ereq->is_cmd_cpl) { ch = ereq->context; + /* + * Take Channel ring event lock to prevent sending + * completion command while the channel is getting + * reset/stopped. + * Abort sending completion event if channel has moved to + * stopped state. + */ + mutex_lock(&ch->ring->event_lock); + if (ch->state == MHI_DEV_CH_STOPPED || + ch->state == MHI_DEV_CH_PENDING_STOP) { + mhi_log(MHI_MSG_ERROR, + "Ch:%d is in %d state, abort sending completion evnt\n" + , ch->ch_id, ch->state); + rc = -ENXIO; + goto exit; + } mhi_log(MHI_MSG_VERBOSE, "Flushing %d cmpl events of ch %d\n", ereq->num_events, ch->ch_id); } else { @@ -487,8 +503,7 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring, rc = mhi_dev_add_element(ring, ereq->tr_events, ereq, evt_len); if (rc) { pr_err("%s(): error in adding element rc %d\n", __func__, rc); - mutex_unlock(&ring->event_lock); - return rc; + goto exit; } ring->ring_ctx_shadow->ev.rp = (ring->rd_offset * @@ -537,6 +552,9 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring, pr_err("%s: error sending in msi\n", __func__); } +exit: + if (!ereq->is_cmd_cpl) + mutex_unlock(&ch->ring->event_lock); mutex_unlock(&ring->event_lock); return rc; } @@ -1972,6 +1990,7 @@ send_start_completion_event: ch = &mhi->ch[ch_id]; mutex_lock(&ch->ch_lock); + mutex_lock(&ch->ring->event_lock); mhi->ch[ch_id].state = MHI_DEV_CH_PENDING_STOP; rc = mhi_dev_process_stop_cmd( @@ -1980,6 +1999,7 @@ send_start_completion_event: if (rc) pr_err("stop event send failed\n"); + mutex_unlock(&ch->ring->event_lock); mutex_unlock(&ch->ch_lock); mhi_update_state_info_ch(ch_id, MHI_STATE_DISCONNECTED); /* Trigger callback to clients */ @@ -2030,6 +2050,7 @@ send_start_completion_event: ch = &mhi->ch[ch_id]; mutex_lock(&ch->ch_lock); + mutex_lock(&ch->ring->event_lock); /* hard stop and set the channel to stop */ mhi->ch_ctx_cache[ch_id].ch_state = @@ -2057,6 +2078,7 @@ send_start_completion_event: MHI_CMD_COMPL_CODE_SUCCESS); if (rc) pr_err("Error sending command completion event\n"); + mutex_unlock(&ch->ring->event_lock); mutex_unlock(&ch->ch_lock); mhi_update_state_info_ch(ch_id, MHI_STATE_DISCONNECTED); mhi_dev_trigger_cb(ch_id); From bf72f4d92f3c347a46fd90f31c74896b9ef3fed3 Mon Sep 17 00:00:00 2001 From: Gauri Joshi Date: Thu, 21 Jan 2021 11:26:19 +0530 Subject: [PATCH 12/90] msm: mhi_dev: stop reading host CH ring when CH is reset The host can asynchronously reset the channel and this can happen when there are pending ch interrupts to process on the EP. The change is to prevent processing the old DB rung by the host by adding delaying channel reset cmd ack. Change-Id: I020a9961196867a7cc1ac8e4f309d0a75c38f6f5 Signed-off-by: Subramanian Ananthanarayanan Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi.c | 118 ++++++++++++++++++++--------- drivers/platform/msm/mhi_dev/mhi.h | 2 + 2 files changed, 84 insertions(+), 36 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 3bc4d448d8bd..c2d9d1921414 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -1829,6 +1829,44 @@ static int mhi_dev_process_stop_cmd(struct mhi_dev_ring *ring, uint32_t ch_id, MHI_CMD_COMPL_CODE_SUCCESS); } +static void mhi_dev_process_reset_cmd(struct mhi_dev *mhi, int ch_id) +{ + int rc = 0; + struct mhi_dev_channel *ch; + struct mhi_addr host_addr; + + ch = &mhi->ch[ch_id]; + /* hard stop and set the channel to stop */ + mhi->ch_ctx_cache[ch_id].ch_state = + MHI_DEV_CH_STATE_DISABLED; + mhi->ch[ch_id].state = MHI_DEV_CH_STOPPED; + + if (mhi->use_ipa) + host_addr.host_pa = + mhi->ch_ctx_shadow.host_pa + + (sizeof(struct mhi_dev_ch_ctx) * ch_id); + else + host_addr.device_va = + mhi->ch_ctx_shadow.device_va + + (sizeof(struct mhi_dev_ch_ctx) * ch_id); + + host_addr.virt_addr = + &mhi->ch_ctx_cache[ch_id].ch_state; + host_addr.size = sizeof(enum mhi_dev_ch_ctx_state); + + /* update the channel state in the host */ + mhi_ctx->write_to_host(mhi, &host_addr, NULL, + MHI_DEV_DMA_SYNC); + + /* send the completion event to the host */ + rc = mhi_dev_send_cmd_comp_event(mhi, + MHI_CMD_COMPL_CODE_SUCCESS); + if (rc) + pr_err("Error sending command completion event\n"); + + ch->reset_pending = false; +} + static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, union mhi_dev_ring_element_type *el, void *ctx) { @@ -2046,38 +2084,19 @@ send_start_completion_event: pr_err("Channel not opened for %d\n", ch_id); return; } - ch = &mhi->ch[ch_id]; - mutex_lock(&ch->ch_lock); mutex_lock(&ch->ring->event_lock); - - /* hard stop and set the channel to stop */ - mhi->ch_ctx_cache[ch_id].ch_state = - MHI_DEV_CH_STATE_DISABLED; - mhi->ch[ch_id].state = MHI_DEV_CH_STOPPED; - if (MHI_USE_DMA(mhi)) - host_addr.host_pa = - mhi->ch_ctx_shadow.host_pa + - (sizeof(struct mhi_dev_ch_ctx) * ch_id); - else - host_addr.device_va = - mhi->ch_ctx_shadow.device_va + - (sizeof(struct mhi_dev_ch_ctx) * ch_id); - - host_addr.virt_addr = - &mhi->ch_ctx_cache[ch_id].ch_state; - host_addr.size = sizeof(enum mhi_dev_ch_ctx_state); - - /* update the channel state in the host */ - mhi_ctx->write_to_host(mhi, &host_addr, NULL, - MHI_DEV_DMA_SYNC); - - /* send the completion event to the host */ - rc = mhi_dev_send_cmd_comp_event(mhi, - MHI_CMD_COMPL_CODE_SUCCESS); - if (rc) - pr_err("Error sending command completion event\n"); + if (ch->db_pending) { + mhi_log(MHI_MSG_ERROR, + "skipping reset cmd ack for channel %d\n", + ch_id); + ch->reset_pending = true; + mutex_unlock(&ch->ring->event_lock); + mutex_unlock(&ch->ch_lock); + return; + } + mhi_dev_process_reset_cmd(mhi, ch_id); mutex_unlock(&ch->ring->event_lock); mutex_unlock(&ch->ch_lock); mhi_update_state_info_ch(ch_id, MHI_STATE_DISCONNECTED); @@ -2126,9 +2145,10 @@ static void mhi_dev_process_ring_pending(struct work_struct *work) struct list_head *cp, *q; struct mhi_dev_ring *ring; struct mhi_dev_channel *ch; - int rc = 0; + int rc = 0, ch_id; mutex_lock(&mhi_ctx->mhi_lock); + rc = mhi_dev_process_ring(&mhi->ring[mhi->cmd_ring_idx]); if (rc) { mhi_log(MHI_MSG_ERROR, "error processing command ring\n"); @@ -2139,12 +2159,6 @@ static void mhi_dev_process_ring_pending(struct work_struct *work) ring = list_entry(cp, struct mhi_dev_ring, list); list_del(cp); mhi_log(MHI_MSG_VERBOSE, "processing ring %d\n", ring->id); - rc = mhi_dev_process_ring(ring); - if (rc) { - mhi_log(MHI_MSG_ERROR, - "error processing ring %d\n", ring->id); - goto exit; - } if (ring->id < mhi->ch_ring_start) { mhi_log(MHI_MSG_ERROR, @@ -2153,12 +2167,39 @@ static void mhi_dev_process_ring_pending(struct work_struct *work) } ch = &mhi->ch[ring->id - mhi->ch_ring_start]; + mutex_lock(&ch->ch_lock); + + rc = mhi_dev_process_ring(ring); + if (rc) { + mhi_log(MHI_MSG_ERROR, + "error processing ring %d\n", ring->id); + mutex_unlock(&ch->ch_lock); + goto exit; + } + ch->db_pending = false; + + if (ch->reset_pending) { + /* + * The channel might be reset asynchronously by the + * host, below reset ack is in case the channel + * was stopped/reset with pending DB. + */ + ch_id = ch->ch_id; + mhi_log(MHI_MSG_VERBOSE, + "processing pending ch:%d reset\n", ch_id); + mutex_lock(&ch->ring->event_lock); + mhi_dev_process_reset_cmd(mhi, ch_id); + mutex_unlock(&ch->ring->event_lock); + } + rc = mhi_dev_mmio_enable_chdb_a7(mhi, ch->ch_id); if (rc) { mhi_log(MHI_MSG_ERROR, "error enabling chdb interrupt for %d\n", ch->ch_id); + mutex_unlock(&ch->ch_lock); goto exit; } + mutex_unlock(&ch->ch_lock); } exit: @@ -2195,6 +2236,7 @@ static void mhi_dev_queue_channel_db(struct mhi_dev *mhi, uint32_t chintr_value, uint32_t ch_num) { struct mhi_dev_ring *ring; + struct mhi_dev_channel *ch; int rc = 0; for (; chintr_value; ch_num++, chintr_value >>= 1) { @@ -2206,6 +2248,10 @@ static void mhi_dev_queue_channel_db(struct mhi_dev *mhi, } mhi_ring_set_state(ring, RING_STATE_PENDING); list_add(&ring->list, &mhi->process_ring_list); + ch = &mhi->ch[ch_num]; + mutex_lock(&ch->ch_lock); + ch->db_pending = true; + mutex_unlock(&ch->ch_lock); rc = mhi_dev_mmio_disable_chdb_a7(mhi, ch_num); if (rc) { pr_err("Error disabling chdb\n"); diff --git a/drivers/platform/msm/mhi_dev/mhi.h b/drivers/platform/msm/mhi_dev/mhi.h index 7fec5e68a001..c477bfa7686b 100644 --- a/drivers/platform/msm/mhi_dev/mhi.h +++ b/drivers/platform/msm/mhi_dev/mhi.h @@ -509,6 +509,8 @@ struct mhi_dev_channel { uint32_t msi_cnt; uint32_t flush_req_cnt; bool skip_td; + bool db_pending; + bool reset_pending; }; /* Structure device for mhi dev */ From 446bace1c84387a93899a49c883662efa72e20e0 Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Tue, 23 Feb 2021 12:07:42 +0530 Subject: [PATCH 13/90] msm: mhi_dev: Use Ring event lock while sending write completion Change involes usage of event ring mutex while sending write channel completion events. Change-Id: I3817e140551954a732e26d097d53176d573bf7f5 Signed-off-by: Subramanian Ananthanarayanan --- drivers/platform/msm/mhi_dev/mhi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index c2d9d1921414..9bdfd9878469 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -1617,7 +1617,7 @@ int mhi_dev_send_event(struct mhi_dev *mhi, int evnt_ring, } } - mutex_lock(&mhi->mhi_event_lock); + mutex_lock(&ring->event_lock); /* add the ring element */ mhi_dev_add_element(ring, el, NULL, 0); @@ -1650,7 +1650,6 @@ int mhi_dev_send_event(struct mhi_dev *mhi, int evnt_ring, */ wmb(); - mutex_unlock(&mhi->mhi_event_lock); mhi_log(MHI_MSG_VERBOSE, "event sent:\n"); mhi_log(MHI_MSG_VERBOSE, "evnt ptr : 0x%llx\n", el->evt_tr_comp.ptr); mhi_log(MHI_MSG_VERBOSE, "evnt len : 0x%x\n", el->evt_tr_comp.len); @@ -1663,6 +1662,7 @@ int mhi_dev_send_event(struct mhi_dev *mhi, int evnt_ring, else rc = ep_pcie_trigger_msi(mhi_ctx->phandle, ctx->ev.msivec); + mutex_unlock(&ring->event_lock); return rc; } From bb1be52e1c84fc5e25bdf8fc398ab7638b05e3d5 Mon Sep 17 00:00:00 2001 From: Gauri Joshi Date: Thu, 18 Mar 2021 10:39:17 +0530 Subject: [PATCH 14/90] msm: mhi: Prevent flush queue if channel is closed Change is to prevent flush events being queued post channel close and wait for pending flush event callbacks prior to channel close. Change-Id: Ic168be0a187b3edcfeccedc565fb02673eaee883 Signed-off-by: Subramanian Ananthanarayanan Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi.c | 47 +++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 9bdfd9878469..46ba74e89570 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -615,18 +615,21 @@ static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi, unsigned long flags; struct event_req *flush_ereq; - /* - * Channel got stopped or closed with transfers pending - * Do not send completion events to host - */ - if (ch->state == MHI_DEV_CH_CLOSED || - ch->state == MHI_DEV_CH_STOPPED) { - mhi_log(MHI_MSG_DBG, "Ch %d closed with %d writes pending\n", - ch->ch_id, ch->pend_wr_count + 1); - return -ENODEV; - } - do { + + /* + * Channel got stopped or closed with transfers pending + * Do not send completion events to host + */ + if (ch->state == MHI_DEV_CH_CLOSED || + ch->state == MHI_DEV_CH_STOPPED) { + mhi_log(MHI_MSG_DBG, + "Ch %d closed with %d writes pending\n", + ch->ch_id, ch->pend_wr_count + 1); + rc = -ENODEV; + break; + } + spin_lock_irqsave(&mhi->lock, flags); if (list_empty(&ch->flush_event_req_buffers)) { spin_unlock_irqrestore(&mhi->lock, flags); @@ -652,7 +655,8 @@ static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi, "Invalid cmpl evt buf - start %pK, end %pK\n", flush_ereq->tr_events, flush_ereq->tr_events + flush_ereq->num_events); - return -EINVAL; + rc = -EINVAL; + break; } rc = mhi_dev_send_multiple_tr_events(mhi, mhi->ch_ctx_cache[ch->ch_id].err_indx, @@ -2429,6 +2433,7 @@ static void mhi_dev_transfer_completion_cb(void *mreq) /* Trigger client call back */ req->client_cb(req); + mutex_lock(&ch->ch_lock); /* Flush read completions to host */ if (snd_cmpl && mhi_ctx->ch_ctx_cache[ch->ch_id].ch_type == MHI_DEV_CH_TYPE_OUTBOUND_CHANNEL) { @@ -2439,7 +2444,7 @@ static void mhi_dev_transfer_completion_cb(void *mreq) "Failed to flush read completions to host\n"); } } - + mutex_unlock(&ch->ch_lock); if (ch->state == MHI_DEV_CH_PENDING_STOP) { ch->state = MHI_DEV_CH_STOPPED; rc = mhi_dev_process_stop_cmd(ch->ring, ch->ch_id, mhi_ctx); @@ -3134,7 +3139,8 @@ void mhi_dev_close_channel(struct mhi_dev_client *handle) ch = handle->channel; do { - if (ch->pend_wr_count) { + if (ch->pend_wr_count && + !list_empty(&ch->event_req_buffers)) { usleep_range(MHI_DEV_CH_CLOSE_TIMEOUT_MIN, MHI_DEV_CH_CLOSE_TIMEOUT_MAX); } else @@ -3146,6 +3152,9 @@ void mhi_dev_close_channel(struct mhi_dev_client *handle) if (ch->pend_wr_count) mhi_log(MHI_MSG_ERROR, "%d writes pending for channel %d\n", ch->pend_wr_count, ch->ch_id); + if (!list_empty(&ch->event_req_buffers)) + mhi_log(MHI_MSG_ERROR, "%d pending flush for channel %d\n", + ch->pend_wr_count, ch->ch_id); if (ch->state != MHI_DEV_CH_PENDING_START) if ((ch->ch_type == MHI_DEV_CH_TYPE_OUTBOUND_CHANNEL && @@ -3157,14 +3166,24 @@ void mhi_dev_close_channel(struct mhi_dev_client *handle) ch->state = MHI_DEV_CH_CLOSED; ch->active_client = NULL; kfree(ch->ereqs); + mhi_log(MHI_MSG_INFO, + "MEM_DEALLOC:ch:%d size:%d EREQ\n", + ch->ch_id, ch->evt_req_size); kfree(ch->tr_events); + mhi_log(MHI_MSG_INFO, + "MEM_DEALLOC:ch:%d size:%d TR_EVENTS\n", + ch->ch_id, ch->evt_buf_size); ch->evt_buf_size = 0; ch->evt_req_size = 0; ch->ereqs = NULL; ch->tr_events = NULL; kfree(handle); + mhi_log(MHI_MSG_INFO, + "MEM_ALLOC:ch:%d size:%d CLNT_HANDLE\n", + ch->ch_id, sizeof(struct mhi_dev_client)); mutex_unlock(&ch->ch_lock); + return; } EXPORT_SYMBOL(mhi_dev_close_channel); From db6c7f0843acd715fcbbff9a2cf334cbc448af8c Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Mon, 16 Nov 2020 14:16:40 +0530 Subject: [PATCH 15/90] msm: mhi_dev: Serialize UCI open and close file node operations Multiple clients might perform open and close file operations simultaneously on the same file node created by UCI. To avoid race conditions which might result in invalid accesses or crashes, the open and close operations are serialized. Change-Id: Ic6a290a2c6af25bcd60983a7b531bf1287201821 Signed-off-by: Subramanian Ananthanarayanan Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi_uci.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c index 2d04c2cbf5b0..c5cb081e8bcc 100644 --- a/drivers/platform/msm/mhi_dev/mhi_uci.c +++ b/drivers/platform/msm/mhi_dev/mhi_uci.c @@ -372,6 +372,7 @@ struct uci_client { struct mhi_uci_ctxt_t *uci_ctxt; struct mutex in_chan_lock; struct mutex out_chan_lock; + struct mutex client_lock; spinlock_t req_lock; unsigned int f_flags; /* Pointer to dynamically allocated mhi_req structs */ @@ -779,6 +780,8 @@ static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait) if (!uci_handle) return -ENODEV; + mutex_lock(&uci_handle->client_lock); + poll_wait(file, &uci_handle->read_wq, wait); poll_wait(file, &uci_handle->write_wq, wait); /* @@ -786,8 +789,10 @@ static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait) * to poll are in connected state and return with the * appropriate mask if channels are disconnected. */ - if (!mhi_uci_are_channels_connected(uci_handle)) { + if (!atomic_read(&uci_handle->mhi_chans_open) || + !mhi_uci_are_channels_connected(uci_handle)) { mask = POLLHUP; + mutex_unlock(&uci_handle->client_lock); return mask; } mask = uci_handle->at_ctrl_mask; @@ -807,6 +812,8 @@ static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait) uci_log(UCI_DBG_VERBOSE, "Client attempted to poll chan %d, returning mask 0x%x\n", uci_handle->in_chan, mask); + mutex_unlock(&uci_handle->client_lock); + return mask; } @@ -1066,6 +1073,7 @@ static int mhi_uci_client_open(struct inode *mhi_inode, return -EINVAL; } + mutex_lock(&uci_handle->client_lock); uci_log(UCI_DBG_DBG, "Client opened struct device node 0x%x, ref count 0x%x\n", iminor(mhi_inode), atomic_read(&uci_handle->ref_count)); @@ -1073,6 +1081,7 @@ static int mhi_uci_client_open(struct inode *mhi_inode, if (!uci_handle) { atomic_dec(&uci_handle->ref_count); uci_log(UCI_DBG_DBG, "No memory, returning failure\n"); + mutex_unlock(&uci_handle->client_lock); return -ENOMEM; } uci_handle->uci_ctxt = &uci_ctxt; @@ -1090,11 +1099,13 @@ static int mhi_uci_client_open(struct inode *mhi_inode, uci_log(UCI_DBG_INFO, "Closing failed channel\n"); } + mutex_unlock(&uci_handle->client_lock); return rc; } } } file_handle->private_data = uci_handle; + mutex_unlock(&uci_handle->client_lock); return 0; @@ -1111,10 +1122,12 @@ static int mhi_uci_client_release(struct inode *mhi_inode, if (!uci_handle) return -EINVAL; + mutex_lock(&uci_handle->client_lock); 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); + mutex_unlock(&uci_handle->client_lock); return -EINVAL; } @@ -1122,6 +1135,7 @@ static int mhi_uci_client_release(struct inode *mhi_inode, uci_log(UCI_DBG_DBG, "Client close chan %d, ref count 0x%x\n", iminor(mhi_inode), atomic_read(&uci_handle->ref_count)); + mutex_unlock(&uci_handle->client_lock); return 0; } @@ -1185,6 +1199,7 @@ static int mhi_uci_client_release(struct inode *mhi_inode, atomic_set(&uci_handle->read_data_ready, 0); atomic_set(&uci_handle->write_data_ready, 0); file_handle->private_data = NULL; + mutex_unlock(&uci_handle->client_lock); return 0; } @@ -1667,6 +1682,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); + mutex_init(&mhi_client->client_lock); spin_lock_init(&mhi_client->req_lock); /* Init the completion event for AT ctrl read */ init_completion(&mhi_client->at_ctrl_read_done); From e1a0f4d9f1452b390ed9f82487cc6ca5f8c5f0f7 Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Wed, 3 Mar 2021 18:02:53 +0530 Subject: [PATCH 16/90] msm: mhi_dev: Use req_lock spinlock during client release The change is to use req_lock spinlock during client release and to use the same spinlock while checking for is_stale during read/write completion callbacks. Change-Id: I7ebafecb7503fa8521fa8f849cabf4b82bbc2f53 Signed-off-by: Subramanian Ananthanarayanan Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi_uci.c | 39 ++++++++++++++++---------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c index c5cb081e8bcc..1e408cdf113f 100644 --- a/drivers/platform/msm/mhi_dev/mhi_uci.c +++ b/drivers/platform/msm/mhi_dev/mhi_uci.c @@ -555,15 +555,25 @@ static struct mhi_req *mhi_uci_get_req(struct uci_client *uci_handle) return req; } -static void mhi_uci_put_req(struct uci_client *uci_handle, struct mhi_req *req) +static int mhi_uci_put_req(struct uci_client *uci_handle, struct mhi_req *req) { unsigned long flags; spin_lock_irqsave(&uci_handle->req_lock, flags); + if (req->is_stale) { + uci_log(UCI_DBG_VERBOSE, + "Got stale completion for ch %d, ignoring\n", + req->chan); + spin_unlock_irqrestore(&uci_handle->req_lock, flags); + return -EINVAL; + } + /* 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); + + return 0; } static void mhi_uci_write_completion_cb(void *req) @@ -579,17 +589,12 @@ static void mhi_uci_write_completion_cb(void *req) * 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; + if (mhi_uci_put_req(uci_handle, ureq)) 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); } @@ -599,19 +604,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); + /* + * If this is a delayed read completion, just clear + * the stale flag and return. The ureq was added to + * the free list when client called release function. + */ + if (mhi_uci_put_req(uci_handle, ureq)) + return; + complete(&uci_handle->read_done); } @@ -1118,6 +1123,7 @@ static int mhi_uci_client_release(struct inode *mhi_inode, const struct chan_attr *in_chan_attr; int count = 0, i; struct mhi_req *ureq; + unsigned long flags; if (!uci_handle) return -EINVAL; @@ -1173,6 +1179,8 @@ static int mhi_uci_client_release(struct inode *mhi_inode, * to client if the transfer completes later. */ count = 0; + + spin_lock_irqsave(&uci_handle->req_lock, flags); while (!(list_empty(&uci_handle->in_use_list))) { ureq = container_of(uci_handle->in_use_list.next, struct mhi_req, list); @@ -1184,6 +1192,7 @@ static int mhi_uci_client_release(struct inode *mhi_inode, list_add_tail(&ureq->list, &uci_handle->req_list); count++; } + spin_unlock_irqrestore(&uci_handle->req_lock, flags); if (count) uci_log(UCI_DBG_DBG, "Client %d closed with %d transfers pending\n", From cdc28c2b3f315289d5ecbadaad6e11d9bee5a942 Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Tue, 9 Mar 2021 10:43:58 +0530 Subject: [PATCH 17/90] msm: mhi_dev: Check to prevent in_use_list access Added a check for accessing in_use_list only in async case. Change-Id: I842f9b9feb688d75152f7b2639c17c25c3376236 Signed-off-by: Subramanian Ananthanarayanan Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi_uci.c | 37 +++++++++++++++----------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c index 1e408cdf113f..8d2f247144cb 100644 --- a/drivers/platform/msm/mhi_dev/mhi_uci.c +++ b/drivers/platform/msm/mhi_dev/mhi_uci.c @@ -1181,16 +1181,19 @@ static int mhi_uci_client_release(struct inode *mhi_inode, count = 0; spin_lock_irqsave(&uci_handle->req_lock, flags); - while (!(list_empty(&uci_handle->in_use_list))) { - ureq = container_of(uci_handle->in_use_list.next, + if (!(uci_handle->f_flags & O_SYNC)) { + 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++; + 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++; + } } spin_unlock_irqrestore(&uci_handle->req_lock, flags); if (count) @@ -2091,13 +2094,15 @@ static void mhi_uci_at_ctrl_client_cb(struct mhi_dev_client_cb_data *cb_data) mhi_dev_close_channel(client->out_handle); mhi_dev_close_channel(client->in_handle); - /* Add back reqs for 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); + /* Add back reqs from in-use list, if any, to free list */ + if (!(client->f_flags & O_SYNC)) { + 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); + } } for (i = 0; i < (client->in_chan_attr->nr_trbs); i++) { From fa2304691b1be4e4ae7bf5f33af5bc6eb486eb1e Mon Sep 17 00:00:00 2001 From: Nitesh Gupta Date: Mon, 1 Mar 2021 09:31:13 +0530 Subject: [PATCH 18/90] msm: mhi_dev: Handle potential deadlock situation With the current logic, MHI driver will hold channel lock while processing the ring element and triggers callback for the clients. Some clients are issuing read requests for the channel in the callback context. MHI driver will try to acquire the same channel lock in read api leading to a deadlock situation. Modify the logic to avoid holding channel lock while processing the ring elements. Change-Id: I62ac28d5eb06e3c9b12437f02288cfe1cdb2bea2 Signed-off-by: Nitesh Gupta Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 46ba74e89570..80320c19045e 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -2171,15 +2171,14 @@ static void mhi_dev_process_ring_pending(struct work_struct *work) } ch = &mhi->ch[ring->id - mhi->ch_ring_start]; - mutex_lock(&ch->ch_lock); rc = mhi_dev_process_ring(ring); if (rc) { mhi_log(MHI_MSG_ERROR, "error processing ring %d\n", ring->id); - mutex_unlock(&ch->ch_lock); goto exit; } + mutex_lock(&ch->ch_lock); ch->db_pending = false; if (ch->reset_pending) { @@ -3262,9 +3261,9 @@ int mhi_dev_read_channel(struct mhi_req *mreq) mutex_lock(&ch->ch_lock); do { - if (ch->state == MHI_DEV_CH_STOPPED) { + if (ch->state == MHI_DEV_CH_STOPPED || ch->reset_pending) { mhi_log(MHI_MSG_VERBOSE, - "channel (%d) already stopped\n", + "channel (%d) already stopped or RST pending\n", mreq->chan); bytes_read = -1; goto exit; @@ -3445,9 +3444,10 @@ int mhi_dev_write_channel(struct mhi_req *wreq) } ch->pend_wr_count++; - if (ch->state == MHI_DEV_CH_STOPPED) { + if (ch->state == MHI_DEV_CH_STOPPED || ch->reset_pending) { mhi_log(MHI_MSG_ERROR, - "channel %d already stopped\n", wreq->chan); + "channel %d already stopped or RST pending\n", + wreq->chan); bytes_written = -1; goto exit; } From f2a589c5b1b06c70f2b3e3d03605e2f20315fbd5 Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Thu, 28 Jan 2021 20:01:19 +0530 Subject: [PATCH 19/90] msm: mhi: Queue pending_ring WQ post channel DB check Change is to queue pending_ring post updating CH db_pend variable. This is done to avoid chdb_ctrl_work WQ from getting pre-empted and pending_ring WQ executing. Change-Id: I3504c89006c1231251be6efdfebac52b0fd35cc9 Signed-off-by: Subramanian Ananthanarayanan Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi.c | 31 ++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 80320c19045e..4e1a15dd8c72 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -2260,20 +2260,29 @@ static void mhi_dev_queue_channel_db(struct mhi_dev *mhi, pr_err("Error disabling chdb\n"); return; } - queue_work(mhi->pending_ring_wq, &mhi->pending_work); } } } -static void mhi_dev_check_channel_interrupt(struct mhi_dev *mhi) +/* + * mhi_dev_check_channel_interrupt () - function called + * to check if CH DB interrupts are present to process. + * + * Return : true if valid interrupts are present + * to process, false if not. + */ + +static bool mhi_dev_check_channel_interrupt(struct mhi_dev *mhi) { int i, rc = 0; + bool pending_work = false; uint32_t chintr_value = 0, ch_num = 0; rc = mhi_dev_mmio_read_chdb_status_interrupts(mhi); if (rc) { - pr_err("Read channel db\n"); - return; + mhi_log(MHI_MSG_ERROR, + "Error while reading CH DB\n"); + return pending_work; } for (i = 0; i < MHI_MASK_ROWS_CH_EV_DB; i++) { @@ -2281,6 +2290,7 @@ static void mhi_dev_check_channel_interrupt(struct mhi_dev *mhi) /* Process channel status whose mask is enabled */ chintr_value = (mhi->chdb[i].status & mhi->chdb[i].mask); if (chintr_value) { + pending_work = true; mhi_log(MHI_MSG_VERBOSE, "processing id: %d, ch interrupt 0x%x\n", i, chintr_value); @@ -2288,11 +2298,13 @@ static void mhi_dev_check_channel_interrupt(struct mhi_dev *mhi) rc = mhi_dev_mmio_write(mhi, MHI_CHDB_INT_CLEAR_A7_n(i), mhi->chdb[i].status); if (rc) { - pr_err("Error writing interrupt clear for A7\n"); - return; + mhi_log(MHI_MSG_ERROR, + "Error writing interrupt clear for A7\n"); + return pending_work; } } } + return pending_work; } static void mhi_update_state_info_all(enum mhi_ctrl_info info) @@ -2458,6 +2470,7 @@ static void mhi_dev_scheduler(struct work_struct *work) struct mhi_dev *mhi = container_of(work, struct mhi_dev, chdb_ctrl_work); int rc = 0; + bool work_pending = false; uint32_t int_value = 0; struct mhi_dev_ring *ring; enum mhi_dev_state state; @@ -2511,11 +2524,13 @@ static void mhi_dev_scheduler(struct work_struct *work) "processing cmd db interrupt with %d\n", int_value); ring = &mhi->ring[MHI_RING_CMD_ID]; ring->state = RING_STATE_PENDING; - queue_work(mhi->pending_ring_wq, &mhi->pending_work); + work_pending = true; } /* get the specific channel interrupts */ - mhi_dev_check_channel_interrupt(mhi); + work_pending |= mhi_dev_check_channel_interrupt(mhi); + if (work_pending) + queue_work(mhi->pending_ring_wq, &mhi->pending_work); fail: mutex_unlock(&mhi_ctx->mhi_lock); From fe9e8630bfafd3482c97e942150cb50c25062bd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 16 Jun 2021 17:09:51 -0700 Subject: [PATCH 20/90] FROMGIT: bpf: Do not change gso_size during bpf_skb_change_proto() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is technically a backwards incompatible change in behaviour, but I'm going to argue that it is very unlikely to break things, and likely to fix *far* more then it breaks. In no particular order, various reasons follow: (a) I've long had a bug assigned to myself to debug a super rare kernel crash on Android Pixel phones which can (per stacktrace) be traced back to BPF clat IPv6 to IPv4 protocol conversion causing some sort of ugly failure much later on during transmit deep in the GSO engine, AFAICT precisely because of this change to gso_size, though I've never been able to manually reproduce it. I believe it may be related to the particular network offload support of attached USB ethernet dongle being used for tethering off of an IPv6-only cellular connection. The reason might be we end up with more segments than max permitted, or with a GSO packet with only one segment... (either way we break some assumption and hit a BUG_ON) (b) There is no check that the gso_size is > 20 when reducing it by 20, so we might end up with a negative (or underflowing) gso_size or a gso_size of 0. This can't possibly be good. Indeed this is probably somehow exploitable (or at least can result in a kernel crash) by delivering crafted packets and perhaps triggering an infinite loop or a divide by zero... As a reminder: gso_size (MSS) is related to MTU, but not directly derived from it: gso_size/MSS may be significantly smaller then one would get by deriving from local MTU. And on some NICs (which do loose MTU checking on receive, it may even potentially be larger, for example my work pc with 1500 MTU can receive 1520 byte frames [and sometimes does due to bugs in a vendor plat46 implementation]). Indeed even just going from 21 to 1 is potentially problematic because it increases the number of segments by a factor of 21 (think DoS, or some other crash due to too many segments). (c) It's always safe to not increase the gso_size, because it doesn't result in the max packet size increasing. So the skb_increase_gso_size() call was always unnecessary for correctness (and outright undesirable, see later). As such the only part which is potentially dangerous (ie. could cause backwards compatibility issues) is the removal of the skb_decrease_gso_size() call. (d) If the packets are ultimately destined to the local device, then there is absolutely no benefit to playing around with gso_size. It only matters if the packets will egress the device. ie. we're either forwarding, or transmitting from the device. (e) This logic only triggers for packets which are GSO. It does not trigger for skbs which are not GSO. It will not convert a non-GSO MTU sized packet into a GSO packet (and you don't even know what the MTU is, so you can't even fix it). As such your transmit path must *already* be able to handle an MTU 20 bytes larger then your receive path (for IPv4 to IPv6 translation) - and indeed 28 bytes larger due to IPv4 fragments. Thus removing the skb_decrease_gso_size() call doesn't actually increase the size of the packets your transmit side must be able to handle. ie. to handle non-GSO max-MTU packets, the IPv4/IPv6 device/ route MTUs must already be set correctly. Since for example with an IPv4 egress MTU of 1500, IPv4 to IPv6 translation will already build 1520 byte IPv6 frames, so you need a 1520 byte device MTU. This means if your IPv6 device's egress MTU is 1280, your IPv4 route must be 1260 (and actually 1252, because of the need to handle fragments). This is to handle normal non-GSO packets. Thus the reduction is simply not needed for GSO packets, because when they're correctly built, they will already be the right size. (f) TSO/GSO should be able to exactly undo GRO: the number of packets (TCP segments) should not be modified, so that TCP's MSS counting works correctly (this matters for congestion control). If protocol conversion changes the gso_size, then the number of TCP segments may increase or decrease. Packet loss after protocol conversion can result in partial loss of MSS segments that the sender sent. How's the sending TCP stack going to react to receiving ACKs/SACKs in the middle of the segments it sent? (g) skb_{decrease,increase}_gso_size() are already no-ops for GSO_BY_FRAGS case (besides triggering WARN_ON_ONCE). This means you already cannot guarantee that gso_size (and thus resulting packet MTU) is changed. ie. you must assume it won't be changed. (h) changing gso_size is outright buggy for UDP GSO packets, where framing matters (I believe that's also the case for SCTP, but it's already excluded by [g]). So the only remaining case is TCP, which also doesn't want it (see [f]). (i) see also the reasoning on the previous attempt at fixing this (commit fa7b83bf3b156c767f3e4a25bbf3817b08f3ff8e) which shows that the current behaviour causes TCP packet loss: In the forwarding path GRO -> BPF 6 to 4 -> GSO for TCP traffic, the coalesced packet payload can be > MSS, but < MSS + 20. bpf_skb_proto_6_to_4() will upgrade the MSS and it can be > the payload length. After then tcp_gso_segment checks for the payload length if it is <= MSS. The condition is causing the packet to be dropped. tcp_gso_segment(): [...] mss = skb_shinfo(skb)->gso_size; if (unlikely(skb->len <= mss)) goto out; [...] Thus changing the gso_size is simply a very bad idea. Increasing is unnecessary and buggy, and decreasing can go negative. Fixes: 6578171a7ff0 ("bpf: add bpf_skb_change_proto helper") Signed-off-by: Maciej Żenczykowski Signed-off-by: Daniel Borkmann Cc: Dongseok Yi Cc: Willem de Bruijn Link: https://lore.kernel.org/bpf/CANP3RGfjLikQ6dg=YpBU0OeHvyv7JOki7CyOUS9modaXAi-9vQ@mail.gmail.com Link: https://lore.kernel.org/bpf/20210617000953.2787453-2-zenczykowski@gmail.com (cherry picked from commit 364745fbe981a4370f50274475da4675661104df https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=364745fbe981a4370f50274475da4675661104df ) Test: builds, TreeHugger Bug: 188690383 Signed-off-by: Maciej Żenczykowski Change-Id: I0ef3174cbd3caaa42d5779334a9c0bfdc9ab81f5 (cherry picked from commit ea53c24cb060b6aae8c7c60ba46f9cd7530419aa) --- net/core/filter.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index aff14a883ffd..65b6ecb07a59 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -2861,8 +2861,6 @@ static int bpf_skb_proto_4_to_6(struct sk_buff *skb) shinfo->gso_type |= SKB_GSO_TCPV6; } - /* Due to IPv6 header, MSS needs to be downgraded. */ - skb_decrease_gso_size(shinfo, len_diff); /* Header must be checked, and gso_segs recomputed. */ shinfo->gso_type |= SKB_GSO_DODGY; shinfo->gso_segs = 0; @@ -2902,8 +2900,6 @@ static int bpf_skb_proto_6_to_4(struct sk_buff *skb) shinfo->gso_type |= SKB_GSO_TCPV4; } - /* Due to IPv4 header, MSS can be upgraded. */ - skb_increase_gso_size(shinfo, len_diff); /* Header must be checked, and gso_segs recomputed. */ shinfo->gso_type |= SKB_GSO_DODGY; shinfo->gso_segs = 0; From 8c02dc9b1f148786c7fa09acc2efbaa87bf2fdaf Mon Sep 17 00:00:00 2001 From: shufma Date: Mon, 28 Jun 2021 10:48:51 +0800 Subject: [PATCH 21/90] msm: kgsl: Add inode info in kgsl mem dump Add inode info in kgsl mem dump. This correlates egl entries in kgsl mem dump with dmabuf_dump info. Change-Id: Iabfbb456fcd7d941095ae1c75d60822af705a90f Signed-off-by: shufma --- drivers/gpu/msm/kgsl.c | 11 +++++++++++ drivers/gpu/msm/kgsl.h | 2 ++ drivers/gpu/msm/kgsl_debugfs.c | 15 +++++++++------ 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 2388ccd48b70..120fcdc5950a 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -3042,11 +3042,22 @@ void kgsl_get_egl_counts(struct kgsl_mem_entry *entry, } spin_unlock(&kgsl_dmabuf_lock); } + +unsigned long kgsl_get_dmabuf_inode_number(struct kgsl_mem_entry *entry) +{ + struct kgsl_dma_buf_meta *meta = entry->priv_data; + + return meta ? file_inode(meta->dmabuf->file)->i_ino : 0; +} #else void kgsl_get_egl_counts(struct kgsl_mem_entry *entry, int *egl_surface_count, int *egl_image_count) { } + +unsigned long kgsl_get_dmabuf_inode_number(struct kgsl_mem_entry *entry) +{ +} #endif long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index fc2cb005722c..bb5ee365117d 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -453,6 +453,8 @@ void kgsl_mem_entry_destroy(struct kref *kref); void kgsl_get_egl_counts(struct kgsl_mem_entry *entry, int *egl_surface_count, int *egl_image_count); +unsigned long kgsl_get_dmabuf_inode_number(struct kgsl_mem_entry *entry); + struct kgsl_mem_entry * __must_check kgsl_sharedmem_find(struct kgsl_process_private *private, uint64_t gpuaddr); diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c index 937cbb669485..8261d9ad2457 100644 --- a/drivers/gpu/msm/kgsl_debugfs.c +++ b/drivers/gpu/msm/kgsl_debugfs.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2002,2008-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2002,2008-2021, The Linux Foundation. All rights reserved. */ #include @@ -177,6 +177,7 @@ static int print_mem_entry(void *data, void *ptr) struct kgsl_memdesc *m = &entry->memdesc; unsigned int usermem_type = kgsl_memdesc_usermem_type(m); int egl_surface_count = 0, egl_image_count = 0; + unsigned long inode_number = 0; flags[0] = kgsl_memdesc_is_global(m) ? 'g' : '-'; flags[1] = '-'; @@ -192,11 +193,13 @@ static int print_mem_entry(void *data, void *ptr) kgsl_get_memory_usage(usage, sizeof(usage), m->flags); - if (usermem_type == KGSL_MEM_ENTRY_ION) + if (usermem_type == KGSL_MEM_ENTRY_ION) { kgsl_get_egl_counts(entry, &egl_surface_count, &egl_image_count); + inode_number = kgsl_get_dmabuf_inode_number(entry); + } - 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 %16llu %6d %6d %10lu", (uint64_t *)(uintptr_t) m->gpuaddr, /* * Show zero for the useraddr - we can't reliably track @@ -205,7 +208,7 @@ static int print_mem_entry(void *data, void *ptr) 0, m->size, entry->id, flags, memtype_str(usermem_type), usage, (m->sgt ? m->sgt->nents : 0), m->size, - egl_surface_count, egl_image_count); + egl_surface_count, egl_image_count, inode_number); if (entry->metadata[0] != 0) seq_printf(s, " %s", entry->metadata); @@ -273,9 +276,9 @@ static void *process_mem_seq_next(struct seq_file *s, void *ptr, static int process_mem_seq_show(struct seq_file *s, void *ptr) { if (ptr == SEQ_START_TOKEN) { - seq_printf(s, "%16s %16s %16s %5s %9s %10s %16s %5s %16s %6s %6s\n", + seq_printf(s, "%16s %16s %16s %5s %9s %10s %16s %5s %16s %6s %6s %10s\n", "gpuaddr", "useraddr", "size", "id", "flags", "type", - "usage", "sglen", "mapsize", "eglsrf", "eglimg"); + "usage", "sglen", "mapsize", "eglsrf", "eglimg", "inode"); return 0; } else return print_mem_entry(s, ptr); From 3bb65a0c8cc8e8eaba87799ae86b7a177988065e Mon Sep 17 00:00:00 2001 From: Vivek Pernamitta Date: Wed, 9 Jun 2021 18:25:57 +0530 Subject: [PATCH 22/90] msm: pci : Avoid deadlock with recovery and enemurate lock Avoid deadlock scenario when wake interrupt arrives at enumeration time and holds recovery lock and wake handler workqueue tries to acquire enumeration lock. In parallel client driver can call msm_pcie_pm_control for suspend where enumeration lock could be successfully acquired by msm_pcie_pm_control instead by wake handler and waiting for recovery lock which is currently acquired by wake handler (which is currently waiting for enumertion lock) which could leads to deadlock scenario. msm_pcie_enumerate wake handler pm_control | | (suspend thread) | | | | x acquired | x acquired | recovery lock | | enumerate lock | | | o waiting for | | enumerate lock | x released x acquired | enumerate lock | enumerate lock | o waiting for recovery lock we have fixed the order of locking in msm_pcie_pm_control to avoid deadlock scenario. Change-Id: Ifc72c643f7c0793cfa10a953723e953ce73a82b6 Signed-off-by: Vivek Pernamitta --- drivers/pci/controller/pci-msm.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index e58be80b51b2..ce014787acbe 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -7898,6 +7898,7 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user, break; } + mutex_lock(&pcie_dev->recovery_lock); mutex_lock(&pcie_dev->enumerate_lock); /* @@ -7928,12 +7929,12 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user, "PCIe: RC%d: request to suspend the link is rejected\n", pcie_dev->rc_idx); mutex_unlock(&pcie_dev->enumerate_lock); + mutex_unlock(&pcie_dev->recovery_lock); break; } pcie_dev->user_suspend = true; - mutex_lock(&pcie_dev->recovery_lock); ret = msm_pcie_pm_suspend(dev, user, data, options); if (ret) { @@ -7949,9 +7950,9 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user, } } - mutex_unlock(&pcie_dev->recovery_lock); - mutex_unlock(&pcie_dev->enumerate_lock); + + mutex_unlock(&pcie_dev->recovery_lock); break; case MSM_PCIE_RESUME: PCIE_DBG(pcie_dev, @@ -7964,6 +7965,8 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user, break; } + mutex_lock(&pcie_dev->recovery_lock); + /* when link was suspended and link resume is requested */ mutex_lock(&pcie_dev->enumerate_lock); list_for_each_entry(dev_info_itr, &pcie_dev->susp_ep_list, @@ -7990,10 +7993,10 @@ int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user, PCIE_ERR(pcie_dev, "PCIe: RC%d: requested to resume when link is already powered on.\n", pcie_dev->rc_idx); + mutex_unlock(&pcie_dev->recovery_lock); break; } - mutex_lock(&pcie_dev->recovery_lock); ret = msm_pcie_pm_resume(dev, user, data, options); if (ret) { PCIE_ERR(pcie_dev, From 45eba39e076a60660ae6bf579a06541f560f0b3d Mon Sep 17 00:00:00 2001 From: Pradeep P V K Date: Tue, 4 May 2021 16:12:16 +0530 Subject: [PATCH 23/90] wait: add wake_up_sync() The synchronous wakeup interface is available only for the interruptible wakeup. Add it for normal wakeup. Change-Id: Ia4460aa55690d14d203cdc843bd600c9e26c53f1 Suggested-by: Pavankumar Kondeti Signed-off-by: Pradeep P V K --- include/linux/wait.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/wait.h b/include/linux/wait.h index 3eb7cae8206c..3222e3a2daaf 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -215,6 +215,7 @@ void __wake_up_sync(struct wait_queue_head *wq_head, unsigned int mode, int nr); #define wake_up_interruptible_nr(x, nr) __wake_up(x, TASK_INTERRUPTIBLE, nr, NULL) #define wake_up_interruptible_all(x) __wake_up(x, TASK_INTERRUPTIBLE, 0, NULL) #define wake_up_interruptible_sync(x) __wake_up_sync((x), TASK_INTERRUPTIBLE, 1) +#define wake_up_sync(x) __wake_up_sync(x, TASK_NORMAL, 1) /* * Wakeup macros to be used to report events to the targets. From ac247e742523076589e7bb9575c1817860f67dd5 Mon Sep 17 00:00:00 2001 From: Pradeep P V K Date: Tue, 4 May 2021 16:14:34 +0530 Subject: [PATCH 24/90] fuse: give wakeup hints to the scheduler Use synchronous wakeup interface to wakeup the userspace daemon. Scheduler can make use of this hint to find a better CPU for the waker task. Change-Id: I7d077235f9b8fe771869dd7e6fccee7d356d858b Suggested-by: Pavankumar Kondeti Signed-off-by: Pradeep P V K --- fs/fuse/dev.c | 21 ++++++++++++--------- fs/fuse/fuse_i.h | 6 +++--- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index bc618e490068..2756b7a67806 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -204,10 +204,13 @@ static unsigned int fuse_req_hash(u64 unique) /** * A new request is available, wake fiq->waitq */ -static void fuse_dev_wake_and_unlock(struct fuse_iqueue *fiq) +static void fuse_dev_wake_and_unlock(struct fuse_iqueue *fiq, bool sync) __releases(fiq->lock) { - wake_up(&fiq->waitq); + if (sync) + wake_up_sync(&fiq->waitq); + else + wake_up(&fiq->waitq); kill_fasync(&fiq->fasync, SIGIO, POLL_IN); spin_unlock(&fiq->lock); } @@ -220,14 +223,14 @@ const struct fuse_iqueue_ops fuse_dev_fiq_ops = { EXPORT_SYMBOL_GPL(fuse_dev_fiq_ops); static void queue_request_and_unlock(struct fuse_iqueue *fiq, - struct fuse_req *req) + struct fuse_req *req, bool sync) __releases(fiq->lock) { req->in.h.len = sizeof(struct fuse_in_header) + fuse_len_args(req->args->in_numargs, (struct fuse_arg *) req->args->in_args); list_add_tail(&req->list, &fiq->pending); - fiq->ops->wake_pending_and_unlock(fiq); + fiq->ops->wake_pending_and_unlock(fiq, sync); } void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, @@ -242,7 +245,7 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, if (fiq->connected) { fiq->forget_list_tail->next = forget; fiq->forget_list_tail = forget; - fiq->ops->wake_forget_and_unlock(fiq); + fiq->ops->wake_forget_and_unlock(fiq, 0); } else { kfree(forget); spin_unlock(&fiq->lock); @@ -262,7 +265,7 @@ static void flush_bg_queue(struct fuse_conn *fc) fc->active_background++; spin_lock(&fiq->lock); req->in.h.unique = fuse_get_unique(fiq); - queue_request_and_unlock(fiq, req); + queue_request_and_unlock(fiq, req, 0); } } @@ -351,7 +354,7 @@ static int queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req) spin_unlock(&fiq->lock); return 0; } - fiq->ops->wake_interrupt_and_unlock(fiq); + fiq->ops->wake_interrupt_and_unlock(fiq, 0); } else { spin_unlock(&fiq->lock); } @@ -417,7 +420,7 @@ static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) /* acquire extra reference, since request is still needed after fuse_request_end() */ __fuse_get_request(req); - queue_request_and_unlock(fiq, req); + queue_request_and_unlock(fiq, req, 1); request_wait_answer(fc, req); /* Pairs with smp_wmb() in fuse_request_end() */ @@ -588,7 +591,7 @@ static int fuse_simple_notify_reply(struct fuse_conn *fc, spin_lock(&fiq->lock); if (fiq->connected) { - queue_request_and_unlock(fiq, req); + queue_request_and_unlock(fiq, req, 0); } else { err = -ENODEV; spin_unlock(&fiq->lock); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index bf040533bed3..0b3f6a4ab42a 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -379,19 +379,19 @@ struct fuse_iqueue_ops { /** * Signal that a forget has been queued */ - void (*wake_forget_and_unlock)(struct fuse_iqueue *fiq) + void (*wake_forget_and_unlock)(struct fuse_iqueue *fiq, bool sync) __releases(fiq->lock); /** * Signal that an INTERRUPT request has been queued */ - void (*wake_interrupt_and_unlock)(struct fuse_iqueue *fiq) + void (*wake_interrupt_and_unlock)(struct fuse_iqueue *fiq, bool sync) __releases(fiq->lock); /** * Signal that a request has been queued */ - void (*wake_pending_and_unlock)(struct fuse_iqueue *fiq) + void (*wake_pending_and_unlock)(struct fuse_iqueue *fiq, bool sync) __releases(fiq->lock); /** From d2bdf73897ec6066838ecaa73438a971345678c9 Mon Sep 17 00:00:00 2001 From: Kaustubh Pandey Date: Tue, 29 Jun 2021 10:20:54 +0530 Subject: [PATCH 25/90] net: tcp: check for NULL send head during MTU probe skb_peek() can return NULL when the socket write queue is empty. This causes problems when using tcp_for_write_queue_from_safe(), as this macro resolves down to "for (tmp = skb->next; ...", causing a NULL dereference. Fix this by indicating that the tcp send queue head can not be coalesced as there is nothing in it. This fixes the following: Unable to handle kernel NULL pointer dereference pc : tcp_write_xmit+0xe1c/0x1210 lr : tcp_write_xmit+0x38/0x1210 Call trace: tcp_write_xmit+0xe1c/0x1210 tcp_tsq_write+0x110/0x140 tcp_tasklet_func+0x120/0x170 tasklet_action_common+0xec/0x128 tasklet_action+0x20/0x28 By ending the MTU probe because of the empty send head. Change-Id: I0c3283c37ee69a4941c8d9e88519e586c7905d25 Signed-off-by: Sean Tranchetti Signed-off-by: Kaustubh Pandey --- net/ipv4/tcp_output.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 5e311e6a31d5..713c8c62c638 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2071,6 +2071,9 @@ static bool tcp_can_coalesce_send_queue_head(struct sock *sk, int len) struct sk_buff *skb, *next; skb = tcp_send_head(sk); + if (!skb) + return false; + tcp_for_write_queue_from_safe(skb, next, sk) { if (len <= skb->len) break; From 29c674dd9ccbd2bd2c65700b8c7b3002ad0a1958 Mon Sep 17 00:00:00 2001 From: Fei Mao Date: Thu, 24 Jun 2021 19:04:52 +0800 Subject: [PATCH 26/90] input: touchscreen: focaltech: add a new property Add a new property to indicate power's state when sleep. Change-Id: Ic54fbbd0adee8716ad0b2d892814f8ac38b683c5 Signed-off-by: Fei Mao --- .../touchscreen/focaltech_touch/focaltech_core.c | 11 +++++++++-- .../touchscreen/focaltech_touch/focaltech_core.h | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_core.c b/drivers/input/touchscreen/focaltech_touch/focaltech_core.c index 9eefb3e783f4..823caa4fdc8e 100644 --- a/drivers/input/touchscreen/focaltech_touch/focaltech_core.c +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_core.c @@ -2476,6 +2476,9 @@ static int fts_parse_dt(struct device *dev, struct fts_ts_platform_data *pdata) FTS_INFO("max touch number:%d, irq gpio:%d, reset gpio:%d", pdata->max_touch_number, pdata->irq_gpio, pdata->reset_gpio); + pdata->power_always_on = + of_property_read_bool(np, "focaltech,power-always-on"); + ret = of_property_read_u32(np, "focaltech,ic-type", &temp_val); if (ret < 0) pdata->type = _FT3518; @@ -2903,6 +2906,7 @@ static int fts_ts_suspend(struct device *dev) { int ret = 0; struct fts_ts_data *ts_data = fts_data; + struct fts_ts_platform_data *pdata = ts_data->pdata; FTS_FUNC_ENTER(); if (ts_data->suspended) { @@ -2934,7 +2938,8 @@ static int fts_ts_suspend(struct device *dev) if (ret < 0) FTS_ERROR("set TP to sleep mode fail, ret=%d", ret); - if (!ts_data->ic_info.is_incell) { + if (!ts_data->ic_info.is_incell && !pdata->power_always_on) { + #if FTS_POWER_SOURCE_CUST_EN ret = fts_power_source_suspend(ts_data); if (ret < 0) { @@ -2953,6 +2958,7 @@ static int fts_ts_suspend(struct device *dev) static int fts_ts_resume(struct device *dev) { struct fts_ts_data *ts_data = fts_data; + struct fts_ts_platform_data *pdata = ts_data->pdata; FTS_FUNC_ENTER(); if (!ts_data->suspended) { @@ -2971,7 +2977,8 @@ static int fts_ts_resume(struct device *dev) if (!ts_data->ic_info.is_incell) { #if FTS_POWER_SOURCE_CUST_EN - fts_power_source_resume(ts_data); + if (!pdata->power_always_on) + fts_power_source_resume(ts_data); #endif fts_reset_proc(200); } diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_core.h b/drivers/input/touchscreen/focaltech_touch/focaltech_core.h index c87cc52e5e47..3c8701f98c62 100644 --- a/drivers/input/touchscreen/focaltech_touch/focaltech_core.h +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_core.h @@ -139,6 +139,7 @@ struct fts_ts_platform_data { u32 x_min; u32 y_min; u32 max_touch_number; + bool power_always_on; }; struct ts_event { From 2d656cb3360259edb5c4f156604b64455a69658b Mon Sep 17 00:00:00 2001 From: Melody Olvera Date: Tue, 29 Jun 2021 11:08:31 -0700 Subject: [PATCH 27/90] soc: qcom: eud: Add support for different interrupt masks The EUD driver defaults to using INT1 for its interrupt mask. However, certain targets don't use that interrupt for signalling the apps processor. To remedy this, look for the interrupt-mask binding in the device tree entry, and, if present, use the offset there instead of the default. Change-Id: Ib2db82c64d21a650044163b7322bc66ffe159d36 Signed-off-by: Melody Olvera --- drivers/soc/qcom/eud.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/soc/qcom/eud.c b/drivers/soc/qcom/eud.c index 91471338a088..597550386965 100644 --- a/drivers/soc/qcom/eud.c +++ b/drivers/soc/qcom/eud.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #include @@ -65,6 +65,7 @@ struct eud_chip { int eud_irq; unsigned int extcon_id; unsigned int int_status; + unsigned int int_mask; bool usb_attach; bool chgr_enable; void __iomem *eud_reg_base; @@ -92,7 +93,7 @@ static inline void msm_eud_enable_irqs(struct eud_chip *chip) { /* Enable vbus, chgr & safe mode warning interrupts */ writel_relaxed(EUD_INT_VBUS | EUD_INT_CHGR | EUD_INT_SAFE_MODE, - chip->eud_reg_base + EUD_REG_INT1_EN_MASK); + chip->eud_reg_base + chip->int_mask); } static int msm_eud_hw_is_enabled(struct platform_device *pdev) @@ -506,7 +507,7 @@ static irqreturn_t handle_eud_irq(int irq, void *data) struct eud_chip *chip = data; u8 reg; u32 int_mask_en1 = readl_relaxed(chip->eud_reg_base + - EUD_REG_INT1_EN_MASK); + chip->int_mask); /* read status register and find out which interrupt triggered */ reg = readb_relaxed(chip->eud_reg_base + EUD_REG_INT_STATUS_1); @@ -705,6 +706,11 @@ static int msm_eud_probe(struct platform_device *pdev) if (chip->secure_eud_en && check_eud_mode_mgr2(chip)) enable = 1; + ret = of_property_read_u32(pdev->dev.of_node, "interrupt-mask", + &chip->int_mask); + if (ret) + chip->int_mask = EUD_REG_INT1_EN_MASK; + ret = uart_add_one_port(&eud_uart_driver, port); if (ret) { dev_err(chip->dev, "failed to add uart port!\n"); From fdf235980d2d045814e06818a83fb8c2c8c51ae1 Mon Sep 17 00:00:00 2001 From: Naman Padhiar Date: Tue, 18 May 2021 13:40:01 +0530 Subject: [PATCH 28/90] cnss2: Add more debug info in ipc_log Add caller context and function information in cnss ipc logs. Change-Id: Id389100b9518511b900cd3d9cde7677f14aa15da Signed-off-by: Naman Padhiar Signed-off-by: Mohammed Siddiq --- drivers/net/wireless/cnss2/debug.c | 33 +++++++++++++ drivers/net/wireless/cnss2/debug.h | 74 ++++++++++++++++-------------- 2 files changed, 72 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/cnss2/debug.c b/drivers/net/wireless/cnss2/debug.c index 66e035c1df88..84b5deeeff3a 100644 --- a/drivers/net/wireless/cnss2/debug.c +++ b/drivers/net/wireless/cnss2/debug.c @@ -876,6 +876,24 @@ void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv) #endif #if IS_ENABLED(CONFIG_IPC_LOGGING) +void cnss_debug_ipc_log_print(void *log_ctx, char *process, const char *fn, + const char *log_level, char *fmt, ...) +{ + struct va_format vaf; + va_list va_args; + + va_start(va_args, fmt); + vaf.fmt = fmt; + vaf.va = &va_args; + + if (log_level) + printk("%scnss: %pV", log_level, &vaf); + + ipc_log_string(log_ctx, "[%s] %s: %pV", process, fn, &vaf); + + va_end(va_args); +} + static int cnss_ipc_logging_init(void) { cnss_ipc_log_context = ipc_log_context_create(CNSS_IPC_LOG_PAGES, @@ -911,6 +929,21 @@ static void cnss_ipc_logging_deinit(void) #else static int cnss_ipc_logging_init(void) { return 0; } static void cnss_ipc_logging_deinit(void) {} +void cnss_debug_ipc_log_print(void *log_ctx, char *process, const char *fn, + const char *log_level, char *fmt, ...) +{ + struct va_format vaf; + va_list va_args; + + va_start(va_args, fmt); + vaf.fmt = fmt; + vaf.va = &va_args; + + if (log_level) + printk("%scnss: %pV", log_level, &vaf); + + va_end(va_args); +} #endif int cnss_debug_init(void) diff --git a/drivers/net/wireless/cnss2/debug.h b/drivers/net/wireless/cnss2/debug.h index da298d7fbf7a..7796d57611b3 100644 --- a/drivers/net/wireless/cnss2/debug.h +++ b/drivers/net/wireless/cnss2/debug.h @@ -4,55 +4,58 @@ #ifndef _CNSS_DEBUG_H #define _CNSS_DEBUG_H -#if IS_ENABLED(CONFIG_IPC_LOGGING) -#include -#endif #include #if IS_ENABLED(CONFIG_IPC_LOGGING) -#define CNSS_IPC_LOG_PAGES 32 +#include +#include extern void *cnss_ipc_log_context; extern void *cnss_ipc_log_long_context; -#define cnss_ipc_log_string(_x...) \ - ipc_log_string(cnss_ipc_log_context, _x) - -#define cnss_ipc_log_long_string(_x...) \ - ipc_log_string(cnss_ipc_log_long_context, _x) +#ifdef CONFIG_CNSS2_DEBUG +#define CNSS_IPC_LOG_PAGES 100 #else -#define cnss_ipc_log_string(_x...) -#define cnss_ipc_log_long_string(_x...) +#define CNSS_IPC_LOG_PAGES 50 +#endif +#define cnss_debug_log_print(_x...) \ + cnss_debug_ipc_log_print(cnss_ipc_log_context, _x) + +#define cnss_debug_log_long_print(_x...) \ + cnss_debug_ipc_log_print(cnss_ipc_log_long_context, _x) +#else +#define cnss_debug_log_print(_x...) \ + cnss_debug_ipc_log_print((void *)NULL, _x) +#define cnss_debug_log_long_print(_x...) \ + cnss_debug_ipc_log_print((void *)NULL, _x) #endif -#define cnss_pr_err(_fmt, ...) do { \ - printk("%scnss: " _fmt, KERN_ERR, ##__VA_ARGS__); \ - cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\ - } while (0) +#define proc_name (in_irq() ? "irq" : \ + (in_softirq() ? "soft_irq" : current->comm)) -#define cnss_pr_warn(_fmt, ...) do { \ - printk("%scnss: " _fmt, KERN_WARNING, ##__VA_ARGS__); \ - cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\ - } while (0) +#define cnss_pr_err(_fmt, ...) \ + cnss_debug_log_print(proc_name, __func__, \ + KERN_ERR, _fmt, ##__VA_ARGS__) -#define cnss_pr_info(_fmt, ...) do { \ - printk("%scnss: " _fmt, KERN_INFO, ##__VA_ARGS__); \ - cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\ - } while (0) +#define cnss_pr_warn(_fmt, ...) \ + cnss_debug_log_print(proc_name, __func__, \ + KERN_WARNING, _fmt, ##__VA_ARGS__) -#define cnss_pr_dbg(_fmt, ...) do { \ - printk("%scnss: " _fmt, KERN_DEBUG, ##__VA_ARGS__); \ - cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\ - } while (0) +#define cnss_pr_info(_fmt, ...) \ + cnss_debug_log_print(proc_name, __func__, \ + KERN_INFO, _fmt, ##__VA_ARGS__) -#define cnss_pr_vdbg(_fmt, ...) do { \ - printk("%scnss: " _fmt, KERN_DEBUG, ##__VA_ARGS__); \ - cnss_ipc_log_long_string("%scnss: " _fmt, "", \ - ##__VA_ARGS__); \ - } while (0) +#define cnss_pr_dbg(_fmt, ...) \ + cnss_debug_log_print(proc_name, __func__, \ + KERN_DEBUG, _fmt, ##__VA_ARGS__) -#define cnss_pr_buf(_fmt, ...) \ - cnss_ipc_log_long_string("%scnss: " _fmt, "", ##__VA_ARGS__) \ +#define cnss_pr_vdbg(_fmt, ...) \ + cnss_debug_log_long_print(proc_name, __func__, \ + KERN_DEBUG, _fmt, ##__VA_ARGS__) + +#define cnss_pr_buf(_fmt, ...) \ + cnss_debug_log_long_print(proc_name, __func__, \ + NULL, _fmt, ##__VA_ARGS__) #ifdef CONFIG_CNSS2_DEBUG #define CNSS_ASSERT(_condition) do { \ @@ -79,5 +82,6 @@ int cnss_debug_init(void); void cnss_debug_deinit(void); int cnss_debugfs_create(struct cnss_plat_data *plat_priv); void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv); - +void cnss_debug_ipc_log_print(void *log_ctx, char *process, const char *fn, + const char *log_level, char *fmt, ...); #endif /* _CNSS_DEBUG_H */ From ef0d4d698c36e046410182d8e343513c815370de Mon Sep 17 00:00:00 2001 From: Balakrishna Godavarthi Date: Mon, 31 May 2021 14:45:53 +0530 Subject: [PATCH 29/90] Add support to vote for SMPS This change will add support to vote for SMPS node if regulator handle is provided in DTS source. Change-Id: Ib370fd2fecfe04585cd2ab643f597714ead18a93 Signed-off-by: Balakrishna Godavarthi --- drivers/bluetooth/btpower.c | 27 +++++++++++++++++++-------- include/linux/btpower.h | 3 --- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/drivers/bluetooth/btpower.c b/drivers/bluetooth/btpower.c index 93a7fbb688b9..e149f5a135dd 100644 --- a/drivers/bluetooth/btpower.c +++ b/drivers/bluetooth/btpower.c @@ -32,12 +32,6 @@ #endif #include -#define PWR_SRC_STATUS_SET(index, status) do { \ - if (index >= PWR_SRC_INIT_STATE_IDX && index < BT_POWER_SRC_SIZE) { \ - bt_power_src_status[index] = (int) status; \ - } \ -} while (0) - #define PWR_SRC_NOT_AVAILABLE -2 #define DEFAULT_INVALID_VALUE -1 #define PWR_SRC_INIT_STATE_IDX 0 @@ -76,9 +70,24 @@ enum power_src_pos { BT_VDD_RFA_0p8_CURRENT, BT_VDD_RFACMN_CURRENT, BT_VDD_IPA_2p2, - BT_VDD_IPA_2p2_CURRENT + BT_VDD_IPA_2p2_CURRENT, + /* The below bucks are voted for HW WAR on some platform which supports + * WNC39xx. + */ + BT_VDD_SMPS, + BT_VDD_SMPS_CURRENT, + /* New entries need to be added before PWR_SRC_SIZE. + * Its hold the max size of power sources states. + */ + BT_POWER_SRC_SIZE, }; +#define PWR_SRC_STATUS_SET(index, status) do { \ + if (index >= PWR_SRC_INIT_STATE_IDX && index < BT_POWER_SRC_SIZE) { \ + bt_power_src_status[index] = (int) status; \ + } \ +} while (0) + // Regulator structure for QCA6174/QCA9377/QCA9379 BT SoC series static struct bt_power_vreg_data bt_vregs_info_qca61x4_937x[] = { {NULL, "qcom,bt-vdd-aon", 928000, 928000, 0, false, false, @@ -116,6 +125,8 @@ static struct bt_power_vreg_data bt_vregs_info_qca6xx0[] = { static struct bt_power bt_vreg_info_wcn399x = { .compatible = "qcom,wcn3990", .vregs = (struct bt_power_vreg_data []) { + {NULL, "qcom,bt-vdd-smps", 984000, 984000, 0, false, false, + {BT_VDD_SMPS, BT_VDD_SMPS_CURRENT}}, {NULL, "qcom,bt-vdd-io", 1700000, 1900000, 0, false, false, {BT_VDD_IO_LDO, BT_VDD_IO_LDO_CURRENT}}, {NULL, "qcom,bt-vdd-core", 1304000, 1304000, 0, false, false, @@ -125,7 +136,7 @@ static struct bt_power bt_vreg_info_wcn399x = { {NULL, "qcom,bt-vdd-xtal", 1700000, 1900000, 0, false, false, {BT_VDD_XTAL_LDO, BT_VDD_XTAL_LDO_CURRENT}}, }, - .num_vregs = 4, + .num_vregs = 5, }; static struct bt_power bt_vreg_info_qca_auto = { diff --git a/include/linux/btpower.h b/include/linux/btpower.h index 57b235733d62..a8bcd48f1623 100644 --- a/include/linux/btpower.h +++ b/include/linux/btpower.h @@ -89,7 +89,4 @@ int btpower_get_chipset_version(void); #define TCS_CMD_IO_ADDR_OFFSET 0x4 -/* total number of power src */ -#define BT_POWER_SRC_SIZE 30 - #endif /* __LINUX_BLUETOOTH_POWER_H */ From 0f5310aa7df98638de3c2b2c48c5e7e2c3f910f5 Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Tue, 1 Jun 2021 17:22:41 -0700 Subject: [PATCH 30/90] msm: ipa3: support dynamic IPPT SW-flt change Add the support for user-space module to dynamically enable or disable IPPT SW-flt lists based on ipv4 or connection port number to decide traffic going to ipa offload or not. Change-Id: I2cfee479c7810a26746179de152281f336a3052d Signed-off-by: Skylar Chang --- include/uapi/linux/msm_ipa.h | 41 +++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 4445d65f9eed..d4dd11734ef0 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -140,6 +140,7 @@ #define IPA_IOCTL_SET_PKT_THRESHOLD 87 #define IPA_IOCTL_ADD_EoGRE_MAPPING 88 #define IPA_IOCTL_DEL_EoGRE_MAPPING 89 +#define IPA_IOCTL_SET_IPPT_SW_FLT 90 /** * max size of the header to be inserted @@ -200,6 +201,12 @@ (IPA_MAX_FLT_RT_CNT_INDEX - IPA_FLT_RT_HW_COUNTER) #define IPA_MAX_FLT_RT_CLIENTS 60 +/** + * Max number of ports/IPs IPPT exception + */ + +#define IPA_MAX_IPPT_NUM_PORT_FLT 5 + /** * New feature flag for CV2X config. */ @@ -887,7 +894,13 @@ enum ipa_eogre_event { #define IPA_EoGRE_EVENT_MAX IPA_EoGRE_EVENT_MAX }; -#define IPA_EVENT_MAX_NUM (IPA_EoGRE_EVENT_MAX) +enum ipa_ippt_sw_flt_event { + IPA_IPPT_SW_FLT_EVENT = IPA_EoGRE_EVENT_MAX, + IPA_IPPT_SW_FLT_EVENT_MAX +#define IPA_IPPT_SW_FLT_EVENT_MAX IPA_IPPT_SW_FLT_EVENT_MAX +}; + +#define IPA_EVENT_MAX_NUM (IPA_IPPT_SW_FLT_EVENT_MAX) #define IPA_EVENT_MAX ((int)IPA_EVENT_MAX_NUM) /** @@ -3266,11 +3279,33 @@ struct ipa_sw_flt_list_type { char iface[IPA_MAX_NUM_IFACE_FLT][IPA_RESOURCE_NAME_MAX]; }; +/** + * struct ipa_ippt_sw_flt_list_type- exception list + * @ipv4_enable: true to block ipv4 addrs given below and false to clean + * up all previous ipv4 addrs + * @num_of_ipv4: holds num of ipv4 to SW-exception + * @ipv4: an array to hold ipv4 addrs to SW-exception + * @port_enable: true to block current ports and false to clean + * up all previous ports + * @num_of_port: holds num of ports to SW-exception + * @port: an array to hold connection ports to SW-exception + */ + +struct ipa_ippt_sw_flt_list_type { + uint8_t ipv4_enable; + int num_of_ipv4; + uint32_t ipv4[IPA_MAX_PDN_NUM]; + uint8_t port_enable; + int num_of_port; + uint16_t port[IPA_MAX_IPPT_NUM_PORT_FLT]; +}; + /** * struct ipa_ioc_sw_flt_list_type * @ioctl_ptr: has to be typecasted to (__u64)(uintptr_t) * @ioctl_data_size: * Eg: For ipa_sw_flt_list_type = sizeof(ipa_sw_flt_list_type) + * Eg: For ipa_ippt_sw_flt_list_type = sizeof(ipa_ippt_sw_flt_list_type) */ struct ipa_ioc_sw_flt_list_type { __u64 ioctl_ptr; @@ -3577,6 +3612,10 @@ struct ipa_ioc_sw_flt_list_type { #define IPA_IOC_DEL_EoGRE_MAPPING _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_DEL_EoGRE_MAPPING, \ struct ipa_ioc_eogre_info) + +#define IPA_IOC_SET_IPPT_SW_FLT _IOWR(IPA_IOC_MAGIC, \ + IPA_IOCTL_SET_IPPT_SW_FLT, \ + struct ipa_ioc_sw_flt_list_type) /* * unique magic number of the Tethering bridge ioctls */ From c3de8d217902b965c26109d5937ca5594064f465 Mon Sep 17 00:00:00 2001 From: Udipto Goswami Date: Wed, 23 Jun 2021 14:00:29 +0530 Subject: [PATCH 31/90] usb: dwc3: Add support of disable L1 in HS mode On some platforms, L1 in HS mode is not supported. Add support to disable L1 in HS mode on those platforms by default through dt. Change-Id: I624bde1e091e6e864bf7f7af93804c3728374d0d Signed-off-by: Udipto Goswami --- drivers/usb/dwc3/core.c | 2 ++ drivers/usb/dwc3/core.h | 1 + drivers/usb/dwc3/gadget.c | 2 +- drivers/usb/gadget/composite.c | 3 ++- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 6791b4ca95dd..5395c52edf3d 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1485,6 +1485,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) "snps,dis-tx-ipgap-linecheck-quirk"); dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev, "snps,parkmode-disable-ss-quirk"); + dwc->usb2_l1_disable = device_property_read_bool(dev, + "snps,usb2-l1-disable"); dwc->tx_de_emphasis_quirk = device_property_read_bool(dev, "snps,tx_de_emphasis_quirk"); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index fee3cf068915..a019b0e6180e 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1363,6 +1363,7 @@ struct dwc3 { unsigned tx_de_emphasis:2; unsigned err_evt_seen:1; unsigned enable_bus_suspend:1; + unsigned usb2_l1_disable:1; atomic_t in_lpm; bool b_suspend; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index fdc52c8d940e..aa03c5b6da10 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -4369,7 +4369,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->gadget.sg_supported = true; dwc->gadget.name = "dwc3-gadget"; - dwc->gadget.lpm_capable = true; + dwc->gadget.lpm_capable = !dwc->usb2_l1_disable; /* * FIXME We might be setting max_speed to desc.bMaxPacketSize0 = cdev->gadget->ep0->maxpacket; + cdev->desc.bcdUSB = cpu_to_le16(0x0200); if (gadget_is_superspeed(gadget)) { if (gadget->speed >= USB_SPEED_SUPER) { cdev->desc.bcdUSB = cpu_to_le16(0x0320); cdev->desc.bMaxPacketSize0 = 9; - } else { + } else if (gadget->lpm_capable) { cdev->desc.bcdUSB = cpu_to_le16(0x0210); } } else { From 22dc79eea862a4fe00f001fa3369b8f77c62eb48 Mon Sep 17 00:00:00 2001 From: shiwgupt Date: Tue, 22 Jun 2021 15:34:08 +0530 Subject: [PATCH 32/90] dt-bindings: msm: Add bindings for flash type Add binding support for flash type for khaje camera. CRs-Fixed: 2938804 Change-Id: I844b59125bb08034b1937422ac29485d5a7a2746 Signed-off-by: shiwgupt --- include/dt-bindings/msm/msm-camera.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/dt-bindings/msm/msm-camera.h b/include/dt-bindings/msm/msm-camera.h index 0a5aadce4eb7..9735e75f7900 100644 --- a/include/dt-bindings/msm/msm-camera.h +++ b/include/dt-bindings/msm/msm-camera.h @@ -95,8 +95,8 @@ #define CAM_CPAS_FUSE_FEATURE_MAX 10 /* Flash type*/ -#define CAM_FLASH_TYPE_GPIO 0 +#define CAM_FLASH_TYPE_PMIC 0 #define CAM_FLASH_TYPE_I2C 1 -#define CAM_FLASH_TYPE_PMIC 2 +#define CAM_FLASH_TYPE_GPIO 2 #endif From b8159e3b1accbd65fcd4a7a55472f98dfc7a5a28 Mon Sep 17 00:00:00 2001 From: Vivek Pernamitta Date: Wed, 30 Jun 2021 23:57:14 +0530 Subject: [PATCH 33/90] mhi: core: Notify all mhi client's for PCIe link down recovery send early notification to all MHI clients devices on PCIe linkdown recovery when device supports RDDM dumps. so all client channels registered to MHI will receive completion event. Change-Id: I3c25d69b7d43afe2701fe5fae705533faf6f4dd1 Signed-off-by: Vivek Pernamitta --- drivers/bus/mhi/core/mhi_pm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c index 0fad46875bab..49a425a6e374 100644 --- a/drivers/bus/mhi/core/mhi_pm.c +++ b/drivers/bus/mhi/core/mhi_pm.c @@ -1063,8 +1063,8 @@ void mhi_control_error(struct mhi_controller *mhi_cntrl) sfr_info->buf_addr); } - /* link is not down if device is in RDDM */ - transition_state = (mhi_cntrl->ee == MHI_EE_RDDM) ? + /* link is not down if device supports RDDM */ + transition_state = (mhi_cntrl->rddm_supported) ? MHI_PM_DEVICE_ERR_DETECT : MHI_PM_LD_ERR_FATAL_DETECT; write_lock_irq(&mhi_cntrl->pm_lock); From 64fdb4fa1d268c170dccc03222b76894776dbbb6 Mon Sep 17 00:00:00 2001 From: Maria Yu Date: Thu, 20 May 2021 11:17:34 +0800 Subject: [PATCH 34/90] soc: wdog: Ensure missing user watchdog pet can trigger bite The user watchdog was waiting the hardware watchdog bite by stop petting it. But in the cpu suspend scenarios, the auto petting by hardware prevent the expected watchdog bite. So add a new user pet timer to explicitly trigger the watchdog bite by software when the user watchdog petting is not happenned before timeout. Change-Id: I71b1139192baa960ae00f7a27c630aedaf5a3ffa Signed-off-by: Maria Yu --- drivers/soc/qcom/qcom_wdt_core.c | 29 +++++++++++++++++++++++++++++ include/soc/qcom/watchdog.h | 1 + 2 files changed, 30 insertions(+) diff --git a/drivers/soc/qcom/qcom_wdt_core.c b/drivers/soc/qcom/qcom_wdt_core.c index b9d16e1eb833..36ab96b56228 100644 --- a/drivers/soc/qcom/qcom_wdt_core.c +++ b/drivers/soc/qcom/qcom_wdt_core.c @@ -371,6 +371,8 @@ int qcom_wdt_pet_suspend(struct device *dev) wdog_dd->freeze_in_progress = true; spin_unlock(&wdog_dd->freeze_lock); del_timer_sync(&wdog_dd->pet_timer); + if (wdog_dd->user_pet_enabled) + del_timer_sync(&wdog_dd->user_pet_timer); return 0; } EXPORT_SYMBOL(qcom_wdt_pet_suspend); @@ -390,6 +392,11 @@ int qcom_wdt_pet_resume(struct device *dev) spin_lock(&wdog_dd->freeze_lock); wdog_dd->pet_timer.expires = jiffies + delay_time; add_timer(&wdog_dd->pet_timer); + if (wdog_dd->user_pet_enabled) { + delay_time = msecs_to_jiffies(wdog_dd->bark_time + 3 * 1000); + wdog_dd->user_pet_timer.expires = jiffies + delay_time; + add_timer(&wdog_dd->user_pet_timer); + } wdog_dd->freeze_in_progress = false; spin_unlock(&wdog_dd->freeze_lock); return 0; @@ -480,6 +487,8 @@ static void qcom_wdt_disable(struct msm_watchdog_data *wdog_dd) qcom_wdt_unregister_die_notifier(wdog_dd); unregister_restart_handler(&wdog_dd->restart_blk); del_timer_sync(&wdog_dd->pet_timer); + if (wdog_dd->user_pet_enabled) + del_timer_sync(&wdog_dd->user_pet_timer); wdog_dd->ops->disable_wdt(wdog_dd); dev_err(wdog_dd->dev, "QCOM Apps Watchdog deactivated\n"); } @@ -583,6 +592,8 @@ static ssize_t qcom_wdt_user_pet_enabled_set(struct device *dev, { struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev); int ret; + unsigned long delay_time = 0; + bool already_enabled = wdog_dd->user_pet_enabled; ret = strtobool(buf, &wdog_dd->user_pet_enabled); if (ret) { @@ -590,6 +601,12 @@ static ssize_t qcom_wdt_user_pet_enabled_set(struct device *dev, return ret; } + delay_time = msecs_to_jiffies(wdog_dd->bark_time + 3 * 1000); + if (wdog_dd->user_pet_enabled) + mod_timer(&wdog_dd->user_pet_timer, jiffies + delay_time); + else if (already_enabled) + del_timer_sync(&wdog_dd->user_pet_timer); + __qcom_wdt_user_pet(wdog_dd); return count; @@ -650,6 +667,15 @@ static void qcom_wdt_pet_task_wakeup(struct timer_list *t) wdog_dd->timer_fired = sched_clock(); wake_up(&wdog_dd->pet_complete); } +static void qcom_wdt_user_pet_bite(struct timer_list *t) +{ + struct msm_watchdog_data *wdog_dd = + from_timer(wdog_dd, t, user_pet_timer); + if (!wdog_dd->user_pet_complete) { + dev_info(wdog_dd->dev, "QCOM Apps Watchdog user pet timeout!\n"); + qcom_wdt_trigger_bite(); + } +} static __ref int qcom_wdt_kthread(void *arg) { @@ -751,6 +777,8 @@ int qcom_wdt_remove(struct platform_device *pdev) irq_dispose_mapping(wdog_dd->bark_irq); dev_info(wdog_dd->dev, "QCOM Apps Watchdog Exit - Deactivated\n"); del_timer_sync(&wdog_dd->pet_timer); + if (wdog_dd->user_pet_enabled) + del_timer_sync(&wdog_dd->user_pet_timer); wdog_dd->timer_expired = true; wdog_dd->user_pet_complete = true; kthread_stop(wdog_dd->watchdog_task); @@ -895,6 +923,7 @@ static int qcom_wdt_init(struct msm_watchdog_data *wdog_dd, timer_setup(&wdog_dd->pet_timer, qcom_wdt_pet_task_wakeup, 0); wdog_dd->pet_timer.expires = jiffies + delay_time; add_timer(&wdog_dd->pet_timer); + timer_setup(&wdog_dd->user_pet_timer, qcom_wdt_user_pet_bite, 0); val = BIT(EN); if (wdog_dd->wakeup_irq_enable) val |= BIT(UNMASKED_INT_EN); diff --git a/include/soc/qcom/watchdog.h b/include/soc/qcom/watchdog.h index f7a7dacb3a93..e38ae008b2be 100644 --- a/include/soc/qcom/watchdog.h +++ b/include/soc/qcom/watchdog.h @@ -149,6 +149,7 @@ struct msm_watchdog_data { struct qcom_irq_info ipi_counts[NR_IPI]; unsigned int tot_irq_count[NR_CPUS]; atomic_t irq_counts_running; + struct timer_list user_pet_timer; }; extern void qcom_wdt_trigger_bite(void); From 897a8bec14b17be8a690508ea7dda624037138e4 Mon Sep 17 00:00:00 2001 From: Akshaya Bhat Date: Thu, 20 May 2021 19:02:42 +0530 Subject: [PATCH 35/90] pinctrl: qcs404: update gpio, function and group binding Modify the gpio, function and group binding to make driver in sync with TLMM specification. Change-Id: Ia9bec2e870983b6f59aa694592883c1a32da2304 Signed-off-by: Akshaya Bhat --- drivers/pinctrl/qcom/pinctrl-qcs404.c | 214 +++++++++++++++++++++----- 1 file changed, 175 insertions(+), 39 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-qcs404.c b/drivers/pinctrl/qcom/pinctrl-qcs404.c index 1c6ba978c69f..d7c15cd523bd 100644 --- a/drivers/pinctrl/qcom/pinctrl-qcs404.c +++ b/drivers/pinctrl/qcom/pinctrl-qcs404.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. */ #include @@ -411,6 +411,18 @@ enum qcs404_functions { msm_mux_blsp_i2c_sda_b2, msm_mux_blsp_i2c_scl_b2, msm_mux_pwm_led11, + msm_mux_i2s_1_sck, + msm_mux_i2s_1_ws, + msm_mux_i2s_1_data0_dsd0, + msm_mux_i2s_1_data0, + msm_mux_i2s_1_data1_dsd1, + msm_mux_i2s_1_data1, + msm_mux_i2s_1_data2_dsd2, + msm_mux_i2s_1_data2, + msm_mux_i2s_1_data3_dsd3, + msm_mux_i2s_1_data3, + msm_mux_i2s_1_data4_dsd4, + msm_mux_i2s_1_data5_dsd5, msm_mux_i2s_3_data0_a, msm_mux_ebi2_lcd, msm_mux_i2s_3_data1_a, @@ -419,14 +431,25 @@ enum qcs404_functions { msm_mux_pwm_led3, msm_mux_i2s_3_data3_a, msm_mux_pwm_led4, - msm_mux_i2s_4, + msm_mux_i2s_4_sck, msm_mux_ebi2_a, msm_mux_dsd_clk_b, msm_mux_pwm_led5, + msm_mux_i2s_4_ws, + msm_mux_i2s_4_data0_dsd0, msm_mux_pwm_led6, + msm_mux_i2s_4_data0, + msm_mux_i2s_4_data1_dsd1, msm_mux_pwm_led7, + msm_mux_i2s_4_data1, + msm_mux_i2s_4_data2_dsd2, msm_mux_pwm_led8, + msm_mux_i2s_4_data2, + msm_mux_i2s_4_data3_dsd3, msm_mux_pwm_led24, + msm_mux_i2s_4_data3, + msm_mux_i2s_4_data4_dsd4, + msm_mux_i2s_4_data5_dsd5, msm_mux_spkr_dac0, msm_mux_blsp_i2c4, msm_mux_pwm_led9, @@ -547,25 +570,21 @@ static const char * const gpio_groups[] = { "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", - "gpio21", "gpio21", "gpio22", "gpio22", "gpio23", "gpio23", "gpio24", - "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", - "gpio32", "gpio33", "gpio34", "gpio35", "gpio36", "gpio36", "gpio36", - "gpio36", "gpio37", "gpio37", "gpio37", "gpio38", "gpio38", "gpio38", - "gpio39", "gpio39", "gpio40", "gpio40", "gpio41", "gpio41", "gpio41", - "gpio42", "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", - "gpio49", "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", - "gpio56", "gpio57", "gpio58", "gpio59", "gpio59", "gpio60", "gpio61", - "gpio62", "gpio63", "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", - "gpio69", "gpio70", "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", - "gpio76", "gpio77", "gpio77", "gpio78", "gpio78", "gpio78", "gpio79", - "gpio79", "gpio79", "gpio80", "gpio81", "gpio81", "gpio82", "gpio83", - "gpio84", "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", - "gpio91", "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", - "gpio98", "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", - "gpio104", "gpio105", "gpio106", "gpio107", "gpio108", "gpio108", - "gpio108", "gpio109", "gpio109", "gpio110", "gpio111", "gpio112", - "gpio113", "gpio114", "gpio115", "gpio116", "gpio117", "gpio118", - "gpio119", + "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", + "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", + "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42", + "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49", + "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56", + "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63", + "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70", + "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77", + "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84", + "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91", + "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98", + "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104", + "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110", + "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116", + "gpio117", "gpio118", "gpio119", }; static const char * const hdmi_tx_groups[] = { @@ -816,9 +835,56 @@ static const char * const pwm_led4_groups[] = { "gpio109", }; -static const char * const i2s_4_groups[] = { - "gpio110", "gpio111", "gpio111", "gpio112", "gpio112", "gpio113", - "gpio113", "gpio114", "gpio114", "gpio115", "gpio115", "gpio116", +static const char * const i2s_1_sck_groups[] = { + "gpio87", +}; + +static const char * const i2s_1_ws_groups[] = { + "gpio88", +}; + +static const char * const i2s_1_data0_dsd0_groups[] = { + "gpio88", +}; + +static const char * const i2s_1_data0_groups[] = { + "gpio89", +}; + +static const char * const i2s_1_data1_dsd1_groups[] = { + "gpio89", +}; + +static const char * const i2s_1_data1_groups[] = { + "gpio90", +}; + +static const char * const i2s_1_data2_dsd2_groups[] = { + "gpio90", +}; + +static const char * const i2s_1_data2_groups[] = { + "gpio91", +}; + +static const char * const i2s_1_data3_dsd3_groups[] = { + "gpio91", +}; + +static const char * const i2s_1_data3_groups[] = { + "gpio92", +}; + +static const char * const i2s_1_data4_dsd4_groups[] = { + "gpio92", +}; + +static const char * const i2s_1_data5_dsd5_groups[] = { + "gpio93", +}; + +static const char * const i2s_4_sck_groups[] = { + "gpio110", }; static const char * const ebi2_a_groups[] = { @@ -833,22 +899,66 @@ static const char * const pwm_led5_groups[] = { "gpio110", }; +static const char * const i2s_4_ws_groups[] = { + "gpio111", +}; + +static const char * const i2s_4_data0_dsd0_groups[] = { + "gpio111", +}; + static const char * const pwm_led6_groups[] = { "gpio111", }; +static const char * const i2s_4_data0_groups[] = { + "gpio112", +}; + +static const char * const i2s_4_data1_dsd1_groups[] = { + "gpio112", +}; + static const char * const pwm_led7_groups[] = { "gpio112", }; +static const char * const i2s_4_data1_groups[] = { + "gpio113", +}; + +static const char * const i2s_4_data2_dsd2_groups[] = { + "gpio113", +}; + static const char * const pwm_led8_groups[] = { "gpio113", }; +static const char * const i2s_4_data2_groups[] = { + "gpio114", +}; + +static const char * const i2s_4_data3_dsd3_groups[] = { + "gpio114", +}; + static const char * const pwm_led24_groups[] = { "gpio114", }; +static const char * const i2s_4_data3_groups[] = { + "gpio115", +}; + +static const char * const i2s_4_data4_dsd4_groups[] = { + "gpio115", +}; + +static const char * const i2s_4_data5_dsd5_groups[] = { + "gpio116", +}; + static const char * const spkr_dac0_groups[] = { "gpio116", }; @@ -1366,14 +1476,37 @@ static const struct msm_function qcs404_functions[] = { FUNCTION(pwm_led3), FUNCTION(i2s_3_data3_a), FUNCTION(pwm_led4), - FUNCTION(i2s_4), + FUNCTION(i2s_1_sck), + FUNCTION(i2s_4_sck), FUNCTION(ebi2_a), FUNCTION(dsd_clk_b), FUNCTION(pwm_led5), + FUNCTION(i2s_1_ws), + FUNCTION(i2s_1_data0_dsd0), + FUNCTION(i2s_4_ws), + FUNCTION(i2s_4_data0_dsd0), FUNCTION(pwm_led6), + FUNCTION(i2s_1_data0), + FUNCTION(i2s_1_data1_dsd1), + FUNCTION(i2s_4_data0), + FUNCTION(i2s_4_data1_dsd1), FUNCTION(pwm_led7), + FUNCTION(i2s_1_data1), + FUNCTION(i2s_1_data2_dsd2), + FUNCTION(i2s_4_data1), + FUNCTION(i2s_4_data2_dsd2), FUNCTION(pwm_led8), + FUNCTION(i2s_1_data2), + FUNCTION(i2s_1_data3_dsd3), + FUNCTION(i2s_4_data2), + FUNCTION(i2s_4_data3_dsd3), FUNCTION(pwm_led24), + FUNCTION(i2s_1_data3), + FUNCTION(i2s_1_data4_dsd4), + FUNCTION(i2s_1_data5_dsd5), + FUNCTION(i2s_4_data3), + FUNCTION(i2s_4_data4_dsd4), + FUNCTION(i2s_4_data5_dsd5), FUNCTION(spkr_dac0), FUNCTION(blsp_i2c4), FUNCTION(pwm_led9), @@ -1582,13 +1715,16 @@ static const struct msm_pingroup qcs404_groups[] = { [84] = PINGROUP(84, NORTH, blsp_uart3, blsp_i2c3, blsp_spi3, gcc_gp1_clk_a, qdss_cti_trig_in_b1, _, _, _, _), [85] = PINGROUP(85, NORTH, blsp_uart3, blsp_i2c3, blsp_spi3, gcc_gp2_clk_a, qdss_tracedata_b, _, _, _, _), [86] = PINGROUP(86, EAST, ext_mclk0, mclk_in1, _, _, _, _, _, _, _), - [87] = PINGROUP(87, EAST, i2s_1, dsd_clk_a, _, _, _, _, _, _, _), - [88] = PINGROUP(88, EAST, i2s_1, i2s_1, _, _, _, _, _, _, _), - [89] = PINGROUP(89, EAST, i2s_1, i2s_1, _, _, _, _, _, _, qdss_tracedata_b), - [90] = PINGROUP(90, EAST, i2s_1, i2s_1, _, _, _, _, _, _, _), - [91] = PINGROUP(91, EAST, i2s_1, i2s_1, _, _, _, _, _, _, _), - [92] = PINGROUP(92, EAST, i2s_1, i2s_1, _, _, _, _, _, qdss_cti_trig_in_a1, _), - [93] = PINGROUP(93, EAST, i2s_1, pwm_led22, i2s_1, _, _, _, _, _, qdss_tracedata_b), + [87] = PINGROUP(87, EAST, i2s_1_sck, dsd_clk_a, _, _, _, _, _, _, _), + [88] = PINGROUP(88, EAST, i2s_1_ws, i2s_1_data0_dsd0, _, _, _, _, _, _, _), + [89] = PINGROUP(89, EAST, i2s_1_data0, i2s_1_data1_dsd1, _, _, _, _, _, _, + qdss_tracedata_b), + [90] = PINGROUP(90, EAST, i2s_1_data1, i2s_1_data2_dsd2, _, _, _, _, _, _, _), + [91] = PINGROUP(91, EAST, i2s_1_data2, i2s_1_data3_dsd3, _, _, _, _, _, _, _), + [92] = PINGROUP(92, EAST, i2s_1_data3, i2s_1_data4_dsd4, _, _, _, _, _, + qdss_cti_trig_in_a1, _), + [93] = PINGROUP(93, EAST, i2s_1_data5_dsd5, pwm_led22, i2s_1, _, _, _, _, _, + qdss_tracedata_b), [94] = PINGROUP(94, EAST, i2s_1, pwm_led23, i2s_1, _, qdss_cti_trig_out_a0, _, rgmi_dll2, _, _), [95] = PINGROUP(95, EAST, i2s_1, pwm_led1, i2s_1, _, qdss_cti_trig_out_a1, _, _, _, _), [96] = PINGROUP(96, EAST, i2s_1, pwm_led2, _, _, _, _, _, _, _), @@ -1605,13 +1741,13 @@ static const struct msm_pingroup qcs404_groups[] = { [107] = PINGROUP(107, EAST, i2s_3_data1_a, ebi2_lcd, _, _, ebi_cdc, _, _, _, _), [108] = PINGROUP(108, EAST, i2s_3_data2_a, ebi2_lcd, atest_char, pwm_led3, ebi_cdc, _, _, _, _), [109] = PINGROUP(109, EAST, i2s_3_data3_a, ebi2_lcd, pwm_led4, bimc_dte1, _, _, _, _, _), - [110] = PINGROUP(110, EAST, i2s_4, ebi2_a, dsd_clk_b, pwm_led5, _, _, _, _, _), - [111] = PINGROUP(111, EAST, i2s_4, i2s_4, pwm_led6, ebi_cdc, _, _, _, _, _), - [112] = PINGROUP(112, EAST, i2s_4, i2s_4, pwm_led7, _, _, _, _, _, _), - [113] = PINGROUP(113, EAST, i2s_4, i2s_4, pwm_led8, _, _, _, _, _, _), - [114] = PINGROUP(114, EAST, i2s_4, i2s_4, pwm_led24, _, _, _, _, _, _), - [115] = PINGROUP(115, EAST, i2s_4, i2s_4, _, _, _, _, _, _, _), - [116] = PINGROUP(116, EAST, i2s_4, spkr_dac0, _, _, _, _, _, _, _), + [110] = PINGROUP(110, EAST, i2s_4_sck, ebi2_a, dsd_clk_b, pwm_led5, _, _, _, _, _), + [111] = PINGROUP(111, EAST, i2s_4_ws, i2s_4_data0_dsd0, pwm_led6, ebi_cdc, _, _, _, _, _), + [112] = PINGROUP(112, EAST, i2s_4_data0, i2s_4_data1_dsd1, pwm_led7, _, _, _, _, _, _), + [113] = PINGROUP(113, EAST, i2s_4_data1, i2s_4_data2_dsd2, pwm_led8, _, _, _, _, _, _), + [114] = PINGROUP(114, EAST, i2s_4_data2, i2s_4_data3_dsd3, pwm_led24, _, _, _, _, _, _), + [115] = PINGROUP(115, EAST, i2s_4_data3, i2s_4_data4_dsd4, _, _, _, _, _, _, _), + [116] = PINGROUP(116, EAST, i2s_4_data5_dsd5, spkr_dac0, _, _, _, _, _, _, _), [117] = PINGROUP(117, NORTH, blsp_i2c4, blsp_spi4, pwm_led9, _, _, _, _, _, _), [118] = PINGROUP(118, NORTH, blsp_i2c4, blsp_spi4, pwm_led10, _, _, _, _, _, _), [119] = PINGROUP(119, EAST, spdifrx_opt, _, _, _, _, _, _, _, _), From 04dbe55b1bcabf31b1a56e5b1d93cf4ecefe329e Mon Sep 17 00:00:00 2001 From: Charan Teja Reddy Date: Fri, 28 May 2021 15:38:54 +0530 Subject: [PATCH 36/90] taskstats: properly account NR_KERNEL_MISC_RECLAIMABLE NR_KERNEL_MISC_RECLAIMABLE contains the info in pages but accounting is done considering it as bytes. Fix it. Change-Id: I99a3bd43b7b77f6b137e1cc4c1854392d4a47635 Fixes: 5a5b186dfb59 ("taskstats: add support for system stats") Signed-off-by: Charan Teja Reddy --- kernel/taskstats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/taskstats.c b/kernel/taskstats.c index ea576b51868e..5efa47cf4f9e 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -482,7 +482,7 @@ static void sysstats_build(struct sys_memstats *stats) stats->version = SYSSTATS_VERSION; stats->memtotal = K(i.totalram); stats->reclaimable = - global_node_page_state(NR_KERNEL_MISC_RECLAIMABLE) >> 10; + K(global_node_page_state(NR_KERNEL_MISC_RECLAIMABLE)); stats->swap_used = K(i.totalswap - i.freeswap); stats->swap_total = K(i.totalswap); stats->vmalloc_total = K(vmalloc_nr_pages()); From 8a0fdd81d82f32aa8ec80c3f90f6736092edc226 Mon Sep 17 00:00:00 2001 From: Mohammed Siddiq Date: Thu, 1 Jul 2021 16:24:36 +0530 Subject: [PATCH 37/90] cnss2: Add code to notify mhi about link down Add code to notify mhi about link down.In scenario of link down recovery failure with SSR enabled, cnss-daemon posts a QMI req during subsystem shutdown execution, the mhi layer tries to access doorbell register to process the qmi msg but it leads to NOC error as pci link is down. So added code to notify mhi about link down to avoid NOC error. Change-Id: I3ccc2cbda37e271f14f3821bb055db3107dac228 Signed-off-by: Mohammed Siddiq --- drivers/net/wireless/cnss2/pci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 90c707279f8f..979c5e149796 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -1287,6 +1287,9 @@ static void cnss_pci_handle_linkdown(struct cnss_pci_data *pci_priv) pci_priv->pci_link_down_ind = true; spin_unlock_irqrestore(&pci_link_down_lock, flags); + /* Notify MHI about link down */ + mhi_control_error(pci_priv->mhi_ctrl); + if (pci_dev->device == QCA6174_DEVICE_ID) disable_irq(pci_dev->irq); From c2b3cdaad301f378076700fa33d5afcd1860d1e3 Mon Sep 17 00:00:00 2001 From: Lei Chen Date: Wed, 17 Mar 2021 16:29:16 +0800 Subject: [PATCH 38/90] defconfig: sdxlemur: Enable DRM and GKI_HIDDEN_DRM_CONFIGS on sdxlemur This change enables DRM and GKI_HIDDEN_DRM_CONFIGS for QPIC display on sdxlemur. Change-Id: I856d26e0dafcffd523eefc660f00612448a4529f Signed-off-by: Lei Chen --- arch/arm/configs/vendor/sdxlemur.config | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/vendor/sdxlemur.config b/arch/arm/configs/vendor/sdxlemur.config index 97f39227174d..2f5481fb10b0 100644 --- a/arch/arm/configs/vendor/sdxlemur.config +++ b/arch/arm/configs/vendor/sdxlemur.config @@ -371,3 +371,5 @@ CONFIG_QPS615=m # CONFIG_BLK_CGROUP is not set # CONFIG_BLK_DEBUG_FS is not set # CONFIG_VT is not set +CONFIG_DRM=y +CONFIG_GKI_HIDDEN_DRM_CONFIGS=y From 5de46e8161b9c91ff39d7d6c84228c797d65d94b Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Tue, 15 Jun 2021 19:09:44 +0800 Subject: [PATCH 39/90] coresight: fix etr pice mode issue Only start the sw mode when pcie_path is configured as sw. Change-Id: I3b9fb890008760b0a25827bb039cd378512f4efe Signed-off-by: Yuanfang Zhang --- drivers/hwtracing/coresight/coresight-byte-cntr.c | 3 ++- drivers/hwtracing/coresight/coresight-tmc-etr.c | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-byte-cntr.c b/drivers/hwtracing/coresight/coresight-byte-cntr.c index 7a785ed2e65d..c26294f1615c 100644 --- a/drivers/hwtracing/coresight/coresight-byte-cntr.c +++ b/drivers/hwtracing/coresight/coresight-byte-cntr.c @@ -674,7 +674,8 @@ static void etr_pcie_client_cb(struct mhi_dev_client_cb_data *cb_data) byte_cntr_data = cb_data->user_data; if (!byte_cntr_data) return; - + if (tmcdrvdata->pcie_path != TMC_ETR_PCIE_SW_PATH) + return; switch (cb_data->ctrl_info) { case MHI_STATE_CONNECTED: if (cb_data->channel == byte_cntr_data->pcie_out_chan) { diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index f661bcde5bb8..02e55f98b5cf 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -1706,8 +1706,6 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) tmc_etr_byte_cntr_start(drvdata->byte_cntr); - if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) - etr_pcie_start(drvdata->byte_cntr); if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE && drvdata->pcie_path == TMC_ETR_PCIE_SW_PATH) From e9efafa35cda10a0a4cb0b06c046bcf2e3fbf123 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Thu, 1 Apr 2021 14:13:37 -0700 Subject: [PATCH 40/90] pci: msm: Remove RC and EP config space shadow save and restore All endpoints and bridge are performing their config space save and restore. Hence root complex driver does not need to perform the same on behalf of them. For root complex use PCI framework provided APIs to perform RC config space save and restore. Save golden copy of the RC config space upon enumeration and use it to restore RC config space in case of link down. Get rid of all custom APIs for saving, restoring and dumping of RC and EP config space entries. Change-Id: I466e26aaaee0ae317323aae0c535c3319f95e681 Signed-off-by: Hemant Kumar --- drivers/pci/controller/pci-msm.c | 330 +++++-------------------------- include/linux/msm_pcie.h | 51 +---- 2 files changed, 50 insertions(+), 331 deletions(-) diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index ce014787acbe..b238ec4ed87c 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -503,7 +503,6 @@ enum msm_pcie_debugfs_option { MSM_PCIE_DISABLE_LINK, MSM_PCIE_ENABLE_LINK, MSM_PCIE_DISABLE_ENABLE_LINK, - MSM_PCIE_DUMP_SHADOW_REGISTER, MSM_PCIE_DISABLE_L0S, MSM_PCIE_ENABLE_L0S, MSM_PCIE_DISABLE_L1, @@ -532,7 +531,6 @@ static const char * const "DISABLE LINK", "ENABLE LINK", "DISABLE AND ENABLE LINK", - "DUMP PCIE SHADOW REGISTER", "DISABLE L0S", "ENABLE L0S", "DISABLE L1", @@ -788,6 +786,8 @@ struct msm_pcie_dev_t { enum msm_pcie_link_status link_status; bool user_suspend; bool disable_pc; + + struct pci_saved_state *default_state; struct pci_saved_state *saved_state; struct wakeup_source *ws; @@ -863,9 +863,6 @@ struct msm_pcie_dev_t { struct msm_pcie_tcsr_info_t *tcsr_config; u32 sid_info_len; struct msm_pcie_sid_info_t *sid_info; - u32 ep_shadow[MAX_DEVICE_NUM][PCIE_CONF_SPACE_DW]; - u32 rc_shadow[PCIE_CONF_SPACE_DW]; - bool shadow_en; bool bridge_found; struct list_head event_reg_list; spinlock_t evt_reg_list_lock; @@ -1524,54 +1521,6 @@ static bool msm_pcie_confirm_linkup(struct msm_pcie_dev_t *dev, return true; } -static void msm_pcie_cfg_recover(struct msm_pcie_dev_t *dev, bool rc) -{ - int i, j; - u32 val = 0; - u32 *shadow; - void __iomem *cfg = dev->conf; - - for (i = 0; i < MAX_DEVICE_NUM; i++) { - if (!rc && !dev->pcidev_table[i].bdf) - break; - if (rc) { - cfg = dev->dm_core; - shadow = dev->rc_shadow; - } else { - if (!msm_pcie_confirm_linkup(dev, false, true, - dev->pcidev_table[i].dev)) - continue; - - shadow = dev->ep_shadow[i]; - PCIE_DBG(dev, - "PCIe Device: %02x:%02x.%01x\n", - dev->pcidev_table[i].bdf >> 24, - dev->pcidev_table[i].bdf >> 19 & 0x1f, - dev->pcidev_table[i].bdf >> 16 & 0x07); - } - for (j = PCIE_CONF_SPACE_DW - 1; j >= 0; j--) { - val = shadow[j]; - if (val != PCIE_CLEAR) { - PCIE_DBG3(dev, - "PCIe: before recovery:cfg 0x%x:0x%x\n", - j * 4, readl_relaxed(cfg + j * 4)); - PCIE_DBG3(dev, - "PCIe: shadow_dw[%d]:cfg 0x%x:0x%x\n", - j, j * 4, val); - msm_pcie_write_reg(cfg, j * 4, val); - PCIE_DBG3(dev, - "PCIe: after recovery:cfg 0x%x:0x%x\n\n", - j * 4, readl_relaxed(cfg + j * 4)); - } - } - if (rc) - break; - - pci_save_state(dev->pcidev_table[i].dev); - cfg += SZ_4K; - } -} - static void msm_pcie_write_mask(void __iomem *addr, uint32_t clear_mask, uint32_t set_mask) { @@ -1701,8 +1650,6 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev) dev->linkdown_panic); PCIE_DBG_FS(dev, "the link is %s suspending\n", dev->suspending ? "" : "not"); - PCIE_DBG_FS(dev, "shadow is %s enabled\n", - dev->shadow_en ? "" : "not"); PCIE_DBG_FS(dev, "the power of RC is %s on\n", dev->power_on ? "" : "not"); PCIE_DBG_FS(dev, "smmu_sid_base: 0x%x\n", @@ -1771,37 +1718,6 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev) dev->l23_rdy_poll_timeout); } -static void msm_pcie_shadow_dump(struct msm_pcie_dev_t *dev, bool rc) -{ - int i, j; - u32 val = 0; - u32 *shadow; - - for (i = 0; i < MAX_DEVICE_NUM; i++) { - if (!rc && !dev->pcidev_table[i].bdf) - break; - if (rc) { - shadow = dev->rc_shadow; - } else { - shadow = dev->ep_shadow[i]; - PCIE_DBG_FS(dev, "PCIe Device: %02x:%02x.%01x\n", - dev->pcidev_table[i].bdf >> 24, - dev->pcidev_table[i].bdf >> 19 & 0x1f, - dev->pcidev_table[i].bdf >> 16 & 0x07); - } - for (j = 0; j < PCIE_CONF_SPACE_DW; j++) { - val = shadow[j]; - if (val != PCIE_CLEAR) { - PCIE_DBG_FS(dev, - "PCIe: shadow_dw[%d]:cfg 0x%x:0x%x\n", - j, j * 4, val); - } - } - if (rc) - break; - } -} - static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, u32 testcase) { @@ -1818,9 +1734,8 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, case MSM_PCIE_DISABLE_LINK: PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable link\n\n", dev->rc_idx); - ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, 0, - dev->dev, NULL, - MSM_PCIE_CONFIG_NO_CFG_RESTORE); + ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, 0, dev->dev, NULL, + 0); if (ret) PCIE_DBG_FS(dev, "PCIe:%s:failed to disable link\n", __func__); @@ -1832,50 +1747,28 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: enable link and recover config space\n\n", dev->rc_idx); - ret = msm_pcie_pm_control(MSM_PCIE_RESUME, 0, - dev->dev, NULL, - MSM_PCIE_CONFIG_NO_CFG_RESTORE); + ret = msm_pcie_pm_control(MSM_PCIE_RESUME, 0, dev->dev, NULL, + 0); if (ret) PCIE_DBG_FS(dev, "PCIe:%s:failed to enable link\n", __func__); - else { - PCIE_DBG_FS(dev, "PCIe:%s:enabled link\n", __func__); - msm_pcie_recover_config(dev->dev); - } break; case MSM_PCIE_DISABLE_ENABLE_LINK: PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable and enable link then recover config space\n\n", dev->rc_idx); - ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, 0, - dev->dev, NULL, - MSM_PCIE_CONFIG_NO_CFG_RESTORE); + ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, 0, dev->dev, NULL, + 0); if (ret) PCIE_DBG_FS(dev, "PCIe:%s:failed to disable link\n", __func__); else PCIE_DBG_FS(dev, "PCIe:%s:disabled link\n", __func__); - ret = msm_pcie_pm_control(MSM_PCIE_RESUME, 0, - dev->dev, NULL, - MSM_PCIE_CONFIG_NO_CFG_RESTORE); + ret = msm_pcie_pm_control(MSM_PCIE_RESUME, 0, dev->dev, NULL, + 0); if (ret) PCIE_DBG_FS(dev, "PCIe:%s:failed to enable link\n", __func__); - else { - PCIE_DBG_FS(dev, "PCIe:%s:enabled link\n", __func__); - msm_pcie_recover_config(dev->dev); - } - break; - case MSM_PCIE_DUMP_SHADOW_REGISTER: - PCIE_DBG_FS(dev, - "\n\nPCIe: RC%d: dumping RC shadow registers\n", - dev->rc_idx); - msm_pcie_shadow_dump(dev, true); - - PCIE_DBG_FS(dev, - "\n\nPCIe: RC%d: dumping EP shadow registers\n", - dev->rc_idx); - msm_pcie_shadow_dump(dev, false); break; case MSM_PCIE_DISABLE_L0S: PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L0s\n\n", @@ -2965,29 +2858,6 @@ static void msm_pcie_cfg_bdf(struct msm_pcie_dev_t *dev, u8 bus, u8 devfn) dev->current_bdf = bdf; } -static void msm_pcie_save_shadow(struct msm_pcie_dev_t *dev, - u32 word_offset, u32 wr_val, - u32 bdf, bool rc) -{ - int i; - - if (rc) { - dev->rc_shadow[word_offset / 4] = wr_val; - } else { - for (i = 0; i < MAX_DEVICE_NUM; i++) { - if (!dev->pcidev_table[i].bdf) { - dev->pcidev_table[i].bdf = bdf; - if ((!dev->bridge_found) && (i > 0)) - dev->bridge_found = true; - } - if (dev->pcidev_table[i].bdf == bdf) { - dev->ep_shadow[i][word_offset / 4] = wr_val; - break; - } - } - } -} - static int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper, int where, int size, u32 *val) { @@ -3089,18 +2959,6 @@ static int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper, msm_pcie_write_reg(config_base, word_offset, wr_val); - if (dev->shadow_en) { - if (rd_val == PCIE_LINK_DOWN && - (readl_relaxed(config_base) == PCIE_LINK_DOWN)) - PCIE_ERR(dev, - "Read of RC%d %d:0x%02x + 0x%04x[%d] is all FFs\n", - rc_idx, bus->number, devfn, - where, size); - else - msm_pcie_save_shadow(dev, word_offset, wr_val, - bdf, rc); - } - PCIE_DBG3(dev, "RC%d %d:0x%02x + 0x%04x[%d] <- 0x%08x; rd 0x%08x val 0x%08x\n", rc_idx, bus->number, devfn, where, size, @@ -3815,11 +3673,6 @@ static void msm_pcie_config_controller(struct msm_pcie_dev_t *dev) PCIE20_ACK_N_FTS, dev->n_fts << 8); - if (dev->shadow_en) - dev->rc_shadow[PCIE20_ACK_F_ASPM_CTRL_REG / 4] = - readl_relaxed(dev->dm_core + - PCIE20_ACK_F_ASPM_CTRL_REG); - PCIE_DBG2(dev, "Updated PCIE20_ACK_F_ASPM_CTRL_REG:0x%x\n", readl_relaxed(dev->dm_core + PCIE20_ACK_F_ASPM_CTRL_REG)); @@ -5094,13 +4947,6 @@ int msm_pcie_enumerate(u32 rc_idx) msm_pcie_write_reg_field(dev->dm_core, PCIE20_DEVICE_CONTROL2_STATUS2, 0xf, dev->cpl_timeout); - if (dev->shadow_en) { - u32 val = readl_relaxed(dev->dm_core + PCIE20_COMMAND_STATUS); - - PCIE_DBG(dev, "PCIE20_COMMAND_STATUS:0x%x\n", val); - dev->rc_shadow[PCIE20_COMMAND_STATUS / 4] = val; - } - do { pcidev = pci_get_device(vendor_id, device_id, pcidev); if (pcidev && (dev == (struct msm_pcie_dev_t *) @@ -5119,6 +4965,8 @@ int msm_pcie_enumerate(u32 rc_idx) pci_walk_bus(dev->dev->bus, msm_pcie_config_device_table, dev); + pci_save_state(pcidev); + dev->default_state = pci_store_saved_state(pcidev); out: mutex_unlock(&dev->enumerate_lock); @@ -5387,7 +5235,6 @@ static void msm_pcie_handle_linkdown(struct msm_pcie_dev_t *dev) return; dev->link_status = MSM_PCIE_LINK_DOWN; - dev->shadow_en = false; if (!dev->suspending) { /* PCIe registers dump on link down */ @@ -6061,7 +5908,7 @@ static int msm_pcie_probe(struct platform_device *pdev) { int ret = 0; int rc_idx = -1; - int i, j, size; + int i, size; struct msm_pcie_dev_t *pcie_dev; struct device_node *of_node; @@ -6274,7 +6121,6 @@ static int msm_pcie_probe(struct platform_device *pdev) PCIE_DBG(pcie_dev, "RC%d: clkreq gpio no:%u\n", pcie_dev->rc_idx, pcie_dev->clkreq_gpio); - pcie_dev->shadow_en = true; pcie_dev->aer_enable = true; memcpy(pcie_dev->vreg, msm_pcie_vreg_info, sizeof(msm_pcie_vreg_info)); @@ -6290,11 +6136,6 @@ static int msm_pcie_probe(struct platform_device *pdev) memcpy(pcie_dev->pipe_reset, msm_pcie_pipe_reset_info[rc_idx], sizeof(msm_pcie_pipe_reset_info[rc_idx])); - for (i = 0; i < PCIE_CONF_SPACE_DW; i++) - pcie_dev->rc_shadow[i] = PCIE_CLEAR; - for (i = 0; i < MAX_DEVICE_NUM; i++) - for (j = 0; j < PCIE_CONF_SPACE_DW; j++) - pcie_dev->ep_shadow[i][j] = PCIE_CLEAR; for (i = 0; i < MAX_DEVICE_NUM; i++) { pcie_dev->pcidev_table[i].bdf = 0; pcie_dev->pcidev_table[i].dev = NULL; @@ -6438,6 +6279,14 @@ static int msm_pcie_remove(struct platform_device *pdev) dev_info(&pdev->dev, "PCIe: RC%d: being removed\n", rc_idx); } + if (msm_pcie_dev[rc_idx].saved_state) + pci_load_and_free_saved_state(msm_pcie_dev[rc_idx].dev, + &msm_pcie_dev[rc_idx].saved_state); + + if (msm_pcie_dev[rc_idx].default_state) + pci_load_and_free_saved_state(msm_pcie_dev[rc_idx].dev, + &msm_pcie_dev[rc_idx].default_state); + msm_pcie_irq_deinit(&msm_pcie_dev[rc_idx]); msm_pcie_vreg_deinit(&msm_pcie_dev[rc_idx]); msm_pcie_clk_deinit(&msm_pcie_dev[rc_idx]); @@ -7331,16 +7180,26 @@ static int msm_pcie_pm_suspend(struct pci_dev *dev, return ret; } - if (dev && !(options & MSM_PCIE_CONFIG_NO_CFG_RESTORE) - && msm_pcie_confirm_linkup(pcie_dev, true, true, dev)) { - ret = pci_save_state(dev); - pcie_dev->saved_state = pci_store_saved_state(dev); - } - if (ret) { - PCIE_ERR(pcie_dev, "PCIe: fail to save state of RC%d:%d.\n", - pcie_dev->rc_idx, ret); - pcie_dev->suspending = false; - return ret; + if (dev) { + if (msm_pcie_confirm_linkup(pcie_dev, true, true, dev)) { + ret = pci_save_state(dev); + if (ret) { + PCIE_ERR(pcie_dev, + "PCIe: RC%d: fail to save state of RC%d:%d.\n", + pcie_dev->rc_idx, ret); + pcie_dev->suspending = false; + return ret; + } + + pcie_dev->saved_state = pci_store_saved_state(dev); + } else { + pci_load_and_free_saved_state(dev, + &pcie_dev->saved_state); + pcie_dev->saved_state = pcie_dev->default_state; + PCIE_DBG(pcie_dev, + "PCIe: RC%d: saved default config space\n", + pcie_dev->rc_idx); + } } spin_lock_irqsave(&pcie_dev->cfg_lock, @@ -7451,37 +7310,11 @@ static int msm_pcie_pm_resume(struct pci_dev *dev, "dev->bus->number = %d dev->bus->primary = %d\n", dev->bus->number, dev->bus->primary); - if (!(options & MSM_PCIE_CONFIG_NO_CFG_RESTORE)) { - if (pcie_dev->saved_state) { - PCIE_DBG(pcie_dev, - "RC%d: entry of PCI framework restore state\n", - pcie_dev->rc_idx); - - pci_load_and_free_saved_state(dev, - &pcie_dev->saved_state); - pci_restore_state(dev); - - PCIE_DBG(pcie_dev, - "RC%d: exit of PCI framework restore state\n", - pcie_dev->rc_idx); - } else { - PCIE_DBG(pcie_dev, - "RC%d: restore rc config space using shadow recovery\n", - pcie_dev->rc_idx); - msm_pcie_cfg_recover(pcie_dev, true); - } - } - - if (pcie_dev->bridge_found) { - PCIE_DBG(pcie_dev, - "RC%d: entry of PCIe recover config\n", - pcie_dev->rc_idx); - - msm_pcie_recover_config(dev); - - PCIE_DBG(pcie_dev, - "RC%d: exit of PCIe recover config\n", - pcie_dev->rc_idx); + if (dev) { + PCIE_DBG(pcie_dev, "RC%d: restore config space\n", + pcie_dev->rc_idx); + pci_load_and_free_saved_state(dev, &pcie_dev->saved_state); + pci_restore_state(dev); } msm_msi_config_access(dev_get_msi_domain(&pcie_dev->dev->dev), true); @@ -8205,76 +8038,5 @@ int msm_pcie_deregister_event(struct msm_pcie_register_event *reg) } EXPORT_SYMBOL(msm_pcie_deregister_event); -int msm_pcie_recover_config(struct pci_dev *dev) -{ - int ret = 0; - struct msm_pcie_dev_t *pcie_dev; - - if (dev) { - pcie_dev = PCIE_BUS_PRIV_DATA(dev->bus); - PCIE_DBG(pcie_dev, - "Recovery for the link of RC%d\n", pcie_dev->rc_idx); - } else { - pr_err("PCIe: the input pci dev is NULL.\n"); - return -ENODEV; - } - - if (msm_pcie_confirm_linkup(pcie_dev, true, true, dev)) { - PCIE_DBG(pcie_dev, - "Recover config space of RC%d and its EP\n", - pcie_dev->rc_idx); - pcie_dev->shadow_en = false; - PCIE_DBG(pcie_dev, "Recover RC%d\n", pcie_dev->rc_idx); - msm_pcie_cfg_recover(pcie_dev, true); - PCIE_DBG(pcie_dev, "Recover EP of RC%d\n", pcie_dev->rc_idx); - msm_pcie_cfg_recover(pcie_dev, false); - PCIE_DBG(pcie_dev, - "Refreshing the saved config space in PCI framework for RC%d and its EP\n", - pcie_dev->rc_idx); - pci_save_state(pcie_dev->dev); - pci_save_state(dev); - pcie_dev->shadow_en = true; - PCIE_DBG(pcie_dev, "Turn on shadow for RC%d\n", - pcie_dev->rc_idx); - } else { - PCIE_ERR(pcie_dev, - "PCIe: the link of RC%d is not up yet; can't recover config space.\n", - pcie_dev->rc_idx); - ret = -ENODEV; - } - - return ret; -} -EXPORT_SYMBOL(msm_pcie_recover_config); - -int msm_pcie_shadow_control(struct pci_dev *dev, bool enable) -{ - int ret = 0; - struct msm_pcie_dev_t *pcie_dev; - - if (dev) { - pcie_dev = PCIE_BUS_PRIV_DATA(dev->bus); - PCIE_DBG(pcie_dev, - "User requests to %s shadow\n", - enable ? "enable" : "disable"); - } else { - pr_err("PCIe: the input pci dev is NULL.\n"); - return -ENODEV; - } - - PCIE_DBG(pcie_dev, - "The shadowing of RC%d is %s enabled currently.\n", - pcie_dev->rc_idx, pcie_dev->shadow_en ? "" : "not"); - - pcie_dev->shadow_en = enable; - - PCIE_DBG(pcie_dev, - "Shadowing of RC%d is turned %s upon user's request.\n", - pcie_dev->rc_idx, enable ? "on" : "off"); - - return ret; -} -EXPORT_SYMBOL(msm_pcie_shadow_control); - MODULE_DESCRIPTION("Qualcomm Technologies, Inc. PCIe RC driver"); MODULE_LICENSE("GPL v2"); diff --git a/include/linux/msm_pcie.h b/include/linux/msm_pcie.h index 6910eb4c76cf..44a076807bb5 100644 --- a/include/linux/msm_pcie.h +++ b/include/linux/msm_pcie.h @@ -9,11 +9,10 @@ enum msm_pcie_config { MSM_PCIE_CONFIG_INVALID = 0, - MSM_PCIE_CONFIG_NO_CFG_RESTORE = 0x1, - MSM_PCIE_CONFIG_LINKDOWN = 0x2, - MSM_PCIE_CONFIG_NO_RECOVERY = 0x4, - MSM_PCIE_CONFIG_NO_L1SS_TO = 0x8, - MSM_PCIE_CONFIG_NO_DRV_PC = 0x10, + MSM_PCIE_CONFIG_LINKDOWN = BIT(0), + MSM_PCIE_CONFIG_NO_RECOVERY = BIT(1), + MSM_PCIE_CONFIG_NO_L1SS_TO = BIT(2), + MSM_PCIE_CONFIG_NO_DRV_PC = BIT(3), }; enum msm_pcie_pm_opt { @@ -174,16 +173,6 @@ int msm_pcie_register_event(struct msm_pcie_register_event *reg); */ int msm_pcie_deregister_event(struct msm_pcie_register_event *reg); -/** - * msm_pcie_recover_config - recover config space. - * @dev: pci device structure - * - * This function recovers the config space of both RC and Endpoint. - * - * Return: 0 on success, negative value on error - */ -int msm_pcie_recover_config(struct pci_dev *dev); - /** * msm_pcie_enumerate - enumerate Endpoints. * @rc_idx: RC that Endpoints connect to. @@ -194,28 +183,6 @@ int msm_pcie_recover_config(struct pci_dev *dev); */ int msm_pcie_enumerate(u32 rc_idx); -/** - * msm_pcie_recover_config - recover config space. - * @dev: pci device structure - * - * This function recovers the config space of both RC and Endpoint. - * - * Return: 0 on success, negative value on error - */ -int msm_pcie_recover_config(struct pci_dev *dev); - -/** - * msm_pcie_shadow_control - control the shadowing of PCIe config space. - * @dev: pci device structure - * @enable: shadowing should be enabled or disabled - * - * This function gives PCIe endpoint device drivers the control to enable - * or disable the shadowing of PCIe config space. - * - * Return: 0 on success, negative value on error - */ -int msm_pcie_shadow_control(struct pci_dev *dev, bool enable); - /* * msm_pcie_debug_info - run a PCIe specific debug testcase. * @dev: pci device structure @@ -286,21 +253,11 @@ static inline int msm_pcie_deregister_event(struct msm_pcie_register_event *reg) return -ENODEV; } -static inline int msm_pcie_recover_config(struct pci_dev *dev) -{ - return -ENODEV; -} - static inline int msm_pcie_enumerate(u32 rc_idx) { return -ENODEV; } -static inline int msm_pcie_shadow_control(struct pci_dev *dev, bool enable) -{ - return -ENODEV; -} - static inline int msm_pcie_debug_info(struct pci_dev *dev, u32 option, u32 base, u32 offset, u32 mask, u32 value) { From 89d2d76a29f9c0288134cb22b55dcbfb2b1f62cc Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Mon, 8 Mar 2021 18:40:50 -0800 Subject: [PATCH 41/90] pci: msm: Get rid of msm pcie device table Since pcidev_table is no longer used in the driver get rid of the table entry from msm pcie device structure. Also remove unused structure members from msm_pcie_device_info. Since device table is removed, rename msm_pcie_config_device_table to msm_pcie_config_device_info. Change-Id: I5359cc0f85d6b7f9f069f7decc3bc67105543abb Signed-off-by: Hemant Kumar --- drivers/pci/controller/pci-msm.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index b238ec4ed87c..18dd212e44e1 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -638,11 +638,7 @@ struct msm_pcie_sid_info_t { /* PCIe device info structure */ struct msm_pcie_device_info { struct list_head pcidev_node; - u32 bdf; struct pci_dev *dev; - short short_bdf; - u32 sid; - int domain; }; /* DRV IPC command type */ @@ -874,7 +870,6 @@ struct msm_pcie_dev_t { struct pinctrl *pinctrl; struct pinctrl_state *pins_default; struct pinctrl_state *pins_sleep; - struct msm_pcie_device_info pcidev_table[MAX_DEVICE_NUM]; struct msm_pcie_drv_info *drv_info; struct work_struct drv_enable_pc_work; @@ -4729,7 +4724,7 @@ static void msm_pcie_disable(struct msm_pcie_dev_t *dev) PCIE_DBG(dev, "RC%d: exit\n", dev->rc_idx); } -static int msm_pcie_config_device_table(struct pci_dev *pcidev, void *pdev) +static int msm_pcie_config_device_info(struct pci_dev *pcidev, void *pdev) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *) pdev; struct msm_pcie_device_info *dev_info; @@ -4963,7 +4958,7 @@ int msm_pcie_enumerate(u32 rc_idx) goto out; } - pci_walk_bus(dev->dev->bus, msm_pcie_config_device_table, dev); + pci_walk_bus(dev->dev->bus, msm_pcie_config_device_info, dev); pci_save_state(pcidev); dev->default_state = pci_store_saved_state(pcidev); @@ -5908,7 +5903,7 @@ static int msm_pcie_probe(struct platform_device *pdev) { int ret = 0; int rc_idx = -1; - int i, size; + int size; struct msm_pcie_dev_t *pcie_dev; struct device_node *of_node; @@ -6136,13 +6131,6 @@ static int msm_pcie_probe(struct platform_device *pdev) memcpy(pcie_dev->pipe_reset, msm_pcie_pipe_reset_info[rc_idx], sizeof(msm_pcie_pipe_reset_info[rc_idx])); - for (i = 0; i < MAX_DEVICE_NUM; i++) { - pcie_dev->pcidev_table[i].bdf = 0; - pcie_dev->pcidev_table[i].dev = NULL; - pcie_dev->pcidev_table[i].short_bdf = 0; - pcie_dev->pcidev_table[i].sid = 0; - } - dev_set_drvdata(&pdev->dev, pcie_dev); ret = msm_pcie_get_resources(pcie_dev, pcie_dev->pdev); From ad22cfa30a628635c4232c50d30dac72f2655476 Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Thu, 26 Nov 2020 12:40:55 +0530 Subject: [PATCH 42/90] msm: mhi_dev: Allocate ring element during M0 Device allocates ring memory during mmio initialization, this causes 128 event ring elements to be created as MHICFG register may not be updated by the host. This causes memory to get exhausted leading to an MMIO init failure. The Change is to allocate ring memory during M0, during which MHICFG register is bound to be updated by the host. Change-Id: I04a0e0ed79a46f16f96e2be4c5c68cba9ee2c99d Signed-off-by: Subramanian Ananthanarayanan Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi.c | 70 ++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 4e1a15dd8c72..5eca5c2d3214 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -91,6 +91,7 @@ static void mhi_dev_cmd_event_msi_cb(void *req); static int mhi_dev_alloc_cmd_ack_buf_req(struct mhi_dev *mhi); +static int mhi_dev_ring_init(struct mhi_dev *dev); static struct mhi_dev_uevent_info channel_state_info[MHI_MAX_CHANNELS]; static DECLARE_COMPLETION(read_from_host); @@ -2685,6 +2686,25 @@ 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; + + /* Allocate ring elements, during M0 when host + * would have updated MHICFG register + */ + + if (!mhi->ring) { + mhi->ring = devm_kcalloc(&pdev->dev, + (mhi->cfg.channels + mhi->cfg.event_rings+1), + sizeof(struct mhi_dev_ring), + GFP_KERNEL); + if (!mhi->ring) { + rc = -ENOMEM; + goto exit; + } + mhi_log(MHI_MSG_INFO, + "MEM_ALLOC: size:%d RING_ALLOC\n", + (sizeof(struct mhi_dev_ring) * + (mhi->cfg.channels + mhi->cfg.event_rings + 1))); + } /* * This func mhi_dev_cache_host_cfg will be called when * processing mhi device reset as well, do not allocate @@ -2731,6 +2751,13 @@ static int mhi_dev_cache_host_cfg(struct mhi_dev *mhi) } memset(mhi->ch_ctx_cache, 0, sizeof(struct mhi_dev_ch_ctx) * mhi->cfg.channels); + + rc = mhi_dev_ring_init(mhi); + if (rc) { + mhi_log(MHI_MSG_VERBOSE, "MHI dev ring init failed\n"); + goto exit; + } + if (MHI_USE_DMA(mhi)) { data_transfer.phy_addr = mhi->cmd_ctx_cache_dma_handle; data_transfer.host_pa = mhi->cmd_ctx_shadow.host_pa; @@ -2761,21 +2788,43 @@ static int mhi_dev_cache_host_cfg(struct mhi_dev *mhi) mhi->ev_ctx_cache->rp, mhi->ev_ctx_cache->wp); - return mhi_ring_start(&mhi->ring[0], + rc = mhi_ring_start(&mhi->ring[0], (union mhi_dev_ring_ctx *)mhi->cmd_ctx_cache, mhi); + if (rc) { + pr_err("MHI ring start failed:%d\n", rc); + goto exit; + } + return 0; exit: - if (mhi->cmd_ctx_cache) + if (mhi->ring) { + devm_kfree(&pdev->dev, mhi->ring); + mhi->ring = NULL; + mhi_log(MHI_MSG_INFO, + "MEM_DEALLOC: size:%d RING_ALLOC\n", + (sizeof(struct mhi_dev_ring) * + (mhi->cfg.channels + mhi->cfg.event_rings + 1))); + } + 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) + mhi_log(MHI_MSG_INFO, + "MEM_DEALLOC: size:%d CMD_CTX_CACHE\n", + sizeof(struct mhi_dev_cmd_ctx)); + } + 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); + mhi_log(MHI_MSG_INFO, + "MEM_DEALLOC: size:%d EV_CTX_CACHE\n", + sizeof(struct mhi_dev_ev_ctx) * + mhi->cfg.event_rings); + } return rc; } @@ -3675,13 +3724,6 @@ static void mhi_dev_enable(struct work_struct *work) } } - rc = mhi_dev_ring_init(mhi); - if (rc) { - pr_err("MHI dev ring init failed\n"); - return; - } - - rc = mhi_dev_mmio_get_mhi_state(mhi, &state, &mhi_reset); if (rc) { pr_err("%s: get mhi state failed\n", __func__); @@ -3995,14 +4037,6 @@ static int mhi_init(struct mhi_dev *mhi) return rc; } - 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; - /* * mhi_init is also called during device reset, in * which case channel mem will already be allocated. From e623db906d62a1da61a6812c68b7d57fc4283c28 Mon Sep 17 00:00:00 2001 From: Nitesh Gupta Date: Fri, 5 Mar 2021 18:11:20 +0530 Subject: [PATCH 43/90] msm: mhi: Queue channel db only if channel is open Channel interrupts are seen on device even before, channel ring is initialized. Queuing pending work without checking ring status can lead to processing of spurious interrupts. Adding proper checks in place before queuing channel doorbell. Change-Id: I3ccd7302b535d2b8ef63eada9d7a1fe553dccdaa Signed-off-by: Nitesh Gupta Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 5eca5c2d3214..573911877588 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -2236,11 +2236,12 @@ static int mhi_dev_get_event_notify(enum mhi_dev_state state, return rc; } -static void mhi_dev_queue_channel_db(struct mhi_dev *mhi, +static bool mhi_dev_queue_channel_db(struct mhi_dev *mhi, uint32_t chintr_value, uint32_t ch_num) { struct mhi_dev_ring *ring; struct mhi_dev_channel *ch; + bool work_pending = false; int rc = 0; for (; chintr_value; ch_num++, chintr_value >>= 1) { @@ -2255,14 +2256,16 @@ static void mhi_dev_queue_channel_db(struct mhi_dev *mhi, ch = &mhi->ch[ch_num]; mutex_lock(&ch->ch_lock); ch->db_pending = true; + work_pending = true; mutex_unlock(&ch->ch_lock); rc = mhi_dev_mmio_disable_chdb_a7(mhi, ch_num); if (rc) { pr_err("Error disabling chdb\n"); - return; + return work_pending; } } } + return work_pending; } /* @@ -2291,11 +2294,11 @@ static bool mhi_dev_check_channel_interrupt(struct mhi_dev *mhi) /* Process channel status whose mask is enabled */ chintr_value = (mhi->chdb[i].status & mhi->chdb[i].mask); if (chintr_value) { - pending_work = true; mhi_log(MHI_MSG_VERBOSE, "processing id: %d, ch interrupt 0x%x\n", i, chintr_value); - mhi_dev_queue_channel_db(mhi, chintr_value, ch_num); + pending_work |= mhi_dev_queue_channel_db(mhi, + chintr_value, ch_num); rc = mhi_dev_mmio_write(mhi, MHI_CHDB_INT_CLEAR_A7_n(i), mhi->chdb[i].status); if (rc) { From 45edd7ec797d479b3113f780b9867044a98c090f Mon Sep 17 00:00:00 2001 From: Nitesh Gupta Date: Mon, 8 Mar 2021 13:23:07 +0530 Subject: [PATCH 44/90] msm: mhi_dev: free allocated memory in reverse order of allocation Freeing cmd_ctx before ereqs will result into NULL ptr dereference. Freeing memory in proper order. Change-Id: Ie999017685574e940685eee3b7c205ebe1672664 Signed-off-by: Nitesh Gupta Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 573911877588..01d2c5dd4e7c 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -2978,8 +2978,8 @@ static int mhi_dev_alloc_cmd_ack_buf_req(struct mhi_dev *mhi) sizeof(*cmd_ctx->ereqs), GFP_KERNEL); if (!cmd_ctx->ereqs) { + rc = -ENOMEM; goto free_ereqs; - return -ENOMEM; } /* Allocate buffers to queue transfer completion events */ @@ -3008,9 +3008,13 @@ static int mhi_dev_alloc_cmd_ack_buf_req(struct mhi_dev *mhi) return 0; free_ereqs: - kfree(mhi->cmd_ctx); kfree(cmd_ctx->ereqs); cmd_ctx->ereqs = NULL; + + kfree(mhi->cmd_ctx); + mhi_log(MHI_MSG_INFO, + "MEM_DEALLOC: size:%d CMD_CTX\n", + sizeof(struct mhi_cmd_cmpl_ctx)); mhi->cmd_ctx = NULL; return rc; } From ec8cdae2939b1cf12acf087842ca00c1c4760900 Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Tue, 9 Mar 2021 15:06:45 +0530 Subject: [PATCH 45/90] msm: mhi_dev: check for error during ring processing The change is to check for error code from cmd processing in case of db pending cases, to avoid rd_offset increment. Change-Id: If213297fe02ec1087bfab572f5af97b1e7bb5791 Signed-off-by: Subramanian Ananthanarayanan Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi.c | 41 +++++++++++++++---------- drivers/platform/msm/mhi_dev/mhi.h | 4 +-- drivers/platform/msm/mhi_dev/mhi_ring.c | 4 +-- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 01d2c5dd4e7c..b9866a4182e9 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -1872,7 +1872,7 @@ static void mhi_dev_process_reset_cmd(struct mhi_dev *mhi, int ch_id) ch->reset_pending = false; } -static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, +static int mhi_dev_process_cmd_ring(struct mhi_dev *mhi, union mhi_dev_ring_element_type *el, void *ctx) { int rc = 0; @@ -1901,7 +1901,7 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, if (rc) mhi_log(MHI_MSG_ERROR, "Error with compl event\n"); - return; + return rc; } goto send_start_completion_event; } @@ -1921,7 +1921,7 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, if (rc) mhi_log(MHI_MSG_ERROR, "Error with compl event\n"); - return; + return rc; } mhi->ring[mhi->ch_ring_start + ch_id].state = @@ -1943,7 +1943,7 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, if (rc) mhi_log(MHI_MSG_ERROR, "Error with compl event\n"); - return; + return rc; } if (mhi->use_edma || mhi->use_ipa) { @@ -1959,7 +1959,7 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, mhi_log(MHI_MSG_ERROR, "error starting event ring %d\n", mhi->ch_ctx_cache[ch_id].err_indx); - return; + return rc; } } mutex_lock(&mhi->ch[ch_id].ch_lock); @@ -2014,7 +2014,7 @@ send_start_completion_event: rc = mhi_dev_flush_cmd_completion_events(mhi, &event); if (rc) { pr_err("stop event send failed\n"); - return; + return rc; } } else { /* @@ -2027,7 +2027,7 @@ send_start_completion_event: ring = &mhi->ring[ch_id + mhi->ch_ring_start]; if (ring->state == RING_STATE_UINT) { pr_err("Channel not opened for %d\n", ch_id); - return; + return -EINVAL; } ch = &mhi->ch[ch_id]; @@ -2076,7 +2076,7 @@ send_start_completion_event: rc = mhi_dev_flush_cmd_completion_events(mhi, &event); if (rc) { pr_err("stop event send failed\n"); - return; + return rc; } } else { @@ -2087,7 +2087,7 @@ send_start_completion_event: ring = &mhi->ring[ch_id + mhi->ch_ring_start]; if (ring->state == RING_STATE_UINT) { pr_err("Channel not opened for %d\n", ch_id); - return; + return -EINVAL; } ch = &mhi->ch[ch_id]; mutex_lock(&ch->ch_lock); @@ -2099,7 +2099,8 @@ send_start_completion_event: ch->reset_pending = true; mutex_unlock(&ch->ring->event_lock); mutex_unlock(&ch->ch_lock); - return; + rc = -EBUSY; + return rc; } mhi_dev_process_reset_cmd(mhi, ch_id); mutex_unlock(&ch->ring->event_lock); @@ -2114,9 +2115,10 @@ send_start_completion_event: pr_err("%s: Invalid command:%d\n", __func__, el->generic.type); break; } + return rc; } -static void mhi_dev_process_tre_ring(struct mhi_dev *mhi, +static int mhi_dev_process_tre_ring(struct mhi_dev *mhi, union mhi_dev_ring_element_type *el, void *ctx) { struct mhi_dev_ring *ring = (struct mhi_dev_ring *)ctx; @@ -2127,7 +2129,7 @@ static void mhi_dev_process_tre_ring(struct mhi_dev *mhi, mhi_log(MHI_MSG_VERBOSE, "invalid channel ring id (%d), should be < %lu\n", ring->id, mhi->ch_ring_start); - return; + return -EINVAL; } ch = &mhi->ch[ring->id - mhi->ch_ring_start]; @@ -2141,6 +2143,7 @@ static void mhi_dev_process_tre_ring(struct mhi_dev *mhi, */ if (ch->active_client && ch->active_client->event_trigger != NULL) ch->active_client->event_trigger(&reason); + return 0; } static void mhi_dev_process_ring_pending(struct work_struct *work) @@ -2155,7 +2158,7 @@ static void mhi_dev_process_ring_pending(struct work_struct *work) mutex_lock(&mhi_ctx->mhi_lock); rc = mhi_dev_process_ring(&mhi->ring[mhi->cmd_ring_idx]); - if (rc) { + if (rc && rc != -EBUSY) { mhi_log(MHI_MSG_ERROR, "error processing command ring\n"); goto exit; } @@ -2181,6 +2184,7 @@ static void mhi_dev_process_ring_pending(struct work_struct *work) } mutex_lock(&ch->ch_lock); ch->db_pending = false; + mutex_unlock(&ch->ch_lock); if (ch->reset_pending) { /* @@ -2191,9 +2195,13 @@ static void mhi_dev_process_ring_pending(struct work_struct *work) ch_id = ch->ch_id; mhi_log(MHI_MSG_VERBOSE, "processing pending ch:%d reset\n", ch_id); - mutex_lock(&ch->ring->event_lock); - mhi_dev_process_reset_cmd(mhi, ch_id); - mutex_unlock(&ch->ring->event_lock); + rc = mhi_dev_process_ring( + &mhi->ring[mhi->cmd_ring_idx]); + if (rc) { + mhi_log(MHI_MSG_ERROR, + "error processing command ring\n"); + goto exit; + } } rc = mhi_dev_mmio_enable_chdb_a7(mhi, ch->ch_id); @@ -2203,7 +2211,6 @@ static void mhi_dev_process_ring_pending(struct work_struct *work) mutex_unlock(&ch->ch_lock); goto exit; } - mutex_unlock(&ch->ch_lock); } exit: diff --git a/drivers/platform/msm/mhi_dev/mhi.h b/drivers/platform/msm/mhi_dev/mhi.h index c477bfa7686b..f703d2b546cf 100644 --- a/drivers/platform/msm/mhi_dev/mhi.h +++ b/drivers/platform/msm/mhi_dev/mhi.h @@ -407,7 +407,7 @@ struct mhi_dev_ring { /* ring_ctx_shadow -> tracking ring_ctx in the host */ union mhi_dev_ring_ctx *ring_ctx_shadow; struct msi_buf_cb_data msi_buffer; - void (*ring_cb)(struct mhi_dev *dev, + int (*ring_cb)(struct mhi_dev *dev, union mhi_dev_ring_element_type *el, void *ctx); }; @@ -775,7 +775,7 @@ int mhi_dev_add_element(struct mhi_dev_ring *ring, * @ring_cb: callback function. */ void mhi_ring_set_cb(struct mhi_dev_ring *ring, - void (*ring_cb)(struct mhi_dev *dev, + int (*ring_cb)(struct mhi_dev *dev, union mhi_dev_ring_element_type *el, void *ctx)); /** diff --git a/drivers/platform/msm/mhi_dev/mhi_ring.c b/drivers/platform/msm/mhi_dev/mhi_ring.c index c06e7b36f310..e7b6fb4c389e 100644 --- a/drivers/platform/msm/mhi_dev/mhi_ring.c +++ b/drivers/platform/msm/mhi_dev/mhi_ring.c @@ -197,7 +197,7 @@ int mhi_dev_process_ring_element(struct mhi_dev_ring *ring, size_t offset) el->tre.len, offset); if (ring->ring_cb) - ring->ring_cb(ring->mhi_dev, el, (void *)ring); + return ring->ring_cb(ring->mhi_dev, el, (void *)ring); else mhi_log(MHI_MSG_ERROR, "No callback registered for ring %d\n", ring->id); @@ -557,7 +557,7 @@ void mhi_ring_init(struct mhi_dev_ring *ring, enum mhi_dev_ring_type type, EXPORT_SYMBOL(mhi_ring_init); void mhi_ring_set_cb(struct mhi_dev_ring *ring, - void (*ring_cb)(struct mhi_dev *dev, + int (*ring_cb)(struct mhi_dev *dev, union mhi_dev_ring_element_type *el, void *ctx)) { if (WARN_ON(!ring || !ring_cb)) From eac435a0a2a6df3199bb8ee7029ac92256283459 Mon Sep 17 00:00:00 2001 From: Abhinab Abhinab Date: Mon, 10 May 2021 17:13:45 +0530 Subject: [PATCH 46/90] msm: mhi_dev: Disabling Ch Db Intr during MHI INIT phase In order to tackle the spurious interrupts coming from the host on an invalid channel, the channel doorbell interrupts are disabled during initialization phase. These are enabled after receiving the start command for a particular channel. Change-Id: I12bb315bcd249383ed442ad969e84c9eef25a324 Signed-off-by: Abhinab Abhinab Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi.c | 49 ++++++++++++++----------- drivers/platform/msm/mhi_dev/mhi_mmio.c | 27 ++++++++++++-- 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index b9866a4182e9..b7662d475f95 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -1349,13 +1349,7 @@ static int mhi_enable_int(void) int rc = 0; mhi_log(MHI_MSG_VERBOSE, - "Enable chdb, ctrl and cmdb interrupts\n"); - - rc = mhi_dev_mmio_enable_chdb_interrupts(mhi_ctx); - if (rc) { - pr_err("Failed to enable channel db: %d\n", rc); - return rc; - } + "Enable ctrl and cmdb interrupts\n"); rc = mhi_dev_mmio_enable_ctrl_interrupt(mhi_ctx); if (rc) { @@ -1840,6 +1834,18 @@ static void mhi_dev_process_reset_cmd(struct mhi_dev *mhi, int ch_id) struct mhi_dev_channel *ch; struct mhi_addr host_addr; + rc = mhi_dev_mmio_disable_chdb_a7(mhi, ch_id); + if (rc) { + mhi_log(MHI_MSG_VERBOSE, + "Failed to disable chdb for ch %d\n", ch_id); + rc = mhi_dev_send_cmd_comp_event(mhi, + MHI_CMD_COMPL_CODE_UNDEFINED); + if (rc) + mhi_log(MHI_MSG_VERBOSE, + "Error with compl event\n"); + return; + } + ch = &mhi->ch[ch_id]; /* hard stop and set the channel to stop */ mhi->ch_ctx_cache[ch_id].ch_state = @@ -1889,7 +1895,7 @@ static int mhi_dev_process_cmd_ring(struct mhi_dev *mhi, switch (el->generic.type) { case MHI_DEV_RING_EL_START: - mhi_log(MHI_MSG_VERBOSE, "recived start cmd for channel %d\n", + mhi_log(MHI_MSG_VERBOSE, "received start cmd for channel %d\n", ch_id); if (ch_id >= (HW_CHANNEL_BASE)) { rc = mhi_hwc_chcmd(mhi, ch_id, el->generic.type); @@ -1897,13 +1903,26 @@ static int mhi_dev_process_cmd_ring(struct mhi_dev *mhi, mhi_log(MHI_MSG_ERROR, "Error with HW channel cmd %d\n", rc); rc = mhi_dev_send_cmd_comp_event(mhi, - MHI_CMD_COMPL_CODE_UNDEFINED); + MHI_CMD_COMPL_CODE_UNDEFINED); if (rc) mhi_log(MHI_MSG_ERROR, "Error with compl event\n"); return rc; } goto send_start_completion_event; + } else { + rc = mhi_dev_mmio_enable_chdb_a7(mhi, ch_id); + if (rc) { + mhi_log(MHI_MSG_VERBOSE, + "Failed to enable chdb for ch %d\n", + ch_id); + rc = mhi_dev_send_cmd_comp_event(mhi, + MHI_CMD_COMPL_CODE_UNDEFINED); + if (rc) + mhi_log(MHI_MSG_VERBOSE, + "Error with compl event\n"); + return rc; + } } /* fetch the channel context from host */ @@ -1934,18 +1953,6 @@ static int mhi_dev_process_cmd_ring(struct mhi_dev *mhi, mhi->ch[ch_id].ring = &mhi->ring[mhi->ch_ring_start + ch_id]; mhi->ch[ch_id].ch_type = mhi->ch_ctx_cache[ch_id].ch_type; - /* enable DB for event ring */ - rc = mhi_dev_mmio_enable_chdb_a7(mhi, ch_id); - if (rc) { - pr_err("Failed to enable channel db\n"); - rc = mhi_dev_send_cmd_comp_event(mhi, - MHI_CMD_COMPL_CODE_UNDEFINED); - if (rc) - mhi_log(MHI_MSG_ERROR, - "Error with compl event\n"); - return rc; - } - if (mhi->use_edma || mhi->use_ipa) { uint32_t evnt_ring_idx = mhi->ev_ring_start + mhi->ch_ctx_cache[ch_id].err_indx; diff --git a/drivers/platform/msm/mhi_dev/mhi_mmio.c b/drivers/platform/msm/mhi_dev/mhi_mmio.c index 71fa971dc8eb..a6aebc969a59 100644 --- a/drivers/platform/msm/mhi_dev/mhi_mmio.c +++ b/drivers/platform/msm/mhi_dev/mhi_mmio.c @@ -601,13 +601,18 @@ EXPORT_SYMBOL(mhi_dev_mmio_reset); int mhi_dev_restore_mmio(struct mhi_dev *dev) { + int rc = 0; uint32_t i, reg_cntl_value; void *reg_cntl_addr; if (WARN_ON(!dev)) return -EINVAL; - mhi_dev_mmio_mask_interrupts(dev); + mhi_dev_mmio_disable_ctrl_interrupt(dev); + + mhi_dev_mmio_disable_cmdb_interrupt(dev); + + mhi_dev_mmio_mask_erdb_interrupts(dev); for (i = 0; i < (MHI_DEV_MMIO_RANGE/4); i++) { reg_cntl_addr = dev->mmio_base_addr + @@ -618,12 +623,26 @@ int mhi_dev_restore_mmio(struct mhi_dev *dev) mhi_dev_mmio_clear_interrupts(dev); + for (i = 0; i < MHI_MASK_ROWS_CH_EV_DB; i++) { + /* Enable channel interrupt whose mask is enabled */ + if (dev->chdb[i].mask) { + mhi_log(MHI_MSG_VERBOSE, + "Enabling id: %d, chdb mask 0x%x\n", + i, dev->chdb[i].mask); + + rc = mhi_dev_mmio_write(dev, MHI_CHDB_INT_MASK_A7_n(i), + dev->chdb[i].mask); + if (rc) { + mhi_log(MHI_MSG_VERBOSE, + "Error writing enable for A7\n"); + return rc; + } + } + } + /* Mask and enable control interrupt */ mhi_dev_mmio_enable_ctrl_interrupt(dev); - /*Enable chdb interrupt*/ - mhi_dev_mmio_enable_chdb_interrupts(dev); - /*Enable cmdb interrupt*/ mhi_dev_mmio_enable_cmdb_interrupt(dev); From ca3c20e9a7dc272539ed79f0769b6928fd2b56c3 Mon Sep 17 00:00:00 2001 From: Pooja Kumari Date: Thu, 1 Jul 2021 13:54:53 +0530 Subject: [PATCH 47/90] msm: ipa3: add v2x ethernet pipes Add cv2x ethernet endpoint configuration changes. Change-Id: I6d1ac9cb5a282a871722e56f51c7c027b24b6b55 Signed-off-by: Pooja Kumari --- include/linux/ipa_uc_offload.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/linux/ipa_uc_offload.h b/include/linux/ipa_uc_offload.h index 095fcb048ada..9d80c752c40b 100644 --- a/include/linux/ipa_uc_offload.h +++ b/include/linux/ipa_uc_offload.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #ifndef _IPA_UC_OFFLOAD_H_ @@ -19,6 +19,7 @@ enum ipa_uc_offload_proto { IPA_UC_INVALID = 0, IPA_UC_WDI = 1, IPA_UC_NTN = 2, + IPA_UC_NTN_V2X = 3, IPA_UC_MAX_PROT_SIZE }; @@ -89,6 +90,7 @@ struct ntn_buff_smmu_map { * @num_buffers: Rx/Tx buffer pool size (in terms of elements) * @data_buff_size: size of the each data buffer allocated in DDR * @ntn_reg_base_ptr_pa: physical address of the Tx/Rx NTN Ring's + * @u8 db_mode: 0 means irq mode, 1 means db mode * tail pointer */ struct ipa_ntn_setup_info { @@ -111,6 +113,8 @@ struct ipa_ntn_setup_info { u32 data_buff_size; phys_addr_t ntn_reg_base_ptr_pa; + + u8 db_mode; }; /** @@ -176,10 +180,12 @@ struct ipa_uc_offload_conn_out_params { * struct ipa_perf_profile - To set BandWidth profile * * @client: type of "client" (IPA_CLIENT_ODU#_PROD/CONS) + * @proto: uC offload protocol type * @max_supported_bw_mbps: maximum bandwidth needed (in Mbps) */ struct ipa_perf_profile { enum ipa_client_type client; + enum ipa_uc_offload_proto proto; u32 max_supported_bw_mbps; }; From b96fd565f8085509ee08ee2dab7c994bd0fa42c2 Mon Sep 17 00:00:00 2001 From: Tony Truong Date: Mon, 8 Feb 2021 17:27:58 -0800 Subject: [PATCH 48/90] msm: pcie: add support to update MPS for all child PCI devices Update Max Payload size (MPS) for all child PCI devices of RC. Child PCI devices will have their MPS scaled to at most RC MPS. Configuring all child PCI devices with the largest MPS possible will help improve overall PCIe link bandwidth performance. Change-Id: I871b49a5ec07d020a445a59f622ceec6061dfc26 Signed-off-by: Tony Truong --- drivers/pci/controller/pci-msm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index 18dd212e44e1..b983b734da7d 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -4848,7 +4848,7 @@ int msm_pcie_enumerate(u32 rc_idx) struct pci_dev *pcidev = NULL; struct pci_host_bridge *bridge; bool found = false; - struct pci_bus *bus; + struct pci_bus *bus, *child; resource_size_t iobase = 0; u32 ids, vendor_id, device_id; LIST_HEAD(res); @@ -4930,6 +4930,9 @@ int msm_pcie_enumerate(u32 rc_idx) bus = bridge->bus; pci_assign_unassigned_bus_resources(bus); + list_for_each_entry(child, &bus->children, node) + pcie_bus_configure_settings(child); + pci_bus_add_devices(bus); dev->enumerated = true; From 52eb9e14397055da49b8607654615672878c272b Mon Sep 17 00:00:00 2001 From: Tony Truong Date: Mon, 8 Feb 2021 17:23:57 -0800 Subject: [PATCH 49/90] msm: pcie: update RC MPS based on MPSS Scale PCIe RC Max Payload Size (MPS) based on its capability Max Payload Size Supported (MPSS). Configurating RC MPS to the largest setting possible will help improve overall PCIe link bandwidth performance. Change-Id: Ice31cf0ab97fd7dd83736eea77e42ff00fb3148c Signed-off-by: Tony Truong --- drivers/pci/controller/pci-msm.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index b983b734da7d..3659190ee875 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -103,6 +103,7 @@ #define PCIE20_ELBI_SYS_STTS (0x08) #define PCIE20_CAP (0x70) +#define PCIE20_CAP_DEVCAP (PCIE20_CAP + 0x04) #define PCIE20_CAP_DEVCTRLSTATUS (PCIE20_CAP + 0x08) #define PCIE20_CAP_LINKCTRLSTATUS (PCIE20_CAP + 0x10) #define PCIE_CAP_DLL_ACTIVE BIT(29) @@ -3646,6 +3647,8 @@ done: static void msm_pcie_config_controller(struct msm_pcie_dev_t *dev) { + u32 val; + PCIE_DBG(dev, "RC%d\n", dev->rc_idx); /* @@ -3681,6 +3684,13 @@ static void msm_pcie_config_controller(struct msm_pcie_dev_t *dev) PCIE20_DEVICE_CONTROL2_STATUS2, 0xf, dev->cpl_timeout); + /* update RC Max Payload Size based on Max Payload Size Supported */ + val = readl_relaxed(dev->dm_core + PCIE20_CAP_DEVCAP) & + PCI_EXP_DEVCAP_PAYLOAD; + msm_pcie_write_reg_field(dev->dm_core, + PCIE20_CAP_DEVCTRLSTATUS, + PCI_EXP_DEVCTL_PAYLOAD, val); + /* Enable AER on RC */ if (dev->aer_enable) { msm_pcie_write_mask(dev->dm_core + PCIE20_BRIDGE_CTRL, 0, From 478702145f812406b3207c3834f89cd7a7c8799f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 8 Jun 2021 19:44:59 -0700 Subject: [PATCH 50/90] usb: fix various gadget panics on 10gbps cabling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit usb_assign_descriptors() is called with 5 parameters, the last 4 of which are the usb_descriptor_header for: full-speed (USB1.1 - 12Mbps [including USB1.0 low-speed @ 1.5Mbps), high-speed (USB2.0 - 480Mbps), super-speed (USB3.0 - 5Gbps), super-speed-plus (USB3.1 - 10Gbps). The differences between full/high/super-speed descriptors are usually substantial (due to changes in the maximum usb block size from 64 to 512 to 1024 bytes and other differences in the specs), while the difference between 5 and 10Gbps descriptors may be as little as nothing (in many cases the same tuning is simply good enough). However if a gadget driver calls usb_assign_descriptors() with a NULL descriptor for super-speed-plus and is then used on a max 10gbps configuration, the kernel will crash with a null pointer dereference, when a 10gbps capable device port + cable + host port combination shows up. (This wouldn't happen if the gadget max-speed was set to 5gbps, but it of course defaults to the maximum, and there's no real reason to artificially limit it) The fix is to simply use the 5gbps descriptor as the 10gbps descriptor, if a 10gbps descriptor wasn't provided. Obviously this won't fix the problem if the 5gbps descriptor is also NULL, but such cases can't be so trivially solved (and any such gadgets are unlikely to be used with USB3 ports any way). Cc: Felipe Balbi Cc: Greg Kroah-Hartman Signed-off-by: Maciej Żenczykowski Cc: stable Link: https://lore.kernel.org/r/20210609024459.1126080-1-zenczykowski@gmail.com Signed-off-by: Greg Kroah-Hartman Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Git-commit: 032e288097a553db5653af552dd8035cd2a0ba96 Change-Id: Ic90930c8ff99f2a3749c79a268f0a410827e485c Signed-off-by: Elson Roy Serrao --- drivers/usb/gadget/config.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index 8bb25773b61e..05507606b2b4 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -164,6 +164,14 @@ int usb_assign_descriptors(struct usb_function *f, { struct usb_gadget *g = f->config->cdev->gadget; + /* super-speed-plus descriptor falls back to super-speed one, + * if such a descriptor was provided, thus avoiding a NULL + * pointer dereference if a 5gbps capable gadget is used with + * a 10gbps capable config (device port + cable + host port) + */ + if (!ssp) + ssp = ss; + if (fs) { f->fs_descriptors = usb_copy_descriptors(fs); if (!f->fs_descriptors) From 52da491c29a8bfc17e1da8b94d27ec63e3405d19 Mon Sep 17 00:00:00 2001 From: Sarthak Garg Date: Fri, 2 Jul 2021 14:32:14 +0530 Subject: [PATCH 51/90] mmc: core: Remove unnecessary scale debugfs entry Current scale debugfs entry is quite unstable and used barely. Hardware cmd timeout and some other issues are being seen when trying to modify the scale entry. Remove unnecessary scale debugfs entry to avoid such issues. Change-Id: I9486a9fe7498ba1855153202415fca80debb13f9 Signed-off-by: Sarthak Garg --- drivers/mmc/core/debugfs.c | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index b99ff071d256..25b53cca4705 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -223,40 +223,6 @@ DEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set, "%llu\n"); #if defined(CONFIG_SDC_QTI) -static int mmc_scale_get(void *data, u64 *val) -{ - struct mmc_host *host = data; - - *val = host->clk_scaling.curr_freq; - - return 0; -} - -static int mmc_scale_set(void *data, u64 val) -{ - int err = 0; - struct mmc_host *host = data; - - mmc_claim_host(host); - - /* change frequency from sysfs manually */ - err = mmc_clk_update_freq(host, val, host->clk_scaling.state); - if (err == -EAGAIN) - err = 0; - else if (err) - pr_err("%s: clock scale to %llu failed with error %d\n", - mmc_hostname(host), val, err); - else - pr_debug("%s: clock change to %llu finished successfully (%s)\n", - mmc_hostname(host), val, current->comm); - - mmc_release_host(host); - - return err; -} - -DEFINE_DEBUGFS_ATTRIBUTE(mmc_scale_fops, mmc_scale_get, mmc_scale_set, - "%llu\n"); static int mmc_max_clock_get(void *data, u64 *val) { @@ -314,8 +280,6 @@ void mmc_add_host_debugfs(struct mmc_host *host) #if defined(CONFIG_SDC_QTI) debugfs_create_file("max_clock", 0600, root, host, &mmc_max_clock_fops); - debugfs_create_file("scale", 0600, root, host, - &mmc_scale_fops); debugfs_create_bool("skip_clk_scale_freq_update", 0600, root, &host->clk_scaling.skip_clk_scale_freq_update); From 9a48d58ca2e3c42091a73c9efb1d58e0e465d3ed Mon Sep 17 00:00:00 2001 From: Shyam Kumar Thella Date: Thu, 3 Jun 2021 16:56:37 +0530 Subject: [PATCH 52/90] power: supply: qbg: Fixes in QBG driver Add changes required in QBG driver after validation on pm5100. 1. Add sample time for different QBG modes. 2. Store batt id and essential param revid after each FIFO processing and at startup use that data to decide whether to load SDAM data or not. 3. PM5100 ADC reports the batt_id directly, drop the voltage based conversion logic. 4. Fix the LSB value for current. Change-Id: Ib51f8c5e48c89ee7bf60e5ee9a6c575617461a02 Signed-off-by: Shyam Kumar Thella --- .../power/supply/qcom/qbg-battery-profile.c | 4 +- drivers/power/supply/qcom/qbg-core.h | 42 +++- drivers/power/supply/qcom/qbg-sdam.c | 105 ++++++-- drivers/power/supply/qcom/qbg-sdam.h | 19 +- drivers/power/supply/qcom/qti-qbg.c | 230 +++++++++++++----- include/uapi/linux/qbg.h | 17 +- 6 files changed, 330 insertions(+), 87 deletions(-) diff --git a/drivers/power/supply/qcom/qbg-battery-profile.c b/drivers/power/supply/qcom/qbg-battery-profile.c index 14b64f581e97..656a9de75d33 100644 --- a/drivers/power/supply/qcom/qbg-battery-profile.c +++ b/drivers/power/supply/qcom/qbg-battery-profile.c @@ -484,7 +484,7 @@ int qbg_batterydata_init(struct device_node *profile_node, rc = alloc_chrdev_region(&battery->dev_no, 0, 1, "qbg_battery"); if (rc < 0) { pr_err("Failed to allocate chrdev, rc=%d\n", rc); - goto free_battery; + return rc; } cdev_init(&battery->battery_cdev, &qbg_battery_data_fops); @@ -534,8 +534,6 @@ delete_cdev: cdev_del(&battery->battery_cdev); unregister_chrdev: unregister_chrdev_region(battery->dev_no, 1); -free_battery: - kfree(battery); return rc; } diff --git a/drivers/power/supply/qcom/qbg-core.h b/drivers/power/supply/qcom/qbg-core.h index 49a619373c08..2690377d3ff2 100644 --- a/drivers/power/supply/qcom/qbg-core.h +++ b/drivers/power/supply/qcom/qbg-core.h @@ -17,14 +17,13 @@ enum debug_mask { QBG_DEBUG_BUS_READ = BIT(0), QBG_DEBUG_BUS_WRITE = BIT(1), - QBG_DEBUG_FIFO = BIT(2), + QBG_DEBUG_SDAM = BIT(2), QBG_DEBUG_IRQ = BIT(3), QBG_DEBUG_DEVICE = BIT(4), QBG_DEBUG_PROFILE = BIT(5), QBG_DEBUG_SOC = BIT(6), - QBG_DEBUG_SDAM = BIT(7), - QBG_DEBUG_STATUS = BIT(8), - QBG_DEBUG_PON = BIT(9), + QBG_DEBUG_STATUS = BIT(7), + QBG_DEBUG_PON = BIT(8), }; enum qbg_sdam { @@ -37,6 +36,32 @@ enum qbg_sdam { SDAM_DATA4, }; +enum qbg_data_tag { + QBG_DATA_TAG_FAST_CHAR, +}; + +enum QBG_SAMPLE_NUM_TYPE { + SAMPLE_NUM_1, + SAMPLE_NUM_2, + SAMPLE_NUM_4, + SAMPLE_NUM_8, + SAMPLE_NUM_16, + SAMPLE_NUM_32, + QBG_SAMPLE_NUM_INVALID, +}; + +enum QBG_ACCUM_INTERVAL_TYPE { + ACCUM_INTERVAL_100MS, + ACCUM_INTERVAL_200MS, + ACCUM_INTERVAL_500MS, + ACCUM_INTERVAL_1000MS, + ACCUM_INTERVAL_2000MS, + ACCUM_INTERVAL_5000MS, + ACCUM_INTERVAL_10000MS, + ACCUM_INTERVAL_100000MS, + ACCUM_INTERVAL_INVALID, +}; + /** * struct qti_qbg - Structure for QTI QBG device * @dev: Pointer to QBG device structure @@ -70,8 +95,11 @@ enum qbg_sdam { * @batt_type_str: String array denoting battery type * @irq: QBG irq number * @base: Base address of QBG HW - * @num_sdams: Number of sdams used for QBG + * @num_data_sdams: Number of data sdams used for QBG * @batt_id_ohm: Battery resistance in ohms + * @sdam_batt_id: Battery ID stored and retrieved from SDAM + * @essential_param_revid: QBG essential parameters revision ID + * @sample_time_us: Array of accumulator sample time in each QBG HW state * @debug_mask: Debug mask to enable/disable debug prints * @pon_ocv: Power-on OCV of QBG device * @pon_ibat: Power-on current of QBG device @@ -138,9 +166,11 @@ struct qti_qbg { int irq; u32 base; u32 sdam_base; - u32 num_sdams; u32 num_data_sdams; u32 batt_id_ohm; + u32 sdam_batt_id; + u32 essential_param_revid; + u32 sample_time_us[QBG_STATE_MAX]; u32 *debug_mask; int pon_ocv; int pon_ibat; diff --git a/drivers/power/supply/qcom/qbg-sdam.c b/drivers/power/supply/qcom/qbg-sdam.c index 4baff57527c7..7afc4c422eea 100644 --- a/drivers/power/supply/qcom/qbg-sdam.c +++ b/drivers/power/supply/qcom/qbg-sdam.c @@ -49,22 +49,18 @@ int qbg_sdam_get_fifo_data(struct qti_qbg *chip, struct fifo_data *fifo, fifo_data_length = fifo_count * QBG_ONE_FIFO_LENGTH; num_sdams = fifo_data_length / QBG_SDAM_ONE_FIFO_REGION_SIZE; - if (num_sdams > chip->num_sdams) { + if (num_sdams > chip->num_data_sdams) { pr_err("Fifo count exceeds QBG SDAMs\n"); return -EINVAL; } - qbg_dbg(chip, QBG_DEBUG_FIFO, "Completely filled sdams=%d\n", + qbg_dbg(chip, QBG_DEBUG_SDAM, "Completely filled sdams=%d\n", num_sdams); /* First read SDAMs that are completely filled */ for (i = 0; i < num_sdams; i++) { - if (!chip->sdam[i]) { - pr_err("Number of SDAMs not sufficient to read FIFOs\n"); - return -ENODEV; - } rc = qbg_sdam_read(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_DATA0 + i), + QBG_SDAM_DATA_START_OFFSET(chip, (SDAM_DATA0 + i)), (((u8 *)fifo) + bytes_read), QBG_SDAM_ONE_FIFO_REGION_SIZE); if (rc < 0) { @@ -77,12 +73,12 @@ int qbg_sdam_get_fifo_data(struct qti_qbg *chip, struct fifo_data *fifo, /* Next read SDAM that is partially filled */ bytes_remaining = fifo_data_length - bytes_read; - qbg_dbg(chip, QBG_DEBUG_FIFO, "Valid data in partially filled sdam:%d bytes\n", + qbg_dbg(chip, QBG_DEBUG_SDAM, "Valid data in partially filled sdam:%d bytes\n", bytes_remaining); if (bytes_remaining) { rc = qbg_sdam_read(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_DATA0 + i), + QBG_SDAM_DATA_START_OFFSET(chip, (SDAM_DATA0 + i)), (((u8 *)fifo) + bytes_read), bytes_remaining); if (rc < 0) { @@ -93,7 +89,7 @@ int qbg_sdam_get_fifo_data(struct qti_qbg *chip, struct fifo_data *fifo, bytes_read += bytes_remaining; } - qbg_dbg(chip, QBG_DEBUG_FIFO, "Total bytes read=%d\n", bytes_read); + qbg_dbg(chip, QBG_DEBUG_SDAM, "Total bytes read=%d\n", bytes_read); return rc; } @@ -106,13 +102,13 @@ int qbg_sdam_get_essential_params(struct qti_qbg *chip, u8 *params) return -EINVAL; rc = qbg_sdam_read(chip, - chip->sdam_base + (SDAM_CTRL1 * 0x100) + + chip->sdam_base + (SDAM_CTRL1 * QBG_SINGLE_SDAM_SIZE) + QBG_ESSENTIAL_PARAMS_START_OFFSET, (u8 *)params, sizeof(struct qbg_essential_params)); if (rc < 0) pr_err("Failed to read QBG essential params, rc=%d\n", rc); else - qbg_dbg(chip, QBG_DEBUG_FIFO, "Read QBG essential params\n"); + qbg_dbg(chip, QBG_DEBUG_SDAM, "Read QBG essential params\n"); return rc; } @@ -125,13 +121,94 @@ int qbg_sdam_set_essential_params(struct qti_qbg *chip, u8 *params) return -EINVAL; rc = qbg_sdam_write(chip, - chip->sdam_base + (SDAM_CTRL1 * 0x100) + + chip->sdam_base + (SDAM_CTRL1 * QBG_SINGLE_SDAM_SIZE) + QBG_ESSENTIAL_PARAMS_START_OFFSET, (u8 *)params, sizeof(struct qbg_essential_params)); if (rc < 0) pr_err("Failed to write QBG essential params, rc=%d\n", rc); else - qbg_dbg(chip, QBG_DEBUG_FIFO, "Written QBG essential params\n"); + qbg_dbg(chip, QBG_DEBUG_SDAM, "Written QBG essential params\n"); + + return rc; +} + +int qbg_sdam_get_essential_param_revid(struct qti_qbg *chip, u8 *revid) +{ + int rc; + + if (!chip || !revid) + return -EINVAL; + + rc = qbg_sdam_read(chip, + chip->sdam_base + (SDAM_CTRL1 * QBG_SINGLE_SDAM_SIZE) + + QBG_ESSENTIAL_PARAMS_REVID_OFFSET, + revid, 1); + if (rc < 0) + pr_err("Failed to read QBG essential params revid, rc=%d\n", rc); + else + qbg_dbg(chip, QBG_DEBUG_SDAM, "Read QBG essential params revid:%u\n", *revid); + + return rc; +} + +int qbg_sdam_set_essential_param_revid(struct qti_qbg *chip, u8 revid) +{ + int rc; + + if (!chip) + return -EINVAL; + + rc = qbg_sdam_write(chip, + chip->sdam_base + (SDAM_CTRL1 * QBG_SINGLE_SDAM_SIZE) + + QBG_ESSENTIAL_PARAMS_REVID_OFFSET, + &revid, 1); + if (rc < 0) + pr_err("Failed to write QBG essential params revid, rc=%d\n", rc); + else + qbg_dbg(chip, QBG_DEBUG_SDAM, "Store QBG essential params revid:%u\n", + revid); + + return rc; +} + +int qbg_sdam_get_battery_id(struct qti_qbg *chip, u32 *battid) +{ + int rc; + u8 buf[2]; + + if (!chip || !battid) + return -EINVAL; + + rc = qbg_sdam_read(chip, + chip->sdam_base + (SDAM_CTRL1 * QBG_SINGLE_SDAM_SIZE) + + QBG_ESSENTIAL_PARAMS_BATTID_OFFSET, + buf, 2); + if (rc < 0) { + pr_err("Failed to read QBG battery ID, rc=%d\n", rc); + } else { + *battid = buf[0] | (buf[1] << 8); + qbg_dbg(chip, QBG_DEBUG_SDAM, "Read QBG battery ID:%u\n", + *battid); + } + + return rc; +} + +int qbg_sdam_set_battery_id(struct qti_qbg *chip, u32 battid) +{ + int rc; + + if (!chip) + return -EINVAL; + + rc = qbg_sdam_write(chip, + chip->sdam_base + (SDAM_CTRL1 * QBG_SINGLE_SDAM_SIZE) + + QBG_ESSENTIAL_PARAMS_BATTID_OFFSET, + (u8 *)&battid, 2); + if (rc < 0) + pr_err("Failed to write QBG battery ID, rc=%d\n", rc); + else + qbg_dbg(chip, QBG_DEBUG_SDAM, "Store QBG battery ID:%u\n", battid); return rc; } diff --git a/drivers/power/supply/qcom/qbg-sdam.h b/drivers/power/supply/qcom/qbg-sdam.h index db888cc20094..1e9109e99f3f 100644 --- a/drivers/power/supply/qcom/qbg-sdam.h +++ b/drivers/power/supply/qcom/qbg-sdam.h @@ -10,7 +10,9 @@ #define QBG_SDAM_FIFO_COUNT_OFFSET 0x46 #define QBG_ESSENTIAL_PARAMS_START_OFFSET 0x47 #define QBG_SDAM_START_OFFSET 0x4b +#define QBG_ESSENTIAL_PARAMS_BATTID_OFFSET 0x45 #define QBG_SDAM_BHARGER_OCV_HDRM_OFFSET 0x5b +#define QBG_ESSENTIAL_PARAMS_REVID_OFFSET 0xbb #define QBG_SDAM_INT_TEST1 0xe0 #define QBG_SDAM_INT_TEST_VAL 0xe1 #define QBG_SDAM_DATA_PUSH_COUNTER_OFFSET 0x46 @@ -19,14 +21,23 @@ #define QBG_SDAM_ONE_FIFO_REGION_SIZE 117 /* 117 bytes for FIFO starting from 0x4B */ #define QBG_SDAM_ESR_PULSE_FIFO_INDEX 11 -#define QBG_SDAM_DATA_START_OFFSET(chip, index) \ - (chip->sdam_base + (index * 0x100) + QBG_SDAM_START_OFFSET) +#define QBG_SINGLE_SDAM_SIZE 0x100 +#define QBG_SDAM_BASE(chip, index) (chip->sdam_base + (index * QBG_SINGLE_SDAM_SIZE)) -int qbg_sdam_read(struct qti_qbg *chip, int offset, u8 *data, int length); -int qbg_sdam_write(struct qti_qbg *chip, int offset, u8 *data, int length); +#define QBG_SDAM_DATA_START_OFFSET(chip, index) \ + (QBG_SDAM_BASE(chip, index) + QBG_SDAM_START_OFFSET) + +int qbg_sdam_read(struct qti_qbg *chip, int offset, u8 *data, + int length); +int qbg_sdam_write(struct qti_qbg *chip, int offset, u8 *data, + int length); int qbg_sdam_get_fifo_data(struct qti_qbg *chip, struct fifo_data *fifo, u32 fifo_count); int qbg_sdam_get_essential_params(struct qti_qbg *chip, u8 *params); int qbg_sdam_set_essential_params(struct qti_qbg *chip, u8 *params); +int qbg_sdam_get_essential_param_revid(struct qti_qbg *chip, u8 *revid); +int qbg_sdam_set_essential_param_revid(struct qti_qbg *chip, u8 revid); +int qbg_sdam_get_battery_id(struct qti_qbg *chip, u32 *battid); +int qbg_sdam_set_battery_id(struct qti_qbg *chip, u32 battid); #endif /* __QBG_SDAM_H__ */ diff --git a/drivers/power/supply/qcom/qti-qbg.c b/drivers/power/supply/qcom/qti-qbg.c index 952452390639..f06114c92b8d 100644 --- a/drivers/power/supply/qcom/qti-qbg.c +++ b/drivers/power/supply/qcom/qti-qbg.c @@ -67,15 +67,28 @@ #define QBG_MAIN_VBAT_EMPTY_THRESH 0x56 +#define QBG_MAIN_HPM_MEAS_CTL2 0x5d + +#define QBG_MAIN_MPM_MEAS_CTL2 0x61 + +#define QBG_MAIN_LPM_MEAS_CTL2 0x65 +#define QBG_NUM_OF_ACCUM_MASK GENMASK(7, 5) +#define QBG_NUM_OF_ACCUM_SHIFT 5 +#define QBG_ACCUM_INTERVAL_MASK GENMASK(2, 0) + +#define QBG_MAIN_FAST_CHAR_MEAS_CTL2 0x69 + #define QBG_MAIN_PON_OCV_ACC0_DATA0 0x70 +#define QBG_MAIN_LAST_ADC_ACC0_DATA0 0x9A + #define QBG_MAIN_LAST_BURST_AVG_ACC0_DATA0 0xA0 #define QBG_MAIN_LAST_BURST_AVG_ACC2_DATA0 0xA4 #define QBG_FAST_CHAR_DELTA_MS 100000 #define VBATT_1S_LSB 19463 -#define IBATT_10A_LSB 30518 +#define IBATT_10A_LSB 6103 #define VBAT_0PCT_OCV 300000000ULL #define ICHG_FS_10A 1 #define TBAT_LSB 7500 @@ -86,12 +99,15 @@ #define OCV_BOOST_MAX_UV 5600000 #define OCV_BOOST_STEP_UV 100000 -enum qbg_data_tag { - QBG_DATA_TAG_FAST_CHAR, -}; - static int qbg_debug_mask; +static const unsigned int qbg_accum_interval[8] = { + 10000, 20000, 50000, 100000, 150000, 200000, 500000, 1000000}; +static const unsigned int qbg_lpm_accum_interval[8] = { + 100000, 200000, 500000, 1000000, 2000000, 5000000, 10000000, 100000000}; +static const unsigned int qbg_fast_char_avg_interval[8] = { + 6250, 12500, 25000, 50000, 100000, 200000, 400000, 800000}; + static const struct qbg_iio_channels qbg_iio_psy_channels[] = { QBG_CHAN_INDEX("debug_battery", PSY_IIO_DEBUG_BATTERY) QBG_CHAN_ENERGY("capacity", PSY_IIO_CAPACITY) @@ -100,6 +116,7 @@ static const struct qbg_iio_channels qbg_iio_psy_channels[] = { QBG_CHAN_VOLT("voltage_max", PSY_IIO_VOLTAGE_MAX) QBG_CHAN_VOLT("voltage_now", PSY_IIO_VOLTAGE_NOW) QBG_CHAN_VOLT("voltage_ocv", PSY_IIO_VOLTAGE_OCV) + QBG_CHAN_VOLT("voltage_avg", PSY_IIO_VOLTAGE_AVG) QBG_CHAN_CUR("current_now", PSY_IIO_CURRENT_NOW) QBG_CHAN_RES("resistance_id", PSY_IIO_RESISTANCE_ID) QBG_CHAN_TSTAMP("time_to_full_avg", PSY_IIO_TIME_TO_FULL_AVG) @@ -215,7 +232,7 @@ static int qbg_get_fifo_count(struct qti_qbg *chip, u32 *fifo_count) u8 val[2]; rc = qbg_sdam_read(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_FIFO_COUNT_OFFSET, + QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_FIFO_COUNT_OFFSET, val, 2); if (rc < 0) { pr_err("Failed to read QBG SDAM, rc=%d\n", rc); @@ -223,7 +240,7 @@ static int qbg_get_fifo_count(struct qti_qbg *chip, u32 *fifo_count) } *fifo_count = (val[1] << 8) | val[0]; - qbg_dbg(chip, QBG_DEBUG_FIFO, "FIFO count=%d\n", *fifo_count); + qbg_dbg(chip, QBG_DEBUG_SDAM, "FIFO count=%d\n", *fifo_count); return rc; } @@ -248,13 +265,14 @@ static void update_ocv_for_boost(struct qti_qbg *chip) qbg_dbg(chip, QBG_DEBUG_STATUS, "Boost OCV value written =%d\n", ocv_for_boost); qbg_sdam_write(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_BHARGER_OCV_HDRM_OFFSET, + QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_BHARGER_OCV_HDRM_OFFSET, (u8 *)&ocv_for_boost, 1); } static void process_udata_work(struct work_struct *work) { struct qti_qbg *chip = container_of(work, struct qti_qbg, udata_work); + int rc; if (chip->udata.param[QBG_PARAM_BATT_SOC].valid) chip->batt_soc = chip->udata.param[QBG_PARAM_BATT_SOC].data; @@ -306,6 +324,20 @@ static void process_udata_work(struct work_struct *work) if (chip->udata.param[QBG_PARAM_TBAT].valid) chip->tbat = chip->udata.param[QBG_PARAM_TBAT].data; + if (chip->udata.param[QBG_PARAM_ESSENTIAL_PARAM_REVID].valid) { + chip->essential_param_revid = + chip->udata.param[QBG_PARAM_ESSENTIAL_PARAM_REVID].data; + + rc = qbg_sdam_set_essential_param_revid(chip, chip->essential_param_revid); + if (rc < 0) + pr_err("Failed to set essential param revid in sdam, rc=%d\n", + rc); + } + + rc = qbg_sdam_set_battery_id(chip, chip->batt_id_ohm / 1000); + if (rc < 0) + pr_err("Failed to set battid in sdam, rc=%d\n", rc); + qbg_dbg(chip, QBG_DEBUG_STATUS, "udata update: batt_soc=%d sys_soc=%d soc=%d qbg_esr=%d\n", (chip->batt_soc != INT_MIN) ? chip->batt_soc : -EINVAL, (chip->sys_soc != INT_MIN) ? chip->sys_soc : -EINVAL, @@ -382,7 +414,7 @@ static int qbg_process_fifo(struct qti_qbg *chip, u32 fifo_count) unsigned long timestamp; if (!fifo_count) { - qbg_dbg(chip, QBG_DEBUG_FIFO, "No FIFO data\n"); + qbg_dbg(chip, QBG_DEBUG_SDAM, "No FIFO data\n"); return -EINVAL; } @@ -439,7 +471,7 @@ static int qbg_process_fifo(struct qti_qbg *chip, u32 fifo_count) esr = (vbat1 - vbat1_esr) / ((ibat_esr - ibat) * 10000); esr *= 10000; chip->esr = esr; - qbg_dbg(chip, QBG_DEBUG_FIFO, "ESR:%u, ibat=%d ibat_esr=%d vbat1:%u vbat1_esr:%u\n", + qbg_dbg(chip, QBG_DEBUG_SDAM, "ESR:%u, ibat=%d ibat_esr=%d vbat1:%u vbat1_esr:%u\n", esr, ibat, ibat_esr, vbat1, vbat1_esr); } else { pr_err("Couldn't calculate ESR, ibat=%d ibat_esr=%d vbat1:%u vbat1_esr:%u\n", @@ -456,7 +488,7 @@ static int qbg_process_fifo(struct qti_qbg *chip, u32 fifo_count) goto ret; } - qbg_dbg(chip, QBG_DEBUG_FIFO, "vbat1:%u ibat:%d tbat:%u ibat_t:%u\n", + qbg_dbg(chip, QBG_DEBUG_SDAM, "vbat1:%u ibat:%d tbat:%u ibat_t:%u\n", vbat1, ibat, tbat, ibat_t); chip->kdata.fifo[i].v1 = vbat1; @@ -464,6 +496,7 @@ static int qbg_process_fifo(struct qti_qbg *chip, u32 fifo_count) chip->kdata.fifo[i].i = ibat; chip->kdata.fifo[i].tbat = tbat; chip->kdata.fifo[i].ibat = ibat_t; + chip->kdata.fifo[i].data_tag = fifo[i].data_tag; } ret: @@ -477,7 +510,7 @@ static int qbg_clear_fifo_data(struct qti_qbg *chip) u8 val[2] = {0, 0}; rc = qbg_sdam_write(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_FIFO_COUNT_OFFSET, + QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_FIFO_COUNT_OFFSET, val, 2); if (rc < 0) { pr_err("Failed to clear QBG FIFO Count, rc=%d\n", rc); @@ -487,7 +520,7 @@ static int qbg_clear_fifo_data(struct qti_qbg *chip) for (i = 0; i < 10; i++) { val[0] = 0; rc = qbg_sdam_write(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST_VAL, + QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST_VAL, val, 1); if (rc < 0) { pr_err("Failed to SDAM0 test val to 0, rc=%d\n", rc); @@ -496,7 +529,7 @@ static int qbg_clear_fifo_data(struct qti_qbg *chip) /* Handshake with PBS to access FIFO data */ rc = qbg_sdam_read(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST_VAL, + QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST_VAL, val, 1); if (rc < 0) { pr_err("Failed to read QBG SDAM, rc=%d\n", rc); @@ -512,7 +545,7 @@ static int qbg_clear_fifo_data(struct qti_qbg *chip) val[0] = QBG_SDAM_START_OFFSET; val[1] = 0x0; rc = qbg_sdam_write(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_DATA0) + QBG_SDAM_DATA_PUSH_COUNTER_OFFSET, + QBG_SDAM_BASE(chip, SDAM_DATA0) + QBG_SDAM_DATA_PUSH_COUNTER_OFFSET, val, 2); if (rc < 0) { pr_err("Failed to configure QBG data push counter, rc=%d\n", rc); @@ -520,7 +553,7 @@ static int qbg_clear_fifo_data(struct qti_qbg *chip) } val[0] = 0x0; rc = qbg_sdam_write(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_PBS_STATUS_OFFSET, + QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_PBS_STATUS_OFFSET, val, 1); if (rc < 0) { pr_err("Failed to set QBG PBS status, rc=%d\n", rc); @@ -537,7 +570,7 @@ static int qbg_init_sdam(struct qti_qbg *chip) val[0] = 0x80; rc = qbg_sdam_write(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST1, val, 1); + QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST1, val, 1); if (rc < 0) { pr_err("Failed to write QBG SDAM, rc=%d\n", rc); return rc; @@ -545,7 +578,7 @@ static int qbg_init_sdam(struct qti_qbg *chip) val[0] = 0; rc = qbg_sdam_read(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST_VAL, + QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST_VAL, val, 1); if (rc < 0) { pr_err("Faiiled to read QBG SDAM, rc=%d\n", rc); @@ -687,7 +720,7 @@ static int qbg_load_battery_profile(struct qti_qbg *chip) } profile_node = of_batterydata_get_best_profile(chip->batt_node, - chip->batt_id_ohm, NULL); + chip->batt_id_ohm / 1000, NULL); if (IS_ERR(profile_node)) { rc = PTR_ERR(profile_node); pr_err("Failed to detect valid QBG battery profile, rc=%d\n", @@ -723,7 +756,7 @@ static int qbg_load_battery_profile(struct qti_qbg *chip) goto out; } - rc = of_property_read_u32(profile_node, "qcom,fastchg-curr-ma", + rc = of_property_read_u32(profile_node, "qcom,fastchg-current-ma", &chip->fastchg_curr_ma); if (rc < 0) { pr_err("Failed to read battery fastcharge current, rc:%d\n", rc); @@ -868,42 +901,23 @@ static bool is_battery_present(struct qti_qbg *chip) return present; } -#define BID_RPULL_OHM 100000 -#define BID_VREF_MV 1875 static int get_batt_id_ohm(struct qti_qbg *chip, u32 *batt_id_ohm) { - int rc, batt_id_mv; - int64_t denom; + int rc, batt_id; if (!chip->batt_id_chan) return -EINVAL; /* Read battery-id */ - rc = iio_read_channel_processed(chip->batt_id_chan, &batt_id_mv); + rc = iio_read_channel_processed(chip->batt_id_chan, &batt_id); if (rc < 0) { pr_err("Failed to read BATT_ID over ADC, rc=%d\n", rc); return rc; } - batt_id_mv = div_s64(batt_id_mv, 1000); - if (batt_id_mv == 0) { - *batt_id_ohm = 0; - pr_debug("batt_id_mv = 0 from ADC\n"); - return 0; - } + *batt_id_ohm = (u32)batt_id; - denom = div64_s64(BID_VREF_MV * 1000, batt_id_mv) - 1000; - if (denom <= 0) { - /* batt id connector might be open, return 0 kohms */ - *batt_id_ohm = 0; - return 0; - } - - *batt_id_ohm = div64_u64(BID_RPULL_OHM * 1000 + denom / 2, denom); - chip->batt_id_ohm = *batt_id_ohm; - - qbg_dbg(chip, QBG_DEBUG_PROFILE, "batt_id_mv=%d, batt_id_ohm=%d\n", - batt_id_mv, *batt_id_ohm); + qbg_dbg(chip, QBG_DEBUG_PROFILE, "batt_id_ohm=%u\n", *batt_id_ohm); return 0; } @@ -934,7 +948,7 @@ static int qbg_setup_battery(struct qti_qbg *chip) /* Update OCV boost headroom compensation value to 4.3V in debug battery case */ if (is_debug_batt_id(chip)) { rc = qbg_sdam_write(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + + QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_BHARGER_OCV_HDRM_OFFSET, &ocv_boost_val, 1); } } @@ -1034,13 +1048,6 @@ static int qbg_determine_pon_soc(struct qti_qbg *chip) return 0; } -static int qbg_psy_set_prop(struct power_supply *psy, - enum power_supply_property psp, - const union power_supply_propval *pval) -{ - return 0; -} - static int qbg_psy_get_prop(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *pval) @@ -1061,7 +1068,6 @@ static struct power_supply_desc qbg_psy_desc = { .properties = qbg_psy_props, .num_properties = ARRAY_SIZE(qbg_psy_props), .get_property = qbg_psy_get_prop, - .set_property = qbg_psy_set_prop, }; static int qbg_init_psy(struct qti_qbg *chip) @@ -1121,6 +1127,9 @@ static int qbg_iio_read_raw(struct iio_dev *indio_dev, case PSY_IIO_VOLTAGE_OCV: *val1 = chip->ocv_uv; break; + case PSY_IIO_VOLTAGE_AVG: + rc = qbg_get_battery_voltage(chip, val1); + break; case PSY_IIO_VOLTAGE_NOW: rc = qbg_get_battery_voltage(chip, val1); break; @@ -1228,6 +1237,85 @@ static int qbg_init_iio(struct qti_qbg *chip, return rc; } +static int qbg_get_accumulator_properties(struct qti_qbg *chip, + enum QBG_STATE state, + enum QBG_SAMPLE_NUM_TYPE *num_of_accum, + enum QBG_ACCUM_INTERVAL_TYPE *accum_interval) +{ + int rc = 0; + unsigned int reg = QBG_MAIN_LPM_MEAS_CTL2; + unsigned char data = 0; + + if (state >= QBG_STATE_MAX || !num_of_accum || !accum_interval) + return -EINVAL; + + switch (state) { + case QBG_LPM: + reg = QBG_MAIN_LPM_MEAS_CTL2; + break; + case QBG_MPM: + reg = QBG_MAIN_MPM_MEAS_CTL2; + break; + case QBG_HPM: + reg = QBG_MAIN_HPM_MEAS_CTL2; + break; + case QBG_FAST_CHAR: + reg = QBG_MAIN_FAST_CHAR_MEAS_CTL2; + break; + default: + pr_err("Invalid QBG state requested for accumulator properties %u\n", + state); + return rc; + } + + rc = qbg_read(chip, reg, &data, 1); + if (rc < 0) { + pr_err("Failed to MEAS_CTL2 %u, rc=%d\n", reg, rc); + return rc; + } + + if (state == QBG_FAST_CHAR) + *num_of_accum = 0; + else + *num_of_accum = (data & QBG_NUM_OF_ACCUM_MASK) >> QBG_NUM_OF_ACCUM_SHIFT; + + *accum_interval = data & QBG_ACCUM_INTERVAL_MASK; + + qbg_dbg(chip, QBG_DEBUG_DEVICE, "state:%u num_of_accum:%u accum_interval:%u\n", + state, *num_of_accum, *accum_interval); + + return rc; +} + +static int qbg_get_sample_time_us(struct qti_qbg *chip) +{ + int rc = 0, index; + unsigned int interval; + enum QBG_ACCUM_INTERVAL_TYPE accum_interval = ACCUM_INTERVAL_100MS; + enum QBG_SAMPLE_NUM_TYPE num_accum = SAMPLE_NUM_1; + + for (index = 0; index < QBG_STATE_MAX; index++) { + if (index == QBG_PON_OCV) + continue; + + rc = qbg_get_accumulator_properties(chip, index, &num_accum, + &accum_interval); + if (rc < 0) + return rc; + + if (index == QBG_FAST_CHAR) + interval = qbg_fast_char_avg_interval[accum_interval]; + else if (index == QBG_LPM) + interval = qbg_lpm_accum_interval[accum_interval]; + else + interval = qbg_accum_interval[accum_interval]; + + chip->sample_time_us[index] = interval; + } + + return rc; +} + static ssize_t qbg_device_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -1361,7 +1449,7 @@ static long qbg_device_ioctl(struct file *file, unsigned int cmd, struct qbg_config config; struct qbg_essential_params __user *params_user; unsigned long rtc_sec; - int rc = 0; + int rc = 0, i; if (!chip) { pr_err("Device private data not set!\n"); @@ -1383,8 +1471,29 @@ static long qbg_device_ioctl(struct file *file, unsigned int cmd, switch (cmd) { case QBGIOCXCFG: config_user = (struct qbg_config __user *)arg; + + rc = qbg_get_sample_time_us(chip); + if (rc < 0) { + pr_err("Failed to calculate sample time us, rc=%d\n", rc); + return rc; + } + + rc = qbg_sdam_get_battery_id(chip, &chip->sdam_batt_id); + if (rc < 0) { + pr_err("Failed to get battid from sdam, rc=%d\n", rc); + return rc; + } + + rc = qbg_sdam_get_essential_param_revid(chip, + (u8 *)&chip->essential_param_revid); + if (rc < 0) { + pr_err("Failed to get essential param revid, rc=%d\n", + rc); + return rc; + } + config.current_time = rtc_sec; - config.batt_id = chip->batt_id_ohm; + config.batt_id = chip->batt_id_ohm / 1000; config.pon_ocv = chip->pon_ocv; config.pon_ibat = chip->pon_ibat; config.pon_tbat = chip->pon_tbat; @@ -1395,16 +1504,25 @@ static long qbg_device_ioctl(struct file *file, unsigned int cmd, config.vph_min_mv = chip->vph_min_mv; config.iterm_ma = chip->iterm_ma; config.rconn_mohm = chip->rconn_mohm; + config.sdam_batt_id = chip->sdam_batt_id; + config.essential_param_revid = chip->essential_param_revid; + for (i = 0; i < QBG_STATE_MAX; i++) { + config.sample_time_us[i] = chip->sample_time_us[i]; + qbg_dbg(chip, QBG_DEBUG_DEVICE, "QBGIOCXCFG: sample_time_us[%d]:%u\n", + i, config.sample_time_us[i]); + } if (copy_to_user(config_user, (void *)&config, sizeof(config))) { pr_err("Failed to copy QBG config to user\n"); return -EFAULT; } - qbg_dbg(chip, QBG_DEBUG_DEVICE, "QBGIOCXCFG: battid:%u pon_ocv:%u pon_ibat:%u pon_soc:%u vbatt_cutoff_mv:%u iterm_ma:%u\n", + qbg_dbg(chip, QBG_DEBUG_DEVICE, "QBGIOCXCFG: sdam_battid:%u essential param revid:%u battid:%u pon_ocv:%u pon_ibat:%u pon_soc:%u vbatt_cutoff_mv:%u iterm_ma:%u\n", + config.sdam_batt_id, config.essential_param_revid, config.batt_id, config.pon_ocv, config.pon_ibat, config.pon_soc, config.vbat_cutoff_mv, config.iterm_ma); + break; case QBGIOCXEPR: params_user = (struct qbg_essential_params __user *)arg; @@ -1538,7 +1656,7 @@ static int qbg_parse_sdam_dt(struct qti_qbg *chip, struct device_node *node) return rc; } - rc = of_property_read_u32(node, "sdam-base", &chip->sdam_base); + rc = of_property_read_u32(node, "qcom,sdam-base", &chip->sdam_base); if (rc < 0) { pr_err("Failed to read SDAM base address, rc=%d\n", rc); return rc; diff --git a/include/uapi/linux/qbg.h b/include/uapi/linux/qbg.h index f8bbb4e1a90c..4ca6a65ee62a 100644 --- a/include/uapi/linux/qbg.h +++ b/include/uapi/linux/qbg.h @@ -8,6 +8,15 @@ #define MAX_FIFO_COUNT 36 +enum QBG_STATE { + QBG_LPM, + QBG_MPM, + QBG_HPM, + QBG_FAST_CHAR, + QBG_PON_OCV, + QBG_STATE_MAX, +}; + enum QBG_SDAM_DATA_OFFSET { QBG_ACC0_OFFSET = 0, QBG_ACC1_OFFSET = 2, @@ -41,10 +50,7 @@ enum qbg { QBG_PARAM_SYS_SOC_HOLD_100PCT, QBG_PARAM_JEITA_COOL_THRESHOLD, QBG_PARAM_TOTAL_IMPEDANCE, - QBG_PARAM_PON_OCV, - QBG_PARAM_PON_IBAT, - QBG_PARAM_PON_SOC, - QBG_PARAM_BATT_ID, + QBG_PARAM_ESSENTIAL_PARAM_REVID, QBG_PARAM_FIFO_TIMESTAMP, QBG_PARAM_MAX, }; @@ -115,6 +121,9 @@ struct qbg_config { unsigned int iterm_ma; unsigned int rconn_mohm; unsigned long current_time; + unsigned int sdam_batt_id; + unsigned int essential_param_revid; + unsigned long sample_time_us[QBG_STATE_MAX]; } __attribute__ ((__packed__)); struct qbg_param { From a459581244c62a158660fc6abbf368504050fee2 Mon Sep 17 00:00:00 2001 From: Kavya Nunna Date: Mon, 28 Jun 2021 18:19:06 +0530 Subject: [PATCH 53/90] include: dt-bindings: Add iio-property for clear soh Add iio property for clear soh to update userspace on first profile load. Change-Id: I7a9c2cf886ad7da76f6156c3ac12828bf37fe78a Signed-off-by: Kavya Nunna --- include/dt-bindings/iio/qti_power_supply_iio.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/dt-bindings/iio/qti_power_supply_iio.h b/include/dt-bindings/iio/qti_power_supply_iio.h index c48865098c6a..84611eb3bcc6 100644 --- a/include/dt-bindings/iio/qti_power_supply_iio.h +++ b/include/dt-bindings/iio/qti_power_supply_iio.h @@ -151,4 +151,7 @@ /* USB */ #define PSY_IIO_MOISTURE_DETECTION_EN 0x7b + +/* BMS */ +#define PSY_IIO_CLEAR_SOH 0x7c #endif /* __QTI_POWER_SUPPLY_IIO_H__ */ From c0b667d58c3d7fddb170da328cadc4485037295d Mon Sep 17 00:00:00 2001 From: Kavya Nunna Date: Mon, 28 Jun 2021 18:26:09 +0530 Subject: [PATCH 54/90] power: qpnp-qg: Add support to clear soh upon first profile load When the battery profile is loaded first time, update the clear soh property so that soh algorithm can clear stored parameters. Change-Id: Idfc25c589f8422b76768229e52dab7d670c6b231 Signed-off-by: Kavya Nunna --- drivers/power/supply/qcom/qg-core.h | 3 ++- drivers/power/supply/qcom/qg-iio.h | 3 ++- drivers/power/supply/qcom/qpnp-qg.c | 8 ++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h index b0909d23c20c..2796e16c2a11 100644 --- a/drivers/power/supply/qcom/qg-core.h +++ b/drivers/power/supply/qcom/qg-core.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. */ #ifndef __QG_CORE_H__ @@ -154,6 +154,7 @@ struct qpnp_qg { bool fvss_active; bool tcss_active; bool bass_active; + bool first_profile_load; int charge_status; int charge_type; int chg_iterm_ma; diff --git a/drivers/power/supply/qcom/qg-iio.h b/drivers/power/supply/qcom/qg-iio.h index 46e2232cd74f..b1ee2c4ea3f5 100644 --- a/drivers/power/supply/qcom/qg-iio.h +++ b/drivers/power/supply/qcom/qg-iio.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. */ #ifndef __QG_IIO_H @@ -91,6 +91,7 @@ static const struct qg_iio_channels qg_iio_psy_channels[] = { QG_CHAN_RES("esr_actual", PSY_IIO_ESR_ACTUAL) QG_CHAN_RES("esr_nominal", PSY_IIO_ESR_NOMINAL) QG_CHAN_INDEX("soh", PSY_IIO_SOH) + QG_CHAN_INDEX("clear_soh", PSY_IIO_CLEAR_SOH) QG_CHAN_ENERGY("cc_soc", PSY_IIO_CC_SOC) QG_CHAN_ACT("fg_reset", PSY_IIO_FG_RESET) QG_CHAN_VOLT("voltage_avg", PSY_IIO_VOLTAGE_AVG) diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 96526b23a1c6..4c8839273140 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -2135,6 +2135,9 @@ static int qg_iio_write_raw(struct iio_dev *indio_dev, if (chip->sp) soh_profile_update(chip->sp, chip->soh); break; + case PSY_IIO_CLEAR_SOH: + chip->first_profile_load = val1; + break; case PSY_IIO_ESR_ACTUAL: chip->esr_actual = val1; break; @@ -2260,6 +2263,9 @@ static int qg_iio_read_raw(struct iio_dev *indio_dev, case PSY_IIO_SOH: *val1 = chip->soh; break; + case PSY_IIO_CLEAR_SOH: + *val1 = chip->first_profile_load; + break; case PSY_IIO_CC_SOC: rc = qg_get_cc_soc(chip, val1); break; @@ -3470,6 +3476,7 @@ static int qg_sanitize_sdam(struct qpnp_qg *chip) rc = qg_sdam_write(SDAM_MAGIC, SDAM_MAGIC_NUMBER); if (!rc) qg_dbg(chip, QG_DEBUG_PON, "First boot. SDAM initilized\n"); + chip->first_profile_load = true; } else { /* SDAM has invalid value */ rc = qg_sdam_clear(); @@ -3477,6 +3484,7 @@ static int qg_sanitize_sdam(struct qpnp_qg *chip) pr_err("SDAM uninitialized, SDAM reset\n"); rc = qg_sdam_write(SDAM_MAGIC, SDAM_MAGIC_NUMBER); } + chip->first_profile_load = true; } if (rc < 0) From 34afd1c16e889700603b6a2c4924e46515fbe97a Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Wed, 30 Jun 2021 20:27:44 +0530 Subject: [PATCH 55/90] sched: Improve the scheduler This change is for general scheduler improvements. Change-Id: I37d6cb75ca8b08d9ca155b86b7d71ff369f46e14 Signed-off-by: Lingutla Chandrasekhar --- kernel/sched/core.c | 6 +++++- kernel/sched/walt/qc_vas.c | 17 ++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 5ee5789c14fb..409bb4e34235 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -3870,8 +3870,12 @@ void scheduler_tick(void) if (curr->sched_class == &fair_sched_class) check_for_migration(rq, curr); - if (idle_cpu(cpu) && is_reserved(cpu)) +#ifdef CONFIG_SMP + rq_lock(rq, &rf); + if (idle_cpu(cpu) && is_reserved(cpu) && !rq->active_balance) clear_reserved(cpu); + rq_unlock(rq, &rf); +#endif trace_android_vh_scheduler_tick(rq); } diff --git a/kernel/sched/walt/qc_vas.c b/kernel/sched/walt/qc_vas.c index d4d6c838babe..ce49eac6d590 100644 --- a/kernel/sched/walt/qc_vas.c +++ b/kernel/sched/walt/qc_vas.c @@ -48,12 +48,23 @@ void walt_rotate_work_func(struct work_struct *work) { struct walt_rotate_work *wr = container_of(work, struct walt_rotate_work, w); + struct rq *src_rq = cpu_rq(wr->src_cpu), *dst_rq = cpu_rq(wr->dst_cpu); + unsigned long flags; migrate_swap(wr->src_task, wr->dst_task, wr->dst_cpu, wr->src_cpu); put_task_struct(wr->src_task); put_task_struct(wr->dst_task); + local_irq_save(flags); + double_rq_lock(src_rq, dst_rq); + + dst_rq->active_balance = 0; + src_rq->active_balance = 0; + + double_rq_unlock(src_rq, dst_rq); + local_irq_restore(flags); + clear_reserved(wr->src_cpu); clear_reserved(wr->dst_cpu); } @@ -140,7 +151,8 @@ void walt_check_for_rotation(struct rq *src_rq) dst_rq = cpu_rq(dst_cpu); double_rq_lock(src_rq, dst_rq); - if (dst_rq->curr->sched_class == &fair_sched_class) { + if (dst_rq->curr->sched_class == &fair_sched_class && + !src_rq->active_balance && !dst_rq->active_balance) { get_task_struct(src_rq->curr); get_task_struct(dst_rq->curr); @@ -153,7 +165,10 @@ void walt_check_for_rotation(struct rq *src_rq) wr->src_cpu = src_cpu; wr->dst_cpu = dst_cpu; + dst_rq->active_balance = 1; + src_rq->active_balance = 1; } + double_rq_unlock(src_rq, dst_rq); if (wr) From f2f05457ef61e89313d30c010fd5c49d0b577960 Mon Sep 17 00:00:00 2001 From: Pratham Pratap Date: Wed, 30 Jun 2021 21:50:48 +0530 Subject: [PATCH 56/90] usb: gadget: Restart USB session if start xfer fails for ep0 Currently driver is just proceding further if start xfer times out for ep0. Start xfer failing for ep0 indicates that the controller is already in bad state and it can access unmapped address leading to SMMU fault. Prevent this by marking this as an error event and restart USB session. Change-Id: Ia46387e16a79318ad945079ced7209a8f2bf47ef Signed-off-by: Pratham Pratap --- drivers/usb/dwc3/ep0.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index a0cbefaad94c..eb810f2aa6cb 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -78,8 +78,20 @@ static int dwc3_ep0_start_trans(struct dwc3_ep *dep) params.param1 = lower_32_bits(dwc->ep0_trb_addr); ret = dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_STARTTRANSFER, ¶ms); - if (ret < 0) + if (ret < 0) { + if (ret == -ETIMEDOUT) { + /* + * If start transfer is timing out then mark it as an error + * event since the controller is already in an unknown + * state. + */ + dbg_log_string("%s: error event seen\n", __func__); + dwc->err_evt_seen = true; + dwc3_notify_event(dwc, DWC3_CONTROLLER_ERROR_EVENT, 0); + dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_CLEAR_DB, 0); + } return ret; + } dwc->ep0_next_event = DWC3_EP0_COMPLETE; From 550d642faa85e19d64edbb58637558d836dea1ac Mon Sep 17 00:00:00 2001 From: Vijay Patil Date: Tue, 6 Jul 2021 21:21:02 +0530 Subject: [PATCH 57/90] icnss2: Add Null check before dereferencing variables Add Null check before dereferencing dev for set FW log mode, force wake request & force wake response. Add ERR_OR_NULL check for wpss load API gets called for wpss subsystem. Check for qdss memory segment length. Change-Id: Id4a43fa9ae332faa7f5741f338d985db8272d17a Signed-off-by: Vijay Patil --- drivers/soc/qcom/icnss2/main.c | 19 +++++++++++++++---- drivers/soc/qcom/icnss2/qmi.c | 15 +++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/drivers/soc/qcom/icnss2/main.c b/drivers/soc/qcom/icnss2/main.c index 49d0d8a74a0f..43b811115bf8 100644 --- a/drivers/soc/qcom/icnss2/main.c +++ b/drivers/soc/qcom/icnss2/main.c @@ -2713,11 +2713,18 @@ EXPORT_SYMBOL(icnss_get_mhi_state); int icnss_set_fw_log_mode(struct device *dev, uint8_t fw_log_mode) { int ret; - struct icnss_priv *priv = dev_get_drvdata(dev); + struct icnss_priv *priv; if (!dev) return -ENODEV; + priv = dev_get_drvdata(dev); + + if (!priv) { + icnss_pr_err("Platform driver not initialized\n"); + return -EINVAL; + } + if (test_bit(ICNSS_FW_DOWN, &penv->state) || !test_bit(ICNSS_FW_READY, &penv->state)) { icnss_pr_err("FW down, ignoring fw_log_mode state: 0x%lx\n", @@ -2737,11 +2744,13 @@ EXPORT_SYMBOL(icnss_set_fw_log_mode); int icnss_force_wake_request(struct device *dev) { - struct icnss_priv *priv = dev_get_drvdata(dev); + struct icnss_priv *priv; if (!dev) return -ENODEV; + priv = dev_get_drvdata(dev); + if (!priv) { icnss_pr_err("Platform driver not initialized\n"); return -EINVAL; @@ -2764,11 +2773,13 @@ EXPORT_SYMBOL(icnss_force_wake_request); int icnss_force_wake_release(struct device *dev) { - struct icnss_priv *priv = dev_get_drvdata(dev); + struct icnss_priv *priv; if (!dev) return -ENODEV; + priv = dev_get_drvdata(dev); + if (!priv) { icnss_pr_err("Platform driver not initialized\n"); return -EINVAL; @@ -3336,7 +3347,7 @@ static void icnss_wpss_load(struct work_struct *wpss_load_work) struct icnss_priv *priv = icnss_get_plat_priv(); priv->subsys = subsystem_get("wpss"); - if (IS_ERR(priv->subsys)) + if (IS_ERR_OR_NULL(priv->subsys)) icnss_pr_err("Failed to load wpss subsys"); } diff --git a/drivers/soc/qcom/icnss2/qmi.c b/drivers/soc/qcom/icnss2/qmi.c index b523a357ec95..d9b99c2c485a 100644 --- a/drivers/soc/qcom/icnss2/qmi.c +++ b/drivers/soc/qcom/icnss2/qmi.c @@ -2078,6 +2078,14 @@ int wlfw_qdss_trace_mem_info_send_sync(struct icnss_priv *priv) } req->mem_seg_len = priv->qdss_mem_seg_len; + + if (priv->qdss_mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG) { + icnss_pr_err("Invalid seg len %u\n", + priv->qdss_mem_seg_len); + ret = -EINVAL; + goto out; + } + for (i = 0; i < req->mem_seg_len; i++) { icnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n", qdss_mem[i].va, &qdss_mem[i].pa, @@ -2469,6 +2477,13 @@ static void wlfw_qdss_trace_req_mem_ind_cb(struct qmi_handle *qmi, } priv->qdss_mem_seg_len = ind_msg->mem_seg_len; + + if (priv->qdss_mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG) { + icnss_pr_err("Invalid seg len %u\n", + priv->qdss_mem_seg_len); + return; + } + for (i = 0; i < priv->qdss_mem_seg_len; i++) { icnss_pr_dbg("QDSS requests for memory, size: 0x%x, type: %u\n", ind_msg->mem_seg[i].size, From 7214dad55442c3ee4c425b6a14c757b3440b7dc9 Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Wed, 7 Jul 2021 12:18:57 +0530 Subject: [PATCH 58/90] sched: walt: resurrect walt_high_irqload tunable Re-introduce walt_high_irqload tunable to decide whether cpu is high irq loaded or not. This tunable takes 50 to 100 in pct, and scaled to sched_ravg_window. ex: echo 90 > /proc/sys/kernel/sched_cpu_high_irqload If 90, cpu's irq load is greater than 90% of window size, then cpu treated as high irq loaded. Change-Id: I018d424d5eea470a640bba3aabf5691ffc227f47 Signed-off-by: Lingutla Chandrasekhar --- include/linux/sched/sysctl.h | 5 +++++ kernel/sched/walt/walt.c | 25 ++++++++++++++++++++++++- kernel/sysctl.c | 11 +++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h index 0e83233722d7..82ed4137f37a 100644 --- a/include/linux/sched/sysctl.h +++ b/include/linux/sched/sysctl.h @@ -62,6 +62,7 @@ extern unsigned int sysctl_sched_prefer_spread; extern unsigned int sysctl_walt_rtg_cfs_boost_prio; extern unsigned int sysctl_walt_low_latency_task_threshold; extern unsigned int sysctl_sched_sync_hint_enable; +extern unsigned int sysctl_walt_cpu_high_irqload; extern int walt_proc_group_thresholds_handler(struct ctl_table *table, int write, @@ -87,6 +88,10 @@ extern int sched_boost_handler(struct ctl_table *table, int write, extern int sched_busy_hyst_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); + +extern int walt_high_irqload_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos); + #endif enum sched_tunable_scaling { diff --git a/kernel/sched/walt/walt.c b/kernel/sched/walt/walt.c index 99e8a0bf78ab..ddf1c0d98356 100644 --- a/kernel/sched/walt/walt.c +++ b/kernel/sched/walt/walt.c @@ -111,6 +111,8 @@ unsigned int sysctl_sched_capacity_margin_up[MAX_MARGIN_LEVELS] = { [0 ... MAX_MARGIN_LEVELS-1] = 1078}; /* ~5% margin */ unsigned int sysctl_sched_capacity_margin_down[MAX_MARGIN_LEVELS] = { [0 ... MAX_MARGIN_LEVELS-1] = 1205}; /* ~15% margin */ + +unsigned int sysctl_walt_cpu_high_irqload = 95; static unsigned int walt_cpu_high_irqload; unsigned int sysctl_sched_walt_rotate_big_tasks; @@ -3666,6 +3668,26 @@ int walt_proc_group_thresholds_handler(struct ctl_table *table, int write, return ret; } +int walt_high_irqload_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + int ret; + static DEFINE_MUTEX(mutex); + + mutex_lock(&mutex); + ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); + + if (ret || !write) { + mutex_unlock(&mutex); + return ret; + } + + walt_cpu_high_irqload = div64_u64((u64)sched_ravg_window * + sysctl_walt_cpu_high_irqload, (u64) 100); + mutex_unlock(&mutex); + return ret; +} + static void walt_init_window_dep(void) { walt_cpu_util_freq_divisor = @@ -3678,7 +3700,8 @@ static void walt_init_window_dep(void) sched_init_task_load_windows_scaled = scale_demand(sched_init_task_load_windows); - walt_cpu_high_irqload = div64_u64((u64)sched_ravg_window * 95, (u64) 100); + walt_cpu_high_irqload = mult_frac((u64)sched_ravg_window, + sysctl_walt_cpu_high_irqload, (u64) 100); } static void walt_init_once(void) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 5fa53e98b3eb..d85172a76f3f 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -149,6 +149,7 @@ static int __maybe_unused max_kswapd_threads = MAX_KSWAPD_THREADS; #ifdef CONFIG_SCHED_WALT static int neg_three = -3; static int three = 3; +static int fifty = 50; static int two_hundred_fifty_five = 255; const int sched_user_hint_max = 1000; static unsigned int ns_per_sec = NSEC_PER_SEC; @@ -594,6 +595,16 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "sched_cpu_high_irqload", + .data = &sysctl_walt_cpu_high_irqload, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = walt_high_irqload_handler, + .extra1 = &fifty, + .extra2 = &one_hundred, + }, + #endif { .procname = "sched_force_lb_enable", From 1e954f343da3b5c326db633c95ea19c3398a38fd Mon Sep 17 00:00:00 2001 From: Sumukh Hallymysore Ravindra Date: Wed, 7 Jul 2021 10:54:04 +0530 Subject: [PATCH 59/90] msm: synx: Fix accessing uninitialized variable Change fixes accessing possible uninitialized variable in an error log. Change-Id: Ibc72faddb7073c0408c2c822991b9835992dffaf Signed-off-by: Sumukh Hallymysore Ravindra --- drivers/media/platform/msm/synx/synx_util.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/synx/synx_util.c b/drivers/media/platform/msm/synx/synx_util.c index 7720141eb133..3739f81a13d3 100644 --- a/drivers/media/platform/msm/synx/synx_util.c +++ b/drivers/media/platform/msm/synx/synx_util.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "synx: " fmt @@ -158,8 +158,8 @@ void synx_util_object_destroy(struct synx_coredata *synx_obj) data = bind_desc->external_data; bind_ops = synx_util_get_bind_ops(type); if (!bind_ops) { - pr_err("bind ops fail id: %d, type: %u, err: %d\n", - sync_id, type, rc); + pr_err("bind ops fail id: %d, type: %u\n", + sync_id, type); continue; } From f094710be7f55e043a9ba628e738a1a3af52dc0d Mon Sep 17 00:00:00 2001 From: Ajay Prathi Date: Fri, 26 Jun 2020 16:38:28 +0530 Subject: [PATCH 60/90] msm: sps: Use iomem attribute for base address Clients may use ioremap api to obtain the bam base address. Add iomem attribute to the base address field in the public SPS structure to avoid type casts. Change-Id: Iba2ec1a9d84c3d57e2ce314ba9dc0b81644db2fb Signed-off-by: Ajay Prathi --- include/linux/msm-sps.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/msm-sps.h b/include/linux/msm-sps.h index 67247dcaa155..773a0be9302b 100644 --- a/include/linux/msm-sps.h +++ b/include/linux/msm-sps.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ /* Smart-Peripheral-Switch (SPS) API. */ @@ -485,7 +485,7 @@ struct sps_bam_props { * */ struct sps_mem_buffer { - void *base; + void __iomem *base; phys_addr_t phys_base; unsigned long iova; u32 size; From c76ce6f8489769c2f18a9c8b870a1cfccb71a514 Mon Sep 17 00:00:00 2001 From: Rama Krishna Phani A Date: Tue, 7 Jul 2020 16:02:33 +0530 Subject: [PATCH 61/90] 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 | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c index 3c37ffb421df..e99e9e3c2b66 100644 --- a/drivers/platform/msm/sps/bam.c +++ b/drivers/platform/msm/sps/bam.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2021, The Linux Foundation. All rights reserved. */ /* Bus-Access-Manager (BAM) Hardware manager. */ @@ -2140,13 +2140,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); @@ -2167,7 +2170,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 a155840f63e603580170272dcf3a69558b28f86f Mon Sep 17 00:00:00 2001 From: Madhuri Medasani Date: Mon, 28 Jun 2021 16:01:41 +0530 Subject: [PATCH 62/90] clk: qcom: debugcc: Add missing measure only clocks Add missing clocks having measure only support for BLAIR. Change-Id: I005d3d7853dbdaddcce82a844ee61341981eb501 Signed-off-by: Madhuri Medasani --- drivers/clk/qcom/debugcc-blair.c | 77 ++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/drivers/clk/qcom/debugcc-blair.c b/drivers/clk/qcom/debugcc-blair.c index 0217171d265f..9b21682f12d3 100644 --- a/drivers/clk/qcom/debugcc-blair.c +++ b/drivers/clk/qcom/debugcc-blair.c @@ -230,6 +230,7 @@ static const char *const gcc_debug_mux_parent_names[] = { "gcc_video_xo_clk", "gpu_cc_debug_mux", "mc_cc_debug_mux", + "measure_only_cnoc_clk", "measure_only_gcc_camera_ahb_clk", "measure_only_gcc_camera_xo_clk", "measure_only_gcc_cpuss_gnoc_clk", @@ -237,6 +238,12 @@ static const char *const gcc_debug_mux_parent_names[] = { "measure_only_gcc_disp_xo_clk", "measure_only_gcc_gpu_cfg_ahb_clk", "measure_only_gcc_video_ahb_clk", + "measure_only_hwkm_ahb_clk", + "measure_only_hwkm_km_core_clk", + "measure_only_ipa_2x_clk", + "measure_only_pka_ahb_clk", + "measure_only_pka_core_clk", + "measure_only_snoc_clk", }; static int gcc_debug_mux_sels[] = { @@ -350,6 +357,7 @@ static int gcc_debug_mux_sels[] = { 0x3F, /* gcc_video_xo_clk */ 0xFB, /* gpu_cc_debug_mux */ 0xAE, /* mc_cc_debug_mux */ + 0x1D, /* measure_only_cnoc_clk */ 0x38, /* measure_only_gcc_camera_ahb_clk */ 0x40, /* measure_only_gcc_camera_xo_clk */ 0xBA, /* measure_only_gcc_cpuss_gnoc_clk */ @@ -357,6 +365,12 @@ static int gcc_debug_mux_sels[] = { 0x41, /* measure_only_gcc_disp_xo_clk */ 0xF9, /* measure_only_gcc_gpu_cfg_ahb_clk */ 0x37, /* measure_only_gcc_video_ahb_clk */ + 0x166, /* measure_only_hwkm_ahb_clk */ + 0x167, /* measure_only_hwkm_km_core_clk */ + 0xD7, /* measure_only_ipa_2x_clk */ + 0x162, /* measure_only_pka_ahb_clk */ + 0x163, /* measure_only_pka_core_clk */ + 0x7, /* measure_only_snoc_clk */ }; static struct clk_debug_mux gcc_debug_mux = { @@ -450,6 +464,14 @@ static struct mux_regmap_names mux_list[] = { { .mux = &mc_cc_debug_mux, .regmap_name = "qcom,mccc" }, }; +static struct clk_dummy measure_only_cnoc_clk = { + .rrate = 1000, + .hw.init = &(struct clk_init_data){ + .name = "measure_only_cnoc_clk", + .ops = &clk_dummy_ops, + }, +}; + static struct clk_dummy measure_only_mccc_clk = { .rrate = 1000, .hw.init = &(struct clk_init_data){ @@ -530,6 +552,54 @@ static struct clk_dummy measure_only_gcc_video_ahb_clk = { }, }; +static struct clk_dummy measure_only_hwkm_ahb_clk = { + .rrate = 1000, + .hw.init = &(struct clk_init_data){ + .name = "measure_only_hwkm_ahb_clk", + .ops = &clk_dummy_ops, + }, +}; + +static struct clk_dummy measure_only_hwkm_km_core_clk = { + .rrate = 1000, + .hw.init = &(struct clk_init_data){ + .name = "measure_only_hwkm_km_core_clk", + .ops = &clk_dummy_ops, + }, +}; + +static struct clk_dummy measure_only_ipa_2x_clk = { + .rrate = 1000, + .hw.init = &(struct clk_init_data){ + .name = "measure_only_ipa_2x_clk", + .ops = &clk_dummy_ops, + }, +}; + +static struct clk_dummy measure_only_pka_ahb_clk = { + .rrate = 1000, + .hw.init = &(struct clk_init_data){ + .name = "measure_only_pka_ahb_clk", + .ops = &clk_dummy_ops, + }, +}; + +static struct clk_dummy measure_only_pka_core_clk = { + .rrate = 1000, + .hw.init = &(struct clk_init_data){ + .name = "measure_only_pka_core_clk", + .ops = &clk_dummy_ops, + }, +}; + +static struct clk_dummy measure_only_snoc_clk = { + .rrate = 1000, + .hw.init = &(struct clk_init_data){ + .name = "measure_only_snoc_clk", + .ops = &clk_dummy_ops, + }, +}; + static struct clk_dummy perfcl_clk = { .rrate = 1000, .hw.init = &(struct clk_init_data){ @@ -555,6 +625,7 @@ static struct clk_dummy l3_clk = { }; static struct clk_hw *debugcc_blair_hws[] = { + &measure_only_cnoc_clk.hw, &measure_only_disp_cc_sleep_clk.hw, &measure_only_disp_cc_xo_clk.hw, &measure_only_gcc_camera_ahb_clk.hw, @@ -564,7 +635,13 @@ static struct clk_hw *debugcc_blair_hws[] = { &measure_only_gcc_disp_xo_clk.hw, &measure_only_gcc_gpu_cfg_ahb_clk.hw, &measure_only_gcc_video_ahb_clk.hw, + &measure_only_ipa_2x_clk.hw, &measure_only_mccc_clk.hw, + &measure_only_snoc_clk.hw, + &measure_only_hwkm_km_core_clk.hw, + &measure_only_hwkm_ahb_clk.hw, + &measure_only_pka_core_clk.hw, + &measure_only_pka_ahb_clk.hw, &perfcl_clk.hw, &pwrcl_clk.hw, &l3_clk.hw, From bce19700f78a71c1f2bdcb5f9149ad556c288f50 Mon Sep 17 00:00:00 2001 From: Kiran Gunda Date: Fri, 25 Jun 2021 18:42:10 +0530 Subject: [PATCH 63/90] input: qcom-hv-haptics: Update the VMAX configuration The VMAX_STEP value is different for HV and MV haptics. Update the VMAX configuration accordingly. Change-Id: I5d0f00e9a07e76b01b16539d79897675ddd63117 Signed-off-by: Kiran Gunda --- drivers/input/misc/qcom-hv-haptics.c | 34 ++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/input/misc/qcom-hv-haptics.c b/drivers/input/misc/qcom-hv-haptics.c index 734af9d8adb9..74ca559c780c 100644 --- a/drivers/input/misc/qcom-hv-haptics.c +++ b/drivers/input/misc/qcom-hv-haptics.c @@ -71,8 +71,11 @@ #define DRV_SLEW_RATE_MASK GENMASK(2, 0) #define HAP_CFG_VMAX_REG 0x48 -#define VMAX_STEP_MV 50 +#define VMAX_HV_STEP_MV 50 +#define VMAX_MV_STEP_MV 32 #define MAX_VMAX_MV 11000 +#define MAX_HV_VMAX_MV 10000 +#define MAX_MV_VMAX_MV 6000 #define CLAMPED_VMAX_MV 5000 #define DEFAULT_VMAX_MV 5000 @@ -175,6 +178,9 @@ #define CAL_RC_CLK_MANUAL_VAL 2 /* These registers are only applicable for PM5100 */ +#define HAP_CFG_HW_CONFIG_REG 0x0D +#define HV_HAP_DRIVER_BIT BIT(1) + #define HAP_CFG_HPWR_INTF_CTL_REG 0x80 #define INTF_CTL_MASK GENMASK(1, 0) #define INTF_CTL_BOB 1 @@ -509,11 +515,13 @@ struct haptics_chip { u8 ptn_revision; u8 hpwr_intf_ctl; u16 hbst_revision; + u16 max_vmax_mv; enum pmic_type pmic_type; bool fifo_empty_irq_en; bool swr_slave_enabled; bool clamp_at_5v; bool hpwr_vreg_enabled; + bool is_hv_haptics; }; struct haptics_reg_info { @@ -1163,18 +1171,20 @@ static int haptics_get_closeloop_lra_period(struct haptics_chip *chip, static int haptics_set_vmax_mv(struct haptics_chip *chip, u32 vmax_mv) { int rc = 0; - u8 val; + u8 val, vmax_step; - if (vmax_mv > MAX_VMAX_MV) { + if (vmax_mv > chip->max_vmax_mv) { dev_err(chip->dev, "vmax (%d) exceed the max value: %d\n", - vmax_mv, MAX_VMAX_MV); + vmax_mv, chip->max_vmax_mv); return -EINVAL; } if (chip->clamp_at_5v && (vmax_mv > CLAMPED_VMAX_MV)) vmax_mv = CLAMPED_VMAX_MV; - val = vmax_mv / VMAX_STEP_MV; + vmax_step = (chip->is_hv_haptics) ? + VMAX_HV_STEP_MV : VMAX_MV_STEP_MV; + val = vmax_mv / vmax_step; rc = haptics_write(chip, chip->cfg_addr_base, HAP_CFG_VMAX_REG, &val, 1); if (rc < 0) @@ -2592,6 +2602,20 @@ static int haptics_hw_init(struct haptics_chip *chip) chip->clamp_at_5v = val[0] & CLAMP_5V_BIT; } + chip->is_hv_haptics = true; + chip->max_vmax_mv = MAX_VMAX_MV; + + if (chip->pmic_type == PM5100) { + rc = haptics_read(chip, chip->cfg_addr_base, + HAP_CFG_HW_CONFIG_REG, val, 1); + if (rc < 0) + return rc; + + chip->is_hv_haptics = val[0] & HV_HAP_DRIVER_BIT; + chip->max_vmax_mv = (chip->is_hv_haptics) ? + MAX_HV_VMAX_MV : MAX_MV_VMAX_MV; + } + /* Config VMAX */ rc = haptics_set_vmax_mv(chip, config->vmax_mv); if (rc < 0) From dcb104f1312e4dcb82f1fb5f85c95ed70840f024 Mon Sep 17 00:00:00 2001 From: lijuang Date: Wed, 30 Jun 2021 19:45:11 +0800 Subject: [PATCH 64/90] soc: qcom: Correct the modem data for wdog bite handler Correct the modem data for wdog bite handler, otherwise it will access a invalid subsys. Change-Id: Iedd7b85597fa95d283d3a7b9bdd59c8a7c765792 Signed-off-by: lijuang --- drivers/soc/qcom/pil-q6v5-mss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/pil-q6v5-mss.c b/drivers/soc/qcom/pil-q6v5-mss.c index 91f680c64450..708ceb3274bd 100644 --- a/drivers/soc/qcom/pil-q6v5-mss.c +++ b/drivers/soc/qcom/pil-q6v5-mss.c @@ -260,7 +260,7 @@ static int modem_ramdump(int enable, const struct subsys_desc *subsys) static irqreturn_t modem_wdog_bite_intr_handler(int irq, void *dev_data) { - struct modem_data *drv = subsys_to_drv(dev_data); + struct modem_data *drv = dev_data; if (drv->ignore_errors) return IRQ_HANDLED; From 65e208cf8947171abf70e09ac08cb0e749f9e296 Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Tue, 22 Jun 2021 18:45:43 +0530 Subject: [PATCH 65/90] msm: kgsl: Retry process private open in a special failure case Currently, process private open/kgsl_open fails in case same pid previous process private refcount is zero but destroy didn't complete yet. In this failure case, as we are sure that destroy is triggered and just pending to finish, retry process private open again after some delay to ensure process private open is successful. Change-Id: I7cd8a2b7d64d9472121ffa8633d0621923f5ec89 Signed-off-by: Deepak Kumar --- drivers/gpu/msm/kgsl.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 120fcdc5950a..f68815f3cf1a 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -933,9 +934,15 @@ static struct kgsl_process_private *kgsl_process_private_new( /* Search in the process list */ list_for_each_entry(private, &kgsl_driver.process_list, list) { if (private->pid == cur_pid) { - if (!kgsl_process_private_get(private)) { - private = ERR_PTR(-EINVAL); - } + if (!kgsl_process_private_get(private)) + /* + * This will happen only if refcount is zero + * i.e. destroy is triggered but didn't complete + * yet. Return -EEXIST to indicate caller that + * destroy is pending to allow caller to take + * appropriate action. + */ + private = ERR_PTR(-EEXIST); /* * We need to hold only one reference to the PID for * each process struct to avoid overflowing the @@ -1043,8 +1050,7 @@ static void kgsl_process_private_close(struct kgsl_device_private *dev_priv, kgsl_process_private_put(private); } - -static struct kgsl_process_private *kgsl_process_private_open( +static struct kgsl_process_private *_process_private_open( struct kgsl_device *device) { struct kgsl_process_private *private; @@ -1062,6 +1068,27 @@ done: return private; } +static struct kgsl_process_private *kgsl_process_private_open( + struct kgsl_device *device) +{ + struct kgsl_process_private *private; + int i; + + private = _process_private_open(device); + + /* + * If we get error and error is -EEXIST that means previous process + * private destroy is triggered but didn't complete. Retry creating + * process private after sometime to allow previous destroy to complete. + */ + for (i = 0; (PTR_ERR_OR_ZERO(private) == -EEXIST) && (i < 5); i++) { + usleep_range(10, 100); + private = _process_private_open(device); + } + + return private; +} + int kgsl_gpu_frame_count(pid_t pid, u64 *frame_count) { struct kgsl_process_private *p; From fd141c239846197b65c36bed66fa106608cc4df1 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Thu, 8 Jul 2021 09:12:22 +0530 Subject: [PATCH 66/90] clk: qcom: clk-alpha-pll: Update the steps to slew the Lucid PLL When PLL HW_UPDATE_LOGIC_BYPASS bit is not set then PLL can be updated dynamically by setting the PLL_UPDATE bit in mode register and hardware would clear the PLL_UPDATE automatically when PLL_ACK_LATCH is asserted. Change-Id: I1c568c9fdd37a554d71fc5c3d840a71e983baf60 Signed-off-by: Taniya Das --- drivers/clk/qcom/clk-alpha-pll.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index e40f344609f8..391761765f3b 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -2895,7 +2895,12 @@ static int alpha_pll_lucid_set_rate(struct clk_hw *hw, unsigned long rate, /* Wait for 2 reference cycles before checking the ACK bit. */ udelay(1); regmap_read(pll->clkr.regmap, PLL_MODE(pll), ®val); - if (!(regval & ALPHA_PLL_ACK_LATCH)) { + if (!(regval & PLL_UPDATE_BYPASS)) { + ret = wait_for_pll_update(pll); + if (ret) + WARN_CLK(&pll->clkr.hw, 1, "PLL Update clear failed\n"); + return ret; + } else if (!(regval & ALPHA_PLL_ACK_LATCH)) { WARN_CLK(&pll->clkr.hw, 1, "PLL latch failed. Output may be unstable!\n"); return -EINVAL; From e3d4ff77a70818065b0c06fe987403b09e1e0ad3 Mon Sep 17 00:00:00 2001 From: Rohith Kollalsi Date: Fri, 28 May 2021 11:03:30 +0530 Subject: [PATCH 67/90] usb: f_cdev: USB remote wake up feature implementation for DUN Implement usb remote wake up feature for dun on sdx12. For super speed this feature supports wake up of a particular function from suspend, where as for high speed, remote wakeup doesn't support wakeup of a particular function from suspend, but entire usb bus needs to wakeup. When usb_func_wakeup in composite driver fails because it needs to wake usb bus before function wakeup is triggered, -EAGAIN is returned which cannot be considered as a function wakeup failure. Hence add proper handling in function driver for EAGAIN return case. Change-Id: I15c18a4a7203e82c74ad1b4905c08eff91d91b4f Signed-off-by: Rohith Kollalsi --- drivers/usb/gadget/function/f_cdev.c | 155 +++++++++++++++++++++++---- 1 file changed, 133 insertions(+), 22 deletions(-) diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c index 720e21950e44..29bc22bb2ef5 100644 --- a/drivers/usb/gadget/function/f_cdev.c +++ b/drivers/usb/gadget/function/f_cdev.c @@ -38,6 +38,7 @@ #include #include #include +#include #define DEVICE_NAME "at_usb" #define MODULE_NAME "msm_usb_bridge" @@ -99,6 +100,7 @@ struct f_cdev { struct list_head read_pool; struct list_head read_queued; struct list_head write_pool; + struct list_head write_pending; /* current active USB RX request */ struct usb_request *current_rx_req; @@ -127,6 +129,8 @@ struct f_cdev { struct workqueue_struct *fcdev_wq; bool is_connected; bool port_open; + bool is_suspended; + bool pending_state_notify; unsigned long nbytes_from_host; unsigned long nbytes_to_host; @@ -536,19 +540,56 @@ static int usb_cser_set_alt(struct usb_function *f, unsigned int intf, return rc; } +static int port_notify_serial_state(struct cserial *cser); + static void usb_cser_resume(struct usb_function *f) { struct f_cdev *port = func_to_port(f); - struct usb_composite_dev *cdev = f->config->cdev; + unsigned long flags; + int ret; - if (cdev->gadget->speed >= USB_SPEED_SUPER && port->func_is_suspended) { - if (port->func_wakeup_pending) { - dev_dbg(&cdev->gadget->dev, - "func_wakeup for port:%s\n", port->name); - usb_func_wakeup(&port->port_usb.func); - port->func_wakeup_pending = false; + struct usb_request *req, *t; + struct usb_ep *in; + + pr_debug("%s\n", __func__); + port->is_suspended = false; + + /* process pending state notifications */ + if (port->pending_state_notify) + port_notify_serial_state(&port->port_usb); + + spin_lock_irqsave(&port->port_lock, flags); + in = port->port_usb.in; + /* process any pending requests */ + list_for_each_entry_safe(req, t, &port->write_pending, list) { + list_del_init(&req->list); + if (!port->is_connected) { + pr_err("%s: cable is disconnected.\n", __func__); + list_add(&req->list, &port->write_pool); + spin_unlock_irqrestore(&port->port_lock, flags); + return; + } + + spin_unlock_irqrestore(&port->port_lock, flags); + ret = usb_ep_queue(in, req, GFP_KERNEL); + spin_lock_irqsave(&port->port_lock, flags); + if (ret) { + pr_err("EP QUEUE failed:%d\n", ret); + list_add(&req->list, &port->write_pool); + } else { + port->nbytes_from_port_bridge += req->length; } } + + spin_unlock_irqrestore(&port->port_lock, flags); +} + +static void usb_cser_suspend(struct usb_function *f) +{ + struct f_cdev *port = func_to_port(f); + + pr_debug("%s\n", __func__); + port->is_suspended = true; } static int usb_cser_func_suspend(struct usb_function *f, u8 options) @@ -557,11 +598,31 @@ static int usb_cser_func_suspend(struct usb_function *f, u8 options) port->func_wakeup_allowed = !!(options & (USB_INTRF_FUNC_SUSPEND_RW >> 8)); - port->func_is_suspended = options & (USB_INTRF_FUNC_SUSPEND_LP >> 8); + if (options & (USB_INTRF_FUNC_SUSPEND_LP >> 8)) { + if (!port->func_is_suspended) { + usb_cser_suspend(f); + port->func_is_suspended = true; + } else { + if (port->func_is_suspended) { + port->func_is_suspended = false; + usb_cser_resume(f); + } + } + } return 0; } +static int usb_cser_get_remote_wakeup_capable(struct usb_function *f, + struct usb_gadget *g) +{ + struct f_cdev *port = func_to_port(f); + + return ((g->speed >= USB_SPEED_SUPER && port->func_wakeup_allowed) || + (g->speed < USB_SPEED_SUPER && usb_get_remote_wakeup_status(g))); + +} + static int usb_cser_get_status(struct usb_function *f) { #ifdef CONFIG_USB_FUNC_WAKEUP_SUPPORTED @@ -643,7 +704,16 @@ static int port_notify_serial_state(struct cserial *cser) unsigned long flags; struct usb_composite_dev *cdev = port->port_usb.func.config->cdev; + if (port->is_suspended) { + port->pending_state_notify = true; + pr_debug("%s: port is suspended\n", __func__); + return 0; + } + spin_lock_irqsave(&port->port_lock, flags); + if (port->pending_state_notify) + port->pending_state_notify = false; + if (!port->port_usb.pending) { port->port_usb.pending = true; spin_unlock_irqrestore(&port->port_lock, flags); @@ -1133,6 +1203,7 @@ static void usb_cser_stop_io(struct f_cdev *port) usb_cser_free_requests(out, &port->read_queued); usb_cser_free_requests(out, &port->read_pool); usb_cser_free_requests(in, &port->write_pool); + usb_cser_free_requests(in, &port->write_pending); spin_unlock_irqrestore(&port->port_lock, flags); } @@ -1298,6 +1369,9 @@ ssize_t f_cdev_write(struct file *file, struct list_head *pool; unsigned int xfer_size; struct usb_ep *in; + struct cserial *cser; + struct usb_function *func; + struct usb_gadget *gadget; port = file->private_data; if (!port) { @@ -1305,6 +1379,9 @@ ssize_t f_cdev_write(struct file *file, return -EINVAL; } + cser = &port->port_usb; + func = &cser->func; + spin_lock_irqsave(&port->port_lock, flags); pr_debug("write on port(%s)(%pK)\n", port->name, port); @@ -1336,9 +1413,40 @@ ssize_t f_cdev_write(struct file *file, if (ret) { pr_err("copy_from_user failed: err %d\n", ret); ret = -EFAULT; + goto err_exit; + } + + req->length = xfer_size; + req->zero = 1; + if (port->is_suspended) { + gadget = cser->func.config->cdev->gadget; + if (!usb_cser_get_remote_wakeup_capable(func, gadget)) { + pr_debug("%s remote-wakeup not capable\n", + __func__); + ret = -EOPNOTSUPP; + goto err_exit; + } + + spin_lock_irqsave(&port->port_lock, flags); + list_add(&req->list, &port->write_pending); + spin_unlock_irqrestore(&port->port_lock, flags); + + if (gadget->speed >= USB_SPEED_SUPER + && port->func_is_suspended) + ret = usb_func_wakeup(func); + else + ret = usb_gadget_wakeup(gadget); + + if (ret < 0 && ret != -EACCES && ret != -EAGAIN) { + pr_err("Remote wakeup failed:%d\n", ret); + spin_lock_irqsave(&port->port_lock, flags); + req = list_first_entry(&port->write_pending, + struct usb_request, list); + list_del(&req->list); + spin_unlock_irqrestore(&port->port_lock, flags); + goto err_exit; + } } else { - req->length = xfer_size; - req->zero = 1; ret = usb_ep_queue(in, req, GFP_KERNEL); if (ret) { pr_err("EP QUEUE failed:%d\n", ret); @@ -1350,19 +1458,18 @@ ssize_t f_cdev_write(struct file *file, spin_unlock_irqrestore(&port->port_lock, flags); } -err_exit: - if (ret) { - spin_lock_irqsave(&port->port_lock, flags); - /* USB cable is connected, add it back otherwise free request */ - if (port->is_connected) - list_add(&req->list, &port->write_pool); - else - usb_cser_free_req(in, req); - spin_unlock_irqrestore(&port->port_lock, flags); - return ret; - } - return xfer_size; + +err_exit: + spin_lock_irqsave(&port->port_lock, flags); + /* USB cable is connected, add it back otherwise free request */ + if (port->is_connected) + list_add(&req->list, &port->write_pool); + else + usb_cser_free_req(in, req); + spin_unlock_irqrestore(&port->port_lock, flags); + + return ret; } static unsigned int f_cdev_poll(struct file *file, poll_table *wait) @@ -1598,6 +1705,8 @@ int usb_cser_connect(struct f_cdev *port) cser->pending = false; cser->q_again = false; port->is_connected = true; + port->pending_state_notify = false; + port->is_suspended = false; spin_unlock_irqrestore(&port->port_lock, flags); usb_cser_start_io(port); @@ -1799,6 +1908,7 @@ static struct f_cdev *f_cdev_alloc(char *func_name, int portno) INIT_LIST_HEAD(&port->read_pool); INIT_LIST_HEAD(&port->read_queued); INIT_LIST_HEAD(&port->write_pool); + INIT_LIST_HEAD(&port->write_pending); port->fcdev_wq = create_singlethread_workqueue(port->name); if (!port->fcdev_wq) { @@ -2089,6 +2199,7 @@ static struct usb_function *cser_alloc(struct usb_function_instance *fi) port->port_usb.func.setup = usb_cser_setup; port->port_usb.func.func_suspend = usb_cser_func_suspend; port->port_usb.func.resume = usb_cser_resume; + port->port_usb.func.suspend = usb_cser_suspend; port->port_usb.func.get_status = usb_cser_get_status; port->port_usb.func.free_func = usb_cser_free_func; From 175aff99f1816ac3e0a386b0a154da314c45f83c Mon Sep 17 00:00:00 2001 From: Vaibhav Agrawal Date: Wed, 30 Jun 2021 11:21:25 +0530 Subject: [PATCH 68/90] soc: qcom: Return correct error code when program_key fails fails When we call crypto_qti_program_key to program the key, and it fails due to trustzone busy issue, we try to call invalidate key method just after that, and in the process, overwrite the error code returned by the program key failure. Fix this by handling the errors from both program key and invalidate key separately, and return the program key error code to caller. Test: Verified device boot up and reboot. Change-Id: Iaff0844f68b4886c23e1840d7e0e4a404d38fc96 Signed-off-by: Vaibhav Agrawal --- drivers/soc/qcom/crypto-qti-common.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/soc/qcom/crypto-qti-common.c b/drivers/soc/qcom/crypto-qti-common.c index c86ca588d1d2..34a1fe16e3bd 100644 --- a/drivers/soc/qcom/crypto-qti-common.c +++ b/drivers/soc/qcom/crypto-qti-common.c @@ -412,7 +412,7 @@ int crypto_qti_keyslot_program(void *priv_data, unsigned int slot, u8 data_unit_mask, int capid) { - int err = 0; + int err1 = 0, err2 = 0; struct crypto_vops_qti_entry *ice_entry; ice_entry = (struct crypto_vops_qti_entry *) priv_data; @@ -421,19 +421,19 @@ int crypto_qti_keyslot_program(void *priv_data, return -EINVAL; } - err = crypto_qti_program_key(ice_entry, key, slot, + err1 = crypto_qti_program_key(ice_entry, key, slot, data_unit_mask, capid); - if (err) { - pr_err("%s: program key failed with error %d\n", __func__, err); - err = crypto_qti_invalidate_key(ice_entry, slot); - if (err) { + if (err1) { + pr_err("%s: program key failed with error %d\n", + __func__, err1); + err2 = crypto_qti_invalidate_key(ice_entry, slot); + if (err2) { pr_err("%s: invalidate key failed with error %d\n", - __func__, err); - return err; + __func__, err2); } } - return err; + return err1; } EXPORT_SYMBOL(crypto_qti_keyslot_program); From c4e2bcf66fb286fbe37c4ea8f324ec44452de4d2 Mon Sep 17 00:00:00 2001 From: Hui Liu Date: Mon, 17 May 2021 18:35:03 +0800 Subject: [PATCH 69/90] power: qcom: qbg: add jeita/step-chg parameters for QBG algorithm Parse JEITA and step charging settings from battery profile and send them to userspace algorithm for TTF calculation. Change-Id: I6250b34ecdca0d94d672f5859843cc4c54923412 Signed-off-by: Hui Liu --- .../power/supply/qcom/qbg-battery-profile.h | 6 + drivers/power/supply/qcom/qbg-core.h | 2 + drivers/power/supply/qcom/qti-qbg.c | 229 ++++++++++++++++++ include/uapi/linux/qbg.h | 27 +++ 4 files changed, 264 insertions(+) diff --git a/drivers/power/supply/qcom/qbg-battery-profile.h b/drivers/power/supply/qcom/qbg-battery-profile.h index c28c6d5864ac..940dd7d89622 100644 --- a/drivers/power/supply/qcom/qbg-battery-profile.h +++ b/drivers/power/supply/qcom/qbg-battery-profile.h @@ -12,6 +12,12 @@ || ((left) <= (right) && (left) <= (value) \ && (value) <= (right))) +enum ttf_calc_mode { + TTF_MODE_VBAT_STEP_CHG = 0, + TTF_MODE_OCV_STEP_CHG, + TTF_MODE_SOC_STEP_CHG, +}; + struct battery_data_table0 { int soc_length; int ocv_length; diff --git a/drivers/power/supply/qcom/qbg-core.h b/drivers/power/supply/qcom/qbg-core.h index 2690377d3ff2..7c0318500c75 100644 --- a/drivers/power/supply/qcom/qbg-core.h +++ b/drivers/power/supply/qcom/qbg-core.h @@ -84,6 +84,7 @@ enum QBG_ACCUM_INTERVAL_TYPE { * @kdata: QBG Kernel space data structure * @udata: QBG user space data structure * @battery: Pointer to QBG battery data structure + * @step_chg_jeita_params: Jeita step charge parameters structure * @fifo_lock: Lock for reading FIFO data * @data_lock: Lock for reading kdata from QBG char device * @batt_id_chan: IIO channel to read battery ID @@ -154,6 +155,7 @@ struct qti_qbg { struct qbg_kernel_data kdata; struct qbg_user_data udata; struct qbg_battery_data *battery; + struct qbg_step_chg_jeita_params *step_chg_jeita_params; struct mutex fifo_lock; struct mutex data_lock; struct iio_channel *batt_id_chan; diff --git a/drivers/power/supply/qcom/qti-qbg.c b/drivers/power/supply/qcom/qti-qbg.c index f06114c92b8d..bdec442c2ae6 100644 --- a/drivers/power/supply/qcom/qti-qbg.c +++ b/drivers/power/supply/qcom/qti-qbg.c @@ -99,6 +99,12 @@ #define OCV_BOOST_MAX_UV 5600000 #define OCV_BOOST_STEP_UV 100000 +#define BATT_HOT_DECIDEGREE_MAX 600 + +#define MILLI_TO_10NANO 100000 +#define MICRO_TO_10NANO 100 +#define MILLI_TO_MICRO 1000 + static int qbg_debug_mask; static const unsigned int qbg_accum_interval[8] = { @@ -706,6 +712,211 @@ static int qbg_notifier_cb(struct notifier_block *nb, return NOTIFY_OK; } +static int qbg_read_range_data_from_node(struct device_node *node, + const char *prop_str, struct ranges *ranges, + int max_threshold, u32 max_value) +{ + int rc = 0, i, length, per_tuple_length, tuples; + + if (!node || !prop_str || !ranges) { + pr_err("Invalid parameters passed\n"); + return -EINVAL; + } + + rc = of_property_count_elems_of_size(node, prop_str, sizeof(u32)); + if (rc < 0) { + pr_err("Count %s failed, rc=%d\n", prop_str, rc); + return rc; + } + + length = rc; + per_tuple_length = sizeof(struct range_data) / sizeof(u32); + if (length % per_tuple_length) { + pr_err("%s length (%d) should be multiple of %d\n", + prop_str, length, per_tuple_length); + return -EINVAL; + } + + tuples = length / per_tuple_length; + if (tuples > QBG_MAX_STEP_CHG_ENTRIES) { + pr_err("too many entries(%d), only %d allowed\n", + tuples, QBG_MAX_STEP_CHG_ENTRIES); + return -EINVAL; + } + + rc = of_property_read_u32_array(node, prop_str, (u32 *)ranges->data, length); + if (rc < 0) { + pr_err("Read %s failed, rc=%d\n", prop_str, rc); + return rc; + } + + for (i = 0; i < tuples; i++) { + if (ranges->data[i].low_threshold > + ranges->data[i].high_threshold) { + pr_err("%s thresholds should be in ascendant ranges data\n", + prop_str); + rc = -EINVAL; + goto clean; + } + + if (i != 0) { + if (ranges->data[i - 1].high_threshold > + ranges->data[i].low_threshold) { + pr_err("%s thresholds should be in ascendant ranges data\n", + prop_str); + rc = -EINVAL; + goto clean; + } + } + + if (ranges->data[i].low_threshold > max_threshold) + ranges->data[i].low_threshold = max_threshold; + if (ranges->data[i].high_threshold > max_threshold) + ranges->data[i].high_threshold = max_threshold; + if (ranges->data[i].value > max_value) + ranges->data[i].value = max_value; + } + + ranges->range_count = tuples; + ranges->valid = true; + return rc; +clean: + memset(ranges, 0, tuples * sizeof(struct range_data)); + return rc; +} + +#define QBG_DEFAULT_JEITA_FULL_FV_10NV 420000000 +#define QBG_DEFAULT_BATTERY_BETA 4250 +#define QBG_DEFAULT_BATTERY_THERM_KOHM 100 +#define QBG_DEFAULT_JEITA_WARM_ADC_DATA 0x25e3 /* WARM = 40 DegC */ +#define QBG_DEFAULT_JEITA_COOL_ADC_DATA 0x5314 /* COOL = 5 DegC */ +static int parse_step_chg_jeita_params(struct qti_qbg *chip, struct device_node *profile_node) +{ + struct qbg_step_chg_jeita_params *step_chg_jeita; + bool soc_based_step_chg = false; + bool ocv_based_step_chg = false; + int rc; + int i = 0; + u32 temp[2]; + bool jeita_thresh_valid = true; + + step_chg_jeita = devm_kzalloc(chip->dev, sizeof(*step_chg_jeita), + GFP_KERNEL); + if (!step_chg_jeita) + return -ENOMEM; + + /* choose the lower of the two soft threaholds as the jeita-full-fv */ + step_chg_jeita->jeita_full_fv_10nv = QBG_DEFAULT_JEITA_FULL_FV_10NV; + rc = of_property_read_u32_array(profile_node, "qcom,jeita-soft-fv-uv", + temp, 2); + if (!rc) + step_chg_jeita->jeita_full_fv_10nv = min(temp[0], temp[1]) * MICRO_TO_10NANO; + else + pr_debug("Failed to read jeita full fv from battery profile, rc=%d\n", rc); + + step_chg_jeita->jeita_full_iterm_10na = chip->iterm_ma * MILLI_TO_10NANO; + + soc_based_step_chg = of_property_read_bool(profile_node, "qcom,soc-based-step-chg"); + ocv_based_step_chg = of_property_read_bool(profile_node, "qcom,ocv-based-step-chg"); + if (soc_based_step_chg) + step_chg_jeita->ttf_calc_mode = TTF_MODE_SOC_STEP_CHG; + else if (ocv_based_step_chg) + step_chg_jeita->ttf_calc_mode = TTF_MODE_OCV_STEP_CHG; + + step_chg_jeita->battery_beta = QBG_DEFAULT_BATTERY_BETA; + rc = of_property_read_u32(profile_node, "qcom,battery-beta", + &step_chg_jeita->battery_beta); + if (rc < 0) + pr_debug("Failed to read battery beta form battery profile, rc=%d\n", rc); + + step_chg_jeita->battery_therm_kohm = QBG_DEFAULT_BATTERY_THERM_KOHM; + rc = of_property_read_u32(profile_node, "qcom,battery-therm-kohm", + &step_chg_jeita->battery_therm_kohm); + if (rc < 0) + pr_debug("Failed to read battery therm from battery profile, rc=%d\n", rc); + + step_chg_jeita->jeita_cool_adc_value = QBG_DEFAULT_JEITA_COOL_ADC_DATA; + step_chg_jeita->jeita_warm_adc_value = QBG_DEFAULT_JEITA_WARM_ADC_DATA; + rc = of_property_read_u32_array(profile_node, "qcom,jeita-soft-thresholds", + temp, 2); + if (!rc) { + step_chg_jeita->jeita_cool_adc_value = temp[0]; + step_chg_jeita->jeita_warm_adc_value = temp[1]; + } else { + jeita_thresh_valid = false; + pr_debug("Failed to read jeita cool and warm value from battery profile, rc=%d\n", + rc); + } + + rc = qbg_read_range_data_from_node(profile_node, + "qcom,jeita-fcc-ranges", + &step_chg_jeita->jeita_fcc_cfg, + BATT_HOT_DECIDEGREE_MAX, + chip->fastchg_curr_ma * MILLI_TO_MICRO); + if (rc < 0) + pr_debug("Failed to read qcom,jeita-fcc-ranges from battery profile, rc=%d\n", + rc); + + rc = qbg_read_range_data_from_node(profile_node, + "qcom,jeita-fv-ranges", + &step_chg_jeita->jeita_fv_cfg, + BATT_HOT_DECIDEGREE_MAX, chip->float_volt_uv); + if (rc < 0) + pr_debug("Failed to read qcom,jeita-fv-ranges from battery profile, rc=%d\n", + rc); + + if ((step_chg_jeita->jeita_fcc_cfg.valid != step_chg_jeita->jeita_fv_cfg.valid) + || (jeita_thresh_valid != step_chg_jeita->jeita_fcc_cfg.valid)) { + pr_err("battery JEITA configuration is not valid\n"); + return -EINVAL; + } + + rc = qbg_read_range_data_from_node(profile_node, + "qcom,step-chg-ranges", + &step_chg_jeita->step_fcc_cfg, + soc_based_step_chg ? 100 : chip->float_volt_uv, + chip->fastchg_curr_ma * MILLI_TO_MICRO); + if (rc < 0) + pr_debug("Failed to read qcom,step-chg-ranges from battery profile, rc=%d\n", + rc); + + qbg_dbg(chip, QBG_DEBUG_PROFILE, "jeita_full_fv = %dnv, jeita_full_iterm = %dna, jeita_warm_adc = 0x%x, jeita_cool_adc = 0x%x, battery_beta = %d, battery_therm = %dkohm\n", + step_chg_jeita->jeita_full_fv_10nv, + step_chg_jeita->jeita_full_iterm_10na, + step_chg_jeita->jeita_warm_adc_value, + step_chg_jeita->jeita_cool_adc_value, + step_chg_jeita->battery_beta, + step_chg_jeita->battery_therm_kohm); + + pr_debug("step-chg-ranges:\n"); + for (i = 0; i < step_chg_jeita->step_fcc_cfg.range_count; i++) { + pr_debug("%d %d %d\n", + step_chg_jeita->step_fcc_cfg.data[i].low_threshold, + step_chg_jeita->step_fcc_cfg.data[i].high_threshold, + step_chg_jeita->step_fcc_cfg.data[i].value); + } + + pr_debug("jeita-fcc-ranges:\n"); + for (i = 0; i < step_chg_jeita->jeita_fcc_cfg.range_count; i++) { + pr_debug("%d %d %d\n", + step_chg_jeita->jeita_fcc_cfg.data[i].low_threshold, + step_chg_jeita->jeita_fcc_cfg.data[i].high_threshold, + step_chg_jeita->jeita_fcc_cfg.data[i].value); + } + + pr_debug("jeita-fv-ranges:\n"); + for (i = 0; i < step_chg_jeita->jeita_fv_cfg.range_count; i++) { + pr_debug("%d %d %d\n", + step_chg_jeita->jeita_fv_cfg.data[i].low_threshold, + step_chg_jeita->jeita_fv_cfg.data[i].high_threshold, + step_chg_jeita->jeita_fv_cfg.data[i].value); + } + + chip->step_chg_jeita_params = step_chg_jeita; + + return 0; +} + static int qbg_load_battery_profile(struct qti_qbg *chip) { struct device_node *node = chip->dev->of_node; @@ -771,6 +982,7 @@ static int qbg_load_battery_profile(struct qti_qbg *chip) } chip->nominal_capacity = temp[0]; + rc = parse_step_chg_jeita_params(chip, profile_node); out: of_node_put(chip->batt_node); return rc; @@ -1448,6 +1660,7 @@ static long qbg_device_ioctl(struct file *file, unsigned int cmd, struct qbg_config __user *config_user; struct qbg_config config; struct qbg_essential_params __user *params_user; + struct qbg_step_chg_jeita_params __user *step_chg_params_user; unsigned long rtc_sec; int rc = 0, i; @@ -1499,6 +1712,7 @@ static long qbg_device_ioctl(struct file *file, unsigned int cmd, config.pon_tbat = chip->pon_tbat; config.pon_soc = chip->pon_soc; config.float_volt_uv = chip->float_volt_uv; + config.fastchg_curr_ma = chip->fastchg_curr_ma; config.vbat_cutoff_mv = chip->vbat_cutoff_mv; config.ibat_cutoff_ma = chip->ibat_cutoff_ma; config.vph_min_mv = chip->vph_min_mv; @@ -1559,6 +1773,21 @@ static long qbg_device_ioctl(struct file *file, unsigned int cmd, qbg_dbg(chip, QBG_DEBUG_SDAM, "Essential params written, time:%lu secs\n", rtc_sec); + break; + case QBGIOCXSTEPCHGCFG: + step_chg_params_user = (struct qbg_step_chg_jeita_params __user *)arg; + + if (copy_to_user(step_chg_params_user, (void *)chip->step_chg_jeita_params, + sizeof(struct qbg_step_chg_jeita_params))) { + pr_err("Failed to copy QBG step and jeita charge params to user\n"); + return -EFAULT; + } + qbg_dbg(chip, QBG_DEBUG_DEVICE, "QBGIOCXSTEPCHGCFG: jeita_full_fv_10nv:%d jeita_warm_adc_value:0x%x jeita_cool_adc_value:0x%x ttf_calc_mode:%u\n", + chip->step_chg_jeita_params->jeita_full_fv_10nv, + chip->step_chg_jeita_params->jeita_warm_adc_value, + chip->step_chg_jeita_params->jeita_cool_adc_value, + chip->step_chg_jeita_params->ttf_calc_mode); + break; default: pr_err("IOCTL %d not supported\n", cmd); diff --git a/include/uapi/linux/qbg.h b/include/uapi/linux/qbg.h index 4ca6a65ee62a..48960a505413 100644 --- a/include/uapi/linux/qbg.h +++ b/include/uapi/linux/qbg.h @@ -7,6 +7,7 @@ #define __QBG_H__ #define MAX_FIFO_COUNT 36 +#define QBG_MAX_STEP_CHG_ENTRIES 6 enum QBG_STATE { QBG_LPM, @@ -143,9 +144,35 @@ struct qbg_user_data { struct qbg_param param[QBG_PARAM_MAX]; } __attribute__ ((__packed__)); +struct range_data { + int low_threshold; + int high_threshold; + unsigned int value; +} __attribute__ ((__packed__)); + +struct ranges { + struct range_data data[QBG_MAX_STEP_CHG_ENTRIES]; + unsigned char range_count; + _Bool valid; +} __attribute__((__packed__)); + +struct qbg_step_chg_jeita_params { + int jeita_full_fv_10nv; + int jeita_full_iterm_10na; + int jeita_warm_adc_value; + int jeita_cool_adc_value; + int battery_beta; + int battery_therm_kohm; + struct ranges step_fcc_cfg; + struct ranges jeita_fcc_cfg; + struct ranges jeita_fv_cfg; + unsigned char ttf_calc_mode; +} __attribute__ ((__packed__)); + /* IOCTLs to read & write QBG config and essential params */ #define QBGIOCXCFG _IOR('B', 0x01, struct qbg_config) #define QBGIOCXEPR _IOR('B', 0x02, struct qbg_essential_params) #define QBGIOCXEPW _IOWR('B', 0x03, struct qbg_essential_params) +#define QBGIOCXSTEPCHGCFG _IOWR('B', 0x04, struct qbg_step_chg_jeita_params) #endif From d09360cb9940baf83d8bbfe9e167b9e7d919d17f Mon Sep 17 00:00:00 2001 From: Kiran Gunda Date: Fri, 25 Jun 2021 12:12:56 +0530 Subject: [PATCH 70/90] input: qcom-hv-haptics: Toggle RC_CAL_EN mode only for PM8350B The incorrect first cycle vibration issue is applicable only for PM8350B PMIC. Hence, make the SW W/A to toggle the CAL_EN mode from disabled to auto mode specific for PM8350B PMIC. Introduce a "wa_flags" variable to handle the SW W/A in a cleaner way. Change-Id: I8f0c31fd21681274081a4d58d589b4ed9a188f34 Signed-off-by: Kiran Gunda --- drivers/input/misc/qcom-hv-haptics.c | 31 ++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/input/misc/qcom-hv-haptics.c b/drivers/input/misc/qcom-hv-haptics.c index 74ca559c780c..40ae40c13d91 100644 --- a/drivers/input/misc/qcom-hv-haptics.c +++ b/drivers/input/misc/qcom-hv-haptics.c @@ -364,6 +364,10 @@ enum pmic_type { PM5100, }; +enum wa_flags { + TOGGLE_CAL_RC_CLK = BIT(0), +}; + static const char * const src_str[] = { "FIFO", "DIRECT_PLAY", @@ -511,6 +515,7 @@ struct haptics_chip { u32 cfg_addr_base; u32 ptn_addr_base; u32 hbst_addr_base; + u32 wa_flags; u8 cfg_revision; u8 ptn_revision; u8 hpwr_intf_ctl; @@ -1451,8 +1456,9 @@ static int haptics_open_loop_drive_config(struct haptics_chip *chip, bool en) if (rc < 0) return rc; - if ((val & CAL_RC_CLK_MASK) == - CAL_RC_CLK_AUTO_VAL << CAL_RC_CLK_SHIFT) { + if ((chip->wa_flags & TOGGLE_CAL_RC_CLK) && + ((val & CAL_RC_CLK_MASK) == + CAL_RC_CLK_AUTO_VAL << CAL_RC_CLK_SHIFT)) { val = CAL_RC_CLK_DISABLED_VAL << CAL_RC_CLK_SHIFT; rc = haptics_masked_write(chip, chip->cfg_addr_base, HAP_CFG_CAL_EN_REG, CAL_RC_CLK_MASK, @@ -2580,6 +2586,23 @@ static int haptics_config_openloop_lra_period(struct haptics_chip *chip, HAP_CFG_TLRA_OL_HIGH_REG, val, 2); } +static int haptics_config_wa(struct haptics_chip *chip) +{ + switch (chip->pmic_type) { + case PM8350B: + chip->wa_flags |= TOGGLE_CAL_RC_CLK; + break; + case PM5100: + break; + default: + dev_err(chip->dev, "PMIC type %d does not match\n", + chip->pmic_type); + return -EINVAL; + } + + return 0; +} + static int haptics_hw_init(struct haptics_chip *chip) { struct haptics_hw_config *config = &chip->config; @@ -2588,6 +2611,10 @@ static int haptics_hw_init(struct haptics_chip *chip) u8 val[2]; u32 t_lra_us; + rc = haptics_config_wa(chip); + if (rc < 0) + return rc; + /* Store CL brake settings */ rc = haptics_store_cl_brake_settings(chip); if (rc < 0) From 1e2b2709254932e0d4344815520cd44d9b0d28d8 Mon Sep 17 00:00:00 2001 From: Vaibhav Agrawal Date: Tue, 6 Jul 2021 17:31:06 +0530 Subject: [PATCH 71/90] mmc: host: Add recovery_finish crypto vops Define recovery_finish crypto vops to support MMC CQE recovery handler path. Test: Initiate CQE recovery, which calls into crypto specific recovery method. If the crypto vops are registered on the device, this flow does not lead to a null pointer dereference with this fix included. Change-Id: I6dfaf52a303b9ffa71b6b65779f8e657d6ca051a Signed-off-by: Vaibhav Agrawal --- drivers/mmc/host/cqhci-crypto-qti.c | 9 ++++++++- drivers/mmc/host/cqhci-crypto-qti.h | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/cqhci-crypto-qti.c b/drivers/mmc/host/cqhci-crypto-qti.c index 5c97d1a56603..37766d13854d 100644 --- a/drivers/mmc/host/cqhci-crypto-qti.c +++ b/drivers/mmc/host/cqhci-crypto-qti.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2020, Linux Foundation. All rights reserved. + * Copyright (c) 2020 - 2021, Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -29,6 +29,7 @@ static struct cqhci_host_crypto_variant_ops __maybe_unused cqhci_crypto_qti_vari .disable = cqhci_crypto_qti_disable, .resume = cqhci_crypto_qti_resume, .debug = cqhci_crypto_qti_debug, + .recovery_finish = cqhci_crypto_qti_recovery_finish, }; static bool ice_cap_idx_valid(struct cqhci_host *host, @@ -317,5 +318,11 @@ int cqhci_crypto_qti_resume(struct cqhci_host *host) return crypto_qti_resume(host->crypto_vops->priv); } +int cqhci_crypto_qti_recovery_finish(struct cqhci_host *host) +{ + keyslot_manager_reprogram_all_keys(host->mmc->ksm); + return 0; +} + MODULE_DESCRIPTION("Vendor specific CQHCI Crypto Engine Support"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/cqhci-crypto-qti.h b/drivers/mmc/host/cqhci-crypto-qti.h index 07300624b6a1..9675a147daa6 100644 --- a/drivers/mmc/host/cqhci-crypto-qti.h +++ b/drivers/mmc/host/cqhci-crypto-qti.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020 - 2021, The Linux Foundation. All rights reserved. */ #ifndef _UFSHCD_CRYPTO_QTI_H @@ -28,4 +28,6 @@ void cqhci_crypto_qti_set_vops(struct cqhci_host *host) int cqhci_crypto_qti_resume(struct cqhci_host *host); +int cqhci_crypto_qti_recovery_finish(struct cqhci_host *host); + #endif /* _UFSHCD_ICE_QTI_H */ From 83100648156919ee3e623ea368b84e77e50c7591 Mon Sep 17 00:00:00 2001 From: Harshitha Sai Neelati Date: Wed, 7 Jul 2021 13:28:07 +0530 Subject: [PATCH 72/90] msm: kgsl: Support QDSS_STM based on QCOM_KGSL_QDSS_STM config Support QDSS_STM and vote for apb_pclk when QCOM_KGSL_QDSS_STM config is enabled. Change-Id: Ibe70585044e369ff9af2854b8fb5c10d860c40e7 Signed-off-by: Harshitha Sai Neelati --- drivers/gpu/msm/Kconfig | 8 ++++++++ drivers/gpu/msm/adreno_a6xx_gmu.c | 4 ++-- drivers/gpu/msm/adreno_a6xx_rgmu.c | 4 ++-- drivers/gpu/msm/kgsl_iommu.c | 4 ++-- drivers/gpu/msm/kgsl_pwrctrl.c | 4 ++-- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/msm/Kconfig b/drivers/gpu/msm/Kconfig index fbcdea99ca6a..fc01862f5641 100644 --- a/drivers/gpu/msm/Kconfig +++ b/drivers/gpu/msm/Kconfig @@ -70,3 +70,11 @@ config QCOM_KGSL_CONTEXT_DEBUG When enabled, total number of KGSL contexts, number of attached and detached contexts are dumped into kernel log for all the processes. This gives insight about the number of contexts held by each process. + +config QCOM_KGSL_QDSS_STM + bool "Enable support for QDSS STM for Adreno GPU" + depends on QCOM_KGSL && CORESIGHT + help + When enabled, the Adreno GPU QDSS STM support is enabled. GPU QDSS STM + memory will be mapped to GPU and QDSS clock needed to access this memory + is voted. Debug kernels should say 'Y' here. diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index acd6a97cb66c..cf3506a06372 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -2664,11 +2664,11 @@ int a6xx_gmu_probe(struct kgsl_device *device, return ret; /* * Voting for apb_pclk will enable power and clocks required for - * QDSS path to function. However, if CORESIGHT is not enabled, + * QDSS path to function. However, if QCOM_KGSL_QDSS_STM is not enabled, * QDSS is essentially unusable. Hence, if QDSS cannot be used, * don't vote for this clock. */ - if (!IS_ENABLED(CONFIG_CORESIGHT)) { + if (!IS_ENABLED(CONFIG_QCOM_KGSL_QDSS_STM)) { for (i = 0; i < ret; i++) { if (!strcmp(gmu->clks[i].id, "apb_pclk")) { gmu->clks[i].clk = NULL; diff --git a/drivers/gpu/msm/adreno_a6xx_rgmu.c b/drivers/gpu/msm/adreno_a6xx_rgmu.c index 4e82413092e9..49d71e5318e5 100644 --- a/drivers/gpu/msm/adreno_a6xx_rgmu.c +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.c @@ -1258,11 +1258,11 @@ static int a6xx_rgmu_clocks_probe(struct a6xx_rgmu_device *rgmu, return ret; /* * Voting for apb_pclk will enable power and clocks required for - * QDSS path to function. However, if CORESIGHT is not enabled, + * QDSS path to function. However, if QCOM_KGSL_QDSS_STM is not enabled, * QDSS is essentially unusable. Hence, if QDSS cannot be used, * don't vote for this clock. */ - if (!IS_ENABLED(CONFIG_CORESIGHT)) { + if (!IS_ENABLED(CONFIG_QCOM_KGSL_QDSS_STM)) { for (i = 0; i < ret; i++) { if (!strcmp(rgmu->clks[i].id, "apb_pclk")) { rgmu->clks[i].clk = NULL; diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 945f2a3838e0..2cacf6dfe490 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -2511,8 +2511,8 @@ int kgsl_iommu_probe(struct kgsl_device *device) */ kgsl_iommu_map_globals(mmu, mmu->defaultpagetable); kgsl_iommu_map_globals(mmu, mmu->lpac_pagetable); - /* QDSS is supported only when CORESIGHT is enabled */ - if (IS_ENABLED(CONFIG_CORESIGHT)) + /* QDSS is supported only when QCOM_KGSL_QDSS_STM is enabled */ + if (IS_ENABLED(CONFIG_QCOM_KGSL_QDSS_STM)) device->qdss_desc = kgsl_allocate_global_fixed(device, "qcom,gpu-qdss-stm", "gpu-qdss"); diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 7003d76d933f..2117d69c5e7d 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1427,8 +1427,8 @@ static int _get_clocks(struct kgsl_device *device) for (i = 0; i < KGSL_MAX_CLKS; i++) { if (pwr->grp_clks[i] || strcmp(clocks[i], name)) continue; - /* apb_pclk should only be enabled if CORESIGHT is enabled */ - if (!strcmp(name, "apb_pclk") && !IS_ENABLED(CONFIG_CORESIGHT)) + /* apb_pclk should only be enabled if QCOM_KGSL_QDSS_STM is enabled */ + if (!strcmp(name, "apb_pclk") && !IS_ENABLED(CONFIG_QCOM_KGSL_QDSS_STM)) continue; pwr->grp_clks[i] = devm_clk_get(dev, name); From e96fc1eeb8595707c10e780ef7be1c890ad67728 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Thu, 11 Jan 2018 14:36:40 -0800 Subject: [PATCH 73/90] usb: gadget: f_serial: Add support for DUN Currently driver only support generic serial interface. Adding communication device class specific descriptors and notification endpoint support required for the enumeration of a DUN interface. Add control transfer APIs to send and receive serial line state. Change-Id: I8d50495ad51797dfc8b3e77464474d9fe70d8636 Signed-off-by: Hemant Kumar --- drivers/usb/gadget/function/f_serial.c | 460 ++++++++++++++++++++++++- drivers/usb/gadget/function/u_serial.h | 12 + 2 files changed, 469 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/f_serial.c b/drivers/usb/gadget/function/f_serial.c index 0f63755c62fd..6d7a4ef7d2bc 100644 --- a/drivers/usb/gadget/function/f_serial.c +++ b/drivers/usb/gadget/function/f_serial.c @@ -28,13 +28,43 @@ struct f_gser { struct gserial port; u8 data_id; u8 port_num; + spinlock_t lock; + + struct usb_ep *notify; + struct usb_request *notify_req; + + u8 online; + u8 pending; + struct usb_cdc_line_coding port_line_coding; + + /* SetControlLineState request */ + u16 port_handshake_bits; +#define ACM_CTRL_RTS (1 << 1) /* unused with full duplex */ +#define ACM_CTRL_DTR (1 << 0) /* host is ready for data r/w */ + + /* SerialState notification */ + u16 serial_state; +#define ACM_CTRL_OVERRUN (1 << 6) +#define ACM_CTRL_PARITY (1 << 5) +#define ACM_CTRL_FRAMING (1 << 4) +#define ACM_CTRL_RI (1 << 3) +#define ACM_CTRL_BRK (1 << 2) +#define ACM_CTRL_DSR (1 << 1) +#define ACM_CTRL_DCD (1 << 0) }; +static inline struct f_gser *port_to_gser(struct gserial *p) +{ + return container_of(p, struct f_gser, port); +} + static inline struct f_gser *func_to_gser(struct usb_function *f) { return container_of(f, struct f_gser, port.func); } +#define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */ +#define GS_NOTIFY_MAXPACKET 10 /* notification + 2 bytes */ /*-------------------------------------------------------------------------*/ /* interface descriptor: */ @@ -43,15 +73,55 @@ static struct usb_interface_descriptor gser_interface_desc = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, /* .bInterfaceNumber = DYNAMIC */ - .bNumEndpoints = 2, + .bNumEndpoints = 3, .bInterfaceClass = USB_CLASS_VENDOR_SPEC, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0x40, /* .iInterface = DYNAMIC */ }; +static struct usb_cdc_header_desc gser_header_desc = { + .bLength = sizeof(gser_header_desc), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_HEADER_TYPE, + .bcdCDC = cpu_to_le16(0x0110), +}; + +static struct usb_cdc_call_mgmt_descriptor +gser_call_mgmt_descriptor = { + .bLength = sizeof(gser_call_mgmt_descriptor), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, + .bmCapabilities = 0, + /* .bDataInterface = DYNAMIC */ +}; + +static struct usb_cdc_acm_descriptor gser_descriptor = { + .bLength = sizeof(gser_descriptor), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_ACM_TYPE, + .bmCapabilities = USB_CDC_CAP_LINE, +}; + +static struct usb_cdc_union_desc gser_union_desc = { + .bLength = sizeof(gser_union_desc), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_UNION_TYPE, + /* .bMasterInterface0 = DYNAMIC */ + /* .bSlaveInterface0 = DYNAMIC */ +}; + /* full speed support: */ +static struct usb_endpoint_descriptor gser_fs_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET), + .bInterval = 1 << GS_LOG2_NOTIFY_INTERVAL, +}; + static struct usb_endpoint_descriptor gser_fs_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -68,12 +138,25 @@ static struct usb_endpoint_descriptor gser_fs_out_desc = { static struct usb_descriptor_header *gser_fs_function[] = { (struct usb_descriptor_header *) &gser_interface_desc, + (struct usb_descriptor_header *) &gser_header_desc, + (struct usb_descriptor_header *) &gser_call_mgmt_descriptor, + (struct usb_descriptor_header *) &gser_descriptor, + (struct usb_descriptor_header *) &gser_union_desc, + (struct usb_descriptor_header *) &gser_fs_notify_desc, (struct usb_descriptor_header *) &gser_fs_in_desc, (struct usb_descriptor_header *) &gser_fs_out_desc, NULL, }; /* high speed support: */ +static struct usb_endpoint_descriptor gser_hs_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET), + .bInterval = GS_LOG2_NOTIFY_INTERVAL+4, +}; static struct usb_endpoint_descriptor gser_hs_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -91,6 +174,11 @@ static struct usb_endpoint_descriptor gser_hs_out_desc = { static struct usb_descriptor_header *gser_hs_function[] = { (struct usb_descriptor_header *) &gser_interface_desc, + (struct usb_descriptor_header *) &gser_header_desc, + (struct usb_descriptor_header *) &gser_call_mgmt_descriptor, + (struct usb_descriptor_header *) &gser_descriptor, + (struct usb_descriptor_header *) &gser_union_desc, + (struct usb_descriptor_header *) &gser_hs_notify_desc, (struct usb_descriptor_header *) &gser_hs_in_desc, (struct usb_descriptor_header *) &gser_hs_out_desc, NULL, @@ -115,8 +203,33 @@ static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc = { .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, }; +static struct usb_endpoint_descriptor gser_ss_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET), + .bInterval = GS_LOG2_NOTIFY_INTERVAL+4, +}; + +static struct usb_ss_ep_comp_descriptor gser_ss_notify_comp_desc = { + .bLength = sizeof(gser_ss_notify_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 2 values can be tweaked if necessary */ + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ + .wBytesPerInterval = cpu_to_le16(GS_NOTIFY_MAXPACKET), +}; + static struct usb_descriptor_header *gser_ss_function[] = { (struct usb_descriptor_header *) &gser_interface_desc, + (struct usb_descriptor_header *) &gser_header_desc, + (struct usb_descriptor_header *) &gser_call_mgmt_descriptor, + (struct usb_descriptor_header *) &gser_descriptor, + (struct usb_descriptor_header *) &gser_union_desc, + (struct usb_descriptor_header *) &gser_ss_notify_desc, + (struct usb_descriptor_header *) &gser_ss_notify_comp_desc, (struct usb_descriptor_header *) &gser_ss_in_desc, (struct usb_descriptor_header *) &gser_ss_bulk_comp_desc, (struct usb_descriptor_header *) &gser_ss_out_desc, @@ -127,7 +240,7 @@ static struct usb_descriptor_header *gser_ss_function[] = { /* string descriptors: */ static struct usb_string gser_string_defs[] = { - [0].s = "Generic Serial", + [0].s = "DUN over Serial", { } /* end of list */ }; @@ -142,13 +255,131 @@ static struct usb_gadget_strings *gser_strings[] = { }; /*-------------------------------------------------------------------------*/ +static void gser_complete_set_line_coding(struct usb_ep *ep, + struct usb_request *req) +{ + struct f_gser *gser = ep->driver_data; + struct usb_composite_dev *cdev = gser->port.func.config->cdev; + + if (req->status != 0) { + dev_dbg(&cdev->gadget->dev, "gser ttyGS%d completion, err %d\n", + gser->port_num, req->status); + return; + } + + /* normal completion */ + if (req->actual != sizeof(gser->port_line_coding)) { + dev_dbg(&cdev->gadget->dev, "gser ttyGS%d short resp, len %d\n", + gser->port_num, req->actual); + usb_ep_set_halt(ep); + } else { + struct usb_cdc_line_coding *value = req->buf; + + gser->port_line_coding = *value; + } +} + +static int +gser_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) +{ + struct f_gser *gser = func_to_gser(f); + struct usb_composite_dev *cdev = f->config->cdev; + struct usb_request *req = cdev->req; + int value = -EOPNOTSUPP; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); + + + switch ((ctrl->bRequestType << 8) | ctrl->bRequest) { + + /* SET_LINE_CODING ... just read and save what the host sends */ + case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) + | USB_CDC_REQ_SET_LINE_CODING: + if (w_length != sizeof(struct usb_cdc_line_coding)) + goto invalid; + + value = w_length; + cdev->gadget->ep0->driver_data = gser; + req->complete = gser_complete_set_line_coding; + break; + + /* GET_LINE_CODING ... return what host sent, or initial value */ + case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) + | USB_CDC_REQ_GET_LINE_CODING: + value = min_t(unsigned int, w_length, + sizeof(struct usb_cdc_line_coding)); + memcpy(req->buf, &gser->port_line_coding, value); + break; + + /* SET_CONTROL_LINE_STATE ... save what the host sent */ + case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) + | USB_CDC_REQ_SET_CONTROL_LINE_STATE: + + value = 0; + gser->port_handshake_bits = w_value; + pr_debug("%s: USB_CDC_REQ_SET_CONTROL_LINE_STATE: DTR:%d RST:%d\n", + __func__, w_value & ACM_CTRL_DTR ? 1 : 0, + w_value & ACM_CTRL_RTS ? 1 : 0); + + if (gser->port.notify_modem) + gser->port.notify_modem(&gser->port, 0, w_value); + + break; + + default: +invalid: + dev_dbg(&cdev->gadget->dev, + "invalid control req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + } + + /* respond with data transfer or status phase? */ + if (value >= 0) { + dev_dbg(&cdev->gadget->dev, + "gser ttyGS%d req%02x.%02x v%04x i%04x l%d\n", + gser->port_num, ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + req->zero = 0; + req->length = value; + value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + if (value < 0) + ERROR(cdev, "gser response on ttyGS%d, err %d\n", + gser->port_num, value); + } + + /* device either stalls (value < 0) or reports success */ + return value; +} static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct f_gser *gser = func_to_gser(f); struct usb_composite_dev *cdev = f->config->cdev; + int rc = 0; /* we know alt == 0, so this is an activation or a reset */ + if (gser->notify->driver_data) { + dev_dbg(&cdev->gadget->dev, + "reset generic ctl ttyGS%d\n", gser->port_num); + usb_ep_disable(gser->notify); + } + + if (!gser->notify->desc) { + if (config_ep_by_speed(cdev->gadget, f, gser->notify)) { + gser->notify->desc = NULL; + return -EINVAL; + } + } + + rc = usb_ep_enable(gser->notify); + if (rc) { + ERROR(cdev, "can't enable %s, result %d\n", + gser->notify->name, rc); + return rc; + } + gser->notify->driver_data = gser; if (gser->port.in->enabled) { dev_dbg(&cdev->gadget->dev, @@ -166,7 +397,9 @@ static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } } gserial_connect(&gser->port, gser->port_num); - return 0; + gser->online = 1; + + return rc; } static void gser_disable(struct usb_function *f) @@ -177,6 +410,178 @@ static void gser_disable(struct usb_function *f) dev_dbg(&cdev->gadget->dev, "generic ttyGS%d deactivated\n", gser->port_num); gserial_disconnect(&gser->port); + usb_ep_disable(gser->notify); + gser->notify->driver_data = NULL; + gser->online = 0; +} + +static int gser_notify(struct f_gser *gser, u8 type, u16 value, + void *data, unsigned int length) +{ + struct usb_ep *ep = gser->notify; + struct usb_request *req; + struct usb_cdc_notification *notify; + const unsigned int len = sizeof(*notify) + length; + void *buf; + int status; + struct usb_composite_dev *cdev = gser->port.func.config->cdev; + + req = gser->notify_req; + gser->notify_req = NULL; + gser->pending = false; + + req->length = len; + notify = req->buf; + buf = notify + 1; + + notify->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS + | USB_RECIP_INTERFACE; + notify->bNotificationType = type; + notify->wValue = cpu_to_le16(value); + notify->wIndex = cpu_to_le16(gser->data_id); + notify->wLength = cpu_to_le16(length); + memcpy(buf, data, length); + + status = usb_ep_queue(ep, req, GFP_ATOMIC); + if (status < 0) { + ERROR(cdev, "gser ttyGS%d can't notify serial state, %d\n", + gser->port_num, status); + gser->notify_req = req; + } + + return status; +} + +static int gser_notify_serial_state(struct f_gser *gser) +{ + int status; + unsigned long flags; + struct usb_composite_dev *cdev = gser->port.func.config->cdev; + + spin_lock_irqsave(&gser->lock, flags); + if (gser->notify_req) { + DBG(cdev, "gser ttyGS%d serial state %04x\n", + gser->port_num, gser->serial_state); + status = gser_notify(gser, USB_CDC_NOTIFY_SERIAL_STATE, + 0, &gser->serial_state, + sizeof(gser->serial_state)); + } else { + gser->pending = true; + status = 0; + } + + spin_unlock_irqrestore(&gser->lock, flags); + return status; +} + +static void gser_notify_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_gser *gser = req->context; + u8 doit = false; + unsigned long flags; + + /* on this call path we do NOT hold the port spinlock, + * which is why ACM needs its own spinlock + */ + + spin_lock_irqsave(&gser->lock, flags); + if (req->status != -ESHUTDOWN) + doit = gser->pending; + + gser->notify_req = req; + spin_unlock_irqrestore(&gser->lock, flags); + + if (doit && gser->online) + gser_notify_serial_state(gser); +} + +static void gser_connect(struct gserial *port) +{ + struct f_gser *gser = port_to_gser(port); + + gser->serial_state |= ACM_CTRL_DSR | ACM_CTRL_DCD; + gser_notify_serial_state(gser); +} + +static unsigned int gser_get_dtr(struct gserial *port) +{ + struct f_gser *gser = port_to_gser(port); + + if (gser->port_handshake_bits & ACM_CTRL_DTR) + return 1; + else + return 0; +} + +static unsigned int gser_get_rts(struct gserial *port) +{ + struct f_gser *gser = port_to_gser(port); + + if (gser->port_handshake_bits & ACM_CTRL_RTS) + return 1; + else + return 0; +} + +static unsigned int gser_send_carrier_detect(struct gserial *port, + unsigned int yes) +{ + u16 state; + struct f_gser *gser = port_to_gser(port); + + state = gser->serial_state; + state &= ~ACM_CTRL_DCD; + if (yes) + state |= ACM_CTRL_DCD; + + gser->serial_state = state; + return gser_notify_serial_state(gser); +} + +static unsigned int gser_send_ring_indicator(struct gserial *port, + unsigned int yes) +{ + u16 state; + struct f_gser *gser = port_to_gser(port); + + state = gser->serial_state; + state &= ~ACM_CTRL_RI; + if (yes) + state |= ACM_CTRL_RI; + + gser->serial_state = state; + return gser_notify_serial_state(gser); +} + +static void gser_disconnect(struct gserial *port) +{ + struct f_gser *gser = port_to_gser(port); + + gser->serial_state &= ~(ACM_CTRL_DSR | ACM_CTRL_DCD); + gser_notify_serial_state(gser); +} + +static int gser_send_break(struct gserial *port, int duration) +{ + u16 state; + struct f_gser *gser = port_to_gser(port); + + state = gser->serial_state; + state &= ~ACM_CTRL_BRK; + if (duration) + state |= ACM_CTRL_BRK; + + gser->serial_state = state; + return gser_notify_serial_state(gser); +} + +static int gser_send_modem_ctrl_bits(struct gserial *port, int ctrl_bits) +{ + struct f_gser *gser = port_to_gser(port); + + gser->serial_state = ctrl_bits; + + return gser_notify_serial_state(gser); } /*-------------------------------------------------------------------------*/ @@ -222,6 +627,21 @@ static int gser_bind(struct usb_configuration *c, struct usb_function *f) goto fail; gser->port.out = ep; + ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_notify_desc); + if (!ep) + goto fail; + gser->notify = ep; + ep->driver_data = cdev; /* claim */ + /* allocate notification */ + gser->notify_req = gs_alloc_req(ep, + sizeof(struct usb_cdc_notification) + 2, + GFP_KERNEL); + if (!gser->notify_req) + goto fail; + + gser->notify_req->complete = gser_notify_complete; + gser->notify_req->context = gser; + /* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds @@ -232,6 +652,15 @@ static int gser_bind(struct usb_configuration *c, struct usb_function *f) gser_ss_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress; gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress; + if (gadget_is_dualspeed(c->cdev->gadget)) { + gser_hs_notify_desc.bEndpointAddress = + gser_fs_notify_desc.bEndpointAddress; + } + if (gadget_is_superspeed(c->cdev->gadget)) { + gser_ss_notify_desc.bEndpointAddress = + gser_fs_notify_desc.bEndpointAddress; + } + status = usb_assign_descriptors(f, gser_fs_function, gser_hs_function, gser_ss_function, NULL); if (status) @@ -244,6 +673,18 @@ static int gser_bind(struct usb_configuration *c, struct usb_function *f) return 0; fail: + if (gser->notify_req) + gs_free_req(gser->notify, gser->notify_req); + + /* we might as well release our claims on endpoints */ + if (gser->notify) + gser->notify->driver_data = NULL; + /* we might as well release our claims on endpoints */ + if (gser->port.out) + gser->port.out->driver_data = NULL; + if (gser->port.in) + gser->port.in->driver_data = NULL; + ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); return status; @@ -324,7 +765,10 @@ static void gser_free(struct usb_function *f) static void gser_unbind(struct usb_configuration *c, struct usb_function *f) { + struct f_gser *gser = func_to_gser(f); + usb_free_all_descriptors(f); + gs_free_req(gser->notify, gser->notify_req); } static struct usb_function *gser_alloc(struct usb_function_instance *fi) @@ -339,6 +783,7 @@ static struct usb_function *gser_alloc(struct usb_function_instance *fi) opts = container_of(fi, struct f_serial_opts, func_inst); + spin_lock_init(&gser->lock); gser->port_num = opts->port_num; gser->port.func.name = "gser"; @@ -348,6 +793,15 @@ static struct usb_function *gser_alloc(struct usb_function_instance *fi) gser->port.func.set_alt = gser_set_alt; gser->port.func.disable = gser_disable; gser->port.func.free_func = gser_free; + gser->port.func.setup = gser_setup; + gser->port.connect = gser_connect; + gser->port.get_dtr = gser_get_dtr; + gser->port.get_rts = gser_get_rts; + gser->port.send_carrier_detect = gser_send_carrier_detect; + gser->port.send_ring_indicator = gser_send_ring_indicator; + gser->port.send_modem_ctrl_bits = gser_send_modem_ctrl_bits; + gser->port.disconnect = gser_disconnect; + gser->port.send_break = gser_send_break; return &gser->port.func; } diff --git a/drivers/usb/gadget/function/u_serial.h b/drivers/usb/gadget/function/u_serial.h index 9acaac1cbb75..74dc864ca050 100644 --- a/drivers/usb/gadget/function/u_serial.h +++ b/drivers/usb/gadget/function/u_serial.h @@ -42,11 +42,23 @@ struct gserial { /* REVISIT avoid this CDC-ACM support harder ... */ struct usb_cdc_line_coding port_line_coding; /* 9600-8-N-1 etc */ + u16 serial_state; + + /* control signal callbacks*/ + unsigned int (*get_dtr)(struct gserial *p); + unsigned int (*get_rts)(struct gserial *p); /* notification callbacks */ void (*connect)(struct gserial *p); void (*disconnect)(struct gserial *p); int (*send_break)(struct gserial *p, int duration); + unsigned int (*send_carrier_detect)(struct gserial *p, + unsigned int yes); + unsigned int (*send_ring_indicator)(struct gserial *p, + unsigned int yes); + int (*send_modem_ctrl_bits)(struct gserial *p, int ctrl_bits); + /* notification changes to modem */ + void (*notify_modem)(void *gser, u8 portno, int ctrl_bits); }; /* utilities to allocate/free request and buffer */ From 36a30662f58838f450fe3e14bfeed8f4bf0cd973 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Tue, 15 Jun 2021 14:59:17 -0700 Subject: [PATCH 74/90] mhi: core: Fix find_last_bit() usage find_last_bit() relies on unsigned long pointer arguments. Driver uses a type cast that generates the KASAN warning. Replace find_last_bit() with __fls() to pass the value and avoid casting pointer to make the warning go away. Change-Id: I247e5c425ba0c44d04b518bd6d4f351f9c700b29 Signed-off-by: Hemant Kumar --- drivers/bus/mhi/core/mhi_init.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index 526d7fd140e8..f026131cf3ab 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -92,9 +92,12 @@ struct mhi_controller *find_mhi_controller_by_name(const char *name) const char *to_mhi_pm_state_str(enum MHI_PM_STATE state) { - int index = find_last_bit((unsigned long *)&state, 32); + int index; - if (index >= ARRAY_SIZE(mhi_pm_state_str)) + if (state) + index = __fls(state); + + if (!state || index >= ARRAY_SIZE(mhi_pm_state_str)) return "Invalid State"; return mhi_pm_state_str[index]; From d2bf6fd5b9d0438d0d57e3aa8d911c823be9ab98 Mon Sep 17 00:00:00 2001 From: Anmolpreet Kaur Date: Mon, 21 Jun 2021 20:13:12 +0530 Subject: [PATCH 75/90] smcinvoke: Add retry mechanism for scm calls This chage adds retry mechanism to smcinvoke driver in case when secure side is busy. Driver will wait for 30 milliseconds before retrying the scm call. This change also makes smcinvoke driver at par with qseecom in terms of trying for around 2 seconds before sending EBUSY error back to client. Change-Id: Ie9523bc81f3aa03497836f06180c9d3f8a8efc99 Signed-off-by: Anmolpreet Kaur --- drivers/firmware/qcom_scm-smc.c | 6 +++--- drivers/soc/qcom/smcinvoke.c | 21 +++++++++++++++++---- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/firmware/qcom_scm-smc.c b/drivers/firmware/qcom_scm-smc.c index 2fb3b66896cd..a731a5f504f0 100644 --- a/drivers/firmware/qcom_scm-smc.c +++ b/drivers/firmware/qcom_scm-smc.c @@ -2321,7 +2321,7 @@ int __qcom_scm_invoke_smc_legacy(struct device *dev, phys_addr_t in_buf, desc.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW, QCOM_SCM_VAL, QCOM_SCM_RW, QCOM_SCM_VAL); - ret = qcom_scm_call(dev, &desc); + ret = qcom_scm_call_noretry(dev, &desc); if (result) *result = desc.res[1]; @@ -2353,7 +2353,7 @@ int __qcom_scm_invoke_smc(struct device *dev, phys_addr_t in_buf, desc.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW, QCOM_SCM_VAL, QCOM_SCM_RW, QCOM_SCM_VAL); - ret = qcom_scm_call(dev, &desc); + ret = qcom_scm_call_noretry(dev, &desc); if (result) *result = desc.res[1]; @@ -2382,7 +2382,7 @@ int __qcom_scm_invoke_callback_response(struct device *dev, phys_addr_t out_buf, desc.args[1] = out_buf_size; desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_RW, QCOM_SCM_VAL); - ret = qcom_scm_call(dev, &desc); + ret = qcom_scm_call_noretry(dev, &desc); if (result) *result = desc.res[1]; diff --git a/drivers/soc/qcom/smcinvoke.c b/drivers/soc/qcom/smcinvoke.c index 020d9da02104..da8a33932180 100644 --- a/drivers/soc/qcom/smcinvoke.c +++ b/drivers/soc/qcom/smcinvoke.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,9 @@ #define SMCINVOKE_MEM_MAP_OBJ 0 #define SMCINVOKE_MEM_RGN_OBJ 1 #define SMCINVOKE_MEM_PERM_RW 6 +#define SMCINVOKE_SCM_EBUSY_WAIT_MS 30 +#define SMCINVOKE_SCM_EBUSY_MAX_RETRY 67 + /* TZ defined values - Start */ #define SMCINVOKE_INVOKE_PARAM_ID 0x224 @@ -1288,7 +1292,7 @@ static int prepare_send_scm_msg(const uint8_t *in_buf, phys_addr_t in_paddr, bool *tz_acked, struct qtee_shm *in_shm, struct qtee_shm *out_shm) { - int ret = 0, cmd; + int ret = 0, cmd, retry_count = 0; u64 response_type; unsigned int data; struct file *arr_filp[OBJECT_COUNTS_MAX_OO] = {NULL}; @@ -1311,9 +1315,18 @@ static int prepare_send_scm_msg(const uint8_t *in_buf, phys_addr_t in_paddr, while (1) { mutex_lock(&g_smcinvoke_lock); - ret = invoke_cmd_handler(cmd, in_paddr, in_buf_len, out_buf, - out_paddr, out_buf_len, &req->result, &response_type, - &data, in_shm, out_shm); + do { + ret = invoke_cmd_handler(cmd, in_paddr, in_buf_len, out_buf, + out_paddr, out_buf_len, &req->result, &response_type, + &data, in_shm, out_shm); + + if (ret == -EBUSY) { + pr_err("Secure side is busy,will retry after 30 ms\n"); + msleep(SMCINVOKE_SCM_EBUSY_WAIT_MS); + } + + } while ((ret == -EBUSY) && + (retry_count++ < SMCINVOKE_SCM_EBUSY_MAX_RETRY)); if (!ret && !is_inbound_req(response_type)) { /* dont marshal if Obj returns an error */ From ed992c7a17ca2a320993d34ab568bfdab072d131 Mon Sep 17 00:00:00 2001 From: Naman Padhiar Date: Mon, 3 May 2021 13:28:31 +0530 Subject: [PATCH 76/90] icnss2: Send ICNSS_SMMU_FAULT uevent to host driver On detection of SMMU fault, platform driver send SMMU_FAULT and FW_DOWN event to Host driver. Change-Id: I623522231b5ee7ab0b03b8c1b25993395b7f3a2d Signed-off-by: Naman Padhiar --- drivers/soc/qcom/icnss2/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soc/qcom/icnss2/main.c b/drivers/soc/qcom/icnss2/main.c index 43b811115bf8..2f70d96be573 100644 --- a/drivers/soc/qcom/icnss2/main.c +++ b/drivers/soc/qcom/icnss2/main.c @@ -3700,6 +3700,8 @@ static int icnss_smmu_fault_handler(struct iommu_domain *domain, if (test_bit(ICNSS_FW_READY, &priv->state)) { fw_down_data.crashed = true; + icnss_call_driver_uevent(priv, ICNSS_UEVENT_SMMU_FAULT, + &fw_down_data); icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); } From 74ab1d4b331162defde6a9af016d8b421c4f8ea9 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Wed, 25 Jul 2018 15:01:38 +0530 Subject: [PATCH 77/90] net: usb: ax88179: Change to check if the packets are coming from gsb Packets from gsb are cloned packets, which has been done to optimize the dl data path. The check for cloned skb calls pskb_expand_head which gives penalty in the throughput. GSB driver data path does not consume the skb so, reallocation of skb is not necessary here. For that reason the check for all packets from gsb is introduced here. This check improves the throughput to about 150 Mbps. Change-Id: Ic1d7cc9c94605f1902ba212aac52d535d0ff84a7 Acked-by: Rishav LNU Signed-off-by: Mohammed Javid --- drivers/net/usb/ax88179_178a.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 8e37e1f58c4b..d78c6327f65b 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -1431,12 +1431,20 @@ ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) headroom = skb_headroom(skb) - 8; +#ifdef CONFIG_ENABLE_SFE + if (((!(skb->fast_forwarded) && skb_header_cloned(skb)) || + headroom < 0) && + pskb_expand_head(skb, headroom < 0 ? 8 : 0, 0, GFP_ATOMIC)) { + dev_kfree_skb_any(skb); + return NULL; + } +#else if ((skb_header_cloned(skb) || headroom < 0) && pskb_expand_head(skb, headroom < 0 ? 8 : 0, 0, GFP_ATOMIC)) { dev_kfree_skb_any(skb); return NULL; } - +#endif ptr = skb_push(skb, 8); put_unaligned_le32(tx_hdr1, ptr); put_unaligned_le32(tx_hdr2, ptr + 4); From 4350ddc2c4ae5e86a3b84ca71972247d217e56e2 Mon Sep 17 00:00:00 2001 From: Pooja Kumari Date: Thu, 1 Jul 2021 14:35:56 +0530 Subject: [PATCH 78/90] msm: ipa3: add v2x ethernet support Add the v2x ethernet pipe connect support for offloading v2x traffic. Change-Id: I5e84f7e1d07722eeb5a7b9fbfbccb69451c72934 Signed-off-by: Pooja Kumari --- include/linux/ipa_uc_offload.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/ipa_uc_offload.h b/include/linux/ipa_uc_offload.h index 9d80c752c40b..2f7474ea7e43 100644 --- a/include/linux/ipa_uc_offload.h +++ b/include/linux/ipa_uc_offload.h @@ -143,10 +143,14 @@ struct ipa_ntn_conn_in_params { * @ul_uc_db_pa: physical address of IPA uc doorbell for UL * @dl_uc_db_pa: physical address of IPA uc doorbell for DL * @clnt_hdl: opaque handle assigned to offload client + * @ul_uc_db_iomem: iomem address of IPA uc doorbell for UL + * @dl_uc_db_iomem: iomem address of IPA uc doorbell for DL */ struct ipa_ntn_conn_out_params { phys_addr_t ul_uc_db_pa; phys_addr_t dl_uc_db_pa; + void __iomem *ul_uc_db_iomem; + void __iomem *dl_uc_db_iomem; }; /** From 3a4bf89f53f47a326fef8087e72623e7d0066395 Mon Sep 17 00:00:00 2001 From: "Jinesh K. Jayakumar" Date: Tue, 13 Jul 2021 12:36:26 -0400 Subject: [PATCH 79/90] defconfig: sdxlemur: Disable IOSS v1 driver IPA Offload Sub-System v1 is deprecated now that all ethernet drivers have moved to v2. This reverts commit 6d40652ad7b4a1b1b2800d7aec09959dd2233916. Change-Id: Ie56390eda564627cd9f9ccdb64123c656b5d96b6 Signed-off-by: Jinesh K. Jayakumar --- arch/arm/configs/vendor/sdxlemur.config | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm/configs/vendor/sdxlemur.config b/arch/arm/configs/vendor/sdxlemur.config index 5974ea0c7c99..374d71a8edcc 100644 --- a/arch/arm/configs/vendor/sdxlemur.config +++ b/arch/arm/configs/vendor/sdxlemur.config @@ -355,9 +355,6 @@ CONFIG_IOSS=m CONFIG_AQFWD_IOSS=m CONFIG_R8125=y CONFIG_R8125_IOSS=m -CONFIG_IPA_ETH=y -CONFIG_IPA_ETH_DEBUG=y -# CONFIG_IPA_ETH_NOAUTO is not set CONFIG_QCOM_SHOW_RESUME_IRQ=y CONFIG_HARDENED_USERCOPY=y # CONFIG_HARDENED_USERCOPY_FALLBACK is not set From a864e70eef25b264b64b349749d3db01b7255390 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Wed, 9 Jun 2021 11:49:01 +0200 Subject: [PATCH 80/90] udp: fix race between close() and udp_abort() Kaustubh reported and diagnosed a panic in udp_lib_lookup(). The root cause is udp_abort() racing with close(). Both racing functions acquire the socket lock, but udp{v6}_destroy_sock() release it before performing destructive actions. We can't easily extend the socket lock scope to avoid the race, instead use the SOCK_DEAD flag to prevent udp_abort from doing any action when the critical race happens. Change-Id: I8ec3f73ed5f8324722b29450c37b4ae23a81c0f3 Diagnosed-and-tested-by: Kaustubh Pandey Fixes: 5d77dca82839 ("net: diag: support SOCK_DESTROY for UDP sockets") Signed-off-by: Paolo Abeni Signed-off-by: David S. Miller Git-Commit: a8b897c7bcd47f4147d066e22cc01d1026d7640e Git-repo: https://kernel.googlesource.com/pub/scm/linux/kernel/git/netdev/net.git Signed-off-by: Kaustubh Pandey --- net/ipv4/udp.c | 10 ++++++++++ net/ipv6/udp.c | 3 +++ 2 files changed, 13 insertions(+) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index d89725d93d6c..99aed1b2571b 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2510,6 +2510,9 @@ void udp_destroy_sock(struct sock *sk) { struct udp_sock *up = udp_sk(sk); bool slow = lock_sock_fast(sk); + + /* protects from races with udp_abort() */ + sock_set_flag(sk, SOCK_DEAD); udp_flush_pending_frames(sk); unlock_sock_fast(sk, slow); if (static_branch_unlikely(&udp_encap_needed_key)) { @@ -2765,10 +2768,17 @@ int udp_abort(struct sock *sk, int err) { lock_sock(sk); + /* udp{v6}_destroy_sock() sets it under the sk lock, avoid racing + * with close() + */ + if (sock_flag(sk, SOCK_DEAD)) + goto out; + sk->sk_err = err; sk->sk_error_report(sk); __udp_disconnect(sk, 0); +out: release_sock(sk); return 0; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 6762430280f5..3c94b81bb459 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1539,6 +1539,9 @@ void udpv6_destroy_sock(struct sock *sk) { struct udp_sock *up = udp_sk(sk); lock_sock(sk); + + /* protects from races with udp_abort() */ + sock_set_flag(sk, SOCK_DEAD); udp_v6_flush_pending_frames(sk); release_sock(sk); From fbda728fefabe98e2c8968311669054dde4ec122 Mon Sep 17 00:00:00 2001 From: Shyam Kumar Thella Date: Tue, 29 Jun 2021 14:27:52 +0530 Subject: [PATCH 81/90] uapi: Add UAPI headers for QBG Add entries for QBG UAPI headers in gen_headers. Change-Id: I514a2cf99f8fb3654e8d9fbb2528623c9cd4aced Signed-off-by: Shyam Kumar Thella --- gen_headers_arm.bp | 2 ++ gen_headers_arm64.bp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/gen_headers_arm.bp b/gen_headers_arm.bp index acafa0e5d7f1..8569b1909c43 100644 --- a/gen_headers_arm.bp +++ b/gen_headers_arm.bp @@ -474,6 +474,8 @@ gen_headers_out_arm = [ "linux/qemu_fw_cfg.h", "linux/qg.h", "linux/qg-profile.h", + "linux/qbg.h", + "linux/qbg-profile.h", "linux/qnx4_fs.h", "linux/qnxtypes.h", "linux/qrng.h", diff --git a/gen_headers_arm64.bp b/gen_headers_arm64.bp index 975584a08898..cd9d16532421 100644 --- a/gen_headers_arm64.bp +++ b/gen_headers_arm64.bp @@ -469,6 +469,8 @@ gen_headers_out_arm64 = [ "linux/qemu_fw_cfg.h", "linux/qg.h", "linux/qg-profile.h", + "linux/qbg.h", + "linux/qbg-profile.h", "linux/qnx4_fs.h", "linux/qnxtypes.h", "linux/qrng.h", From 71cb759242c03758f100cd201c5e0aa91fb978a1 Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Wed, 16 Jun 2021 19:49:36 +0530 Subject: [PATCH 82/90] pci: msm: Update NTN3 de-emphasis values via I2C Change is to update the de-emphasis value of NTN3 via i2c register writes to resolve link failure issues seen on MBB platforms. Change-Id: If90e5efc19691a14c3d5f12af78df9ff5c2b2a25 Signed-off-by: Subramanian Ananthanarayanan --- drivers/pci/controller/pci-msm.c | 51 ++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index 3659190ee875..79a0af8b47cf 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -698,6 +698,11 @@ struct msm_pcie_drv_info { struct completion completion; }; +struct pcie_i2c_reg_update { + u32 offset; + u32 val; +}; + /* i2c control interface for a i2c client device */ struct pcie_i2c_ctrl { struct i2c_client *client; @@ -708,6 +713,8 @@ struct pcie_i2c_ctrl { u32 ep_reset_gpio_mask; u32 *dump_regs; u32 dump_reg_count; + struct pcie_i2c_reg_update *reg_update; + u32 reg_update_count; /* client specific callbacks */ int (*client_i2c_read)(struct i2c_client *client, u32 reg_addr, @@ -716,6 +723,7 @@ struct pcie_i2c_ctrl { u32 val); int (*client_i2c_reset)(struct pcie_i2c_ctrl *i2c_ctrl, bool reset); void (*client_i2c_dump_regs)(struct pcie_i2c_ctrl *i2c_ctrl); + void (*client_i2c_de_emphasis_wa)(struct pcie_i2c_ctrl *i2c_ctrl); }; enum i2c_client_id { @@ -4496,6 +4504,28 @@ static void ntn3_dump_regs(struct pcie_i2c_ctrl *i2c_ctrl) } } +static void ntn3_de_emphasis_wa(struct pcie_i2c_ctrl *i2c_ctrl) +{ + int i, val; + struct msm_pcie_dev_t *pcie_dev = container_of(i2c_ctrl, + struct msm_pcie_dev_t, + i2c_ctrl); + + PCIE_DBG(pcie_dev, "PCIe: RC%d: NTN3 reg update\n", pcie_dev->rc_idx); + + for (i = 0; i < i2c_ctrl->reg_update_count; i++) { + i2c_ctrl->client_i2c_write(i2c_ctrl->client, i2c_ctrl->reg_update[i].offset, + i2c_ctrl->reg_update[i].val); + /*Read to make sure writes are completed*/ + i2c_ctrl->client_i2c_read(i2c_ctrl->client, i2c_ctrl->reg_update[i].offset, + &val); + PCIE_DBG(pcie_dev, "PCIe: RC%d: NTN3 reg off:0x%x wr_val:0x%x rd_val:0x%x\n", + pcie_dev->rc_idx, i2c_ctrl->reg_update[i].offset, + i2c_ctrl->reg_update[i].val, val); + } + +} + static int msm_pcie_enable(struct msm_pcie_dev_t *dev) { int ret = 0; @@ -4609,6 +4639,9 @@ static int msm_pcie_enable(struct msm_pcie_dev_t *dev) ep_up_timeout = jiffies + usecs_to_jiffies(EP_UP_TIMEOUT_US); + if (dev->i2c_ctrl.client && dev->i2c_ctrl.client_i2c_de_emphasis_wa) + dev->i2c_ctrl.client_i2c_de_emphasis_wa(&dev->i2c_ctrl); + msm_pcie_config_sid(dev); msm_pcie_config_controller(dev); @@ -5909,6 +5942,23 @@ static int msm_pcie_i2c_ctrl_init(struct msm_pcie_dev_t *pcie_dev) i2c_ctrl->dump_reg_count = 0; } + of_get_property(i2c_client_node, "reg_update", &size); + + if (size) { + i2c_ctrl->reg_update = devm_kzalloc(dev, size, GFP_KERNEL); + if (!i2c_ctrl->reg_update) + return -ENOMEM; + + i2c_ctrl->reg_update_count = size / sizeof(*i2c_ctrl->reg_update); + + ret = of_property_read_u32_array(i2c_client_node, + "reg_update", + (unsigned int *)i2c_ctrl->reg_update, + size/sizeof(i2c_ctrl->reg_update->offset)); + if (ret) + i2c_ctrl->reg_update_count = 0; + } + return 0; } @@ -6982,6 +7032,7 @@ static int pcie_i2c_ctrl_probe(struct i2c_client *client, i2c_ctrl->client_i2c_write = ntn3_i2c_write; i2c_ctrl->client_i2c_reset = ntn3_ep_reset_ctrl; i2c_ctrl->client_i2c_dump_regs = ntn3_dump_regs; + i2c_ctrl->client_i2c_de_emphasis_wa = ntn3_de_emphasis_wa; } else { dev_err(&client->dev, "invalid client id %d\n", client_id); } From 5078963db49d263d50ef797cf44f6d0e4a026860 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Tue, 13 Jul 2021 11:52:00 +0530 Subject: [PATCH 83/90] clk: qcom: common: Check for rclks before access The critical devices or critical clocks where the clocks of the device node requires to be kept enabled should be checked for valid rclk before update. Thus check for NULL before accessing the rclk. Change-Id: Ie0cf1486f8cc422de8fce0241bd6e81fd9d7ca2b Signed-off-by: Taniya Das --- drivers/clk/qcom/common.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index 9fc95cf85c6c..43c772826b18 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -247,7 +247,8 @@ static void qcom_cc_set_critical(struct device *dev, struct qcom_cc *cc) if (i >= cc->num_rclks) continue; - cc->rclks[i]->flags |= QCOM_CLK_IS_CRITICAL; + if (cc->rclks[i]) + cc->rclks[i]->flags |= QCOM_CLK_IS_CRITICAL; } of_property_for_each_u32(dev->of_node, "qcom,critical-devices", prop, p, i) { @@ -265,7 +266,8 @@ static void qcom_cc_set_critical(struct device *dev, struct qcom_cc *cc) if (args.np != dev->of_node || clock_idx >= cc->num_rclks) continue; - cc->rclks[clock_idx]->flags |= QCOM_CLK_IS_CRITICAL; + if (cc->rclks[clock_idx]) + cc->rclks[clock_idx]->flags |= QCOM_CLK_IS_CRITICAL; of_node_put(args.np); } From 1502b7f36eb148278cf0e8ff4fc0de5895d14402 Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Mon, 12 Jul 2021 10:22:21 +0530 Subject: [PATCH 84/90] serial: msm-geni-serial: Update is_clock_off to atomic variable Update is_clock_off and wakeup_enabled variable to atomic to avoid race conditions while accessing it. Change-Id: I7e792b5938befeeede60f15353be328d20c25758 Signed-off-by: Anvesh Salveru Signed-off-by: Chandana Kishori Chiluveru --- drivers/tty/serial/msm_geni_serial.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index 21dbdc0075f1..04d6bdd1084c 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -232,7 +232,7 @@ struct msm_geni_serial_port { struct completion s_cmd_timeout; spinlock_t rx_lock; bool pm_auto_suspend_disable; - bool is_clock_off; + atomic_t is_clock_off; enum uart_error_code uart_error; }; @@ -1268,7 +1268,7 @@ static void msm_geni_serial_start_tx(struct uart_port *uport) static unsigned int ios_log_limit; /* when start_tx is called with UART clocks OFF return. */ - if (uart_console(uport) && msm_port->is_clock_off) { + if (uart_console(uport) && (uport->suspended || atomic_read(&msm_port->is_clock_off))) { IPC_LOG_MSG(msm_port->console_log, "%s. Console in suspend state\n", __func__); return; @@ -2166,7 +2166,7 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport, bool s_cmd_done = false; bool m_cmd_done = false; - if (uart_console(uport) && msm_port->is_clock_off) { + if (uart_console(uport) && atomic_read(&msm_port->is_clock_off)) { IPC_LOG_MSG(msm_port->console_log, "%s. Console in suspend state\n", __func__); goto exit_geni_serial_isr; @@ -2991,11 +2991,11 @@ static void msm_geni_serial_cons_pm(struct uart_port *uport, if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF) { se_geni_resources_on(&msm_port->serial_rsc); - msm_port->is_clock_off = false; + atomic_set(&msm_port->is_clock_off, 0); } else if (new_state == UART_PM_STATE_OFF && old_state == UART_PM_STATE_ON) { + atomic_set(&msm_port->is_clock_off, 1); se_geni_resources_off(&msm_port->serial_rsc); - msm_port->is_clock_off = true; } } @@ -3620,6 +3620,7 @@ static int msm_geni_serial_sys_suspend(struct device *dev) struct uart_port *uport = &port->uport; if (uart_console(uport) || port->pm_auto_suspend_disable) { + IPC_LOG_MSG(port->console_log, "%s start\n", __func__); uart_suspend_port((struct uart_driver *)uport->private_data, uport); IPC_LOG_MSG(port->console_log, "%s\n", __func__); @@ -3652,6 +3653,7 @@ static int msm_geni_serial_sys_resume(struct device *dev) if ((uart_console(uport) && console_suspend_enabled && uport->suspended) || port->pm_auto_suspend_disable) { + IPC_LOG_MSG(port->console_log, "%s start\n", __func__); uart_resume_port((struct uart_driver *)uport->private_data, uport); IPC_LOG_MSG(port->console_log, "%s\n", __func__); From f5945564e786db88a56c2893bbf09474dc7bbb10 Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Wed, 14 Jul 2021 14:59:58 +0530 Subject: [PATCH 85/90] serial: msm_geni_serial: Reset UART error code to default during shutdown Currently driver is seting UART error code to default only when BT host calling TIOCFAULT crash ioctl. This change is to reset UART error code to default during shutdown so that it will helps in passing correct UART error code from UART driver from next session. Change-Id: I2a073634699d54e905ca3970392563f7d8130640 Signed-off-by: Chandana Kishori Chiluveru --- drivers/tty/serial/msm_geni_serial.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index 21dbdc0075f1..b16ede74c13e 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -2380,6 +2380,8 @@ static void msm_geni_serial_shutdown(struct uart_port *uport) IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: Error %d pinctrl_select_state\n", __func__, ret); } + /* Reset UART error to default during port_close() */ + msm_port->uart_error = UART_ERROR_DEFAULT; } IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: End\n", __func__); } From fcabf414041c7f9e2087573d6a533756380407ba Mon Sep 17 00:00:00 2001 From: Rohith Kollalsi Date: Mon, 12 Jul 2021 20:57:19 +0530 Subject: [PATCH 86/90] usb: dwc3: Drive a pulse on DP for iio based cdp charger detection also Charger detection can be iio based or psy based or ADSP based. In case of psy based charger detection POWER_SUPPLY_USB_TYPE_CDP enum is returned, while in case of iio based charger detection POWER_SUPPLY_TYPE_USB_CDP enum is returned for cdp detection. Current case is handling only psy based charger detection i.e driving a pulse on DP for cdp detection is happening only for psy based charger detection ensuring proper CDP detection, while failure is seen in case of iio based cdp charger detection. Hence add support to check appropriate enum for iio based charger detection as well. To add more info for ADSP based charger detection driving of dp pulse will be taken care by adsp. Change-Id: I991a44efb77542b21fbfce14ab98ffad3f102edb Signed-off-by: Rohith Kollalsi --- drivers/usb/dwc3/dwc3-msm.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 3b439bf49bdf..2d258cd8edcf 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -4070,6 +4070,7 @@ static int dwc3_msm_vbus_notifier(struct notifier_block *nb, struct dwc3_msm *mdwc = enb->mdwc; char *eud_str; const char *edev_name; + bool is_cdp; if (!edev || !mdwc) return NOTIFY_DONE; @@ -4094,12 +4095,21 @@ static int dwc3_msm_vbus_notifier(struct notifier_block *nb, mdwc->vbus_active = event; } + /* + * In case of ADSP based charger detection driving a pulse on + * DP to ensure proper CDP detection will be taken care by + * ADSP. + */ + is_cdp = ((mdwc->apsd_source == IIO) && + (get_chg_type(mdwc) == POWER_SUPPLY_TYPE_USB_CDP)) || + ((mdwc->apsd_source == PSY) && + (get_chg_type(mdwc) == POWER_SUPPLY_USB_TYPE_CDP)); + /* * Drive a pulse on DP to ensure proper CDP detection * and only when the vbus connect event is a valid one. */ - if (get_chg_type(mdwc) == POWER_SUPPLY_USB_TYPE_CDP && - mdwc->vbus_active && !mdwc->check_eud_state) { + if (is_cdp && mdwc->vbus_active && !mdwc->check_eud_state) { dev_dbg(mdwc->dev, "Connected to CDP, pull DP up\n"); mdwc->hs_phy->charger_detect(mdwc->hs_phy); } From b8fb16ef6c3ca2c524dfcb67c86cf208bb0bda56 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Sun, 20 Jun 2021 21:21:29 +0530 Subject: [PATCH 87/90] iio: qcom-spmi-adc5: Add support for SW calibrated ADC Add support for reading ADC channels on a PMIC7 ADC directly from the ADC_PBS peripheral on that PMIC instead of through PMK8350 ADC peripheral using PBS, for targets where PMK8350 does not run in master mode. The conversion request sequence for using ADC_PBS is similar to the existing one for ADC7, with some differences in register writes. In addition, SW now performs calibration in place of PBS, for every conversion, by reading the three calibration channels, calculating the reference values and entering them in the calibration registers. Change-Id: I9e47ed69e75ee2580a37195ea9063f24ffb8aac5 Signed-off-by: Jishnu Prakash --- drivers/iio/adc/qcom-spmi-adc5.c | 338 ++++++++++++++++++++++++++++++- 1 file changed, 332 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index 0c7713b4ef2e..fc670d7ef4e7 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -89,6 +90,24 @@ #define ADC_APP_SID_MASK 0xf #define ADC7_CONV_TIMEOUT_MS 501 +/* For ADC_PBS on PMIC7 with SW calibration */ +#define ADC7_SW_CALIB_PBS_CALREF_FLAG 0x57 +#define ADC7_SW_CALIB_PBS_CALREF_RDY BIT(7) + +#define ADC7_SW_CALIB_PBS_GND_REF_D0 0x58 +#define ADC7_SW_CALIB_PBS_GND_REF_D1 0x59 +#define ADC7_SW_CALIB_PBS_VREF_VADC_DELTA_D0 0x5a +#define ADC7_SW_CALIB_PBS_VREF_VADC_DELTA_D1 0x5b +#define ADC7_SW_CALIB_PBS_VREF_MBG_DELTA_D0 0x5c +#define ADC7_SW_CALIB_PBS_VREF_MBG_DELTA_D1 0x5d + +/* For ADC_CMN on PMIC7 with SW calibration */ +#define ADC7_SW_CALIB_CMN_PBUS_WRITE_SYNC_CTL 0x4e +#define ADC7_PBUS_WRITE_SYNC_SW_CLK_REQ BIT(2) +#define ADC7_PBUS_WRITE_SYNC_SW_CLK_REQ_MODE BIT(1) +#define ADC7_PBUS_WRITE_SYNC_BYPASS BIT(0) + + enum adc5_cal_method { ADC5_NO_CAL = 0, ADC5_RATIOMETRIC_CAL, @@ -134,6 +153,8 @@ struct adc5_channel_prop { * @regmap: SPMI ADC5 peripheral register map field. * @dev: SPMI ADC5 device. * @base: base address for the ADC peripheral. + * @cmn_base: base address for the ADC_CMN peripheral, needed + * for SW calibrated ADC. * @nchannels: number of ADC channels. * @chan_props: array of ADC channel properties. * @iio_chans: array of IIO channels specification. @@ -146,6 +167,7 @@ struct adc5_chip { struct regmap *regmap; struct device *dev; u16 base; + u16 cmn_base; unsigned int nchannels; struct adc5_channel_prop *chan_props; struct iio_chan_spec *iio_chans; @@ -175,17 +197,50 @@ static const struct vadc_prescale_ratio adc5_prescale_ratios[] = { static int adc5_read(struct adc5_chip *adc, u16 offset, u8 *data, int len) { - return regmap_bulk_read(adc->regmap, adc->base + offset, data, len); + int ret; + + ret = regmap_bulk_read(adc->regmap, adc->base + offset, data, len); + if (ret) + pr_err("adc read to register %#x of length:%d failed, ret=%d\n", + offset, len, ret); + + return ret; } static int adc5_write(struct adc5_chip *adc, u16 offset, u8 *data, int len) { - return regmap_bulk_write(adc->regmap, adc->base + offset, data, len); + int ret; + + ret = regmap_bulk_write(adc->regmap, adc->base + offset, data, len); + if (ret) + pr_err("adc write to register %#x of length:%d failed, ret=%d\n", + offset, len, ret); + + return ret; } static int adc5_masked_write(struct adc5_chip *adc, u16 offset, u8 mask, u8 val) { - return regmap_update_bits(adc->regmap, adc->base + offset, mask, val); + int ret; + + ret = regmap_update_bits(adc->regmap, adc->base + offset, mask, val); + if (ret) + pr_err("adc masked write to register %#x with mask:0x%x failed, ret=%d\n", + offset, mask, ret); + + return ret; +} + +static int adc5_cmn_write(struct adc5_chip *adc, u16 offset, u8 *data, int len) +{ + int ret; + + ret = regmap_bulk_write(adc->regmap, adc->cmn_base + offset, data, len); + if (ret) + pr_err("adc_cmn write to register %#x of length:%d failed, ret=%d\n", + offset, len, ret); + + return ret; } static int adc5_prescaling_from_dt(u32 num, u32 den) @@ -242,11 +297,11 @@ static int adc5_read_voltage_data(struct adc5_chip *adc, u16 *data) int ret; u8 rslt_lsb, rslt_msb; - ret = adc5_read(adc, ADC5_USR_DATA0, &rslt_lsb, sizeof(rslt_lsb)); + ret = adc5_read(adc, ADC5_USR_DATA0, &rslt_lsb, 1); if (ret) return ret; - ret = adc5_read(adc, ADC5_USR_DATA1, &rslt_msb, sizeof(rslt_lsb)); + ret = adc5_read(adc, ADC5_USR_DATA1, &rslt_msb, 1); if (ret) return ret; @@ -385,6 +440,52 @@ static int adc7_configure(struct adc5_chip *adc, return ret; } +static int adc7_sw_calib_configure(struct adc5_chip *adc, + struct adc5_channel_prop *prop) +{ + int ret; + u8 buf[5], val = 0; + + /* Read registers 0x42 through 0x46 */ + ret = adc5_read(adc, ADC5_USR_DIG_PARAM, buf, sizeof(buf)); + if (ret < 0) + return ret; + + /* Digital param selection */ + adc5_update_dig_param(adc, prop, &buf[0]); + + /* Update fast average sample value */ + buf[1] &= (u8) ~ADC5_USR_FAST_AVG_CTL_SAMPLES_MASK; + buf[1] |= prop->avg_samples | ADC5_USR_FAST_AVG_CTL_EN; + + /* Select ADC channel */ + buf[2] = prop->channel; + + /* Select HW settle delay for channel */ + buf[3] &= (u8) ~ADC5_USR_HW_SETTLE_DELAY_MASK; + buf[3] |= prop->hw_settle_time; + + /* Select ADC enable */ + buf[4] |= ADC5_USR_EN_CTL1_ADC_EN; + + if (!adc->poll_eoc) + reinit_completion(&adc->complete); + + ret = adc5_write(adc, ADC5_USR_DIG_PARAM, buf, sizeof(buf)); + if (ret < 0) + return ret; + + val = ADC7_PBUS_WRITE_SYNC_SW_CLK_REQ | ADC7_PBUS_WRITE_SYNC_SW_CLK_REQ_MODE; + + ret = adc5_cmn_write(adc, ADC7_SW_CALIB_CMN_PBUS_WRITE_SYNC_CTL, &val, 1); + if (ret < 0) + return ret; + + /* Select CONV request */ + val = ADC5_USR_CONV_REQ_REQ; + return adc5_write(adc, ADC5_USR_CONV_REQ, &val, 1); +} + static int adc5_do_conversion(struct adc5_chip *adc, struct adc5_channel_prop *prop, struct iio_chan_spec const *chan, @@ -494,6 +595,59 @@ unlock: return ret; } +#define ADC7_SW_CALIB_CONV_TIMEOUT_MS 150 +static int adc7_sw_calib_do_conversion(struct adc5_chip *adc, + struct adc5_channel_prop *prop, u16 *adc_code_volt) +{ + int ret; + unsigned long rc; + u8 status = 0, val; + + mutex_lock(&adc->lock); + + ret = adc7_sw_calib_configure(adc, prop); + if (ret) { + pr_err("ADC configure failed with %d\n", ret); + goto unlock; + } + + /* No support for polling mode at present*/ + rc = wait_for_completion_timeout(&adc->complete, + msecs_to_jiffies(ADC7_SW_CALIB_CONV_TIMEOUT_MS)); + if (!rc) { + pr_err("Reading ADC channel %s timed out\n", + prop->datasheet_name); + ret = -ETIMEDOUT; + goto unlock; + } + + ret = adc5_read(adc, ADC5_USR_STATUS1, &status, 1); + if (ret < 0) + goto unlock; + + if (!(status & ADC5_USR_STATUS1_EOC)) { + pr_err("ADC channel %s EOC bit not set, status=%#x\n", + prop->datasheet_name, status); + ret = -EIO; + goto unlock; + } + + ret = adc5_read_voltage_data(adc, adc_code_volt); + if (ret < 0) + goto unlock; + + val = 0; + ret = adc5_write(adc, ADC5_USR_EN_CTL1, &val, 1); + if (ret < 0) + goto unlock; + + ret = adc5_cmn_write(adc, ADC7_SW_CALIB_CMN_PBUS_WRITE_SYNC_CTL, &val, 1); +unlock: + mutex_unlock(&adc->lock); + + return ret; +} + static irqreturn_t adc5_isr(int irq, void *dev_id) { struct adc5_chip *adc = dev_id; @@ -503,6 +657,21 @@ static irqreturn_t adc5_isr(int irq, void *dev_id) return IRQ_HANDLED; } +static struct adc5_channel_prop *adc7_get_channel(struct adc5_chip *adc, + unsigned int num) +{ + unsigned int i; + + for (i = 0; i < adc->nchannels; i++) { + if (adc->chan_props[i].channel == num) + return &adc->chan_props[i]; + } + + pr_err("Invalid channel %02x\n", num); + + return NULL; +} + static int adc5_of_xlate(struct iio_dev *indio_dev, const struct of_phandle_args *iiospec) { @@ -609,6 +778,118 @@ static int adc5_read_raw(struct iio_dev *indio_dev, return 0; } +static int adc7_calib(struct adc5_chip *adc) +{ + int ret = 0; + u16 gnd, vref_1p25, vref_vdd; + u8 buf[2]; + struct adc5_channel_prop *gnd_prop, *vref_1p25_prop, *vref_vdd_prop; + + /* These channels are mandatory, they are used as reference points */ + gnd_prop = adc7_get_channel(adc, ADC7_REF_GND); + if (!gnd_prop) { + dev_err(adc->dev, "GND channel not defined for SW calibration\n"); + return -ENODEV; + } + + vref_1p25_prop = adc7_get_channel(adc, ADC7_1P25VREF); + if (!vref_1p25_prop) { + dev_err(adc->dev, "1.25VREF channel not defined for SW calibration\n"); + return -ENODEV; + } + + vref_vdd_prop = adc7_get_channel(adc, ADC7_VREF_VADC); + if (!vref_vdd_prop) { + dev_err(adc->dev, "VDD channel not defined for SW calibration\n"); + return -ENODEV; + } + + ret = adc7_sw_calib_do_conversion(adc, gnd_prop, &gnd); + if (ret) { + dev_err(adc->dev, "Failed to read GND channel, ret = %d\n", ret); + return ret; + } + + ret = adc7_sw_calib_do_conversion(adc, vref_1p25_prop, &vref_1p25); + if (ret) { + dev_err(adc->dev, "Failed to read 1.25VREF channel, ret = %d\n", ret); + return ret; + } + + ret = adc7_sw_calib_do_conversion(adc, vref_vdd_prop, &vref_vdd); + if (ret) { + dev_err(adc->dev, "Failed to read VDD channel, ret = %d\n", ret); + return ret; + } + + buf[0] = gnd & 0xff; + buf[1] = gnd >> 8; + ret = adc5_write(adc, ADC7_SW_CALIB_PBS_GND_REF_D0, buf, sizeof(buf)); + if (ret) + return ret; + + vref_vdd -= gnd; + buf[0] = vref_vdd & 0xff; + buf[1] = vref_vdd >> 8; + ret = adc5_write(adc, ADC7_SW_CALIB_PBS_VREF_VADC_DELTA_D0, buf, sizeof(buf)); + if (ret) + return ret; + + vref_1p25 -= gnd; + buf[0] = vref_1p25 & 0xff; + buf[1] = vref_1p25 >> 8; + ret = adc5_write(adc, ADC7_SW_CALIB_PBS_VREF_MBG_DELTA_D0, buf, sizeof(buf)); + + if (!ret) + dev_dbg(adc->dev, "SW calibration done, gnd:0x%x vref_vdd:0x%x vref_1p25:0x%x\n", + gnd, vref_vdd, vref_1p25); + + return ret; +} + +static int adc7_sw_calib_conv(struct adc5_chip *adc, struct adc5_channel_prop *prop, int *val) +{ + int ret = 0; + u16 adc_code_volt; + + ret = adc7_calib(adc); + if (ret) + return ret; + + ret = adc7_sw_calib_do_conversion(adc, prop, &adc_code_volt); + if (ret) + return ret; + + return qcom_adc5_hw_scale(prop->scale_fn_type, + &adc5_prescale_ratios[prop->prescale], + adc->data, + adc_code_volt, val); +} + +static int adc7_sw_calib_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, + long mask) +{ + struct adc5_chip *adc = iio_priv(indio_dev); + struct adc5_channel_prop *prop; + int ret; + + prop = &adc->chan_props[chan->address]; + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + ret = adc7_sw_calib_conv(adc, prop, val); + if (ret) + return ret; + + return IIO_VAL_INT; + default: + return -EINVAL; + } + + return 0; +} + static const struct iio_info adc5_info = { .read_raw = adc5_read_raw, .of_xlate = adc5_of_xlate, @@ -619,6 +900,11 @@ static const struct iio_info adc7_info = { .of_xlate = adc7_of_xlate, }; +static const struct iio_info adc7_sw_calib_info = { + .read_raw = adc7_sw_calib_read_raw, + .of_xlate = adc5_of_xlate, +}; + struct adc5_channels { const char *datasheet_name; unsigned int prescale_index; @@ -711,6 +997,8 @@ static const struct adc5_channels adc7_chans_pmic[ADC5_MAX_CHANNEL] = { SCALE_HW_CALIB_DEFAULT) [ADC7_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 0, SCALE_HW_CALIB_DEFAULT) + [ADC7_VREF_VADC] = ADC5_CHAN_VOLT("vref_vadc", 0, + SCALE_HW_CALIB_DEFAULT) [ADC7_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 1, SCALE_HW_CALIB_DEFAULT) [ADC7_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 3, @@ -904,6 +1192,8 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc, if (of_property_read_bool(node, "qcom,ratiometric")) prop->cal_method = ADC5_RATIOMETRIC_CAL; + else if (of_property_read_bool(node, "qcom,no-cal")) + prop->cal_method = ADC5_NO_CAL; else prop->cal_method = ADC5_ABSOLUTE_CAL; @@ -980,6 +1270,10 @@ static const struct of_device_id adc5_match_table[] = { .compatible = "qcom,spmi-adc7", .data = &adc7_data_pmic, }, + { + .compatible = "qcom,spmi-adc7-sw-calib", + .data = &adc7_data_pmic, + }, { .compatible = "qcom,spmi-adc-rev2", .data = &adc5_data_pmic_rev2, @@ -1062,8 +1356,10 @@ static int adc5_probe(struct platform_device *pdev) struct adc5_chip *adc; struct regmap *regmap; const char *irq_name; + const __be32 *prop_addr; int ret, irq_eoc; u32 reg; + u8 val; regmap = dev_get_regmap(dev->parent, NULL); if (!regmap) @@ -1080,13 +1376,32 @@ static int adc5_probe(struct platform_device *pdev) adc = iio_priv(indio_dev); adc->regmap = regmap; adc->dev = dev; - adc->base = reg; + + prop_addr = of_get_address(dev->of_node, 0, NULL, NULL); + if (!prop_addr) { + pr_err("invalid IO resource\n"); + return -EINVAL; + } + adc->base = be32_to_cpu(*prop_addr); + + prop_addr = of_get_address(dev->of_node, 1, NULL, NULL); + if (!prop_addr) + pr_debug("invalid cmn resource\n"); + else + adc->cmn_base = be32_to_cpu(*prop_addr); platform_set_drvdata(pdev, adc); if (of_device_is_compatible(node, "qcom,spmi-adc7")) { indio_dev->info = &adc7_info; adc->is_pmic7 = true; + } else if (of_device_is_compatible(node, "qcom,spmi-adc7-sw-calib")) { + if (!adc->cmn_base) { + pr_err("ADC_CMN undefined\n"); + return -ENODEV; + } + indio_dev->info = &adc7_sw_calib_info; + adc->is_pmic7 = true; } else { indio_dev->info = &adc5_info; } @@ -1116,6 +1431,17 @@ static int adc5_probe(struct platform_device *pdev) return ret; } + if (of_device_is_compatible(node, "qcom,spmi-adc7-sw-calib")) { + ret = adc7_calib(adc); + if (ret) + return ret; + + val = ADC7_SW_CALIB_PBS_CALREF_RDY; + ret = adc5_write(adc, ADC7_SW_CALIB_PBS_CALREF_FLAG, &val, 1); + if (ret < 0) + return ret; + } + indio_dev->dev.parent = dev; indio_dev->dev.of_node = node; indio_dev->name = pdev->name; From 336d33b9386b195103f9ec173155b7799327a4c9 Mon Sep 17 00:00:00 2001 From: Udipto Goswami Date: Wed, 7 Jul 2021 18:46:13 +0530 Subject: [PATCH 88/90] usb: dwc3: Perform pm_runtime async op for suspend in ep_disable The ep_disable functions uses pm_runtime_get_sync & pm_runtime_put_sync_autosuspend to manage the dev & sysdev, however doing auto suspend in sync context might lead to errors on runtime framework due to the ASYNC flag not set. When this happens, the runtime framework triggers __might_sleep which in turn leads to a kernel panic. Fix this by performing pm_runtime_put_autosuspend instead of doing sync. This will set the ASYNC flag and will not go for might_sleep check. Change-Id: I9cff7738def5fac94d11e7648efc3602b9fe3ea6 Signed-off-by: Udipto Goswami Signed-off-by: Rohith Kollalsi --- drivers/usb/dwc3/gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index aa03c5b6da10..6452a161c89b 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -971,7 +971,7 @@ static int dwc3_gadget_ep_disable(struct usb_ep *ep) dbg_event(dep->number, "DISABLE", ret); spin_unlock_irqrestore(&dwc->lock, flags); pm_runtime_mark_last_busy(dwc->sysdev); - pm_runtime_put_sync_autosuspend(dwc->sysdev); + pm_runtime_put_autosuspend(dwc->sysdev); return ret; } From 7c5235d350737bec625c0f366a58b2b908c2c3e1 Mon Sep 17 00:00:00 2001 From: Naman Padhiar Date: Mon, 19 Jul 2021 20:33:01 +0530 Subject: [PATCH 89/90] cnss2: Avoid ASSERT in panic handler Avoid calling ASSERT from select_window API when it called from panic handler. As device is already crashed, calling ASSERT will just add unwanted prints and dump stacks. Change-Id: If38be6d8e452c49cabfa059b4bf12b2f8a3c60a2 Signed-off-by: Naman Padhiar --- drivers/net/wireless/cnss2/pci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 979c5e149796..08635be66660 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -685,6 +685,8 @@ int cnss_pci_check_link_status(struct cnss_pci_data *pci_priv) static void cnss_pci_select_window(struct cnss_pci_data *pci_priv, u32 offset) { + struct cnss_plat_data *plat_priv = pci_priv->plat_priv; + u32 window = (offset >> WINDOW_SHIFT) & WINDOW_VALUE_MASK; u32 window_enable = WINDOW_ENABLE_BIT | window; u32 val; @@ -703,7 +705,8 @@ static void cnss_pci_select_window(struct cnss_pci_data *pci_priv, u32 offset) if (val != window_enable) { cnss_pr_err("Failed to config window register to 0x%x, current value: 0x%x\n", window_enable, val); - if (!cnss_pci_check_link_status(pci_priv)) + if (!cnss_pci_check_link_status(pci_priv) && + !test_bit(CNSS_IN_PANIC, &plat_priv->driver_state)) CNSS_ASSERT(0); } } From 8058227d7122fa9a89f9157edfe812483e52e87f Mon Sep 17 00:00:00 2001 From: Tushar Nimkar Date: Tue, 20 Jul 2021 11:40:44 +0530 Subject: [PATCH 90/90] drivers: pinctrl: sdxlemur: Update GPIO PDC map This change updates gpio to pdc mapping for sdxlemur. Change-Id: I0149b3cc798815693a7999335444419b1d896444 Signed-off-by: Tushar Nimkar --- drivers/pinctrl/qcom/pinctrl-sdxlemur.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-sdxlemur.c b/drivers/pinctrl/qcom/pinctrl-sdxlemur.c index 4a26b0ddd0fe..4576fcb3ab2e 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdxlemur.c +++ b/drivers/pinctrl/qcom/pinctrl-sdxlemur.c @@ -1044,12 +1044,13 @@ static const struct msm_gpio_wakeirq_map sdxlemur_pdc_map[] = { {1, 20}, {2, 21}, {5, 22}, {6, 23}, {9, 24}, {10, 25}, {11, 26}, {12, 27}, {13, 28}, {14, 29}, {15, 30}, {16, 31}, {17, 32}, {18, 33}, {19, 34}, {21, 35}, {22, 36}, {23, 70}, - {24, 37}, {25, 38}, {35, 40}, {43, 41}, {46, 44}, {48, 45}, - {49, 57}, {50, 46}, {52, 47}, {54, 49}, {55, 50}, {60, 53}, + {24, 37}, {25, 38}, {32, 39}, {35, 40}, {43, 41}, {44, 42}, + {45, 43}, {46, 44}, {48, 45}, {49, 57}, {50, 46}, {52, 47}, + {53, 48}, {54, 49}, {55, 50}, {56, 51}, {57, 52}, {60, 53}, {61, 54}, {64, 55}, {65, 81}, {68, 56}, {71, 58}, {73, 59}, - {77, 77}, {81, 65}, {83, 63}, {84, 64}, {86, 66}, {88, 67}, - {89, 68}, {90, 69}, {93, 71}, {94, 72}, {95, 73}, {96, 74}, - {99, 75}, {103, 78}, {104, 79} + {76, 60}, {77, 77}, {78, 61}, {79, 62}, {81, 65}, {83, 63}, + {84, 64}, {86, 66}, {88, 67}, {89, 68}, {90, 69}, {93, 71}, + {94, 72}, {95, 73}, {96, 74}, {99, 75}, {103, 78}, {104, 79}, }; static const struct msm_pinctrl_soc_data sdxlemur_pinctrl = {